From 5e4377558d1ef5e5f436c1e6fbe68d254f14b98d Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 02:42:40 +0000 Subject: [PATCH 1/8] fix(docs): restore AgentEye language navigation --- .github/workflows/translate-docs.yml | 26 +++++-- .../scripts/translate-docs/config.test.ts | 6 ++ .../translate-docs/mintlify-nav.test.ts | 7 ++ docs/docs.json | 4 +- scripts/translate-docs/config.ts | 70 +++++++++++++++---- scripts/translate-docs/mintlify-nav.ts | 7 +- scripts/translate-docs/types.ts | 3 + 7 files changed, 100 insertions(+), 23 deletions(-) diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 4da4e25f..7616fde2 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -4,19 +4,19 @@ on: push: branches: [main] paths: - - 'docs/*.mdx' - - 'docs/**/*.mdx' - - 'README.md' + - "docs/*.mdx" + - "docs/**/*.mdx" + - "README.md" workflow_dispatch: inputs: force: - description: 'Ignore cache and re-translate everything' + description: "Ignore cache and re-translate everything" type: boolean default: false languages: - description: 'Comma-separated language codes (leave empty for all)' + description: "Comma-separated language codes (leave empty for all)" type: string - default: '' + default: "" concurrency: group: translate-docs @@ -129,6 +129,20 @@ jobs: bun scripts/translate-docs/cli.ts --update-nav --languages zh,ja,ko,es,pt-br,de,fr,ru,hi,tr,vi,it,ar,he + - uses: actions/setup-node@v6 + with: + node-version: 22 + + - name: Install Mintlify CLI + run: npm install -g mintlify + + - name: Validate generated docs config + working-directory: docs + run: mintlify validate + + - name: Validate translated MDX pages + run: bun run validate:mdx + - name: Download cache fragments continue-on-error: true uses: actions/download-artifact@v8 diff --git a/__tests__/scripts/translate-docs/config.test.ts b/__tests__/scripts/translate-docs/config.test.ts index 6fbfbf35..cec14327 100644 --- a/__tests__/scripts/translate-docs/config.test.ts +++ b/__tests__/scripts/translate-docs/config.test.ts @@ -15,6 +15,12 @@ describe("LANGUAGES", () => { expect(LANGUAGES).toHaveLength(14); }); + it("uses Mintlify's canonical locale without changing the folder code", () => { + const portuguese = LANGUAGES.find((language) => language.code === "pt-br"); + + expect(portuguese?.mintlifyCode).toBe("pt-BR"); + }); + it("has unique codes", () => { const codes = LANGUAGES.map((l) => l.code); expect(new Set(codes).size).toBe(codes.length); diff --git a/__tests__/scripts/translate-docs/mintlify-nav.test.ts b/__tests__/scripts/translate-docs/mintlify-nav.test.ts index 025240ef..fbbea307 100644 --- a/__tests__/scripts/translate-docs/mintlify-nav.test.ts +++ b/__tests__/scripts/translate-docs/mintlify-nav.test.ts @@ -212,4 +212,11 @@ describe("localizeProductsNavigation", () => { "es/agenteye/overview", ]); }); + + it("uses Mintlify's canonical Portuguese locale with existing paths", () => { + const portuguese = buildLanguageNav(sampleEnglishTabs, "pt-br"); + + expect(portuguese.language).toBe("pt-BR"); + expect(portuguese.tabs[0].groups[0].pages[0]).toBe("pt-br/introduction"); + }); }); diff --git a/docs/docs.json b/docs/docs.json index 56e2c9da..07ba70d0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -344,7 +344,7 @@ ] }, { - "language": "pt-br", + "language": "pt-BR", "tabs": [ { "tab": "Documentação", @@ -1275,7 +1275,7 @@ ] }, { - "language": "pt-br", + "language": "pt-BR", "tabs": [ { "tab": "Documentação", diff --git a/scripts/translate-docs/config.ts b/scripts/translate-docs/config.ts index 83819a92..fb15e0a8 100644 --- a/scripts/translate-docs/config.ts +++ b/scripts/translate-docs/config.ts @@ -2,22 +2,60 @@ import type { LanguageConfig } from "./types"; export const LANGUAGES: LanguageConfig[] = [ // Tier 1 — largest developer populations - { code: "zh", name: "Chinese (Simplified)", nativeName: "\u7b80\u4f53\u4e2d\u6587", tier: 1 }, + { + code: "zh", + name: "Chinese (Simplified)", + nativeName: "\u7b80\u4f53\u4e2d\u6587", + tier: 1, + }, { code: "ja", name: "Japanese", nativeName: "\u65e5\u672c\u8a9e", tier: 1 }, { code: "ko", name: "Korean", nativeName: "\ud55c\uad6d\uc5b4", tier: 1 }, { code: "es", name: "Spanish", nativeName: "Espa\u00f1ol", tier: 1 }, - { code: "pt-br", name: "Portuguese (Brazil)", nativeName: "Portugu\u00eas", tier: 1 }, + { + code: "pt-br", + mintlifyCode: "pt-BR", + name: "Portuguese (Brazil)", + nativeName: "Portugu\u00eas", + tier: 1, + }, { code: "de", name: "German", nativeName: "Deutsch", tier: 1 }, { code: "fr", name: "French", nativeName: "Fran\u00e7ais", tier: 1 }, // Tier 2 — strong tech communities - { code: "ru", name: "Russian", nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", tier: 2 }, - { code: "hi", name: "Hindi", nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940", tier: 2 }, + { + code: "ru", + name: "Russian", + nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", + tier: 2, + }, + { + code: "hi", + name: "Hindi", + nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940", + tier: 2, + }, { code: "tr", name: "Turkish", nativeName: "T\u00fcrk\u00e7e", tier: 2 }, - { code: "vi", name: "Vietnamese", nativeName: "Ti\u1ebfng Vi\u1ec7t", tier: 2 }, + { + code: "vi", + name: "Vietnamese", + nativeName: "Ti\u1ebfng Vi\u1ec7t", + tier: 2, + }, { code: "it", name: "Italian", nativeName: "Italiano", tier: 2 }, // Tier 3 — RTL languages - { code: "ar", name: "Arabic", nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629", tier: 3, rtl: true }, - { code: "he", name: "Hebrew", nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea", tier: 3, rtl: true }, + { + code: "ar", + name: "Arabic", + nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629", + tier: 3, + rtl: true, + }, + { + code: "he", + name: "Hebrew", + nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea", + tier: 3, + rtl: true, + }, ]; export function getLanguagesByTier(maxTier: number): LanguageConfig[] { @@ -184,17 +222,21 @@ export const NAV_TRANSLATIONS: Record< ru: { docs: "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f", examples: "\u041f\u0440\u0438\u043c\u0435\u0440\u044b", - gettingStarted: "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b", - coreConcepts: "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438", + gettingStarted: + "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b", + coreConcepts: + "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438", cli: "CLI", tools: "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b", - advanced: "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439", + advanced: + "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439", }, hi: { docs: "\u0926\u0938\u094d\u0924\u093e\u0935\u0947\u091c\u093c", examples: "\u0909\u0926\u093e\u0939\u0930\u0923", gettingStarted: "\u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902", - coreConcepts: "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901", + coreConcepts: + "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901", cli: "CLI", tools: "\u0909\u092a\u0915\u0930\u0923", advanced: "\u0909\u0928\u094d\u0928\u0924", @@ -230,7 +272,8 @@ export const NAV_TRANSLATIONS: Record< docs: "\u0627\u0644\u0645\u0633\u062a\u0646\u062f\u0627\u062a", examples: "\u0623\u0645\u062b\u0644\u0629", gettingStarted: "\u0627\u0644\u0628\u062f\u0627\u064a\u0629", - coreConcepts: "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629", + coreConcepts: + "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629", cli: "CLI", tools: "\u0627\u0644\u0623\u062f\u0648\u0627\u062a", advanced: "\u0645\u062a\u0642\u062f\u0645", @@ -238,7 +281,8 @@ export const NAV_TRANSLATIONS: Record< he: { docs: "\u05ea\u05d9\u05e2\u05d5\u05d3", examples: "\u05d3\u05d5\u05d2\u05de\u05d0\u05d5\u05ea", - gettingStarted: "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4", + gettingStarted: + "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4", coreConcepts: "\u05de\u05d5\u05e9\u05d2\u05d9 \u05d9\u05e1\u05d5\u05d3", cli: "CLI", tools: "\u05db\u05dc\u05d9\u05dd", diff --git a/scripts/translate-docs/mintlify-nav.ts b/scripts/translate-docs/mintlify-nav.ts index 854c4ff2..e003c6bf 100644 --- a/scripts/translate-docs/mintlify-nav.ts +++ b/scripts/translate-docs/mintlify-nav.ts @@ -1,7 +1,7 @@ import { readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -import { NAV_TRANSLATIONS, LANGUAGES } from "./config"; +import { getLanguageByCode, NAV_TRANSLATIONS, LANGUAGES } from "./config"; const __dirname = dirname(fileURLToPath(import.meta.url)); const DOCS_JSON_PATH = join(__dirname, "..", "..", "docs", "docs.json"); @@ -105,7 +105,10 @@ export function buildLanguageNav( })), })); - return { language: lang, tabs }; + return { + language: getLanguageByCode(lang)?.mintlifyCode ?? lang, + tabs, + }; } /** diff --git a/scripts/translate-docs/types.ts b/scripts/translate-docs/types.ts index b578a56a..22ea32f6 100644 --- a/scripts/translate-docs/types.ts +++ b/scripts/translate-docs/types.ts @@ -1,5 +1,8 @@ export interface LanguageConfig { + /** Internal code used for folders, cache keys, and translation routing. */ code: string; + /** Mintlify locale when its canonical casing differs from `code`. */ + mintlifyCode?: string; name: string; nativeName: string; tier: 1 | 2 | 3; From da39629c37f107ce56617f19d98aa1220dbf533f Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 02:50:30 +0000 Subject: [PATCH 2/8] fix(ci): make docs translation atomic --- .github/workflows/translate-docs.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 7616fde2..85bef4d0 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -67,7 +67,9 @@ jobs: restore-keys: bun-${{ runner.os }}- - name: Install dependencies - run: bun install --frozen-lockfile + # Translation only runs TypeScript tooling. Avoid the package prepare + # hook, which builds the full Next.js application once per language. + run: bun install --frozen-lockfile --ignore-scripts - name: Restore translation cache uses: actions/cache/restore@v6 @@ -100,7 +102,9 @@ jobs: consolidate: needs: [prepare, translate] - if: always() && needs.translate.result != 'cancelled' + # Never publish a partial translation set. A failed language produces no + # artifact and would otherwise leave that locale silently stale. + if: needs.translate.result == 'success' runs-on: ubuntu-latest permissions: contents: write @@ -114,10 +118,9 @@ jobs: bun-version: latest - name: Install dependencies - run: bun install --frozen-lockfile + run: bun install --frozen-lockfile --ignore-scripts - name: Download all translations - continue-on-error: true uses: actions/download-artifact@v8 with: pattern: translations-* @@ -144,7 +147,6 @@ jobs: run: bun run validate:mdx - name: Download cache fragments - continue-on-error: true uses: actions/download-artifact@v8 with: pattern: cache-* From bd01f7545d370da12ff1838b69d4bdb9d24085b1 Mon Sep 17 00:00:00 2001 From: Chetan Raghuvanshi <145042127+chhhee10@users.noreply.github.com> Date: Wed, 15 Jul 2026 12:07:33 +0530 Subject: [PATCH 3/8] =?UTF-8?q?feat:=20agent=20CLI=20expansion=20=E2=80=94?= =?UTF-8?q?=20Goose=20+=20OpenClaw=20+=20Factory=20+=20Devin=20+=20Antigra?= =?UTF-8?q?vity=20(12=20CLIs),=20remove=20Gemini=20(#508)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: OpenClaw (openclaw gateway) integration — real-time enforcement + audit Adds OpenClaw as the 9th CLI/agent integration, dual-pillar like Hermes: Pillar 1 (live enforcement) — OpenClaw's in-process plugin hooks (its file-based "internal hooks" are observation-only and cannot block): - openclaw-plugin/ shipped package (manifest + plain-ESM index.js) that async-spawns the failproofai binary and maps a flat {permission,reason} verdict to each hook's native return shape (before_tool_call → {block:true,blockReason}; before_agent_run → {outcome:"block"}; before_agent_finalize → {action:"revise"}). - OPENCLAW_EVENT_MAP / TOOL_MAP / TOOL_INPUT_MAP in types.ts; handler + tool-name-canonicalize + policy-evaluator branches; the openclaw Integration (install/uninstall manages plugins.load.paths + plugins.entries.failproofai in ~/.openclaw/openclaw.json); bin plumbing. Pillar 2 (audit + dashboard) — reads the real JSONL transcripts at ~/.openclaw/agents//sessions/.jsonl: - lib/openclaw-sessions.ts (pure type-discriminated parser, UUID-safe discovery) + lib/openclaw-projects.ts (sessions.json index, agentId grouping) + src/audit/cli-adapters/openclaw.ts. - Dashboard wiring: cli-registry, projects, download-session, app routes. Verified live against openclaw v2026.7.1 (tool block confirmed end-to-end; hook payloads, tool ids, and transcript schema captured from a real gateway). Tests mirror the Hermes matrix. All maps are validated, not provisional. Co-Authored-By: Claude Opus 4.8 * docs: document OpenClaw integration (CHANGELOG + CLAUDE.md) - CHANGELOG 0.0.13-beta.3 entry (Features + Docs). - CLAUDE.md "OpenClaw hooks" section: plugin-not-shell-hook enforcement surface, async-spawn design, per-hook verdict mapping, the real Stop gate, audit layout, and the auth-profile / bundledDiscovery setup gotchas. Co-Authored-By: Claude Opus 4.8 * fix(openclaw): organize dashboard by channel with readable session names Live testing surfaced two UX issues: OpenClaw routes gateway sessions through the agent's default key (agent::main) and records the channel in metadata (lastChannel / chatType / origin.{label,provider,from}), NOT in the session key. So the prior key-parsing grouped everything under "openclaw-main" (which the dashboard's decodeFolderName rendered as the confusing "openclaw/main") and named sessions with the raw "agent:main:main" key. Now group projects by channel (telegram/slack/…/local, like Hermes groups by source) and name sessions from the human-readable origin.label — so it reads as "openclaw / telegram" → "Chetan (@chhhee10) id:8674922496" with the chat id/type in the gateway-metadata columns. Verified live against openclaw v2026.7.1. Co-Authored-By: Claude Opus 4.8 * feat: remove Gemini CLI integration entirely Google retired Gemini CLI (consumer accounts stopped 2026-06-18) in favor of the closed-source Antigravity CLI (agy), which failproofai is migrating to. Removes the `gemini` id from INTEGRATION_TYPES, the INTEGRATIONS/ADAPTERS registries, KNOWN_CLI_IDS, all GEMINI_* event/tool maps, the gemini audit adapter + lib/gemini-{projects,sessions}.ts, the --cli gemini install/audit paths (bin + docs), and the dashboard's Gemini session provider. Deletes the gemini logo assets and the .gemini dogfood config. Keeps the ~/.gemini/ config-file protections in the block-* builtins and re-points them at Antigravity (which reuses that directory). Fixes a latent bug where OpenClaw sessions without a cwd were mislabeled "Gemini CLI" in the session viewer. Docs + all 14 locale mirrors swept; tsc/build/tests green (111 files, 1916 tests). Co-Authored-By: Claude Opus 4.8 * feat: add Factory droid (droid) CLI integration 9th CLI integration. Factory droid is a Claude-shaped external-shell-hook CLI, but with two contract quirks that were live-verified against droid v0.171.0 (and differ from Factory's published docs): - hooks.json uses event names at the TOP LEVEL (no `{"hooks":{...}}` wrapper — droid rejects the wrapper as unknown keys). Tool events carry matcher:"*". - deny is driven by EXIT CODE 2 + stderr, not a JSON decision (droid ignores the JSON decision field). Stop uses `{decision:"block"}` for require-*-before-stop. Payload is Claude snake_case (no normalization); FACTORY_TOOL_MAP maps Execute→Bash, Create→Write, etc. Config at ~/.factory/hooks.json (user) / .factory/hooks.json (project); binary probe `droid`. Audit reads the JSONL transcripts at ~/.factory/sessions//.jsonl (Claude-style adapter). Wires all surfaces: types union + maps, Integration + registry, canonicalize, policy-evaluator deny/instruct branches, audit adapter + lib providers, cli-registry, projects/download-session, app pages, bin VALID_CLIS + help. Adds unit + e2e + canonicalize tests, CLAUDE.md section, CHANGELOG, docs. tsc/lint clean; 1932 unit + 289 e2e tests pass; build green. Co-Authored-By: Claude Opus 4.8 * feat: add Devin CLI (devin) integration 10th CLI integration. Devin CLI is a pure Claude-clone for hooks — same snake_case payloads (hook_event_name, tool_name, tool_input, tool_use_id), so the Integration is modeled verbatim on claudeCode with a "hooks" key in ~/.config/devin/config.json (user) / .devin/config.json (project). Verified live against devin v3000.1.27: deny via {"decision":"block","reason"} on stdout blocks the tool (and overrides --permission-mode dangerous). DEVIN_TOOL_MAP maps exec→Bash (tool_input.command already canonical); no payload/event maps. Audit reads the SQLite store at ~/.local/share/devin/cli/sessions.db (sessions.working_directory → per-project grouping, message_nodes.chat_message JSON). Devin's tool_calls use a flat {id,name,arguments-as-object} shape (not the OpenAI wire form), so lib/devin-sessions.ts uses a Devin-specific normalizer; created_at prefers the higher-precision metadata ISO string. All 16 surfaces wired; unit + e2e + SQLite-parser tests added; CLAUDE.md section, CHANGELOG, docs. tsc/lint clean; 1956 unit + 297 e2e pass; build green. Co-Authored-By: Claude Opus 4.8 * feat: add Antigravity CLI (agy) integration — Gemini's successor 11th CLI integration. Antigravity CLI (`agy`, Google's closed-source Go replacement for the retired Gemini CLI) has its OWN hook contract — NOT a Claude clone. Live-verified against agy v1.1.2. - Named-hook schema: hooks.json = {"failproofai": {"PreToolUse":[{matcher,hooks}], "PreInvocation":[{...}], "Stop":[{...}]}} at ~/.gemini/config/hooks.json (user) / .agents/hooks.json (project). Tool events use a {matcher,hooks} wrapper; PreInvocation/Stop are flat handler arrays. - camelCase protojson payload → the handler normalizes toolCall.name→tool_name, toolCall.args→tool_input, conversationId→session_id, workspacePaths[0]→cwd, transcriptPath→transcript_path before the usual canonicalization. - Own response shapes: PreToolUse deny → {decision:"deny",reason}; Stop → {decision:"continue",reason} (re-enters the loop, so require-*-before-stop enforce); instruct → PreInvocation {injectSteps:[{ephemeralMessage}]}. - ANTIGRAVITY_TOOL_MAP (run_command→Bash, view_file→Read, ...) + ANTIGRAVITY_TOOL_INPUT_MAP (Bash: CommandLine→command, Cwd→cwd). - Audit reads plain JSONL transcript_full.jsonl under ~/.gemini/antigravity-cli/brain//.system_generated/logs/, indexed by conversation_summaries.db (falls back to brain/ dir scan when the index is empty). Keeps the ~/.gemini/ path guards (relabeled for Antigravity in the Gemini removal). All 16 surfaces wired; unit + e2e + parser tests; CLAUDE.md section, CHANGELOG, docs. tsc/lint clean; 1976 unit + 306 e2e pass; build green. Co-Authored-By: Claude Opus 4.8 * docs: backfill OpenClaw into user-facing docs + document VS Code coverage Two documentation gaps closed: 1. OpenClaw was shipped as a fully-wired integration but was never added to the user-facing supported-CLI lists. Backfills it into README + docs (configuration / getting-started / introduction): a dual-pillar bullet after Hermes, the --cli lists, install examples, and the detection list. 2. Documents that VS Code's Copilot Chat agent mode (Preview) needs no dedicated integration — its agent hooks load from .github/hooks/*.json, ~/.copilot/hooks/*.json, and ~/.claude/settings.json (the exact paths the copilot/claude integrations already write), verified live against VS Code 1.127 / github.copilot-chat 0.55.0. So `--cli copilot` (or --cli claude) already enforces in VS Code agent-mode sessions. Adds a CLAUDE.md section + a docs note. No code change. tsc/build/tests green (115 files, 1976 tests). Co-Authored-By: Claude Opus 4.8 * refactor: make resolve-transcript-path enumerate openclaw explicitly Add an explicit `case "openclaw"` (functionally a no-op that returns undefined, same as the default) documenting that OpenClaw's transcript_path comes from its plugin shim's stdin and its audit reads sessions directly via lib/openclaw-sessions.ts. Makes the switch cover all 11 CLIs explicitly so the wiring is unambiguous for future integrations. No behavior change. Co-Authored-By: Claude Opus 4.8 * chore: drop brittle line-number cross-refs from policy-evaluator comments Replace stale `(line ~N)` / `at line ~N` comment cross-references (which went out of date when the Gemini branches were removed and shift on every edit) with descriptive references to the mirrored per-CLI branches. Comment-only; no behavior change. Avoids automated-review flags on outdated line numbers. Co-Authored-By: Claude Opus 4.8 * feat: add Goose (codename goose, Block) as the 12th CLI integration Dual-pillar like Hermes/OpenClaw/Factory/Devin/Antigravity — real-time policy enforcement + offline audit. Enforcement uses Goose's "hooks" system (the cross-agent Open Plugins spec): the installer drops an auto-discovered plugin dir at ~/.agents/plugins/failproofai/hooks/hooks.json (user/project). Deny is {"decision":"block"} JSON on PreToolUse only (goose >= v1.37.0); goose has no Stop event, so require-*-before-stop is inapplicable (like Hermes). Audit reads the SQLite sessions.db (cwd-grouped like Devin; Claude-style content_json). Verified live end-to-end against goose v1.43.0 (real sudo blocked; real sessions.db read). Follows the Factory (enforcement) + Devin (SQLite audit) templates. Also backfills the README supported-CLI logo grid (openclaw/factory/devin/ antigravity/goose were missing) with dark/light variants, and documents Goose across CLAUDE.md + docs/{getting-started,configuration}. Co-Authored-By: Claude Opus 4.8 (1M context) * docs: link each supported-CLI logo to its official site Point the 9 logos the maintainer supplied URLs for at their official pages (codex→learn.chatgpt.com, copilot→github.com/features/copilot/cli, cursor, opencode, pi, hermes, openclaw, factory, goose→goose-docs.ai); claude/devin/ antigravity keep their existing links. Co-Authored-By: Claude Opus 4.8 (1M context) * fix(hooks): correct Antigravity file-tool map + quiet channel-less allow-notes Two issues surfaced while testing every CLI: 1. Antigravity file writes weren't gated. ANTIGRAVITY_TOOL_MAP had guessed tool names (`write_file`/`list_directory`/`find_filepath`) — the real ones (from the agy binary + live transcripts) are `write_to_file`/`list_dir`/ `find_by_name`, and there was no input-key map for file tools, so the path (delivered as `TargetFile`) never became `file_path`. Result: block-env-files / block-secrets-write silently allowed `.env` writes on Antigravity. Corrected the tool names and added Write/Edit/Read input maps (TargetFile→file_path, CodeContent→content). Verified live: agy now denies a `.env` write. 2. Noisy Stop-hook output. Informational allow-notes were emitted as stdout `{reason}` on events with no agent-facing context channel (Stop, SubagentStop, Session*, …), so a passing Stop rendered as a "…skipping commit check…skipping PR check…" wall (visible e.g. in droid). Those notes now go to stderr + the activity store only; stdout stays clean on channel-less events. Co-Authored-By: Claude Opus 4.8 (1M context) * docs(readme): arrange the 12 CLI logos as 2 rows of 6 Co-Authored-By: Claude Opus 4.8 (1M context) * fix(audit): reconstruct Devin's active conversation path (de-dup the forest) Devin stores a session's messages as a FOREST (node_id/parent_node_id) and replays earlier context under fresh roots on later turns, so message_nodes holds many branches that repeat the same messages — verified live: 26-31 raw nodes for 8-10 real messages. The parser read every node in node_id order, so the dashboard rendered each message 2-4× (a wall of duplicated "Create a file named .env…"). Reconstruct the real conversation instead: walk parent_node_id from the newest leaf (max node_id) to its root and reverse. Devin sessions now render the true 8-10 message conversation. Adds devinActiveConversationPath + unit tests. Co-Authored-By: Claude Opus 4.8 (1M context) * chore(release): finalize CHANGELOG + dogfood the 4 newest CLIs - CHANGELOG: add the missing Fixes section (Antigravity file-tool map, quiet channel-less allow-notes, Devin forest de-dup) and a Docs entry for the README logo grid. - Dogfood: ship project-scope configs for Factory (.factory/hooks.json), Devin (.devin/config.json), Antigravity (.agents/hooks.json), and Goose (.agents/plugins/failproofai/hooks/hooks.json) using the dev `bun bin/failproofai.mjs` command — generated from each integration's own writeHookEntries so they track the live schema. Documented in CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) * chore(release): bump to 0.0.14-beta.1 main shipped 0.0.13 stable (#506) without this CLI-expansion work, so it releases as 0.0.14-beta.1. Moves the branch's CHANGELOG entries into a fresh 0.0.14-beta.1 section above the released 0.0.13. Co-Authored-By: Claude Opus 4.8 (1M context) * docs(changelog): reference PR #508 Co-Authored-By: Claude Opus 4.8 (1M context) * docs: complete the dashboard + config CLI lists for all 12 agents The dashboard project-list description, session-viewer/activity badge lists, the ?cli= filter, and the auto-detect list only covered the original 7 CLIs. Add the five newer ones (OpenClaw, Factory Droid, Devin, Antigravity, Goose) with their session-store paths and badge colors. Caught by the PR #508 automated review. Co-Authored-By: Claude Opus 4.8 (1M context) --------- Co-authored-by: Claude Opus 4.8 --- .agents/hooks.json | 46 + .agents/plugins/failproofai/hooks/hooks.json | 54 ++ .devin/config.json | 88 ++ .factory/hooks.json | 112 +++ .gemini/settings.json | 147 --- CHANGELOG.md | 26 + CLAUDE.md | 477 ++++++++-- CONTRIBUTING.md | 2 +- README.md | 69 +- __tests__/actions/get-hooks-config.test.ts | 14 +- __tests__/components/project-list.test.tsx | 6 +- __tests__/e2e/helpers/hook-runner.ts | 95 +- __tests__/e2e/helpers/payloads.ts | 323 +++++-- .../hooks/antigravity-integration.e2e.test.ts | 234 +++++ .../e2e/hooks/devin-integration.e2e.test.ts | 208 +++++ .../e2e/hooks/factory-integration.e2e.test.ts | 223 +++++ .../e2e/hooks/gemini-integration.e2e.test.ts | 379 -------- .../e2e/hooks/goose-integration.e2e.test.ts | 174 ++++ .../hooks/antigravity-canonicalize.test.ts | 107 +++ __tests__/hooks/devin-canonicalize.test.ts | 51 + __tests__/hooks/factory-canonicalize.test.ts | 63 ++ __tests__/hooks/goose-canonicalize.test.ts | 102 ++ __tests__/hooks/handler.test.ts | 175 +--- __tests__/hooks/install-prompt.test.ts | 20 +- __tests__/hooks/integrations.test.ts | 667 +++++++++---- __tests__/hooks/openclaw-canonicalize.test.ts | 75 ++ __tests__/hooks/policy-evaluator.test.ts | 371 ++------ __tests__/hooks/resolve-cwd.test.ts | 1 - .../hooks/resolve-transcript-path.test.ts | 13 - __tests__/lib/cli-registry.test.ts | 11 +- __tests__/lib/devin-sessions.test.ts | 118 +++ __tests__/lib/download-session.test.ts | 5 +- __tests__/lib/gemini-projects.test.ts | 113 --- __tests__/lib/goose-sessions.test.ts | 131 +++ __tests__/lib/openclaw-projects.test.ts | 104 +++ __tests__/lib/openclaw-sessions.test.ts | 124 +++ __tests__/lib/projects.test.ts | 70 +- app/audit/_components/empty-state.tsx | 2 +- app/policies/hooks-client.tsx | 6 +- app/project/[name]/page.tsx | 40 +- .../[name]/session/[sessionId]/page.tsx | 92 +- assets/logos/antigravity.svg | 1 + assets/logos/devin.svg | 1 + assets/logos/factory-dark.png | Bin 0 -> 38436 bytes assets/logos/factory-light.png | Bin 0 -> 32933 bytes assets/logos/gemini-dark.svg | 13 - assets/logos/gemini-light.svg | 13 - assets/logos/goose-dark.svg | 1 + assets/logos/goose-light.svg | 1 + assets/logos/openclaw.svg | 22 + bin/failproofai.mjs | 49 +- docs/ar/built-in-policies.mdx | 9 +- docs/ar/cli/audit.mdx | 2 +- docs/ar/configuration.mdx | 10 +- docs/ar/dashboard.mdx | 16 +- docs/ar/getting-started.mdx | 5 +- docs/ar/introduction.mdx | 2 +- docs/built-in-policies.mdx | 9 +- docs/cli/audit.mdx | 2 +- docs/configuration.mdx | 22 +- docs/dashboard.mdx | 16 +- docs/de/built-in-policies.mdx | 9 +- docs/de/cli/audit.mdx | 2 +- docs/de/configuration.mdx | 10 +- docs/de/dashboard.mdx | 16 +- docs/de/getting-started.mdx | 5 +- docs/de/introduction.mdx | 2 +- docs/es/built-in-policies.mdx | 9 +- docs/es/cli/audit.mdx | 2 +- docs/es/configuration.mdx | 10 +- docs/es/dashboard.mdx | 16 +- docs/es/getting-started.mdx | 5 +- docs/es/introduction.mdx | 2 +- docs/fr/built-in-policies.mdx | 9 +- docs/fr/cli/audit.mdx | 2 +- docs/fr/configuration.mdx | 10 +- docs/fr/dashboard.mdx | 16 +- docs/fr/getting-started.mdx | 5 +- docs/fr/introduction.mdx | 2 +- docs/getting-started.mdx | 10 +- docs/he/built-in-policies.mdx | 9 +- docs/he/cli/audit.mdx | 2 +- docs/he/configuration.mdx | 10 +- docs/he/dashboard.mdx | 16 +- docs/he/getting-started.mdx | 5 +- docs/he/introduction.mdx | 2 +- docs/hi/built-in-policies.mdx | 9 +- docs/hi/cli/audit.mdx | 2 +- docs/hi/configuration.mdx | 10 +- docs/hi/dashboard.mdx | 16 +- docs/hi/getting-started.mdx | 5 +- docs/hi/introduction.mdx | 2 +- docs/i18n/README.ar.md | 9 +- docs/i18n/README.de.md | 9 +- docs/i18n/README.es.md | 9 +- docs/i18n/README.fr.md | 9 +- docs/i18n/README.he.md | 9 +- docs/i18n/README.hi.md | 9 +- docs/i18n/README.it.md | 9 +- docs/i18n/README.ja.md | 9 +- docs/i18n/README.ko.md | 9 +- docs/i18n/README.pt-br.md | 9 +- docs/i18n/README.ru.md | 9 +- docs/i18n/README.tr.md | 9 +- docs/i18n/README.vi.md | 9 +- docs/i18n/README.zh.md | 9 +- docs/introduction.mdx | 2 +- docs/it/built-in-policies.mdx | 7 +- docs/it/cli/audit.mdx | 2 +- docs/it/configuration.mdx | 10 +- docs/it/dashboard.mdx | 16 +- docs/it/getting-started.mdx | 5 +- docs/it/introduction.mdx | 2 +- docs/ja/built-in-policies.mdx | 9 +- docs/ja/cli/audit.mdx | 2 +- docs/ja/configuration.mdx | 10 +- docs/ja/dashboard.mdx | 16 +- docs/ja/getting-started.mdx | 5 +- docs/ja/introduction.mdx | 2 +- docs/ko/built-in-policies.mdx | 9 +- docs/ko/cli/audit.mdx | 2 +- docs/ko/configuration.mdx | 10 +- docs/ko/dashboard.mdx | 16 +- docs/ko/getting-started.mdx | 5 +- docs/ko/introduction.mdx | 2 +- docs/pt-br/built-in-policies.mdx | 7 +- docs/pt-br/cli/audit.mdx | 2 +- docs/pt-br/configuration.mdx | 10 +- docs/pt-br/dashboard.mdx | 16 +- docs/pt-br/getting-started.mdx | 5 +- docs/pt-br/introduction.mdx | 2 +- docs/ru/built-in-policies.mdx | 7 +- docs/ru/cli/audit.mdx | 2 +- docs/ru/configuration.mdx | 10 +- docs/ru/dashboard.mdx | 16 +- docs/ru/getting-started.mdx | 5 +- docs/ru/introduction.mdx | 2 +- .../config/vocabularies/Mintlify/accept.txt | 1 - docs/tr/built-in-policies.mdx | 7 +- docs/tr/cli/audit.mdx | 2 +- docs/tr/configuration.mdx | 10 +- docs/tr/dashboard.mdx | 16 +- docs/tr/getting-started.mdx | 5 +- docs/tr/introduction.mdx | 2 +- docs/vi/built-in-policies.mdx | 7 +- docs/vi/cli/audit.mdx | 2 +- docs/vi/configuration.mdx | 10 +- docs/vi/dashboard.mdx | 16 +- docs/vi/getting-started.mdx | 5 +- docs/vi/introduction.mdx | 2 +- docs/zh/built-in-policies.mdx | 9 +- docs/zh/cli/audit.mdx | 2 +- docs/zh/configuration.mdx | 10 +- docs/zh/dashboard.mdx | 16 +- docs/zh/getting-started.mdx | 5 +- docs/zh/introduction.mdx | 2 +- lib/antigravity-projects.ts | 224 +++++ lib/antigravity-sessions.ts | 283 ++++++ lib/cli-registry.ts | 32 +- lib/devin-projects.ts | 141 +++ lib/devin-sessions.ts | 343 +++++++ lib/download-session.ts | 61 +- lib/factory-projects.ts | 109 +++ lib/factory-sessions.ts | 312 +++++++ lib/gemini-projects.ts | 243 ----- lib/gemini-sessions.ts | 365 -------- lib/goose-projects.ts | 148 +++ lib/goose-sessions.ts | 296 ++++++ lib/openclaw-projects.ts | 182 ++++ lib/openclaw-sessions.ts | 284 ++++++ lib/projects.ts | 42 +- openclaw-plugin/index.js | 223 +++++ openclaw-plugin/openclaw.plugin.json | 6 + openclaw-plugin/package.json | 12 + package.json | 3 +- scripts/sync-agent-cli-harnesses-prompt.md | 17 +- src/audit/cli-adapters/antigravity.ts | 87 ++ src/audit/cli-adapters/devin.ts | 53 ++ src/audit/cli-adapters/factory.ts | 75 ++ src/audit/cli-adapters/gemini.ts | 51 - src/audit/cli-adapters/goose.ts | 53 ++ src/audit/cli-adapters/index.ts | 36 +- src/audit/cli-adapters/openclaw.ts | 56 ++ src/audit/cli.ts | 2 +- src/audit/report.ts | 2 +- src/audit/types.ts | 2 +- src/hooks/builtin-policies.ts | 10 +- src/hooks/handler.ts | 61 +- src/hooks/install-prompt.ts | 4 +- src/hooks/integrations.ts | 877 +++++++++++++++--- src/hooks/policy-evaluator.ts | 422 ++++++--- src/hooks/resolve-cwd.ts | 2 +- src/hooks/resolve-permission-mode.ts | 6 +- src/hooks/resolve-transcript-path.ts | 32 +- src/hooks/tool-name-canonicalize.ts | 32 +- src/hooks/types.ts | 538 ++++++++--- 196 files changed, 8513 insertions(+), 3247 deletions(-) create mode 100644 .agents/hooks.json create mode 100644 .agents/plugins/failproofai/hooks/hooks.json create mode 100644 .devin/config.json create mode 100644 .factory/hooks.json delete mode 100644 .gemini/settings.json create mode 100644 __tests__/e2e/hooks/antigravity-integration.e2e.test.ts create mode 100644 __tests__/e2e/hooks/devin-integration.e2e.test.ts create mode 100644 __tests__/e2e/hooks/factory-integration.e2e.test.ts delete mode 100644 __tests__/e2e/hooks/gemini-integration.e2e.test.ts create mode 100644 __tests__/e2e/hooks/goose-integration.e2e.test.ts create mode 100644 __tests__/hooks/antigravity-canonicalize.test.ts create mode 100644 __tests__/hooks/devin-canonicalize.test.ts create mode 100644 __tests__/hooks/factory-canonicalize.test.ts create mode 100644 __tests__/hooks/goose-canonicalize.test.ts create mode 100644 __tests__/hooks/openclaw-canonicalize.test.ts create mode 100644 __tests__/lib/devin-sessions.test.ts delete mode 100644 __tests__/lib/gemini-projects.test.ts create mode 100644 __tests__/lib/goose-sessions.test.ts create mode 100644 __tests__/lib/openclaw-projects.test.ts create mode 100644 __tests__/lib/openclaw-sessions.test.ts create mode 100644 assets/logos/antigravity.svg create mode 100644 assets/logos/devin.svg create mode 100644 assets/logos/factory-dark.png create mode 100644 assets/logos/factory-light.png delete mode 100644 assets/logos/gemini-dark.svg delete mode 100644 assets/logos/gemini-light.svg create mode 100644 assets/logos/goose-dark.svg create mode 100644 assets/logos/goose-light.svg create mode 100644 assets/logos/openclaw.svg create mode 100644 lib/antigravity-projects.ts create mode 100644 lib/antigravity-sessions.ts create mode 100644 lib/devin-projects.ts create mode 100644 lib/devin-sessions.ts create mode 100644 lib/factory-projects.ts create mode 100644 lib/factory-sessions.ts delete mode 100644 lib/gemini-projects.ts delete mode 100644 lib/gemini-sessions.ts create mode 100644 lib/goose-projects.ts create mode 100644 lib/goose-sessions.ts create mode 100644 lib/openclaw-projects.ts create mode 100644 lib/openclaw-sessions.ts create mode 100644 openclaw-plugin/index.js create mode 100644 openclaw-plugin/openclaw.plugin.json create mode 100644 openclaw-plugin/package.json create mode 100644 src/audit/cli-adapters/antigravity.ts create mode 100644 src/audit/cli-adapters/devin.ts create mode 100644 src/audit/cli-adapters/factory.ts delete mode 100644 src/audit/cli-adapters/gemini.ts create mode 100644 src/audit/cli-adapters/goose.ts create mode 100644 src/audit/cli-adapters/openclaw.ts diff --git a/.agents/hooks.json b/.agents/hooks.json new file mode 100644 index 00000000..f7b02da4 --- /dev/null +++ b/.agents/hooks.json @@ -0,0 +1,46 @@ +{ + "failproofai": { + "PreToolUse": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreToolUse --cli antigravity", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PostToolUse --cli antigravity", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "PreInvocation": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreInvocation --cli antigravity", + "timeout": 30, + "__failproofai_hook__": true + } + ], + "Stop": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook Stop --cli antigravity", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } +} diff --git a/.agents/plugins/failproofai/hooks/hooks.json b/.agents/plugins/failproofai/hooks/hooks.json new file mode 100644 index 00000000..3e01bf19 --- /dev/null +++ b/.agents/plugins/failproofai/hooks/hooks.json @@ -0,0 +1,54 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionStart --cli goose" + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook UserPromptSubmit --cli goose" + } + ] + } + ], + "PreToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreToolUse --cli goose" + } + ] + } + ], + "PostToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PostToolUse --cli goose" + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionEnd --cli goose" + } + ] + } + ] + } +} diff --git a/.devin/config.json b/.devin/config.json new file mode 100644 index 00000000..3b311ccd --- /dev/null +++ b/.devin/config.json @@ -0,0 +1,88 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionStart --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook UserPromptSubmit --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "PreToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreToolUse --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "PostToolUse": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PostToolUse --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "PermissionRequest": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PermissionRequest --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook Stop --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionEnd --cli devin", + "timeout": 60, + "__failproofai_hook__": true + } + ] + } + ] + } +} diff --git a/.factory/hooks.json b/.factory/hooks.json new file mode 100644 index 00000000..b2fa3660 --- /dev/null +++ b/.factory/hooks.json @@ -0,0 +1,112 @@ +{ + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionStart --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "UserPromptSubmit": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook UserPromptSubmit --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "PreToolUse": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreToolUse --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "PostToolUse": [ + { + "matcher": "*", + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PostToolUse --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "Notification": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook Notification --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "Stop": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook Stop --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "SubagentStop": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SubagentStop --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "PreCompact": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook PreCompact --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ], + "SessionEnd": [ + { + "hooks": [ + { + "type": "command", + "command": "bun bin/failproofai.mjs --hook SessionEnd --cli factory", + "timeout": 30, + "__failproofai_hook__": true + } + ] + } + ] +} diff --git a/.gemini/settings.json b/.gemini/settings.json deleted file mode 100644 index 781e6d5c..00000000 --- a/.gemini/settings.json +++ /dev/null @@ -1,147 +0,0 @@ -{ - "hooks": { - "SessionStart": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook SessionStart --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "SessionEnd": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook SessionEnd --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "BeforeAgent": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook BeforeAgent --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "AfterAgent": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook AfterAgent --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "BeforeModel": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook BeforeModel --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "AfterModel": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook AfterModel --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "BeforeToolSelection": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook BeforeToolSelection --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "BeforeTool": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook BeforeTool --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "AfterTool": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook AfterTool --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "PreCompress": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook PreCompress --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ], - "Notification": [ - { - "matcher": "*", - "hooks": [ - { - "type": "command", - "command": "bun $GEMINI_PROJECT_DIR/bin/failproofai.mjs --hook Notification --cli gemini", - "timeout": 60000, - "__failproofai_hook__": true - } - ] - } - ] - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md index 05a04f41..5b43eb5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## 0.0.14-beta.1 — 2026-07-14 + +### Features +- Add Goose (codename goose, Block) as the 12th CLI/agent integration — **dual-pillar** like Hermes/OpenClaw/Factory/Devin/Antigravity: real-time policy enforcement **and** offline audit + dashboard. Goose is a **local, MCP-based** dev-agent; enforcement uses its **"hooks" system** (the cross-agent **Open Plugins** spec) — an auto-discovered plugin dir at `~/.agents/plugins/failproofai/hooks/hooks.json` (user) / `/.agents/plugins/failproofai/hooks/hooks.json` (project) whose `command` runs `failproofai --hook --cli goose`. The entire contract was verified **live against goose v1.43.0**: (1) Deny is `{"decision":"block","reason"}` JSON on stdout at exit 0 (also exit 2), honored on **`PreToolUse` ONLY** (shipped goose ≥ **v1.37.0**, PR block/goose#9304); any other error fails **open**. `PreToolUse` fires for the shell tool AND **inside delegated subagents**, so it is the single sufficient deny point. Goose has **no `Stop` event** (the 5 `require-*-before-stop` builtins are inapplicable, like Hermes) and does not honor deny on `UserPromptSubmit`/`PostToolUse`. (2) Event names are already PascalCase (no `GOOSE_EVENT_MAP`, no handler branch), but the stdin payload uses `event`/`working_dir` — the handler normalizes `working_dir`→`cwd`. (3) Tool names arrive **both** bare (`shell`, `write`, `edit`, `view`, `read_image`, `tree`, `delegate`) **and** `__` namespaced (`todo__todo_write`); `GOOSE_TOOL_MAP` covers both, and `GOOSE_TOOL_INPUT_MAP` maps path-bearing tools' `path`/`source` → `file_path`. `instruct()` degrades to allow + stderr note (no additional-context channel). The installer just **drops the plugin dir** — Goose auto-discovers it and self-registers it into `config.yaml` (no config edit needed). Install via `failproofai policies --install --cli goose` (user + project scope). Also surfaces Goose sessions in the dashboard's audit + history browser: reads the SQLite DB at `~/.local/share/goose/sessions/sessions.db` (schema_version 15; `sessions` rows carry a real `working_dir` → per-project cwd grouping like Devin; `messages.content_json` is a Claude-style typed-block array parsed via the same block model) — `session_type='hidden'` (`--no-session`) scratch runs are filtered — via `lib/goose-sessions.ts` (pure, unit-tested parser) and `lib/goose-projects.ts`, wired through `src/audit/cli-adapters/goose.ts`, `lib/cli-registry.ts` (lime badge), `lib/projects.ts`, `lib/download-session.ts` (SQLite→JSONL export), and the `app/project/[name]` routes. `GOOSE_HOME` / `GOOSE_DB_PATH` override the data dir for tests. (#508) +- Add Antigravity CLI (`agy`) as the 11th CLI/agent integration — **dual-pillar** like Hermes/OpenClaw/Factory/Devin: real-time policy enforcement **and** offline audit + dashboard. Unlike Factory/Devin, Antigravity has its **OWN** hook contract (NOT a Claude-clone), verified **live against agy v1.1.2**. (1) `hooks.json` uses a **NAMED-hook schema** — the top-level key is a hook *name* (`"failproofai"`) whose value is an event→handlers map; tool events (`PreToolUse`/`PostToolUse`) wrap handlers in `{matcher:"*", hooks:[…]}`, while `PreInvocation`/`Stop` are **flat** handler arrays. Config at `~/.gemini/config/hooks.json` (user) / `/.agents/hooks.json` (project); no `local` scope. (2) The stdin payload is **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — the handler normalizes it to canonical snake_case before policies run; `run_command`'s args are PascalCase (`CommandLine`/`Cwd`) → canonicalized via `ANTIGRAVITY_TOOL_INPUT_MAP`. (3) Response shapes are **Antigravity's own**: deny → `{decision:"deny", reason}` (exit 0); deny/instruct on `Stop` → `{decision:"continue", reason}` (re-enters the loop, so the 5 `require-*-before-stop` builtins enforce); instruct on `PreInvocation` (→ `UserPromptSubmit`) → `{injectSteps:[{ephemeralMessage}]}`. Adds `ANTIGRAVITY_EVENT_MAP` (`PreInvocation→UserPromptSubmit`) + `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Install via `failproofai policies --install --cli antigravity` (user + project scope). Also surfaces Antigravity sessions in the dashboard's audit + history browser: reads the plain-JSONL transcripts at `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (pairing `PLANNER_RESPONSE` tool_calls with their following result step) via `lib/antigravity-sessions.ts` (pure, unit-tested parser) and the SQLite conversation index (`conversation_summaries.db`) via `lib/antigravity-projects.ts`, wired through `src/audit/cli-adapters/antigravity.ts`, `lib/cli-registry.ts` (cyan badge), `lib/projects.ts`, `lib/download-session.ts` (real-file download), and the `app/project/[name]` routes. `ANTIGRAVITY_HOME` overrides the data dir for tests. (#508) +- Add Devin CLI (`devin`, Cognition) as the 10th CLI/agent integration — **dual-pillar** like Hermes/OpenClaw/Factory: real-time policy enforcement **and** offline audit + dashboard. Devin is a **pure Claude-clone** verified **live against devin v3000.1.27** — same PascalCase event names (no `DEVIN_EVENT_MAP`, no handler branch), same snake_case stdin payload (no normalization), and the standard Claude `"hooks"`-wrapper config schema. Config lives under the `"hooks"` key of `~/.config/devin/config.json` (user) / `/.devin/config.json` (project) — merge-preserving so the file's other keys (`org_id`, `theme_mode`, …) survive. Deny is `{"decision":"block","reason"}` JSON on stdout at exit 0 for **every** event (verified — the block overrode `--permission-mode dangerous`); on `Stop` the reason carries the MANDATORY-ACTION force-retry wording, so the 5 `require-*-before-stop` builtins enforce. Adds `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` already canonical). Install via `failproofai policies --install --cli devin` (user + project scope). Also surfaces Devin sessions in the dashboard's audit + history browser: reads the SQLite DB at `~/.local/share/devin/cli/sessions.db` (`sessions` table carries a real `working_directory` → per-project cwd grouping like Claude; `message_nodes.chat_message` is OpenAI-style JSON) via `lib/devin-sessions.ts` (pure, unit-tested parser) and `lib/devin-projects.ts`, wired through `src/audit/cli-adapters/devin.ts`, `lib/cli-registry.ts` (violet badge), `lib/projects.ts`, `lib/download-session.ts` (SQLite→JSONL export), and the `app/project/[name]` routes. `DEVIN_HOME` / `DEVIN_DB_PATH` override the data dir for tests. (#508) +- Add Factory (droid) as the 9th CLI/agent integration — **dual-pillar** like Hermes/OpenClaw: real-time policy enforcement **and** offline audit + dashboard. droid ships a Claude-compatible external-command hook system, but with two schema quirks verified **live against droid v0.171.0**: (1) event names live at the **TOP LEVEL** of `~/.factory/hooks.json` — there is **no `"hooks"` wrapper** (droid rejects one with `WARN Ignoring unknown hook event keys keys:["hooks"]`); tool events (`PreToolUse`/`PostToolUse`) carry `"matcher": "*"`, non-tool events omit it. (2) Deny is driven by **exit code 2 + stderr**, not a JSON decision (droid ignores `{decision:…}` on tool events: `Hook returned exit code 2, throwing ToolExecutionControlError`); the `Stop` event is the exception — there droid honors `{decision:"block", reason}` on stdout at exit 0. Event names are already PascalCase (no `FACTORY_EVENT_MAP`, no handler branch) and the payload is Claude snake_case (no normalization). Adds `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Install via `failproofai policies --install --cli factory` (user + project scope). Also surfaces droid sessions in the dashboard's audit + history browser: reads the real JSONL transcripts at `~/.factory/sessions//.jsonl` (Claude-style encoded-cwd folders) via `lib/factory-sessions.ts` (pure, unit-tested parser) and `lib/factory-projects.ts`, wired through `src/audit/cli-adapters/factory.ts`, `lib/cli-registry.ts` (rose badge), `lib/projects.ts`, `lib/download-session.ts` (real-file download), and the `app/project/[name]` routes. (#508) +- Remove the Gemini CLI integration entirely. Google retired Gemini CLI (consumer accounts stopped serving on 2026-06-18) in favor of the closed-source **Antigravity CLI** (`agy`), which failproofai is migrating to. Drops the `gemini` id from `INTEGRATION_TYPES`, the `INTEGRATIONS`/`ADAPTERS` registries, `KNOWN_CLI_IDS`, all `GEMINI_*` event/tool maps, the `gemini` audit adapter + `lib/gemini-{projects,sessions}.ts`, the `--cli gemini` install/audit paths, and the dashboard's Gemini session provider. The `~/.gemini/` config-file protections in `block-*` builtins are **kept and re-pointed at Antigravity** (which reuses that directory). Fixes a latent bug where OpenClaw sessions without a cwd were mislabeled "Gemini CLI" in the session viewer. (#508) + +- Add OpenClaw (openclaw gateway) as the 9th CLI/agent integration — **dual-pillar** like Hermes: real-time policy enforcement **and** offline audit + dashboard. Enforcement uses OpenClaw's **in-process plugin hooks** (its file-based "internal hooks" are observation-only and cannot block), so failproofai ships a static plugin package (`openclaw-plugin/`, like `pi-extension/`) that **async-spawns** the binary (never `spawnSync` — the gateway is long-running and multi-channel) and maps a flat `{permission, reason}` verdict to each hook's native return shape: `before_tool_call → {block:true, blockReason}` (PreToolUse), `before_agent_run → {outcome:"block", reason}` (UserPromptSubmit), and `before_agent_finalize → {action:"revise", reason}` (Stop — a **real turn-end gate**, unlike Hermes which has none, so the 5 `require-*-before-stop` builtins enforce). Install (`failproofai policies --install --cli openclaw`) registers the plugin in `~/.openclaw/openclaw.json` (`plugins.load.paths` + `plugins.entries.failproofai` with `hooks.allowConversationAccess: true`), preserving operator config. Adds `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) / `OPENCLAW_TOOL_INPUT_MAP`; canonicalization stays binary-side (no inline maps in the shim). **User-scope only** (OpenClaw has no project config). Verified live against **openclaw v2026.7.1** (tool block confirmed end-to-end). (#489) +- Surface OpenClaw sessions in the dashboard's audit + history browser: reads the real JSONL transcripts at `~/.openclaw/agents//sessions/.jsonl` (skipping the heavy `.trajectory.jsonl` OTel traces) via `lib/openclaw-sessions.ts` (a pure, unit-tested type-discriminated parser that pairs assistant `toolCall` blocks with their `toolResult` by `toolCallId`) and `lib/openclaw-projects.ts` (reads the `sessions.json` index, groups by agentId into `openclaw-` projects, parses channel metadata from the sessionKey). Wired through `src/audit/cli-adapters/openclaw.ts`, `lib/cli-registry.ts` (teal badge), `lib/projects.ts`, `lib/download-session.ts` (real-file download — no synthesis needed), and the `app/project/[name]` routes. (#489) + +### Fixes +- Fix the Pi live `pi list` roundtrip e2e tests against pi-coding-agent ≥0.80: newer Pi no longer trusts project-local `.pi/settings.json` by default, so the tests now detect the installed Pi version and pass `pi list --approve` on ≥0.80 (older Pi trusts project settings without the flag and would reject it) to include the project-scope package failproofai's installer writes (previously `pi list` printed "No packages installed." — failing the install roundtrip and making the uninstall roundtrip pass vacuously). Gated behind `detectPiVersion()`, so it only runs where `pi` is installed. (#491) +- Fix Antigravity file writes slipping past path/content policies. `ANTIGRAVITY_TOOL_MAP` had best-effort tool names; the real ones (verified against the `agy` binary + live transcripts) are `write_to_file` (not `write_file`), `list_dir` (not `list_directory`), and `find_by_name` (not `find_filepath`), and there was **no** input-key map for file tools — so `write_to_file`'s path (delivered as `TargetFile`) never became `file_path` and `block-env-files` / `block-secrets-write` silently allowed `.env` writes on Antigravity. Corrected the tool names and added `Write`/`Edit`/`Read` input maps (`TargetFile`→`file_path`, `CodeContent`→`content`). Verified live: `agy` now denies a `.env` write. (#508) +- Keep informational allow-notes out of the agent-facing hook stdout on events with no additional-context channel (`Stop`, `SubagentStop`, `Session*`, `PreCompact`, …). Previously a *passing* `Stop` emitted its allow-reasons as `{reason}` on stdout, so agents like droid rendered a "…skipping commit check…skipping PR check…" wall on a perfectly fine turn. Those notes now go to stderr + the activity store only; stdout stays clean on channel-less events. (#508) +- Fix duplicated Devin session transcripts in the dashboard. Devin stores a session's messages as a **forest** (`node_id`/`parent_node_id`) and replays earlier context under fresh roots each turn, so a 10-message conversation is stored as 26-31 nodes — the parser read every node and rendered each message 2-4×. Now reconstructs the real conversation (walk `parent_node_id` from the newest leaf to its root, reversed) via `devinActiveConversationPath`. (#508) + +### Docs +- Backfill **OpenClaw** into the user-facing supported-CLI docs (README + `configuration` / `getting-started` / `introduction`) — it shipped as a wired integration but was never added to those lists. (#508) +- Add all 12 supported-CLI logos to the README (added openclaw/factory/devin/antigravity/goose with light+dark variants), link each logo to its official site, and lay them out as 2 rows of 6. (#508) +- Document that **VS Code Copilot agent mode** (Preview) is already covered by the `copilot` / `claude` integrations: its agent hooks load from `.github/hooks/*.json`, `~/.copilot/hooks/*.json`, and `~/.claude/settings.json` — the exact paths failproofai already writes — so `--cli copilot` (or `--cli claude`) enforces in VS Code agent-mode sessions with no dedicated `vscode` id. (#508) + ## 0.0.13 — 2026-07-14 ### Release @@ -13,6 +36,9 @@ ### Fixes - Fix the Pi live `pi list` roundtrip e2e tests against pi-coding-agent ≥0.80: newer Pi no longer trusts project-local `.pi/settings.json` by default, so the tests now detect the installed Pi version and pass `pi list --approve` on ≥0.80 (older Pi trusts project settings without the flag and would reject it) to include the project-scope package failproofai's installer writes (previously `pi list` printed "No packages installed." — failing the install roundtrip and making the uninstall roundtrip pass vacuously). Gated behind `detectPiVersion()`, so it only runs where `pi` is installed. (#491) +### Docs +- Document OpenClaw across `CLAUDE.md` (new "OpenClaw hooks" section), the README (install examples + logo), and the reference docs — `configuration` / `getting-started` / `dashboard` / `introduction`. (#489) + ## 0.0.13-beta.2 — 2026-07-10 ### Fixes diff --git a/CLAUDE.md b/CLAUDE.md index b5e98fd5..384737ec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -253,68 +253,9 @@ workaround (queue the instruction in `tool_call`, drain in the next `context` handler by inserting a system message into `event.messages`) is feasible but deferred until upstream Pi adds a first-class channel. -### Gemini hooks (`.gemini/settings.json`) - -This repo also ships a `.gemini/settings.json` for Gemini CLI sessions, mirroring -the `.claude/settings.json`, `.codex/hooks.json`, `.github/hooks/failproofai.json`, -`.cursor/hooks.json`, and `.opencode/` setups. Gemini's hook contract is -intentionally close to Claude Code's: same `{matcher, hooks: [{type, command, -timeout}]}` matcher-wrapper schema, same PascalCase event names, same -snake_case stdin payload field names (`session_id`, `tool_name`, `tool_input`, -`hook_event_name`, `cwd`, `transcript_path`), and a subprocess execution model. - -Verified empirically against gemini-cli v0.40.1 — drop a `.gemini/settings.json` -at the repo root and Gemini picks up failproofai hooks on the next session. -Settings file paths: - -| Scope | Path | -|---------|-----------------------------------| -| user | `~/.gemini/settings.json` | -| project | `/.gemini/settings.json` | -| system | `/etc/gemini-cli/settings.json` (documented but not exposed by failproofai) | - -Gemini exposes both `$GEMINI_PROJECT_DIR` and `$CLAUDE_PROJECT_DIR` (alias -provided for back-compat) in the hook's environment. The dogfood config in this -repo uses `$GEMINI_PROJECT_DIR` for clarity; the existing `bun -$CLAUDE_PROJECT_DIR/...` form would also work because of the alias. - -For production users (outside this repo), the recommended Gemini install is: -```bash -failproofai policies --install --cli gemini --scope project -``` -which writes a portable `npx -y failproofai --hook ... --cli gemini` command. -Same self-reference caveat applies — do **not** install the standard `npx` -form from inside this repo (it would overwrite the dev `bun bin/failproofai.mjs` -path, re-fetching failproofai on every hook). - -**Tool-name canonicalization.** Gemini's tools are snake_case -(`run_shell_command`, `read_file`, `read_many_files`, `write_file`, `replace`, -`glob`, `grep_search`, `list_directory`, `web_fetch`, `google_web_search`, -`write_todos`, `save_memory`, `ask_user`). The handler translates to Claude -PascalCase via `GEMINI_TOOL_MAP` so existing builtin policies (matching -`toolName === "Bash"` etc.) fire unchanged. Unknown tools (MCP `mcp_*`, -extensions, Skills) pass through unchanged. - -**Per-event capability matrix** (verified against gemini-cli v0.40.1 / docs as -of 2026-04-13): - -| Gemini event | Canonical | Veto / mutate? | Notes | -|------------------------|----------------------------|----------------|-------| -| `BeforeTool` | `PreToolUse` | ✅ deny | `{decision:"deny", reason}` shape; can rewrite via `hookSpecificOutput.tool_input` (not used today). | -| `AfterTool` | `PostToolUse` | observation | `additionalContext` injection supported. | -| `BeforeAgent` | `UserPromptSubmit` | ✅ deny | `{decision:"deny", reason}` + `additionalContext` injection. | -| `AfterAgent` | `Stop` | ✅ force-retry | `{decision:"block", reason}` mirrors Claude's exit-2-from-Stop "do this before stopping" semantics. Gemini's exit-2 is documented as per-action only ("turn continues"), so we use the JSON shape. | -| `SessionStart` | `SessionStart` | observation | `additionalContext` injection supported. | -| `SessionEnd` | `SessionEnd` | observation | No context-injection channel — emitted via stderr only. | -| `PreCompress` | `PreCompact` | observation | Same. | -| `Notification` | `Notification` | observation | Same. | -| `BeforeModel` | (Gemini-only, no canonical) | observation | Binary still records activity but no policies match. | -| `AfterModel` | (Gemini-only, no canonical) | observation | Same. | -| `BeforeToolSelection` | (Gemini-only, no canonical) | observation | Same. | - ### Hermes hooks (`~/.hermes/config.yaml`) -Unlike the seven CLIs above, this repo does **not** ship a dogfood Hermes config — +Unlike the six CLIs above, this repo does **not** ship a dogfood Hermes config — Hermes (hermes-agent) is a downstream client's Slack/Telegram gateway, not something we run in-repo. Hermes is a **dual-pillar** integration: an **audit** adapter (`src/audit/cli-adapters/hermes.ts`, reads `~/.hermes/state.db` directly) **and** a @@ -392,6 +333,422 @@ For production users the recommended Hermes install is: failproofai policies --install --cli hermes --scope user ``` +### OpenClaw hooks (`~/.openclaw/openclaw.json`) + +Like Hermes, this repo does **not** ship a dogfood OpenClaw config — OpenClaw +(openclaw gateway) is a downstream self-hosted assistant, not something we run +in-repo. OpenClaw is a **dual-pillar** integration: an **audit** adapter +(`src/audit/cli-adapters/openclaw.ts`, reads `~/.openclaw/agents//sessions/*.jsonl`) +**and** a **live-hook** integration (`openclaw` in `INTEGRATIONS`). + +**OpenClaw's enforcement surface is its IN-PROCESS PLUGIN hooks, not shell hooks.** +OpenClaw has two extension surfaces: file-based **internal hooks** +(`~/.openclaw/hooks/`) which are **observation-only and cannot block**, and typed +**plugin hooks** (`api.on(name, handler, {priority, timeoutMs})`) which have +block/cancel semantics. So — like OpenCode — failproofai ships a **plugin** +(`openclaw-plugin/`, a static package like `pi-extension/`, shipped in the npm +tarball via `package.json` "files") that async-spawns the binary and translates +the verdict. The install registers it in `~/.openclaw/openclaw.json` (JSON): + +- `plugins.load.paths[]` ← the shipped `openclaw-plugin/` dir (absolute path) +- `plugins.entries.failproofai = { enabled: true, hooks: { allowConversationAccess: true } }` + (`allowConversationAccess` is required for the raw-conversation hooks + `before_agent_run` / `before_agent_finalize`; verified live) + +**User-scope only** — OpenClaw has no project config (workspace plugins are +disabled by default), so `getSettingsPath` ignores scope/cwd. Uninstall only +edits `openclaw.json`; it **never deletes the shipped plugin dir**. + +**Async spawn, never `spawnSync`.** OpenClaw is a long-running multi-channel +gateway; a sync spawn on every hook would stall every channel. The shim +(`openclaw-plugin/index.js`) uses async `spawn` + a 30s guard and **fails open** +(any spawn/parse/timeout error → allow). It carries **no inline tool maps** +(unlike the OpenCode/Pi shims) — it forwards raw event/tool names and a +Claude-shaped stdin (`params→tool_input`, `toolName→tool_name`, +`transcriptPath→transcript_path`, `stopHookActive→stop_hook_active`, +`sessionKey→session_id`), and the binary canonicalizes via the `OPENCLAW_*` +maps in `types.ts` (single source of truth). + +**Verdict mapping** (`policy-evaluator.ts` emits a flat Pi-style +`{permission, reason}`; the shim maps per-hook): + +| OpenClaw plugin hook | Canonical (`OPENCLAW_EVENT_MAP`) | Veto / mutate? | Shim return on deny | +|----------------------|----------------------------------|----------------|---------------------| +| `before_tool_call` | `PreToolUse` | ✅ block | `{block: true, blockReason}` | +| `after_tool_call` | `PostToolUse` | observation | — | +| `before_agent_run` | `UserPromptSubmit`| ✅ block | `{outcome: "block", reason}` | +| `before_agent_finalize` | `Stop` | ✅ revise | `{action: "revise", reason}` | +| `session_start` / `session_end` | `SessionStart` / `SessionEnd` | observation | — | +| `subagent_ended` | `SubagentStop` | observation only | — (cannot veto) | +| `before_compaction` | `PreCompact` | observation | — | + +**`before_agent_finalize` is a real turn-end gate** (carries `transcriptPath` + +`stopHookActive`, ≈ Claude's Stop payload), so the 5 `require-*-before-stop` +builtins **enforce** on OpenClaw — a deny becomes a `{action:"revise"}` that +re-runs the turn (unlike Hermes, which has no Stop event at all). **Instruct** +degrades to allow + stderr note on non-Stop events (no additional-context +channel); on Stop it emits the MANDATORY-ACTION deny so the revise loop carries +the directive. **Omitted hooks:** `agent_end` (would double-fire Stop) and +`message_sending` (outbound-message cancel gate — an OpenClaw-only capability, +deferred). + +**No headless consent prompt** (unlike Hermes, which needed `hooks_auto_accept`) +— verified live: registering plugin hooks does not prompt on a headless gateway. + +**Setup gotcha worth knowing** (hit during live verification): a config +`env._API_KEY` is **not enough** to make a provider usable — the agent +runtime only registers a provider once an **auth profile** exists +(`openclaw models auth paste-api-key --provider

`); until then you get a +misleading `Unknown model:

/`. Also, a restrictive `plugins.allow` +gates **bundled provider discovery** (`openclaw doctor --fix` sets +`plugins.bundledDiscovery: "compat"`). + +**Audit pillar.** Sessions are real JSONL at +`~/.openclaw/agents//sessions/.jsonl` (UUID-named) + a +`sessions.json` index keyed by sessionKey. Siblings `.trajectory.jsonl` +(OTel trace) and `.trajectory-path.json` are **ignored**. `OPENCLAW_HOME` +overrides the home dir for tests. Transcript downloads stream the real file +(no synthesis, unlike Hermes). + +For production users the recommended OpenClaw install is: +```bash +failproofai policies --install --cli openclaw --scope user +``` + +### Factory droid hooks (`~/.factory/hooks.json`) + +Factory's **droid** CLI is a **dual-pillar** integration (live hooks + audit), +supporting **user + project** scope. Unlike Hermes/OpenClaw it uses a +Claude/Codex-style **external shell-hook system** — the installed command is +`bun bin/failproofai.mjs --hook --cli factory` (dev) / +`npx -y failproofai --hook --cli factory` (production project scope). +The entire contract below was **verified live against droid v0.171.0**. + +**Schema: event names at the TOP LEVEL — NO `"hooks"` wrapper.** The published +docs are **wrong**: droid rejects a `{"hooks":{…}}` wrapper with +`WARN Ignoring unknown hook event keys keys:["hooks"]`. The `hooks.json` file +**is** the events object: + +```json +{ "PreToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "…", "timeout": 30 } ] } ], + "PostToolUse": [ { "matcher": "*", "hooks": [ … ] } ], + "Stop": [ { "hooks": [ … ] } ] } +``` + +Tool events (`PreToolUse`, `PostToolUse`) MUST include `"matcher": "*"` (matches +all tools per the docs). Non-tool events use `{ "hooks": [ … ] }` with **no** +matcher. `writeHookEntries` in `integrations.ts` branches on this; the file has +**no** top-level wrapper key, so `removeHooksFromFile` / `hooksInstalledInSettings` +iterate the top-level event keys directly. + +**Events** (`FACTORY_HOOK_EVENT_TYPES`, all PascalCase): `SessionStart`, +`UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `Notification`, `Stop`, +`SubagentStop`, `PreCompact`, `SessionEnd`. Because they're already canonical +there is **no `FACTORY_EVENT_MAP` and no `handler.ts` branch**. The stdin +payload is Claude snake_case (`session_id`, `transcript_path`, `cwd`, +`permission_mode`, `hook_event_name`, `tool_name`, `tool_input:{command,…}`), so +**no payload normalization** is needed. + +**Tool-name canonicalization** (`FACTORY_TOOL_MAP`): `Execute→Bash`, `Read→Read`, +`Edit→Edit`, `Create→Write`, `Grep→Grep`, `Glob→Glob`, `LS→LS`, +`FetchUrl→WebFetch`, `WebSearch→WebSearch`, `TodoWrite→TodoWrite`, `Task→Task`. +`tool_input.command` is already the canonical Bash key, so there is **no** +`FACTORY_TOOL_INPUT_MAP`. + +**Deny contract = EXIT CODE 2 + reason on stderr** (NOT a JSON decision — droid +ignores a `{decision:…}` object on tool events and drives blocking purely off +exit code 2; verified live: `Hook returned exit code 2, throwing +ToolExecutionControlError`). The **`Stop`** event is the exception — droid does +**not** support exit-2 force-retry there, so we emit `{decision:"block", +reason}` JSON on **stdout at exit 0** (docs: "if decision is block, Droid does +not stop"). So `policy-evaluator.ts`'s `cli === "factory"` branch: Stop → +exit 0 + `{decision:"block", reason: }`; every other +event (PreToolUse, PostToolUse, …) → exit 2 + the blocked message on stderr. +`instruct()` degrades to allow + stderr note on non-Stop events (no +additional-context channel), and to the Stop `{decision:"block"}` shape on Stop. + +**Audit pillar.** Sessions are real JSONL at +`~/.factory/sessions//.jsonl` (Claude-style encoded-cwd +folders, e.g. `-home-chetan`), one per session alongside a +`.settings.json` sibling we **ignore**. JSONL lines: +`{type:"session_start", id, cwd, …}` (carries cwd), +`{type:"message", message:{role, content:[…], visibility}, timestamp, …}`, +`{type:"compaction_state", …}`. `lib/factory-sessions.ts` (pure parser, cloned +from the Claude/OpenClaw pattern) + `lib/factory-projects.ts` enumerate and +parse them; `FACTORY_HOME` overrides the home dir for tests. Transcript +downloads stream the real file (no synthesis). + +For production users the recommended Factory install is: +```bash +failproofai policies --install --cli factory --scope project +``` + +### Devin CLI hooks (`~/.config/devin/config.json` / `.devin/config.json`) + +Devin's CLI (Cognition) is a **dual-pillar** integration (live hooks + audit), +supporting **user + project** scope. It is a **pure Claude-clone** — the entire +contract below was **verified live against devin v3000.1.27** — so the +Integration in `integrations.ts` mirrors `claudeCode` verbatim, changing only +`getSettingsPath` and the `--cli devin` command flag. + +**Config lives under a Claude-style `"hooks"` key** (the file also holds +`org_id`, `theme_mode`, etc., so `readSettings`/`writeSettings` use the +merge-preserving `readJsonFile`/`writeJsonFile` helpers like Claude/Copilot): + +| Scope | Path | +|---------|-----------------------------------| +| user | `~/.config/devin/config.json` | +| project | `/.devin/config.json` | + +There is **no `local` scope**. Devin does not expose a `$DEVIN_PROJECT_DIR`; the +installed command uses `"" --hook --cli devin` (user) / +`npx -y failproofai --hook --cli devin` (project). `buildHookEntry` +emits `{type:"command", command, timeout:60, [FAILPROOFAI_HOOK_MARKER]:true}` +— Devin reads Claude's seconds-based `timeout`. + +**Events** (`DEVIN_HOOK_EVENT_TYPES`, all PascalCase → **no `DEVIN_EVENT_MAP`, +no `handler.ts` branch**): `SessionStart`, `UserPromptSubmit`, `PreToolUse`, +`PostToolUse`, `PermissionRequest`, `Stop`, `SessionEnd`. The stdin payload is +**pure Claude snake_case → no normalization**: PreToolUse `{hook_event_name, +tool_name:"exec", tool_input:{command}, tool_use_id}`; PostToolUse adds +`tool_response:{success, output, error}`; Stop `{stop_hook_active}`. + +**Tool-name canonicalization** (`DEVIN_TOOL_MAP`): `exec→Bash` only (the shell +tool; `tool_input.command` is already the canonical Bash key, so there is **no** +`DEVIN_TOOL_INPUT_MAP`). All other Devin tool names pass through unchanged. + +**Deny contract = `{"decision":"block","reason"}` JSON on stdout at exit 0** +(VERIFIED live — the block overrode `--permission-mode dangerous`). +`policy-evaluator.ts`'s `cli === "devin"` deny branch emits this shape for +**every** event: non-Stop → `{decision:"block", reason: blockedMessage}`; +Stop → `{decision:"block", reason: }` (force-retry for the +5 `require-*-before-stop` builtins). **Instruct**: Devin is Claude-compatible, so +on Stop it emits the `{decision:"block"}` MANDATORY text, and every +context-injection event falls through to the generic Claude +`{hookSpecificOutput:{hookEventName, additionalContext}}` path. + +**Audit pillar** (VERIFIED): sessions live in SQLite at +`~/.local/share/devin/cli/sessions.db`. The `sessions` table has one row per +session **with a real `working_directory`** (so sessions group by project cwd +like Claude, unlike cwd-less Hermes); `message_nodes.chat_message` is +OpenAI-style JSON (`{role, content, tool_calls?:[{id, name, arguments}], +tool_call_id?}`). `lib/devin-sessions.ts` (pure, unit-tested parser, cloned from +the Hermes SQLite pattern) + `lib/devin-projects.ts` enumerate and parse them via +the shared WAL-aware `lib/sqlite-reader.ts`; `resolve-transcript-path.ts` returns +a `devin-db://` virtual path (like opencode) and `download-session.ts` +synthesizes a JSONL export. `DEVIN_HOME` (data dir) / `DEVIN_DB_PATH` (db file) +override for tests. + +For production users the recommended Devin install is: +```bash +failproofai policies --install --cli devin --scope project +``` + +### Antigravity CLI hooks (`~/.gemini/config/hooks.json` / `.agents/hooks.json`) + +Antigravity (`agy`) is the 11th CLI — a **dual-pillar** integration (live-hook +enforcement **and** audit) that, unlike Factory/Devin, has its **OWN** hook +contract (NOT a Claude-clone). Verified **live against agy v1.1.2** (shipped +docs at `~/.gemini/antigravity-cli/builtin/skills/agy-customizations/docs/hooks.md`). +Binary probe: `agy`. + +**NAMED-hook schema.** `hooks.json`'s top-level key is a hook *name* +(`"failproofai"`), whose value is an event→handlers map. Tool events +(`PreToolUse`/`PostToolUse`) wrap handlers in a `{matcher, hooks:[…]}` group; +non-tool events (`PreInvocation`/`Stop`) are **flat** arrays of handler objects: + +```json +{ "failproofai": { + "PreToolUse": [ { "matcher": "*", "hooks": [ { "type":"command", "command":"…", "timeout":30 } ] } ], + "PostToolUse": [ { "matcher": "*", "hooks": [ { "type":"command", "command":"…", "timeout":30 } ] } ], + "PreInvocation": [ { "type":"command", "command":"…", "timeout":30 } ], + "Stop": [ { "type":"command", "command":"…", "timeout":30 } ] } } +``` + +`writeHookEntries`/`removeHooksFromFile`/`hooksInstalledInSettings` operate under +`settings.failproofai`, handling both the wrapper (`{matcher,hooks:[]}`) and flat +(`[{…}]`) shapes, and preserve any other named-hook keys (e.g. a user's +`"lint-checker"`). Multiple named hooks merge; `"enabled": false` disables one. +Settings paths: + +| Scope | Path | +|---------|-------------------------------| +| user | `~/.gemini/config/hooks.json` | +| project | `/.agents/hooks.json` | + +No `local` scope. `timeout` is in **seconds** (30). Command: project +`npx -y failproofai --hook --cli antigravity`; user +`"" --hook --cli antigravity`. `ANTIGRAVITY_HOOK_EVENT_TYPES` += `["PreToolUse","PostToolUse","PreInvocation","Stop"]`. + +**Event map.** `ANTIGRAVITY_EVENT_MAP`: `PreToolUse→PreToolUse`, +`PostToolUse→PostToolUse`, `PreInvocation→UserPromptSubmit`, `Stop→Stop`. The +`canonicalizeEventType` branch in `handler.ts` maps the `--hook` arg. + +**camelCase → snake_case normalization.** Antigravity pipes camelCase protojson. +`handler.ts` normalizes it right after `JSON.parse` (before any canonicalization): +`toolCall.{name,args}` → `tool_name`/`tool_input`, `conversationId` → +`session_id`, `workspacePaths[0]` → `cwd`, `transcriptPath` → `transcript_path`. +After that the existing extraction works. `run_command`'s args are PascalCase +(`CommandLine`/`Cwd`) → `ANTIGRAVITY_TOOL_INPUT_MAP` (keyed by canonical `Bash`) +maps them to `command`/`cwd`. Tool names via `ANTIGRAVITY_TOOL_MAP` +(`run_command→Bash` VERIFIED; `view_file→Read`, `edit_file→Edit`, … best-effort; +unknown tools pass through). + +**Response shapes (Antigravity's OWN — `policy-evaluator.ts` `cli === "antigravity"`):** + +| Case | Shape (exit 0) | +|------|----------------| +| Deny (tool/prompt events) | `{decision:"deny", reason}` | +| Deny on `Stop` | `{decision:"continue", reason}` — `"continue"` re-enters the loop (how `require-*-before-stop` enforces) | +| Instruct on `UserPromptSubmit` (canonical for `PreInvocation`) | `{injectSteps:[{ephemeralMessage:"Instruction from failproofai: …"}]}` | +| Instruct on `Stop` | `{decision:"continue", reason}` | +| Instruct on other events | stderr note only (degrade like Hermes) | + +**Audit pillar.** Plain-JSONL transcripts at +`~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` +(one step per line: `{step_index, source, type, status, created_at, content?, +tool_calls?}`). `type` enum (uppercase): `USER_INPUT` → user message, +`PLANNER_RESPONSE` (text and/or `tool_calls:[{name, args}]`) → assistant turn, +`` (e.g. `RUN_COMMAND`, the uppercased tool name) → the result step paired +back onto the matching `tool_use`, `CONVERSATION_HISTORY`/`CHECKPOINT` → skipped. +The conversation index is SQLite at `conversation_summaries.db` +(`conversation_summaries` table: `conversation_id, title, step_count, +workspace_uris, last_modified_time, …`) — read via `lib/sqlite-reader.ts` for +title/cwd enrichment, but the `brain/` transcripts are the source of truth for +existence (the DB can be checkpointed empty). `workspace_uris` gives cwd → +per-project grouping; when absent we recover cwd from the first `run_command` +`Cwd` arg, else a synthetic `antigravity` project. `lib/antigravity-sessions.ts` +(pure parser + `findAntigravityTranscript`) + `lib/antigravity-projects.ts` + +`src/audit/cli-adapters/antigravity.ts`. `ANTIGRAVITY_HOME` overrides the home +dir for tests. + +For production users the recommended Antigravity install is: +```bash +failproofai policies --install --cli antigravity --scope project +``` + +### VS Code agent hooks (covered by the `copilot` / `claude` integrations — no dedicated id) + +VS Code's built-in **Copilot Chat agent mode** (Preview, `github.copilot-chat`) +ships its own lifecycle-hooks engine, but it is NOT a separate failproofai +integration — it reuses hook-config paths failproofai already writes, so it's +covered for free. Verified live against VS Code 1.127 (`github.copilot-chat` +v0.55.0): the agent discovers and loads hook configs from **`.github/hooks/*.json`**, +**`~/.copilot/hooks/*.json`**, and **`~/.claude/settings.json`** (governed by the +`chat.hookFilesLocations` setting, whose default includes all three), using the +Claude-shaped `{hookSpecificOutput:{permissionDecision:"deny",permissionDecisionReason}}` +contract over a snake_case stdin payload. + +Those are exactly the paths the **`copilot`** integration +(`.github/hooks/failproofai.json` project, `~/.copilot/hooks/failproofai.json` +user) and the **`claude`** integration (`~/.claude/settings.json`) already write. +So **`failproofai policies --install --cli copilot`** (or `--cli claude`) already +enforces inside VS Code agent-mode sessions — no `vscode` id, no new code. (VS +Code's logs were observed loading `failproofai.json` from both `[local] .github/hooks/` +and `[user] ~/.copilot/hooks/` during a live probe.) + +**Caveat:** the hooks feature is a **Preview** and requires an active GitHub +Copilot subscription + agent mode; the OpenAI ChatGPT / Claude Code VS Code +extensions are separate runtimes (the Claude Code extension routes through +failproofai's `claude` hooks in `~/.claude/settings.json` — also already covered). + +### Goose hooks (`~/.agents/plugins/failproofai/hooks/hooks.json`) + +Goose (codename goose, Block) is a **local, MCP-based** dev-agent — a +**dual-pillar** integration (live hooks + audit) supporting **user + project** +scope. The entire contract below was **verified live against goose v1.43.0**. + +**Enforcement uses Goose's "hooks" system — the cross-agent Open Plugins spec.** +A plugin is a directory whose `hooks/hooks.json` wires shell commands into agent +events; Goose **auto-discovers** any dir under `~/.agents/plugins//` (user) +or `/.agents/plugins//` (project) at startup and **self-registers** it +into `~/.config/goose/config.yaml`. So the installer just **drops the plugin dir** +(no config edit — simpler than OpenCode). The installed command is +`bun bin/failproofai.mjs --hook --cli goose` (dev) / +`npx -y failproofai --hook --cli goose` (production). + +**Schema: an Open Plugins `hooks.json` WITH a top-level `"hooks"` wrapper** (unlike +Factory, which has none), and **the matcher is OMITTED on every event** — a bare +`"*"` is an **invalid regex that matches nothing** (verified live; omitted = match +all). failproofai owns the entire `failproofai` plugin dir, so entries stay the +clean `{type, command}` shape (**no `__failproofai_hook__` marker** — Goose parses +this file); our hooks are identified by the `--cli goose` command substring. + +```json +{ "hooks": { + "PreToolUse": [ { "hooks": [ { "type": "command", "command": "…" } ] } ], + "PostToolUse": [ { "hooks": [ … ] } ], + "SessionStart":[ { "hooks": [ … ] } ] } } +``` + +**Events** (`GOOSE_HOOK_EVENT_TYPES`, all PascalCase → **no `GOOSE_EVENT_MAP`, no +handler event branch**): `SessionStart`, `UserPromptSubmit`, `PreToolUse`, +`PostToolUse`, `SessionEnd`. The stdin payload uses `event` (not +`hook_event_name`) and `working_dir` (not `cwd`), so `handler.ts` normalizes +`working_dir`→`cwd` for goose (a small block, like Antigravity); `tool_name` / +`tool_input` are already canonical field names. + +**Deny contract = `{"decision":"block","reason"}` JSON on stdout at exit 0**, honored +on **`PreToolUse` ONLY** (shipped goose ≥ **v1.37.0**, PR block/goose#9304; exit 2 +also blocks). Any other error/timeout → **fail-open** (allow). `PreToolUse` fires +for the shell tool **and inside delegated subagents**, so it is the single +sufficient deny point. Goose has **NO `Stop` event** (the 5 +`require-*-before-stop` builtins never fire for it — inapplicable, like Hermes) and +does **not** honor deny on `UserPromptSubmit`/`PostToolUse` (observation only). So +`policy-evaluator.ts`'s `cli === "goose"` deny branch emits the block JSON for +every event (Goose honors it on PreToolUse, ignores it elsewhere — no Stop +special-case). `instruct()` degrades to **allow + stderr note** (no +additional-context channel — a non-block decision injects nothing). + +**Tool-name canonicalization** (`GOOSE_TOOL_MAP`): tool names arrive **both** bare +(`shell→Bash`, `write→Write`, `edit→Edit`, `view→Read`, `read_image→Read`, +`glob→Glob`, `grep→Grep`, `tree→LS`, `delegate→Task`) **and** `__` +namespaced (`todo__todo_write→TodoWrite`); the map covers both, unknown tools pass +through. **`GOOSE_TOOL_INPUT_MAP`** maps path-bearing tools' `path` (and +read_image's `source`) → `file_path` so path builtins fire; shell's `command` is +already canonical. + +**Audit pillar.** Sessions are SQLite at +`~/.local/share/goose/sessions/sessions.db` (schema_version 15). `sessions` rows +carry a real `working_dir`, so audit groups by project cwd like **Devin** (not +grouped-by-source like Hermes); `messages.content_json` is a **Claude-style +typed-block array** (`toolRequest`/`toolResponse`) parsed by `lib/goose-sessions.ts` +(pure, unit-tested) + `lib/goose-projects.ts`. `session_type='hidden'` +(`--no-session`) scratch runs are filtered. `GOOSE_HOME` / `GOOSE_DB_PATH` override +the data dir for tests. Transcript downloads synthesize JSONL from the rows. + +**Provider gotcha** (not failproofai's concern, but hit during live verification): +with the OS keyring disabled, goose reads the provider API key from the +**environment** (`OPENAI_API_KEY`), **not** from `config.yaml` — the YAML key is +ignored (`401 No api key passed in`). + +For production users the recommended Goose install is: +```bash +failproofai policies --install --cli goose --scope project +``` + +### Dogfood configs for Factory / Devin / Antigravity / Goose + +Like the Codex / Cursor / OpenCode / Pi setups above, this repo ships +**project-scope dogfood configs** for the four newest CLIs so failproofai +enforces on itself when you drive this repo with them. Each uses the dev +`bun bin/failproofai.mjs --hook --cli ` command (never the `npx` +production form — same self-reference caveat as the others): + +| CLI | Dogfood path | Schema | +|-----|--------------|--------| +| Factory (`droid`) | `.factory/hooks.json` | top-level event keys, `matcher:"*"` on tool events (no `"hooks"` wrapper) | +| Devin | `.devin/config.json` | Claude `"hooks"` wrapper | +| Antigravity (`agy`) | `.agents/hooks.json` | named-hook schema under the `failproofai` key | +| Goose | `.agents/plugins/failproofai/hooks/hooks.json` | Open Plugins (auto-discovered; matcher omitted — a bare `*` matches nothing) | + +These were generated from each integration's own `writeHookEntries`, so they +track the live schema. See each CLI's architecture section above for the full +contract. As with the other CLIs, do **not** run +`failproofai policies --install --cli ` from inside this repo — it would +overwrite the dev `bun bin/failproofai.mjs` path with the production `npx` form. + ## Workflow rules ### One PR per branch diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fc42a2f3..8da1b944 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -20,7 +20,7 @@ The dev server starts at `http://localhost:8020`. ### Build before the in-repo dev hooks will work This repo **dogfoods failproofai on itself**: `.claude/settings.json` (and the -sibling `.codex/`, `.cursor/`, `.gemini/`, `.github/hooks/`, … configs) register +sibling `.codex/`, `.cursor/`, `.github/hooks/`, … configs) register hooks that run `bun bin/failproofai.mjs --hook `. Those hooks load the custom policies in `.failproofai/policies/*.mjs`, which `import` the `failproofai` package — resolved against the **compiled `dist/index.js` bundle**. diff --git a/README.md b/README.md index 9fbfcdf3..7d909470 100644 --- a/README.md +++ b/README.md @@ -29,61 +29,90 @@ before they become incidents. Zero latency. Runs locally. Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Install hooks for one or any combination: `failproofai policies --install --cli opencode pi gemini` (or `--cli claude codex copilot cursor opencode pi gemini hermes`). Omit `--cli` to auto-detect installed CLIs and prompt. +> Install hooks for one or any combination: `failproofai policies --install --cli opencode pi` (or `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Omit `--cli` to auto-detect installed CLIs and prompt. > > **Hermes** (hermes-agent, a Slack/Telegram gateway) is supported for both **live-hook enforcement** (`--cli hermes` — one install intercepts tool calls from every platform and subagent) and offline **audit** replay of its gateway sessions from the single `~/.hermes/state.db`. +> +> **OpenClaw** (openclaw gateway, a self-hosted multi-channel assistant) is supported for both **live-hook enforcement** (`--cli openclaw`, user-scope) and offline **audit** replay of its JSONL sessions (`~/.openclaw/agents//sessions/*.jsonl`). Enforcement uses OpenClaw's **in-process plugin hooks** (a shipped `openclaw-plugin/` that async-spawns failproofai — its file-based internal hooks are observation-only and can't block): `before_tool_call` blocks a tool, and `before_agent_finalize` is a real turn-end gate, so the `require-*-before-stop` builtins enforce. +> +> **Factory Droid** (`droid`) is supported for both **live-hook enforcement** (`--cli factory`, user + project scope) and offline **audit** replay of its on-disk JSONL sessions. droid blocks tool calls off hook **exit code 2** (not a JSON decision) and honors `{decision:"block"}` only on the turn-end `Stop` event — failproofai emits the right shape per event automatically. +> +> **Devin CLI** (`devin`, Cognition) is supported for both **live-hook enforcement** (`--cli devin`, user + project scope) and offline **audit** replay of its SQLite sessions (`~/.local/share/devin/cli/sessions.db`). Devin is a **pure Claude-clone** — same event names, same snake_case payload, same `"hooks"`-wrapper config (`~/.config/devin/config.json` / `/.devin/config.json`) — blocking via `{decision:"block"}` JSON on every event. +> +> **Antigravity CLI** (`agy`) is supported for both **live-hook enforcement** (`--cli antigravity`, user + project scope) and offline **audit** replay of its plain-JSONL sessions (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity has its **own** contract (not a Claude-clone): a **named-hook** `hooks.json` schema (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), a camelCase stdin payload that failproofai normalizes, and its own response shapes — `{decision:"deny"}` to block a tool, `{decision:"continue"}` to force another turn at `Stop`, `{injectSteps}` to inject a reminder before the model runs. +> +> **Goose** (codename goose, Block) is supported for both **live-hook enforcement** (`--cli goose`, user + project scope) and offline **audit** replay of its SQLite sessions (`~/.local/share/goose/sessions/sessions.db`). Enforcement uses Goose's **hooks** system (the cross-agent **Open Plugins** spec) — the installer just drops a plugin dir at `~/.agents/plugins/failproofai/` and Goose auto-discovers it. Blocking is `{"decision":"block"}` JSON on the `PreToolUse` event (which fires for the shell tool and inside delegated subagents), verified live against goose v1.43.0; Goose has no turn-end `Stop` event, so the `require-*-before-stop` builtins don't apply (as with Hermes). --- diff --git a/__tests__/actions/get-hooks-config.test.ts b/__tests__/actions/get-hooks-config.test.ts index 72079bcc..b88cce8a 100644 --- a/__tests__/actions/get-hooks-config.test.ts +++ b/__tests__/actions/get-hooks-config.test.ts @@ -17,7 +17,6 @@ const installedFlags: Record = { cursor: false, opencode: false, pi: false, - gemini: false, }; const detectedFlags: Record = { @@ -27,11 +26,10 @@ const detectedFlags: Record = { cursor: false, opencode: false, pi: false, - gemini: false, }; vi.mock("@/src/hooks/integrations", () => { - const ids = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini"] as const; + const ids = ["claude", "codex", "copilot", "cursor", "opencode", "pi"] as const; const make = (id: (typeof ids)[number]) => ({ id, displayName: id, @@ -51,18 +49,18 @@ describe("getHooksConfigAction — clis payload", () => { // reset to baseline Object.assign(installedFlags, { claude: true, codex: false, copilot: false, cursor: false, - opencode: false, pi: false, gemini: false, + opencode: false, pi: false, }); Object.assign(detectedFlags, { claude: true, codex: true, copilot: false, cursor: false, - opencode: false, pi: false, gemini: false, + opencode: false, pi: false, }); }); it("returns one entry per CLI in registry order", async () => { const config = await getHooksConfigAction(); expect(config.clis.map((c) => c.id)).toEqual([ - "claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", + "claude", "codex", "copilot", "cursor", "opencode", "pi", ]); }); @@ -70,14 +68,11 @@ describe("getHooksConfigAction — clis payload", () => { const config = await getHooksConfigAction(); const claude = config.clis.find((c) => c.id === "claude")!; const codex = config.clis.find((c) => c.id === "codex")!; - const gemini = config.clis.find((c) => c.id === "gemini")!; expect(claude.installed).toBe(true); expect(claude.detected).toBe(true); expect(codex.installed).toBe(false); expect(codex.detected).toBe(true); - expect(gemini.installed).toBe(false); - expect(gemini.detected).toBe(false); }); it("carries the per-CLI user-scope settingsPath", async () => { @@ -94,6 +89,5 @@ describe("getHooksConfigAction — clis payload", () => { const config = await getHooksConfigAction(); expect(config.clis.find((c) => c.id === "claude")!.label).toBe("Claude Code"); expect(config.clis.find((c) => c.id === "codex")!.label).toBe("OpenAI Codex"); - expect(config.clis.find((c) => c.id === "gemini")!.label).toBe("Gemini CLI"); }); }); diff --git a/__tests__/components/project-list.test.tsx b/__tests__/components/project-list.test.tsx index 90ce01aa..6d5440af 100644 --- a/__tests__/components/project-list.test.tsx +++ b/__tests__/components/project-list.test.tsx @@ -252,8 +252,12 @@ describe("ProjectList", () => { "Cursor Agent", "OpenCode", "Pi", - "Gemini CLI", "Hermes", + "OpenClaw", + "Factory Droid", + "Devin CLI", + "Antigravity CLI", + "Goose", ]); }); diff --git a/__tests__/e2e/helpers/hook-runner.ts b/__tests__/e2e/helpers/hook-runner.ts index 7a8ab034..caa3919c 100644 --- a/__tests__/e2e/helpers/hook-runner.ts +++ b/__tests__/e2e/helpers/hook-runner.ts @@ -40,7 +40,7 @@ export interface HookRunResult { export function runHook( event: string, payload: Record, - opts?: { homeDir?: string; cli?: "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "gemini" }, + opts?: { homeDir?: string; cli?: "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "hermes" | "openclaw" | "factory" | "devin" | "antigravity" | "goose" }, ): HookRunResult { const binaryPath = getBinaryPath(); @@ -144,7 +144,7 @@ export function assertCursorStopBlock(result: HookRunResult): void { // Cursor's stop / subagentStop hooks honor `{followup_message}` on stdout // (exit 0) — auto-submitted as next user message, capped at loop_limit // (default 5). The flat `{permission: "deny"}` shape is ignored on Stop. - // Mirrors assertCopilotStopBlock and assertGeminiStopBlock. + // Mirrors assertCopilotStopBlock. // Ref: https://cursor.com/docs/hooks expect(result.exitCode).toBe(0); expect(typeof result.parsed?.followup_message).toBe("string"); @@ -180,30 +180,90 @@ export function assertPiAllow(result: HookRunResult): void { } } -// ── Gemini-shaped assertions ─────────────────────────────────────────────── -// Gemini uses a flat `{decision: "deny", reason}` JSON shape per its "Golden -// Rule" exit-0 contract. Stop policies emit `{decision: "block", reason}` to -// trigger AfterAgent's force-retry. Context injection uses Claude's -// `{hookSpecificOutput: {hookEventName, additionalContext}}` shape but with -// the hookEventName carrying the raw Gemini event name (BeforeTool/AfterTool/ -// BeforeAgent/SessionStart). Ref: https://geminicli.com/docs/hooks/ +// ── Factory (droid) assertions ───────────────────────────────────────────── +// Factory drives tool blocking off EXIT CODE 2 + stderr (it ignores a JSON +// decision on tool events — verified live against droid v0.171.0). The Stop +// event is the exception: droid reads `{decision:"block", reason}` on stdout. -export function assertGeminiDeny(result: HookRunResult): void { +export function assertFactoryDeny(result: HookRunResult): void { + // Non-Stop deny: exit 2, no stdout, blocked message on stderr. + expect(result.exitCode).toBe(2); + expect(result.stdout).toBe(""); + expect(result.stderr).toMatch(/Blocked/i); +} + +export function assertFactoryStopBlock(result: HookRunResult): void { + // Stop deny/instruct: droid honors `{decision:"block", reason}` on stdout at + // exit 0 ("if decision is block, Droid does not stop"). + expect(result.exitCode).toBe(0); + expect(result.parsed?.decision).toBe("block"); + expect(typeof result.parsed?.reason).toBe("string"); + expect(result.parsed?.reason).toMatch(/MANDATORY ACTION REQUIRED/); +} + +// ── Devin (Cognition) assertions ─────────────────────────────────────────── +// Devin is a pure Claude-clone that honors `{decision:"block", reason}` on +// stdout at exit 0 for EVERY event (verified live against devin v3000.1.27 — +// the block overrode `--permission-mode dangerous`). + +export function assertDevinDeny(result: HookRunResult): void { + // Non-Stop deny: exit 0, `{decision:"block", reason}` on stdout. + expect(result.exitCode).toBe(0); + expect(result.parsed?.decision).toBe("block"); + expect(typeof result.parsed?.reason).toBe("string"); +} + +export function assertDevinStopBlock(result: HookRunResult): void { + // Stop deny/instruct: `{decision:"block", reason}` carrying the force-retry + // MANDATORY ACTION wording. + expect(result.exitCode).toBe(0); + expect(result.parsed?.decision).toBe("block"); + expect(typeof result.parsed?.reason).toBe("string"); + expect(result.parsed?.reason).toMatch(/MANDATORY ACTION REQUIRED/); +} + +// ── Antigravity (agy) assertions ─────────────────────────────────────────── +// Antigravity has its OWN response shapes (NOT Claude's), verified live against +// agy v1.1.2: tool/prompt deny → `{decision:"deny", reason}` on stdout (exit 0); +// Stop deny/instruct → `{decision:"continue", reason}` (re-enters the loop); +// UserPromptSubmit instruct → `{injectSteps:[{ephemeralMessage}]}`. + +export function assertAntigravityDeny(result: HookRunResult): void { + // Tool/prompt deny: exit 0, `{decision:"deny", reason}` on stdout. expect(result.exitCode).toBe(0); expect(result.parsed?.decision).toBe("deny"); expect(typeof result.parsed?.reason).toBe("string"); expect(result.parsed?.reason).toMatch(/Blocked/i); - // Gemini uses the flat shape — no Claude-style hookSpecificOutput wrapper. - expect(result.parsed?.hookSpecificOutput).toBeUndefined(); } -export function assertGeminiStopBlock(result: HookRunResult): void { +export function assertAntigravityStopContinue(result: HookRunResult): void { + // Stop deny/instruct: `{decision:"continue", reason}` carrying the force-retry + // MANDATORY ACTION wording — "continue" re-enters the agent loop. expect(result.exitCode).toBe(0); - expect(result.parsed?.decision).toBe("block"); + expect(result.parsed?.decision).toBe("continue"); expect(typeof result.parsed?.reason).toBe("string"); expect(result.parsed?.reason).toMatch(/MANDATORY ACTION REQUIRED/); } +export function assertAntigravityInjectSteps(result: HookRunResult): void { + // UserPromptSubmit (canonical for PreInvocation) instruct → injectSteps with + // an ephemeralMessage carrying the failproofai instruction. + expect(result.exitCode).toBe(0); + const steps = result.parsed?.injectSteps as Array> | undefined; + expect(Array.isArray(steps)).toBe(true); + expect(steps?.[0]?.ephemeralMessage).toMatch(/^Instruction from failproofai:/); +} + +// ── Goose (codename goose, Block) assertions ─────────────────────────────── +// Goose honors `{decision:"block", reason}` on stdout at exit 0, on PreToolUse +// ONLY (verified live against goose v1.43.0). It has no Stop event, and does not +// honor deny on UserPromptSubmit/PostToolUse. +export function assertGooseDeny(result: HookRunResult): void { + expect(result.exitCode).toBe(0); + expect(result.parsed?.decision).toBe("block"); + expect(typeof result.parsed?.reason).toBe("string"); +} + export function assertCopilotStopBlock(result: HookRunResult): void { // Copilot's `agentStop` honors `{decision: "block", reason}` JSON on stdout // (exit 0) — the reason becomes the next-turn prompt and the agent retries. @@ -214,10 +274,3 @@ export function assertCopilotStopBlock(result: HookRunResult): void { expect(typeof result.parsed?.reason).toBe("string"); expect(result.parsed?.reason).toMatch(/MANDATORY ACTION REQUIRED/); } - -export function assertGeminiInstruct(result: HookRunResult, hookEventName: string): void { - expect(result.exitCode).toBe(0); - const output = result.parsed?.hookSpecificOutput as Record | undefined; - expect(output?.hookEventName).toBe(hookEventName); - expect(output?.additionalContext).toMatch(/^Instruction from failproofai:/); -} diff --git a/__tests__/e2e/helpers/payloads.ts b/__tests__/e2e/helpers/payloads.ts index 939ae74e..fb9918b3 100644 --- a/__tests__/e2e/helpers/payloads.ts +++ b/__tests__/e2e/helpers/payloads.ts @@ -13,9 +13,6 @@ const SESSION_ID = "test-session-e2e-001"; */ const TRANSCRIPT_PATH = "/dev/null"; -/** ISO-8601 timestamp used by integrations that include one in stdin (Gemini). */ -const TIMESTAMP = "2026-05-03T18:00:00.000Z"; - export const Payloads = { preToolUse: { bash(command: string, cwd: string): Record { @@ -591,163 +588,287 @@ export const PiPayloads = { }, }; -const GEMINI_SESSION_ID = "g1234567-9abc-7def-0123-456789abcdef"; - /** - * Gemini CLI hook payload shapes. - * - * Gemini sends Claude-shape stdin: snake_case fields (`session_id`, - * `tool_name`, `tool_input`, `hook_event_name`, `cwd`, `transcript_path`) - * plus `timestamp`. Tool names are snake_case (`run_shell_command`, - * `read_file`, `write_file`, `replace`, etc.) — the binary canonicalizes - * these to PascalCase via GEMINI_TOOL_MAP before policy lookup. - * - * Per https://geminicli.com/docs/hooks/ as of 2026-04-13. + * Factory (droid) payload factories. droid's hook stdin is Claude snake_case + * (`session_id`, `transcript_path`, `cwd`, `permission_mode`, `hook_event_name`, + * `tool_name`, `tool_input`) with already-PascalCase event names — so no payload + * or event canonicalization is needed. droid's tool registry uses + * `Execute`/`Read`/`Edit`/`Create`/… which the handler maps to Claude builtins + * via FACTORY_TOOL_MAP (see src/hooks/types.ts). Verified live against droid + * v0.171.0. */ -export const GeminiPayloads = { - beforeTool: { - runShellCommand(command: string, cwd: string): Record { +const FACTORY_SESSION_ID = "test-session-factory-001"; + +export const FactoryPayloads = { + preToolUse: { + bash(command: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: FACTORY_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeTool", - timestamp: TIMESTAMP, - tool_name: "run_shell_command", + permission_mode: "default", + hook_event_name: "PreToolUse", + tool_name: "Execute", tool_input: { command }, }; }, - readFile(filePath: string, cwd: string): Record { + write(filePath: string, content: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: FACTORY_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeTool", - timestamp: TIMESTAMP, - tool_name: "read_file", - tool_input: { file_path: filePath }, + permission_mode: "default", + hook_event_name: "PreToolUse", + tool_name: "Create", + tool_input: { file_path: filePath, content }, }; }, - writeFile(filePath: string, content: string, cwd: string): Record { + read(filePath: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: FACTORY_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeTool", - timestamp: TIMESTAMP, - tool_name: "write_file", - tool_input: { file_path: filePath, content }, + permission_mode: "default", + hook_event_name: "PreToolUse", + tool_name: "Read", + tool_input: { file_path: filePath }, }; }, - replace(filePath: string, oldStr: string, newStr: string, cwd: string): Record { + }, + postToolUse: { + bash(command: string, output: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: FACTORY_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeTool", - timestamp: TIMESTAMP, - tool_name: "replace", - tool_input: { file_path: filePath, old_string: oldStr, new_string: newStr }, + permission_mode: "default", + hook_event_name: "PostToolUse", + tool_name: "Execute", + tool_input: { command }, + tool_response: output, }; }, - mcpExtension(toolName: string, input: Record, cwd: string): Record { + }, + userPromptSubmit(prompt: string, cwd: string): Record { + return { + session_id: FACTORY_SESSION_ID, + transcript_path: TRANSCRIPT_PATH, + cwd, + permission_mode: "default", + hook_event_name: "UserPromptSubmit", + prompt, + }; + }, + stop(cwd: string): Record { + return { + session_id: FACTORY_SESSION_ID, + transcript_path: TRANSCRIPT_PATH, + cwd, + permission_mode: "default", + hook_event_name: "Stop", + }; + }, +}; + +/** + * Devin (Cognition) payload factories. Devin is a pure Claude-clone: its hook + * stdin is Claude snake_case (`session_id`, `transcript_path`, `cwd`, + * `permission_mode`, `hook_event_name`, `tool_name`, `tool_input`) with + * already-PascalCase event names — so no payload or event canonicalization is + * needed. Devin's shell tool is `exec` (mapped to Bash via DEVIN_TOOL_MAP); + * `tool_input.command` is already canonical. Verified live against devin + * v3000.1.27. + */ +const DEVIN_SESSION_ID = "test-session-devin-001"; + +export const DevinPayloads = { + preToolUse: { + bash(command: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: DEVIN_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeTool", - timestamp: TIMESTAMP, - tool_name: toolName, - tool_input: input, + permission_mode: "default", + hook_event_name: "PreToolUse", + tool_name: "exec", + tool_input: { command }, + tool_use_id: "call_devin_0001", }; }, }, - afterTool: { - runShellCommand(command: string, output: string, cwd: string): Record { + postToolUse: { + bash(command: string, output: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: DEVIN_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "AfterTool", - timestamp: TIMESTAMP, - tool_name: "run_shell_command", + permission_mode: "default", + hook_event_name: "PostToolUse", + tool_name: "exec", tool_input: { command }, - tool_response: { llmContent: output, returnDisplay: output }, + tool_response: { success: true, output, error: null }, + tool_use_id: "call_devin_0001", }; }, }, - beforeAgent(prompt: string, cwd: string): Record { + userPromptSubmit(prompt: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: DEVIN_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "BeforeAgent", - timestamp: TIMESTAMP, + permission_mode: "default", + hook_event_name: "UserPromptSubmit", prompt, }; }, - afterAgent(prompt: string, response: string, cwd: string): Record { + stop(cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, + session_id: DEVIN_SESSION_ID, transcript_path: TRANSCRIPT_PATH, cwd, - hook_event_name: "AfterAgent", - timestamp: TIMESTAMP, - prompt, - prompt_response: response, + permission_mode: "default", + hook_event_name: "Stop", stop_hook_active: false, }; }, - sessionStart(cwd: string, source: "startup" | "resume" | "clear" = "startup"): Record { - return { - session_id: GEMINI_SESSION_ID, - transcript_path: TRANSCRIPT_PATH, - cwd, - hook_event_name: "SessionStart", - timestamp: TIMESTAMP, - source, - }; +}; + +/** + * Antigravity (agy) payload factories. Antigravity pipes a camelCase protojson + * payload (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, + * `transcriptPath`) — the handler normalizes these to snake_case before + * canonicalization. `run_command`'s args are PascalCase (`CommandLine`, `Cwd`). + * Verified live against agy v1.1.2. Note: no `hook_event_name` field — the + * event comes solely from the `--hook ` arg. + */ +const ANTIGRAVITY_CONVERSATION_ID = "test-conversation-antigravity-001"; + +export const AntigravityPayloads = { + preToolUse: { + bash(command: string, cwd: string): Record { + return { + conversationId: ANTIGRAVITY_CONVERSATION_ID, + workspacePaths: [cwd], + transcriptPath: TRANSCRIPT_PATH, + modelName: "auto", + stepIdx: 19, + toolCall: { + name: "run_command", + args: { CommandLine: command, Cwd: cwd, WaitMsBeforeAsync: 5000 }, + }, + }; + }, }, - sessionEnd(cwd: string, reason: "exit" | "clear" | "logout" | "prompt_input_exit" | "other" = "exit"): Record { + postToolUse: { + bash(command: string, cwd: string): Record { + return { + conversationId: ANTIGRAVITY_CONVERSATION_ID, + workspacePaths: [cwd], + transcriptPath: TRANSCRIPT_PATH, + modelName: "auto", + stepIdx: 20, + toolCall: { + name: "run_command", + args: { CommandLine: command, Cwd: cwd }, + }, + }; + }, + }, + // PreInvocation → canonical UserPromptSubmit. + preInvocation(cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, - transcript_path: TRANSCRIPT_PATH, - cwd, - hook_event_name: "SessionEnd", - timestamp: TIMESTAMP, - reason, + conversationId: ANTIGRAVITY_CONVERSATION_ID, + workspacePaths: [cwd], + transcriptPath: TRANSCRIPT_PATH, + modelName: "auto", + invocationNum: 3, + initialNumSteps: 10, }; }, - beforeModel(cwd: string): Record { + stop(cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, - transcript_path: TRANSCRIPT_PATH, - cwd, - hook_event_name: "BeforeModel", - timestamp: TIMESTAMP, - llm_request: { model: "gemini-pro", messages: [] }, + conversationId: ANTIGRAVITY_CONVERSATION_ID, + workspacePaths: [cwd], + transcriptPath: TRANSCRIPT_PATH, + modelName: "auto", + executionNum: 1, + terminationReason: "model_stop", + fullyIdle: true, }; }, - preCompress(cwd: string): Record { +}; + +/** + * Goose (codename goose, Block) payload factories. Goose pipes a hook stdin that + * uses `event` (not `hook_event_name`), `working_dir` (not `cwd`), and + * `matcher_context` (the string the matcher regex tests). tool_name is BARE + * (`shell`, `write`, `view`) — mapped to Claude builtins via GOOSE_TOOL_MAP — + * and path-bearing tools deliver the path as `path`/`source` (→ `file_path` via + * GOOSE_TOOL_INPUT_MAP). There is NO transcript_path (audit reads sessions.db). + * Verified live against goose v1.43.0. + */ +const GOOSE_SESSION_ID = "20260714_1"; + +export const GoosePayloads = { + preToolUse: { + bash(command: string, cwd: string): Record { + return { + event: "PreToolUse", + session_id: GOOSE_SESSION_ID, + matcher_context: "shell", + tool_name: "shell", + tool_input: { command }, + working_dir: cwd, + }; + }, + write(filePath: string, content: string, cwd: string): Record { + return { + event: "PreToolUse", + session_id: GOOSE_SESSION_ID, + matcher_context: "write", + tool_name: "write", + tool_input: { path: filePath, content }, + working_dir: cwd, + }; + }, + read(filePath: string, cwd: string): Record { + return { + event: "PreToolUse", + session_id: GOOSE_SESSION_ID, + matcher_context: "view", + tool_name: "view", + tool_input: { path: filePath }, + working_dir: cwd, + }; + }, + }, + postToolUse: { + bash(command: string, cwd: string): Record { + return { + event: "PostToolUse", + session_id: GOOSE_SESSION_ID, + matcher_context: "shell", + tool_name: "shell", + tool_input: { command }, + working_dir: cwd, + }; + }, + }, + userPromptSubmit(prompt: string, cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, - transcript_path: TRANSCRIPT_PATH, - cwd, - hook_event_name: "PreCompress", - timestamp: TIMESTAMP, - trigger: "auto", + event: "UserPromptSubmit", + session_id: GOOSE_SESSION_ID, + matcher_context: prompt, + message: prompt, + working_dir: cwd, }; }, - notification(cwd: string, message = "test"): Record { + sessionStart(cwd: string): Record { return { - session_id: GEMINI_SESSION_ID, - transcript_path: TRANSCRIPT_PATH, - cwd, - hook_event_name: "Notification", - timestamp: TIMESTAMP, - notification_type: "ToolPermission", - message, - details: {}, + event: "SessionStart", + session_id: GOOSE_SESSION_ID, + matcher_context: null, + working_dir: cwd, }; }, }; diff --git a/__tests__/e2e/hooks/antigravity-integration.e2e.test.ts b/__tests__/e2e/hooks/antigravity-integration.e2e.test.ts new file mode 100644 index 00000000..313a8300 --- /dev/null +++ b/__tests__/e2e/hooks/antigravity-integration.e2e.test.ts @@ -0,0 +1,234 @@ +/** + * E2E: Antigravity (agy) hook integration. + * + * Exercises the full install → fire → decide flow using the real failproofai + * binary as a subprocess (no mocks). Antigravity has its OWN response contract + * (NOT Claude's), verified live against agy v1.1.2: + * • tool/prompt deny → `{decision:"deny", reason}` on stdout (exit 0) + * • Stop deny/instruct → `{decision:"continue", reason}` (re-enters the loop) + * • PreInvocation (→ UserPromptSubmit) instruct → `{injectSteps:[{ephemeralMessage}]}` + * The camelCase `toolCall:{name,args}` payload is normalized to snake_case by + * the handler before policies run. hooks.json uses a NAMED-hook schema. + */ +import { describe, it, expect } from "vitest"; +import { execSync } from "node:child_process"; +import { mkdtempSync, writeFileSync, readFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { + runHook, + assertAllow, + assertAntigravityDeny, + assertAntigravityStopContinue, + assertAntigravityInjectSteps, +} from "../helpers/hook-runner"; +import { AntigravityPayloads } from "../helpers/payloads"; +import { createFixtureEnv } from "../helpers/fixture-env"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); +const BINARY_PATH = resolve(REPO_ROOT, "bin/failproofai.mjs"); + +function createAntigravityEnv(): { home: string; cwd: string; cleanup: () => void } { + const home = mkdtempSync(join(tmpdir(), "fp-e2e-antigravity-home-")); + const cwd = mkdtempSync(join(tmpdir(), "fp-e2e-antigravity-cwd-")); + mkdirSync(resolve(cwd, ".failproofai"), { recursive: true }); + return { + home, + cwd, + cleanup() { + rmSync(home, { recursive: true, force: true }); + rmSync(cwd, { recursive: true, force: true }); + }, + }; +} + +function writeConfig(cwd: string, enabledPolicies: string[]): void { + const configPath = resolve(cwd, ".failproofai", "policies-config.json"); + mkdirSync(dirname(configPath), { recursive: true }); + writeFileSync(configPath, JSON.stringify({ enabledPolicies }, null, 2)); +} + +describe("E2E: Antigravity integration — hook protocol", () => { + it("PreToolUse: block-sudo denies via {decision:'deny'} JSON (exit 0)", () => { + const env = createAntigravityEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + const result = runHook( + "PreToolUse", + AntigravityPayloads.preToolUse.bash("sudo apt install foo", env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + assertAntigravityDeny(result); + } finally { + env.cleanup(); + } + }); + + it("PreToolUse: camelCase toolCall{name:run_command} is normalized + canonicalized to Bash", () => { + const env = createAntigravityEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + // toolCall.name "run_command" → tool_name → Bash; args.CommandLine → command. + const result = runHook( + "PreToolUse", + AntigravityPayloads.preToolUse.bash("sudo rm -rf /", env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + assertAntigravityDeny(result); + } finally { + env.cleanup(); + } + }); + + it("Stop deny emits {decision:'continue', reason} with MANDATORY ACTION wording", () => { + const env = createAntigravityEnv(); + try { + writeConfig(env.cwd, ["require-commit-before-stop"]); + // require-commit-before-stop denies when the cwd has uncommitted changes. + execSync( + "git init -q && git config user.email t@t && git config user.name t && touch tracked && git add tracked && git commit -q -m initial && echo dirty > tracked", + { cwd: env.cwd, env: { ...process.env, GIT_TERMINAL_PROMPT: "0" } }, + ); + const result = runHook( + "Stop", + AntigravityPayloads.stop(env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + assertAntigravityStopContinue(result); + } finally { + env.cleanup(); + } + }); + + it("PreInvocation (→ UserPromptSubmit) instruct emits {injectSteps:[{ephemeralMessage}]}", () => { + const env = createFixtureEnv(); + const hookPath = env.writeHook("instruct-prompt.mjs", ` + import { customPolicies, instruct } from "failproofai"; + customPolicies.add({ + name: "instruct-on-prompt", + description: "Always instruct on prompt submit", + match: { events: ["UserPromptSubmit"] }, + fn: async () => instruct("review the plan before acting"), + }); + `); + env.writeConfig({ enabledPolicies: [], customPoliciesPath: hookPath }); + const result = runHook( + "PreInvocation", + AntigravityPayloads.preInvocation(env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + assertAntigravityInjectSteps(result); + const steps = result.parsed?.injectSteps as Array>; + expect(String(steps[0].ephemeralMessage)).toContain("review the plan before acting"); + }); + + it("PreInvocation: allow when no policy matches", () => { + const env = createAntigravityEnv(); + try { + writeConfig(env.cwd, []); + const result = runHook( + "PreInvocation", + AntigravityPayloads.preInvocation(env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + assertAllow(result); + } finally { + env.cleanup(); + } + }); + + it("activity entry tags decision with integration: antigravity", () => { + const env = createAntigravityEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + runHook( + "PreToolUse", + AntigravityPayloads.preToolUse.bash("sudo cat /etc/passwd", env.cwd), + { homeDir: env.home, cli: "antigravity" }, + ); + const activityPath = resolve(env.home, ".failproofai", "cache", "hook-activity", "current.jsonl"); + expect(existsSync(activityPath)).toBe(true); + const lines = readFileSync(activityPath, "utf-8").trim().split("\n").filter(Boolean); + const last = JSON.parse(lines[lines.length - 1]) as Record; + expect(last.integration).toBe("antigravity"); + expect(last.decision).toBe("deny"); + } finally { + env.cleanup(); + } + }); +}); + +describe("E2E: Antigravity integration — install/uninstall", () => { + it("policies --install --cli antigravity --scope project writes .agents/hooks.json with named-hook schema", () => { + const env = createAntigravityEnv(); + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli antigravity --scope project`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH } }, + ); + const configPath = resolve(env.cwd, ".agents", "hooks.json"); + expect(existsSync(configPath)).toBe(true); + const settings = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + // Named-hook schema: our events live under the "failproofai" key. + expect(settings.failproofai).toBeDefined(); + // Tool events → {matcher:"*", hooks:[…]} wrapper. + expect(settings.failproofai.PreToolUse[0].matcher).toBe("*"); + const toolCmd = settings.failproofai.PreToolUse[0].hooks[0].command as string; + expect(toolCmd).toContain("--cli antigravity"); + // PreInvocation / Stop → flat handler objects (no wrapper). + expect(settings.failproofai.PreInvocation[0].type).toBe("command"); + expect(settings.failproofai.PreInvocation[0].hooks).toBeUndefined(); + expect(settings.failproofai.Stop[0].command).toContain("--cli antigravity"); + } finally { + env.cleanup(); + } + }); + + it("policies --install --cli antigravity --scope local fails with friendly error", () => { + const env = createAntigravityEnv(); + try { + let err: { status?: number; stderr?: Buffer } | null = null; + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli antigravity --scope local`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1" }, stdio: "pipe" }, + ); + } catch (e) { + err = e as { status?: number; stderr?: Buffer }; + } + expect(err).not.toBeNull(); + const stderr = err?.stderr?.toString() ?? ""; + expect(stderr).toMatch(/local.*not supported.*Antigravity CLI/i); + } finally { + env.cleanup(); + } + }); + + it("policies --uninstall --cli antigravity removes the failproofai named hook but preserves other named hooks", () => { + const env = createAntigravityEnv(); + try { + const baseEnv = { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH }; + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli antigravity --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const configPath = resolve(env.cwd, ".agents", "hooks.json"); + expect(existsSync(configPath)).toBe(true); + // Simulate an operator's own named hook surviving uninstall. + const withOther = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + withOther["lint-checker"] = { PostToolUse: [{ matcher: "run_command", hooks: [{ type: "command", command: "./lint.sh" }] }] }; + writeFileSync(configPath, JSON.stringify(withOther, null, 2)); + + execSync( + `bun ${BINARY_PATH} policies --uninstall --cli antigravity --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const settings = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + expect(settings.failproofai).toBeUndefined(); + expect(settings["lint-checker"]).toBeDefined(); + } finally { + env.cleanup(); + } + }); +}); diff --git a/__tests__/e2e/hooks/devin-integration.e2e.test.ts b/__tests__/e2e/hooks/devin-integration.e2e.test.ts new file mode 100644 index 00000000..a5b59f83 --- /dev/null +++ b/__tests__/e2e/hooks/devin-integration.e2e.test.ts @@ -0,0 +1,208 @@ +/** + * E2E: Devin (Cognition) hook integration. + * + * Exercises the full install → fire → decide flow using the real failproofai + * binary as a subprocess (no mocks). Each test runs against an isolated fixture + * HOME so we don't pollute the user's ~/.config/devin or ~/.devin. + * + * Devin is a pure Claude-clone: its deny contract is `{decision:"block", + * reason}` JSON on stdout at exit 0 for every event (verified live against + * devin v3000.1.27 — the block overrode `--permission-mode dangerous`). Config + * uses the standard Claude `"hooks"`-wrapper schema. + */ +import { describe, it, expect } from "vitest"; +import { execSync } from "node:child_process"; +import { mkdtempSync, writeFileSync, readFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { + runHook, + assertAllow, + assertDevinDeny, + assertDevinStopBlock, +} from "../helpers/hook-runner"; +import { DevinPayloads } from "../helpers/payloads"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); +const BINARY_PATH = resolve(REPO_ROOT, "bin/failproofai.mjs"); + +function createDevinEnv(): { home: string; cwd: string; cleanup: () => void } { + const home = mkdtempSync(join(tmpdir(), "fp-e2e-devin-home-")); + const cwd = mkdtempSync(join(tmpdir(), "fp-e2e-devin-cwd-")); + mkdirSync(resolve(cwd, ".failproofai"), { recursive: true }); + return { + home, + cwd, + cleanup() { + rmSync(home, { recursive: true, force: true }); + rmSync(cwd, { recursive: true, force: true }); + }, + }; +} + +function writeConfig(cwd: string, enabledPolicies: string[]): void { + const configPath = resolve(cwd, ".failproofai", "policies-config.json"); + mkdirSync(dirname(configPath), { recursive: true }); + writeFileSync(configPath, JSON.stringify({ enabledPolicies }, null, 2)); +} + +describe("E2E: Devin integration — hook protocol", () => { + it("PreToolUse: block-sudo denies via {decision:'block'} JSON (exit 0)", () => { + const env = createDevinEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + const result = runHook( + "PreToolUse", + DevinPayloads.preToolUse.bash("sudo apt install foo", env.cwd), + { homeDir: env.home, cli: "devin" }, + ); + assertDevinDeny(result); + } finally { + env.cleanup(); + } + }); + + it("PreToolUse: devin's `exec` tool is canonicalized to Bash", () => { + const env = createDevinEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + // tool_name: "exec" must map to Bash so block-sudo fires. + const result = runHook( + "PreToolUse", + DevinPayloads.preToolUse.bash("sudo rm -rf /", env.cwd), + { homeDir: env.home, cli: "devin" }, + ); + assertDevinDeny(result); + } finally { + env.cleanup(); + } + }); + + it("Stop deny emits {decision:'block', reason} with MANDATORY ACTION wording", () => { + const env = createDevinEnv(); + try { + writeConfig(env.cwd, ["require-commit-before-stop"]); + // require-commit-before-stop denies when the cwd has uncommitted changes. + execSync("git init -q && git config user.email t@t && git config user.name t && touch tracked && git add tracked && git commit -q -m initial && echo dirty > tracked", { + cwd: env.cwd, + env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, + }); + const result = runHook( + "Stop", + DevinPayloads.stop(env.cwd), + { homeDir: env.home, cli: "devin" }, + ); + assertDevinStopBlock(result); + } finally { + env.cleanup(); + } + }); + + it("UserPromptSubmit: allow when no policy matches", () => { + const env = createDevinEnv(); + try { + writeConfig(env.cwd, []); + const result = runHook( + "UserPromptSubmit", + DevinPayloads.userPromptSubmit("Just a normal user prompt", env.cwd), + { homeDir: env.home, cli: "devin" }, + ); + assertAllow(result); + } finally { + env.cleanup(); + } + }); + + it("activity entry tags decision with integration: devin", () => { + const env = createDevinEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + runHook( + "PreToolUse", + DevinPayloads.preToolUse.bash("sudo cat /etc/passwd", env.cwd), + { homeDir: env.home, cli: "devin" }, + ); + const activityPath = resolve(env.home, ".failproofai", "cache", "hook-activity", "current.jsonl"); + expect(existsSync(activityPath)).toBe(true); + const lines = readFileSync(activityPath, "utf-8").trim().split("\n").filter(Boolean); + const last = JSON.parse(lines[lines.length - 1]) as Record; + expect(last.integration).toBe("devin"); + expect(last.decision).toBe("deny"); + } finally { + env.cleanup(); + } + }); +}); + +describe("E2E: Devin integration — install/uninstall", () => { + it("policies --install --cli devin --scope project writes .devin/config.json with Claude-style hooks wrapper", () => { + const env = createDevinEnv(); + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli devin --scope project`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH } }, + ); + const configPath = resolve(env.cwd, ".devin", "config.json"); + expect(existsSync(configPath)).toBe(true); + const settings = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + // Claude-style `hooks` wrapper — event names live under it. + expect(settings.hooks).toBeDefined(); + expect(settings.hooks.PreToolUse).toBeDefined(); + expect(settings.hooks.PostToolUse).toBeDefined(); + expect(settings.hooks.Stop).toBeDefined(); + expect(settings.hooks.SessionStart).toBeDefined(); + const cmd = settings.hooks.PreToolUse[0].hooks[0].command as string; + expect(cmd).toContain("--cli devin"); + } finally { + env.cleanup(); + } + }); + + it("policies --install --cli devin --scope local fails with friendly error", () => { + const env = createDevinEnv(); + try { + let err: { status?: number; stderr?: Buffer } | null = null; + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli devin --scope local`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1" }, stdio: "pipe" }, + ); + } catch (e) { + err = e as { status?: number; stderr?: Buffer }; + } + expect(err).not.toBeNull(); + const stderr = err?.stderr?.toString() ?? ""; + expect(stderr).toMatch(/local.*not supported.*Devin CLI/i); + } finally { + env.cleanup(); + } + }); + + it("policies --uninstall --cli devin removes hooks but preserves other config keys", () => { + const env = createDevinEnv(); + try { + const baseEnv = { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH }; + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli devin --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const configPath = resolve(env.cwd, ".devin", "config.json"); + expect(existsSync(configPath)).toBe(true); + // Simulate an operator's own key surviving uninstall. + const withOrg = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + withOrg.org_id = "acme"; + writeFileSync(configPath, JSON.stringify(withOrg, null, 2)); + + execSync( + `bun ${BINARY_PATH} policies --uninstall --cli devin --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const settings = JSON.parse(readFileSync(configPath, "utf-8")) as Record; + expect(settings.hooks).toBeUndefined(); + expect(settings.org_id).toBe("acme"); + } finally { + env.cleanup(); + } + }); +}); diff --git a/__tests__/e2e/hooks/factory-integration.e2e.test.ts b/__tests__/e2e/hooks/factory-integration.e2e.test.ts new file mode 100644 index 00000000..9986f308 --- /dev/null +++ b/__tests__/e2e/hooks/factory-integration.e2e.test.ts @@ -0,0 +1,223 @@ +/** + * E2E: Factory (droid) hook integration. + * + * Exercises the full install → fire → decide flow using the real failproofai + * binary as a subprocess (no mocks). Each test runs against an isolated fixture + * HOME so we don't pollute the user's ~/.factory/. + * + * Factory's deny contract is EXIT CODE 2 + stderr (droid ignores JSON decisions + * on tool events); Stop is the exception — droid honors `{decision:"block"}`. + * Verified live against droid v0.171.0. + */ +import { describe, it, expect } from "vitest"; +import { execSync } from "node:child_process"; +import { mkdtempSync, writeFileSync, readFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { + runHook, + assertAllow, + assertFactoryDeny, + assertFactoryStopBlock, +} from "../helpers/hook-runner"; +import { FactoryPayloads } from "../helpers/payloads"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); +const BINARY_PATH = resolve(REPO_ROOT, "bin/failproofai.mjs"); + +function createFactoryEnv(): { home: string; cwd: string; cleanup: () => void } { + const home = mkdtempSync(join(tmpdir(), "fp-e2e-factory-home-")); + const cwd = mkdtempSync(join(tmpdir(), "fp-e2e-factory-cwd-")); + mkdirSync(resolve(cwd, ".failproofai"), { recursive: true }); + return { + home, + cwd, + cleanup() { + rmSync(home, { recursive: true, force: true }); + rmSync(cwd, { recursive: true, force: true }); + }, + }; +} + +function writeConfig(cwd: string, enabledPolicies: string[]): void { + const configPath = resolve(cwd, ".failproofai", "policies-config.json"); + mkdirSync(dirname(configPath), { recursive: true }); + writeFileSync(configPath, JSON.stringify({ enabledPolicies }, null, 2)); +} + +describe("E2E: Factory integration — hook protocol", () => { + it("PreToolUse: block-sudo denies via EXIT CODE 2 + stderr (not JSON)", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + const result = runHook( + "PreToolUse", + FactoryPayloads.preToolUse.bash("sudo apt install foo", env.cwd), + { homeDir: env.home, cli: "factory" }, + ); + assertFactoryDeny(result); + } finally { + env.cleanup(); + } + }); + + it("PreToolUse: droid's `Execute` tool is canonicalized to Bash", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + // tool_name: "Execute" must map to Bash so block-sudo fires. + const result = runHook( + "PreToolUse", + FactoryPayloads.preToolUse.bash("sudo rm -rf /", env.cwd), + { homeDir: env.home, cli: "factory" }, + ); + assertFactoryDeny(result); + } finally { + env.cleanup(); + } + }); + + it("PostToolUse: deny also uses exit-2 + stderr", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, ["sanitize-jwt"]); + const result = runHook( + "PostToolUse", + FactoryPayloads.postToolUse.bash( + "echo done", + "JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTYifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c", + env.cwd, + ), + { homeDir: env.home, cli: "factory" }, + ); + assertFactoryDeny(result); + } finally { + env.cleanup(); + } + }); + + it("Stop deny emits {decision:'block', reason} JSON (droid's turn-end retry shape)", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, ["require-commit-before-stop"]); + // require-commit-before-stop denies when the cwd has uncommitted changes. + execSync("git init -q && git config user.email t@t && git config user.name t && touch tracked && git add tracked && git commit -q -m initial && echo dirty > tracked", { + cwd: env.cwd, + env: { ...process.env, GIT_TERMINAL_PROMPT: "0" }, + }); + const result = runHook( + "Stop", + FactoryPayloads.stop(env.cwd), + { homeDir: env.home, cli: "factory" }, + ); + assertFactoryStopBlock(result); + } finally { + env.cleanup(); + } + }); + + it("UserPromptSubmit: allow when no policy matches", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, []); + const result = runHook( + "UserPromptSubmit", + FactoryPayloads.userPromptSubmit("Just a normal user prompt", env.cwd), + { homeDir: env.home, cli: "factory" }, + ); + assertAllow(result); + } finally { + env.cleanup(); + } + }); + + it("activity entry tags decision with integration: factory", () => { + const env = createFactoryEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + runHook( + "PreToolUse", + FactoryPayloads.preToolUse.bash("sudo cat /etc/passwd", env.cwd), + { homeDir: env.home, cli: "factory" }, + ); + const activityPath = resolve(env.home, ".failproofai", "cache", "hook-activity", "current.jsonl"); + expect(existsSync(activityPath)).toBe(true); + const lines = readFileSync(activityPath, "utf-8").trim().split("\n").filter(Boolean); + const last = JSON.parse(lines[lines.length - 1]) as Record; + expect(last.integration).toBe("factory"); + expect(last.decision).toBe("deny"); + } finally { + env.cleanup(); + } + }); +}); + +describe("E2E: Factory integration — install/uninstall", () => { + it("policies --install --cli factory --scope project writes .factory/hooks.json with TOP-LEVEL event keys", () => { + const env = createFactoryEnv(); + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli factory --scope project`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH } }, + ); + const hooksPath = resolve(env.cwd, ".factory", "hooks.json"); + expect(existsSync(hooksPath)).toBe(true); + const settings = JSON.parse(readFileSync(hooksPath, "utf-8")) as Record; + // No `hooks` wrapper — event names live at the top level. + expect(settings.hooks).toBeUndefined(); + expect(settings.PreToolUse).toBeDefined(); + expect(settings.PostToolUse).toBeDefined(); + expect(settings.Stop).toBeDefined(); + expect(settings.SessionStart).toBeDefined(); + // Tool events carry matcher:"*"; Stop does not. + expect(settings.PreToolUse[0].matcher).toBe("*"); + expect(settings.Stop[0].matcher).toBeUndefined(); + } finally { + env.cleanup(); + } + }); + + it("policies --install --cli factory --scope local fails with friendly error", () => { + const env = createFactoryEnv(); + try { + let err: { status?: number; stderr?: Buffer } | null = null; + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli factory --scope local`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1" }, stdio: "pipe" }, + ); + } catch (e) { + err = e as { status?: number; stderr?: Buffer }; + } + expect(err).not.toBeNull(); + const stderr = err?.stderr?.toString() ?? ""; + expect(stderr).toMatch(/local.*not supported.*Factory Droid/i); + } finally { + env.cleanup(); + } + }); + + it("policies --uninstall --cli factory removes hooks from .factory/hooks.json", () => { + const env = createFactoryEnv(); + try { + const baseEnv = { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH }; + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli factory --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const hooksPath = resolve(env.cwd, ".factory", "hooks.json"); + expect(existsSync(hooksPath)).toBe(true); + + execSync( + `bun ${BINARY_PATH} policies --uninstall --cli factory --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const settings = JSON.parse(readFileSync(hooksPath, "utf-8")) as Record; + expect(settings.PreToolUse).toBeUndefined(); + expect(settings.Stop).toBeUndefined(); + } finally { + env.cleanup(); + } + }); +}); diff --git a/__tests__/e2e/hooks/gemini-integration.e2e.test.ts b/__tests__/e2e/hooks/gemini-integration.e2e.test.ts deleted file mode 100644 index f53da58a..00000000 --- a/__tests__/e2e/hooks/gemini-integration.e2e.test.ts +++ /dev/null @@ -1,379 +0,0 @@ -/** - * E2E: Gemini CLI hook integration. - * - * Exercises the full install → fire → decide flow using the real failproofai - * binary as a subprocess (no mocks). Each test runs against an isolated - * fixture HOME so we don't pollute the user's ~/.gemini/. - * - * Verifies four invariants that distinguish Gemini from the other 6 CLIs: - * 1. Tool-name canonicalization (run_shell_command → Bash, etc.) - * 2. Event-name canonicalization (BeforeTool → PreToolUse, etc.) - * 3. Flat `{decision: "deny", reason}` shape (NOT Claude's hookSpecificOutput) - * 4. AfterAgent → `{decision: "block", reason}` for Stop policies - */ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs"; -import { tmpdir } from "node:os"; -import { join, resolve, dirname } from "node:path"; -import { - runHook, - assertAllow, - assertGeminiDeny, - assertGeminiStopBlock, - assertGeminiInstruct, -} from "../helpers/hook-runner"; -import { GeminiPayloads } from "../helpers/payloads"; - -function createGeminiEnv(): { home: string; cwd: string; cleanup: () => void } { - const home = mkdtempSync(join(tmpdir(), "fp-e2e-gemini-home-")); - const cwd = mkdtempSync(join(tmpdir(), "fp-e2e-gemini-cwd-")); - // Pre-create the .failproofai dir under cwd so the parent-walk finds it. - mkdirSync(resolve(cwd, ".failproofai"), { recursive: true }); - return { - home, - cwd, - cleanup() { - rmSync(home, { recursive: true, force: true }); - rmSync(cwd, { recursive: true, force: true }); - }, - }; -} - -function writeConfig(cwd: string, enabledPolicies: string[], policyParams?: Record>): void { - const configPath = resolve(cwd, ".failproofai", "policies-config.json"); - mkdirSync(dirname(configPath), { recursive: true }); - writeFileSync(configPath, JSON.stringify({ enabledPolicies, ...(policyParams ? { policyParams } : {}) }, null, 2)); -} - -describe("E2E: Gemini integration — hook protocol", () => { - describe("Tool-name canonicalization (snake_case → Claude PascalCase)", () => { - it("run_shell_command + sudo → Bash → block-sudo deny shape", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.runShellCommand("sudo apt install foo", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertGeminiDeny(result); - expect(result.parsed?.reason).toMatch(/Bash/); - // Confirm canonicalization actually mapped run_shell_command → Bash by - // checking the deny message references the canonical tool name. - expect(result.parsed?.reason).not.toMatch(/run_shell_command/); - } finally { - env.cleanup(); - } - }); - - it("run_shell_command + rm -rf / → Bash → block-rm-rf deny shape", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-rm-rf"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.runShellCommand("rm -rf /", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertGeminiDeny(result); - expect(result.parsed?.reason).toMatch(/Bash/); - } finally { - env.cleanup(); - } - }); - - it("read_file outside cwd → Read → block-read-outside-cwd deny shape", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-read-outside-cwd"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.readFile("/etc/passwd", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertGeminiDeny(result); - expect(result.parsed?.reason).toMatch(/Read/); - } finally { - env.cleanup(); - } - }); - - it("write_file inside cwd → Write → allow", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-rm-rf"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.writeFile(`${env.cwd}/foo.txt`, "hello", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertAllow(result); - } finally { - env.cleanup(); - } - }); - - it("MCP tool name (mcp_github_create_issue) passes through unchanged", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.mcpExtension("mcp_github_create_issue", { title: "x" }, env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - // Unknown tool, no policy matches → allow with empty stdout - assertAllow(result); - } finally { - env.cleanup(); - } - }); - }); - - describe("Event-name canonicalization (Gemini PascalCase → Claude canonical)", () => { - it("BeforeTool → PreToolUse — block-sudo fires on the canonical event", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.runShellCommand("sudo ls", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertGeminiDeny(result); - } finally { - env.cleanup(); - } - }); - - it("BeforeAgent → UserPromptSubmit — fires on the canonical event", () => { - const env = createGeminiEnv(); - try { - // No deny policy for UserPromptSubmit by default; this just verifies - // the event name canonicalizes without crashing and exits 0. - writeConfig(env.cwd, []); - const result = runHook( - "BeforeAgent", - GeminiPayloads.beforeAgent("hello", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertAllow(result); - } finally { - env.cleanup(); - } - }); - - it("AfterTool → PostToolUse — fires without crashing on benign payload", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - const result = runHook( - "AfterTool", - GeminiPayloads.afterTool.runShellCommand("ls", "file1\nfile2", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertAllow(result); - } finally { - env.cleanup(); - } - }); - - it("AfterAgent → Stop — fires without crashing on benign payload", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - const result = runHook( - "AfterAgent", - GeminiPayloads.afterAgent("hi", "hello", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - // No Stop policies enabled → exit 0 with no stdout - expect(result.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - - it("BeforeModel — Gemini-only event with no canonical, exits 0 with no stdout", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - const result = runHook( - "BeforeModel", - GeminiPayloads.beforeModel(env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - // BeforeModel has no canonical Claude event, so getPoliciesForEvent → [] - expect(result.exitCode).toBe(0); - expect(result.stdout).toBe(""); - } finally { - env.cleanup(); - } - }); - - it("PreCompress → PreCompact — passes through (no policies match by default)", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - const result = runHook( - "PreCompress", - GeminiPayloads.preCompress(env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - expect(result.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - - it("Notification — passes through without crashing", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - const result = runHook( - "Notification", - GeminiPayloads.notification(env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - expect(result.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - - it("SessionStart and SessionEnd both exit 0 cleanly", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - const start = runHook( - "SessionStart", - GeminiPayloads.sessionStart(env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - expect(start.exitCode).toBe(0); - const end = runHook( - "SessionEnd", - GeminiPayloads.sessionEnd(env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - expect(end.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - }); - - describe("Response-shape correctness (Gemini-specific JSON, NOT Claude's)", () => { - it("BeforeTool deny → flat {decision:'deny', reason}, NO hookSpecificOutput wrapper", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.runShellCommand("sudo apt update", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - assertGeminiDeny(result); - // Crucial regression guard: not Claude's nested shape - expect(result.parsed?.hookSpecificOutput).toBeUndefined(); - // Not Cursor's `permission` field - expect(result.parsed?.permission).toBeUndefined(); - // Not Codex's PermissionRequest decision shape - const out = result.parsed?.hookSpecificOutput as Record | undefined; - expect(out?.decision).toBeUndefined(); - } finally { - env.cleanup(); - } - }); - - it("AfterAgent (Stop) deny → {decision:'block', reason} with MANDATORY ACTION REQUIRED", () => { - const env = createGeminiEnv(); - try { - // Force a Stop deny by enabling a require-* policy and missing what it requires. - // The exact policy isn't important; we just want a Stop-event deny path. - writeConfig(env.cwd, ["require-pr-before-stop"]); - const result = runHook( - "AfterAgent", - GeminiPayloads.afterAgent("hi", "hello", env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - // Either deny (no PR found) → block; or allow if branch is somehow ok. - // Branch on what we got — but assert that *if* there's a stdout JSON, it - // uses block (not deny) for AfterAgent. - if (result.stdout) { - assertGeminiStopBlock(result); - } - } finally { - env.cleanup(); - } - }); - - it("Stdin >1MB is discarded gracefully (matches handler.ts:73 cap)", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, []); - // 1.1 MB padding pushes the stdin past the limit - const huge = "x".repeat(1_200_000); - const result = runHook( - "BeforeTool", - { ...GeminiPayloads.beforeTool.runShellCommand("ls", env.cwd), padding: huge }, - { homeDir: env.home, cli: "gemini" }, - ); - // The handler discards the payload and falls open to allow with no stdout - expect(result.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - - it("Malformed stdin JSON falls open to allow (no crash)", () => { - const env = createGeminiEnv(); - try { - writeConfig(env.cwd, ["block-sudo"]); - // Manually corrupt by passing a string (runHook stringifies, so wrap in - // an object with one key whose value can't be properly used) — easier: - // pass an empty object so policies have nothing to match on. - const result = runHook( - "BeforeTool", - {} as Record, - { homeDir: env.home, cli: "gemini" }, - ); - expect(result.exitCode).toBe(0); - } finally { - env.cleanup(); - } - }); - }); - - describe("Tool-name canonicalization edge cases", () => { - it("Every documented Gemini tool name canonicalizes correctly when piped through deny path", () => { - const env = createGeminiEnv(); - try { - // Use sanitize-api-keys which fires on Read for both raw `read_file` and `read_many_files` - // — picks up the canonical "Read" name regardless of which Gemini tool name was used. - writeConfig(env.cwd, []); - const cases = [ - { gemini: "run_shell_command", input: { command: "echo hi" } }, - { gemini: "read_file", input: { file_path: `${env.cwd}/foo.txt` } }, - { gemini: "read_many_files", input: { file_paths: [`${env.cwd}/foo.txt`] } }, - { gemini: "write_file", input: { file_path: `${env.cwd}/bar.txt`, content: "x" } }, - { gemini: "replace", input: { file_path: `${env.cwd}/bar.txt`, old_string: "x", new_string: "y" } }, - { gemini: "glob", input: { pattern: "*.ts" } }, - { gemini: "grep_search", input: { pattern: "foo" } }, - { gemini: "list_directory", input: { path: env.cwd } }, - ]; - for (const c of cases) { - const result = runHook( - "BeforeTool", - GeminiPayloads.beforeTool.mcpExtension(c.gemini, c.input, env.cwd), - { homeDir: env.home, cli: "gemini" }, - ); - // No deny policy enabled → allow regardless - expect(result.exitCode).toBe(0); - } - } finally { - env.cleanup(); - } - }); - }); -}); diff --git a/__tests__/e2e/hooks/goose-integration.e2e.test.ts b/__tests__/e2e/hooks/goose-integration.e2e.test.ts new file mode 100644 index 00000000..b895a0ef --- /dev/null +++ b/__tests__/e2e/hooks/goose-integration.e2e.test.ts @@ -0,0 +1,174 @@ +/** + * E2E: Goose (codename goose, Block) hook integration. + * + * Exercises the full install → fire → decide flow using the real failproofai + * binary as a subprocess (no mocks). Each test runs against an isolated fixture + * HOME/cwd so we don't pollute the user's ~/.agents/plugins/. + * + * Goose's deny contract is `{decision:"block", reason}` JSON on stdout at exit 0, + * honored on PreToolUse ONLY (goose has no Stop event). Its stdin uses `event` / + * `working_dir` (normalized in handler.ts) and BARE tool names mapped via + * GOOSE_TOOL_MAP. Verified live against goose v1.43.0. + */ +import { describe, it, expect } from "vitest"; +import { execSync } from "node:child_process"; +import { mkdtempSync, writeFileSync, readFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; +import { runHook, assertAllow, assertGooseDeny } from "../helpers/hook-runner"; +import { GoosePayloads } from "../helpers/payloads"; + +const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../.."); +const BINARY_PATH = resolve(REPO_ROOT, "bin/failproofai.mjs"); + +function createGooseEnv(): { home: string; cwd: string; cleanup: () => void } { + const home = mkdtempSync(join(tmpdir(), "fp-e2e-goose-home-")); + const cwd = mkdtempSync(join(tmpdir(), "fp-e2e-goose-cwd-")); + mkdirSync(resolve(cwd, ".failproofai"), { recursive: true }); + return { + home, + cwd, + cleanup() { + rmSync(home, { recursive: true, force: true }); + rmSync(cwd, { recursive: true, force: true }); + }, + }; +} + +function writeConfig(cwd: string, enabledPolicies: string[]): void { + const configPath = resolve(cwd, ".failproofai", "policies-config.json"); + mkdirSync(dirname(configPath), { recursive: true }); + writeFileSync(configPath, JSON.stringify({ enabledPolicies }, null, 2)); +} + +describe("E2E: Goose integration — hook protocol", () => { + it("PreToolUse: block-sudo denies via {decision:'block'} JSON (goose's shell → Bash)", () => { + const env = createGooseEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + // tool_name "shell" must canonicalize to Bash so block-sudo fires. + const result = runHook( + "PreToolUse", + GoosePayloads.preToolUse.bash("sudo apt install foo", env.cwd), + { homeDir: env.home, cli: "goose" }, + ); + assertGooseDeny(result); + } finally { + env.cleanup(); + } + }); + + it("PreToolUse: write's `path` is canonicalized to file_path so block-env-files fires", () => { + const env = createGooseEnv(); + try { + writeConfig(env.cwd, ["block-env-files"]); + // goose `write` delivers the path as `path`; without the input map, + // block-env-files (which reads file_path) would silently no-op. + const result = runHook( + "PreToolUse", + GoosePayloads.preToolUse.write(resolve(env.cwd, ".env"), "SECRET=abc123", env.cwd), + { homeDir: env.home, cli: "goose" }, + ); + assertGooseDeny(result); + } finally { + env.cleanup(); + } + }); + + it("UserPromptSubmit: allow when no policy matches", () => { + const env = createGooseEnv(); + try { + writeConfig(env.cwd, []); + const result = runHook( + "UserPromptSubmit", + GoosePayloads.userPromptSubmit("Just a normal user prompt", env.cwd), + { homeDir: env.home, cli: "goose" }, + ); + assertAllow(result); + } finally { + env.cleanup(); + } + }); + + it("PreToolUse: allow when the command is harmless", () => { + const env = createGooseEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + const result = runHook( + "PreToolUse", + GoosePayloads.preToolUse.bash("echo hello", env.cwd), + { homeDir: env.home, cli: "goose" }, + ); + assertAllow(result); + } finally { + env.cleanup(); + } + }); + + it("activity entry tags decision with integration: goose", () => { + const env = createGooseEnv(); + try { + writeConfig(env.cwd, ["block-sudo"]); + runHook( + "PreToolUse", + GoosePayloads.preToolUse.bash("sudo cat /etc/passwd", env.cwd), + { homeDir: env.home, cli: "goose" }, + ); + const activityPath = resolve(env.home, ".failproofai", "cache", "hook-activity", "current.jsonl"); + expect(existsSync(activityPath)).toBe(true); + const lines = readFileSync(activityPath, "utf-8").trim().split("\n").filter(Boolean); + const last = JSON.parse(lines[lines.length - 1]) as Record; + expect(last.integration).toBe("goose"); + expect(last.decision).toBe("deny"); + } finally { + env.cleanup(); + } + }); +}); + +describe("E2E: Goose integration — install/uninstall", () => { + it("policies --install --cli goose --scope project writes the Open Plugins hooks.json", () => { + const env = createGooseEnv(); + try { + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli goose --scope project`, + { cwd: env.cwd, env: { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH } }, + ); + const hooksPath = resolve(env.cwd, ".agents", "plugins", "failproofai", "hooks", "hooks.json"); + expect(existsSync(hooksPath)).toBe(true); + const settings = JSON.parse(readFileSync(hooksPath, "utf-8")) as Record; + // Open Plugins schema: top-level "hooks" wrapper, matcher OMITTED. + expect(settings.hooks).toBeDefined(); + expect(settings.hooks.PreToolUse).toBeDefined(); + expect(settings.hooks.PostToolUse).toBeDefined(); + expect(settings.hooks.SessionStart).toBeDefined(); + expect(settings.hooks.PreToolUse[0].matcher).toBeUndefined(); + expect(settings.hooks.PreToolUse[0].hooks[0].command).toContain("--cli goose"); + } finally { + env.cleanup(); + } + }); + + it("policies --uninstall --cli goose removes hooks from the plugin hooks.json", () => { + const env = createGooseEnv(); + try { + const baseEnv = { ...process.env, HOME: env.home, FAILPROOFAI_TELEMETRY_DISABLED: "1", FAILPROOFAI_BINARY_OVERRIDE: BINARY_PATH }; + execSync( + `bun ${BINARY_PATH} policies --install block-sudo --cli goose --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const hooksPath = resolve(env.cwd, ".agents", "plugins", "failproofai", "hooks", "hooks.json"); + expect(existsSync(hooksPath)).toBe(true); + + execSync( + `bun ${BINARY_PATH} policies --uninstall --cli goose --scope project`, + { cwd: env.cwd, env: baseEnv }, + ); + const settings = JSON.parse(readFileSync(hooksPath, "utf-8")) as Record; + expect(settings.hooks).toBeUndefined(); + } finally { + env.cleanup(); + } + }); +}); diff --git a/__tests__/hooks/antigravity-canonicalize.test.ts b/__tests__/hooks/antigravity-canonicalize.test.ts new file mode 100644 index 00000000..a12d7ba1 --- /dev/null +++ b/__tests__/hooks/antigravity-canonicalize.test.ts @@ -0,0 +1,107 @@ +// @vitest-environment node +// +// Locks in Antigravity (agy) event mapping + tool NAME/INPUT canonicalization. +// Verified live against agy v1.1.2: shell runs as `run_command` with PascalCase +// args (`CommandLine`, `Cwd`); PreInvocation maps to the canonical +// UserPromptSubmit event. +import { describe, it, expect } from "vitest"; +import { + canonicalizeToolName, + canonicalizeToolInput, +} from "@/src/hooks/tool-name-canonicalize"; +import { + ANTIGRAVITY_HOOK_EVENT_TYPES, + ANTIGRAVITY_EVENT_MAP, + ANTIGRAVITY_TOOL_MAP, + HOOK_EVENT_TYPES, +} from "@/src/hooks/types"; + +describe("Antigravity event mapping", () => { + it("subscribes to the 4 verified agy hook events", () => { + expect(ANTIGRAVITY_HOOK_EVENT_TYPES).toEqual([ + "PreToolUse", + "PostToolUse", + "PreInvocation", + "Stop", + ]); + }); + + it("maps every agy --hook arg to a canonical HookEventType", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of ANTIGRAVITY_HOOK_EVENT_TYPES) { + expect(canonical.has(ANTIGRAVITY_EVENT_MAP[ev]), `${ev} → ${ANTIGRAVITY_EVENT_MAP[ev]}`).toBe(true); + } + }); + + it("PreInvocation maps to UserPromptSubmit; tool/stop pass through", () => { + expect(ANTIGRAVITY_EVENT_MAP.PreInvocation).toBe("UserPromptSubmit"); + expect(ANTIGRAVITY_EVENT_MAP.PreToolUse).toBe("PreToolUse"); + expect(ANTIGRAVITY_EVENT_MAP.PostToolUse).toBe("PostToolUse"); + expect(ANTIGRAVITY_EVENT_MAP.Stop).toBe("Stop"); + }); +}); + +describe("Antigravity tool-name canonicalization", () => { + it("canonicalizes agy tool ids to Claude builtins", () => { + expect(canonicalizeToolName("run_command", "antigravity")).toBe("Bash"); + expect(canonicalizeToolName("write_to_file", "antigravity")).toBe("Write"); + expect(canonicalizeToolName("read_file", "antigravity")).toBe("Read"); + expect(canonicalizeToolName("view_file", "antigravity")).toBe("Read"); + expect(canonicalizeToolName("edit_file", "antigravity")).toBe("Edit"); + expect(canonicalizeToolName("replace_file_content", "antigravity")).toBe("Edit"); + expect(canonicalizeToolName("list_dir", "antigravity")).toBe("LS"); + expect(canonicalizeToolName("find_by_name", "antigravity")).toBe("Glob"); + expect(canonicalizeToolName("grep_search", "antigravity")).toBe("Grep"); + expect(canonicalizeToolName("read_url_content", "antigravity")).toBe("WebFetch"); + expect(canonicalizeToolName("search_web", "antigravity")).toBe("WebSearch"); + }); + + it("passes unknown agy tools through unchanged (MCP, future tools)", () => { + expect(canonicalizeToolName("mcp__server__tool", "antigravity")).toBe("mcp__server__tool"); + expect(canonicalizeToolName("some_future_tool", "antigravity")).toBe("some_future_tool"); + }); + + it("maps every ANTIGRAVITY_TOOL_MAP key to a non-empty canonical name", () => { + for (const [raw, canonical] of Object.entries(ANTIGRAVITY_TOOL_MAP)) { + expect(canonicalizeToolName(raw, "antigravity")).toBe(canonical); + } + }); +}); + +describe("Antigravity tool-input canonicalization", () => { + it("maps run_command's PascalCase args (CommandLine/Cwd) to command/cwd on Bash", () => { + const out = canonicalizeToolInput( + "Bash", + { CommandLine: "npm test", Cwd: "/repo", WaitMsBeforeAsync: 5000 }, + "antigravity", + ) as Record; + expect(out.command).toBe("npm test"); + expect(out.cwd).toBe("/repo"); + // unknown keys pass through unchanged + expect(out.WaitMsBeforeAsync).toBe(5000); + }); + + it("maps write_to_file's TargetFile/CodeContent to file_path/content on Write", () => { + // Regression: without this, block-env-files/block-secrets-write never saw a + // file_path and silently allowed Antigravity .env writes. + const out = canonicalizeToolInput( + "Write", + { TargetFile: "/home/u/.env", CodeContent: "SECRET=x", Overwrite: true }, + "antigravity", + ) as Record; + expect(out.file_path).toBe("/home/u/.env"); + expect(out.content).toBe("SECRET=x"); + // unknown keys pass through unchanged + expect(out.Overwrite).toBe(true); + }); + + it("maps a file tool's TargetFile to file_path on Edit", () => { + const out = canonicalizeToolInput("Edit", { TargetFile: "/repo/.env" }, "antigravity") as Record; + expect(out.file_path).toBe("/repo/.env"); + }); + + it("leaves a tool with no map entry untouched (reference-equal)", () => { + const input = { pattern: "TODO" }; + expect(canonicalizeToolInput("Grep", input, "antigravity")).toBe(input); + }); +}); diff --git a/__tests__/hooks/devin-canonicalize.test.ts b/__tests__/hooks/devin-canonicalize.test.ts new file mode 100644 index 00000000..0c70efeb --- /dev/null +++ b/__tests__/hooks/devin-canonicalize.test.ts @@ -0,0 +1,51 @@ +// @vitest-environment node +// +// Locks in Devin (Cognition) tool NAME canonicalization (verified live against +// devin v3000.1.27: the shell tool runs as `exec` with `tool_input.command`). +// tool_input keys are already canonical, so there is no DEVIN_TOOL_INPUT_MAP. +import { describe, it, expect } from "vitest"; +import { canonicalizeToolName } from "@/src/hooks/tool-name-canonicalize"; +import { + DEVIN_HOOK_EVENT_TYPES, + DEVIN_TOOL_MAP, + HOOK_EVENT_TYPES, +} from "@/src/hooks/types"; + +describe("Devin event types", () => { + it("are all already-canonical PascalCase HookEventTypes (no event map needed)", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of DEVIN_HOOK_EVENT_TYPES) { + expect(canonical.has(ev), `${ev} must be a HookEventType`).toBe(true); + } + }); + + it("subscribes to the 7 verified devin events", () => { + expect(DEVIN_HOOK_EVENT_TYPES).toEqual([ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "PermissionRequest", + "Stop", + "SessionEnd", + ]); + }); +}); + +describe("Devin tool canonicalization", () => { + it("canonicalizes the exec shell tool to Bash", () => { + expect(canonicalizeToolName("exec", "devin")).toBe("Bash"); + }); + + it("passes unknown/other devin tools through unchanged (MCP, extensions, file tools)", () => { + expect(canonicalizeToolName("mcp__server__tool", "devin")).toBe("mcp__server__tool"); + expect(canonicalizeToolName("str_replace_editor", "devin")).toBe("str_replace_editor"); + expect(canonicalizeToolName("SomeFutureTool", "devin")).toBe("SomeFutureTool"); + }); + + it("maps every DEVIN_TOOL_MAP key to a non-empty canonical name", () => { + for (const [raw, canonical] of Object.entries(DEVIN_TOOL_MAP)) { + expect(canonicalizeToolName(raw, "devin")).toBe(canonical); + } + }); +}); diff --git a/__tests__/hooks/factory-canonicalize.test.ts b/__tests__/hooks/factory-canonicalize.test.ts new file mode 100644 index 00000000..9f8bafed --- /dev/null +++ b/__tests__/hooks/factory-canonicalize.test.ts @@ -0,0 +1,63 @@ +// @vitest-environment node +// +// Locks in Factory (droid) tool NAME canonicalization (verified live against +// droid v0.171.0: shell runs as `Execute`, file writes as `Create`, URL fetches +// as `FetchUrl`). tool_input keys are already canonical (`command`, `file_path`), +// so there is no FACTORY_TOOL_INPUT_MAP. +import { describe, it, expect } from "vitest"; +import { canonicalizeToolName } from "@/src/hooks/tool-name-canonicalize"; +import { + FACTORY_HOOK_EVENT_TYPES, + FACTORY_TOOL_MAP, + HOOK_EVENT_TYPES, +} from "@/src/hooks/types"; + +describe("Factory event types", () => { + it("are all already-canonical PascalCase HookEventTypes (no event map needed)", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of FACTORY_HOOK_EVENT_TYPES) { + expect(canonical.has(ev), `${ev} must be a HookEventType`).toBe(true); + } + }); + + it("subscribes to the 9 verified droid events", () => { + expect(FACTORY_HOOK_EVENT_TYPES).toEqual([ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "Notification", + "Stop", + "SubagentStop", + "PreCompact", + "SessionEnd", + ]); + }); +}); + +describe("Factory tool canonicalization", () => { + it("canonicalizes droid tool ids to Claude builtins", () => { + expect(canonicalizeToolName("Execute", "factory")).toBe("Bash"); + expect(canonicalizeToolName("Read", "factory")).toBe("Read"); + expect(canonicalizeToolName("Edit", "factory")).toBe("Edit"); + expect(canonicalizeToolName("Create", "factory")).toBe("Write"); + expect(canonicalizeToolName("Grep", "factory")).toBe("Grep"); + expect(canonicalizeToolName("Glob", "factory")).toBe("Glob"); + expect(canonicalizeToolName("LS", "factory")).toBe("LS"); + expect(canonicalizeToolName("FetchUrl", "factory")).toBe("WebFetch"); + expect(canonicalizeToolName("WebSearch", "factory")).toBe("WebSearch"); + expect(canonicalizeToolName("TodoWrite", "factory")).toBe("TodoWrite"); + expect(canonicalizeToolName("Task", "factory")).toBe("Task"); + }); + + it("passes unknown droid tools through unchanged (MCP, extensions)", () => { + expect(canonicalizeToolName("mcp__server__tool", "factory")).toBe("mcp__server__tool"); + expect(canonicalizeToolName("SomeFutureTool", "factory")).toBe("SomeFutureTool"); + }); + + it("maps every FACTORY_TOOL_MAP key to a non-empty canonical name", () => { + for (const [raw, canonical] of Object.entries(FACTORY_TOOL_MAP)) { + expect(canonicalizeToolName(raw, "factory")).toBe(canonical); + } + }); +}); diff --git a/__tests__/hooks/goose-canonicalize.test.ts b/__tests__/hooks/goose-canonicalize.test.ts new file mode 100644 index 00000000..8fabd964 --- /dev/null +++ b/__tests__/hooks/goose-canonicalize.test.ts @@ -0,0 +1,102 @@ +// @vitest-environment node +// +// Locks in Goose (codename goose, Block) tool NAME + tool-INPUT canonicalization +// (verified live against goose v1.43.0: developer tools arrive bare — `shell`, +// `write`, `edit`, `view`, `read_image`, `tree` — while other extensions +// namespace theirs, e.g. `todo__todo_write`; path-bearing tools deliver the path +// as `path` (or `source` for read_image), which builtins read as `file_path`). +import { describe, it, expect } from "vitest"; +import { canonicalizeToolName, canonicalizeToolInput } from "@/src/hooks/tool-name-canonicalize"; +import { + GOOSE_HOOK_EVENT_TYPES, + GOOSE_TOOL_MAP, + GOOSE_TOOL_INPUT_MAP, + HOOK_EVENT_TYPES, +} from "@/src/hooks/types"; + +describe("Goose event types", () => { + it("are all already-canonical PascalCase HookEventTypes (no event map needed)", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of GOOSE_HOOK_EVENT_TYPES) { + expect(canonical.has(ev), `${ev} must be a HookEventType`).toBe(true); + } + }); + + it("subscribes to the 5 events failproofai installs (no Stop — goose has none)", () => { + expect(GOOSE_HOOK_EVENT_TYPES).toEqual([ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "SessionEnd", + ]); + // Goose 1.43.0 has NO Stop event — the require-*-before-stop builtins are + // inapplicable, so Stop must not be installed. + expect(GOOSE_HOOK_EVENT_TYPES).not.toContain("Stop"); + }); +}); + +describe("Goose tool-name canonicalization", () => { + it("canonicalizes bare developer tool ids to Claude builtins", () => { + expect(canonicalizeToolName("shell", "goose")).toBe("Bash"); + expect(canonicalizeToolName("write", "goose")).toBe("Write"); + expect(canonicalizeToolName("edit", "goose")).toBe("Edit"); + expect(canonicalizeToolName("view", "goose")).toBe("Read"); + expect(canonicalizeToolName("read_image", "goose")).toBe("Read"); + expect(canonicalizeToolName("glob", "goose")).toBe("Glob"); + expect(canonicalizeToolName("grep", "goose")).toBe("Grep"); + expect(canonicalizeToolName("tree", "goose")).toBe("LS"); + expect(canonicalizeToolName("delegate", "goose")).toBe("Task"); + }); + + it("canonicalizes namespaced extension tools (__)", () => { + expect(canonicalizeToolName("todo__todo_write", "goose")).toBe("TodoWrite"); + }); + + it("passes unknown / other-extension tools through unchanged", () => { + expect(canonicalizeToolName("analyze", "goose")).toBe("analyze"); + expect(canonicalizeToolName("mcp__server__tool", "goose")).toBe("mcp__server__tool"); + expect(canonicalizeToolName("SomeFutureTool", "goose")).toBe("SomeFutureTool"); + }); + + it("maps every GOOSE_TOOL_MAP key to its declared canonical name", () => { + for (const [raw, canonical] of Object.entries(GOOSE_TOOL_MAP)) { + expect(canonicalizeToolName(raw, "goose")).toBe(canonical); + } + }); +}); + +describe("Goose tool-input canonicalization", () => { + it("maps write/edit `path` → `file_path` so path builtins fire", () => { + expect(canonicalizeToolInput("Write", { path: "/tmp/x", content: "hi" }, "goose")).toEqual({ + file_path: "/tmp/x", + content: "hi", + }); + expect(canonicalizeToolInput("Edit", { path: "/tmp/x", before: "a", after: "b" }, "goose")).toEqual({ + file_path: "/tmp/x", + before: "a", + after: "b", + }); + }); + + it("maps read `path` AND read_image `source` → `file_path`", () => { + expect(canonicalizeToolInput("Read", { path: "/tmp/f.txt" }, "goose")).toEqual({ + file_path: "/tmp/f.txt", + }); + expect(canonicalizeToolInput("Read", { source: "/tmp/img.png" }, "goose")).toEqual({ + file_path: "/tmp/img.png", + }); + }); + + it("leaves shell `command` untouched (already canonical for Bash builtins)", () => { + expect(canonicalizeToolInput("Bash", { command: "echo hi" }, "goose")).toEqual({ + command: "echo hi", + }); + }); + + it("has a GOOSE_TOOL_INPUT_MAP keyed by canonical tool names only", () => { + for (const key of Object.keys(GOOSE_TOOL_INPUT_MAP)) { + expect(["Read", "Write", "Edit", "LS"]).toContain(key); + } + }); +}); diff --git a/__tests__/hooks/handler.test.ts b/__tests__/hooks/handler.test.ts index ded82a16..41be695b 100644 --- a/__tests__/hooks/handler.test.ts +++ b/__tests__/hooks/handler.test.ts @@ -612,116 +612,12 @@ describe("hooks/handler", () => { ); }); - it("canonicalizes Gemini BeforeTool → PreToolUse before evaluating", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, - stdout: "", - stderr: "", - policyName: null, - reason: null, - decision: "allow", - }); - mockStdin(JSON.stringify({ tool_name: "run_shell_command", hook_event_name: "BeforeTool" })); - const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); - - await handleHookEvent("BeforeTool", "gemini"); - - expect(evaluatePolicies).toHaveBeenCalledWith( - "PreToolUse", - expect.any(Object), - expect.any(Object), - expect.any(Object), - ); - expect(persistHookActivity).toHaveBeenCalledWith( - expect.objectContaining({ integration: "gemini", eventType: "PreToolUse" }), - ); - }); - - it("canonicalizes Gemini snake_case tool name run_shell_command → Bash before evaluating", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, - stdout: "", - stderr: "", - policyName: null, - reason: null, - decision: "allow", - }); - mockStdin(JSON.stringify({ tool_name: "run_shell_command", hook_event_name: "BeforeTool" })); - const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); - - await handleHookEvent("BeforeTool", "gemini"); - - // The mutated payload passed to evaluatePolicies should carry the canonicalized tool_name - expect(evaluatePolicies).toHaveBeenCalledWith( - "PreToolUse", - expect.objectContaining({ tool_name: "Bash" }), - expect.any(Object), - expect.any(Object), - ); - // Activity store should also see canonicalized toolName=Bash, NOT raw run_shell_command - expect(persistHookActivity).toHaveBeenCalledWith( - expect.objectContaining({ integration: "gemini", toolName: "Bash" }), - ); - }); - - it("canonicalizes every Gemini tool name in GEMINI_TOOL_MAP", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - const cases: Array<[string, string]> = [ - ["run_shell_command", "Bash"], - ["read_file", "Read"], - ["read_many_files", "Read"], - ["write_file", "Write"], - ["replace", "Edit"], - ["glob", "Glob"], - ["grep_search", "Grep"], - ["list_directory", "LS"], - ["web_fetch", "WebFetch"], - ["google_web_search", "WebSearch"], - ["write_todos", "TodoWrite"], - ["save_memory", "Memory"], - ["ask_user", "AskUser"], - ]; - for (const [raw, canonical] of cases) { - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow", - }); - mockStdin(JSON.stringify({ tool_name: raw, hook_event_name: "BeforeTool" })); - await handleHookEvent("BeforeTool", "gemini"); - expect(evaluatePolicies).toHaveBeenLastCalledWith( - "PreToolUse", - expect.objectContaining({ tool_name: canonical }), - expect.any(Object), - expect.any(Object), - ); - } - }); - - it("passes through unknown Gemini tool names (MCP, extensions) unchanged", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow", - }); - mockStdin(JSON.stringify({ tool_name: "mcp_github_create_issue", hook_event_name: "BeforeTool" })); - - await handleHookEvent("BeforeTool", "gemini"); - - // Unknown tool names are NOT in GEMINI_TOOL_MAP — must pass through unchanged so MCP tools aren't lost - expect(evaluatePolicies).toHaveBeenCalledWith( - "PreToolUse", - expect.objectContaining({ tool_name: "mcp_github_create_issue" }), - expect.any(Object), - expect.any(Object), - ); - }); - it("does NOT canonicalize tool names when cli=claude (other CLIs unaffected)", async () => { const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); vi.mocked(evaluatePolicies).mockResolvedValueOnce({ exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow", }); - // A Claude session that somehow has a Gemini-shaped tool name should NOT be remapped. + // A Claude session that somehow has a snake_case tool name should NOT be remapped. mockStdin(JSON.stringify({ tool_name: "run_shell_command", hook_event_name: "PreToolUse" })); await handleHookEvent("PreToolUse", "claude"); @@ -734,75 +630,6 @@ describe("hooks/handler", () => { ); }); - it("canonicalizes all 11 Gemini events to canonical names (BeforeAgent → UserPromptSubmit, etc.)", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - const cases: Array<[string, string]> = [ - ["SessionStart", "SessionStart"], - ["SessionEnd", "SessionEnd"], - ["BeforeAgent", "UserPromptSubmit"], - ["AfterAgent", "Stop"], - ["BeforeTool", "PreToolUse"], - ["AfterTool", "PostToolUse"], - ["PreCompress", "PreCompact"], - ["Notification", "Notification"], - // Gemini-only events with no Claude canonical — passthrough. - ["BeforeModel", "BeforeModel"], - ["AfterModel", "AfterModel"], - ["BeforeToolSelection", "BeforeToolSelection"], - ]; - for (const [raw, canonical] of cases) { - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow", - }); - mockStdin(JSON.stringify({ hook_event_name: raw })); - await handleHookEvent(raw, "gemini"); - expect(evaluatePolicies).toHaveBeenLastCalledWith( - canonical, - expect.any(Object), - expect.any(Object), - expect.any(Object), - ); - } - }); - - it("tags telemetry with cli=gemini and canonicalized tool_name=Bash when invoked with --cli gemini", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, - stdout: '{"decision":"deny","reason":"sudo blocked"}', - stderr: "", - policyName: "block-sudo", - reason: "sudo blocked", - decision: "deny", - }); - mockStdin(JSON.stringify({ tool_name: "run_shell_command", hook_event_name: "BeforeTool" })); - const { trackHookEvent } = await import("../../src/hooks/hook-telemetry"); - - await handleHookEvent("BeforeTool", "gemini"); - - // Telemetry should see the canonicalized tool name (Bash, not run_shell_command) - expect(trackHookEvent).toHaveBeenCalledWith( - "test-instance-id", - "hook_policy_triggered", - expect.objectContaining({ cli: "gemini", event_type: "PreToolUse", tool_name: "Bash" }), - ); - }); - - it("tags activity store entry with integration=gemini and canonicalized eventType for Gemini hook fires", async () => { - const { evaluatePolicies } = await import("../../src/hooks/policy-evaluator"); - vi.mocked(evaluatePolicies).mockResolvedValueOnce({ - exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow", - }); - mockStdin(JSON.stringify({ tool_name: "read_file", hook_event_name: "BeforeTool" })); - const { persistHookActivity } = await import("../../src/hooks/hook-activity-store"); - - await handleHookEvent("BeforeTool", "gemini"); - - expect(persistHookActivity).toHaveBeenCalledWith( - expect.objectContaining({ integration: "gemini", eventType: "PreToolUse", toolName: "Read" }), - ); - }); - // -- OpenCode handler-side canonicalization (defense-in-depth) ---------- // // The OpenCode plugin shim already canonicalizes tool name + tool input diff --git a/__tests__/hooks/install-prompt.test.ts b/__tests__/hooks/install-prompt.test.ts index e48e8a80..e6de55f8 100644 --- a/__tests__/hooks/install-prompt.test.ts +++ b/__tests__/hooks/install-prompt.test.ts @@ -141,9 +141,9 @@ describe("hooks/install-prompt", () => { "install", ); - // 1 aggregate "all" + 2 detected + 6 undetected - expect(options).toHaveLength(9); - expect(undetected).toEqual(["copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + // 1 aggregate "all" + 2 detected + 10 undetected + expect(options).toHaveLength(13); + expect(undetected).toEqual(["copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); expect(options[0]).toMatchObject({ isAll: true, detected: true, value: ["claude", "codex"] }); expect(options[0].label).toBe("Install for all 2 detected"); @@ -162,8 +162,12 @@ describe("hooks/install-prompt", () => { "Cursor Agent", "OpenCode", "Pi", - "Gemini CLI", "Hermes", + "OpenClaw", + "Factory Droid", + "Devin CLI", + "Antigravity CLI", + "Goose", ]); }); @@ -180,16 +184,16 @@ describe("hooks/install-prompt", () => { expect(options.every((o) => o.detected)).toBe(true); }); - it("install with all 8 detected: no aggregate-row needed beyond the standard one, no undetected section", async () => { + it("install with all 12 detected: no aggregate-row needed beyond the standard one, no undetected section", async () => { const { buildCliMenuOptions } = await import("../../src/hooks/install-prompt"); const { options, undetected } = buildCliMenuOptions( - ["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"], + ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"], "install", ); expect(undetected).toEqual([]); - expect(options).toHaveLength(9); // aggregate + 8 detected - expect(options[0].label).toBe("Install for all 8 detected"); + expect(options).toHaveLength(13); // aggregate + 12 detected + expect(options[0].label).toBe("Install for all 12 detected"); }); it("install with 1 detected + many undetected: skips aggregate row (1 ≯ 1)", async () => { diff --git a/__tests__/hooks/integrations.test.ts b/__tests__/hooks/integrations.test.ts index fc392e8e..e525d566 100644 --- a/__tests__/hooks/integrations.test.ts +++ b/__tests__/hooks/integrations.test.ts @@ -20,8 +20,12 @@ import { cursor, opencode, pi, - gemini, hermes, + openclaw, + factory, + devin, + antigravity, + goose, getIntegration, listIntegrations, } from "../../src/hooks/integrations"; @@ -35,18 +39,18 @@ import { OPENCODE_EVENT_MAP, PI_HOOK_EVENT_TYPES, PI_EVENT_MAP, - GEMINI_HOOK_EVENT_TYPES, - GEMINI_EVENT_MAP, - GEMINI_TOOL_MAP, HERMES_HOOK_EVENT_TYPES, HERMES_EVENT_MAP, + FACTORY_HOOK_EVENT_TYPES, + DEVIN_HOOK_EVENT_TYPES, + ANTIGRAVITY_HOOK_EVENT_TYPES, + GOOSE_HOOK_EVENT_TYPES, HOOK_EVENT_TYPES, FAILPROOFAI_HOOK_MARKER, type CodexHookEventType, type CursorHookEventType, type OpenCodeHookEventType, type PiHookEventType, - type GeminiHookEventType, type HermesHookEventType, } from "../../src/hooks/types"; import { homedir } from "node:os"; @@ -73,9 +77,9 @@ afterEach(() => { }); describe("integrations registry", () => { - it("listIntegrations returns claude, codex, copilot, cursor, opencode, pi, gemini, and hermes in declared order", () => { + it("listIntegrations returns claude, codex, copilot, cursor, opencode, pi, hermes, and openclaw in declared order", () => { const ids = listIntegrations().map((i) => i.id); - expect(ids).toEqual(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + expect(ids).toEqual(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); }); it("getIntegration('claude') returns claudeCode", () => { @@ -102,14 +106,30 @@ describe("integrations registry", () => { expect(getIntegration("pi")).toBe(pi); }); - it("getIntegration('gemini') returns gemini", () => { - expect(getIntegration("gemini")).toBe(gemini); - }); - it("getIntegration('hermes') returns hermes", () => { expect(getIntegration("hermes")).toBe(hermes); }); + it("getIntegration('openclaw') returns openclaw", () => { + expect(getIntegration("openclaw")).toBe(openclaw); + }); + + it("getIntegration('factory') returns factory", () => { + expect(getIntegration("factory")).toBe(factory); + }); + + it("getIntegration('antigravity') returns antigravity", () => { + expect(getIntegration("antigravity")).toBe(antigravity); + }); + + it("getIntegration('goose') returns goose", () => { + expect(getIntegration("goose")).toBe(goose); + }); + + it("getIntegration('devin') returns devin", () => { + expect(getIntegration("devin")).toBe(devin); + }); + it("getIntegration throws for unknown id", () => { // @ts-expect-error — testing error path expect(() => getIntegration("unknown-cli")).toThrow(); @@ -1096,204 +1116,525 @@ describe("PI_EVENT_MAP", () => { }); }); -describe("Gemini CLI integration", () => { - it("getSettingsPath maps user → ~/.gemini/settings.json and project → /.gemini/settings.json", () => { - expect(gemini.getSettingsPath("project", tempDir)).toBe( - resolve(tempDir, ".gemini", "settings.json"), - ); - expect(gemini.getSettingsPath("user")).toMatch(/\.gemini\/settings\.json$/); +describe("OpenClaw integration", () => { + it("is user-scope only and points at ~/.openclaw/openclaw.json", () => { + expect(openclaw.scopes).toEqual(["user"]); + // getSettingsPath ignores scope/cwd (OpenClaw has no project config). + const p = openclaw.getSettingsPath("user"); + expect(p).toBe(join(homedir(), ".openclaw", "openclaw.json")); + expect(openclaw.getSettingsPath("project", "/some/where")).toBe(p); }); - it("getSettingsPath('local') falls back to project (no gemini local scope)", () => { - expect(gemini.getSettingsPath("local", tempDir)).toBe( - resolve(tempDir, ".gemini", "settings.json"), - ); + it("writeHookEntries registers the plugin path + enables the entry with allowConversationAccess", () => { + const settings: Record = {}; + openclaw.writeHookEntries(settings, ""); + const plugins = settings.plugins as Record; + expect(Array.isArray(plugins.load.paths)).toBe(true); + expect(plugins.load.paths.some((p: string) => p.endsWith("openclaw-plugin"))).toBe(true); + expect(plugins.entries.failproofai.enabled).toBe(true); + expect(plugins.entries.failproofai.hooks.allowConversationAccess).toBe(true); + }); + + it("writeHookEntries is idempotent (double install → single path entry)", () => { + const settings: Record = {}; + openclaw.writeHookEntries(settings, ""); + openclaw.writeHookEntries(settings, ""); + const plugins = settings.plugins as Record; + const ours = plugins.load.paths.filter((p: string) => p.includes("openclaw-plugin")); + expect(ours).toHaveLength(1); }); - it("scopes are user|project (no local; system scope ignored)", () => { - expect(gemini.scopes).toEqual(["user", "project"]); - expect(gemini.scopes).not.toContain("local"); + it("writeHookEntries preserves operator config (other plugins, deny list, load extras)", () => { + const settings: Record = { + plugins: { + deny: ["untrusted"], + load: { paths: ["/opt/other-plugin"], watch: true }, + entries: { other: { enabled: true, config: { x: 1 } } }, + }, + }; + openclaw.writeHookEntries(settings, ""); + const plugins = settings.plugins as Record; + expect(plugins.deny).toEqual(["untrusted"]); + expect(plugins.load.watch).toBe(true); + expect(plugins.load.paths).toContain("/opt/other-plugin"); + expect(plugins.entries.other).toEqual({ enabled: true, config: { x: 1 } }); + expect(plugins.entries.failproofai.enabled).toBe(true); }); - it("eventTypes are the 11 PascalCase Gemini events", () => { - expect(gemini.eventTypes).toEqual(GEMINI_HOOK_EVENT_TYPES); - expect(gemini.eventTypes).toContain("SessionStart"); - expect(gemini.eventTypes).toContain("SessionEnd"); - expect(gemini.eventTypes).toContain("BeforeAgent"); - expect(gemini.eventTypes).toContain("AfterAgent"); - expect(gemini.eventTypes).toContain("BeforeModel"); - expect(gemini.eventTypes).toContain("AfterModel"); - expect(gemini.eventTypes).toContain("BeforeToolSelection"); - expect(gemini.eventTypes).toContain("BeforeTool"); - expect(gemini.eventTypes).toContain("AfterTool"); - expect(gemini.eventTypes).toContain("PreCompress"); - expect(gemini.eventTypes).toContain("Notification"); - expect(gemini.eventTypes).toHaveLength(11); + it("isFailproofaiHook recognizes our load.paths string entry and the marked sentinel", () => { + expect(openclaw.isFailproofaiHook("/x/failproofai/openclaw-plugin")).toBe(true); + expect(openclaw.isFailproofaiHook("/abs/openclaw-plugin")).toBe(true); + expect(openclaw.isFailproofaiHook("/opt/other-plugin")).toBe(false); + expect(openclaw.isFailproofaiHook({ [FAILPROOFAI_HOOK_MARKER]: true })).toBe(true); }); - it("buildHookEntry uses Claude-shaped {type,command,timeout,marker} with --cli gemini", () => { - const entry = gemini.buildHookEntry("/usr/bin/failproofai", "BeforeTool", "user") as Record; - expect(entry.type).toBe("command"); - expect(entry.command).toBe('"/usr/bin/failproofai" --hook BeforeTool --cli gemini'); - expect(entry.timeout).toBe(60_000); + it("removeHooksFromFile reverses install and prunes empties, leaving operator config intact", () => { + const file = join(tempDir, "openclaw.json"); + const settings: Record = { + plugins: { deny: ["untrusted"], load: { paths: ["/opt/other-plugin"] }, entries: { other: { enabled: true } } }, + }; + openclaw.writeHookEntries(settings, ""); + writeFileSync(file, JSON.stringify(settings)); + + const removed = openclaw.removeHooksFromFile(file); + expect(removed).toBeGreaterThanOrEqual(2); // path + entry + + const after = JSON.parse(readFileSync(file, "utf-8")) as Record; + expect(after.plugins.entries.failproofai).toBeUndefined(); + expect(after.plugins.entries.other).toEqual({ enabled: true }); + expect(after.plugins.load.paths).toEqual(["/opt/other-plugin"]); + expect(after.plugins.deny).toEqual(["untrusted"]); + }); + + it("removeHooksFromFile deletes an empty plugins object when nothing else remains", () => { + const file = join(tempDir, "openclaw2.json"); + const settings: Record = {}; + openclaw.writeHookEntries(settings, ""); + writeFileSync(file, JSON.stringify(settings)); + + openclaw.removeHooksFromFile(file); + const after = JSON.parse(readFileSync(file, "utf-8")) as Record; + expect(after.plugins).toBeUndefined(); + }); +}); + +describe("Factory Droid integration", () => { + it("getSettingsPath maps user → ~/.factory/hooks.json and project → /.factory/hooks.json", () => { + expect(factory.getSettingsPath("project", tempDir)).toBe( + resolve(tempDir, ".factory", "hooks.json"), + ); + expect(factory.getSettingsPath("user")).toMatch(/\.factory\/hooks\.json$/); + }); + + it("scopes are user|project (no local)", () => { + expect(factory.scopes).toEqual(["user", "project"]); + }); + + it("buildHookEntry includes --cli factory and a 30s timeout", () => { + const entry = factory.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "user"); + expect(entry.command).toContain("--cli factory"); + expect(entry.command).toContain("--hook PreToolUse"); + expect(entry.timeout).toBe(30); expect(entry[FAILPROOFAI_HOOK_MARKER]).toBe(true); - // Gemini entries use Claude's `command` field, not Copilot's bash/powershell split. - expect(entry.bash).toBeUndefined(); - expect(entry.powershell).toBeUndefined(); }); - it("project scope uses npx -y failproofai (portable across machines)", () => { - const entry = gemini.buildHookEntry("/usr/bin/failproofai", "BeforeTool", "project") as Record; - expect(entry.command).toBe("npx -y failproofai --hook BeforeTool --cli gemini"); + it("project scope uses npx -y failproofai", () => { + const entry = factory.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "project"); + expect(entry.command).toBe("npx -y failproofai --hook PreToolUse --cli factory"); }); - it("writeHookEntries writes the matcher-wrapper schema for all 11 events with matcher='*'", () => { + it("writeHookEntries stores event names at the TOP LEVEL (no `hooks` wrapper)", () => { const settings: Record = {}; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "user"); - const hooks = settings.hooks as Record>>; - for (const eventType of GEMINI_HOOK_EVENT_TYPES) { - expect(hooks[eventType]).toBeDefined(); - const matchers = hooks[eventType]; - expect(matchers.length).toBeGreaterThanOrEqual(1); - // Matcher-wrapper: each element is {matcher, hooks: [{type, command, ...}]} - expect(matchers[0].matcher).toBe("*"); - const inner = matchers[0].hooks as Array>; - expect(inner).toHaveLength(1); - expect(inner[0].type).toBe("command"); - expect(typeof inner[0].command).toBe("string"); - expect(inner[0][FAILPROOFAI_HOOK_MARKER]).toBe(true); + factory.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + // No wrapper key — the file IS the events object. + expect(settings.hooks).toBeUndefined(); + for (const eventType of FACTORY_HOOK_EVENT_TYPES) { + expect(Array.isArray(settings[eventType])).toBe(true); } }); - it("re-running writeHookEntries is idempotent (replaces, doesn't duplicate)", () => { + it("writeHookEntries adds matcher:'*' for tool events and omits it elsewhere", () => { const settings: Record = {}; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "user"); - gemini.writeHookEntries(settings, "/different/path/failproofai", "user"); - const hooks = settings.hooks as Record>>; - // Each event has exactly one matcher; the inner hook is the most recent. - expect(hooks.BeforeTool).toHaveLength(1); - const inner = (hooks.BeforeTool[0].hooks as Array>)[0]; - expect(inner.command).toBe('"/different/path/failproofai" --hook BeforeTool --cli gemini'); + factory.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + const pre = (settings.PreToolUse as Array>)[0]; + const post = (settings.PostToolUse as Array>)[0]; + const stop = (settings.Stop as Array>)[0]; + expect(pre.matcher).toBe("*"); + expect(post.matcher).toBe("*"); + expect(stop.matcher).toBeUndefined(); }); - it("writeHookEntries preserves a hand-written user hook with the same event key", () => { - const userHook = { type: "command", command: "/my/script.sh", timeout: 5000 }; - const settings: Record = { - hooks: { BeforeTool: [{ matcher: "write_file", hooks: [userHook] }] }, - }; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "user"); - const hooks = settings.hooks as Record>>; - // User's hook is preserved at index 0, ours appended at index 1 - expect(hooks.BeforeTool).toHaveLength(2); - const userMatcher = hooks.BeforeTool[0]; - expect(userMatcher.matcher).toBe("write_file"); - expect((userMatcher.hooks as Array>)[0].command).toBe("/my/script.sh"); - const ourMatcher = hooks.BeforeTool[1]; - expect(ourMatcher.matcher).toBe("*"); - expect((ourMatcher.hooks as Array>)[0][FAILPROOFAI_HOOK_MARKER]).toBe(true); - }); - - it("removeHooksFromFile removes only failproofai-marked entries (preserves user hooks)", () => { - const userHook = { type: "command", command: "/my/script.sh", timeout: 5000 }; - const settingsPath = gemini.getSettingsPath("project", tempDir); - mkdirSync(resolve(tempDir, ".gemini"), { recursive: true }); + it("re-running writeHookEntries is idempotent", () => { + const settings: Record = {}; + factory.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + factory.writeHookEntries(settings, "/different/path/failproofai", "user"); + const pre = settings.PreToolUse as Array<{ hooks: unknown[] }>; + expect(pre).toHaveLength(1); + expect(pre[0].hooks).toHaveLength(1); + }); + + it("removeHooksFromFile clears all failproofai entries (returns count)", () => { + const settingsPath = factory.getSettingsPath("project", tempDir); + const settings: Record = {}; + factory.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + factory.writeSettings(settingsPath, settings); + expect(existsSync(settingsPath)).toBe(true); + + const removed = factory.removeHooksFromFile(settingsPath); + expect(removed).toBe(FACTORY_HOOK_EVENT_TYPES.length); + + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + for (const eventType of FACTORY_HOOK_EVENT_TYPES) { + expect(after[eventType]).toBeUndefined(); + } + }); + + it("removeHooksFromFile preserves a user's own hook entries", () => { + const settingsPath = factory.getSettingsPath("project", tempDir); const settings: Record = { - hooks: { BeforeTool: [{ matcher: "write_file", hooks: [userHook] }] }, + PreToolUse: [{ matcher: "*", hooks: [{ type: "command", command: "my-own-hook" }] }], }; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "project"); - gemini.writeSettings(settingsPath, settings); + factory.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + factory.writeSettings(settingsPath, settings); - const removed = gemini.removeHooksFromFile(settingsPath); - // 11 events × 1 marked entry each = 11 removed - expect(removed).toBe(GEMINI_HOOK_EVENT_TYPES.length); + factory.removeHooksFromFile(settingsPath); + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + // The user's own hook survives; only the failproofai-marked entry is gone. + const flattened = (after.PreToolUse ?? []).flatMap((m: any) => m.hooks ?? []); + expect(flattened.some((h: any) => h.command === "my-own-hook")).toBe(true); + expect(flattened.some((h: any) => h[FAILPROOFAI_HOOK_MARKER] === true)).toBe(false); + }); - const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; - const afterHooks = after.hooks as Record; - // User's BeforeTool hook still there - expect(afterHooks.BeforeTool).toHaveLength(1); - expect((afterHooks.BeforeTool[0] as Record).matcher).toBe("write_file"); - // Other event keys (which only had failproofai entries) are deleted - expect(afterHooks.SessionStart).toBeUndefined(); + it("hooksInstalledInSettings detects installed hooks", () => { + const settingsPath = factory.getSettingsPath("project", tempDir); + const settings: Record = {}; + factory.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + factory.writeSettings(settingsPath, settings); + + expect(factory.hooksInstalledInSettings("project", tempDir)).toBe(true); + }); +}); + +describe("Devin CLI integration", () => { + it("getSettingsPath maps user → ~/.config/devin/config.json and project → /.devin/config.json", () => { + expect(devin.getSettingsPath("project", tempDir)).toBe( + resolve(tempDir, ".devin", "config.json"), + ); + expect(devin.getSettingsPath("user")).toMatch(/\.config\/devin\/config\.json$/); }); - it("removeHooksFromFile clears all and removes the top-level hooks key when nothing remains", () => { - const settingsPath = gemini.getSettingsPath("project", tempDir); - mkdirSync(resolve(tempDir, ".gemini"), { recursive: true }); + it("scopes are user|project (no local)", () => { + expect(devin.scopes).toEqual(["user", "project"]); + }); + + it("subscribes to the 7 verified devin events", () => { + expect(DEVIN_HOOK_EVENT_TYPES).toEqual([ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "PermissionRequest", + "Stop", + "SessionEnd", + ]); + }); + + it("every devin event is a canonical HookEventType (no event map needed)", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of DEVIN_HOOK_EVENT_TYPES) { + expect(canonical.has(ev), `${ev} must be a HookEventType`).toBe(true); + } + }); + + it("buildHookEntry includes --cli devin and a 60s timeout", () => { + const entry = devin.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "user"); + expect(entry.command).toContain("--cli devin"); + expect(entry.command).toContain("--hook PreToolUse"); + expect(entry.command).toBe(`"/usr/bin/failproofai" --hook PreToolUse --cli devin`); + expect(entry.timeout).toBe(60); + expect(entry[FAILPROOFAI_HOOK_MARKER]).toBe(true); + }); + + it("project scope uses npx -y failproofai", () => { + const entry = devin.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "project"); + expect(entry.command).toBe("npx -y failproofai --hook PreToolUse --cli devin"); + }); + + it("writeHookEntries stores events under a Claude-style `hooks` wrapper", () => { const settings: Record = {}; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "project"); - gemini.writeSettings(settingsPath, settings); + devin.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + const hooks = settings.hooks as Record; + expect(hooks).toBeDefined(); + for (const eventType of DEVIN_HOOK_EVENT_TYPES) { + expect(Array.isArray(hooks[eventType])).toBe(true); + } + }); - const removed = gemini.removeHooksFromFile(settingsPath); - expect(removed).toBe(GEMINI_HOOK_EVENT_TYPES.length); + it("writeHookEntries preserves other top-level config keys (org_id, theme_mode)", () => { + const settings: Record = { org_id: "acme", theme_mode: "dark" }; + devin.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + expect(settings.org_id).toBe("acme"); + expect(settings.theme_mode).toBe("dark"); + }); + + it("re-running writeHookEntries is idempotent", () => { + const settings: Record = {}; + devin.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + devin.writeHookEntries(settings, "/different/path/failproofai", "user"); + const hooks = settings.hooks as Record>; + expect(hooks.PreToolUse).toHaveLength(1); + expect(hooks.PreToolUse[0].hooks).toHaveLength(1); + }); + + it("removeHooksFromFile clears all failproofai entries (returns count)", () => { + const settingsPath = devin.getSettingsPath("project", tempDir); + const settings: Record = {}; + devin.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + devin.writeSettings(settingsPath, settings); + expect(existsSync(settingsPath)).toBe(true); + + const removed = devin.removeHooksFromFile(settingsPath); + expect(removed).toBe(DEVIN_HOOK_EVENT_TYPES.length); const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; expect(after.hooks).toBeUndefined(); }); + it("removeHooksFromFile preserves a user's own hook entries and other keys", () => { + const settingsPath = devin.getSettingsPath("project", tempDir); + const settings: Record = { + org_id: "acme", + hooks: { + PreToolUse: [{ hooks: [{ type: "command", command: "my-own-hook" }] }], + }, + }; + devin.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + devin.writeSettings(settingsPath, settings); + + devin.removeHooksFromFile(settingsPath); + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + expect(after.org_id).toBe("acme"); + const flattened = (after.hooks?.PreToolUse ?? []).flatMap((m: any) => m.hooks ?? []); + expect(flattened.some((h: any) => h.command === "my-own-hook")).toBe(true); + expect(flattened.some((h: any) => h[FAILPROOFAI_HOOK_MARKER] === true)).toBe(false); + }); + it("hooksInstalledInSettings detects installed hooks", () => { - const settingsPath = gemini.getSettingsPath("project", tempDir); - mkdirSync(resolve(tempDir, ".gemini"), { recursive: true }); + const settingsPath = devin.getSettingsPath("project", tempDir); const settings: Record = {}; - gemini.writeHookEntries(settings, "/usr/bin/failproofai", "project"); - gemini.writeSettings(settingsPath, settings); + devin.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + devin.writeSettings(settingsPath, settings); + + expect(devin.hooksInstalledInSettings("project", tempDir)).toBe(true); + }); +}); - expect(gemini.hooksInstalledInSettings("project", tempDir)).toBe(true); +describe("Antigravity CLI integration", () => { + it("getSettingsPath maps user → ~/.gemini/config/hooks.json and project → /.agents/hooks.json", () => { + expect(antigravity.getSettingsPath("project", tempDir)).toBe( + resolve(tempDir, ".agents", "hooks.json"), + ); + expect(antigravity.getSettingsPath("user")).toMatch(/\.gemini\/config\/hooks\.json$/); }); - it("hooksInstalledInSettings returns false when file is missing", () => { - expect(gemini.hooksInstalledInSettings("project", tempDir)).toBe(false); + it("scopes are user|project (no local)", () => { + expect(antigravity.scopes).toEqual(["user", "project"]); }); - it("hooksInstalledInSettings returns false on corrupt JSON (fail-open)", () => { - const settingsPath = gemini.getSettingsPath("project", tempDir); - mkdirSync(resolve(tempDir, ".gemini"), { recursive: true }); - writeFileSync(settingsPath, "{not json"); - expect(gemini.hooksInstalledInSettings("project", tempDir)).toBe(false); + it("subscribes to the 4 verified agy events", () => { + expect(ANTIGRAVITY_HOOK_EVENT_TYPES).toEqual([ + "PreToolUse", + "PostToolUse", + "PreInvocation", + "Stop", + ]); }); -}); -describe("GEMINI_EVENT_MAP", () => { - it("maps every Gemini event to a canonical HookEventType (or passthrough)", () => { - expect(GEMINI_EVENT_MAP.SessionStart).toBe("SessionStart"); - expect(GEMINI_EVENT_MAP.SessionEnd).toBe("SessionEnd"); - expect(GEMINI_EVENT_MAP.BeforeAgent).toBe("UserPromptSubmit"); - expect(GEMINI_EVENT_MAP.AfterAgent).toBe("Stop"); - expect(GEMINI_EVENT_MAP.BeforeTool).toBe("PreToolUse"); - expect(GEMINI_EVENT_MAP.AfterTool).toBe("PostToolUse"); - expect(GEMINI_EVENT_MAP.PreCompress).toBe("PreCompact"); - expect(GEMINI_EVENT_MAP.Notification).toBe("Notification"); - // Three Gemini-only events have no canonical Claude equivalent — passthrough. - expect(GEMINI_EVENT_MAP.BeforeModel).toBe("BeforeModel"); - expect(GEMINI_EVENT_MAP.AfterModel).toBe("AfterModel"); - expect(GEMINI_EVENT_MAP.BeforeToolSelection).toBe("BeforeToolSelection"); - }); - - it("GEMINI_EVENT_MAP keys exactly match GEMINI_HOOK_EVENT_TYPES", () => { - const mapKeys = Object.keys(GEMINI_EVENT_MAP).sort(); - const eventTypes = [...GEMINI_HOOK_EVENT_TYPES].sort(); - expect(mapKeys).toEqual(eventTypes); + it("buildHookEntry includes --cli antigravity and a 30s timeout", () => { + const entry = antigravity.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "user"); + expect(entry.command).toContain("--cli antigravity"); + expect(entry.command).toContain("--hook PreToolUse"); + expect(entry.timeout).toBe(30); + expect(entry[FAILPROOFAI_HOOK_MARKER]).toBe(true); + }); + + it("project scope uses npx -y failproofai", () => { + const entry = antigravity.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "project"); + expect(entry.command).toBe("npx -y failproofai --hook PreToolUse --cli antigravity"); + }); + + it("writeHookEntries nests events under a named 'failproofai' hook key", () => { + const settings: Record = {}; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + const named = settings.failproofai as Record; + expect(named).toBeDefined(); + for (const eventType of ANTIGRAVITY_HOOK_EVENT_TYPES) { + expect(Array.isArray(named[eventType])).toBe(true); + } + }); + + it("tool events use a {matcher:'*', hooks} wrapper; PreInvocation/Stop are flat handler arrays", () => { + const settings: Record = {}; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + const named = settings.failproofai as Record; + + // Tool events → wrapper with matcher "*". + const pre = named.PreToolUse[0]; + const post = named.PostToolUse[0]; + expect(pre.matcher).toBe("*"); + expect(Array.isArray(pre.hooks)).toBe(true); + expect(pre.hooks[0][FAILPROOFAI_HOOK_MARKER]).toBe(true); + expect(post.matcher).toBe("*"); + + // Flat events → the handler object sits directly in the array (no wrapper). + const preInvocation = named.PreInvocation[0]; + const stop = named.Stop[0]; + expect(preInvocation.matcher).toBeUndefined(); + expect(preInvocation.hooks).toBeUndefined(); + expect(preInvocation.type).toBe("command"); + expect(preInvocation[FAILPROOFAI_HOOK_MARKER]).toBe(true); + expect(stop.matcher).toBeUndefined(); + expect(stop.type).toBe("command"); + expect(stop[FAILPROOFAI_HOOK_MARKER]).toBe(true); + }); + + it("re-running writeHookEntries is idempotent (tool wrapper + flat handler)", () => { + const settings: Record = {}; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + antigravity.writeHookEntries(settings, "/different/path/failproofai", "user"); + const named = settings.failproofai as Record; + expect(named.PreToolUse).toHaveLength(1); + expect(named.PreToolUse[0].hooks).toHaveLength(1); + expect(named.Stop).toHaveLength(1); + }); + + it("removeHooksFromFile clears all failproofai entries (returns count)", () => { + const settingsPath = antigravity.getSettingsPath("project", tempDir); + const settings: Record = {}; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + antigravity.writeSettings(settingsPath, settings); + expect(existsSync(settingsPath)).toBe(true); + + const removed = antigravity.removeHooksFromFile(settingsPath); + expect(removed).toBe(ANTIGRAVITY_HOOK_EVENT_TYPES.length); + + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + // The named hook is dropped entirely once empty. + expect(after.failproofai).toBeUndefined(); + }); + + it("removeHooksFromFile preserves other named hooks", () => { + const settingsPath = antigravity.getSettingsPath("project", tempDir); + const settings: Record = { + "lint-checker": { + PostToolUse: [{ matcher: "run_command", hooks: [{ type: "command", command: "./lint.sh" }] }], + }, + }; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + antigravity.writeSettings(settingsPath, settings); + + antigravity.removeHooksFromFile(settingsPath); + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + // The user's own named hook survives; the failproofai named hook is gone. + expect(after["lint-checker"]).toBeDefined(); + expect(after["lint-checker"].PostToolUse[0].hooks[0].command).toBe("./lint.sh"); + expect(after.failproofai).toBeUndefined(); }); - it("GeminiHookEventType is exhaustive", () => { - const sample: GeminiHookEventType = "BeforeTool"; - expect(GEMINI_EVENT_MAP[sample]).toBe("PreToolUse"); + it("hooksInstalledInSettings detects installed hooks", () => { + const settingsPath = antigravity.getSettingsPath("project", tempDir); + const settings: Record = {}; + antigravity.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + antigravity.writeSettings(settingsPath, settings); + + expect(antigravity.hooksInstalledInSettings("project", tempDir)).toBe(true); }); }); -describe("GEMINI_TOOL_MAP", () => { - it("maps every documented Gemini snake_case tool name to a Claude PascalCase canonical name", () => { - expect(GEMINI_TOOL_MAP.run_shell_command).toBe("Bash"); - expect(GEMINI_TOOL_MAP.read_file).toBe("Read"); - expect(GEMINI_TOOL_MAP.read_many_files).toBe("Read"); - expect(GEMINI_TOOL_MAP.write_file).toBe("Write"); - expect(GEMINI_TOOL_MAP.replace).toBe("Edit"); - expect(GEMINI_TOOL_MAP.glob).toBe("Glob"); - expect(GEMINI_TOOL_MAP.grep_search).toBe("Grep"); - expect(GEMINI_TOOL_MAP.list_directory).toBe("LS"); - expect(GEMINI_TOOL_MAP.web_fetch).toBe("WebFetch"); - expect(GEMINI_TOOL_MAP.google_web_search).toBe("WebSearch"); - expect(GEMINI_TOOL_MAP.write_todos).toBe("TodoWrite"); - expect(GEMINI_TOOL_MAP.save_memory).toBe("Memory"); - expect(GEMINI_TOOL_MAP.ask_user).toBe("AskUser"); +describe("Goose integration", () => { + it("getSettingsPath maps user/project to the Open Plugins hooks.json in the plugin dir", () => { + expect(goose.getSettingsPath("project", tempDir)).toBe( + resolve(tempDir, ".agents", "plugins", "failproofai", "hooks", "hooks.json"), + ); + expect(goose.getSettingsPath("user")).toMatch( + /\.agents\/plugins\/failproofai\/hooks\/hooks\.json$/, + ); + }); + + it("scopes are user|project (no local)", () => { + expect(goose.scopes).toEqual(["user", "project"]); + }); + + it("subscribes to the 5 verified events and NOT Stop (goose has none)", () => { + expect(GOOSE_HOOK_EVENT_TYPES).toEqual([ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "SessionEnd", + ]); + expect(GOOSE_HOOK_EVENT_TYPES).not.toContain("Stop"); + }); + + it("buildHookEntry emits a clean {type, command} with --cli goose and NO marker field", () => { + const entry = goose.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "user"); + expect(entry.type).toBe("command"); + expect(entry.command).toContain("--cli goose"); + expect(entry.command).toContain("--hook PreToolUse"); + // Goose parses this file, so we add NO __failproofai_hook__ marker. + expect(entry[FAILPROOFAI_HOOK_MARKER]).toBeUndefined(); + expect(entry.timeout).toBeUndefined(); + }); + + it("project scope uses npx -y failproofai", () => { + const entry = goose.buildHookEntry("/usr/bin/failproofai", "PreToolUse", "project"); + expect(entry.command).toBe("npx -y failproofai --hook PreToolUse --cli goose"); + }); + + it("writeHookEntries writes the Open Plugins schema (top-level 'hooks' wrapper, matcher OMITTED)", () => { + const settings: Record = {}; + goose.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + const hooks = settings.hooks as Record; + expect(hooks).toBeDefined(); + for (const eventType of GOOSE_HOOK_EVENT_TYPES) { + expect(Array.isArray(hooks[eventType])).toBe(true); + const matcherObj = hooks[eventType][0]; + // matcher must be OMITTED — a bare "*" is an invalid regex that matches nothing. + expect(matcherObj.matcher).toBeUndefined(); + expect(Array.isArray(matcherObj.hooks)).toBe(true); + expect(matcherObj.hooks[0].command).toContain("--cli goose"); + } + }); + + it("re-running writeHookEntries is idempotent (updates in place, no dup)", () => { + const settings: Record = {}; + goose.writeHookEntries(settings, "/usr/bin/failproofai", "user"); + goose.writeHookEntries(settings, "/different/path/failproofai", "user"); + const hooks = settings.hooks as Record; + expect(hooks.PreToolUse).toHaveLength(1); + expect(hooks.PreToolUse[0].hooks).toHaveLength(1); + // Updated to the new binary path. + expect(hooks.PreToolUse[0].hooks[0].command).toContain("/different/path/failproofai"); + }); + + it("removeHooksFromFile clears all failproofai entries (returns count)", () => { + const settingsPath = goose.getSettingsPath("project", tempDir); + const settings: Record = {}; + goose.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + goose.writeSettings(settingsPath, settings); + expect(existsSync(settingsPath)).toBe(true); + + const removed = goose.removeHooksFromFile(settingsPath); + expect(removed).toBe(GOOSE_HOOK_EVENT_TYPES.length); + + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + expect(after.hooks).toBeUndefined(); + }); + + it("removeHooksFromFile preserves a user's own non-failproofai plugin hooks", () => { + const settingsPath = goose.getSettingsPath("project", tempDir); + const settings: Record = { + hooks: { + PostToolUse: [{ hooks: [{ type: "command", command: "${PLUGIN_ROOT}/scripts/log.sh" }] }], + }, + }; + goose.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + goose.writeSettings(settingsPath, settings); + + goose.removeHooksFromFile(settingsPath); + const after = JSON.parse(readFileSync(settingsPath, "utf-8")) as Record; + // The user's own log hook survives; failproofai's is gone. + const postHooks = after.hooks.PostToolUse.flatMap((m: any) => m.hooks); + expect(postHooks.some((h: any) => h.command.includes("log.sh"))).toBe(true); + expect(postHooks.some((h: any) => h.command.includes("--cli goose"))).toBe(false); + }); + + it("hooksInstalledInSettings detects installed hooks", () => { + const settingsPath = goose.getSettingsPath("project", tempDir); + const settings: Record = {}; + goose.writeHookEntries(settings, "/usr/bin/failproofai", "project"); + goose.writeSettings(settingsPath, settings); + + expect(goose.hooksInstalledInSettings("project", tempDir)).toBe(true); }); }); diff --git a/__tests__/hooks/openclaw-canonicalize.test.ts b/__tests__/hooks/openclaw-canonicalize.test.ts new file mode 100644 index 00000000..bb4d828f --- /dev/null +++ b/__tests__/hooks/openclaw-canonicalize.test.ts @@ -0,0 +1,75 @@ +// @vitest-environment node +// +// Locks in OpenClaw event + tool NAME + INPUT canonicalization (verified live +// against openclaw v2026.7.1: before_tool_call payload tool `exec` with params +// `{command}`; file tools deliver the path as `path`, which Claude builtins read +// as `file_path`). +import { describe, it, expect } from "vitest"; +import { canonicalizeToolName, canonicalizeToolInput } from "@/src/hooks/tool-name-canonicalize"; +import { + OPENCLAW_EVENT_MAP, + OPENCLAW_HOOK_EVENT_TYPES, + HOOK_EVENT_TYPES, +} from "@/src/hooks/types"; + +describe("OpenClaw event canonicalization", () => { + it("maps every subscribed hook to a valid canonical event", () => { + const canonical = new Set(HOOK_EVENT_TYPES); + for (const ev of OPENCLAW_HOOK_EVENT_TYPES) { + const mapped = OPENCLAW_EVENT_MAP[ev]; + expect(mapped, `${ev} must map`).toBeTruthy(); + expect(canonical.has(mapped), `${mapped} must be a HookEventType`).toBe(true); + } + }); + + it("maps the enforcement hooks to the right canonical events", () => { + expect(OPENCLAW_EVENT_MAP.before_tool_call).toBe("PreToolUse"); + expect(OPENCLAW_EVENT_MAP.after_tool_call).toBe("PostToolUse"); + expect(OPENCLAW_EVENT_MAP.before_agent_run).toBe("UserPromptSubmit"); + // before_agent_finalize is the real turn-end gate (unlike Hermes, which has none). + expect(OPENCLAW_EVENT_MAP.before_agent_finalize).toBe("Stop"); + expect(OPENCLAW_EVENT_MAP.session_start).toBe("SessionStart"); + expect(OPENCLAW_EVENT_MAP.session_end).toBe("SessionEnd"); + expect(OPENCLAW_EVENT_MAP.subagent_ended).toBe("SubagentStop"); + expect(OPENCLAW_EVENT_MAP.before_compaction).toBe("PreCompact"); + }); + + it("does not subscribe to agent_end (would double-fire Stop) or message_sending (deferred)", () => { + expect(OPENCLAW_HOOK_EVENT_TYPES).not.toContain("agent_end"); + expect(OPENCLAW_HOOK_EVENT_TYPES).not.toContain("message_sending"); + }); +}); + +describe("OpenClaw tool canonicalization", () => { + it("canonicalizes OpenClaw tool ids to Claude builtins", () => { + expect(canonicalizeToolName("exec", "openclaw")).toBe("Bash"); + expect(canonicalizeToolName("read", "openclaw")).toBe("Read"); + expect(canonicalizeToolName("write", "openclaw")).toBe("Write"); + expect(canonicalizeToolName("edit", "openclaw")).toBe("Edit"); + expect(canonicalizeToolName("grep", "openclaw")).toBe("Grep"); + expect(canonicalizeToolName("glob", "openclaw")).toBe("Glob"); + expect(canonicalizeToolName("web_search", "openclaw")).toBe("WebSearch"); + expect(canonicalizeToolName("web_fetch", "openclaw")).toBe("WebFetch"); + }); + + it("passes unknown OpenClaw tools through unchanged (browser, process, memory_*)", () => { + expect(canonicalizeToolName("browser", "openclaw")).toBe("browser"); + expect(canonicalizeToolName("process", "openclaw")).toBe("process"); + expect(canonicalizeToolName("memory_search", "openclaw")).toBe("memory_search"); + }); + + it("maps the file tools' `path` arg to `file_path` so path builtins fire", () => { + expect(canonicalizeToolInput("Read", { path: "/srv/.env" }, "openclaw")).toEqual({ file_path: "/srv/.env" }); + expect(canonicalizeToolInput("Write", { path: "/srv/x", content: "s" }, "openclaw")).toEqual({ + file_path: "/srv/x", + content: "s", + }); + expect(canonicalizeToolInput("Edit", { path: "/srv/x" }, "openclaw")).toEqual({ file_path: "/srv/x" }); + }); + + it("leaves exec's already-canonical `command` unchanged (matches Bash builtins)", () => { + expect(canonicalizeToolInput("Bash", { command: "sudo rm -rf /" }, "openclaw")).toEqual({ + command: "sudo rm -rf /", + }); + }); +}); diff --git a/__tests__/hooks/policy-evaluator.test.ts b/__tests__/hooks/policy-evaluator.test.ts index 7640c127..390aee65 100644 --- a/__tests__/hooks/policy-evaluator.test.ts +++ b/__tests__/hooks/policy-evaluator.test.ts @@ -271,6 +271,54 @@ describe("hooks/policy-evaluator", () => { expect(result.stderr).toContain("prefer git mv"); // surfaced on stderr for logs }); + it("OpenClaw deny on PreToolUse emits flat {permission:'deny'} (shim maps to {block:true})", async () => { + registerPolicy("blocker", "desc", () => ({ decision: "deny", reason: "no sudo" }), { + events: ["PreToolUse"], + }); + const result = await evaluatePolicies("PreToolUse", { tool_name: "Bash" }, { cli: "openclaw" }); + expect(result.exitCode).toBe(0); + expect(result.stderr).toBe(""); + expect(result.decision).toBe("deny"); + const parsed = JSON.parse(result.stdout) as Record; + expect(parsed.permission).toBe("deny"); + expect(parsed.reason).toContain("no sudo"); + }); + + it("OpenClaw deny on Stop emits MANDATORY-ACTION wording (shim maps to {action:'revise'})", async () => { + registerPolicy("commit", "desc", () => ({ decision: "deny", reason: "commit first" }), { + events: ["Stop"], + }); + const result = await evaluatePolicies("Stop", {}, { cli: "openclaw" }); + expect(result.exitCode).toBe(0); + expect(result.decision).toBe("deny"); + const parsed = JSON.parse(result.stdout) as Record; + expect(parsed.permission).toBe("deny"); + expect(String(parsed.reason)).toContain("MANDATORY ACTION REQUIRED"); + expect(String(parsed.reason)).toContain("commit first"); + }); + + it("OpenClaw instruct on Stop emits MANDATORY-ACTION deny (revise); on tool events degrades to allow + note", async () => { + registerPolicy("advise-stop", "desc", () => ({ decision: "instruct", reason: "run tests" }), { + events: ["Stop"], + }); + const stop = await evaluatePolicies("Stop", {}, { cli: "openclaw" }); + const stopParsed = JSON.parse(stop.stdout) as Record; + expect(stop.decision).toBe("instruct"); + expect(stopParsed.permission).toBe("deny"); // revise on Stop + expect(String(stopParsed.reason)).toContain("MANDATORY ACTION REQUIRED"); + + clearPolicies(); + registerPolicy("advise-tool", "desc", () => ({ decision: "instruct", reason: "prefer git mv" }), { + events: ["PreToolUse"], + }); + const pre = await evaluatePolicies("PreToolUse", { tool_name: "Bash" }, { cli: "openclaw" }); + expect(pre.decision).toBe("instruct"); + const preParsed = JSON.parse(pre.stdout) as Record; + expect(preParsed.permission).toBe("allow"); // does NOT block — no context channel on tool events + expect(preParsed.reason).toContain("prefer git mv"); + expect(pre.stderr).toContain("prefer git mv"); + }); + it("Cursor SubagentStop + instruct emits {followup_message} JSON (parity with Stop branch)", async () => { // The Cursor Stop instruct branch was widened to also match SubagentStop // so custom policies subscribing to SubagentStop on Cursor get the same @@ -376,25 +424,6 @@ describe("hooks/policy-evaluator", () => { expect(parsed.reason).toContain("fyi"); }); - it("Gemini Stop + instruct emits {decision:'block', reason} JSON on stdout (force-retry via AfterAgent)", async () => { - // Confirms the existing cli==="gemini" Stop arm in the instruct path - // emits the documented force-retry shape. Pairs with the deny-path - // test in the "Stop event deny format" describe block. - registerPolicy("verify", "desc", () => ({ - decision: "instruct", - reason: "needs verification", - }), { events: ["Stop"] }); - - const result = await evaluatePolicies("Stop", {}, { cli: "gemini" }); - expect(result.exitCode).toBe(0); - expect(result.stderr).toBe(""); - expect(result.decision).toBe("instruct"); - const parsed = JSON.parse(result.stdout) as { decision?: string; reason?: string }; - expect(parsed.decision).toBe("block"); - expect(parsed.reason).toContain("MANDATORY ACTION REQUIRED"); - expect(parsed.reason).toContain("needs verification"); - }); - it("accumulates multiple instruct messages", async () => { registerPolicy("first", "desc", () => ({ decision: "instruct", @@ -448,8 +477,11 @@ describe("hooks/policy-evaluator", () => { expect(result.decision).toBe("allow"); expect(result.policyName).toBe("failproofai/info1"); expect(result.policyNames).toEqual(["failproofai/info1", "failproofai/info2"]); - const parsed = JSON.parse(result.stdout); - expect(parsed.reason).toBe("Commit check passed\nPush check passed"); + // Stop has no agent-facing context channel, so the combined note is kept + // OUT of stdout (prevents droid-style "…skipping…" noise on a fine turn); + // it stays in the return `reason` + stderr for diagnostics. + expect(result.stdout).toBe(""); + expect(result.reason).toBe("Commit check passed\nPush check passed"); expect(result.stderr).toContain("[failproofai] failproofai/info1: Commit check passed"); expect(result.stderr).toContain("[failproofai] failproofai/info2: Push check passed"); }); @@ -874,25 +906,6 @@ describe("hooks/policy-evaluator", () => { expect(parsed.reason).toContain("sudo not allowed"); }); - it("Gemini Stop deny emits {decision:'block', reason} JSON on stdout (force-retry via AfterAgent)", async () => { - // Per Gemini's hooks docs (https://geminicli.com/docs/hooks/), the - // AfterAgent hook (canonical "Stop") force-retries when the hook - // returns `{decision: "block", reason}` on stdout. Exit-2 is per- - // action only ("turn continues") and would NOT trigger the retry. - registerPolicy("stop-blocker", "desc", () => ({ - decision: "deny", - reason: "tests not run", - }), { events: ["Stop"] }); - - const result = await evaluatePolicies("Stop", {}, { cli: "gemini" }); - expect(result.exitCode).toBe(0); - expect(result.stderr).toBe(""); - const parsed = JSON.parse(result.stdout) as { decision?: string; reason?: string }; - expect(parsed.decision).toBe("block"); - expect(parsed.reason).toContain("MANDATORY ACTION REQUIRED"); - expect(parsed.reason).toContain("tests not run"); - expect(result.decision).toBe("deny"); - }); }); describe("workflow policy chain integration", () => { @@ -940,11 +953,13 @@ describe("hooks/policy-evaluator", () => { expect(result.exitCode).toBe(0); expect(result.decision).toBe("allow"); expect(result.policyNames).toEqual(["failproofai/wf-commit", "failproofai/wf-push", "failproofai/wf-pr", "failproofai/wf-ci"]); - const parsed = JSON.parse(result.stdout); - expect(parsed.reason).toContain("All changes committed"); - expect(parsed.reason).toContain("All commits pushed"); - expect(parsed.reason).toContain("PR #42 exists"); - expect(parsed.reason).toContain("All CI checks passed"); + // Stop has no context channel → the combined note lives in the return + // `reason` + stderr (NOT stdout), so it isn't rendered as agent-facing noise. + expect(result.stdout).toBe(""); + expect(result.reason).toContain("All changes committed"); + expect(result.reason).toContain("All commits pushed"); + expect(result.reason).toContain("PR #42 exists"); + expect(result.reason).toContain("All CI checks passed"); }); it("allow messages from early policies are discarded when a later policy denies", async () => { @@ -994,8 +1009,9 @@ describe("hooks/policy-evaluator", () => { expect(result.decision).toBe("allow"); expect(result.policyName).toBe("failproofai/informative"); expect(result.policyNames).toEqual(["failproofai/informative"]); - const parsed = JSON.parse(result.stdout); - expect(parsed.reason).toBe("CI is green"); + // Stop note → return `reason` + stderr, stdout stays empty. + expect(result.stdout).toBe(""); + expect(result.reason).toBe("CI is green"); }); it("policy that throws is skipped — subsequent policies still run", async () => { @@ -1203,265 +1219,4 @@ describe("hooks/policy-evaluator", () => { expect(result.reason).toBe("hard block. deny hint"); }); }); - - describe("Gemini CLI response shape", () => { - const geminiSession = (hookEventName: string) => ({ - sessionId: "g-1", cwd: "/tmp", cli: "gemini" as const, hookEventName, - }); - - it("PreToolUse deny → flat {decision:'deny', reason} (NOT Claude's hookSpecificOutput shape)", async () => { - registerPolicy("blocker", "desc", () => ({ decision: "deny", reason: "sudo blocked" }), { - events: ["PreToolUse"], - }); - const result = await evaluatePolicies( - "PreToolUse", - { tool_name: "Bash", tool_input: { command: "sudo ls" } }, - geminiSession("BeforeTool"), - ); - expect(result.exitCode).toBe(0); - expect(result.stderr).toBe(""); - const parsed = JSON.parse(result.stdout); - expect(parsed.decision).toBe("deny"); - expect(parsed.reason).toContain("sudo blocked"); - expect(parsed.reason).toContain("Blocked Bash by failproofai"); - // Crucial: NOT Claude's nested shape - expect(parsed.hookSpecificOutput).toBeUndefined(); - }); - - it("BeforeAgent deny (UserPromptSubmit) → flat {decision:'deny', reason}", async () => { - registerPolicy("prompt-block", "desc", () => ({ decision: "deny", reason: "bad prompt" }), { - events: ["UserPromptSubmit"], - }); - const result = await evaluatePolicies( - "UserPromptSubmit", - { prompt: "" }, - geminiSession("BeforeAgent"), - ); - expect(result.exitCode).toBe(0); - const parsed = JSON.parse(result.stdout); - expect(parsed.decision).toBe("deny"); - expect(parsed.reason).toContain("bad prompt"); - expect(parsed.hookSpecificOutput).toBeUndefined(); - }); - - it("AfterAgent deny (Stop) → {decision:'block', reason} with MANDATORY ACTION REQUIRED prefix", async () => { - registerPolicy("must-do", "desc", () => ({ decision: "deny", reason: "missing CHANGELOG" }), { - events: ["Stop"], - }); - const result = await evaluatePolicies( - "Stop", - {}, - geminiSession("AfterAgent"), - ); - expect(result.exitCode).toBe(0); - const parsed = JSON.parse(result.stdout); - // Gemini's AfterAgent supports "Retry / Halt" via decision: "block" - expect(parsed.decision).toBe("block"); - expect(parsed.reason).toContain("MANDATORY ACTION REQUIRED"); - expect(parsed.reason).toContain("missing CHANGELOG"); - }); - - it("instruct on PreToolUse → {hookSpecificOutput:{hookEventName:'BeforeTool', additionalContext}}", async () => { - registerPolicy("advisor", "desc", () => ({ decision: "instruct", reason: "consider X" }), { - events: ["PreToolUse"], - }); - const result = await evaluatePolicies( - "PreToolUse", - { tool_name: "Bash" }, - geminiSession("BeforeTool"), - ); - expect(result.exitCode).toBe(0); - const parsed = JSON.parse(result.stdout); - // hookEventName must be the Gemini event name (not the canonical PreToolUse) - expect(parsed.hookSpecificOutput.hookEventName).toBe("BeforeTool"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("Instruction from failproofai"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("consider X"); - // Must NOT use Gemini's flat block shape — that's reserved for deny - expect(parsed.decision).toBeUndefined(); - }); - - it("instruct on AfterTool → {hookSpecificOutput:{hookEventName:'AfterTool', additionalContext}}", async () => { - registerPolicy("after", "desc", () => ({ decision: "instruct", reason: "post note" }), { - events: ["PostToolUse"], - }); - const result = await evaluatePolicies( - "PostToolUse", - { tool_name: "Read" }, - geminiSession("AfterTool"), - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.hookSpecificOutput.hookEventName).toBe("AfterTool"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("post note"); - }); - - it("instruct on SessionStart → {hookSpecificOutput:{hookEventName:'SessionStart', additionalContext}}", async () => { - registerPolicy("greet", "desc", () => ({ decision: "instruct", reason: "warm context" }), { - events: ["SessionStart"], - }); - const result = await evaluatePolicies( - "SessionStart", - {}, - geminiSession("SessionStart"), - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.hookSpecificOutput.hookEventName).toBe("SessionStart"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("warm context"); - }); - - it("instruct on AfterAgent (Stop) → {decision:'block', reason} with MANDATORY ACTION", async () => { - registerPolicy("must-do", "desc", () => ({ decision: "instruct", reason: "open the PR" }), { - events: ["Stop"], - }); - const result = await evaluatePolicies( - "Stop", - {}, - geminiSession("AfterAgent"), - ); - const parsed = JSON.parse(result.stdout); - // For Gemini AfterAgent, both deny and instruct map to {decision: "block"} which forces a retry. - expect(parsed.decision).toBe("block"); - expect(parsed.reason).toContain("MANDATORY ACTION REQUIRED"); - expect(parsed.reason).toContain("open the PR"); - }); - - it("multiple instruct on AfterAgent → reasons concatenated, single {decision:'block'} response", async () => { - registerPolicy("a", "desc", () => ({ decision: "instruct", reason: "first" }), { events: ["Stop"] }); - registerPolicy("b", "desc", () => ({ decision: "instruct", reason: "second" }), { events: ["Stop"] }); - const result = await evaluatePolicies( - "Stop", - {}, - geminiSession("AfterAgent"), - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.decision).toBe("block"); - expect(parsed.reason).toContain("first"); - expect(parsed.reason).toContain("second"); - }); - - it("instruct on a non-context-injection event (e.g. SessionEnd) → stderr only, no stdout JSON", async () => { - registerPolicy("byebye", "desc", () => ({ decision: "instruct", reason: "after-note" }), { - events: ["SessionEnd"], - }); - const result = await evaluatePolicies( - "SessionEnd", - {}, - geminiSession("SessionEnd"), - ); - // SessionEnd is observation-only on Gemini; we don't emit a stdout JSON shape - expect(result.stdout).toBe(""); - // Reason still surfaces via stderr for visibility - expect(result.stderr).toContain("after-note"); - }); - - it("allow with informational reason on BeforeAgent → context-injection shape", async () => { - registerPolicy("info", "desc", () => ({ decision: "allow", reason: "fyi" }), { - events: ["UserPromptSubmit"], - }); - const result = await evaluatePolicies( - "UserPromptSubmit", - { prompt: "x" }, - geminiSession("BeforeAgent"), - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.hookSpecificOutput.hookEventName).toBe("BeforeAgent"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("Note from failproofai"); - expect(parsed.hookSpecificOutput.additionalContext).toContain("fyi"); - }); - - it("allow with informational reason on SessionEnd → stderr only", async () => { - registerPolicy("info", "desc", () => ({ decision: "allow", reason: "fyi" }), { - events: ["SessionEnd"], - }); - const result = await evaluatePolicies( - "SessionEnd", - {}, - geminiSession("SessionEnd"), - ); - expect(result.stdout).toBe(""); - expect(result.stderr).toContain("fyi"); - }); - - it("allow without reason → empty stdout, exit 0 (no extra noise)", async () => { - registerPolicy("ok", "desc", () => ({ decision: "allow" }), { events: ["PreToolUse"] }); - const result = await evaluatePolicies( - "PreToolUse", - { tool_name: "Bash" }, - geminiSession("BeforeTool"), - ); - expect(result.exitCode).toBe(0); - expect(result.stdout).toBe(""); - }); - - it("instruct falls back to session.rawHookEventName when stdin omits hook_event_name", async () => { - registerPolicy("advisor", "desc", () => ({ decision: "instruct", reason: "consider X" }), { - events: ["PreToolUse"], - }); - const result = await evaluatePolicies( - "PreToolUse", - { tool_name: "Bash" }, - // session.hookEventName intentionally undefined; rawHookEventName carries - // the raw CLI --hook arg as captured by handler.ts. - { sessionId: "g", cwd: "/tmp", cli: "gemini", rawHookEventName: "BeforeTool" }, - ); - const parsed = JSON.parse(result.stdout); - // Must use the raw Gemini event name, NOT the canonicalized "PreToolUse". - expect(parsed.hookSpecificOutput.hookEventName).toBe("BeforeTool"); - }); - - it("allow-with-context also falls back to session.rawHookEventName", async () => { - registerPolicy("info", "desc", () => ({ decision: "allow", reason: "fyi" }), { - events: ["UserPromptSubmit"], - }); - const result = await evaluatePolicies( - "UserPromptSubmit", - { prompt: "x" }, - { sessionId: "g", cwd: "/tmp", cli: "gemini", rawHookEventName: "BeforeAgent" }, - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.hookSpecificOutput.hookEventName).toBe("BeforeAgent"); - }); - - it("session.hookEventName from stdin still wins over rawHookEventName when both are set", async () => { - registerPolicy("advisor", "desc", () => ({ decision: "instruct", reason: "x" }), { - events: ["PreToolUse"], - }); - const result = await evaluatePolicies( - "PreToolUse", - { tool_name: "Bash" }, - { sessionId: "g", cwd: "/tmp", cli: "gemini", hookEventName: "BeforeTool", rawHookEventName: "RawShouldLose" }, - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.hookSpecificOutput.hookEventName).toBe("BeforeTool"); - }); - - it("UserPromptSubmit deny on Gemini emits event-appropriate text (NOT 'Blocked unknown tool')", async () => { - registerPolicy("prompt-block", "desc", () => ({ decision: "deny", reason: "bad prompt" }), { - events: ["UserPromptSubmit"], - }); - const result = await evaluatePolicies( - "UserPromptSubmit", - { prompt: "" }, - geminiSession("BeforeAgent"), - ); - const parsed = JSON.parse(result.stdout); - // Without ctx.toolName, the deny message used to say "Blocked unknown tool"; - // now we branch on event type. - expect(parsed.reason).toMatch(/Blocked prompt/); - expect(parsed.reason).not.toMatch(/Blocked unknown tool/); - }); - - it("SessionStart deny emits 'Blocked session start' label, not 'unknown tool'", async () => { - registerPolicy("greet-block", "desc", () => ({ decision: "deny", reason: "no greeting" }), { - events: ["SessionStart"], - }); - const result = await evaluatePolicies( - "SessionStart", - {}, - geminiSession("SessionStart"), - ); - const parsed = JSON.parse(result.stdout); - expect(parsed.reason).toMatch(/Blocked session start/); - expect(parsed.reason).not.toMatch(/Blocked unknown tool/); - }); - }); }); diff --git a/__tests__/hooks/resolve-cwd.test.ts b/__tests__/hooks/resolve-cwd.test.ts index 882fc788..2b01c7da 100644 --- a/__tests__/hooks/resolve-cwd.test.ts +++ b/__tests__/hooks/resolve-cwd.test.ts @@ -10,7 +10,6 @@ const ALL_CLIS: IntegrationType[] = [ "copilot", "cursor", "pi", - "gemini", "opencode", ]; diff --git a/__tests__/hooks/resolve-transcript-path.test.ts b/__tests__/hooks/resolve-transcript-path.test.ts index ab74cb92..d3f950e6 100644 --- a/__tests__/hooks/resolve-transcript-path.test.ts +++ b/__tests__/hooks/resolve-transcript-path.test.ts @@ -13,16 +13,12 @@ vi.mock("../../lib/cursor-sessions", () => ({ vi.mock("../../lib/pi-sessions", () => ({ findPiTranscript: vi.fn(), })); -vi.mock("../../lib/gemini-sessions", () => ({ - findGeminiTranscript: vi.fn(), -})); import { resolveTranscriptPath } from "../../src/hooks/resolve-transcript-path"; import { findCodexTranscript } from "../../lib/codex-sessions"; import { findCopilotTranscript } from "../../lib/copilot-sessions"; import { findCursorTranscript } from "../../lib/cursor-sessions"; import { findPiTranscript } from "../../lib/pi-sessions"; -import { findGeminiTranscript } from "../../lib/gemini-sessions"; import type { IntegrationType } from "../../src/hooks/types"; describe("resolveTranscriptPath", () => { @@ -37,7 +33,6 @@ describe("resolveTranscriptPath", () => { "copilot", "cursor", "pi", - "gemini", "opencode", ]; it.each(cases)( @@ -60,7 +55,6 @@ describe("resolveTranscriptPath", () => { "copilot", "cursor", "pi", - "gemini", "opencode", ]; it.each(cases)("returns undefined when no stdin path AND no sessionId (%s)", (cli) => { @@ -109,13 +103,6 @@ describe("resolveTranscriptPath", () => { expect(out).toBe("/home/u/.pi/agent/sessions/encoded/2026-05-05_sess-pi.jsonl"); }); - it("gemini → findGeminiTranscript(sessionId)", () => { - vi.mocked(findGeminiTranscript).mockReturnValue("/home/u/.gemini/tmp/projhash/chats/sess-gemini.json"); - const out = resolveTranscriptPath("gemini", {}, "sess-gemini"); - expect(findGeminiTranscript).toHaveBeenCalledWith("sess-gemini"); - expect(out).toBe("/home/u/.gemini/tmp/projhash/chats/sess-gemini.json"); - }); - it("opencode → synthetic opencode-db:// marker (transcripts live in SQLite)", () => { const out = resolveTranscriptPath("opencode", {}, "ses_test_opencode001"); expect(out).toBe("opencode-db://ses_test_opencode001"); diff --git a/__tests__/lib/cli-registry.test.ts b/__tests__/lib/cli-registry.test.ts index ec721c34..238043dd 100644 --- a/__tests__/lib/cli-registry.test.ts +++ b/__tests__/lib/cli-registry.test.ts @@ -12,7 +12,7 @@ import { describe("lib/cli-registry", () => { it("KNOWN_CLI_IDS lists all supported CLIs in stable order", () => { - expect(KNOWN_CLI_IDS).toEqual(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + expect(KNOWN_CLI_IDS).toEqual(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); }); it("getCliEntry returns the entry for known ids and undefined for unknown", () => { @@ -22,15 +22,14 @@ describe("lib/cli-registry", () => { expect(getCliEntry("cursor")?.label).toBe("Cursor Agent"); expect(getCliEntry("opencode")?.label).toBe("OpenCode"); expect(getCliEntry("pi")?.label).toBe("Pi"); - expect(getCliEntry("gemini")?.label).toBe("Gemini CLI"); expect(getCliEntry("hermes")?.label).toBe("Hermes"); + expect(getCliEntry("goose")?.label).toBe("Goose"); expect(getCliEntry("unknown")).toBeUndefined(); }); it("getCliLabel falls back to the id itself for unknown", () => { expect(getCliLabel("claude")).toBe("Claude Code"); expect(getCliLabel("pi")).toBe("Pi"); - expect(getCliLabel("gemini")).toBe("Gemini CLI"); expect(getCliLabel("xyz")).toBe("xyz"); }); @@ -41,8 +40,8 @@ describe("lib/cli-registry", () => { expect(getCliBadgeClasses("cursor")).toContain("emerald"); expect(getCliBadgeClasses("opencode")).toContain("amber"); expect(getCliBadgeClasses("pi")).toContain("pink"); - expect(getCliBadgeClasses("gemini")).toContain("sky"); expect(getCliBadgeClasses("hermes")).toContain("indigo"); + expect(getCliBadgeClasses("goose")).toContain("lime"); expect(getCliBadgeClasses("unknown")).toContain("orange"); // falls back to claude }); @@ -52,8 +51,8 @@ describe("lib/cli-registry", () => { expect(isKnownCli("cursor")).toBe(true); expect(isKnownCli("opencode")).toBe(true); expect(isKnownCli("pi")).toBe(true); - expect(isKnownCli("gemini")).toBe(true); expect(isKnownCli("hermes")).toBe(true); + expect(isKnownCli("goose")).toBe(true); expect(isKnownCli("nope")).toBe(false); expect(isKnownCli(null)).toBe(false); expect(isKnownCli(undefined)).toBe(false); @@ -74,7 +73,7 @@ describe("lib/cli-registry", () => { it("listExternalCliEntries excludes claude", () => { const ids = listExternalCliEntries().map((c) => c.id); - expect(ids).toEqual(["codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + expect(ids).toEqual(["codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); }); it("each CLI has a unique badgeClasses string", () => { diff --git a/__tests__/lib/devin-sessions.test.ts b/__tests__/lib/devin-sessions.test.ts new file mode 100644 index 00000000..4c64e7b4 --- /dev/null +++ b/__tests__/lib/devin-sessions.test.ts @@ -0,0 +1,118 @@ +// @vitest-environment node +import { describe, it, expect } from "vitest"; +import { devinRowsToLogEntries, devinActiveConversationPath } from "@/lib/devin-sessions"; +import { logEntriesToEvents } from "@/src/audit/cli-adapters/shared"; + +/** Parsed `chat_message` objects as they come off `message_nodes.chat_message` + * (OpenAI-style, verified live against devin v3000.1.27): assistant tool calls + * are flat `tool_calls[].{id, name, arguments}` where `arguments` is already an + * object, and results are separate `role:"tool"` rows keyed by `tool_call_id`. + * `_created_at` is the DB row's epoch-seconds timestamp injected by the loader. */ +const msg = (o: Record) => o; + +describe("lib/devin-sessions: devinRowsToLogEntries", () => { + it("pairs a tool result onto its tool_use by tool_call_id (flat name/arguments)", () => { + const entries = devinRowsToLogEntries([ + msg({ role: "user", content: "run it", _created_at: 1_784_016_000 }), + msg({ + role: "assistant", + content: "ok", + tool_calls: [{ id: "call_1", name: "exec", arguments: { command: "echo hi" }, index: 0, kind: "function" }], + _created_at: 1_784_016_001, + }), + msg({ role: "tool", tool_call_id: "call_1", content: "hi\nExit code: 0", _created_at: 1_784_016_002 }), + ]); + const assistant = entries.find((e) => e.type === "assistant"); + const toolUse = + assistant?.type === "assistant" + ? assistant.message.content.find((b) => b.type === "tool_use") + : undefined; + expect(toolUse).toMatchObject({ type: "tool_use", name: "exec", input: { command: "echo hi" } }); + expect(toolUse && "result" in toolUse ? toolUse.result?.content : "").toContain("hi"); + }); + + it("canonicalizes exec→Bash through logEntriesToEvents", () => { + const entries = devinRowsToLogEntries([ + msg({ role: "assistant", tool_calls: [{ id: "c1", name: "exec", arguments: { command: "ls" } }], _created_at: 1_784_016_000 }), + ]); + const events = logEntriesToEvents(entries, { cli: "devin", sessionId: "s", transcriptPath: "devin-db://s", cwd: "" }); + expect(events).toHaveLength(1); + expect(events[0]).toMatchObject({ toolName: "Bash", rawToolName: "exec", toolInput: { command: "ls" } }); + }); + + it("prefers metadata.created_at (ISO) over the injected _created_at row value", () => { + const entries = devinRowsToLogEntries([ + msg({ role: "user", content: "hi", _created_at: 1_784_016_000, metadata: { created_at: "2026-07-14T07:59:58.000Z" } }), + ]); + expect(entries[0].timestamp).toBe("2026-07-14T07:59:58.000Z"); + }); + + it("keeps system / unknown roles as system entries (never dropped)", () => { + const entries = devinRowsToLogEntries([ + msg({ role: "system", content: "env info", _created_at: 1 }), + msg({ role: "user", content: "hi", _created_at: 2 }), + ]); + expect(entries.some((e) => e.type === "system")).toBe(true); + expect(entries.some((e) => e.type === "user")).toBe(true); + }); + + it("drops an assistant turn with empty content and no tool_calls", () => { + const entries = devinRowsToLogEntries([ + msg({ role: "assistant", content: "", tool_calls: [], _created_at: 1 }), + ]); + expect(entries).toHaveLength(0); + }); + + it("returns [] for no rows", () => { + expect(devinRowsToLogEntries([])).toHaveLength(0); + }); +}); + +describe("lib/devin-sessions: devinActiveConversationPath (forest de-dup)", () => { + const node = (id: number, parent: number | null, text: string) => ({ + node_id: id, + parent_node_id: parent, + chat_message: JSON.stringify({ role: "user", content: text, message_id: `m${text}` }), + created_at: id, + }); + + it("returns only the newest leaf's root→leaf path, dropping replayed branches", () => { + // Mirrors the real Devin shape: an early branch (0→1→2) is replayed under a + // later root (3→4→5) that ends at the newest leaf. Reading all nodes would + // duplicate A/B; the active path is just the newest chain. + const rows = [ + node(0, null, "A"), + node(1, 0, "B"), + node(2, 1, "C"), // dead branch leaf + node(3, null, "A"), // replay root + node(4, 3, "B"), // replay + node(5, 4, "D"), // newest leaf + ]; + const path = devinActiveConversationPath(rows).map((r) => + JSON.parse(r.chat_message!).content, + ); + expect(path).toEqual(["A", "B", "D"]); // 5→4→3 reversed; branch 0-2 dropped + }); + + it("picks the branch to the max node_id when a parent has sibling children", () => { + // node 5 and 6 both child of 4; the newest leaf (7, under 6) wins. + const rows = [ + node(0, null, "root"), + node(4, 0, "shared"), + node(5, 4, "deadSibling"), + node(6, 4, "liveSibling"), + node(7, 6, "leaf"), + ]; + const path = devinActiveConversationPath(rows).map((r) => + JSON.parse(r.chat_message!).content, + ); + expect(path).toEqual(["root", "shared", "liveSibling", "leaf"]); + expect(path).not.toContain("deadSibling"); + }); + + it("handles a single linear chain unchanged and [] for no rows", () => { + const rows = [node(0, null, "x"), node(1, 0, "y")]; + expect(devinActiveConversationPath(rows).map((r) => JSON.parse(r.chat_message!).content)).toEqual(["x", "y"]); + expect(devinActiveConversationPath([])).toEqual([]); + }); +}); diff --git a/__tests__/lib/download-session.test.ts b/__tests__/lib/download-session.test.ts index c9e27916..032ee20c 100644 --- a/__tests__/lib/download-session.test.ts +++ b/__tests__/lib/download-session.test.ts @@ -14,7 +14,7 @@ describe("lib/download-session: isValidSessionId", () => { }); it("accepts UUIDs for non-opencode CLIs", () => { - for (const cli of ["claude", "codex", "copilot", "cursor", "pi", "gemini"] as const) { + for (const cli of ["claude", "codex", "copilot", "cursor", "pi"] as const) { expect(isValidSessionId(cli, VALID_UUID)).toBe(true); expect(isValidSessionId(cli, "ses_abc123")).toBe(false); expect(isValidSessionId(cli, "not-a-uuid")).toBe(false); @@ -41,7 +41,6 @@ describe("lib/download-session: resolveDownloadSource", () => { vi.doUnmock("@/lib/copilot-sessions"); vi.doUnmock("@/lib/cursor-sessions"); vi.doUnmock("@/lib/pi-sessions"); - vi.doUnmock("@/lib/gemini-sessions"); vi.doUnmock("@/lib/opencode-sessions"); }); @@ -85,7 +84,6 @@ describe("lib/download-session: resolveDownloadSource", () => { ["copilot", "@/lib/copilot-sessions", "findCopilotTranscript"], ["cursor", "@/lib/cursor-sessions", "findCursorTranscript"], ["pi", "@/lib/pi-sessions", "findPiTranscript"], - ["gemini", "@/lib/gemini-sessions", "findGeminiTranscript"], ] as const)( "%s: returns {kind:'file', path} when transcript is found", async (cli, modulePath, fnName) => { @@ -102,7 +100,6 @@ describe("lib/download-session: resolveDownloadSource", () => { ["copilot", "@/lib/copilot-sessions", "findCopilotTranscript"], ["cursor", "@/lib/cursor-sessions", "findCursorTranscript"], ["pi", "@/lib/pi-sessions", "findPiTranscript"], - ["gemini", "@/lib/gemini-sessions", "findGeminiTranscript"], ] as const)("%s: returns null when transcript is missing", async (cli, modulePath, fnName) => { vi.doMock(modulePath, () => ({ [fnName]: () => null })); vi.resetModules(); diff --git a/__tests__/lib/gemini-projects.test.ts b/__tests__/lib/gemini-projects.test.ts deleted file mode 100644 index c9b4eca2..00000000 --- a/__tests__/lib/gemini-projects.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -// @vitest-environment node -import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs"; -import { join } from "node:path"; -import { tmpdir } from "node:os"; - -import { - getGeminiSessionsForCwd, - getGeminiSessionsByEncodedName, -} from "@/lib/gemini-projects"; - -const FULL_UUID = "89eb30b0-27c0-4ea3-a5b9-06fc00085610"; -const PREFIX = FULL_UUID.slice(0, 8); - -function header(sessionId: string, startTime = "2026-05-09T12:00:00.000Z"): string { - return JSON.stringify({ - sessionId, - projectHash: "deadbeef", - startTime, - lastUpdated: startTime, - kind: "chat", - }); -} - -describe("lib/gemini-projects", () => { - let originalRoot: string | undefined; - let fakeRoot: string; - - function makeProject(basename: string, cwd: string) { - const projectDir = join(fakeRoot, basename); - mkdirSync(join(projectDir, "chats"), { recursive: true }); - writeFileSync(join(projectDir, ".project_root"), cwd); - return projectDir; - } - - function writeSession(projectDir: string, prefix: string, body: string) { - // Filename matches `session-YYYY-MM-DDTHH-MM-<8hex>.jsonl` (gemini-cli v0.40.1). - const filename = `session-2026-05-09T12-00-${prefix}.jsonl`; - writeFileSync(join(projectDir, "chats", filename), body); - return filename; - } - - beforeEach(() => { - originalRoot = process.env.GEMINI_SESSIONS_DIR; - fakeRoot = mkdtempSync(join(tmpdir(), "gemini-projects-")); - process.env.GEMINI_SESSIONS_DIR = fakeRoot; - }); - - afterEach(() => { - if (originalRoot === undefined) delete process.env.GEMINI_SESSIONS_DIR; - else process.env.GEMINI_SESSIONS_DIR = originalRoot; - rmSync(fakeRoot, { recursive: true, force: true }); - }); - - it("exposes the full UUID from the JSONL metadata header — not the 8-char filename prefix", async () => { - // Regression for #337: the project page rendered links with an 8-hex - // sessionId, which the session detail route's UUID_RE check rejected (404). - // Building the link from the metadata header's full UUID round-trips. - const cwd = "/home/u/dev-purge"; - const projectDir = makeProject("dev-purge", cwd); - writeSession(projectDir, PREFIX, header(FULL_UUID) + "\n"); - - const byCwd = await getGeminiSessionsForCwd(cwd); - expect(byCwd).toHaveLength(1); - expect(byCwd[0].sessionId).toBe(FULL_UUID); - expect(byCwd[0].sessionId).not.toBe(PREFIX); - - const byName = await getGeminiSessionsByEncodedName("-home-u-dev-purge"); - expect(byName.cwd).toBe(cwd); - expect(byName.sessions).toHaveLength(1); - expect(byName.sessions[0].sessionId).toBe(FULL_UUID); - }); - - it("leaves sessionId undefined when the metadata header is malformed JSON", async () => { - // Un-parseable header → un-linked row in the dashboard. Better than a - // clickable link to the 8-hex prefix that 404s. - const cwd = "/home/u/broken"; - const projectDir = makeProject("broken", cwd); - writeSession(projectDir, PREFIX, "not json\n"); - - const byCwd = await getGeminiSessionsForCwd(cwd); - expect(byCwd).toHaveLength(1); - expect(byCwd[0].sessionId).toBeUndefined(); - - const byName = await getGeminiSessionsByEncodedName("-home-u-broken"); - expect(byName.sessions).toHaveLength(1); - expect(byName.sessions[0].sessionId).toBeUndefined(); - }); - - it("leaves sessionId undefined when the metadata header lacks a sessionId field", async () => { - const cwd = "/home/u/headerless"; - const projectDir = makeProject("headerless", cwd); - writeSession( - projectDir, - PREFIX, - JSON.stringify({ projectHash: "x", startTime: "2026-05-09T12:00:00.000Z" }) + "\n", - ); - - const byCwd = await getGeminiSessionsForCwd(cwd); - expect(byCwd).toHaveLength(1); - expect(byCwd[0].sessionId).toBeUndefined(); - }); - - it("leaves sessionId undefined when meta.sessionId is not a UUID", async () => { - const cwd = "/home/u/nonuuid"; - const projectDir = makeProject("nonuuid", cwd); - writeSession(projectDir, PREFIX, header("not-a-uuid") + "\n"); - - const byCwd = await getGeminiSessionsForCwd(cwd); - expect(byCwd).toHaveLength(1); - expect(byCwd[0].sessionId).toBeUndefined(); - }); -}); diff --git a/__tests__/lib/goose-sessions.test.ts b/__tests__/lib/goose-sessions.test.ts new file mode 100644 index 00000000..b96db26a --- /dev/null +++ b/__tests__/lib/goose-sessions.test.ts @@ -0,0 +1,131 @@ +// @vitest-environment node +// +// Unit tests for the PURE Goose message parser (gooseRowsToLogEntries) and the +// timestamp coercion helper. Uses content_json shapes captured live from goose +// v1.43.0 (sessions.db, schema_version 15): typed-block arrays with `text`, +// `toolRequest`, and `toolResponse` blocks; tool RESULTS arrive in role:"user" +// rows and must attach to the matching earlier tool_use by id. +import { describe, it, expect } from "vitest"; +import { + gooseRowsToLogEntries, + gooseTimestampToMs, + GOOSE_SESSION_ID_RE, + type GooseMessageRow, +} from "@/lib/goose-sessions"; + +function row(role: string, blocks: unknown[], ts: number): GooseMessageRow { + return { role, content_json: JSON.stringify(blocks), created_timestamp: ts }; +} + +const T0 = 1_784_000_000_000; // > 1e12 → treated as epoch ms + +describe("gooseTimestampToMs", () => { + it("passes epoch-ms through and scales epoch-seconds to ms", () => { + expect(gooseTimestampToMs(T0)).toBe(T0); + expect(gooseTimestampToMs(1_700_000_000)).toBe(1_700_000_000_000); + }); + + it("parses SQLite CURRENT_TIMESTAMP strings as UTC", () => { + // "YYYY-MM-DD HH:MM:SS" has no zone; must be read as UTC, not local. + expect(gooseTimestampToMs("2026-07-14 16:01:00")).toBe(Date.parse("2026-07-14T16:01:00Z")); + }); + + it("returns a finite number for unparseable input (fallback to now)", () => { + expect(Number.isFinite(gooseTimestampToMs("not-a-date"))).toBe(true); + expect(Number.isFinite(gooseTimestampToMs(null))).toBe(true); + }); +}); + +describe("GOOSE_SESSION_ID_RE", () => { + it("matches date-prefixed counters and rejects UUIDs / traversal", () => { + expect(GOOSE_SESSION_ID_RE.test("20260714_3")).toBe(true); + expect(GOOSE_SESSION_ID_RE.test("20260714_12")).toBe(true); + expect(GOOSE_SESSION_ID_RE.test("not-a-session")).toBe(false); + expect(GOOSE_SESSION_ID_RE.test("../etc/passwd")).toBe(false); + }); +}); + +describe("gooseRowsToLogEntries", () => { + const rows: GooseMessageRow[] = [ + row("user", [{ type: "text", text: "Run the shell command: echo AUDIT" }], T0), + row( + "assistant", + [ + { + type: "toolRequest", + id: "call_1", + toolCall: { status: "success", value: { name: "shell", arguments: { command: "echo AUDIT" } } }, + _meta: { goose_extension: "developer" }, + }, + ], + T0 + 1000, + ), + row( + "user", + [ + { + type: "toolResponse", + id: "call_1", + toolResult: { + status: "success", + value: { content: [{ type: "text", text: "AUDIT" }], structuredContent: { stdout: "AUDIT" }, isError: false }, + }, + }, + ], + T0 + 2000, + ), + row("assistant", [{ type: "text", text: "The command printed AUDIT" }], T0 + 3000), + ]; + + it("produces user + assistant(tool) + assistant(text) entries (tool-result row adds none)", () => { + const entries = gooseRowsToLogEntries(rows); + // 4 rows, but the pure tool-result row attaches to the tool_use rather than + // producing its own entry → 3 entries. + expect(entries).toHaveLength(3); + expect(entries[0].type).toBe("user"); + expect(entries[1].type).toBe("assistant"); + expect(entries[2].type).toBe("assistant"); + }); + + it("keeps the raw goose tool name (canonicalization happens downstream)", () => { + const entries = gooseRowsToLogEntries(rows); + const asst = entries[1] as unknown as { message: { content: Array> } }; + const toolUse = asst.message.content.find((b) => b.type === "tool_use") as + | { name: string; input: Record; result?: { content: string } } + | undefined; + expect(toolUse).toBeDefined(); + expect(toolUse?.name).toBe("shell"); // NOT "Bash" — logEntriesToEvents maps it later + expect((toolUse?.input as { command?: string }).command).toBe("echo AUDIT"); + }); + + it("pairs a toolResponse (in a role:user row) with its earlier toolRequest by id", () => { + const entries = gooseRowsToLogEntries(rows); + const asst = entries[1] as unknown as { message: { content: Array> } }; + const toolUse = asst.message.content.find((b) => b.type === "tool_use") as + | { result?: { content: string } } + | undefined; + expect(toolUse?.result?.content).toBe("AUDIT"); + }); + + it("carries the user text through", () => { + const entries = gooseRowsToLogEntries(rows); + const user = entries[0] as unknown as { message: { content: string } }; + expect(user.message.content).toBe("Run the shell command: echo AUDIT"); + }); + + it("skips rows with empty / non-array content_json without crashing", () => { + const bad: GooseMessageRow[] = [ + { role: "user", content_json: null, created_timestamp: T0 }, + { role: "assistant", content_json: "not json", created_timestamp: T0 }, + { role: "assistant", content_json: JSON.stringify({ not: "array" }), created_timestamp: T0 }, + ]; + expect(gooseRowsToLogEntries(bad)).toHaveLength(0); + }); + + it("does not crash on an orphan toolResponse (no matching request)", () => { + const orphan: GooseMessageRow[] = [ + row("user", [{ type: "toolResponse", id: "missing", toolResult: { value: { content: [] } } }], T0), + ]; + expect(() => gooseRowsToLogEntries(orphan)).not.toThrow(); + }); +}); diff --git a/__tests__/lib/openclaw-projects.test.ts b/__tests__/lib/openclaw-projects.test.ts new file mode 100644 index 00000000..52cf424b --- /dev/null +++ b/__tests__/lib/openclaw-projects.test.ts @@ -0,0 +1,104 @@ +// @vitest-environment node +// +// Covers OpenClaw dashboard enumeration: reads the on-disk transcripts + +// per-agent sessions.json index, groups by **channel** (from metadata fields — +// OpenClaw routes gateway sessions through the default key and records the +// channel in `lastChannel`/`origin`, verified live v2026.7.1), and names +// sessions from the human-readable `origin.label`. OPENCLAW_HOME fixture. +import { describe, it, expect, afterEach } from "vitest"; +import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { + getOpenClawSessions, + getOpenClawProjects, + getOpenClawSessionsByEncodedName, +} from "@/lib/openclaw-projects"; + +const UUID_TG = "aa111111-2222-3333-4444-555555555555"; +const UUID_CLI = "f9e8516e-fed2-4e54-acbe-7a20aefc6cfa"; + +let home: string | undefined; +const prev = process.env.OPENCLAW_HOME; + +function seed(): string { + const h = mkdtempSync(join(tmpdir(), "openclaw-proj-")); + const sessions = join(h, "agents", "main", "sessions"); + mkdirSync(sessions, { recursive: true }); + writeFileSync(join(sessions, `${UUID_TG}.jsonl`), JSON.stringify({ type: "session", cwd: "/x" }) + "\n"); + writeFileSync(join(sessions, `${UUID_CLI}.jsonl`), JSON.stringify({ type: "session", cwd: "/x" }) + "\n"); + writeFileSync( + join(sessions, "sessions.json"), + JSON.stringify({ + // A Telegram gateway session — channel lives in metadata, not the key. + "agent:main:main": { + sessionId: UUID_TG, + lastInteractionAt: 5000, + lastChannel: "telegram", + lastTo: "telegram:8674922496", + chatType: "direct", + origin: { label: "Chetan (@chhhee10) id:8674922496", provider: "telegram", from: "telegram:8674922496", chatType: "direct" }, + }, + // A pure CLI/local session — no channel metadata. + "agent:main:cli": { sessionId: UUID_CLI, lastInteractionAt: 2000 }, + }), + ); + process.env.OPENCLAW_HOME = h; + return h; +} + +afterEach(() => { + if (home) rmSync(home, { recursive: true, force: true }); + home = undefined; + if (prev === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = prev; +}); + +describe("getOpenClawSessions", () => { + it("derives channel + label + chat metadata from sessions.json (not the key)", async () => { + home = seed(); + const sessions = await getOpenClawSessions(); + // Sorted by mtime desc → telegram (5000) before cli (2000). + expect(sessions.map((s) => s.sessionId)).toEqual([UUID_TG, UUID_CLI]); + + const tg = sessions.find((s) => s.sessionId === UUID_TG)!; + expect(tg.channel).toBe("telegram"); + expect(tg.label).toBe("Chetan (@chhhee10) id:8674922496"); + expect(tg.chatType).toBe("direct"); + expect(tg.chatId).toBe("telegram:8674922496"); + + const cli = sessions.find((s) => s.sessionId === UUID_CLI)!; + expect(cli.channel).toBe("local"); // no channel metadata → local + expect(cli.label).toBeUndefined(); + }); +}); + +describe("getOpenClawProjects / getOpenClawSessionsByEncodedName", () => { + it("groups sessions into one project per channel", async () => { + home = seed(); + const projects = await getOpenClawProjects(); + // telegram (newest) first, then local. + expect(projects.map((p) => p.name)).toEqual(["openclaw-telegram", "openclaw-local"]); + expect(projects[0].path).toBe("openclaw:telegram"); + expect(projects[0].cli).toEqual(["openclaw"]); + }); + + it("names sessions by origin.label and carries channel metadata; non-openclaw names return empty", async () => { + home = seed(); + const tg = await getOpenClawSessionsByEncodedName("openclaw-telegram"); + expect(tg.sessions).toHaveLength(1); + const s = tg.sessions[0]; + expect(s.name).toBe("Chetan (@chhhee10) id:8674922496"); // readable, not the raw key + expect(s.path).toBe(UUID_TG); // real transcript → download streams the file + expect(s.cli).toBe("openclaw"); + expect(s.channelId).toBe("telegram:8674922496"); + expect(s.channelType).toBe("direct"); + + const local = await getOpenClawSessionsByEncodedName("openclaw-local"); + expect(local.sessions).toHaveLength(1); + expect(local.sessions[0].name).toBe(UUID_CLI); // no label → falls back to id + + const none = await getOpenClawSessionsByEncodedName("claude-foo"); + expect(none.sessions).toEqual([]); + }); +}); diff --git a/__tests__/lib/openclaw-sessions.test.ts b/__tests__/lib/openclaw-sessions.test.ts new file mode 100644 index 00000000..3a3147f3 --- /dev/null +++ b/__tests__/lib/openclaw-sessions.test.ts @@ -0,0 +1,124 @@ +// @vitest-environment node +// +// Locks in the pure OpenClaw transcript parser + UUID-based transcript +// resolution. Line shapes mirror a real ~/.openclaw/agents/main/sessions/ +// .jsonl captured live from openclaw v2026.7.1: type-discriminated lines +// where `type:"message"` wraps {role, content}; assistant content is a list of +// {type:"text"} / {type:"toolCall", id, name, arguments}; results arrive as a +// {role:"toolResult", toolCallId, toolName, content, details} message. +import { describe, it, expect } from "vitest"; +import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { + openclawLinesToLogEntries, + findOpenClawTranscript, + listOpenClawTranscripts, + OPENCLAW_SESSION_ID_RE, +} from "@/lib/openclaw-sessions"; +import type { AssistantEntry } from "@/lib/log-entries"; + +const UUID = "f9e8516e-fed2-4e54-acbe-7a20aefc6cfa"; + +const LINES: Record[] = [ + { type: "session", version: 3, id: UUID, timestamp: "2026-07-14T05:01:34.420Z", cwd: "/home/node/.openclaw/workspace" }, + { type: "model_change", id: "m1", timestamp: "2026-07-14T05:01:34.431Z", provider: "groq", modelId: "x" }, + { type: "custom", customType: "model-snapshot", data: {}, id: "c1", timestamp: "2026-07-14T05:01:34.527Z" }, + { type: "message", id: "u1", parentId: null, timestamp: "2026-07-14T05:10:20.000Z", message: { role: "user", content: "run echo probe" } }, + { + type: "message", + id: "a1", + parentId: "u1", + timestamp: "2026-07-14T05:10:25.000Z", + message: { + role: "assistant", + model: "llama-4-scout", + content: [ + { type: "text", text: "Running it." }, + { type: "toolCall", id: "c5sf91qpf", name: "exec", arguments: { command: "echo probe-test-123" } }, + ], + }, + }, + { + type: "message", + id: "t1", + parentId: "a1", + timestamp: "2026-07-14T05:10:26.000Z", + message: { + role: "toolResult", + toolCallId: "c5sf91qpf", + toolName: "exec", + content: [{ type: "text", text: "probe-test-123" }], + details: { status: "completed", exitCode: 0, durationMs: 19 }, + isError: false, + }, + }, +]; + +describe("openclawLinesToLogEntries", () => { + it("skips non-message metadata lines (session/model_change/custom)", () => { + const entries = openclawLinesToLogEntries(LINES); + // Only the user + assistant turns become entries (toolResult is folded in). + expect(entries.map((e) => e.type)).toEqual(["user", "assistant"]); + }); + + it("parses the user turn (string content)", () => { + const entries = openclawLinesToLogEntries(LINES); + const user = entries[0]; + expect(user.type).toBe("user"); + if (user.type === "user") expect(user.message.content).toBe("run echo probe"); + }); + + it("parses assistant text + toolCall and pairs the toolResult by toolCallId", () => { + const entries = openclawLinesToLogEntries(LINES); + const asst = entries.find((e) => e.type === "assistant") as AssistantEntry; + expect(asst.message.model).toBe("llama-4-scout"); + const [text, tool] = asst.message.content; + expect(text).toEqual({ type: "text", text: "Running it." }); + expect(tool.type).toBe("tool_use"); + if (tool.type === "tool_use") { + expect(tool.name).toBe("exec"); + expect(tool.input).toEqual({ command: "echo probe-test-123" }); + // Result folded in from the later toolResult message. + expect(tool.result?.content).toBe("probe-test-123"); + expect(tool.result?.durationMs).toBe(19); // from details.durationMs + } + }); + + it("is pure — no filesystem access, safe on empty input", () => { + expect(openclawLinesToLogEntries([])).toEqual([]); + }); +}); + +describe("OpenClaw transcript resolution", () => { + it("session-id regex accepts UUIDs and rejects traversal / non-UUID", () => { + expect(OPENCLAW_SESSION_ID_RE.test(UUID)).toBe(true); + expect(OPENCLAW_SESSION_ID_RE.test("../../etc/passwd")).toBe(false); + expect(OPENCLAW_SESSION_ID_RE.test("agent:main:main")).toBe(false); + expect(OPENCLAW_SESSION_ID_RE.test("")).toBe(false); + }); + + it("discovers transcripts under agents//sessions and skips trajectory files", () => { + const home = mkdtempSync(join(tmpdir(), "openclaw-home-")); + const sessions = join(home, "agents", "main", "sessions"); + mkdirSync(sessions, { recursive: true }); + writeFileSync(join(sessions, `${UUID}.jsonl`), LINES.map((l) => JSON.stringify(l)).join("\n")); + // Heavy OTel trace + pointer must be ignored. + writeFileSync(join(sessions, `${UUID}.trajectory.jsonl`), "{}\n"); + writeFileSync(join(sessions, `${UUID}.trajectory-path.json`), "{}\n"); + const prev = process.env.OPENCLAW_HOME; + process.env.OPENCLAW_HOME = home; + try { + const found = listOpenClawTranscripts(); + expect(found.map((t) => t.sessionId)).toEqual([UUID]); + expect(found[0].agentId).toBe("main"); + expect(findOpenClawTranscript(UUID)).toBe(join(sessions, `${UUID}.jsonl`)); + // Traversal id never resolves. + expect(findOpenClawTranscript("../../etc/passwd")).toBeNull(); + } finally { + if (prev === undefined) delete process.env.OPENCLAW_HOME; + else process.env.OPENCLAW_HOME = prev; + rmSync(home, { recursive: true, force: true }); + } + }); +}); diff --git a/__tests__/lib/projects.test.ts b/__tests__/lib/projects.test.ts index cf03caf1..94121532 100644 --- a/__tests__/lib/projects.test.ts +++ b/__tests__/lib/projects.test.ts @@ -40,9 +40,6 @@ vi.mock("@/lib/pi-projects", () => ({ getPiProjects: vi.fn(async () => []), })); -vi.mock("@/lib/gemini-projects", () => ({ - getGeminiProjects: vi.fn(async () => []), -})); // Mock hermes-projects too — getProjectFolders() calls getHermesProjects(), // which does real ~/.hermes/state.db I/O; without this the suite is non-hermetic // and fails on any box with a real gateway DB. @@ -50,6 +47,12 @@ vi.mock("@/lib/hermes-projects", () => ({ getHermesProjects: vi.fn(async () => []), })); +// Antigravity reads the real ~/.gemini/antigravity-cli/brain dir; mock it to [] +// so a developer's local Antigravity sessions don't leak into these assertions. +vi.mock("@/lib/antigravity-projects", () => ({ + getAntigravityProjects: vi.fn(async () => []), +})); + import { readdir, stat } from "fs/promises"; import { extractSessionId, getProjectFolders, getSessionFiles, type ProjectFolder } from "@/lib/projects"; import { getCodexProjects } from "@/lib/codex-projects"; @@ -57,7 +60,6 @@ import { getCopilotProjects } from "@/lib/copilot-projects"; import { getCursorProjects } from "@/lib/cursor-projects"; import { getOpenCodeProjects } from "@/lib/opencode-projects"; import { getPiProjects } from "@/lib/pi-projects"; -import { getGeminiProjects } from "@/lib/gemini-projects"; import { getHermesProjects } from "@/lib/hermes-projects"; const mockGetCodexProjects = vi.mocked(getCodexProjects); @@ -65,7 +67,6 @@ const mockGetCopilotProjects = vi.mocked(getCopilotProjects); const mockGetCursorProjects = vi.mocked(getCursorProjects); const mockGetOpenCodeProjects = vi.mocked(getOpenCodeProjects); const mockGetPiProjects = vi.mocked(getPiProjects); -const mockGetGeminiProjects = vi.mocked(getGeminiProjects); const mockGetHermesProjects = vi.mocked(getHermesProjects); const mockReaddir = vi.mocked(readdir); @@ -534,26 +535,6 @@ describe("getProjectFolders", () => { expect(result[0].cli).toEqual(["claude"]); }); - it("includes Gemini-only projects (no matching Claude/Codex/Copilot/Cursor/OpenCode/Pi folder)", async () => { - mockStat.mockResolvedValueOnce({ isDirectory: () => true } as any); - mockReaddir.mockResolvedValueOnce([] as any); - mockGetGeminiProjects.mockResolvedValueOnce([ - { - name: "-home-u-gemini-only", - path: "/home/u/gemini-only", - isDirectory: true, - lastModified: new Date("2026-08-15T00:00:00Z"), - lastModifiedFormatted: "2026-08-15T00:00:00.000Z", - cli: ["gemini"], - } satisfies ProjectFolder, - ]); - - const result = await getProjectFolders(); - expect(result).toHaveLength(1); - expect(result[0].cli).toEqual(["gemini"]); - expect(result[0].path).toBe("/home/u/gemini-only"); - }); - it("surfaces a standalone Hermes project", async () => { mockStat.mockResolvedValueOnce({ isDirectory: () => true } as any); mockReaddir.mockResolvedValueOnce([] as any); @@ -574,45 +555,6 @@ describe("getProjectFolders", () => { expect(result[0].path).toBe("hermes:slack"); }); - it("merges a Gemini project with the same encoded name into one row with both badges", async () => { - mockStat.mockResolvedValueOnce({ isDirectory: () => true } as any); - mockReaddir.mockResolvedValueOnce([ - { name: "-home-u-shared", isDirectory: () => true, isFile: () => false } as any, - ] as any); - mockStat.mockResolvedValueOnce({ mtime: new Date("2026-04-01T00:00:00Z") } as any); - mockGetGeminiProjects.mockResolvedValueOnce([ - { - name: "-home-u-shared", - path: "/home/u/shared", - isDirectory: true, - lastModified: new Date("2026-09-01T00:00:00Z"), - lastModifiedFormatted: "2026-09-01T00:00:00.000Z", - cli: ["gemini"], - } satisfies ProjectFolder, - ]); - - const result = await getProjectFolders(); - expect(result).toHaveLength(1); - // Claude registered first → cli order is ["claude", "gemini"]; lastModified - // takes the newer Gemini date (Sept > April) so the row sorts to the top. - expect(result[0].cli).toEqual(["claude", "gemini"]); - expect(result[0].lastModified.toISOString()).toBe("2026-09-01T00:00:00.000Z"); - }); - - it("falls back gracefully when getGeminiProjects rejects", async () => { - mockStat.mockResolvedValueOnce({ isDirectory: () => true } as any); - mockReaddir.mockResolvedValueOnce([ - { name: "-home-u-claude", isDirectory: () => true, isFile: () => false } as any, - ] as any); - mockStat.mockResolvedValueOnce({ mtime: new Date("2026-04-01T00:00:00Z") } as any); - mockGetGeminiProjects.mockRejectedValueOnce(new Error("scan failed")); - - const result = await getProjectFolders(); - // Claude row still surfaces even though Gemini scan blew up. - expect(result).toHaveLength(1); - expect(result[0].cli).toEqual(["claude"]); - }); - it("falls back gracefully when getCursorProjects rejects", async () => { mockStat.mockResolvedValueOnce({ isDirectory: () => true } as any); mockReaddir.mockResolvedValueOnce([ diff --git a/app/audit/_components/empty-state.tsx b/app/audit/_components/empty-state.tsx index 73688e4a..4e652810 100644 --- a/app/audit/_components/empty-state.tsx +++ b/app/audit/_components/empty-state.tsx @@ -74,7 +74,7 @@ export function EmptyState({ mode, running, onStarted, onCompleted }: Props) {

run your first audit.

we'll walk every transcript across your installed CLIs — Claude Code, - Codex, Copilot, Cursor, OpenCode, Pi, Gemini — and count every wasteful + Codex, Copilot, Cursor, OpenCode, Pi — and count every wasteful or risky action. you'll get a tier, a score, and a punch-list.

diff --git a/app/policies/hooks-client.tsx b/app/policies/hooks-client.tsx index d2dcf362..6cef0b47 100644 --- a/app/policies/hooks-client.tsx +++ b/app/policies/hooks-client.tsx @@ -99,12 +99,10 @@ function SessionCell({ (transcriptPath?.includes("/.opencode/") ?? false); const isPi = integration === "pi" || (transcriptPath?.includes("/.pi/") ?? false); - const isGemini = - integration === "gemini" || (transcriptPath?.includes("/.gemini/") ?? false); - if (isCodex || isCopilot || isCursor || isOpenCode || isPi || isGemini) { + if (isCodex || isCopilot || isCursor || isOpenCode || isPi) { // The session route auto-detects CLI by file location, so [name] only // affects the breadcrumb. Encode the cwd Claude-style when we have it. - const fallbackSeg = isCodex ? "codex" : isCopilot ? "copilot" : isCursor ? "cursor" : isOpenCode ? "opencode" : isPi ? "pi" : "gemini"; + const fallbackSeg = isCodex ? "codex" : isCopilot ? "copilot" : isCursor ? "cursor" : isOpenCode ? "opencode" : "pi"; const projectSeg = cwd ? encodeCwdForUrl(cwd) : fallbackSeg; return ( !!s) .map((s) => s.lastModified) .reduce((acc, d) => (!acc || d.getTime() > acc.getTime() ? d : acc), null); @@ -110,8 +126,12 @@ export default async function ProjectPage({ params }: ProjectPageProps) { ...cursorSessions, ...opencodeSessions, ...piSessions, - ...geminiSessions, ...hermesSessions, + ...openclawSessions, + ...factorySessions, + ...devinSessions, + ...antigravitySessions, + ...gooseSessions, ].sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); // Path line: prefer the Claude storage dir if present (matches existing UX); diff --git a/app/project/[name]/session/[sessionId]/page.tsx b/app/project/[name]/session/[sessionId]/page.tsx index f328613b..14f87827 100644 --- a/app/project/[name]/session/[sessionId]/page.tsx +++ b/app/project/[name]/session/[sessionId]/page.tsx @@ -8,8 +8,12 @@ import { getCachedCopilotSessionLog } from "@/lib/copilot-sessions"; import { getCachedCursorSessionLog } from "@/lib/cursor-sessions"; import { getCachedOpenCodeSessionLog } from "@/lib/opencode-sessions"; import { getCachedPiSessionLog } from "@/lib/pi-sessions"; -import { getCachedGeminiSessionLog } from "@/lib/gemini-sessions"; import { getCachedHermesSessionLog } from "@/lib/hermes-sessions"; +import { getCachedOpenClawSessionLog } from "@/lib/openclaw-sessions"; +import { getCachedFactorySessionLog } from "@/lib/factory-sessions"; +import { getCachedDevinSessionLog } from "@/lib/devin-sessions"; +import { getCachedAntigravitySessionLog } from "@/lib/antigravity-sessions"; +import { getCachedGooseSessionLog } from "@/lib/goose-sessions"; import { decodeFolderName } from "@/lib/paths"; import { baseSessionId } from "@/lib/utils/session-id"; import { resolveProjectPath, UUID_RE } from "@/lib/projects"; @@ -53,7 +57,7 @@ export default async function SessionPage({ params }: SessionPageProps) { let entries: LogEntry[] | null = null; let rawLines: Record[] | null = null; let error: string | null = null; - let cli: "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "gemini" | "hermes" = "claude"; + let cli: "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "hermes" | "openclaw" | "factory" | "devin" | "antigravity" | "goose" = "claude"; let externalCwd: string | undefined; try { @@ -102,21 +106,53 @@ export default async function SessionPage({ params }: SessionPageProps) { externalCwd = pi.cwd; cli = "pi"; } else { - const gemini = await getCachedGeminiSessionLog(decodedSessionId); - if (gemini) { - entries = gemini.entries; - rawLines = gemini.rawLines; - externalCwd = gemini.cwd; - cli = "gemini"; + const hermes = await getCachedHermesSessionLog(decodedSessionId); + if (hermes) { + entries = hermes.entries; + rawLines = hermes.rawLines; + externalCwd = hermes.cwd; + cli = "hermes"; } else { - const hermes = await getCachedHermesSessionLog(decodedSessionId); - if (hermes) { - entries = hermes.entries; - rawLines = hermes.rawLines; - externalCwd = hermes.cwd; - cli = "hermes"; + const openclaw = await getCachedOpenClawSessionLog(decodedSessionId); + if (openclaw) { + entries = openclaw.entries; + rawLines = openclaw.rawLines; + externalCwd = openclaw.cwd; + cli = "openclaw"; } else { - error = "Session log file not found."; + const factory = await getCachedFactorySessionLog(decodedSessionId); + if (factory) { + entries = factory.entries; + rawLines = factory.rawLines; + externalCwd = factory.cwd; + cli = "factory"; + } else { + const devin = await getCachedDevinSessionLog(decodedSessionId); + if (devin) { + entries = devin.entries; + rawLines = devin.rawLines; + externalCwd = devin.cwd; + cli = "devin"; + } else { + const antigravity = await getCachedAntigravitySessionLog(decodedSessionId); + if (antigravity) { + entries = antigravity.entries; + rawLines = antigravity.rawLines; + externalCwd = antigravity.cwd; + cli = "antigravity"; + } else { + const goose = await getCachedGooseSessionLog(decodedSessionId); + if (goose) { + entries = goose.entries; + rawLines = goose.rawLines; + externalCwd = goose.cwd; + cli = "goose"; + } else { + error = "Session log file not found."; + } + } + } + } } } } @@ -142,11 +178,19 @@ export default async function SessionPage({ params }: SessionPageProps) { ? `OpenCode${externalCwd ? ` · ${externalCwd}` : ""}` : cli === "pi" ? `Pi${externalCwd ? ` · ${externalCwd}` : ""}` - : cli === "gemini" - ? `Gemini CLI${externalCwd ? ` · ${externalCwd}` : ""}` - : cli === "hermes" - ? `Hermes${externalCwd ? ` · ${externalCwd}` : ""}` - : decodedName; + : cli === "hermes" + ? `Hermes${externalCwd ? ` · ${externalCwd}` : ""}` + : cli === "openclaw" + ? `OpenClaw${externalCwd ? ` · ${externalCwd}` : ""}` + : cli === "factory" + ? `Factory Droid${externalCwd ? ` · ${externalCwd}` : ""}` + : cli === "devin" + ? `Devin CLI${externalCwd ? ` · ${externalCwd}` : ""}` + : cli === "antigravity" + ? `Antigravity CLI${externalCwd ? ` · ${externalCwd}` : ""}` + : cli === "goose" + ? `Goose${externalCwd ? ` · ${externalCwd}` : ""}` + : decodedName; return (
@@ -216,7 +260,13 @@ export default async function SessionPage({ params }: SessionPageProps) { ? "Pi" : cli === "hermes" ? "Hermes" - : "Gemini CLI")) + : cli === "openclaw" + ? "OpenClaw" + : cli === "factory" + ? "Factory Droid" + : cli === "devin" + ? "Devin CLI" + : "Antigravity CLI")) : decodedName } sessionId={decodedSessionId} diff --git a/assets/logos/antigravity.svg b/assets/logos/antigravity.svg new file mode 100644 index 00000000..3ed10ab6 --- /dev/null +++ b/assets/logos/antigravity.svg @@ -0,0 +1 @@ +Antigravity \ No newline at end of file diff --git a/assets/logos/devin.svg b/assets/logos/devin.svg new file mode 100644 index 00000000..ec2be393 --- /dev/null +++ b/assets/logos/devin.svg @@ -0,0 +1 @@ +Devin \ No newline at end of file diff --git a/assets/logos/factory-dark.png b/assets/logos/factory-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..3495c05d32523b07359ea9fbec6eb16881f26aa5 GIT binary patch literal 38436 zcmcF~^-~a-Cl&Y(ge2A5(1J!mxqh2phd)z8;@(S~ITF@8~rXD^T6+;vDS{?~xub$^Xc zS$~JTGWeyLk!Tfm!%N5GR}|a&RXSGdrGPG6ir2Mt|35p2brOAGsKBbS>xD%8L!4WD z;FA)8cDqwjqYcA)_ak}`E$^3Yp1K%)J@#Qtu<1Nh5p>D^8|io3jVH$>4a%0+yT=C* zEBta73Z`SOE2^BabzV);E09K6Y>-olEy2FUh!XTw5Sa`6eQoFmse8mWB4h~X38W;Y%8%0X$3iZ71M#mI z@h=Y%mT6>0uMzxIyW?Yvq!}qLP+aULTKXu>gbawGEC+O5Tg5kDKuCvhnmNu~w}Q9G zKk#RKLd%zXzr4SO)5UNr<|zsg%cL85y`~I%vz4w5?mh^HkVH&U7H=|`XMROIgNc%5 zKGKCBZ6=%VnuCf&;lphxU?pMPGq1ghmdPlvY(5Pdu)#u!LrYUwxT*+` zg28W8l*Dn9p|#(=K1c#OOV9&QWl?(y9(!c(pGZD9sO=k;q3T61(i|v~IbeuU-TH0i z0cX8k>tkzMWrUX5n{L9{y_r14&)VYu20=fGMvQo~-xoW&Nxhp%s#hh#+x3E)EeMda zixG-3iqRYYQZ088O{Dy6P5t3Dq=(V|r*JRjE#;ZAQfTI~gSfv@+0Y9DL%#Wa$Z;VC z)0}noCB*kh>Bh}O7ffsjCi3+BK=`dT!Rc>0scwC?LL9AEgN(HWy1*MMM57easA3di z=*GSf2U*2sm+lebrxK!)-AY}8bv*bmPat?LNZRvsS?x^^K*z{xN>mK>N&_^8aPkd}cdG@35YsS%BHe>M9y+Ge(xDQmn zjcUxKU?RA?sF~Bm>O9nF){eV_GE^hWv}u0|^;+@fUzDa;8*Yt~-F6EVp@l5gE#02M ziNZoY8F?$O zrNdvaGPz#2`7faG-0z|vhm&kqM5&6XY-y9AFDb&bs$9l>$0tF)s^YCT3x4ULCCZfSdCd@gkLY9X~XU#!d`8} z!V-i#;%;M!M>R945J4=B!V7Uzhq|0ik33tWdzrX1LvEPCM4I)f?HkdQZIULw^b}~- z)E4dW*-HFsmzW*by^$kR*%NZtW`gXWWNjJ{ka~p$3!-&-{{m?Az@jULxi%Ao3D7J+ zULZ*X<{N_rnQ1#94>`Nm=+E@atdB;gEc*-$OXh8kLy$ zqDr;zle)huZn+4nSKCr!Xek;`3x?Z(7Cj4ruZr2t@40-X>&#v42JqvAG*%wtN3@-` z1@y41tiiv3$ora-wek(?NS!RIEfj{WVmhnHNt-0L1{Jn+C!BJ+d4Kl97h||(BQJmm zjY&w7khl1xrt`HrPOwJO^PYcylukGMqNa)GE^qKcJ{7RDF~temVZ;tzxFNIQuV^7P zm`pyK;kQ(tS5s-KCcUy8YI+hB?!lh8XS7-I)GGV1bUjr>zI7a)hW~0)@4DMCo*L8d zOoqxKZV_6~>u!oo%QC{(cnwlZACqw+E5g&5yUqFYQHanWr8ol0uPIz!@ra#rI88W% z()``XdcWXHF@SkVac{~ntrf2e2T-7GmF35HhYvRXtyQKxWK$Cov4)BXxr|CH6eh{l zsE&cT?3i`(Q4d!m9}~zt(+~mtlWda20$^*?50aQ&!Vp)VYe^G&MIoY@Ps#3gD1oE# z>ic);t3f1VoW0m2DohCo&MwhZtMT_cH=QT%gG0DSrs`YL#^HjA7^4&`;bWh8sak7e zb)b)WLR$r8O)eM$s5{c6;^hSKpVP^hc|yWLd` z#1zveIFf&?O4~|>h6If2X#@%S$#{JFCTwG@f)M#HmZv?Z)ZeHxox=p)(?OGtU}5_v zCw=j{8I@xDW16%s&k^y(*t0<&1^tv`NAa)d`~T(uPZ2MBl&xS;OFMUxY)vfMm9~6B z{62Fz9iYV^5x#!%X8T`|O2TZ~s-Mm=!^>ylXoL=#;*KOCKll8H>s`Mq!d5#Z-Kp!w z;pJ~*p4p9U>&4A$w5C(uO3!GkVn9TkCxzsnB*ZG5bJ|wb_}ypsD3Ph3Hs*$RO&0%0 z8i*L7fcuQW-pSfZBSLoZfSV$sv>VpN3*{>Hiz{GvzD=M@#Ep+wqMl%|+^zfge~7pD z)MfXhguYs>wJeh@kcib4ZzYP?{oEwz@dp+PvwiKT4%}~)UQfdChZoG(w9dS$1}@S@ zO#@wqgwEKr=$A`^H^l>Fy>kAPUo9tIYu1J1Oed`h;WDjlwz8V+SNVcn28^y((N_d$ z7r#9TR6Cvxi(iSPbCJoUQny7(v(EC)A<3#Nyz50(<-5!m z*>#)9YMg$b_m!lz-=j=Zx`vEv(d%Ot;XEF$VkjoyohQmxN1Ke#dF!R3u}GAnoBb;M zl-9D2GnWBAA>;0xXilR7p7I2{_Q)}@=G({ZtJdT-jUQfbJPLP}R3Fx8oo?Q2=EOmTTaxr58rklb zqj}BA{0}l z`*Qc!o2>I!E3=7S!W?pi@wuu%Z_*Wm3rvuZ8EXmj%rEg7PHUN_*!DAV5=BF%J~L*H zzz)ls1gZS^+g-tJ4k7gE=yk@C>LFoVjO?Y$>I#I2ld7ie(S>kI^r$ z{$wtVC|>DLxG#_){0@Mu17V!Z?T)(TKlyS&!3bG-oMfhS_U`o`*5=>XI5+?q5Y)F? z-y;Fp5zF&D!w0Ses_!lp-e`@@t#n_>bu(c;h9!2S1~Yvp`JUE%c;yYFbx4Ejm|q_2 zyc^06lARQMWqopLs3SZYr3W!-#{3x576i^vd6z4nc_<1Jc&%+6pn90)c1Qo-_W{8S zEcxejoqGfGGrgl8r&An_->>i%_s|zp01$L`YGsoj8&`C?puw(8vrg7xKqo3&w6<*P z@z{LBo8>r)|b7ILa#jS{8O+PI}D5xt*x2!#QE=gR7aRe*x*!x<{Xxk$-_WU(*QCklxIscuA1y zt}O~L9OaYSPzKW9vH%j8P!{drEj4H2t!SESsr+}BkO3cob^&$gVoyAnYe`nod%;s} za>kod@J@hnF6iq|1-n1?E6A%cL3S)l=b+0~@?3Ub95FkEo)a9kkA4ppFg{HZa zv8h|SvL~v$QewxgZyng^>s2#6-*>a>^^-2#bn!NiVj({9%z%i-eVkDsJ|1P zl5GG%_3d}+^l6^aw@LbVsd=QuNf<`8<|o`z?g8`e&Fk0qO~_T)gr5t!?j4M*eTyg~ zppm#&D-Mjtp zSsSUMA;8a8n0dFR0C=`H2%3X(L(rY%t48WItFS$;IEO1!<#}^d9BY4ki5c;4v}O)_ ze@$apE_b6pvJxcpx?dJ6eO*f_nH5MS+$w8{7u2+S7Pz7r=ewaBP7luzoSP|HPh@{o z?xTVxQCSJp^De+}_!A>lp~n_H-KKcfL|rZ*0(AQQ+MlofH?gIB@6}U5P`xE<3hK^6 zNHL1P15$2z_NF{x2gV&vR2GX77EPNJw9^6mQPO6B$9B4Xgggt(!>DjMjgDM5eeS^$ z=D5Z8J}#sWpX25?_|V+(w;szJ9s*jdqgg28U9AIgA7CUXFX{6%5WGy!&9mzeWy=XT zUQN<}36XBEwYldyyNN&Zw@o_%xIJ8;teE=K-qI;akd3f$JEJc~8rf~*yEYcOM3R^I z{*G2d?DysTjQu5x5h|b2JNUgqx&1s>^j(j|B*lN1@rY}V-kU)atK(}Cpn~WO#c>FC zGx7hxQ~c)9@qPfF$*#f5SGVbsK`Z~s9Em0q&(je&8%icjiu2c@AyDWDw9{dzy=8A3 zUg1B9L6ynn|AmE3(5&&CZR>I*rsXq#Vm(7|^Cz-~ANX}7`@_5fL>Sks>%I0yBmU#P zsz;t{r$_mIY5#K-?c5L@s?Bv!wmd60cumHWvBlxe5Qyc)Gi^Mz#I;N_#kKVefJqnV zWga08OtyhBI1NU;ji_wQcj@Y3be=3nue|ZR?HJ;c3jTeMp1`32**cfgm5R?3rhLE_ zBOOv=G5+eJ%i%^VFM$?)9{x)jI><9C8 z11GHo{WVMpwOSFW_2vksrQ}L&0$#LD6}*12!>-rHZwqv;2277*+^ba8yo zB=J{g$ZEqB%kJJ6?1K=WFP|iYteQ<9^}56dvqy|WKP+C=W`k=fT6vQ8Y>r*AZ>gQd z&R%6{UVF(WP7fv9N)e5?9Jsc(Mk1JbIU(il{Ory-Lv<9t98n8KLYap|P3^i3I7?w? z3$g1z>rGqrGz{3;9FBM#{fzT$+@z~o?s}PB>Zmly16Yl5{S#b92xQ3Ew1S}XElw%> zf5z}Yl0^jeC69J`q1R+th0Kzane*6A83C_r*`%o1c&y)jrcsN*3fG42WDXqU>t$q# zyrll~HjM2}+N>mbkU`_qt=xR`AGw$aRK{0N42KBjp#uYJR1Ma}L+PsdnI|E5zYnE9 zHi=P6mfs`F*I~+8F>lxEUoT-$VMUehu|>>&etPpQnx|w36&cX@t=IS%F0az>*?PwA zs?t!)i>O7fR_bph> z%x3NIK%Vk0foE;KjwX7Kc<9xvln<|0%}y2t?*CvXM$E>|ToRa^f}V)JYVI$;vr{la zwFc*79k(LXWDkR*jA4gn=)pTEzn6VgL$o50EOW+#ltnJKZVVJIdXf~vS>~GsdTcxJ zf`~7f{bX9!`sKSK6)ywd#RSc6$uks~-vzjq*#2b^y;jJ;AAmIH|E2YF(&Q;nYiznf zlXZCz%8v2#huA(tw6Sxt+g*}Av2EOx{}MDH{>ywd}|c?{Hu|!IxICwqxs!pqH2Zm$uv|f7>ld9(dWEPpOcJYn>WR3RyZ+a zS4&}Cm$_FK%~4KL+{$p#_DzzIk1V^L^$D(O+n02nI&Kzv@*5xn+LP$Je{^IqH^OKE z76M;o8NnL2e5N@I&lFdFC$UsCo1z@C!LlW3JT}K1HkQ5i`X=;f516m{J2Anco{YG0 z$&C;Ff1vVfKdai#g4bA=AgOvr82YV_PJ{J~UJAXn5jQ3|B1*IC>#<71cG%iBVciy6 zZdD0iByl_C9V%|tFeHk*pTR=9s%qJe90SIG4lLjrw|Hu&ZB(`Pq%FK*oy~D}vJEPW zNC@YjJ58YFa$@wp`^Xj|wEIlXwP#DCn|H3-*9}K+RfsQjsh{JmvWo6a8Y}HBegOM* zUkKIfYY&xd_jcy{o_I6usi(A)0t47gb6uMNInx7cGm)!kADfw%4+Dq{Zz{-|J1f1R-EA9C{8JPj3DX~yKkpz!M^A7j%t{E3JVXW{&6F~ZoDQ}PAbA5 znRrI2Y8D}%X+`h$UaWbk02i4?H)a-Di>uvi573%&{Adwx)ya3bnOzRa#ib zKjS3t?aG^4%vjD(3c35EWB(|XaZ7i>+hW}m+tRmpxKxKT*7zM<5-e-B+DSy(f|NUH zaaX8ot(UhspuFgSa~9TD@~gl2^Cyxf|0c(s5|v$s6o#5kyj!8V!#~G1$I5^`?b2xU z%F!9e4;w);4rMMN*T)`q2A4cfd^c)iQ}zgWnZJ%#ROQlXxADF4;N*Ccxx>zlya`GX zMcae}tEUidNns4^JfQUauiYNnrX0Wn&dHtQPx2Bch?UnIlt2B_5N=`4P+R%j%D9QA$yi!r%FdE|Xb-CewCRB`|2f@BX=X^)+)cftHifjsrp zM8U+)4LFUM%nI>if1;-*0MY8MVEh{$wqFu~u_cPSDJMK7J0&x~+y9zeXY?JVYOUIp zoHU-(3~jr+{})CSK4s(Y_QLyr1t@qYO>P_2Ls((201?90KW^zAK$GZq&~d*7+SE?{ zc+_CB2X{wwAiwoe`vjG zC77QYMy9HKU5>U49Atai_^v{ zk<-WA4-9FtjFyJwHAFqOVByxnUCzBR3Uju8m!MJPz#Z`!#XDBb#iCZUnUEe5V-!`W zzlbT}kZb)jqY5mQRn3%W7_;=f(1$4Cw$KZBBG*<_taDR)^S<+N#@VJ!G9OOgK$F5a zaTyBZ*QQhU*aQURw_|=y0$hJA&+{^t)Xf6Y`C=U^_9hsr^yh~_7uI!_e=!mvjbehx zOMmvx<4z&N|H0&HF7EEL^y~Z0C_xkK88-prwQzQfn8lXz1)(vDQ)TogW6oD|BO&~) zK^H(KCBK&a4D4yo5H}8uWa_XYRlEf<603VD+6d+S)<{=z!qWBKjl^n`;JVESTXt>b z!2nVd&Nk>67H>qtJj2X<%K7e2xs8j5IQPm8ILtQPGJKEMQmLS1Gx2Yzq*`&Z+RvmW zDor@LD##$zkX_|)JOe(8x{VgE;w&*0bLG%EuEuYCmD>=OMcGDo2_nVaxwTB`lxnnXy zY0r~88$!2nj+U#6HH*Ds~uGcV5c9puH1Q__DH5YvdO4E-x&<>@DSS&_K4bsw0| zchcL}9XSD|jXRfB>CP#p?W6CwUi`vq@NRh^-4qS4!8nV2ka|5QU1yF@PN~}>a59#+ z9(8u?!Hyg*UK4SnYE{dj;k(|(Om!Z&N5)b#M>_`h<^ddlP{z|$@Now3@c`cf?4Lb2 zhHlC!=#h;B^li4XB}(UWQ8Sb!(+UDJqljG5=$n6H6{TP{%4%L=_zv^oYd8!kjYhJi z2^#)O@vg~`fA*dwt0X9Cd7u)A4YY2Y z09vFi=`Wui4;)ymVRkXtflCM$?&r)N+Cb%TqXptir%!T89z~DrHry{=Iq#nnw#EVwPc>XGFn>uRwC8dE(8~@ z^4a#Q>w5zuzP7VkUI04vfzhtYtdZ&_zQO7&?oWsWYqu4u5mD?b3{Pa2iY;3=XKH{H z3>VSg;w;zMdi-1pdXF=-acvj zKg6xIzAi6h{mtm5llY1ncwjkgTt5+RebF>mHosiP=o_^r_bYlUw~&p9G57redsyV3 z`SE&8-FD=>AF25zOS9LFVx>q2`$XN!ml;E6v5m+ z*Lb(bycZOP4`!|Yj|O`hjyaHYfWd|MMcJHr7JQKoV%C(&v=ZRjO0p0M`e_?TKf05A zT4q=)lY!^OOX}kv$@z;fEv90IG+%`@I!R4{x3hw9iXUq;j=*s~4HH>MZ8%eX84%Qe zRa$%Jg9o>%X(Pd#v~kC7hn6U#ty`Hm3{A1ZQq>|EKr0s|ea{o2GTO7KCXxSX_Aumf zzveMCA?*CwvI4q5u|_n=-lq;ghi=@rT7WK_K!mby^4{36n3wvD7J~(kMk;Ve&16Dn zXt6a?$9cqiIVzYd150<}`&C(lufS^{5~Dv#Xi0M~QbII;I>z@pQUf?+fW-&b7TIW?hUrp` zqdd-q8(XF8`nV!FyvtV?!qekc$ywnE*%i_#qCjTJ&zUn~Vq`d{vWX*s;mwXv2Gv#U zh9b&hUK}`r-r+pFT6A0Lhe?DykR-fInfMB%Ya2v##+$z==Uo?{-(#7eBWzC+v1$7^6oh^%ZuObtNehE+N%+&+A#mt-k;@NdyMb8iC-9l$eC0gApPzQ zV9PxIK_+64)kER8wWQiMfUHRNOZxq>mUy;Md)Jh3-|ik&ZXo%w4AHGA`G4Xub7(a) z8QP249qB@ed@+x-TCIYpv6~znmn0)<;7-yq2rd$;G&U8~R_hNqYG#&I zd%PK_5<=XMU^d^AH9Ws7LAJ`5(#{O%z5+*I41Hy{=V+5^^)J(~|4WJpqG*ZCuKEke z8UNwS5zxwdd@A9qxuyn=Ur6vsnx_~7rjV@97ghZ|N#blgd;LyvMMg-(=DIoV0q_mo zd>X(-`LFyoSc7^VN^)s9;(2T8%b@As6HrkJO}bHV7n=HRouvt;)6u{a68C3ry3q%X zH|2Gi^<}zdcd3gcntiUA8N-AnDGX zwg=hZ+kIq;0wFUi!PdO@TGPA%82oipT^jv#Ea^q#uvD~AGB*{e{{CBYse0=xW!|pV z*tIP|UGXU`Thu3%p~`yI!@D>&nvq;PnEIl+bCFGXv;G0TWw5rACHUc$Emz=~uexZ0 z{NAe&ijyl($7^tfv4$z8PrPHQ%3>MC>6mpwR8y0UF(D=SJ-zD>4*+jClgcupil5H% zOsyyZOvI<)vr80iSnhLGOe3(p>)K;lT8B9lB97Q#jIGx9&sh1aY+kqi=iN@99cl68 z6U*!$PJYFR`5|91uPTMpDs$0IJIR1RSwpUH;WZ6ew=tzB}2qlt_D{nu_ij2zw*U$>LQGQ z&j8vc9qC3Ex51N}E9RXiA+@fP5a~7L_K#@C^B>4)F9i=e)^HvKjv_B!&7MO1S?W4{ zT!ZSqY0X!*5r`3wI$q0H2E4!S+Rs2b)arY@9s_o{0RtQ;^IE8weU{~I9g1A_#fOR0 z>Z)2U!v9{f7s>ekxSk44Rf&4`Z~l6|2z~psA74lxMMD7p6}6Vl!HSmRO>P>^jzf0A z|C2eNAT2;4yOrd7V_$cb!3E98x)Vk=2pl=5L+^n%3gageXtg^&#urMb^Bb+W-_wcZ zeF{^&S-5H8hxCx`G^M-%dtJ1x;JE;o)L`OvBf4XNV`uZw-9)aL=b^C%`=E#l`pA*wt9I8m z)SR+GxZ#YFsIf#y4^7@9G~i?hc!VP>tD;0}11%~aFvTtYPDpGSao1JUI#+-jZxtuL zS5L3$((37(+dp{xMk%YD2a{i8N@YRE)rs*VR%oKHY&Yjh2=W!)w7I4R`);KcUrvSR zv{(ibp#|{aAYACU%u9(`+MQmw!2eHWSl1z!4tBG&!b4zpWIYVZULJJ>7-`TSi`bM( z4bRu+mvFd6+HBj@;=bwH>CE#0J~yO$KczwGL~}x}D|C|2e^-+J$7&K# zeDFS=^OR`+7w>{O@HMeo$j6U%Od$-x>#7k=j+*EZMy-12#o^W+DJGW152cX(%N{1p z{u3bgPrO6U6spa(mzppbCfPIiw#-!b)zv0!Uj#aKkl#32!7UIw%E5&o_*-$ewW+-J z!Qv>9D%0+c@BL#g>4`v-A|1S?c)T@_oNtK(kGm`COAuNC= z2HRx~X1w15dp6>P_NpOySPvnUwlTe(zYIfJhs*DNe(1%&751$kZx@!CX0&B+Ra*RG z>l@N0@)&;^?_FRq_xVVNR9+aCdmq{n?JPNp9^WzqU6ahUW2ZpXiNx%@X zr}wA88qd069f2ozo8egeWiRt^sk*j|JE3gKXTD$kP2-KS04Wg1(Wq^Xu!(l`BHu^e zze7pU)V#w>vnvg0+)ZpaSfz=H`*v`e8tDh|&@ibuCtymuRH63FM4AW38D>~C2A zneMl1MI$GL4s&f{pyxi7%bikP4aQx>`+ta?+?QV8^xrxAK1+qs>EhJlzVOGcC!MYV zdj@D#T_ZnSK5M;;$yl8ZbQ;9rt8PsAtMc~a_-3S0wdoZb@KDvL~TEL~FAp;QylTP7Vpp+TnDSGQGJO@ zl&Cm(lSyp1<@3qcRj{wNW?4J&HYU6E(e3Lz6LfX$dMS(pp$6MVwPI(jhMxfkf>zZVG(OUx*-X#R1%zK1?Nvl0~y z<7(y4mp6FyQLD?_dGs$YrJ#P%QrSxpl`%N=V#bU(OUc&y+RT0dUcY7;)VmtqZzY=};;oi{PD3dP zE->#(eUjNip>5ZN6JXuz-b^(13j0?NH!9}hh3PlqLjTn>yf0SiJ`DxEu6`ktkUCH5 zfrYiuk&eWZ$}uG-C;XuEWrB|-*_5h0nP*a5JSX9*3uDHLeqA1@7HMb=L!;}5Z{+1d zp;u^3%=#MS$N6>Q$p(y-)PJO$RnDp;HkYexZN-fogMooFH*dS*jOQZu1^4LCq%wvN ztq<5@tmX9o!)nx-)S=|b^P*ffK2zlKdde#L#7keX$BTBo|vNN+b9l~a~@#0d3480C84`C&w8&vMndja@){n+lc2w8};wytDnxprWBi zcG|}NJJ9Ygg{7)p2?}BGnSkjp3f}3%GszBZ%Ct?K2fVL%-x6SXCO=?0VX{a^ z4?dUy=Br^{e0C~Dr`{Aa<4ni<)!&-3g}mdVt+MdzBg~@XGRH8?5oG+r$oC``5;E8- z?Idci>f7+Sei!S*9J;K#paSX>m2N6w?6apD_s>7G-MhGz%qq>^Gt#+;CF~}5P@x?w z-9xvYN_3>_)Wt-h5_lg&9t=?Np{KjkoQ>_yFIIcE8uM3LVCn+IEY*oIrPIN%Am#0n zhW7LdM;!2q5YV0+fx7ejlE7( zlmj&WD}R>=`@7%?Xc}HhDWL?D{r2!$9qC3r#SnxTUNJ4so@-XI5m#Hii1wTen%-?> zVq2qh*<8@bEyPk|oIa_1TQb|ztT9nBzazs)RaI<*%2mS@H1Hn4_8;tSw zRH(xZD&$=B(-syx^?MvtZ|`mAvKCOYMws+R?#iO4>lP9`u4 zVUjAV@Vn7^r~ZWVPNPY`ZgnxykxMd(k=rJSBv3qhZ?O=)3s0C(Obqf&?9B$5S?cP= zgfqdrk&B-k?_+1dUo}W!HLVQB;Ktr{*0SaaKE*kTh2tIToFmt*gc0jI(iOX-(08Tl z*-VxGN+&9^N3VPsWYuJO0&>u;*uYOd2PfPz*;ZjU=p$g96b<64~^#r+I zrL@()T_;$tW|^!2^EwP{%4|mI@Q>|RgapAs>xmD=j+$-NS05W%DA1l$vQRB*JL-2E z1${C(iQ5V40BIPVL0NT^a>)&h`^A6*L z1gC$Hq)0VX$q)%_Pd^N-;(ShUJpI?x{vIkynZ^*y+#6+@N3B%QWZVNU)?;MX-TjjJ*w0Q?O+J9I96VW@1q2C&k`-D)M&@-pBVLey>B!Z!kM~H=B~m%kr|xW{42LE z4g5>P**|S(*PT>CYo(7Z(XhzNFBo3qEI4su9dd3UY&cO4DY zc+x_O+VroqycrE+Xm3dg^(Qxzef2TC4yZ*gZ2#D23|d^QirYfM^n)->bXs|@K2!Fu z`^AFH69_!asRdUBIrHok&Ysg0vXQcY#WVfp&)KWd^pf0)0L_5;JXIz8f0PFgJ#s4! z_V4{C=s3mIE$s36PZ@g{hCKbta8~fk*JD6ac3eJHU-Cpv^QMY7dGDth&nz;t4P}lu zq`uiV!L5S_ax27ttQRBbyTahHi1Q6Zu4UTV`gD2n&ee9vYSW^}B;)1ji2!5;|6S^S zAOR_$#OStoi1^rzNX5=R$8Nf=xnPuW#Cq8S6Pbo~!_YV6c&wFFvRahuS^Fjy`%Vqu zB2C&z)K-8gp<}2pjOG}XasFNl`RJ*jW zz8+Y?ELQ!u4$G7~as9Pxy9VpUN;FS};?M9W;EFYJ7;z;z)3TjUDVrExAIA8E^*weQ-zYw^ehuJ5u|pzp#>@&s`b{87_1k% z)&R&eCBPmySctYbeN$Rl$`2~UJ5zbFm<(&PEwVAmpDHT{w8Fiz^+_?F2E@1{TUb%;!p2h)ds+&u1akqx61zd^!3i+zB z7%oXbN95{ z-%06sq@bh!izJh8KW|U;y9IZ>0@Y<%|E@CcG{)QFwFLJmws?(eRpUWH9sNF*zOjD4 zVsMh$DatKPbDAwp)3nWQU>h~FgjYT62IWkAOIAm0V4Hnhm*=UDvxAw&p_n zF|{lAk7F>qF8;B4JOZ&3G*83KKbTwt55C@r({42HDq0-*S3SE>?yWWXE@e%O zEcfsl{XxqFX2wTnb(c-VzQD*uprJp)J-EH-&tMfjR*Y0xD9yap!m*#B(!|6`>`vHb zxfh-bYc;+Yr<6f$pAoLCV)iq`9%kLAQ}^Dt-~rZ`GA$mMAfLZ86DT8H$&ST1&8W_( zUFW^r4N^>mw+mhPX9@H`ZIhL#mLx`u2eGbohB*ZeXW!R+WKR%OSEaalazut#6#Qja zEdPjf&nVE-J74@2N}-;%bEzx$;JZaJ@_L=MtA{4q!ElgI4rtJ6imX^u`6Wq7fPaSYpOrW=y{(}BV6OJ+ujyW=y-*X+5TzA?vEHyo0H~-^$!L34NPJaR=~^e@!v{?F3aa{v446(_-KzjA-Nx}`$bdOUut~jinOc(eX>-c@LfTt9;~6{ z-Qy!1>qRs?_eTbHGp6_WUkAOvidT|~p|#hQsGvUjH0_(}tDiuSLtKePyxd+?rC#r3 z`;7!cWu41|2x-F>fBi6}&vM$9-|#ylkVUb(Csd}I%N(x>s)!bih@9aEv}>_X*c*Xc z!HM;697_?gkvG$Fe2Zn3uKauG@RlUi5(R~4@Lh8 zqD*V~P`Ad4aZ9u?mBi&ig1R_0GA_nd`fA|66vXA{5mR}uE~yfrbBDl?Io--u9Vq)(oJyM6h^3I>Fo>s#t#pDjg>3lRvnA9cpT?Y*Oo2#k z#5F+BxM6X)=VUCoNn(gubsM(K&CBrB;I?Vywq4C3tJ z58>3hT|js-r6mLb?>qB0!msjV(g0rKmpse7rLXP4M3ffZNjR=y+oaz??>F&4DD!JfZP=3NJYz=2rf`#9(WO%E% z3Vxj%lc+b}<1MG|j8L*47%_p6;2|vw2mK3zpB>Wud?=ix$m`%fGu=fjE&e98cqz{u z_sI>YRHcLQywBF&r8InX!oD)_yndh5M;XGDn5G$aahpA4(KHJmew|#QjldLjOI5bU ziCpo`fr!T!MuS3~<>pi)~ee-FIGxq2LU zvjj`ifkFK?$~h;&TaSA-4Xu3-VO@M$A0D{Q7Aswh3LQ%nKiT@{@CIlhkzQT@U69g9K$UTWXHyt7*-BLt@6jQ%Cb3V}E`)6H~1R<*kd8m)w&k z;#tN~s=_bI<#)vel27Lc*qH9Cbz6DZHk3M>qa3}v2{9#kb@=StvlR)}qnmU^)2fgzjyR z*pGLtb#nqUsQ>Iy*i!~{MpwOJ7Kd`pedmKM8{|eyzMg$oyUYXWoFq3~nL~NHgYb6A z$LOCaVIMSqGD39k=XsQ-(QIc*(#+0Tp~Cw^Rk@#Tq+#Lx%K}{j@92sT0M`{L&sUD+`Df(?OW5wJ2~j2KL>Y^$ zU*=04g@@tvLIFi?UPEc_bJ$!1S3GkwJ6*zz1-oUbWD?d4uhPYW@e;l#8b46m zbTEC~G&lOLMJO&*aOQgDE|+vVu3KgAF$?C*$ZoKk6I$qhp3LGAPAqqICN=g}wd<|G zJc9g=88de3{cJ?H=Eb?{xOC^O#co!})op%+D(gOs=o|H-w_2JkhciY622jLZ48`ru zU(Dvs2+2XQyf;)E9_oWpJyh*{maIegF2KcD&tR`@&%BMxfqk)BFUpL%T(P$38+dgV zcILQ)ZXp+6{!C<|+XiF+*@F<<_4}$ScHXI~+jZTt{LeDJep3b*Sr<^to^qRa{v3MY zZlA2oPr<}(A8$T&xX+F|O+yBB`EOzSiR>%k0(=K~t#B}%PuQE13Y2v8Sd2Fol0$N6 zDjkQ?4iRTW$>IKlDELdbV{Sx8fA5WhRb{6w!7eZo&IK}6lLMEplHISozv0^wVlHe( zG{-uyj!y!aln4C>G=QulV^8v8+48j91b4hy>%}UA*N%FEK^WDA#)M?sMxl{Ap#fB> z({R^3c} zM*{T#K;!U#!|x1}a#76@5C(-^IM|IVK>JT>&5C{sg>IB134}%MI|0|fxe4mP z@fofDCYsRyV4hl5c20qrI|Po$JvEN*yl&jzj6{~R*U~{9mwM#HVZPUQIFxPWJi%_2 zjK7qx1fmY^cV^37bO76zmFxtqrSyd|6kth!Gxs^&KX+5Y8GWBvu=w0hzzshqWrv^? zRnz|ghCq40$wgsxKZ#&tvIL}?I}KTyCm>6EA5whFaY|Pq*vhl?Cx#lDfqItu9O=Fl zlLk{rTz(JAuHJwak>ikj>kxE*MoEihB)pv@$<+IRUqNKKjdaaAHUrxT+Ue5TO1TYb z@=hTYCO0x@OpIGl49bMpE%61D8ffrs$bRo4O|GA!Sl<^=)5mkNpW{ebSxBq4gW!!^ zzetKsE}5vDGy&b0->8WVdVEBz0%zny%tW$Vv!c_2tT`VzF*4U@O%y4J#LC*k>m?L?Ze=b{y; z(S(CnsNIqKv6(dRn^|5~7Gi>Bj(nis@(B;f`w;0}j$(bs0&hm=?#bumMWcilvw_2C zVpzYnCA`j)_#EWkU4rT-KZywC2}pOgFDVhyD2i@hQEIakwxLRoTgY2iwh|rRv<2tH z1tbgSsVE6?Dk3?@Nqb4Pt=1*lop)7*#qvJxsHJO0(kzzxLF$v}bLmCa_a&(M;W}j9 zMeECp;4hGP_!wlh*)sQaGvWFA&7o`Y1~fOv!|_DXeb=GgF+69~_5%J6xuy;xH!|pL z@_!om9ki->pm(~Z7i()_VL;tMXlu{U>wrmB(iS7k2wwfBqj{7hapL!)Cxy>wW zJLTgy0ms;=yM)AyY*8QBjMBlVqnsdx9&Sbi_a5XO-9sW;&mCWTkF71p3Vb&3Zz$Uw zp(fzD9uWUJaK`y$8 z#n(DKGlPidQe>rlhlQnEMZ%9Q(|VCL+>5+~D-h97lUhCXlCQ~jHPl|ndcPR$WfJ>N zcDe^u7wsgxXobz98+s#Bs#}@@3kO5|-vj4RbQ3oqOQCC5pcTM%n=@!2e*?MpFF_3z zwjk@p*T~fpCO}&;QT5*+KD*N~UijaFSXZ@dMx^{~?g8D1rG$OhuAlG)9)-_OUC)|Y57R5MP{jWs=;#Z*z z_~Q}znfRh^3zF*;iO=p$C*wtEk^BWBe%E&%h9>E&kh^^VNiJf7U#a_C54P5v1unv_ zqGOVgfTHDWSV@pTO?j-N%LkU0NhNWwbLT_{WY zJQT~jjD=N1U4?eX@C=*C$D_&m#KQB7S$i?YbUkVv|09w+^GL=9QfUz6V}8D#$DlaZ zQ;^)^KvLW=c0loj^#6^xr0vEO>UsBV)c)#7G;YpBnbvJ+vUwT^P9Z!Glo?cr{?{}%>0EznOYe=S^-+{nJd$CTso2{rPPkq)uunt8cP4W0 zjAD|*;@hUtn^PeKQwyqC_WcfGa+?MOm9q)-Xe-p@hy9$-V{Q&Kk z>zJ(Lfc3JVF^jqqcQR&VeP1U~BI19MNZAseXc0!q%FodJx`@;=t?SSUgcr?i(B7Mu zAc;yn_;sGx&MM6#m-aPua6hglBF69>3tcLh+>2b>$0Jww<)|Zu1J`!F+F4({62v}t z?f^57ET`RBXt~&ujqhD6ik^qbC}v9UMFe*R3OC$>+;F!vvos_&sepy8r~Ey=bsk>~ zwh--ty86WBW1m2aUle8g+7z?sASu#sWyju?=mf$m#x|x=AFel1KStsMc97kAsTt%B zyc~%y*8>)t6z*l`2^cF-dQpsY3|*@ip;(v8*Ct40+R2C$F}m`O)j?haYyt98R@q8n zvW*FdX*4E3gWS|B5y6ckt!2H=$npQ^ewwf>2U-cDmF9TkAX*44`u<-?&lziLJw{Bz z?y1;^tm(f*TQGJd+DUkhZPe?kdmxH!_=ZQ)E3T?u$$i7#fcDJj=*>i$0LNN9sbdea z7{7@+yJ-D+LTpBv%>RJ|xZRMUHKxe7hqp!NrlIvTiH+(MmqV=guA#0mUq@Ecce3ws z)l6J)dPr3q#r}8xzj$vgBl36ku)JFvWjfK)i&oxaP!@Q97B*^)WNAf351N-xK~kBn zLnl~xi{Z_vsX)=JhJ1V^4)k4U;60XnE1P(dMN#H@MqG48QOAdIse9=?gfgk$NA0tIj;c+H z<7y*~^#p7;29O~8-;kEo=V0qU&a>(4v0+rRDV`KF zW6{bhrvKlIRP|AZ}C+n=K3MvZ(QzD`G61Q&bE)_*J&^8zq| z5+Jvsq{HRNio2T>*Rpj}+}W+0DiJoJZZoeUg#n60=d#BbLU=py`=rR>yW z@HQdQ=!Z~d(TFh^@10Q0DBX?Z7e6Jx>evKt_GT{K2wxWm%H15YA6dzLs5R1WBhs^_ zRCEP99VRu$g6)#J?;j+B+lC14r${bxEh@_2PLjJsI9U-(+TxZ4oeYz552`KxJ7mq< z!nOLL*wA5D_TEY06-dY&Khy4TM-ofBD=n77PNe<$43et2i$_fP7ZVsx?eC8o5xkjn z1A9osw;oE*mV;|1T?{@*e#501v~b*$Jr2e6rBEKEUL1PS1b8N?Qo&YJr`Oqn$ZHcizilXq^<`wq+=q+jom9LS@t%gZfT`ckIr9&;8fGAm-MkRVbL`e)U4h~^>M?BCqaU;?#zy+wr_942U z2D_69&x30Q4bpF-zHg9P+xYpSi)-uURVc=AKl%3DQM0yQ;cMkOP{*T=M;i&f7*)HB zklL}2v9diU+KmsR7Ft&!m#Y|CGfDM?-!+nj>jceYc;2n=`@`$pZ_iCwy8#w6+x`40 za!*e~=jJx{ew{m{^pfuXFtYHT1^hP}E3UuoNGq?C2@ldh{3cqRPe3XE=!(ViG7ng* z)Q>?&{H*BO7W)-;3ry0WYxO=X#2#HK{S z`^YCRDlF6{PNUMy&!Z%vQQLYdWCUZ z&LuptGGHT$Njw&1qM&=?cpFK*(qdhuT~No7q7`V#1?akML>Aos=(;@~wFWu{35+3a zLfuEo&^4>LzD)F!7QLOwCA)^Spv{stnjWV+HF9Ob*9a1E?LsHv_VLcXKAAmLpx`Cva?{w=9B#Ve`v+Q0t zhGMtD9ZvlJUZ_gt5L78~0?M==NGcnGbPeiNOmsuX6gMgzL%jj#k%bbki(_n-qBxV< z@f86rKrzv0PwHA!3;Zk+(M1CxHX495R-S^qhI_~-d^!r9On8vuSSGORQ46TkNIRm( zeFuCa;{PKk)A&i0g(@~7=u~*4o*0WW@yDH`X3!Ri$0FC_nC$-(5gEkF2n%lG=X-aw z;=t~7SSY;(7emn_!Gu6MG7~MCatq ze!%&tJIvkXAO7ml$%N-3?4k>DA-WmQ$o}`ua)3GpS51J2A=maAx<@M&-Bn1fwM~2n zqZRcubbbc_2O(EAx*@h|9FK_!h~i@5_jHSe2We972D}a}g6~BOqTPR^a%U5YT~{KZ zU4jJI$B=KwW>So`wvfDpvyn$}XK6>hMs#v%S+T{DcUs?x+8KQa1>2`d`&vLEJjb&f z>$w7zNnPKvGiWY`5V4(&vvSJ)m@uzvumQ+y)uI1;%PEwQyAW@C%`MZ??p^`NSRjdVT{M%eAW zA0@oriA2c7IBu*uh!eM%-14>P^eT#GU>I%o{j%(Tw^wuX(%79ShLN_Th35F||CrtN zJZW2bXEzhx5NZza$JzfTo_HhN`POFnPP9GUCrM>h!=ys-IO&%ovG|%^(%uj;b_S`P zRlV%+AR_GjQM}|y$Yni(rQOPAR69f~&Q_pHsA3zg7#e`)?)X(EeD59C9YT}wB2h<3*v^&|??c`{F|+5&Q_c)-lY|a&$A{ zffV5%LfSG9PP=aosyd733;lVto#R&W{n0G>XjGJ3v=Sl#x(>MLI`;v4pxE0!*>RtR zthoKd=WRnGVP|3Ot{1z*tQD~vbX+K$!0@hUCb(kUuNx32sCAvQDBJ%vR3UIT$sP8& z7i+JhxVsxdBF(^2Xn{D4gt^I<fV8_^t%2)d&S!~;Ab<2lyCW4}QC?!Jy{uCFIg z^l^h8$4l1}c1N4`yq+XZkL|%?iz!>uJ)~A+uSPM{m=tNNmE6sQ2fC1l0{?^r$qwNA zMtJ{);(nx;qfD;_%SCsykr;#PQ;P-Yy`;S$jzO}KCm?I|AY|di0Z`9cD<&4=|DMEa zjpfCr0WsD&hup!huyAX^gHTA|bts5A zdg3$ydlfH0iN5*pn8!-Ja>wW~d>k1U4~ECQ*tCWCx|#62s*C_HMe)3Yv*+T5BctJe zPl74nFMz)#bpTmv`@F^A70<5H24umViHL50WZ8|ORnM!VTkga-pDhZzkan?5Lhi^> z7A8?m-^d=SfCHTbqM+vha90IPNxygpy|<6FQQD zT~-hH2~z*J*8=ZH@f+{T6hC)4ct8vQr=WPnlM(4|LW9E16C<4Ig8U$H3@s*2e1Gg> zHCrw+hX&<0flr~V_x)&K){qtF1!68c#yin9>vY2FA>DUdc(Kt$ge|>INZ)t_N+8{Y zYD+(Yh|evu9_EoRVD|alf%eyZ0{L)9(F5_=jP>n%0nbMsl`ZDBy0qO)cpkuWXaar) zb^bVnL>x2ZJF9FWkGIz5}>q+Q~ zHwgRQ5C{ch#MYx-wRNJ=nrXZBOf;oHIX>9(1@(Y$tK^o8&PKU$4G$v>qycQ z+x&Y$iB`3*p|h)vw!ey-6`AbsMx^&&hy4o8FWr0n_PV2tH6pb7aNwBh$wQb5*C2R0*X z<|(M!;Y3m_qU=m%Ja#8n95ZxgELt#rkDCh&BhuJ`k`5Q6zJRyVn9Cmf>3Nc#4!o7* z-Yf;{;I<-(jVH=VCXDd|bdSD9(#;)-+8DhA#YwFpgd|1UfvglrHu9FqS0E{cu%dbZ`9yV<3MwD*F8 z(bpll$?+t2x47c_Lfa~Q3CcuXjpA3mC>wbyl3<*Qh%a_+X@xAqb)oa5-M1i}6C_JE z3Z|WLy$V&9dPqm122SW?m?FIxip?Qi=~Yxp!oJpv{{GO&4kxS+8ut1L|_-9 zPAbnMxlvYvJC5V`_o7(dU!zVccc2M%0*c>QUJ?VfUZKj4dwg?Z)8%Akvf*xa_&PG-*RLJNkTG}y~i$4w3>Dy z`OH;l7qXY4yGA)Lz|C|PwLiiuvF9nY<3EICu`>lL>l zFq$PIZ#Eoy0G-2aNSC<>_3N>Vh=jR2>O6iC3JbKYc|$i7o`uCOSFt$s7r;Lv>&#ik zcyS%ma*S&ix*=zfZem=;ro&^g)l%7rE_ifVoiQEFj^$o7;lGjnzKPVH$E4=Zaa^Vm zvU7)w8PpQ~eB|0RTGr;|Pd{?`?m*Qg`_ouQ*VF z{f~>>3@LWoNc=Ij&YB=uyitba`t51pIF#XiA-WIWLayA6;j^3wvw8qJm;7Q3atgQ^ zS?0UZ*c`AW=dp4c3JKj!8_%=bV|c@)>Inxzy?R`aCP`867K7M+pGnR2uyJ78Wo~Ev zXiW8cu-uHSi7%l^bq|VJK{`JZ&NwM?VK;TTps~+)4kc>-5lL>9fvsLIJ*-i zHolH5n;&M+dH;>Y&?!j^$P2e0jk5Zu)3`j!uk#}L&nOnVV~O{aif*>>K*Y3>3@N%yOHJq%yk+ z8oTd4=SL$~@loXCGRqD40kqG=Uu4HQoE?wjagD&lx-W_WU5YZzKE7gg4CowhCXvkr zNS}EiiD*Vx9!?5*5sk(1kSsj^9j%#JbiMXMp@3gQA%>5mkb~osjtLhn?nZ_0Wh2%N z--i|+hj*5Pt?3wZJ{#?fc6D)PB%xsfu*Ym{N9=HxA(+|R!OW8jdcylnaNk3H-7Y{@Vo|3z zU-;jazAZP87h8P(KQ03P?l@Kq6WbUH-v2GKbl-yNt@{hF^YNH4qfmXZIcu?avqCR% z{Q4fMm0Em=~fBDUe@)ob~oV zF7_PUfSPS?&E8`oGr3*D z^VzXEX|^1(+RBb|U=%G{k0tFQXb;7Ti`X-->FDI7g|n+Mc4mx`ZtzLS?K+jTsdO_2 zWHT^M($Uqj|9eRR`+0Puw<4mu9M!abi#!q9CAZ~SW9h(mBZ%d5c7vlOaRiFDoJ_v+ zNG-f34*b|p@L^Pv^%D|tL;>?Wvbs(rPyEIEW}@+P4z|2+|yIaxGe>(OPmMZ!M@t znr9)Q{(&@RNjjqrx~3jOe~;XHNaK2jv5s5UqFIx}+{|&N&iYs+Y4%vNl^@l4M-i0!x zo}i9t`TOR8{{{T-a4bcOttY(4lA{6O4^Xx*5-)}K`a4asKJGy@PPS){4WZ_%FGE_o zN0F*o;s!xQi^kdGwP3FBx5w=aip_otwdeW z{=E=7i8g}9{Sn#UjtRD;+^mxc&lkyhD+@iJj8yecLghua{=AYjA}44Cd`ynXc?EtL zWxGCx#LhoJTDqbOAG6Gk&Dg5#q48MCQWzx#`XO0VXP}JYzNG7E(u*YI_ryT`y~qmt zZg_7bCr|9-k)`JBb4)DRaw*&TQsqcQ@w-f}kl(1rJrf5=R@)gUPWm)Nd|s@g zmDlWXwb*An7P}3R-49T9_i7aTixozGzwd|7zZv7h@Ys7CBD}*IcuyQJzOUO5$qgdG z_UB1NZEd2%E9=t2^D4a?ir<`%R+&As=N-^)l~iPb^gph5eo?Drj{RofPlEx!?T z^M}x2b5fvK?XgzGK?Z5?U5GN9(aPCHKA{nt0YIve{V&wO!R~VGe-`7Hn~`;UIC)DD z^35J1p^_c%a}e>>L)5YPx;j1=twxi(6DpQCJsY{X-iSITu>864d)9*39ov)K7I#tn z{xB-<`YMV;ev9PR7RN+0DjB?Z#D(Kj6y`XL#uA>9L5wOqtWgE*n0 zg*l2Wv2U}qj%@>4Wa0wi<8;}c<8pq_4n+1}LlU4@W!D3etfpCus?XKuX)8C*Nmq!} zNc*6iOd`LpAc@b7+3V}Mx2r`xV&9X-Vt4gEE0XvuQXU*aYE9W9$v`m_X=w6ygH={!MCzD(e zyU~NBjw2?ZA@UttEyLJMp& zV|ZSGW|86X78+~*8jm;5Nyk6OQI`4xq_9Hit)t2$yl92kI`GQvN#eqP>)|F*Z09$T zTT~{Nb4}ciDGsup@Z2o<4T)W`@qI)Z|G?4{vb0sKK}7f1!R6mZl@WU`@jfGxlU=J{ zL$SZ8ky{J{$hx}(#mpcd^IOhkd_C}Q;j{dm8(6w6Q=^DUoyVfdegUcljzkRk-h(Eh zdhR$h*CmeM4I;aXP~X5yNp-%Sd-fn|B;mBjVN6{4_+5!)EAySGyU+&KuJ@Zl7V2}e z|803gKK9yFlqwty`BQX5?fzS4VXM+)9IHc`3D2Y5ksE$KN*;Ya z`?(E;Qe1{uTok;po1kmt%Ncu-`*|?BF3mWHA+&fLi^dJ)7mZR-CgIJa0qB**7GEq} z-+(UQ$!I66r)H0}x&ovgA;rM_0BPR~OE1QedHy{Vqq~I0-HA>iz^D^E4+W(iBU}#s zq|m|?+UD@)6@LFt6nuXsE5GL_Avg2V?EfjW2u;wO>+3~&5Z(WAlvTbJC1(C-b_@rS zR}#!4VsYaMFOUO;&t7Yc*^6)D=+!77>p}4Vjk#6LMzkzq z-RL};oSV@3T#KXv7a@yoN8vL@$tN7*bDctVF=lcis!oaZyN!^Z&*eIlM6gJ(L%8g>6~{jd{*(C znlbMjhKP+Z=1Jqub^eacSPvdxyQ7JFEUA2In&k>_z5kpLhiPCkXKzO#WBBa3qjI{)pY4S}M|3(a$DV-J^$QCvix=-EAd!FO2=iN=lUY9+y48jbsV73d>m%jx!FT5~=@2Wj}YIl`v-NVzGM6dUi5A0S-lje6|Z^dOh$nP`)k7>8+CMgZG5T?m*hK z%TcH87a$SyraGTlF9Eh%M2(xz-AO1nUv>D%*EMFz9XH>M8oOEt>IL2ex-t6>pL?_A zUI(B8g1g9Dd8MFi9bOa~?m%h&*P^l_m+!bR9@@A;Zw9+!9*{SoK=sFfACa#Yb>XvH z=Qv5>pW^3s8hX&;^D;ExAz9>&3~EbLzJUnK*~yhAX?AAse-MQ@8YKhEl%9!_7h6dL z(2Q{ut;I;Bj>nl49H;w9_VZP=>C^8aH`mDxXFNTA)(U5)V>1EBm(s=h+KAY)$@i-# zyxzoVHGz`}QAFGfX-*HiM#mzL$>_?YMISQzJvjCS-i#zCX7U(pjTf{X#s4Nd59Gf> z>HQnfISix8X)DOFNXu6ooL+9i$4Y>9q8BOVUrW-bxtmKP-7sp1q`ryVA%CVVq2=I- zx(mgTOn46HFGmXY2o6Irw6BvA4b9SWIUX5ZT4!z{5yE_U?nj9DK8&vIYmp1tA70z& zqOu&Kd%0XD*xwx!DD}uUY7`;AAFao1GswrN&nvcN8b^!IcI3)Fw(vTy_>lm&lLq}bx}UqU*L)Ji?rh<%1Qx}D z!X0;zq$Q0^Doa3|Wj>tF%7UAKZa@;2SD`rYog^uU7r#hsK6iUY&YF7ebVGc&5yXu3 zUT9odW>Z=Wuk0kj0NV890#Z3j6l#_UCrxHZ^{dtwIX*FoGK_CPF_*8?{y1W@5Ic{= zwEq+$z28CB5hPc3iWE+8u-gLMn0=i?dbCev{||)cRzf(oCby$F-u4Wm5cPlH?@kMd_lTh&6pWAMD5r_$(36hKY1>jFnqtp*0 zS%&AxMr8F`A`;Iv?oras=m|d?5$O+x=So4D17iejio9F){~#%A+lm;Ti~H>=jH2w> z-vNJuN}6m9xWZrp4bEn@@NOrHgU74s1xWYg$DGxRlgJrRXKel37T*U^V@mJ(2C0+^ z8lRAUT_3W7u0j*Nk#T7^(BFR?vhtuaVq7r+P>j1dQ@b67RQ>=F-^Wml&sMa<34X6h zv{S|GD?u@SxjU(RvnvU25GmnfOw1?OiWS)LA8tIQ> zo!=;}3%U-F+=p+X-g=+S9`~enCl^~e{@n@v^wtW;;B49TqVlK5kS3cgIlEqNLTbw| zN^#uE>zgR^=y+gs*BoSTWQF$FbDXO$``m2}p5Hua!E(Lp8Ki7&yWtpP4B=Qd5_|Mn z4&}w^5)@;73bOcyQMnp4zqM35;W6oR86(9lOAC9I9mDglL;1%|u!RPoh~;fZUnEn9+>-ttbnyi{WuHODf}<3y(pXjFU8Gfw)VHuk{?V ztiM8%4^0+cZvvhoe~(Oln@~dmpPTy?Mm=IHJ7N1gjG~Uu^8r#O++N0YsI&7^Q3zox zNn_XvF8f+h45K)VR9YP^luLO1s4txLR<1~xrgeljhqPkfAn5|vy1ikyz?Q=Z5_O)7 zEbd0@RqgKDN~s~2^ER3{AY%=(C;WFwq-=7s6>b8H6$Y*wbv)=C6gM6s-D_L4j)`>x zM$mCziX=q8jI2L5Dn^zaZ&OyZ38p24dzpKGujNY1Jrm;!l#AGsf?UJKmRx0ptQXHs{W` zR=_{f;q%^z5)}uL;zo@SUUXwY8SX2|Z`i#SI95nFo*v{CTutiw0eSa37PDJ2Gfv7X zgX&kEZMXErG2L!)2V-mX&FFl-hBoghwMk}+5KGHI_r~Yjl`*_tv|3+J%7jMkSJ`lt zz@elPGk1e+1>trI&PLfw?<)e0C5=odz36&`>h8@O{}qnwODZo;QEyV9agy*{1X2AC$3Q#@Czes*lX2NT2u|*4E zn3N!JBILE%^G;|u4hXG_A+H7Ay3!RcHB^yceO|YtC{c6cQ7Dnn%OsvTn;4pQx9+3-H9hoK&P$CKhb>mgIS8?x@UkdKEs`?nlSj`yRjCx5}}8hkGG`4;C! z_twu@o)QxcuB?b;?1jw9i8&---H7(-Fl-t6J3Ae5FAWQFPe9gsw|GMx9pC>$M{&czyuK$>ee&86rDFD zh5j@Pb#kr-sD+={K;Y+S!Sd%s!dVNVMlF7y$H1pZ%?jMfWsp2sIr-#s-WZN;01@8a zXd>CtYqVCk6W~UuJ5l1|B$BW@mYYHTdU|pDD5~B#HT!)fN%Ra0w@{6X52V`P_`DMf z#f8t~Ch7{8B4&rSdXbXi#&FK1El6b(9_XaEp&iCQKwh2#DTC(6n@M=X*>{g2EALm) z1b`G*tcBP5rgcLtt@kW&XBSU|ab(@S1`)(AlBM8sx@f6I#e2Lr7R7#*WZlJ5u(I(G zvMjwwx@qQ0;#d0tPa{>(xV3pV#K5c_G>%0HxZ+|{3$M3TJ^=g&sxEpD+GX$ki1?m@ zN&~M$L~4nPt8He;hko2?$i(OBog#{r6H!()N$R0!cx+Cf#OBY!YfFo1A`e70WLQw=1`FTJS5oN zkv$&uf1M7;H+vCTxu<0Gj*8`Gv*=v^8d>MIj@=FC2Pn+6FA`~=hsbnq(#AuBh=|;Y zJdPh<`<}vM@pxSKYZ=g3c&)<<)7j_VhLTkGWzSn{SqfTF(>hG*xpqD9m)YMhA+1QB zlu=u?R*aB{&TXM~N4ur%4*VNwPgJ+zfmBY_>2P+^E3b?EABPIiy@1$SwP4pSY_YR! zbVr=g{w8uaATRx}Or%V>vSXZNkwv{;Bk%7=Ey^B?BvM8<$U35hv<1cQ>MdNh_)IiI zNUwK4DLmlMnGUbJ8+Bm*BntJMj#_LTk1XRcQb;Oh(HHAT97)im<>a6@xr!c!N%b=% zy>5JODJXjrpD0pw+wh+QZ$`}it7xO&9q8hCC$nZXI*gSSV`%b>pd$K%keUBsloI!@ z^}CQ2*k}=ZyWrj6yl8AdF3PLWHI0kLB>4uD(XuOA3I3TvvAeA-l(V#gFnW-z=@v8z zSK4&KdcFNo#`gOpJ!Ut+i_SFK^Wm69UT1=c$(_%Uyq7UjeJ-R>g^6z~viNR5H>yE+vjvCgFKCa8T4YWfTqMzeQzA z{{szZzb3kuYeDR+Z1dTV4p2Wh~%@7vpq}k6M=o zd9o{B@2g1C5LI*Al3TnsOeE&+_= z%;WYwD8zMZcI>;zH=`{DWfGpv>u6HXp$j#dJ@y~yg#Q=1peCqhBvTx7in_a)A?`sj ziwn?z`VX|iJ(wL|r^oSZF;A0(x95}gsc<%JkVN)H>pAM$;$yQYu)RGz7OlTl$vP%b zmz(p^1a2gD7vTl;SVVe1BenYPbeI?p08T@RsHjo%^G;Uy@9U5kwUy+S+NF$ApeYjZ z%@sZu)QI#Bl<@c*BD($2JUtmDgEo*tCVrnYxhA`LG?%O-_&Q2nUW%H?4w1r7rDxB} zBs`aJ*;Ry8N9#<`7Nobj4)`OKS=>l-+}c_487Rjd{M(k!EZPL-U(n9+ZzWkaoemSw zBx(+DHtAfW-Z8oyeWciC5nj2ckgE@gR9i`Ogzvi<70+)WS?!IIo{x7=6rcJmvKqU^ ztp&BMKb}NXZoltXEaa`h8%c|`b&DpWC|!vbpRH#<7h~&_+0XrmNUtPWlLw>4p79zk*Pdr|ECPGognf~;(J7q?;IPAPG#fKoQoDwFV>35zm$h$+1Z_J0+ zw8C9-jI@RpiRYpKz1!%+!U_ZbZ?f}((#6ZO73!pXaXkOu-uF66&sGRM~M#pHE%iy@BD;<@_z6pyXA zP~4RLtQMYI#p5h(=fHLfFda*?D0CFXSzZXd9VInv!cUO8@y1%*s2L-Bz9>#z46*va z0#{2JUWO*dA0YA_BNgAD{iOCiF>wAp^F$kjU!SpmK_jZ9b*x2^6Wbe%6I1^3$tlhrs%pxmAP z-)I~!Rw6j#c^+~RO`6Wy)+3%)A(C7~4aM)CM!o{6*wZgstJk6V(+x4owxHc5HV>mo zX32f*i$*Z5`Cxun}klZ@Sq`z>B_>8-;iR(rvjL^$Pe8GiA0g}Wb7&*!engh7AdGpGA$uv1t~PqPkijc}&07mbH&5lQV&<4rtmxf@fY=AfTuVfW@@%c(N4T+-qQ z(muN}z5p>tD&sn(}2H1it#@~>3Jt%%Em@S{D+a;^Oa;6O>`EY-iH1kk#ZB?H;s3zY2H`N^VRR-m@I~NZlZ6*6?&r7Mw8 z-T0s%Wp;lR6>onRC0zC)O(-K0XDpfODZH+S{C=IrAZq=yAw1_UGb;&G__N1>E6}xr z&e#>p*I^u8?_QM1+D2pUY_y;TN%30${y!+@YU{n&7p`nXi_O-oE0O*O3XOQ2`M1wI zl3y>1ao&m+uz5No>C};EH{q=XuG(;H?P@eoehHDmH7Mp|7uSL5VqtP5ocO={gPD9y zD!nwe3D6Tz8>*{Onbz}A?d~R$BqVCeV%bn{_B!k0ASD<;ZtSzO^PV7S6IasBH(rbD zQ0Ew{>pNkSqe$M?O#TqL+|7`UJPuW+#L!8RSjxlzX|atP7HuZgLobCW4!)VxKoh#B z{Z-4+&ZNa!VHb0bR3Hth^TU6k{YkA++ntZ*Nf$%yL!Ag=Me$Bq9)%pvO zM(Rtb#O9}{!ekfu?5YFx+sSvja66qI;CGQg+87M)g_TX%NmQ?T1Ic=gOaDx8 z*CE&KFxF0b2cwX{*IBqowBp=jjd^T(c^avg;Zlfgp?-|UQ*0>Ej>?#hM>i9mCxVH{ zZl?*t^`Kusl9Dq~*6TQwaB!JgjLF%eb88`gz6X#Cup4z5VuAJ;>NfEhL|C6g6Zm^* zb-pXSK6aRJJk107G?c6uCly}D>)}OUInwj_-G}NU{XIVac3TNfTtVvJH;rnqpGk9C zh&>r)ZLc6-64)x2c8HX4>O%zoq6XjZ(!xn(;kg}@y^+$&v$`4GOn8t;p_tY6K$=H^ z+$)ibyBl&fPe)eY<57{b`}~h)pS7J-plwp@4d2nob@PCZ#~S;By%1TT_oAL}*COlm zdq@j6OzPj)ll{FXBD-Ny8!brgw?E&+yxj4Teb@I%q+YM&saIE9F{{bS`@B8a*tTv)CoE+PhOY5`Fh=g-0ywX`1!tWXQJ5Z zE!pF(wvKF(13VvvUK%A`SD`o@;f1*(yhYH>gy#wF4BiY2n;j05Z*=G~qleK%--23y z|0gOLdk!L=eMs%4JRnUZjW!5y7nVqjjt@HdVe}xEcM~GNlTby+IH|YUK4@Z&BJwub z4~EaMyrxm>=WY~J^!b>SJ7vQ7T02}}9pp!m26C;ap>nfx(HQXNHLbuL$%~jk3+`E@ zxMibW#1BZ>_1G7$is98kHxu4m;Wwo8zKO*#4oFszNoWKS$ySs+xEZy4KNJzpZ=oJv zdy{V(>hE0c+F52(&+>}L7b`@fzG^>2UI&p932ymqLi6WYx?%Ef1anB&b~!2I-AV4O zW2domuCvjfLJeEj0*{-$P#?q#(KU9Ll~!GcDRh1>MEAU?8dwZ-DB*QIc~8O%{p8|r zUBBpNSxP+=^>>jBosqQ^B$j`9piiTW*9VZRa~A5)cPX+S9m6Y5h16{-WQ5hWJ zF{4q@bgbxk0UNr0NAKQ!K(_hIRi%FMmYH-?8JkkiS znHWOZ(|iy)E@Q&?SCgY8BT*(owxd|3p5K;cptoB6S$k{~imRNIW zvRpzUi*b^r*~<1vtHmctBoMWOjh4lYpnK#Vi07aX$0)6-H0dE#8=ZoZXtvb6yO_NZ zx9OiHEn;(MSGn!k=fya4C&XYo65Z_5mW>z-*^Xi*KR``NcSj_61d_ZQm_0Uz2HXZx zme`hCBoR-_c~VPuyWE!5G{efMM_m4nZ=nQ^D>Q8Rw$hzj3%-nER|m0>q#G@-GnoLK zk^OwRiO0AUya*nEV#fy|GPBiRPhu3MR8vUWWEVU(qOB~vMNkpm;_zzg!RJ-;VdM_~ z6C$`H(dzsdB#1p05uqz7VgeuzO7GI-7DZm6-JWW#hzS$BySuVuo*=u^ozFo<26L~SF@1dd=0wg zKDHDU;Vq7y!rv~`wgond2;^!cARa|Jze5r69fjIRosc~qF+;vRRdH}O+Wu%M)RWHm zGk=U?KW?!fCrFKyB(f1+hXfz zg*t&Vi-`Fi^7qhPgIYz{U5ASB7KaC26g1m4bp?b8WEQ!-+fjV)GE`DFiZXA|@|x(qjTSM{qPM|}F4|xsY7lqw-sk=a z_x!%k-p}6a?C)AwDQ;TwW6Fqt=`B6ErO;p{U0VlZztg2;6$kp!Ggnx~ z%Tvx218*cB=_2!A0u^qQd64|*D7jc*J9DOU5Te~XPDMw=O~`te0@kVM(R~yN3@dcz z?2gc;Iv@fDm-NsW_phJlL*j|r#1H7F1@FSe7UMk!m>D-%V#@CG{btDxsST)QDX&{f zjOphX6f-rHoBsJ|V^m|;$2!B{B_b-{vg*}Ima6Z#+I1(dlCRQuB}cAPku~b+7-y|A zQJb-$_WQ!&f!%!$q%ly>h1(#-3fAOC)sWRlTk8;vy?1{4&Y$}kK>j{;avTX**IwWM zHFbco2!l(JJ3F%QPx#@Ft>rrHbzXK39#sWU_b4B^6eM#yn9ig=;}gg*UeR!ACNc(_ zUByu$i^t{MEsD*xQw=-fPGx_gz>OB~n?!<4K=(KtEDPCX!tzuDN3B`TgnVZg9ep0T zbKGe^fb@)$$Lh{0jK-7|J(M!i!WL{TCtI#)iYb1hT25By)ts9-N)MLeGz$obmDNqX zRMP0en*YT}*1V~GKDP1j9a!5N$Tr~IGn<3##w23)xD0+@J+!BqXB(p42pcfqPjq1^ zXH8&Y8|mRGL9dV`xO&Pz$+;Il!p|F{v=qPFDmxSQVzpCRa6U>@EPQ(9%&JYigD8+*qdk zXOzF8L&&Oc51~Zx4)FSZ%$y>C-e$?W5bg9I;_#G@`PxcNB}wq4%HWSAQi+gH$Bc!= za0%{fN(1QwkaW>DKl_X25DY55Kh3EGLC8PrgZ-}@-W(fm4=UfE^*Ky#f5oG339~jM zoOV9l*sB^0CzKp`{IcFR^Y4WCcnI~oV(xq*lWV6a;5o7Sg^0s!4jAwFCvyQPzCCdB zJ7%@QsZlFMa3yqO54tV#)MJgdR#^yRWvClwMg;tYsBQ1z|71FYf=-7!Cj4)H7=eUVJaO2w8c%Cu+;TD;ZU5_8k2rXG< zw|JMUgeB=047mBw*t9XN^ttCKWj)X?0l1CwlDQ6L2>jk`$stevn!{o{4`#Ca%p`hF z8Mv0M;Z+`Mq`gjYl*wA5mf?JSKj<|4NMcWstuB5!lQ3Q;Rt;G`Fy|QZ_Rz1<`V-rykl7#9MH?t5 zooDsNcU}6go*eRAvzJVdXsYMzX7nMP}t%PBHm4|6&9zUZd&IO`n{cCz1o%-T z(rCoZzi3$NyOM(RI<6#Df*yIptv3Ii5KR8by0_Z*MuLAwb1+V`e`G*?aW@}$w&iIe z7)%8%X{+aRC&vDpfV*%Zj)<9O#237Iw7@}ZY4ybUOsu*2P>tkA^Kp0wi$x2;Tf`>nkl5Tmq*<8RrzK$8#0#8T z8=L8|+eNf=cnL)3m3|-%$OPxnMUhGMN7?;`#LcBm&Gg^R+&f)~qCS`hjl0qHe=Wh* zyg){0K?z}zCy5&!Ee8LJYv{L{(JhH%Bx}%I<9@5C^A2oud(GNpGJv1I>qFh+js(NB zTLvq2Z{17sQnM7o8OqL7=HIp3dTVoK^;6Z{2^b7fDE~M3wVdr7@`2cziSb zv=UMKUw?9c8hN0!GVO2mO7L1zLFvoK2qudzTY5gZYNzZ$*7}_McVKH5_*lDE#bEXX z(GhYS)qGL+1WnRpdd^zR?L&&KP#GOvO&nOuRR;!%@*}f|!eDSwMI?N{jk)qNv`UL{>4CIy4WvCyq&ssieO-py=_g{&~JX^qd!*+_?*uM|%e1l!ema z66dXTfk}5H3cFFL|5(B=>8YaCrTWlJQt4Wt)pKL9?CI7+Y+MRd< zq-TlvH;BluY0$V9$$1!Ovva;A7stGp#d5Pu|K~KIHf8(`{UCQ3$6!-H!aVE6(@e3- zTTH7>EcXXG7j>2-JV>wPInt1?IdV**N^yjA5b!*_ih=>;SpZS5&s2cY(`fVW&&$s* ze_ah&;weo9oWwiQGu-pF)&lu9mLCu+lXlRa#5L%-ogFInMBJaK8T&ez`urYdtj+bH z`B%S6`+9=U7egC)_~Pr*?^o4Aqcy0f7 zaY~K*X4ijuaa`z#Dls=t8^4PtP~IiV!Wo(be=|b^PVB(bv~-v+^J66w&g=cW ziEcNzu;O91s#J6r2I7o6+B?q_s+V9rY^cl5D7vQLk4!DZuEgqG6IbnvNzy-x$Ec*1 zbDs)jHZ?7_M_qB(!=&WHq=qVy-xiEHrD#e3*@iJpfBl3amO=K9B=PY?e`dhZKvrbY z`)7tg(h8I3>fA4LqhE!tkmUQD{J0|Z2uH}qEDw(ZUHO$>C^$OVg(n> zK)Ugw?sqlkPisN`3pSPm|@cb!B|iHvtiof?ymd3{@1i3}K^FpB$N`4Qt1L zSC8|G_ImJqGg{;&TP#_et7P76#$UB*!`q3M4WUIS>dyv7VX(s~Q@|#A)$!eQ(>yDA zP1N)$LaIXwK0_knCY=EGFVKwM^sG*oSeonoSv8Mu6?<^S6?Dr^jp<&PW9rC6c&`{V z^-Tv4u%A;`339_Wj25jVfXbU_t&CtQ%>uF)k0%Wrnc2r|M;~9^XY&QO-H~^VEO@4@ zwp#e~v0)BY9H0NXE6;0t+jaTS(FuR`+*FEfWVVSYgNO@p@j>62i0Rzv{QdA&w@|^?AOs0`T zy<#jV_~-L;huw}Y^Z_D$wNMeT7NztVcspUXU|A&wY+69L(=;;gH^MllK=+EG{4|~e zz?3V~N9{lKjr_ACgwe@a#qd*u7!%WKW?ZpJFCmT?HB&V+J zP#S1y25){5usDI9Tuy|S(KX>0p0^zEGWBYQXnL=PFno0I7Hl7mG%RV>PLJOXgw;2X zqO0!+I!Y<{^~AU?qM~$2xN1V44mXPTQ8(8ROA7Ani)KVa@k81GCBsSygqvz*x$ta7 zpu)$<+FbVZ`!7oKg9LkXL0hR~#UB<-CqoW+2cA@FUqAi4=aF`p_$3*On{mE|9aGyBzWjLcn2MpYrIa&?y|6RK4%qZm92xxYU&~6cV{vBez>JX#j z&lQmZ{3=8ok=%X)5$e_~6%bEDmsrgw#h_;!yN8WGvaQ&`IJg8PLGLG_Arq;A>0vCo zkK~f8HJJLvCdkkx(!L|@JE{VwsWdl47V}#7k(_lq-_?6@< zCxcgsZkWoqi4j&)b9ej1FM#I}VtB!$s(LW8!kGZ6Cce8dRzY_Dq7+F0HADMtiV_gk z3r9xZo3-AU;Y7$jUmJ@9QjxDRDH!xIV*w8@!~5sN#{;C~t^8#izr11JUpx7VyVmdz z@7&4)DIMPSudGH3pYB*m6n~gcrio2!LQ+W3%*D>B@11d31QE2|x-T{dri14@YAPh& zAPcDw_eQ2^h~qTLLiDD3*W{-M*PQ`BI$6_}{Da?=rE>{apW8P2<+SvBzE|`D8sx2K z<{G`hFQzfwbps_Re1{%CBe>*MYPcZTROnZO=mUkdL1|SFupH>m%3-o@9J+9dA~S5l z@%jlrQc*|q2G*XJR9LDh-!@JR(wViv z{3=mrAm~%b1KnxL)VHSzon%fPC02XiUBt+xEPW-rQnB$|N(CC5c6M4Z*DAm-rx*A? z;7>Y)K?C$I9T3$QZt)$mlblqF1pc|}dcj0^Gi*1dsx7h4tcb)U+Kd~_QP8?D2jg7b z6Api@1?Oi(CS*{sY#}{-7-_=lZK2k)Vn!Y(UZsPsMLyBkUI^k&)8e(m3Kp^9X_qsn zFhph6k;QVGM=<8`nr~zMkOP+BW*?2eI9DY7QwFNLni>a)y_acv#!Tm7W6<2fn{}e0 z!x+Z$c_c$MJ%u$f z#0C&nO^H!V5K7`h!Jj2j`n)$~N2Xr)m*qq%obkZ&HQQvg%{xa9$@8EHWskn33!Ge; z4q(gRU*u=;avlro8%iZ287HrAUHsPrO*|Ue^AUHd!S)pPNfDuSd&j6^kBJu*FB5e+ zembsnM}CFfo5iYk(6vONQJyu}P4iEnkA-!LdKgtQc>V#+MtxTSKqTSLS*jxt?ECB8 zI&3(^I@ksyj0p=gm)%;65E3YMI>23y=xkp>Cc&or+7p6*V}WC0DfO_jeAOJIr5av}$?L~dXSGeXHA|h@v}1~N z$M^8G^II11`t+f99vpu~(^L1PWTZk$Rbt>wuv?R_^a$~`*FpM)B~BDKQtqu?*UFKm z7a%iq?=Z#M%zMj~C8(1+9-ZA6(M@@-vTb|b9vmm5vu1BLhMr9HMd!jeE+NKZ5@z|2 z8@{;xuUGIzvfQeaC-zB>Jex&WT)Np+|F_#q$x9#9*rt&niM?yYqrob~+`_&qeBmiK zz+e{qRhPj<7PV>`wLPhzC9f|k6DERpU$L0K3CD0`XmrID#eB5_A%EYf&IrA5?Qiia zZQTm3%~z!VE5^4(94hC41#8-s!vB1F4^aIp<%dus*c-EQ)fZ~nbxt+@Z+XV;#P7LFaq}G;DHFo z-8~_#g|z?vF34w-btB0ZXLhtnS}6?Jt!yFioe{fcmu>@-{Mx$BP`bL|1baGMDCk^q zVtoj@?VJKDmAfPwBjB9bPsAQTG{I|nM(CAM+)s09y1m2-(gH7a&EPzuEEf3&*`76s zp?}#`1jcNZWVbgW-MlV2gi*mTX6)4wxYImzNxxsB^oI@=v`P*Z6J&kr_s{72qeZO1$h)pjZW_@o?~>em>!!3naIZWpKv0PvO_4P1zY(nJnX>cu^BX zEyPIXR+UjvZ@ZdiFq5c>xh$a@^%%-MQl{0H2qSweL5L`sL@PN68$^+MOhDBCwW70) lp=6q+7VWM0|89I0Q8>nX&o(Be{}$oV)qD=DR{!VS{{Xb3MU(&l literal 0 HcmV?d00001 diff --git a/assets/logos/factory-light.png b/assets/logos/factory-light.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a7b6fd6e299116c9c627f222d29c1738f37346 GIT binary patch literal 32933 zcmcdyRZ|>Hu*KbFaVJ=i;10ndK=9y;yF+ldAd5qAhhPcr?iw6|!{UqE;)~qxR^8ul zAEst%UV3V}&*|#vGcoF46|gbLG2r0fu$2^LHR0gk#r}7oq5QXFjEw!?6ym5PE2Zs| zd*1Dv`$1R#{r$r8ev9gByDYVjn7iIpkn%B_F}YXNBZ9( ze;US^lr8atbH-I>Zi9k@15Ti#YI%mOozC8O=l(V)P``h_UBErYttX4Z zGrmhRh#Uq@wsXaDAi)3gLa2+oWtGGg$pY($NOCmvVE5I{l(kDxC%_qh1>uYZ$c0Ea zYy*jX2Ru)~aA)_t!1 znO`J;xxrPBK*_(uXTgS8c-4LDVzP9C*ppGqn2K#v2nvV~C>NL;03qZRt(WthKGe_| zI7y`YWWbWNTaD7TsoO>M@cRMgi>qvxf(snAhYRh9&-Fw7?j`2%CBWRxqi!48e$%V* zGNXOn`ho9)uutXs;j!!g3^~%BzW`<3;Eic~(5`H^r~9xKvoUPpr-&i#SU%WS)Z6Zi z+w2>k4R)}U215o-w&P1+R0;@=+%Ooot;%66c#roJQ;6}f8&Mr${6YGz%hK5&acYDb zlp6RTEJvW<(c|nxH*ijDY=c~Rt714lnrlzTGl20yD`a4G8JL%alS1B#LGf6|spM zN&`=VV8R*%)DL(U*zQBwGy##@B5%2xB5>q7^@WF&!{aidbHENo6diItgPd9(X=bJK z;igf5u@PIO^S3y3X6@<$YKsCmx^X4fq$TS#sNXOJau1F+D0S9gu>sakB^hD>7_+dgCNDD}Ok1gJzM-JA9<(3Mtt&W1rD zHBzAQg7!8c5=Mx4DY74<<#2cT8c4rE=-iVA+{e zis^a8GHQq#T%yrVhe4AN{U_kd2D%s^tJEvo`QQIF|aWrVEh(Ml` znG36v$76^AszfP*oH+wV5NfopCBblCKlWJYK5j9X%{@^kBIn}-5TF;bbOBfsH^nw{ zRBMih2j4zpilQpKJaiAw{00?(rDsb1-55}&Ukz;$058#k!5AAj93vIKhUFUb_e8e4 z$L4T&4&;#&8b-k7N^=@CKLiuGOS!>RKFG1Akb&Qo*T%-mMQxsPsdL-${*A~7-oSFnPhRdyc+M}j;Tw5sZ29bn8xfCwFz%z! zcv>8S?FXmoV+Q-=r3q0Md;j_8s4_XwPDJG2ma}fV?Z{GOZZ-F8!TL`ncK1|7ukjMq zW}_Nu{B2I9^|`VS4TxEP9^imKUed37AnKpY^6wIDdKLIQUIRF8se9gb?B>iLO?e$e z4Z1889pE43wlSLEY8W^sm`EVfZWlOLIB6yVY-?1div$i68h=HxeRz0Q&lz&c|EwNl z--v}12Q?1!3pF_NKIlwgseu54;Vc_}DutBa5BuJW299o>=WiR9{sWyO<5ht1 zV4U8ZsS4r)(i_6h1>Zr}j)c*vf7npP!5ljD0x5gnr3>?pzY=L5SBry$L}a_B=oz2wb@qfPN6m;k#%E4DmfA#kabdb3RX0kOZh3ue{hMa5EO^ z!07YnY{9TtJe*`I@)E~%PI&xP`wk&tz^*$gP;u!KI~-6-Sk6js$E}kDE|dL zMu+~yQ}kb!4?`A?@2j-Mjn~2=O6@Z9`=S-Mf8;=e7&t1jxj)?ZidX%Jl^BE+8$p~* z+@hn7)IZg+MK4faM3vNq!<=?BekpOxb3EQ0Ip(*vB}df`lOOO9tiUKJ%K;oeFa&Hy zlavI|JSG%~3V{KzP&MM^rq0K9aU+-1w{B9)XzL~|rMT+ShS~xJ&%SW-l6a9~Wjgy3 z5Q|{le@DRKzJ8Rbu;yLYogsqh}fh~tGedY zq%~hmJcwPc85VDyadVtAKjN03w@*-LQWY33UTscRV3z{<22l|mbWtmnfR=MGtD5_S zg8|M=+qYmQypQ7yA>Q;f#;H;{X2QF#J};7OW%y2W=F#{c*{R_J3M>z?2BP-E9=pCR zmS&)anqV%YSrsi3O)^ocu9eJYc40q#%9A$7wpFJXkWUN_Si0^3wv5y})_;xrvh>Qb z_uN+!l9P0Ej>3OIXxpDfwwk65uuqg(8_^lQq#_Um`DoL(3Z7W!Z@TbQGgs64 zu6N(^2924jn;>!Exzeiz$Y+;$gf!#%(Z5jzAQt3cf#3AMa^1 zfP*(W{vmGHulk99XK+0MY0Iw9gh5jiv*|^|!fI&8bb7=eG}D7<6sySaADR96guD@x z1_O9MNl|H7OhEs!2L#8hBwK_Oq4#ttZ9nyWFvEIz^+@C2G=hmy@^#_F{uqU2$$W?` zQD0jwmLr*Tu!c9Avi&c+`fFf2Y@9#UC>s{^BiGyOB*( zejuDcAMlNLrA{_3GvdaN5%G}UwXK0&z6HD_1f+8N_PIayT1^ZHmH#xD*@2EaJYpJ1 zbg9ZvH0jY;Cy^adH#m27!R5xReWW&inKB+V^%>c$WbkHBcrV)!^^7C3jd4Qe=we68 zz#l)#3pGKe4lnN0NUgt$SX3N?xI_4Zx1`eLG?nrx5?nqYi|qP}mR^_zaV{4onDGw3 ztCi&TinC}2P|{2Kyc`T4A=~y}xY9)Rv2kx_8`SdlOSd zs(qMtTr)b-Q}%gbD()Mvw^Xy+0#77e!O~GAnsF znj7ysht}^J%s6asa2Q}w-uwEZdiRj^IVIbDN4wLAw$9Ci<~U8SO*Yi^z_k${$eJ0I{t(WB6+&f~h~;+hh!!+BRfQk9*d6A+i_B@0lRI5kCeinr;%IvkPtk zvA0~k3NNf&$~Nw*l`>?o2m%S(=&FnB?QBtl&g%|$P^K4b&D9FE6RR1qQJRv<8s1k` zglJqTIYv@7_AY6NF55Gz1J&m;S`mFv?8SX_Q-U2S#=BbEPgUvc#k>$n2^n_;rSwIS z>OldWLeo+P^R3A-op=%?{-a;DmbzGhux$3GUZagY^ys?2SN~pXz4GNruAVBJk2=&7a7Z zT%IyHv8Ucxbjc99=O3G$RMO%*p?VAESg01KLW96iPK3OmyPbPwcu+(SnmlmhELDl) z7sw?=J%(jf8-yv#Kn&-w&!1|IC0p^tdCpv`?q>rN)G+Pu*fT$ug>{h8r|W10UKGTe z{jED{Nm)Mm`dSChGy3+jaBhGz>hW}*Ax1%-)Sn?5xjAD8pYSG;7h|nHk0YEmKDsM_ zy8UFT(m;o**cM|G)A<^=5|4#c=R=-iP|-g;04vg*cAI z@LfUFO58i4oIXQtoWuK?JZ2ZpF`1K08O-N#-OntvJ(~V6m^G-ipmCU~kl4o|s=1PT z-{V@5lO5m?}Y2PU>%el6ZuXF%~Q^xvbB)omta?fH1s%cpE$`hG&9aVr{R^It5Y zI*6sR2%dkL535{g94Lq%IR40D=ldV1W7mpJT;v8Wf33FPctxIy-;CK~mC2$8W2GB~ zxUW$w3YT*U`a}J5WW#FEJ-Tp;0S~sNzK1i`-4r7TS6?PLM58`@sFVZsY!CY*T-i?$ zsdxe=jULYkZd}A;Zo*t$zU2U|*~=bZk@j(Oa3LbqyWQsub7HS>j}$|; z0SHz!)-_WHQvvQIeYBc_<^~fqTGowrY)_Ax+fqBC<*TIRuK*4KO0R7&@l%=mbh}7Y z-nhEYs4{j#lBydF|HTD7i zV59ANHwfhyyf0!qen*f)o$8znM+wr2@%N00W;<36c^u%18Y8->gQ%~5GPrewh(B7U zFDGe%@`UTLqNocGy@E-(L}gU_!=usFJE!JrWo@7~frI#TtNdH%&xze7_eq4A5|uyX zghl_klr^q|e6m%eM!U|-5)#A*Uqa>p*srBuO13>&yt8OexIOF}RSH{LTlV88>h&t; zEr5YF>?g-pn@M%Loujaq1Zd>H01{sZk~$LKfsCP+kN!$N#0qmATk6Uon?n z+c(@^7AQ?FyBQf^*A6S1Q$AuhDHem7%j~`@27WL%t~TjSPYWV&kc4$7P>sDm$Y=A~ zZ7TeOz%Wk44o}w&0xrKzQ2Lb=562Z*?!7Z^x}@5P<6?sO^ShlHn*X~(Q4OjJend8Q8y)%rASdG6b~ROR$fTm$iI|2^nbE#D@fL{kePQ^$v!PGA*17r@@?Yl^ zyH`Nz0e_@Y>1zA$EPv_miZM<1p~85du;QkFn~Ab2OwVxMujz5+$AxKZk$NTbjpbqI z_R4`mcg5zB5+uY@b>w*kpD(S|*&EJ?e=lLasW?7CJh~$8ax8n8GkUtS+^b!Q zu6#wl5C%F4k~7n*^2=NAdDsu2J|k|+^_|CF^2r5(05UPv+8&vk$$o@AGQ!c^s4omt zD$iYN5q~#YXj7N)*Kw>0fSYK}MElCog;0r|&L}EwHT;QCx)7TbB%`hwrU>H;Ory`^ zJ1z*+ksEZPdV$okettAM@JXcAF39#E&%rdg5%7G$9(ZjKxniWL(qV$1Rl&Dhecpj_ zCvLOxdG5wqaqT2EnN^4l#Ku!FWFsWCy92UF$(ZIZI%sEhBZ}}S4WhzDp8iY@@gmrp z1o$~ja4V)^wzGXZ0&skjBc>9v)y!_Ftm(^<3ETV0mywdBl@1ZY`IREeQ4(8MI4$0$ zeLhtho22piJBciv8;TN|9CjD$`E*!y?2^QCQ-;RpBk?|(!hE_`DW&rspu>fRDddCy z9`R+Xtp>$hTnOLlg%lg{@5VuY4dak8(V|tQRpq02_!*8KNiWjBb_IS^$r3@5^Y@%` zm3$=#m|{6$Uk{#wOD*kD^NML&ViwanUY+tTkHEoU_KhYnlNSXtYbGjpF>eb(8Gp!H z$ble!x@VQ#@O#Y@^tjA15yThq>?T!R#yG1eZuAYLWS7IAw4NmAo@rBcI6MvtbZ!E* zhIca->gSF`^3J-)%c_FAUU?ploWNfiBHP5H?*ZGAA-%HaY%ahJg-QQ7X%`{{d5#~H z39=WTu}D25e@vBK(nh_@KlZqXLI$VLAnKehrwT_0KT-d(%(xH%bpD{lR*ECP6 z{LdMoNh?+EF%3(34qm877ic64Hr62ybMnt-`yE0Y8~!Rf_H)Go=3sR7uR6x>dB`JH zeS3q#sKiYnLp(3^&w>l=ixv*@y$@+WF3cFXiG%!dzsmP4Dn@Vn=P-+}mkC`L1N46# zPiawuH*$eWgtwQNwp!if?OgeCUkF_0in)fyw(de7QVHDlEP+Z#foOIBZeeeA>!{vK zVBdSBL(T90{j&VXej5;Ugj|C~0bh`U+i7(9i6XkFtfnwF*$KA2+otz;hFpX3p5s9+ ze?Ix@YvF8Jvm;l{X&?FeXd(&sf^nnYVZd~FdQet3>PYWT^)YI4MXZ7J7z8%e3wO^u zu<(mI0p@{JdT@zC8!q9lHt!dNvZ~MYP-cnxzk)PB3R4T*V zlT-yXERrcdFuWXyRTa1;*Da9kh50=eToUY0f-H6+Fn4W!eEu~mTZ<=8+4npC{Rbm7h=`(Z&rmy&zM&to*z+~Ff%>@u zmN=K(_@yB8zuT`#Y$Eh>!TGxl@r$3jht1G1<1N(x_S-HEi8TjEKl?~szkAWE@vfki zH)}WY_JZDulMXLHZ(`-H0R+hAg}LXFDvRpeK2U$f&T-_GFAvmH`n`~4unc*x8__1~ zr%sKnT?>u6{l8IPJSpP4p-weG>Pk|1U?$5bCO*Y(}^R!spL6xLg&|02sxalN8(n}n6C@9~Ym zJ*7ZD*E>#Di8vf72iw7Sl%e38WPh~c;t7zByYLEuuSH`vxmzG-Qi!}jE7|1ypRI(k z%oFTI1efSZ&q4Z@XA>|^5Q}1h)pYXaEcD*1us z8U`t$O>bVU++C3(kLv3A*IaKg3~@$%5#s^%s?Jke^n#7x9vE)LXl#;AK?au2^IRo; ze|1AhO1|Y7g8ZXPF`bY{@k5*{i0pneENRJo+#hc&_?ab#q7l&h0d_q6&bKrY?FiO6 z(|`e+u8LaI8}+YVfw+$!o31Q|8mGlaha4m?Pt~VBGCHw<``B5`(e;32+}~c_xmi}O z4J%3~u~QFOF$G~4CqVyyfg=w%))wa8!|;oXN8v1a6U6e@&k99KS|EN?f`8mSRH`X$ zu)|+ULEX4Qt&i`JgukfIx+Zw&t&qspH) z7W!rhk&Hb?P<9f@{4d3i8;(8$a;Zavm)f#;C;nsT(x+uLlXND(N@jDUK9fP$cTvz| zQ+kq{#;Bqz_E16n>*HKaGe?}3KQau<3pe-*erGutQ`D~m-@E9xv!_#~)er;HfsvQ>2P z6KT!*F=7NS=CE8bl`S!CIJZTA-`kgEFu6SKA@6FYdd%kg$20?izok`Qa=#IvL5GF& zWqr+YrH@usYO55l_`8yt9`~ecN_Kqf4L=7Ymu_O)OC+SSz~YTr>>k@$GAkoNIGxhZR%VUcD(_q_3Xy4B2m{W@EgQ8+;v&WwlDXR1-{?6HK#0%yX&Uwd!|^{%plK_mDF z!hB1;iC=Ky$JX45#?z>Nu)Ot|ndEwhb~*EciGGHno=>{-{eC7?)DB2BB0v5!s|EfDCpqw)QEMWgO;@GJACBJ zA^f?g+#I=XmCX17z;@pE%V=(rDZ;{V$_X28F~&F@i{{9*C&?K1BZ;pa8CAwz%lKqr zy-~6MP>*~6svZetv=l~Wn0Rc4$OSB+CLK0_-1ClU)&EtDM^pSRIHum#)v#RFI6f*n zikcFhj_g{qCbRRdueMUzX(zuk_A2pXHcs?F!W5GnW3@!tqUOjRExO4ukqvkglu6~V z{}_(vx2zB-=WmDXYxcUXfpA>cx98Ar6UDOwxzkY6;G8|hh!9S}z49%!;YACT%<4{H zED-#a8~fjr(5t>@M7|_ca?CqJaEgpbtV~0>mY}WP(T%xy;2FLnYD290w0ugkGwC(I zfZ6_4Ia=z_TXAzm%z4lfnIFT!F-Y&5M=Jx}1H1M#LC)m&hUFR~AsQcw3B_KnwW-NN z)1Q)@?utxCx2(hCceEm^6`oFo%{W6ny-8 zfm0kL*(`Kf$aB3nkoZ<4sDAlu!RT)CxL$O%g{kN`^N-!*9UEea))P=3I^0X@4Y!&BTxut0C?c-$T%9rx2yO4)X&5z1#F!DXd#|S+D z=Kx7O%~|ymMxIyVh_y3w-WPgHfx?PE!aIbhK&|5s4y2Q}$ zDf)~-9=Mu_6Ur^l=m8o3YJ01?oblz>x|0L(g?Cz`E`_q^`j)PskU4`ay3K;XR_@{) z1&bUZ%9UrfD`mz;FA6K^`7SoweLQce-%aI3(OdsY8$RU7xh3lmD~%FlwO?f+r;++{ zehCZ2n4eDIs-d$ErkHEWk;m=36mD_`fBUyPQ+p1^AD$*Hf%c6kVy+tby6w~oBtyHp z5yyi0SUf(I6_65+AyjnY?KMtTEmYZU&Ov50j07yn5XwD&hH1aR!*;k zi`8H0uA&&_Y*9B4pS}eBEgH$+EhqD8EeXi8718D>)~osHpmY6S!iX@CJ@^VKNdwu? z?RaAy$XX|TiX$YODEr&|9doM-FlU(%{Dt5u{11{omt%2WblXi;gl}z06~WHkQ9G{m zASegK4?QjF8t*WeV7FSke>Cb18yTMAVVX)92>V{Mj&v;SA|>J8`AK9fVCL_1_Uw&H z#$j_ut54tuO~2e80*0BO{6W0iQwo8s0K!CtwC!(s;^X(J^b$JRk=|(U;wDJ|5uKuY z#EKP|Dhr-FMGCDzOH@HVDK68wpGM!vu07Wy4K2#*kvHj2)I$g_@(Ve^&8sZ8#q<`> ze1ps6Hj?xiK2JQ$)Ol?cL)~8SSz$XV>~bXj@7%D){8h``xg@F;VOQ4v@2+h3^DDnd zW6Hg@Aal!yywVGA>IJ8`gh*}l%UePDujf@#W6b4brq$;j zZgKkv)n}13-5W_}oV8m?`AIN)ZBd>&C1Y<2iwj(d@a!N`Uk}=#%bUX%SLP^Afbfvf z)u4rH#lb%mp_BSQEDVO3lYZt?ra`ud4fqAFB8Up=ABVW%33de zy6(F}R4C)9qlvcXJfetGgu$ zc8m9yUl?h4^vA9A9^b)%G2#{lHPd`vdo2v(+4{_!jQbK(ijjp) z@g5Hl+Z%iGzd;F}u{Nc-B1>sEb+SpBGyFuA@(IQgE2fro!9ak=9{COut@n0P4?8BX z(h3$1Xo>N)3GG77+8rfXR@W6BQ*Q2wVo(12EHui(fRQdoRM!#aj`$EC0qNt(_QyrK zm_{*F44-XkNv1E>_(|pIDA)5b=On=q+kW5=38CWeYb4R=3p=j)8`|@Mxq#c6jUut& zV%jdkn{jrccLy*VpF_i$tU-S_2n>mJsN(G{w&Mpq1Ka#pSZt3@eyhg1X~h2I7f)>LdQPI|GIO{(R>)$dvP}NZ2@+eGnYARo5FGYcQj`|2FhS zu;5tSf_hA5;O}u|0dIGQD+99mcmNTX*B7cm)rxlA^+=g)XgBGKn5Zx22Az7Vc|lH8TY5aWvFo<|bN z^_s?U6ic2-(rrnK7C8O-tjk25<;kU)N^C@Wv>iCq9NuE1( zeiba4>oDjy|Y6|G1L4aHd zOd4%4^4t|*xtKHc)5rH8r3aKPVotMl77JzWZ31!S96?cR$uv7SJXd>(X&$7gTiBr;^~WteV`T0kIR21 zw|THKWi2tmB}Sg}xH%)E_`iA58edNBeSm##Dq>z`mkq&l#G=0LO@hDlq_#y)Appqq z@w@_d{e#@3Oq^=`jnO#kcF>sasaw;we#~4&<={l(a?;dVIX^FBPPkhdaIwVyz&DzMZ=!af1t7{9=@0 z`{TTATH^yEr?gaG^2n4r!29b}`zpe3^w11K>NeB0|CRjUO+fun*wXHcCn(Ob4D$|! z%+uRboC^-@_bdvwE=eE_huXT~Q~aXK5nmB5S$Y@%oeK8{?N5}2GMY8~CgqZgOBvukxDmnDB~k=veJdH4}p@oXiBp}wJ12nlmW4EC2!`5WzH z&ODGK?*?g)Uv(;WMiZ&dxd>vBQ!Aov5aA;XVgLTxDYM+%LzNZhHuq1CNaFr<1KW;n zF3Mh2l;Eph$@L7WsV}pEUh*H$B&zG|&l2f1S_vL(&tfi!FCQj^CoBIIb2TYRbp1Pw zVm-(ReV2>xlm~EQ+?L-ibD0t0U^cLv9V$)5K;cy5)J;GH#=-I0kp$dW2Kmj%jhjQm z>fVDq{R79V!Z3Vxfb3EqP}w_!pBKEZ8odj7@uP8_*)`(!o|ROP8w_v2U0KdgJRk3) zp(WhHe^7)6kXf7%aPfJ{PIuWPuQWuNz15;0?)ee$fKKEe)7Tm}y$UVKY|hBWjn=BOU1Tj`Am8|KjF;R znI!VjIm8LChJ-5*CS6xLsdp8dX;T1lA zT6+QyAvrtfuuHGTKX4amNnsrRu>QVoyX4?Q-DVwZlM!CiW}!i#jppuC$c63Bm*_OZ z5lp4GU$*lGqA_5aaHS^cGo9?9r^63QgW*gN>TsA6o~JmM&%$D{K{r;IT`b~PET^M z(jypbouktGwDDNQ7Cc=r6)w4scM3IJ^)a&w^{f~@jl2>mI0bscLf(;_HH~@^eHpUC zZ5~67aVx8Z_uL3a=`?YSbQowco2wpP{eE0TC@Yw%a?ms{bOaKfpos=AHxGBS7s;OM zmWZ)(#kC0~umxQdO>%A|qBN7ADc6tqiY^*9Rb`CXOG9#oyKf0A?_NcCVBcklj<2hD zd*=SU(z6wiGo4Q<9WH3QAUp{P#V& z0aI`Wl1a_yo;d-O%qcYA$CCqaD<*mhvq^$<8I_GBgBHj0##eHf^>c!TTaC(BUf z=QhJp$2r_5ziJK1fb*7574`ZCN*z?SE;Qn4p&o*U0w4~@WfPa4L)v+#>XssxA||K{ z6?L!OrPr06JC9IZ#F_HR?Z(x*vK$BBbtQwY$nMwga}T~eYqG$EltHK)_-GJADqto% z2ieq!d0Ow0++9^~OfG)9R#4^2X+QiS{5Jd*V4u_gvi?%;l@u{Q%<{UUJf;+c#!*v( z?>Xx>JVQ~^)kjf88wx!%5Bt69YaBtXY9^|kL)waC)q>GDFVnr%q}cD!qqKV1rG%f)R<->y<~KkJ~6FuphMG_OJ5et*VDllO?8O9{Ne@F%a%q3|NqX@x2^msUb8LpomI5Y*<71&zkl}xB41SwwTzN5Zy6RgdNiN!Xc zuOM}42otm+I}sEV1F3;nEbR1NM_QG=tNM+r$S=GGNUv>#XIdRd9|HV=SmAZNH`)Y= zjgkNODzVPAzthmjYM<$l8`mZTQFyLs#zN^1WiB{?CSjU6Uq4K(A1QmzTIrpPEys1C z+%%_s#Lvd_xh(3~)2LlU%|TTtIhxH=f8C-;2G|D|I$%!q;rF&yD)FlcUo{v7m~1J2 z$X=3^7uK0U{K|U4YA>cRM@eawDDj`9WACjv>y07p0PI5aJUym^PvWzAZ6e#xlc)vk zu3ugGBAm#XzPXwrMBGd$PGKi=AFO)^ycb_yP0AM9g?d(6VGT^t>JA~Yq{59>rQ6Pb z%er8Q6lxz)2hQs7K|kXZ4Zq*+zKG6lXC<(BBk5X|!609o_HuuGNdU&b#A{GAKdoz* zu6EW>SwU`xzj?WtLEy6r5DH|b)VwrnmTaZ}f|S~>1H9!8+>ApnkbUud;9q}HpGiwh zDr#7nsOMe2Q%}G*)v~LZZ#l|_lBmv>Bp*KuM*CQBRd$qyA6n%K>b&Nn(p|al0C<_E z5rh7#|CeekjxCA4&qUa0n)9KMM!Q$F0blBr}`bF6cb9?ymUpT*#{oz6IrgVM>SJ*mYy= zFm#JPt4zQDr$9-3buR$E)Cxva+#T-aGY6S~!l>FMNwT3HUyHe8JvgWPHzY}Fku_)S zaf_?oKZT!SQXpFrgrYgEU-e=qK0hA~>?=SQ|VI6#i`X-~zAg((AtNeYqH4b``l;%#prP0H82 z*YCN=mop}~ZJ%IoMunr4GVfv`8{`_Ni5^4XPAc@J8SM>kV5(C;dHaP3i?PM5(#T)$9A#e&{GlG8RkqM8bC7j>VBH{N2k{5J^&Fv zX)Ci~P^choZgE|IgT$5+YBXWX`A()(q5m;vhL6Mt@bz6f3yI%e%B@F?rxTnhOX<<) z4*the1rry~{b>JPHLH;c$5Ti4X9yGqxH8m$JIH5wg#L6r*Jw1Ha&+3gV$#rQC*Xe& zi?$9v5eyCfe8z7LqCRGeVZw8IumyI9UZ7G;4R!=LyaRK&00DwoUY}Hp1sdSSkWaqJ zc0;jbe+E*I55*2}@%Zp@7jdXt1eO|}4@W}XN_D`Q4Kd`$5a=$H>bqzb>qW33H)kuo z)xEbO`f8BZoB~-SxHUO=F^rij2n;kD9AyPN#GxF1^($E4dpUEJXjG-}RnjGNrC#-_ zLOubMx=G?6fPnJk6b_JkHJqw+ezhSJ3`vjHeuQjY-6E{eUiouwZ;}TRTU#`-n7!M|Zr3X4TTQDD3wLdQ+X>#|8@^0U_xf*|qO!=_sy>!f&N8k{Vxy&?l zm)=)qk}D2A4nhKnHt;QFeMhtMXrB;E2;;(d9-UXsA%cnU@eAJATy|KL3%!c4?Y~pA z?ve*~w{Iu(;?hrKliWkV?a}i+TUcU5AI>k!*15#UfSn!3(Xw&w(mZz6Z*NQoj7qT9 zlMDC1ELJv(M$PK~Vd^rskTQNfzA2tpeK50jAs2Usa7l;s`ZcqKzy!vd zLErDa?n=|sD^vvS8rEAE{z0lT{p+k?GSEw7`{}ij)#3Zx`!n7IKA03Q=Fjkx&tyu< zY~Z=ug%nhx%vL`H4e&;g%zpMk98|>;NVJQCu)o)mtiVNc#X~Ur9_fSE`k%T3rOvTK z0ouKM%7DS$L8dyS#23wtz6$zPuz7Bt_M2F_uyEB_%s&2YGh6!XW76g0+$8tlFwS;{ zdSc?;S3TXZ#|N435U4MLf^*wr7ENJnJO$D6v46~(Z%w2eCH9N4Tg{6>amd7LBj%2% zM^%Y;q=zxZTW{3>{c|QK*NA|E3ZJv)wlBL^@z&ok-WzR$- zS{iBoOMjM}8tTzDjdt#&;6sZAdQ*Zde;_+B`ZZ#oOXgK6o@r_|{s-?d*Dpg}_c1Ug zqxTA=Or6O6)sYm(D*!tyj8h_U&6m0@v$U&SEX_Tw#d&qRR)do_`!o5lxBXi%Cz?qV z!Ma75L%{iVYVd;^YRRs2jX|9oRttmKI~I{${ESTr(%hG!-|bdJ;bJ&(L%mOT{a5WQ zr3DH%3-WOWB_&0JCCM`4&soo_J2gl_okAHj(m#9cNOzFG^L(LsVvqG(v(eFETl{MR zpqg%fS~-nIFT+&K@e{@9*l!*eu;8F%|I|X~@!HGERVEVPXdN`s>YLA4{ULh)n<0ON5lHByalQq4;3g3&PA?A zV)?v7QS9rz{iKbF7Rv?Dxz9LlGFIo__xGHJx0!Kakz+VszmJUpRBf4sC% zRKKY9J?EZ#bWu_o=_V~=R%|y1M9is?VJ^RJd0F~_Q64$8(amCgnUiPKm(oP|Y|`bY zroabm1#At5ox)Y~Ugi^;Z@uk_*B{JOXn*k@yaaMQ4*~dg9_m|qnnBSe=e83X+Zufr zSAMuL2bO|7=WkeUZNnk5rMvZHXSboi_y|9$tpkV>rWswA1kEq4jpPPNn})WLG4Ds{ zSkw}0P3triD(xjhjd>T8`5mXQaC|0ta&HX9@pk^1$~b<`JJ!Ebyb8k?yNWF)%K{INM(~k{80I6@=yq zh?9hJ@Cg^K8mvhbE<4+4ouv1rYS{P5mBJFnho9;{zxqvP4(z_iC*0}ZItI~jk5kGu z*PhlW8aCop!8V^7FGf+@;sDTsxv3-ybYtj{eItf$md$8U_EJU>%YoWJTiXx5Z*-Gd zUn!kM@=EOy4P~=k|4=0uY!9UqfyKib0GRU70+0>Em|38=E-s7@@q_yVYp8m&uzfkebH}#kvRO{!LAg>(9z4Nuf^s>FvF2c9_#| zPaa`HQ^;PSqQy_qb6QeizQ;JRMm3grf@WnD{hO*WjkW$+yeC1^g1%UZ{G){tdNS;? zrAYNbxWXNRFri`XP?+!0j@w*iUc}l@vY>07T=?4^W)!{>VG>VTsm5HNq(Uq8W|ShF zpR=I>_ncoN9m<}VC)m-2(kZ9v1J_zS`HXp7D;3AQB(<$$%e)qS(-0rg9QWdP9yO^Y zbx-SbV#m@!!QURFMP4=k?OyBt^y#u@LnwqzASj0Dsf(9&%DNjk@wFXu)u`BO|!txya137PWBuIJ2rL0v7w*$q+p%W5E^+;bjju7gR< z1M*Km536Xfj&v*k3)$l15orgRnf!PxIh&7Q51nSwEA7cwKee!jk_%M{2#c+suUpWh z-oqugeJ0n6T@zw(*v;-AWp#C(^q+|i)E|sEgL-l7q)nux-C1G1BIJgXMU8dm3bX+~ zOMUk-#hDpgcO+QIUyRb4dRomV&7ItVG-v)G>1sB~x|l+_jiln!9Z^L^F!o%!l;Doj z83%l2JK!xKumtlI*-}G$=}F0HbZD@ z;Tp!L{H1O&Z+S+dV}X)Ed6+e368Q!jy(Ff$9P;!^otV@KE1oq@M=%f78eM107yn65 z!!ogq-_zY8?3o~?4?s`lR`XloL!F**_fpBkm9^#_+Ifi5q8j&85MzB-_AC;)ZEQh- z++2}`(q>YjcTL*NoYX%+IW6Q4p6?pRTkq8Hb5}@#%rDhMDUd(z_+)D#MS0ib8AItK z%u?u~ZqM`{Mj2D>2fqp9n3I2mMsHfBSVKnKeKyB|Tt(N->M<(4JxeiHorvtH8l^CU zZOmx?L!-2uBTgHwBWm5SWu)+-G?NrqH@cZNII<4|9Dx<0gPv--G zA1{WW+v0_8d{VDQsLD(FQrqP-+nb`dxB;R&VGuKYdH{MXA5e~8+0|L(Df)2g6V0X6 zv`^ADIR3@G6)_(vAVqdCP0O8MY8y{K&p&WPV%#V-p`aeLZN8uH!~G>nIQ@c2Z@ofb z=l6ex+{++>5tj+e!P@ATvp^QfYT7~s(+3wo|(R=ahF`~;ADi7 z%|Rg7FJ#+->d3=#rN}3gTp71=g!bxGwM+h!^hIx zei<&E;%b^48=-;=&)P1SQQb)ss+f3{8R!2Qd1U>51m98X`1&N@{0UFVkc@qf6C?OXt?-4n zoax}SP?yT}AFLbi^@lp3rj^kth#Q%SSvuO{Zp-zYV<}p1^86;hx3o2JD0LE--n!f5 z$Jz!J>rpeynZvlg)XTGN+6dHWUpo50p`LE`6O9g^@^ms3#(g)y6p(uOC(@~A$`~~N zCy3(bVP3RA4sdep`hn$5xXDDEedMCj6ZtXAb>^>Z;vps{ zov-GbV#EIu#PlENWvfmWllAxs1t}Le4-TBKA6`}uyW%`2*Sd5YmkkzgzAE%|iRmzH z6}(#`?*|ZMn1N8P>8t*oJmTHN1i{IrnIl;DfDVM=pDQO06VdbhLtz?QI@Q~ti8@(+ zoLFq`PrR6`#*wF@s+Z%^`Nxqx@iA0Cl$af+0^LqhY?UILSE`9@qkkeEuo;}2`T~ty z3(T0+E@Hpap#rUY=7Usz&ORYGu+d8}^__hdHNmc)c2*~CLx@XiQ|StW#Y!Su_T7tk z`3}3y+0~Rw8Rb>o1$k*Tx2m8YpcGVLc`<9hDx0`~W$0r1=#9KVk<)e1SJg#b_`+sB< ze=B;BFFSGeQ)uRx^~T3~a%zRyLg@n`bu5*B8`R;6)=p>LY0 zN01_^E#+1A7;EQgwU&q`F%|`fbyWJHG6gr4F5x)D#PVDuXI@t#f;0=~9iVL86|ACT z$8r&I&;oDDFA1)q$|Bxl?0xZV^|L;qQbdTvhgE9{bFH_cib+&`eyh8`bDI54O{U(Nq5n zx_-ty9WS!jp-dU%gh^*X&*@i>;qe(X&XEH_Ks5ZMBFDb=>LD-yA)AF> z3SeHfnkJ)tCgHQew&6mdmHRp>WgREjgZG>0My(V+;Np{RLZ8#N0FCGfJNS7E4y_UA zURFM`Dc{}6p}t#;#qmX5Y-0|-m#&OGUH#*oKZ ztS!VQ@{jHVj^!{`tc#UEHFCD3R!TSF@i>z|IB+7bUGQErt@y5|4o1I7%#(6!fTQMw zP4#{y>a}`>s}gwg%WLA3MwE69fmvneX5PoMp?Gu<3}8K)8zf$j-K;*WSNb(A1_p~yi#=PVD+*{9Vms z^a%DUj`twuswnRBzL^mrh=6VP!^AbhX^c{^ZVfXt>I1|IZNszjYORtkXJ+$wYS2}}< z#FYbE7k%;i4NYaeqU&8Qe@_GjiIwm#k-{Z!}XIQYiz2#Gv-9nt%dSjWTf}v+Pm>ztw@(-8$(MWpDJz z+*GxeJXC?{bWr>*KNGE{PP@5qd0POATcII!KkC9=!1J>Tu|+HYnW06w(&oIym3wym z_ru45yX-|*d*^}ms3(^q#L$5ES{K>nN@gZP#sDb2jRXHdw%nkK1{TnM1F|*RGCXF0G(?vY#hZg!1c{MgXCCWIWDTvVK-k8_# zf62Sig{Xn~C#_^L+S_fH>zPwxesZof&iE7f6_ra)V4~(XT}nPkpX_6*cA@0A1hdgh z^Web>r?O@D0-5L6M@EG(MDbf5X{dy0HM4rTO*Nvc?V3i&@-qH+Cxsbu z<&d`yv_%(d_SWN#H>KG_i|u(wIU6f0h}Lc89cX}g8dXC+omBMJg6flAt9P|`U?70t zeZOi#+tn42gE!>udA7354pYL~+<4ki6n|J2J>5MdfuXo?I!i*GsiwyLejW!Lwl~E1 zek752fu!#do&90bYTs$gVRN>$=TF$HZ*DbeFJ%q4gNkG$Q7-kwUv^g#+z}k~RolD3 zM53_b9^|+>UX~z0h0>8D0J^k`%PSj({0b9F2azCRWRn4hJxtRVQff;fr|71hi5;~2 znOfO%8kOVYVp5SEX69TS%|sYe?NGw%=HlT^O}3d&*VFSCw~*r5a2^;5U@g7sm|D(O z;*=%%%NiNR$tOC)vcviN)i9CWh6Pvok)fcs_y3vTNJOXMB$~}=?QvCR-Y=(&#H{8L|{r+KS%I*&Sc{_9CJ4TOP@k zi3Y_s7DKddUa;Y-d`ivGnz0qfiI_M!o01QTxKN$UOp;rdw=qv5H^3Ir@Agl;vkIIeqjAOY_sL%@VAhlGjdaaLnnK|=txH83YW*!$wI4<524aB`eN!j=t>wT4g zDxKC;n;INcly{v3``hA^)ih`;U-K>R-I|@(q0CjWB-I^_r5Vx#k(pF-5RFWS^Zk7h zP5f+rvXDE{#n93SZGZx};{J)FxJhA&cI%emI@xQ!5~Dd|JGY0HKHf1WEx~li|7Ux= zRMzUSz`6tdM}&)+hd%&!vLCT?yM4+h1EGhqw!8A-fN`{4CMS(8Z>hpJ&& zx=w%)<};dwaW}!-YIWq|8C$|Y-1qh2p*W^rZyM)AS{N+(s#g2~RWYK`4WU1Ma!!;CjRAFkL(0sX3m6ScDsgA!Bd(D+XIAX(0K%xA#r z2hOwkm_t(Od~`2+1!DXNrLJ}mJzv;s*ixB`sV?)_mF?^-s)tmiOf4*0XICmYjLDQH zH5r04n7qeq@!KR)8?_*8@xwvRQL-j%d3`nRysE@>*~=3MkEqY6d!V>L8|Y}A(Ru@C z7!?ht*5=SI^-26W?&0gE-#&q2OmiEg&@?ubYP0HilQ<)OX8M&+;`wBmt88y#@aZ! z?Ki7LY+^|PubmT}xESSn^s<}rNdNeU%o_iZrD+p&d;QNrE|delY^&Vu{KV)_`<;G9 zBL#NNMywb}bWjTjBc39)3lRhn_B_#CDj$B8P5Kf1B6IKmjdUT4f5n0EUJ>G0b3g{@ zS9n|<2CZsta8)<_0QZ#!a;6%h>J!Cj+}M_;`v})3{o(JuRP+-(vsI|NGM;VOePbE2 zRTxI-3ziuJpU}GHbc66-TH25lI6m;?GsJ4d;dW^XOe+0 z`xBf%EMOymMR?B2k4lN#DpJMkZJ4Pz@YbiPH|hrjI&v)v2J z^gn+`KK%K(o-bLb1w-=-?$SG#Cy0B+fsOYH{a96a&f_kepuH328(`(-DwODNDAzyR z-Km|f1h;~Dy6_d%cFSs8e{^r0gHaDGZFSzXT=i32b8{2xd<;@QYl+x2guWM7hffEN zt)!R2#3@XxyXM$<+U$P7#nJN-)SX?2#TW1h$Uy<asrb^XUvMX`u!ZnHAQF~$p&^WP25 zJUnTMaZF18-V!uM=jhDpNG13uG=s{GNQ_7+hS+k#J=A0Q1g6&2efSpg&(=X;7c7&c z`G)4*m)vK20&h##?oK!6X03!g4bt^%Gi|7QL9`KqoQiI|FpDA$LaZeCmwCX< zD{Ed9LztE2=ug+I^bc>>Ps9C{MdKIk77Af;ckQrLgwaP=%wHbb{?e)|N#F-ehq$f^`sLc=x1w_foH7`os2U9o(Rj>!KDATmDQyJsXX(t;|>|>v})qs!Zua+9zv5 zOnb*Q$D&CbPHo}zIl3{Jwdk3;XylhTW$HD9oo{LyX&nDiP@zC?iRh>FMQTxWakiyd zM2sP8MVmQ`IEXmVXCO8xNZfaV4|&<1>(>V%=T7>9;H(;$e0dXEb}qRhJte6_0qIgd z6`$z-13vB6hz(>>v6+Qt#GJk=isK@VWfwFjN)tDB*%oL7^Kssy7AQQCS^iQILAWly zwc%gJfm=__gxk=dWp?(U(p4;*lg~-bpSJ(~=7SKPmD#rq_s*CGtQXUd?PP$AH$1rtI6!1PP4iKLdjK5kl=*ABh)ajx-%a2&qtf4rSAO z+DTQfPCy$z*xOY9a$P3&B4Z3lK}>Ft`SxCcGi4pKE9R6!x*PY!BlEIDm(fARVS-2O zw3rign$+*YvAE(XhJ&taA08j=N1KLQd255C1r+ zsT}X%Fx|V&4M%Kevw@ll?`c<&CmcIbCF52%#S@gPxPRw--kB5w)cHR0pE-^u&-m9l z+z_ajgfaEH2*!Tw#3!Jk(ri{qd2su=Dr(!pExwB=r z0^U#9oQK_0c>Lx?ZpkQNSGV+PIV?-SzrcSc*2+@j)}w~x)z;%nv*0=!ILfx-_%_tv zx_Xfp-Sh;nx({FbHVbckv-E_6(-JrPvJmYV)%(r&DAl<f)rk^@ zZpPx4c{&?!$ZFNQ*qz(&mY; z{LCfhTrBQ>8j)+yZLj$CZi&1L?GA0n-W@HZBn!-@%h%e%eQ%l;5DHF0U<=f+KQFYp z>NXnAvu$trQ2#*G9bP?-R-(W)c84d91~pewO1m4R!Ty5A=gHs3th_1yuVigfSwBL||I@$Mrv zO7e)QlOOgfkp+C*tJxJUr&Aq-89Ez_&KG^Rlr$RklTN!|&WzG|+4 zAkRy*(+g=VDiav?>(?`w9I#(hU9uLHy%wYxDvmzMY_PY}-ZPjSw_Z<%ZAQch^b zxdtIKuwIi1L}Y>P6%HCc4;{we)@KT27HCXYg9^krV5}EC@K%$x`+)6cS*f^qfbx%Q zmR8Y*yeFWu@)0bMB%8XgK%c_P39HB&`dBNrO&XDE|6ifZlTj^uX}*!_E!hGed62kx zW;aC8u)Hl=Hvca}{Q~V2FnW7yLU6rO;hIH#%c#~U!Uz)&L~-Id>Vzt7tqhrY{_CIc z@5OBE-(hl(9rX3F>ot^*!DCjro+0rA%~^DXuKtf!g3+-Tn(@fz1;%&OHZK2^Puj(T zQP;8G^A*I-x-a~|_1mB1p575dK|?*@9?TQm8J}mF ze*bGy{n{OX>0l&JXvL>W&B?R%a5LqopngNB@YuL#%f)R*x!#TzXitW;?O%~gGQNCi68ND zb96jK_Vql@oMvC{=?<2!$s7IT+HUmuTc%s1km3ejTN_aCKkgZRo06>A1?>|TewN#P z^oqUBtYAGGoHS}d%{Ez($MU2Y&z3s##lk0t#~E!*n6%R^{+ zz?NQpQG}R{$FjFU)ZgR3EiAd6H?Y&D!|X%sj@ z5(ezE3l}j5(AVL?UmGxz_1a{&l9Yw?@hSh!a0Y zV?*n?hiEzCX5~$nZ`qY;=El43WWG;zl|DfYx`|T$FD|ZSBJ{>O0p&U7WHwc7XwHWF z-e3J+klB=!yZBAnc7& zaZ}}{#BPIR)1@Ygt=JXSK_jAOFR^5H{u&jm-ex-2!pgHpPpIm+^p_5ruGO|V&R0hj zrfU81xrSqcsC<7PSr|eVb3fasKHKKL_)Pyo8&S1_>{R}F`UZAUB9hc(aN45DND|-n z62T57;e#VF9U1?ZZNR9pCLzLW6Jl*@&2c8pqL{?B_;oMts&i28C7qW`&ILI=ShP(~ zm#2N%;#Cg&y)An9790A;=gqQFN7eymC$o;(9o^{tS9LU?TNR%sF6`;^6m%)69CR$(wdGZmScF*k~ob<~OJh~a)$iMEc<(|=O8 zRU5YnM#p*(pGy_3t}yFuB#z0RzulL{I5pL}W)JG-@V^OC26D%@5zRjXwR}h0V=s;W z>lEEW2!}PEWjPCBpLwic5?C9n8hq(bOYhi%%6rl5alu8!qXiq2K>{V~i4}E1484Ix zWbzYx2=K%tjn1ll^~ul$wRnN}@Rc_wX3YsF=dvtdcl+JFLP~>l#-0aTBKWHY zEF1M3^wqFN89K|^#G~L_873mM^q_oAQEk%pHVC?cK z5;$4uc_)djzt2nRo>g?tEgP+m!d-gwZHn%ogN>_zD#zD6{rUR0$@ZjzBZ{*Dhnq}m z!ntNXLBXc_TK@L&ExQ~)5wea|^Cx2-7FgH?=Cm@+w!Kqt< znhCQvJt=qj1Ka08!Q3Cztuh7ja$5z0-9h-nqWG5*T{c~!y-RaquQgt$-rZ4gwQ(0c zHS6kjAhDD~XV&SxpKXSfc+*JYiI`8PAj2=}?vE5C{S|OVt(0nUl{s?h-1cPL!!7~6 zar`j(HHYUM9d`WBwEr<7<$bHUgT(c4{tkFB81nBojoq2=?F?=%elLb~+eeQFyZi$? z?o-}ytiTIk)E!dk?>ja6j@B49&fh}qjWKoSkBf6cW=I7>9-Q1-jI1=G36CAryW}J{ z)|uB9>mf}}{Qmv7Q=xSp(`=U<15d3>4x^%IG1cm48N)Kt$){v-ORRl^L{dZ^x0Em@ zFWQqeSm#Nlhjmi&tA%MmB>Zf-6urQjGV(P~cp1IHlOu7%j$=06+In$s6MBTX@IFN< zRL~5=wP-bwi8sS9=PX|~AHA@#-&=BNtj#j~mxJ!6;fLh%AA4Vtr_G8S z4P*%H9*y9Eec?y!4wJZy=F9?vrrSOtoc}e@06$A*~|k(hb+`Ts))~>b2(luBlq{hmUO2f+`#(V%iK% zi83V2LU^po`#3*(LmiRO2)kq@S+)Y}6q-+W-O_|r&V}tQ!G~AYRX7T!Qc(hb#ZwyP zg5E0i{cKV>T$xkciIa5V=c$xc5UmXsnme?KtZHKwGMu51f6nqM$z4ip{5g>R{GDEn z5y^{xV*yozoEJDpAVgtc^Ju|M4XYT-ME7C`Mq(O^Puwu>nZ|}* z@+X8IxYLzsGOHvHmL*InrrZiF`7pL+6eH?!{-XC^Nfh z)eW1sEM&S?9L6w|8hJ}`fStLGoI|l%n&?q&21(N!du|w``k)A|Yv@g-_qjp=NM-PK zzqJiHkQr1mN4|rM8md*-RlDnN`-o$%>9=1(Xgn3LY^m-72+8edM-E?rR)fEM$8gMgI+>g;ZLY*VaViud&WH_{Sl;sB${b|8D!Iim1DUEeNe2so#{6b z=K$@nJR{0Ao3ADAIpm}2g$GhWFR%zUMP|$naENf0xmH6dhgp4009H$}k6UQxeH;KXPa3h}>o7fcILWX1A z9R{`Omd%-L1=JgdkfK?0-#z|Q-58Hn8R*IfyXJiKug+Nx+l-r0F=>FerXob}VhdhMMU%U`mE+k{d|%P<7xCHrA`L;8mryP zt5mg?G{*Ez%=-(+J}3I5iCtpvh{VhJEN)`dlVBWWrkpfYx?UiSPFUpD-6u%mNk~3a zi-l*Xn-eOM*5EA6C-yYBbQ6N3{iG5?@nDB=RAP(T*A0Tzt^<6R|K9vn$HeAV$X~*xgT_Gc&wH_w(CXuuh`9E~ z(%#bqN*{gMB=ssXQ6hix%o$805!WoKttGD})Ex2c#ROQIqE;0f>KqIHv3wWT+d+8E`9IQsPHo@Owac0T&Z}G=F z$s7NB!f=6<9xHf==b$B#r9vYA#z(%UguwTD9nE6M^tX-^C4Sw4xrtds_x>pcI?W@R z)lXw6JS>j28VfEtgS>awW}nYdF)KPF>PHS9V3(&E1Xc3^WZ-Wvn+YmuMh8(uf}PZR zy`3cKc?v9%!zTm%cp&sRT4_?92@`A0eO_sM*R~F(Fy2%QxuK5y5 z_7JdNt%?9Pg&froI>QI{9H$?v>&0h2(g;XWi3E?ysNk(EOIO0R$RJpBrz{OE4^b7A zSe*+ive-^mUy;n)#Mr%w4($BlEg9+W-yNR97$oOm_#62`6y6&nM$uy?vUTsE4I@TK zh9gr3g-~pYaQdg%9XsPA_r+ZmM7OOj7z=y!{pR~+lZQkzaJIwnkH$Hct>+N)@-@a) zt_Z_LoLWxfrtt8Qx(}kN=ElMrRUwJLPn}iR*?^J6+i6c6sc8Y$pOR=1t`!+)hQ3~3 zyl}OsQ(3KohXRZEkc2TO6-y-p$s_h@W$ic-Zw1b2gebNLZo5-1LifI@GUv#n<3~J@ zqqN+#)rR?tyFs%0n@*k#_+zKW8dPA8SgYz$7yl08m1<6xV+@J<$47dU8=+^=HeiVd;%qs(<+Q_X)dkzMK6c9@&LGX0?u08F>|2+ z>y)1vS&z93E&oo}L6*T)FHXt?XrD{DE|?OJ0CXXU5g$fk+!wDl#(0nM0!2bfg>;NO zENKMUfZ9b^H1VZ9TaWA8uw0k+q|<77(W#c|59_vKxF3x|P}#6S7uW7Lmmif;#tW}i zm+g(gTdx1`S1D7&$ikqkmD5b-`0(^n`qiaBaQ<=UF5L-(T_f^8F(ld9-X; zvZPPzl+1Es`gMRUB!mF`-oDjVhgr*<{z|upGR}V4CNFYPrekL4i^l3hLNZJ^X;Cl| zi7yMTe&#qU{1@`Jp!KXROo+9ezH)_wGTvxI6vrAXXJN{5yHHe6$NyAOnf;ZeV)~Vh z_w?N(QLLRJkX6_Vg6?8mvh-tiR5Z|I{CiDN&LHJ<{^GtsMu#sw>-*?^G11le+Yoxqsl{}+Tc=pDzjml%jh}>%)jWC>+^s{<_W>%XWysoT>y zmcp3F@yHVT&jFOt?4yR-dCEm2wdl6G-Qm%gQi=>{k_xS34z!m1BAESwM1GglqL?#b z${YTKcj9TjrWB0db{rTnx(-o-G!4({>KQOY#8{dIml8>~Q}k#YgxtC_n(k+`2>i!8C)*<_YqTqMg+tL|h$MQy=g`n$HOY-ScOb&QmGQh9Zx z*E`$n`LsjgMm)^q462kLW`vF()or~0FjY&y%4BUp&s{1h?OT>R*8?YFqYe+;pM*}vIqo{q!2=URU;TdWo8evOD&tK}lIH=JQgotN8MuvOXs7H_~# zp+4{TIM8mjk!-6?%DOLl7A-IczbhX0iOb=$r&emq9#K+$GvX0btPGLF$<8PQjkJKx z<3jD5M#%i$>>vZ*FAQE~l^r!e+!1DqI0A2JDxbTi`4WA*<%BJ#dFkvp>m++b7)p(5 zYU6a-X=QaKk^{W(YpsN1?zXr~x_kvAqsZ&$t=?jbv`20Wi9@1%UTrbLsrJB zaw>F>k3aGY=Q>yrH|bzaFZLeWmMUtep9+uN;ls~w4~-6wJ^Jgb3h78gBMyo<)VZ=W zWIeWAi7uO38%B$QCRGG-5%PozmwR9&k z>_gP4k|hKIMSjVMGG#tFiK9E+(I?LbdZ~EIP)>(uoVpF{*tPYkGa#F4AciGSk|+K! z$q4w1##pme)R*gz!)u?e&i$hdQetkgRPjrATe-<=lEHW)O_*6$rk|3nrWa26wW1_;w^(Z5@Pw#?Od95CjUFHjqeXY6b8fG z4e=_4i9i5L@{%7W1FpANrSTo{_YUAf%LPW>gVQ|cS!E-YJw8JFWI{+ul#Lftst98P zBkhysAWqptGS+Zmk;0j*t%|T*xqFnGdD-4tG-TjoAC(!3upV7n(UMRG|mYw=^XAN~6JUwr;LQfn@ZLy{{SxeZZW=6`3#d7r&B1_ZEokbanA$DfwD z=Z1O+bhL~p98}!$iQw$_G7aYDt&KS)E&7Z9;_+5+#YNZ8v)xz#8eXAcH4NJj%osmr z&-v1~)V%Ke;Yaj6v<$mDf7mrIj+x zSjH@-<-&00qI2xZ4ew|xk63%9t3i|vdj;498Qyz-4W)&#tng@SbdN+Vse-uJzf#S?(5`B;W8D5WSFsg)#6rPC=dZClwqI=wEv|E$5d>iJxS;<)=>~ z$>;Uml&GAAxHGy14?dWFdoi5;P?-P%tXl)ff5X}+T-<~1&Yt}7(uoW!;GG<9-8*h~ zJ~cV(>(Bu$`V=bt!!}wo4JWfHCF!;I@2$s?gpY>rw>+nhbC+XRP@P#Z+M0Nc^{8Lu z-&4{{76vx1XZ27u)kqhKC%06JYCbnJH`3Gm7bjS(8zf8$DMg*tIA6=eAA$Rt&P7xZy}c#YQGi8)~hw)SAS0K~I0B=Y| zrA*8pb;J(v%}Z2cI(P;b`dv7lu%jkQKTukBRK4NMrp*j)r2Q}&ctHdyc4uX(71QBg zUewFXd^1SZOUmyHt5L)%%I(5zEP9n)b|6)tYWO4n=+UVzqlANt-=My%3(73UNl?-t z1zMPiFiBZH2Evb@us*?QL0#~PXo9#+S0QbL1qR*nERvT*GomrhuX4scP8A{T~&YWlV%0wQhK4oic z)z!5dp066p)T7Om852Q_Ds_)HE{CW+beW;N^bvn9T4_^^ZD+jvGqUBlV_rRg^u?OO z`^{GDp`r`LlQDQvxXD!CJCI7zX*)m%Er^8;6i*w$uuV;fZX*4i|3vuFFD*&|qrY*V*&?{5Y}G?A2GkTCxJyXFuLElpNt906{}! zsttPCDqK>jLu)9B#{t=vn zd78f^_eWGq+FKx)qxZWtSgo*qjLc4v0$4+&vE`jp`F4h~70*E9UR$yKn7?%{M zAV{#K#%U}&m%G|ln!T887PKSV6OhE>i_AVHWL%SfM?Fd~Q?~VuC=6lH{pEG}9J1{B zftj9eljiTGnBHw$%Q6w%%A?jbV=ahBguAcqz+K(D7wCYlJhntObxMuM&XCR3XQg53 zS$9nxqPIpGhDra~gm_Xs7I1t`MGaN&y5BZV1!;IK!3A@)B)4aLIz-}8sH>loYyGI+2jBq~whr?-)_(lQ*o|!z z4V|v0Gx)*_JFR^k^M&wIOIQDWtT5|gnIb$CmUN^zR?M?E-|Up_!J4(oides%>Xf1` zvtKE_^V1;w;yAdvBST?oVSV!eK>ol)Puo6Sg;wpkD8~VzgK()xVL zZ4tn8E&{qF&0p*~d-88kZh?U{|2**7HAD9 zL>vhyw*WceT;u<*;YpPeBe&!mil$t|9cwC}JHm*2!!0#1kBQ2ET*#p690;ZA!~-BC zi3AUg@f=2J7~rqDyzrkjkmUX-n{mhF(q7G|^%5QzK`uHdj3)x(^V6`AOyw(mA?(!* z?kh}Q_VnI`1HJ<6p1{!f5eP#|g6uMwe4cgqRfP8RZkCw!ruVu@G<$xZ*+*wKrj?Jd zJu6_|mc|6V;44GP)JgyuT1LEIFEqZy1(Lsz+jIv3gHby?9coDe-(YZApkJ|@I z1VvLYw@NMcVqqPb$J(F2Opq?{a{cB`P#hb-9CX2j)}mvaXYEK}mW9a2%$Kej9Vrp0 zo~})>{(xqjk`md_tJASQWU@b?ciOleFrrhcX&l_T@q3G7%H&02ZlA`65)5gd{Ii5O zr7%rW57)9Fx+nnQfH9wIMRY|)m|{~efTT;n?kca{B=St)O%+eD!9^5!M-#WmHr1T6z!piFC!Vgg3xU*d$4p3%?A z(kGfBwtO37|1aEs{>mBHh`jg3uAGmi zn4=o!ul$L)?;n(>skw}+Ths7jt>?h$P*i_qW$l_`qj735B})k1OZ;3_N0E-py91#V zf?~S2nc`vlxc_Zt$t*9k54f7o0?w_I2HpM7CFd9O{OymoD_npH@0Bu4hzi6k`zXGu z!&aHP=OZfm7R14y27$_CV<~PAZb&Cx__T^?pN3My*R1Tlk_h9>af>7Veo6{1WKo>Y zr)da3d7=aUQ~KXR-Da!meXe_laHvB6tBkyDv!NGz`hd(~Do(11eG64=3}f1G(tlhD z^M?p?Ol&q{C-IKhiytEzc6a^$?2o;21v3=3on+gY{h!6zF8&$s%(zWosNGGF>Bk7R z18}WLZy)tXL(Llu3agIgR5!B~ZXb=O1Ds?-r&PwGCavaQxq)b}#{>O6e}1>6=@&=) z&ManIZ>dvYtT}E=%8opQIlSp7utK|MSC7QY#6rZik#9F+U_K-XT3r`pNBl8LIV8&9 zmFj>`s2^8KOj-DM;ixBaz1e5)w1xPNhZv{Z_NI_7681%qC=e+)5jdqyW)|#_)CMe<04-#lJQ~x6<~w-fv6Lh zL6?3+X%YRrCGrQEc0_Y=vpH3W%qEWR?%+@sT97Rxf+Xl~1i+u@_k@(nLr+&M>gawc zAR1ijQNIwj=mOO|VXXL+kLLc$zKW2j6Ydhmc#O8V8CYrT@K~>a+kMCe z#r;d~=~PCZWJ0D>uVYV{*7xBHAuR3IY>k32s|A;pe<&7cL(%K!MME8>bv6jChp- z17e>Mi+CNVXlxRCLgJw-P{s9O%H3CrEQ_s#&$lY@na$uM|h-DPc zKNAzAkp#H&9F=68M=4}<{?CUs?IszkGq2+dKII_8`{PwAwn9#z;a6Cr zI2Na!Ur7-h_(ABC`PC)e*@q37irOF_2-cs~sSV6|MpT_pn&7kLrAwj4owOyu^WCaR#$5~is!~ZSxi@aLOx&2-?2b%gv zQ|}sHhoMl`3!OVrB#9h1#nAiZN551oC&3Ve@81gD963p)By*;D5{k=V^lLm7{67V((XrzF%EFMpl{+52SN5-!_Hbl&!KqAVlmG~U%pWmQ zhI=mj#~5R1C1CPe7#$tO$lbxV!9Z`xb1`WeetF@9<&U{~=ppb8zQl}wNt_ARxgks0 zr5%6Ci*I{9bh6yUdCt4arB5K^cdp4e461(bY~32%5k&?K4`kE3C(#VKx-q}O8$L*h z)1j-OHXA(OsMt+THxcB8@OJR2A=`|FZ0oFJ+Ti~U`G;JZt={iq9enu|fM4)^zPQpW z5uN<)p$vW~Vp-}khRmr)u5UjL=){7Re?F`pU%O*O7oRT*!K#IL1OKp5=JOC$Fk_FQGaolJK5%Rn_XibM(9LU$Xpx9E3^% zvVV?Sqkren^OjL&iB4%=GmNrWSe`8Z-2U~p^O5S{_ZLAQ84Pq`99uX8~lp)uzQX=R+W)r25d$+0;mSeAA>ttk! zx~)>hI7ZCW=yzB4X@1`ZqiwsRp0q^6Mz~_@Um1p!F2WmcmzqSN{-s=_`lEsoW8+cC zq*|+eo@Lez;X=vsOr~CfXZ|UX{=`*p7q;HL4i|o?2g4p{BeP%Q91~8^_H+n%YK{JU zlDT&?kwZ!$W$50Fk3E%)Y`ptbG!V$N8>D+r6NJ_TbH6-0WJ6ESQza()b(uGarPVXU z95H`ZbTnkoCqorO*^D3Nkcc1r!ucIMX&%Cgg2x?r`=DVRB2WNuBVs#q#XS?- z2(ZaZRDxM&{~FjThmv^bMyZra9w`KhCyg{v3${xE(C`yLSXQitNhh?fB!(h>$@^Cy zn9c&j#pX@qTi2_ygD$1M)!8p4&(5voFG?ttrzc8!(xN`TkJYD5MEy&zy-kOul6YL! zgN`3}`2s+!s!k8nOWp!<|L-<>MSC)Joj_wISCawBo7hlbzT-%QRv!7ZZR;CaI;lg{ z+V4NfzZW6qDHb`@7%mtK#Dq$9iGxA{gWJPsXK$G9CZKH^cMojV=R_6cQC|Hm-rWX}=PrRp3ju+g}`UDTULp1n7k>L&iPvT{W+E$1$^m|VKwnyvB8 z`*;I9yCp-hMn2%GeZE9n6i6j4 - - - - - - - - - diff --git a/assets/logos/gemini-light.svg b/assets/logos/gemini-light.svg deleted file mode 100644 index 2d9f6403..00000000 --- a/assets/logos/gemini-light.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/assets/logos/goose-dark.svg b/assets/logos/goose-dark.svg new file mode 100644 index 00000000..8a355cb7 --- /dev/null +++ b/assets/logos/goose-dark.svg @@ -0,0 +1 @@ +Goose \ No newline at end of file diff --git a/assets/logos/goose-light.svg b/assets/logos/goose-light.svg new file mode 100644 index 00000000..43bf93b0 --- /dev/null +++ b/assets/logos/goose-light.svg @@ -0,0 +1 @@ +Goose \ No newline at end of file diff --git a/assets/logos/openclaw.svg b/assets/logos/openclaw.svg new file mode 100644 index 00000000..bcbc1e10 --- /dev/null +++ b/assets/logos/openclaw.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/bin/failproofai.mjs b/bin/failproofai.mjs index a3104d25..b7490cc0 100755 --- a/bin/failproofai.mjs +++ b/bin/failproofai.mjs @@ -65,7 +65,7 @@ const hookIdx = args.indexOf("--hook"); if (hookIdx >= 0) { if (!args[hookIdx + 1]) { console.error("Error: Missing event type after --hook"); - console.error("Usage: failproofai --hook [--cli ]"); + console.error("Usage: failproofai --hook [--cli ]"); process.exit(1); } const eventType = args[hookIdx + 1]; @@ -81,8 +81,12 @@ if (hookIdx >= 0) { || cliArg === "cursor" || cliArg === "opencode" || cliArg === "pi" - || cliArg === "gemini" || cliArg === "hermes" + || cliArg === "openclaw" + || cliArg === "factory" + || cliArg === "devin" + || cliArg === "antigravity" + || cliArg === "goose" ) ? cliArg : "claude"; @@ -130,18 +134,18 @@ COMMANDS policies, p List all available policies and their status policies --install, -i Enable policies in agent CLI settings [names...] Specific policy names to enable - --cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes + --cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose Agent CLI(s) to install for; space-separated - (e.g. --cli claude codex copilot cursor opencode pi gemini hermes) or repeated. + (e.g. --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose) or repeated. Default: detect installed CLIs and prompt. --scope user|project|local Config scope to write to (default: user) - (Codex / Copilot / Cursor / OpenCode / Pi / Gemini support user|project only) + (Codex / Copilot / Cursor / OpenCode / Pi support user|project only) --beta Include beta policies --custom, -c Path to a JS file of custom policies policies --uninstall, -u Disable policies or remove hooks [names...] Specific policy names to disable - --cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes + --cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose Agent CLI(s) to uninstall from --scope user|project|local|all Config scope to remove from (default: user) --beta Remove only beta policies @@ -176,8 +180,9 @@ EXAMPLES failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project - failproofai policies --install --cli claude codex copilot cursor opencode pi gemini hermes + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose failproofai policies --install --custom ./my-policies.js failproofai policies -i -c ./my-policies.js failproofai policies --uninstall block-sudo @@ -186,7 +191,6 @@ EXAMPLES failproofai policies --uninstall --cli cursor failproofai policies --uninstall --cli opencode failproofai policies --uninstall --cli pi - failproofai policies --uninstall --cli gemini failproofai policies --uninstall --custom LINKS @@ -226,20 +230,20 @@ USAGE OPTIONS (install) [names...] Specific policy names to enable (omit for interactive) - --cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes + --cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose Agent CLI(s) to install for; space-separated - (e.g. --cli claude codex copilot cursor opencode pi gemini hermes) or repeated. + (e.g. --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose) or repeated. Omit to detect installed CLIs and prompt (or auto-pick if only one is found). --scope user|project|local Config scope to write to (default: user) - (Codex / Copilot / Cursor / OpenCode / Pi / Gemini support user|project only) + (Codex / Copilot / Cursor / OpenCode / Pi support user|project only) --beta Include beta policies --custom, -c Path to a JS file of custom policies (skips interactive prompt; validates file first) OPTIONS (uninstall) [names...] Specific policy names to disable (omit to remove hooks) - --cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes + --cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose Agent CLI(s) to uninstall from --scope user|project|local|all Config scope to remove from (default: user) --beta Remove only beta policies @@ -254,8 +258,9 @@ EXAMPLES failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project - failproofai policies --install --cli claude codex copilot cursor opencode pi gemini hermes + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose failproofai policies --install --custom ./my-policies.js failproofai policies -i -c ./my-policies.js failproofai policies --uninstall block-sudo @@ -296,7 +301,7 @@ EXAMPLES // --cli claude codex copilot // --cli claude --cli codex // Values are consumed greedily until the next flag or end of argv. - const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); const cliFlagValues = []; const cliConsumedIdxs = new Set(); const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0); @@ -313,7 +318,7 @@ EXAMPLES consumed++; } if (consumed === 0) { - throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)"); + throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi hermes openclaw (or any subset)"); } } @@ -385,7 +390,7 @@ EXAMPLES } // --cli accepts one or more space-separated values; same parser as install. - const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); const cliFlagValues = []; const cliConsumedIdxs = new Set(); const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0); @@ -402,7 +407,7 @@ EXAMPLES consumed++; } if (consumed === 0) { - throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)"); + throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi hermes openclaw (or any subset)"); } } @@ -511,7 +516,7 @@ USAGE failproofai policy remove Disable one policy OPTIONS - --cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes + --cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose Agent CLI(s) to apply to; space-separated or repeated. Omit to detect installed CLIs and prompt. --scope user|project|local Config scope (default: user) @@ -549,7 +554,7 @@ EXAMPLES } // --cli accepts one or more space-separated values, optionally repeated. - const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]); + const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"]); const cliFlagValues = []; const cliConsumedIdxs = new Set(); const cliFlagIdxs = rest.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0); @@ -564,7 +569,7 @@ EXAMPLES consumed++; } if (consumed === 0) { - throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)"); + throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi hermes openclaw (or any subset)"); } } diff --git a/docs/ar/built-in-policies.mdx b/docs/ar/built-in-policies.mdx index 1c508863..2f712836 100644 --- a/docs/ar/built-in-policies.mdx +++ b/docs/ar/built-in-policies.mdx @@ -710,7 +710,7 @@ icon: shield ### دلالات Stop لكل CLI -يبدو إنفاذ Stop مختلفاً قليلاً عبر سبعة CLI مدعومة لأن كل واحد يعرّض عقد hook مختلفاً. النتيجة **متطابقة** — الوكيل لا يهرب من التوقف بينما تفشل بوابة سير العمل — لكن **الميكانيكا** تختلف. يلخص الجدول أدناه؛ فقط Pi لديه خصوصية واضحة للمستخدم تستحق الفهم قبل تفعيل سياسة `require-*-before-stop`. +يبدو إنفاذ Stop مختلفاً قليلاً عبر ستة CLI مدعومة لأن كل واحد يعرّض عقد hook مختلفاً. النتيجة **متطابقة** — الوكيل لا يهرب من التوقف بينما تفشل بوابة سير العمل — لكن **الميكانيكا** تختلف. يلخص الجدول أدناه؛ فقط Pi لديه خصوصية واضحة للمستخدم تستحق الفهم قبل تفعيل سياسة `require-*-before-stop`. | CLI | متى تعمل البوابة | ما تراه | |---|---|---| @@ -718,20 +718,19 @@ icon: shield | Codex | نفس حلقة الوكيل، فوراً | نفس Claude. | | GitHub Copilot CLI | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة إعادة محاولة `{decision:"block", reason}` الخاصة بـ Copilot — تم التحقق منها تجريبياً ضد Copilot CLI 1.0.41). | | Cursor Agent | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة `{followup_message}` الخاصة بـ Cursor — محدودة بـ `loop_limit`، افتراضي 5 إعادة محاولات). | -| Gemini CLI | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة `{decision:"block", reason}` الخاصة بـ Gemini على `AfterAgent`). | | OpenCode | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم استدعاء SDK `client.session.prompt(...)` الخاص بـ OpenCode الموجه عبر `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **دور المستخدم التالي** | **يتوقف Pi بشكل واضح** عندما تعمل البوابة — تنهي حلقة الوكيل الخاصة به وتعودين إلى الموجه. تعمل البوابة بعد ذلك في المرة القادمة التي تقدّمين فيها موجهاً: يضيف failproofai توجيهاً `MANDATORY ACTION REQUIRED` إلى موجه نظام هذا الدور، يعلّم LLM بإكمال خطوة سير العمل (التزام، دفع، إلخ) قبل فعل ما طلبتِ. | -**قيد Pi.** `AgentEndEvent` الخاص بـ Pi (المعادل الأعلى لـ hook `Stop` الخاص بـ Claude) لا يملك نوع Result — بحلول الوقت الذي يعمل فيه، تكون حلقة الوكيل الخاصة بـ Pi قد خرجت بالفعل. لا يمكن إجبار Pi على إعادة محاولة نفس الحلقة بالطريقة التي يمكن بها Claude / Copilot / Cursor / Gemini / OpenCode. ينقل failproofai البوابة إلى حدث `before_agent_start` الخاص بـ Pi (الذي يعمل بعد الموجه التالي للمستخدم) لذا يبقى فحص سير العمل مفروضاً، فقط على الدور التالي بدلاً من الحالي. +**قيد Pi.** `AgentEndEvent` الخاص بـ Pi (المعادل الأعلى لـ hook `Stop` الخاص بـ Claude) لا يملك نوع Result — بحلول الوقت الذي يعمل فيه، تكون حلقة الوكيل الخاصة بـ Pi قد خرجت بالفعل. لا يمكن إجبار Pi على إعادة محاولة نفس الحلقة بالطريقة التي يمكن بها Claude / Copilot / Cursor / OpenCode. ينقل failproofai البوابة إلى حدث `before_agent_start` الخاص بـ Pi (الذي يعمل بعد الموجه التالي للمستخدم) لذا يبقى فحص سير العمل مفروضاً، فقط على الدور التالي بدلاً من الحالي. **ما يعنيه هذا عملياً:** - بعد توقف Pi، يتم التقاط رار الرفض في الذاكرة بمفتاح معرف جلسة Pi. الموجه التالي الذي تقدّمينه بالضبط في نفس عملية Pi يصرفه: يرى LLM توجيه `MANDATORY ACTION REQUIRED` في أعلى موجه النظام الخاص به، يلتزم (أو يدفع / يفتح PR / ينتظر CI)، وفقط بعد ذلك يستمر مع طلبك. رار الرفض المقبوض مرة واحدة — بمجرد صرفه، تكون البوابة واضحة. -- البوابة محدودة بعمر عملية Pi. إذا قمتِ بـ `Ctrl+C` Pi أو أغلقتِ بين الأدوار، يتم حذف الإدخال في الذاكرة مع العملية والبوابة تُفتقد. Claude و Copilot و Cursor و Gemini و OpenCode لديها نفس الحد (اقتل الوكيل والبوابة تُفتقد) — Pi فقط يجعله أكثر وضوحاً لأن الوكيل يخرج بشكل واضح قبل عمل البوابة. +- البوابة محدودة بعمر عملية Pi. إذا قمتِ بـ `Ctrl+C` Pi أو أغلقتِ بين الأدوار، يتم حذف الإدخال في الذاكرة مع العملية والبوابة تُفتقد. Claude و Copilot و Cursor و OpenCode لديها نفس الحد (اقتل الوكيل والبوابة تُفتقد) — Pi فقط يجعله أكثر وضوحاً لأن الوكيل يخرج بشكل واضح قبل عمل البوابة. - رار الرفض المعلق يتم مسحه أيضاً على `session_shutdown` لأي سبب (`new` / `resume` / `fork` / `quit`)، لذا بوابة قديمة من جلسة سابقة لا تستطيع التسرب إلى جلسة جديدة بدأت في نفس عملية Pi. -إذا احتجتِ إلى إعادة محاولة نفس الحلقة بأسلوب Claude، قومي بتشغيل سياسات `Stop` الخاصة بك تحت أي من ستة CLI الأخرى المدعومة. نحن نتابع Pi في المنبع لنوع Result مستقبلي على `AgentEndEvent` الذي سيسمح لنا بإغلاق هذه الفجوة. +إذا احتجتِ إلى إعادة محاولة نفس الحلقة بأسلوب Claude، قومي بتشغيل سياسات `Stop` الخاصة بك تحت أي من خمسة CLI الأخرى المدعومة. نحن نتابع Pi في المنبع لنوع Result مستقبلي على `AgentEndEvent` الذي سيسمح لنا بإغلاق هذه الفجوة. ### `require-commit-before-stop` diff --git a/docs/ar/cli/audit.mdx b/docs/ar/cli/audit.mdx index fd1384a9..2efba375 100644 --- a/docs/ar/cli/audit.mdx +++ b/docs/ar/cli/audit.mdx @@ -46,7 +46,7 @@ failproofai قم بتشغيل `failproofai audit -h` (أو `--help`) لرؤية الاستخدام. يعمل التدقيق **بالكامل بدون اتصال** — لا تحتاج إلى حساب أو شبكة — ولوحة التحكم تستمر في الخدمة حتى توقفها بـ `Ctrl+C`. -تقوم لوحة التحكم بفحص نصوص وكيل CLI السابقة على هذا الجهاز (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) وتقرر كم مرة فعل الوكيل أشياء تم بناء failproofai لإيقافها — فحوصات متغيرات البيئة، الدفعات القسرية، البادئات `cd ` الزائدة، حلقات الانتظار بالنوم، إعادة قراءة الملفات التي تم تحريرها للتو، وغير ذلك. +تقوم لوحة التحكم بفحص نصوص وكيل CLI السابقة على هذا الجهاز (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) وتقرر كم مرة فعل الوكيل أشياء تم بناء failproofai لإيقافها — فحوصات متغيرات البيئة، الدفعات القسرية، البادئات `cd ` الزائدة، حلقات الانتظار بالنوم، إعادة قراءة الملفات التي تم تحريرها للتو، وغير ذلك. لكل نص، يتم إعادة تشغيل كل حدث استخدام أداة عبر السياسات المدمجة البالغ عددها 39 **و** عبر 8 كواشف خاصة بالتدقيق فقط التي تلتقط الأنماط التي لم تغطها السياسات الوقتية بعد. يتم تجميع الأعداد لكل سياسة / كاشف عبر جميع الجلسات. diff --git a/docs/ar/configuration.mdx b/docs/ar/configuration.mdx index 71fa9a37..9c277024 100644 --- a/docs/ar/configuration.mdx +++ b/docs/ar/configuration.mdx @@ -197,13 +197,12 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى ا - **OpenAI Codex**: `~/.codex/hooks.json` (مستخدم), `/.codex/hooks.json` (مشروع) — Codex ليس له نطاق محلي - **GitHub Copilot CLI _(نسخة تجريبية)_**: `~/.copilot/hooks/failproofai.json` (مستخدم), `/.github/hooks/failproofai.json` (مشروع) — Copilot ليس له نطاق محلي. إدخالات الخطاف تستخدم حقول أوامر Copilot المفتاحة بنظام التشغيل `bash`/`powershell` مع `timeoutSec`؛ يحمل الملف علامة `version: 1` على المستوى الأعلى. دعم GitHub Copilot CLI **نسخة تجريبية** بينما نتحقق من مخطط سجل `events.jsonl` (الذي لا تحدده المستندات العامة) مقابل جلسات حقيقية أكثر. - **Cursor Agent _(نسخة تجريبية)_**: `~/.cursor/hooks.json` (مستخدم), `/.cursor/hooks.json` (مشروع) — Cursor ليس له نطاق محلي. إدخالات الخطاف تستخدم نموذج `{type, command, timeout}` على شكل Claude (لا انقسام `bash`/`powershell`)، لكن يتم تخزينها تحت مفاتيح أحداث camelCase (`preToolUse`, `beforeSubmitPrompt`, …) في مصفوفة مسطحة وفقاً [لمخطط الخطافات](https://cursor.com/docs/hooks) الخاص بـ Cursor؛ يحمل الملف علامة `version: 1` على المستوى الأعلى. يقوم المعالج بتحويل camelCase → PascalCase عبر `CURSOR_EVENT_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. دعم Cursor Agent **نسخة تجريبية** بينما نتحقق من نسخة Cursor على القرص (غير محددة في المستندات العامة) مقابل عمليات تثبيت حقيقية أكثر. - - **OpenCode _(نسخة تجريبية)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (مستخدم), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (مشروع) — OpenCode ليس له نطاق محلي. على عكس المحررات الستة الأخرى، OpenCode **ليس له نظام خطاف أوامر خارجية**: يحمل في الذاكرة مكوّنات JavaScript/TypeScript مسجلة بشكل صريح عبر مصفوفة `plugin: []` في `opencode.json` (الاكتشاف التلقائي من `.opencode/plugins/` **ليس** كيف يتم تحميل المكونات على opencode v1.14.33). التثبيت ينقط مكون شيم صغير يستدعي ثنائي failproofai عبر subprocess ويترجم استجابة JSON على شكل Claude الخاصة بالثنائي إلى دلالات المكون: `throw new Error()` لرفض حدث الأداة (يلغي استدعاء الأداة)، `client.session.prompt(...)` للتعليمات **و** لرفض `Stop` / `SubagentStop` (يرسل سبب الرفض كرسالة المستخدم التالية — القناة الوحيدة للإعادة القسرية منذ أن `session.idle` إخطار فقط والرمي منه لا يعمل)، بدون عملية للسماح. يقوم الشيم بتحويل أسماء الأدوات (lowercase → PascalCase عبر `OPENCODE_TOOL_MAP`) ومفاتيح حجج إدخال الأداة (camelCase → snake_case عبر `OPENCODE_TOOL_INPUT_MAP` لـ `Read` / `Write` / `Edit`، مثلاً `filePath` → `file_path`, `oldString` → `old_string`) قبل إعادة التوجيه إلى الثنائي، بحيث تعمل عمليات التحقق من المسارات المدمجة مثل `block-read-outside-cwd`, `block-env-files`, و `block-secrets-write` بدون تغيير على استدعاءات أداة OpenCode. الجلسات تعيش في قاعدة بيانات OpenCode SQLite في `~/.local/share/opencode/opencode.db`؛ عارض الجلسات في لوحة التحكم يقرأها عبر `opencode db --format json` و `opencode export `. دعم OpenCode **نسخة تجريبية** بينما نتحقق من السلوك عبر الإصدارات ومقابل جلسات حقيقية أكثر. انظر [مستندات مكونات OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(نسخة تجريبية)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (مستخدم), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (مشروع) — OpenCode ليس له نطاق محلي. على عكس المحررات الخمسة الأخرى، OpenCode **ليس له نظام خطاف أوامر خارجية**: يحمل في الذاكرة مكوّنات JavaScript/TypeScript مسجلة بشكل صريح عبر مصفوفة `plugin: []` في `opencode.json` (الاكتشاف التلقائي من `.opencode/plugins/` **ليس** كيف يتم تحميل المكونات على opencode v1.14.33). التثبيت ينقط مكون شيم صغير يستدعي ثنائي failproofai عبر subprocess ويترجم استجابة JSON على شكل Claude الخاصة بالثنائي إلى دلالات المكون: `throw new Error()` لرفض حدث الأداة (يلغي استدعاء الأداة)، `client.session.prompt(...)` للتعليمات **و** لرفض `Stop` / `SubagentStop` (يرسل سبب الرفض كرسالة المستخدم التالية — القناة الوحيدة للإعادة القسرية منذ أن `session.idle` إخطار فقط والرمي منه لا يعمل)، بدون عملية للسماح. يقوم الشيم بتحويل أسماء الأدوات (lowercase → PascalCase عبر `OPENCODE_TOOL_MAP`) ومفاتيح حجج إدخال الأداة (camelCase → snake_case عبر `OPENCODE_TOOL_INPUT_MAP` لـ `Read` / `Write` / `Edit`، مثلاً `filePath` → `file_path`, `oldString` → `old_string`) قبل إعادة التوجيه إلى الثنائي، بحيث تعمل عمليات التحقق من المسارات المدمجة مثل `block-read-outside-cwd`, `block-env-files`, و `block-secrets-write` بدون تغيير على استدعاءات أداة OpenCode. الجلسات تعيش في قاعدة بيانات OpenCode SQLite في `~/.local/share/opencode/opencode.db`؛ عارض الجلسات في لوحة التحكم يقرأها عبر `opencode db --format json` و `opencode export `. دعم OpenCode **نسخة تجريبية** بينما نتحقق من السلوك عبر الإصدارات ومقابل جلسات حقيقية أكثر. انظر [مستندات مكونات OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(نسخة تجريبية)_**: `~/.pi/agent/settings.json` (مستخدم), `/.pi/settings.json` (مشروع) — Pi ليس له نطاق محلي. يحمل Pi حزم ملحقات TypeScript عند البدء؛ ملف الإعدادات مصفوفة نصية مسطحة `{"packages": ["./relative/path", …]}`. يكتب failproofai إدخالة مصفوفة حزم واحدة تشير إلى دليل `pi-extension/` المجمع الخاص به. يشترك الملحق داخلياً في أحداث Pi `tool_call` / `user_bash` / `input` / `session_start` ويقذف إلى `failproofai --hook --cli pi`؛ يقوم المعالج بتحويل underscore_lower_snake_case → PascalCase عبر `PI_EVENT_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. يتم أيضاً تحويل حجج إدخال الأداة عبر `PI_TOOL_INPUT_MAP` (تسليم Pi للقراءة / الكتابة / التحرير `path` بدلاً من `file_path`؛ تعيين المفتاح على المستوى الأعلى يسمح بتشغيل `block-env-files` و `block-secrets-write` — `block-read-outside-cwd` كان لديه بالفعل بديل `path`). دعم Pi **نسخة تجريبية** بينما تستقر ملحقات Pi API وتخطيط سجل الجلسة. - - **Gemini CLI _(نسخة تجريبية)_**: `~/.gemini/settings.json` (مستخدم), `/.gemini/settings.json` (مشروع) — Gemini ليس له نطاق محلي (يوثق نطاق `system` على `/etc/gemini-cli/settings.json` الذي لا يعرضه failproofai). إدخالات الخطاف تستخدم نموذج Claude `{type, command, timeout}` ملفوف في مخطط مطابق Gemini `{matcher, hooks: [...]}` مع `matcher: "*"` افتراضياً. الأحداث تكون PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); يقوم المعالج بالتعيين إلى أسماء Claude الأساسية عبر `GEMINI_EVENT_MAP`. أسماء الأدوات تكون snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — يقوم المعالج بتحويلها عبر `GEMINI_TOOL_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. يصدر محقق السياسة شكل Gemini المسطح `{decision: "deny", reason}` (مفضل وفقاً لـ Golden Rule للخروج-0 من Gemini)، `{hookSpecificOutput: {hookEventName, additionalContext}}` لحقن السياق على BeforeAgent / AfterTool / SessionStart، و `{decision: "block", reason}` على AfterAgent لدلالات الإعادة القسرية. دعم Gemini CLI **نسخة تجريبية** بينما نوسع التغطية الحقيقية. انظر [مستندات خطافات Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**نطاق المستخدم فقط** — Hermes ليس له إعدادات المشروع/المحلي). Hermes هو **بوابة** Slack/Telegram، لذلك تثبيت واحد يعترض استدعاءات الأدوات من كل منصة (Slack/Telegram/cli/cron) **و** الوكلاء الفرعيين الداخليين. إدخالات الخطاف هي زوج `{command, timeout}` (المهلة الزمنية **بالثواني**) تحت خريطة `hooks:` مفتاحها بأحداث snake_case من Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); يقوم المعالج بتحويل الأحداث عبر `HERMES_EVENT_MAP` وأسماء الأدوات عبر `HERMES_TOOL_MAP` بحيث تعمل السياسات المدمجة بدون تغيير. يتم تحرير الإعدادات من خلال استدارة YAML `Document` حفاظاً على التعليقات بحيث تبقى الإعدادات الأخرى للمشغل، والتثبيت يعيّن `hooks_auto_accept: true` بحيث تعمل بوابة بدون رأس (لا TTY) الخطافات بدون موجه موافقة. يصدر المقيّم عقد stdout الخاص بـ Hermes `{"decision":"block","reason"}` (يتجاهل Hermes أكواد الخروج). **القيود:** Hermes ليس له حدث نهاية الدور `Stop`، لذا فإن المدمجات `require-*-before-stop` لن تعمل أبداً لـ Hermes (غير قابلة للتطبيق، وليس كسر)؛ `instruct` تنخفض إلى السماح مع ملاحظة مسجلة (لا قناة سياق إضافية)؛ وإعادة تسمية سرية الإخراج (`sanitize-*`) لا يمكن إعادة كتابة إخراج الأداة على عقد shell-hook. Hermes هو **أيضاً** مصدر **تدقيق** غير متصل — لوحة التحكم تقرأ جلسات بوابتها مباشرة من `~/.hermes/state.db`. - **`policies-config.json`** — يخبر failproofai بالسياسات التي يجب تقييمها وبأية معاملات (مشاركة عبر جميع عملاء الوكيل) -مرر `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` لاستهداف وكيل محدد (مفصول بمسافات أو متكرر لأي مجموعة فرعية): +مرر `--cli claude|codex|copilot|cursor|opencode|pi|hermes` لاستهداف وكيل محدد (مفصول بمسافات أو متكرر لأي مجموعة فرعية): ```bash failproofai policies --install --cli codex --scope project @@ -211,12 +210,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -عندما يتم حذف `--cli`، يكتشف failproofai عملاء الوكيل المثبتة (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +عندما يتم حذف `--cli`، يكتشف failproofai عملاء الوكيل المثبتة (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **تم اكتشاف عميل واحد** — يختار ذلك العميل تلقائياً بدون فور. - **عملاء متعددة مكتشفة** في محطة طرفية تفاعلية — يعرض موجه اختيار مفرد بمفاتيح الأسهم مجمع في قسم `Detected (N)` (مع صف إجمالي للتثبيت لكل عميل مكتشفة N + كل عميل مكتشفة بشكل فردي) وقسم `Not installed (M) · install hooks ahead of time` يسرد كل عميل مكتشفة مدعومة كخيار تثبيت آجل (↑↓ للتحريك، أدخل للاختيار، ^C للخروج). يعرض تدفق الإلغاء قسم Detected فقط. diff --git a/docs/ar/dashboard.mdx b/docs/ar/dashboard.mdx index fc2633a9..3aa42b0a 100644 --- a/docs/ar/dashboard.mdx +++ b/docs/ar/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### المشاريع -يسرد جميع مشاريع Claude Code و OpenAI Codex و GitHub Copilot CLI _(إصدار تجريبي)_ و Cursor Agent _(إصدار تجريبي)_ و OpenCode _(إصدار تجريبي)_ و Pi _(إصدار تجريبي)_ و Gemini CLI _(إصدار تجريبي)_ و Hermes الموجودة على جهازك. يتم اكتشاف مشاريع Claude من `~/.claude/projects/` (أو المسار المحدد بواسطة `CLAUDE_PROJECTS_PATH`); يتم اكتشاف مشاريع Codex بمسح كل نص تحت `~/.codex/sessions///
/*.jsonl` وتجميعها حسب `cwd` المسجل في السجل الأول من كل جلسة; يتم اكتشاف مشاريع Copilot CLI بمسح كل `~/.copilot/session-state//workspace.yaml` (قابل للتكوين عبر `COPILOT_HOME`) وتجميعها حسب حقل `cwd` الخاص به; يتم اكتشاف مشاريع Cursor Agent بمسح البيانات الفوقية لكل جلسة تحت `~/.cursor/agent-sessions//` (قابل للتكوين عبر `CURSOR_HOME`، مع اختبار `conversations/` و `sessions/` كبدائل) للبحث عن `cwd` في `meta.json` / `session.json` / `workspace.yaml`; يتم اكتشاف مشاريع OpenCode بالاستعلام عن قاعدة بيانات SQLite الخاصة به في `~/.local/share/opencode/opencode.db` عبر `opencode db --format json` (نحن نقرأ الجداول `session` و `project` ونجمعها حسب `project_id`); يتم اكتشاف مشاريع Pi بمسح نصوص JSONL لكل جلسة تحت `~/.pi/agent/sessions//_.jsonl` (قابل للتكوين عبر `PI_SESSIONS_DIR`) واستخراج `cwd` من السجل الأول من كل جلسة; يتم اكتشاف مشاريع Gemini CLI بمسح `~/.gemini/tmp//chats/session--.jsonl` (قابل للتكوين عبر `GEMINI_SESSIONS_DIR`) واسترجاع cwd القانوني من علامة النص المجاورة `.project_root`; تتم قراءة جلسات بوابة Hermes مباشرة من متجرها SQLite في `~/.hermes/state.db` (قابل للتكوين عبر `HERMES_DB_PATH`) وتجميعها في مشاريع `hermes-` حسب `source` (Slack/Telegram/cli/cron — جلسات البوابة لا تحتوي على cwd). يتم عرض المشروع الذي تم استخدامه بواسطة عدة CLIs كصف واحد مع جميع الشارات المطابقة. استخدم القائمة المنسدلة **CLI** فوق الجدول للتصفية حسب CLI وكيل معين; يحافظ عنوان URL على اختيارك كـ `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +يسرد جميع مشاريع Claude Code و OpenAI Codex و GitHub Copilot CLI _(إصدار تجريبي)_ و Cursor Agent _(إصدار تجريبي)_ و OpenCode _(إصدار تجريبي)_ و Pi _(إصدار تجريبي)_ و Hermes الموجودة على جهازك. يتم اكتشاف مشاريع Claude من `~/.claude/projects/` (أو المسار المحدد بواسطة `CLAUDE_PROJECTS_PATH`); يتم اكتشاف مشاريع Codex بمسح كل نص تحت `~/.codex/sessions///
/*.jsonl` وتجميعها حسب `cwd` المسجل في السجل الأول من كل جلسة; يتم اكتشاف مشاريع Copilot CLI بمسح كل `~/.copilot/session-state//workspace.yaml` (قابل للتكوين عبر `COPILOT_HOME`) وتجميعها حسب حقل `cwd` الخاص به; يتم اكتشاف مشاريع Cursor Agent بمسح البيانات الفوقية لكل جلسة تحت `~/.cursor/agent-sessions//` (قابل للتكوين عبر `CURSOR_HOME`، مع اختبار `conversations/` و `sessions/` كبدائل) للبحث عن `cwd` في `meta.json` / `session.json` / `workspace.yaml`; يتم اكتشاف مشاريع OpenCode بالاستعلام عن قاعدة بيانات SQLite الخاصة به في `~/.local/share/opencode/opencode.db` عبر `opencode db --format json` (نحن نقرأ الجداول `session` و `project` ونجمعها حسب `project_id`); يتم اكتشاف مشاريع Pi بمسح نصوص JSONL لكل جلسة تحت `~/.pi/agent/sessions//_.jsonl` (قابل للتكوين عبر `PI_SESSIONS_DIR`) واستخراج `cwd` من السجل الأول من كل جلسة; تتم قراءة جلسات بوابة Hermes مباشرة من متجرها SQLite في `~/.hermes/state.db` (قابل للتكوين عبر `HERMES_DB_PATH`) وتجميعها في مشاريع `hermes-` حسب `source` (Slack/Telegram/cli/cron — جلسات البوابة لا تحتوي على cwd). يتم عرض المشروع الذي تم استخدامه بواسطة عدة CLIs كصف واحد مع جميع الشارات المطابقة. استخدم القائمة المنسدلة **CLI** فوق الجدول للتصفية حسب CLI وكيل معين; يحافظ عنوان URL على اختيارك كـ `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. يعرض كل مشروع: - اسم المشروع (مشتق من مسار المجلد) -- شارة CLI — `Claude Code` (برتقالي)، `OpenAI Codex` (بنفسجي)، `GitHub Copilot` (أزرق)، `Cursor Agent` (زمردي)، `OpenCode` (كهرماني)، `Pi` (وردي)، `Gemini CLI` (سماوي)، و/أو `Hermes` (نيلي) +- شارة CLI — `Claude Code` (برتقالي)، `OpenAI Codex` (بنفسجي)، `GitHub Copilot` (أزرق)، `Cursor Agent` (زمردي)، `OpenCode` (كهرماني)، `Pi` (وردي)، و/أو `Hermes` (نيلي) - تاريخ آخر نشاط جلسة انقر على مشروع لمشاهدة جلساته. @@ -47,7 +47,7 @@ failproofai ### عارض الجلسة -يجيب عارض الجلسة على السؤال الأساسي للوكلاء المستقلين: ماذا فعل الوكيل، وهل بقي على المسار الصحيح؟ تشير شارة CLI بجانب الرأس إلى ما إذا كانت الجلسة نسخة Claude Code أو OpenAI Codex أو GitHub Copilot CLI أو Cursor Agent أو OpenCode أو Pi أو Gemini CLI أو Hermes. يعرض جدول زمني لكل ما حدث في جلسة: +يجيب عارض الجلسة على السؤال الأساسي للوكلاء المستقلين: ماذا فعل الوكيل، وهل بقي على المسار الصحيح؟ تشير شارة CLI بجانب الرأس إلى ما إذا كانت الجلسة نسخة Claude Code أو OpenAI Codex أو GitHub Copilot CLI أو Cursor Agent أو OpenCode أو Pi أو Hermes. يعرض جدول زمني لكل ما حدث في جلسة: - **الرسائل** - استجابات نصية من Claude ومحفزات المستخدم - **استدعاءات الأدوات** - كل أداة استدعاها Claude، مع إدخالها وإخراجها @@ -55,7 +55,7 @@ failproofai تعرض شريط الإحصائيات في الأعلى مدة الجلسة وإجمالي استدعاءات الأدوات وملخص قرارات الخطاف (عدد السماح/الرفض/التعليمات). -انقر على زر **تحميل السجلات** لتصدير الجلسة. بالنسبة لجلسات Claude Code و Codex و Copilot و Cursor و Pi و Gemini، تحصل على نص JSONL الأصلي على القرص بالكامل; بالنسبة لـ OpenCode (التي تعيش جلساتها في SQLite وليس على القرص) تحصل على وثيقة JSON تعكس جداول `session` / `messages` / `parts` الأساسية. +انقر على زر **تحميل السجلات** لتصدير الجلسة. بالنسبة لجلسات Claude Code و Codex و Copilot و Cursor و Pi، تحصل على نص JSONL الأصلي على القرص بالكامل; بالنسبة لـ OpenCode (التي تعيش جلساتها في SQLite وليس على القرص) تحصل على وثيقة JSON تعكس جداول `session` / `messages` / `parts` الأساسية. ### التدقيق @@ -75,16 +75,16 @@ failproofai - - حدد بطاقة متعددة الاختيار CLI الذي يحمي failproofai من لوحة واحدة — Claude Code و OpenAI Codex و GitHub Copilot و Cursor Agent و OpenCode و Pi و Gemini CLI و Hermes لها جميعاً صف مع حالة التثبيت (`نشط` / `مكتشف` / `غير نشط`)، مسار إعدادات نطاق المستخدم، وتمييز ملون العلامة التجارية. قم بتحديد أو إلغاء تحديد CLIs التي تريد وانقر `تطبيق التغييرات` لتثبيت/إلغاء تثبيت الفرق في خطوة واحدة. CLIs التي تم اكتشاف ملفها الثنائي على PATH يتم تحديدها مسبقاً. + - حدد بطاقة متعددة الاختيار CLI الذي يحمي failproofai من لوحة واحدة — Claude Code و OpenAI Codex و GitHub Copilot و Cursor Agent و OpenCode و Pi و Hermes لها جميعاً صف مع حالة التثبيت (`نشط` / `مكتشف` / `غير نشط`)، مسار إعدادات نطاق المستخدم، وتمييز ملون العلامة التجارية. قم بتحديد أو إلغاء تحديد CLIs التي تريد وانقر `تطبيق التغييرات` لتثبيت/إلغاء تثبيت الفرق في خطوة واحدة. CLIs التي تم اكتشاف ملفها الثنائي على PATH يتم تحديدها مسبقاً. - بدّل السياسات الفردية على أو بيقاف مع نقرة واحدة (يكتب إلى `~/.failproofai/policies-config.json` — مشترك عبر كل CLI مثبت) - قم بتوسيع سياسة لتكوين معاملات (للسياسات التي تدعم `policyParams`) - عيّن مسار ملف سياسات مخصص - السجل الكامل المقسم على صفحات لكل حدث خطاف تم تشغيله عبر جميع الجلسات - - التصفية حسب القرار ونوع الحدث و CLI (Claude Code / OpenAI Codex / GitHub Copilot _(إصدار تجريبي)_ / Cursor Agent _(إصدار تجريبي)_ / OpenCode _(إصدار تجريبي)_ / Pi _(إصدار تجريبي)_ / Gemini CLI _(إصدار تجريبي)_ / Hermes) واسم السياسة أو معرف الجلسة - - يعرض كل صف: الطابع الزمني واسم السياسة والقرار وشارة CLI (برتقالي = Claude Code، بنفسجي = OpenAI Codex، أزرق = GitHub Copilot، زمردي = Cursor Agent، كهرماني = OpenCode، وردي = Pi، سماوي = Gemini CLI، نيلي = Hermes) واسم الأداة ومعرف الجلسة وسبب قرارات الرفض/التعليمات - - انقر على معرف جلسة لفتح النص الخاص به — الكاشف التلقائي للعارض CLI الذي أطلق الخطاف (Claude `~/.claude/projects/…`، Codex `~/.codex/sessions/…`، Copilot CLI `~/.copilot/session-state//events.jsonl`، Cursor Agent `~/.cursor/agent-sessions//events.jsonl`، OpenCode `~/.local/share/opencode/opencode.db`، Pi `~/.pi/agent/sessions//.jsonl`، Gemini CLI `~/.gemini/tmp//chats/.jsonl`، Hermes `~/.hermes/state.db`) ويعرض شارة CLI المطابقة في الرأس + - التصفية حسب القرار ونوع الحدث و CLI (Claude Code / OpenAI Codex / GitHub Copilot _(إصدار تجريبي)_ / Cursor Agent _(إصدار تجريبي)_ / OpenCode _(إصدار تجريبي)_ / Pi _(إصدار تجريبي)_ / Hermes) واسم السياسة أو معرف الجلسة + - يعرض كل صف: الطابع الزمني واسم السياسة والقرار وشارة CLI (برتقالي = Claude Code، بنفسجي = OpenAI Codex، أزرق = GitHub Copilot، زمردي = Cursor Agent، كهرماني = OpenCode، وردي = Pi، نيلي = Hermes) واسم الأداة ومعرف الجلسة وسبب قرارات الرفض/التعليمات + - انقر على معرف جلسة لفتح النص الخاص به — الكاشف التلقائي للعارض CLI الذي أطلق الخطاف (Claude `~/.claude/projects/…`، Codex `~/.codex/sessions/…`، Copilot CLI `~/.copilot/session-state//events.jsonl`، Cursor Agent `~/.cursor/agent-sessions//events.jsonl`، OpenCode `~/.local/share/opencode/opencode.db`، Pi `~/.pi/agent/sessions//.jsonl`، Hermes `~/.hermes/state.db`) ويعرض شارة CLI المطابقة في الرأس diff --git a/docs/ar/getting-started.mdx b/docs/ar/getting-started.mdx index 350cf141..b917f144 100644 --- a/docs/ar/getting-started.mdx +++ b/docs/ar/getting-started.mdx @@ -38,9 +38,9 @@ bun add -g failproofai failproofai policies --install ``` - يكتب هذا إدخالات hook في أدوات الوكيل المثبتة لديك (ملف Claude Code `~/.claude/settings.json`، ملف OpenAI Codex `~/.codex/hooks.json`، ملف GitHub Copilot CLI `~/.copilot/hooks/failproofai.json`، ملف Cursor Agent `~/.cursor/hooks.json`، مكون OpenCode المولد في `~/.config/opencode/plugins/failproofai.mjs` بالإضافة إلى إدخال التسجيل في مصفوفة `plugin` في `~/.config/opencode/opencode.json`، ملف Pi `~/.pi/agent/settings.json`، ملف Gemini CLI `~/.gemini/settings.json`، أو ملف Hermes `~/.hermes/config.yaml`). عند وجود أكثر من واحد ستُطلب منك المتابعة؛ مرر `--cli claude codex copilot cursor opencode pi gemini hermes` (أي مجموعة فرعية) لتخطي الطلب. + يكتب هذا إدخالات hook في أدوات الوكيل المثبتة لديك (ملف Claude Code `~/.claude/settings.json`، ملف OpenAI Codex `~/.codex/hooks.json`، ملف GitHub Copilot CLI `~/.copilot/hooks/failproofai.json`، ملف Cursor Agent `~/.cursor/hooks.json`، مكون OpenCode المولد في `~/.config/opencode/plugins/failproofai.mjs` بالإضافة إلى إدخال التسجيل في مصفوفة `plugin` في `~/.config/opencode/opencode.json`، ملف Pi `~/.pi/agent/settings.json`، أو ملف Hermes `~/.hermes/config.yaml`). عند وجود أكثر من واحد ستُطلب منك المتابعة؛ مرر `--cli claude codex copilot cursor opencode pi hermes` (أي مجموعة فرعية) لتخطي الطلب. - دعم GitHub Copilot CLI و Cursor Agent و OpenCode و Pi و Gemini CLI موجود في مرحلة **تجريبية** — ثبّت باستخدام `--cli copilot` أو `--cli cursor` أو `--cli opencode` أو `--cli pi` أو `--cli gemini`. يثبّت Hermes (hermes-agent، بوابة Slack/Telegram) بنطاق المستخدم باستخدام `--cli hermes` وهو أيضًا **مصدر تدقيق** دون اتصال. + دعم GitHub Copilot CLI و Cursor Agent و OpenCode و Pi موجود في مرحلة **تجريبية** — ثبّت باستخدام `--cli copilot` أو `--cli cursor` أو `--cli opencode` أو `--cli pi`. يثبّت Hermes (hermes-agent، بوابة Slack/Telegram) بنطاق المستخدم باستخدام `--cli hermes` وهو أيضًا **مصدر تدقيق** دون اتصال. ```bash failproofai policies --install --scope project @@ -49,7 +49,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/ar/introduction.mdx b/docs/ar/introduction.mdx index 2475e146..f93cccce 100644 --- a/docs/ar/introduction.mdx +++ b/docs/ar/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI يوفر للوكلاء الذكيين 39 سياسة [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -الخطافات والسياسات لـ **معالجة أعطال الذكاء الاصطناعي** و **استرجاع الأخطاء** و **موثوقية نماذج اللغة الكبيرة**. حافظ على موثوقية وكلائك الذكيين والعمل بشكل مستقل عبر **Claude Code** و **OpenAI Codex** و **GitHub Copilot** و **Cursor Agent** و **OpenCode** و **Pi** و **Gemini CLI** و **Hermes** و **Agents SDK**. +الخطافات والسياسات لـ **معالجة أعطال الذكاء الاصطناعي** و **استرجاع الأخطاء** و **موثوقية نماذج اللغة الكبيرة**. حافظ على موثوقية وكلائك الذكيين والعمل بشكل مستقل عبر **Claude Code** و **OpenAI Codex** و **GitHub Copilot** و **Cursor Agent** و **OpenCode** و **Pi** و **Hermes** و **Agents SDK**. الوكلاء الذكيون يفشلون بطرق يمكن التنبؤ بها. يقومون بتنفيذ أوامر مدمرة، تسرب الأسرار، الانجراف عن المهمة الأساسية، الوقوع في حلقات، أو الدفع مباشرة إلى الفرع الرئيسي. إذا تركت دون مراقبة، فإن الأعطال الصغيرة قد تؤدي إلى انقطاعات، تسرب بيانات الاعتماد، وفقدان العمل. diff --git a/docs/built-in-policies.mdx b/docs/built-in-policies.mdx index 55093ffe..95fe24f5 100644 --- a/docs/built-in-policies.mdx +++ b/docs/built-in-policies.mdx @@ -710,7 +710,7 @@ All workflow policies are **fail-open**: if the required tool is not available ( ### Per-CLI Stop semantics -Stop enforcement looks slightly different across the seven supported CLIs because each one exposes a different "agent finished" hook contract. The **outcome** is the same — the agent doesn't get away with stopping while a workflow gate is failing — but the **mechanics** differ. The table below summarizes; only Pi has a user-visible quirk worth understanding before you enable a `require-*-before-stop` policy. +Stop enforcement looks slightly different across the six supported CLIs because each one exposes a different "agent finished" hook contract. The **outcome** is the same — the agent doesn't get away with stopping while a workflow gate is failing — but the **mechanics** differ. The table below summarizes; only Pi has a user-visible quirk worth understanding before you enable a `require-*-before-stop` policy. | CLI | When the gate fires | What you see | |---|---|---| @@ -718,20 +718,19 @@ Stop enforcement looks slightly different across the seven supported CLIs becaus | Codex | Same agent loop, immediately | Same as Claude. | | GitHub Copilot CLI | Same agent loop, immediately | Same as Claude (uses Copilot's `{decision:"block", reason}` retry channel — verified empirically against Copilot CLI 1.0.41). | | Cursor Agent | Same agent loop, immediately | Same as Claude (uses Cursor's `{followup_message}` channel — capped at `loop_limit`, default 5 retries). | -| Gemini CLI | Same agent loop, immediately | Same as Claude (uses Gemini's `{decision:"block", reason}` channel on `AfterAgent`). | | OpenCode | Same agent loop, immediately | Same as Claude (uses OpenCode's `client.session.prompt(...)` SDK call routed through `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Next user turn** | **Pi visibly stops** when the gate fires — its agent loop exits and you're returned to the prompt. The gate then fires the next time you submit a prompt: failproofai prepends a `MANDATORY ACTION REQUIRED` directive to that turn's system prompt, instructing the LLM to complete the workflow step (commit, push, etc.) before doing whatever you asked. | -**Pi limitation.** Pi's `AgentEndEvent` (the upstream equivalent of Claude's `Stop` hook) has no Result type — by the time it fires, Pi's agent loop has already exited. Pi cannot be forced to retry the same loop the way Claude / Copilot / Cursor / Gemini / OpenCode can. failproofai shifts the gate to Pi's `before_agent_start` event (which fires after the next user prompt) so the workflow check still enforces, just on the next turn rather than the current one. +**Pi limitation.** Pi's `AgentEndEvent` (the upstream equivalent of Claude's `Stop` hook) has no Result type — by the time it fires, Pi's agent loop has already exited. Pi cannot be forced to retry the same loop the way Claude / Copilot / Cursor / OpenCode can. failproofai shifts the gate to Pi's `before_agent_start` event (which fires after the next user prompt) so the workflow check still enforces, just on the next turn rather than the current one. **What this means in practice:** - After Pi stops, the deny reason is captured in-memory keyed by Pi session id. The very next prompt you submit in the same Pi process drains it: the LLM sees the `MANDATORY ACTION REQUIRED` directive at the top of its system prompt, commits (or pushes / opens the PR / waits for CI), and only then continues with your request. The captured deny reason is one-shot — once drained, the gate is clear. -- The gate is bounded by Pi's process lifetime. If you `Ctrl+C` Pi or quit between turns, the in-memory entry is dropped along with the process and the gate is missed. Claude, Copilot, Cursor, Gemini, and OpenCode have the same bound (kill the agent and the gate is missed) — Pi just makes it more visible because the agent visibly exits before the gate fires. +- The gate is bounded by Pi's process lifetime. If you `Ctrl+C` Pi or quit between turns, the in-memory entry is dropped along with the process and the gate is missed. Claude, Copilot, Cursor, and OpenCode have the same bound (kill the agent and the gate is missed) — Pi just makes it more visible because the agent visibly exits before the gate fires. - A pending deny is also cleared on `session_shutdown` for any reason (`new` / `resume` / `fork` / `quit`), so a stale gate from a prior session cannot leak into a fresh session started in the same Pi process. -If you need Claude-style same-loop retry, run your `Stop` policies under any of the other six supported CLIs. We are tracking Pi upstream for a future Result type on `AgentEndEvent` that would let us close this gap. +If you need Claude-style same-loop retry, run your `Stop` policies under any of the other five supported CLIs. We are tracking Pi upstream for a future Result type on `AgentEndEvent` that would let us close this gap. ### `require-commit-before-stop` diff --git a/docs/cli/audit.mdx b/docs/cli/audit.mdx index 6972cbcc..cc059e45 100644 --- a/docs/cli/audit.mdx +++ b/docs/cli/audit.mdx @@ -55,7 +55,7 @@ failproofai until you stop it with `Ctrl+C`. -The dashboard scans past agent CLI transcripts on this machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) and reports how often the agent did things failproofai is built to stop — env-var checks, force pushes, redundant `cd ` prefixes, sleep-polling loops, re-reading files just edited, and more. +The dashboard scans past agent CLI transcripts on this machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) and reports how often the agent did things failproofai is built to stop — env-var checks, force pushes, redundant `cd ` prefixes, sleep-polling loops, re-reading files just edited, and more. For each transcript, every tool-use event is replayed through the 39 builtin policies **and** through 8 audit-only detectors that catch patterns not yet covered by runtime policies. Counts are aggregated per policy / detector across all sessions. diff --git a/docs/configuration.mdx b/docs/configuration.mdx index b1568711..795dc884 100644 --- a/docs/configuration.mdx +++ b/docs/configuration.mdx @@ -194,15 +194,19 @@ The `policies --install` and `policies --uninstall` commands write to your agent - **Agent CLI settings** — tells the agent to call `failproofai --hook ` on each tool use: - **Claude Code**: `~/.claude/settings.json` (user), `/.claude/settings.json` (project), `/.claude/settings.local.json` (local) - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex doesn't have a `local` scope - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot has no `local` scope. Hook entries use Copilot's OS-keyed `bash`/`powershell` command fields with `timeoutSec`; the file carries a top-level `version: 1` marker. Copilot CLI support is **beta** while we verify the `events.jsonl` record schema (which the public docs do not specify) against more real-world sessions. + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot has no `local` scope. Hook entries use Copilot's OS-keyed `bash`/`powershell` command fields with `timeoutSec`; the file carries a top-level `version: 1` marker. Copilot CLI support is **beta** while we verify the `events.jsonl` record schema (which the public docs do not specify) against more real-world sessions. **VS Code Copilot Chat agent mode (Preview)** reads hook configs from `.github/hooks/*.json`, `~/.copilot/hooks/*.json`, and `~/.claude/settings.json` (governed by the `chat.hookFilesLocations` setting) using the same Claude-shaped `{hookSpecificOutput:{permissionDecision:"deny",…}}` contract — the exact paths this `copilot` integration and the `claude` integration (`~/.claude/settings.json`) already write, so `failproofai policies --install --cli copilot` (or `--cli claude`) **already enforces in VS Code agent mode** with no separate `vscode` integration needed (confirmed live from VS Code's discovery logs). - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor has no `local` scope. Hook entries use the Claude-shaped `{type, command, timeout}` form (no `bash`/`powershell` split), but stored under camelCase event keys (`preToolUse`, `beforeSubmitPrompt`, …) in a flat array per Cursor's [hooks schema](https://cursor.com/docs/hooks); the file carries a top-level `version: 1` marker. The handler canonicalizes camelCase → PascalCase via `CURSOR_EVENT_MAP` so existing built-in policies fire unchanged. Cursor Agent support is **beta** while we verify Cursor's transcript on-disk format (not specified in the public docs) against more real-world installs. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode has no `local` scope. Unlike the other six CLIs, OpenCode has **no external-command hook system**: it loads in-process JS/TS plugins explicitly registered via the `plugin: []` array in `opencode.json` (auto-discovery from `.opencode/plugins/` is **not** how plugins load on opencode v1.14.33). Install drops a small generated plugin shim that subprocess-calls the failproofai binary and translates the binary's Claude-shape JSON response back into plugin semantics: `throw new Error()` for tool-event deny (cancels the tool call), `client.session.prompt(...)` for instruct AND for `Stop` / `SubagentStop` deny (submits the deny reason as the next user message — the only force-retry channel since `session.idle` is notification-only and throwing from it is a no-op), and no-op for allow. The shim canonicalizes both tool names (lowercase → PascalCase via `OPENCODE_TOOL_MAP`) and tool-input arg keys (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` for `Read` / `Write` / `Edit`, e.g. `filePath` → `file_path`, `oldString` → `old_string`) before forwarding to the binary, so path-checking builtins like `block-read-outside-cwd`, `block-env-files`, and `block-secrets-write` fire unchanged on OpenCode tool calls. Sessions live in opencode's SQLite DB at `~/.local/share/opencode/opencode.db`; the dashboard's session viewer reads them via `opencode db --format json` and `opencode export `. OpenCode support is **beta** while we verify behavior across versions and against more real-world sessions. See the [OpenCode plugins docs](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode has no `local` scope. Unlike the other five CLIs, OpenCode has **no external-command hook system**: it loads in-process JS/TS plugins explicitly registered via the `plugin: []` array in `opencode.json` (auto-discovery from `.opencode/plugins/` is **not** how plugins load on opencode v1.14.33). Install drops a small generated plugin shim that subprocess-calls the failproofai binary and translates the binary's Claude-shape JSON response back into plugin semantics: `throw new Error()` for tool-event deny (cancels the tool call), `client.session.prompt(...)` for instruct AND for `Stop` / `SubagentStop` deny (submits the deny reason as the next user message — the only force-retry channel since `session.idle` is notification-only and throwing from it is a no-op), and no-op for allow. The shim canonicalizes both tool names (lowercase → PascalCase via `OPENCODE_TOOL_MAP`) and tool-input arg keys (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` for `Read` / `Write` / `Edit`, e.g. `filePath` → `file_path`, `oldString` → `old_string`) before forwarding to the binary, so path-checking builtins like `block-read-outside-cwd`, `block-env-files`, and `block-secrets-write` fire unchanged on OpenCode tool calls. Sessions live in opencode's SQLite DB at `~/.local/share/opencode/opencode.db`; the dashboard's session viewer reads them via `opencode db --format json` and `opencode export `. OpenCode support is **beta** while we verify behavior across versions and against more real-world sessions. See the [OpenCode plugins docs](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi has no `local` scope. Pi loads TypeScript extension packages at startup; the settings file is a flat string array `{"packages": ["./relative/path", …]}`. failproofai writes a single packages-array entry pointing at its bundled `pi-extension/` directory. The extension internally subscribes to Pi's `tool_call` / `user_bash` / `input` / `session_start` events and shells out to `failproofai --hook --cli pi`; the handler canonicalizes underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` so existing built-in policies fire unchanged. Tool input args are also canonicalized via `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit deliver `path` rather than `file_path`; mapping the top-level key lets `block-env-files` and `block-secrets-write` fire — `block-read-outside-cwd` already had a `path` fallback). Pi support is **beta** while Pi's extension API and session-log layout stabilize. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini has no `local` scope (it documents a `system` scope at `/etc/gemini-cli/settings.json` which failproofai does not expose). Hook entries use Claude's `{type, command, timeout}` form wrapped in Gemini's `{matcher, hooks: [...]}` matcher schema with `matcher: "*"` by default. Events are PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); the handler maps to Claude canonical names via `GEMINI_EVENT_MAP`. Tool names are snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — the handler canonicalizes via `GEMINI_TOOL_MAP` so existing built-in policies fire unchanged. The policy evaluator emits Gemini's flat `{decision: "deny", reason}` shape (preferred per Gemini's "Golden Rule" exit-0 contract), `{hookSpecificOutput: {hookEventName, additionalContext}}` for context injection on BeforeAgent / AfterTool / SessionStart, and `{decision: "block", reason}` on AfterAgent for force-retry semantics. Gemini CLI support is **beta** while we widen real-world coverage. See the [Gemini CLI hooks docs](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**user scope only** — Hermes has no project/local config). Hermes is a Slack/Telegram **gateway**, so one install intercepts tool calls from every platform (Slack/Telegram/cli/cron) **and** internal subagents. Hook entries are a `{command, timeout}` pair (timeout in **seconds**) under a `hooks:` map keyed by Hermes's snake_case events (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); the handler canonicalizes events via `HERMES_EVENT_MAP` and tool names via `HERMES_TOOL_MAP` so built-in policies fire unchanged. The config is edited through a comment-preserving YAML `Document` round-trip so the operator's other settings survive, and install sets `hooks_auto_accept: true` so the headless gateway (no TTY) runs the hooks without a consent prompt. The evaluator emits Hermes's `{"decision":"block","reason"}` stdout contract (Hermes ignores exit codes). **Limitations:** Hermes has no turn-end `Stop` event, so the `require-*-before-stop` builtins never fire for it (inapplicable, not broken); `instruct` degrades to allow-with-logged-note (no additional-context channel); and output-secret redaction (`sanitize-*`) can't rewrite tool output over the shell-hook contract. Hermes is **also** an offline **audit** source — the dashboard reads its gateway sessions directly from `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**user scope only** — OpenClaw has no project/local config). Like Hermes, OpenClaw is a self-hosted multi-channel **gateway**, so one install intercepts tool calls from every channel and its internal subagents. Enforcement runs through OpenClaw's **in-process plugin hooks** (its file-based internal hooks are observation-only and cannot block), so — like OpenCode/Pi — failproofai ships a static `openclaw-plugin/` package that async-spawns the failproofai binary and translates the verdict. Install registers the shipped plugin dir in `openclaw.json`'s `plugins.load.paths[]` and enables it under `plugins.entries.failproofai` (with `hooks.allowConversationAccess: true`, required for the raw-conversation hooks). The evaluator emits a flat `{permission, reason}` verdict and the shim maps it to each hook's native return shape: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), and `before_agent_finalize → {action:"revise", reason}` (**Stop** — a real turn-end gate, so the `require-*-before-stop` builtins **enforce** on OpenClaw, unlike Hermes). Events and tool names canonicalize binary-side via `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) so built-in policies fire unchanged; the shim fails open on any spawn/parse/timeout error. OpenClaw is **also** an offline **audit** source — the dashboard reads its JSONL sessions at `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (user), `/.factory/hooks.json` (project) — Factory has no `local` scope. droid ships a Claude-style external-command hook system, but with two quirks verified live against droid v0.171.0: (1) event names live at the **top level** of `hooks.json` — there is **no `"hooks"` wrapper** (droid rejects one); tool events (`PreToolUse`/`PostToolUse`) carry `"matcher": "*"`, non-tool events omit it. (2) Deny is driven by hook **exit code 2 + stderr**, not a JSON decision — the evaluator's `factory` branch returns exit 2 for tool/prompt events and `{decision:"block", reason}` only on the turn-end `Stop` event (droid's sole force-retry channel). Events are already PascalCase (no event map) and the payload is Claude snake_case; only tool names are canonicalized via `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory is **also** an offline **audit** source — the dashboard reads its on-disk JSONL sessions at `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (user), `/.devin/config.json` (project) — Devin has no `local` scope. Devin is a **pure Claude-clone** verified live against devin v3000.1.27: it uses the standard Claude `"hooks"`-wrapper schema (writes are merge-preserving so the config file's other keys — `org_id`, `theme_mode`, … — survive), already-PascalCase event names (no event map, no handler branch), and a Claude snake_case stdin payload (no normalization). The evaluator's `devin` branch denies with `{"decision":"block","reason"}` JSON on stdout at exit 0 for **every** event (verified — the block overrode `--permission-mode dangerous`); on the turn-end `Stop` event the reason carries the MANDATORY-ACTION force-retry wording so the `require-*-before-stop` builtins enforce. Only tool names are canonicalized via `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` is already canonical). Devin is **also** an offline **audit** source — the dashboard reads its SQLite sessions at `~/.local/share/devin/cli/sessions.db` (each `sessions` row carries a real `working_directory`, so sessions group by project cwd like Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (user), `/.agents/hooks.json` (project) — Antigravity has no `local` scope. Unlike Factory/Devin, Antigravity has its **own** contract (not a Claude-clone), verified live against agy v1.1.2. `hooks.json` uses a **named-hook** schema: the top-level key is a hook *name* (`"failproofai"`) whose value is an event→handlers map — tool events (`PreToolUse`/`PostToolUse`) wrap handlers in `{matcher:"*", hooks:[…]}`, while `PreInvocation`/`Stop` are **flat** handler arrays (other named hooks are preserved). The stdin payload is **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai normalizes it to snake_case before policies run, and maps `run_command`'s PascalCase args (`CommandLine`/`Cwd`) via `ANTIGRAVITY_TOOL_INPUT_MAP`. The evaluator's `antigravity` branch uses Antigravity's **own** response shapes: `{decision:"deny", reason}` blocks a tool/prompt (exit 0), `{decision:"continue", reason}` on the turn-end `Stop` re-enters the loop (so the `require-*-before-stop` builtins enforce), and `{injectSteps:[{ephemeralMessage}]}` injects an instruction on `PreInvocation` (→ `UserPromptSubmit`). Tool names canonicalize via `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity is **also** an offline **audit** source — the dashboard reads its plain-JSONL transcripts at `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (conversation index in `conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (user), `/.agents/plugins/failproofai/hooks/hooks.json` (project) — Goose has no `local` scope. Enforcement uses Goose's **hooks** system, the cross-agent **Open Plugins** spec: the installer just drops the `failproofai` plugin dir and Goose auto-discovers it at startup (self-registering it into `~/.config/goose/config.yaml`). The `hooks.json` uses an Open Plugins schema **with** a top-level `"hooks"` wrapper, and the matcher is **omitted** on every event — a bare `"*"` is an invalid regex that matches nothing (verified live against goose v1.43.0). Event names are already PascalCase (no event map); the stdin payload uses `event`/`working_dir`, which the handler normalizes to `hook_event_name`/`cwd`. The evaluator's `goose` branch denies with `{"decision":"block","reason"}` JSON on stdout at exit 0, honored on the **`PreToolUse`** event only (shipped in goose ≥ v1.37.0) — which fires for the shell tool **and inside delegated subagents**, so it is the single sufficient deny point; any other hook error fails **open**. Goose has **no `Stop` event**, so the `require-*-before-stop` builtins don't apply (as with Hermes). Tool names canonicalize via `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) and path keys via `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose is **also** an offline **audit** source — the dashboard reads its SQLite sessions at `~/.local/share/goose/sessions/sessions.db` (each `sessions` row carries a real `working_dir`, so sessions group by project cwd like Devin; `--no-session` scratch runs are filtered). - **`policies-config.json`** — tells failproofai which policies to evaluate and with what params (shared across all agent CLIs) -Pass `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` to target a specific agent (space-separated or repeated for any subset): +Pass `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` to target a specific agent (space-separated or repeated for any subset): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +214,16 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -When `--cli` is omitted, `failproofai` detects which agent CLIs are installed (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +When `--cli` is omitted, `failproofai` detects which agent CLIs are installed (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): - **One CLI detected** — auto-selects that CLI without prompting. - **Multiple CLIs detected** in an interactive terminal — shows an arrow-key single-select prompt grouped into a `Detected (N)` section (with an `Install for all N detected` aggregate row + each detected CLI individually) and a `Not installed (M) · install hooks ahead of time` section listing every undetected supported CLI as a forward-install option (↑↓ to move, Enter to select, ^C to quit). The uninstall flow shows only the Detected section. diff --git a/docs/dashboard.mdx b/docs/dashboard.mdx index a528fb40..bfdee30d 100644 --- a/docs/dashboard.mdx +++ b/docs/dashboard.mdx @@ -24,11 +24,11 @@ The dashboard reads directly from the filesystem - your Claude Code project fold ### Projects -Lists all Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, and Hermes projects found on your machine. Claude projects are discovered from `~/.claude/projects/` (or the path set by `CLAUDE_PROJECTS_PATH`); Codex projects are discovered by scanning every transcript under `~/.codex/sessions///
/*.jsonl` and grouping by the `cwd` recorded in each session's first record; Copilot CLI projects are discovered by scanning each `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) and grouping by its `cwd` field; Cursor Agent projects are discovered by scanning per-session metadata under `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, with `conversations/` and `sessions/` probed as fallbacks) for a `cwd` scalar in `meta.json` / `session.json` / `workspace.yaml`; OpenCode projects are discovered by querying its SQLite DB at `~/.local/share/opencode/opencode.db` via `opencode db --format json` (we read the `session` and `project` tables and group by `project_id`); Pi projects are discovered by scanning per-session JSONL transcripts under `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) and pulling the `cwd` from each session's first record; Gemini CLI projects are discovered by scanning `~/.gemini/tmp//chats/session--.jsonl` (configurable via `GEMINI_SESSIONS_DIR`) and recovering the canonical cwd from the sibling `.project_root` text marker; Hermes gateway sessions are read directly from its SQLite store at `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) and grouped into `hermes-` projects by `source` (Slack/Telegram/cli/cron — gateway sessions have no cwd). A project that has been used by multiple CLIs renders as a single row with all matching badges. Use the **CLI** dropdown above the table to filter by a specific agent CLI; the URL preserves your selection as `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lists all Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, and Goose projects found on your machine. Claude projects are discovered from `~/.claude/projects/` (or the path set by `CLAUDE_PROJECTS_PATH`); Codex projects are discovered by scanning every transcript under `~/.codex/sessions///
/*.jsonl` and grouping by the `cwd` recorded in each session's first record; Copilot CLI projects are discovered by scanning each `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) and grouping by its `cwd` field; Cursor Agent projects are discovered by scanning per-session metadata under `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, with `conversations/` and `sessions/` probed as fallbacks) for a `cwd` scalar in `meta.json` / `session.json` / `workspace.yaml`; OpenCode projects are discovered by querying its SQLite DB at `~/.local/share/opencode/opencode.db` via `opencode db --format json` (we read the `session` and `project` tables and group by `project_id`); Pi projects are discovered by scanning per-session JSONL transcripts under `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) and pulling the `cwd` from each session's first record; Hermes gateway sessions are read directly from its SQLite store at `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) and grouped into `hermes-` projects by `source` (Slack/Telegram/cli/cron — gateway sessions have no cwd); OpenClaw gateway sessions are read from `~/.openclaw/agents//sessions/*.jsonl` and grouped into `openclaw-` projects (also cwd-less); Factory Droid projects are discovered from the JSONL transcripts at `~/.factory/sessions//*.jsonl` and grouped by cwd; Devin projects from its SQLite DB at `~/.local/share/devin/cli/sessions.db` (grouped by each session's `working_directory`); Antigravity projects from the JSONL transcripts at `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` and grouped by cwd; and Goose projects from its SQLite DB at `~/.local/share/goose/sessions/sessions.db` (grouped by each session's `working_dir`). A project that has been used by multiple CLIs renders as a single row with all matching badges. Use the **CLI** dropdown above the table to filter by a specific agent CLI; the URL preserves your selection as `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Each project shows: - Project name (derived from the folder path) -- A CLI badge — `Claude Code` (orange), `OpenAI Codex` (purple), `GitHub Copilot` (blue), `Cursor Agent` (emerald), `OpenCode` (amber), `Pi` (pink), `Gemini CLI` (sky), and/or `Hermes` (indigo) +- A CLI badge — `Claude Code` (orange), `OpenAI Codex` (purple), `GitHub Copilot` (blue), `Cursor Agent` (emerald), `OpenCode` (amber), `Pi` (pink), and/or `Hermes` (indigo) - Date of most recent session activity Click a project to see its sessions. @@ -47,7 +47,7 @@ Click a session to open the session viewer. ### Session viewer -The session viewer answers the key question for autonomous agents: what did the agent do, and did it stay on track? A CLI badge beside the header indicates whether the session is a Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, or Hermes transcript. It shows a timeline of everything that happened in a session: +The session viewer answers the key question for autonomous agents: what did the agent do, and did it stay on track? A CLI badge beside the header indicates whether the session is a Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, or Goose transcript. It shows a timeline of everything that happened in a session: - **Messages** - Claude's text responses and user prompts - **Tool calls** - Every tool Claude invoked, with its input and output @@ -55,7 +55,7 @@ The session viewer answers the key question for autonomous agents: what did the The stats bar at the top shows session duration, total tool calls, and a summary of hook decisions (allow / deny / instruct counts). -Click the **Download Logs** button to export the session. For Claude Code, Codex, Copilot, Cursor, Pi, and Gemini sessions you get the original on-disk JSONL transcript byte-for-byte; for OpenCode (whose sessions live in SQLite, not on disk) you get a JSON document mirroring the underlying `session` / `messages` / `parts` tables. +Click the **Download Logs** button to export the session. For Claude Code, Codex, Copilot, Cursor, and Pi sessions you get the original on-disk JSONL transcript byte-for-byte; for OpenCode (whose sessions live in SQLite, not on disk) you get a JSON document mirroring the underlying `session` / `messages` / `parts` tables. ### Audit @@ -75,16 +75,16 @@ A two-tab page for managing policies and reviewing activity. - - Multi-select which agent CLIs failproofai protects from a single panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, and Hermes all have a row with install status (`Active` / `Detected` / `Inactive`), the user-scope settings path, and a brand-colored accent. Check or uncheck the CLIs you want and click `Apply changes` to install/uninstall the diff in one step. CLIs whose binary is detected on PATH are pre-checked. + - Multi-select which agent CLIs failproofai protects from a single panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, and Hermes all have a row with install status (`Active` / `Detected` / `Inactive`), the user-scope settings path, and a brand-colored accent. Check or uncheck the CLIs you want and click `Apply changes` to install/uninstall the diff in one step. CLIs whose binary is detected on PATH are pre-checked. - Toggle individual policies on or off with a single click (writes to `~/.failproofai/policies-config.json` — shared across every installed CLI) - Expand a policy to configure its parameters (for policies that support `policyParams`) - Set a custom policies file path - Full paginated history of every hook event that has fired across all sessions - - Filter by decision, event type, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), policy name, or session ID - - Each row shows: timestamp, policy name, decision, CLI badge (orange = Claude Code, purple = OpenAI Codex, blue = GitHub Copilot, emerald = Cursor Agent, amber = OpenCode, pink = Pi, sky = Gemini CLI, indigo = Hermes), tool name, session ID, and the reason for deny/instruct decisions - - Click a session ID to open its transcript — the viewer auto-detects which CLI fired the hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) and renders the matching CLI badge in the header + - Filter by decision, event type, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), policy name, or session ID + - Each row shows: timestamp, policy name, decision, CLI badge (orange = Claude Code, purple = OpenAI Codex, blue = GitHub Copilot, emerald = Cursor Agent, amber = OpenCode, pink = Pi, indigo = Hermes, teal = OpenClaw, rose = Factory Droid, violet = Devin, cyan = Antigravity, lime = Goose), tool name, session ID, and the reason for deny/instruct decisions + - Click a session ID to open its transcript — the viewer auto-detects which CLI fired the hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) and renders the matching CLI badge in the header diff --git a/docs/de/built-in-policies.mdx b/docs/de/built-in-policies.mdx index c7bbeca4..cb5e240f 100644 --- a/docs/de/built-in-policies.mdx +++ b/docs/de/built-in-policies.mdx @@ -704,7 +704,7 @@ Alle Workflow-Richtlinien sind **fail-open**: Wenn das erforderliche Tool nicht ### Stop-Semantik je CLI -Die Stop-Durchsetzung sieht bei den sieben unterstützten CLIs etwas unterschiedlich aus, da jede eine andere Vertragsgestaltung für den Hook „Agent fertig" bietet. Das **Ergebnis** ist dasselbe — der Agent kommt nicht damit durch, anzuhalten, während ein Workflow-Gate fehlschlägt — aber die **Mechanik** unterscheidet sich. Die folgende Tabelle fasst dies zusammen; nur Pi hat eine für Benutzer sichtbare Besonderheit, die Sie verstehen sollten, bevor Sie eine `require-*-before-stop`-Richtlinie aktivieren. +Die Stop-Durchsetzung sieht bei den sechs unterstützten CLIs etwas unterschiedlich aus, da jede eine andere Vertragsgestaltung für den Hook „Agent fertig" bietet. Das **Ergebnis** ist dasselbe — der Agent kommt nicht damit durch, anzuhalten, während ein Workflow-Gate fehlschlägt — aber die **Mechanik** unterscheidet sich. Die folgende Tabelle fasst dies zusammen; nur Pi hat eine für Benutzer sichtbare Besonderheit, die Sie verstehen sollten, bevor Sie eine `require-*-before-stop`-Richtlinie aktivieren. | CLI | Wann das Gate auslöst | Was Sie sehen | |---|---|---| @@ -712,20 +712,19 @@ Die Stop-Durchsetzung sieht bei den sieben unterstützten CLIs etwas unterschied | Codex | Gleiche Agentenschleife, sofort | Wie Claude. | | GitHub Copilot CLI | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Copilots `{decision:"block", reason}`-Wiederholungskanal — empirisch verifiziert gegen Copilot CLI 1.0.41). | | Cursor Agent | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Cursors `{followup_message}`-Kanal — begrenzt auf `loop_limit`, standardmäßig 5 Wiederholungen). | -| Gemini CLI | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Geminis `{decision:"block", reason}`-Kanal auf `AfterAgent`). | | OpenCode | Gleiche Agentenschleife, sofort | Wie Claude (verwendet OpenCodes `client.session.prompt(...)`-SDK-Aufruf, der über `hookSpecificOutput.additionalContext` geleitet wird). | | **Pi (pi-coding-agent)** | **Nächster Benutzerturn** | **Pi hält sichtbar an**, wenn das Gate auslöst — seine Agentenschleife beendet sich und Sie gelangen zurück zur Eingabeaufforderung. Das Gate löst dann beim nächsten Absenden einer Eingabe aus: failproofai stellt eine `MANDATORY ACTION REQUIRED`-Direktive an den Systempromt dieses Turns voran und weist das LLM an, den Workflow-Schritt (Commit, Push usw.) abzuschließen, bevor es das Gewünschte tut. | -**Pi-Einschränkung.** Pis `AgentEndEvent` (das Upstream-Äquivalent zu Claudes `Stop`-Hook) hat keinen Result-Typ — wenn er auslöst, hat Pis Agentenschleife bereits beendet. Pi kann nicht dazu gezwungen werden, dieselbe Schleife zu wiederholen, wie es Claude / Copilot / Cursor / Gemini / OpenCode können. failproofai verlagert das Gate auf Pis `before_agent_start`-Ereignis (das nach der nächsten Benutzereingabe auslöst), sodass die Workflow-Prüfung trotzdem greift, nur beim nächsten Turn statt beim aktuellen. +**Pi-Einschränkung.** Pis `AgentEndEvent` (das Upstream-Äquivalent zu Claudes `Stop`-Hook) hat keinen Result-Typ — wenn er auslöst, hat Pis Agentenschleife bereits beendet. Pi kann nicht dazu gezwungen werden, dieselbe Schleife zu wiederholen, wie es Claude / Copilot / Cursor / OpenCode können. failproofai verlagert das Gate auf Pis `before_agent_start`-Ereignis (das nach der nächsten Benutzereingabe auslöst), sodass die Workflow-Prüfung trotzdem greift, nur beim nächsten Turn statt beim aktuellen. **Was das in der Praxis bedeutet:** - Nachdem Pi anhält, wird der Ablehnungsgrund im Speicher gespeichert, indexiert nach Pi-Sitzungs-ID. Die nächste Eingabe, die Sie im selben Pi-Prozess absenden, entleert ihn: Das LLM sieht die `MANDATORY ACTION REQUIRED`-Direktive am Anfang seines Systemprompts, führt einen Commit durch (oder Push / öffnet den PR / wartet auf CI) und fährt erst dann mit Ihrer Anfrage fort. Der gespeicherte Ablehnungsgrund ist einmalig — sobald entleert, ist das Gate frei. -- Das Gate ist durch die Prozesslebensdauer von Pi begrenzt. Wenn Sie Pi zwischen den Turns mit `Ctrl+C` beenden oder schließen, wird der In-Memory-Eintrag zusammen mit dem Prozess gelöscht und das Gate wird verfehlt. Claude, Copilot, Cursor, Gemini und OpenCode haben dieselbe Einschränkung (Agent beenden und das Gate wird verfehlt) — bei Pi ist es nur sichtbarer, weil der Agent sichtbar beendet wird, bevor das Gate auslöst. +- Das Gate ist durch die Prozesslebensdauer von Pi begrenzt. Wenn Sie Pi zwischen den Turns mit `Ctrl+C` beenden oder schließen, wird der In-Memory-Eintrag zusammen mit dem Prozess gelöscht und das Gate wird verfehlt. Claude, Copilot, Cursor und OpenCode haben dieselbe Einschränkung (Agent beenden und das Gate wird verfehlt) — bei Pi ist es nur sichtbarer, weil der Agent sichtbar beendet wird, bevor das Gate auslöst. - Ein ausstehender Deny wird auch bei `session_shutdown` aus beliebigem Grund (`new` / `resume` / `fork` / `quit`) gelöscht, sodass ein veraltetes Gate einer vorherigen Sitzung nicht in eine neue Sitzung überlaufen kann, die im selben Pi-Prozess gestartet wurde. -Wenn Sie das Claude-ähnliche Wiederholen in derselben Schleife benötigen, führen Sie Ihre `Stop`-Richtlinien unter einer der anderen sechs unterstützten CLIs aus. Wir verfolgen Pi upstream auf einen zukünftigen Result-Typ bei `AgentEndEvent`, der es uns ermöglichen würde, diese Lücke zu schließen. +Wenn Sie das Claude-ähnliche Wiederholen in derselben Schleife benötigen, führen Sie Ihre `Stop`-Richtlinien unter einer der anderen fünf unterstützten CLIs aus. Wir verfolgen Pi upstream auf einen zukünftigen Result-Typ bei `AgentEndEvent`, der es uns ermöglichen würde, diese Lücke zu schließen. ### `require-commit-before-stop` diff --git a/docs/de/cli/audit.mdx b/docs/de/cli/audit.mdx index 833e1a9d..1b4d816d 100644 --- a/docs/de/cli/audit.mdx +++ b/docs/de/cli/audit.mdx @@ -54,7 +54,7 @@ failproofai bis du es mit `Ctrl+C` beendest. -Das Dashboard scannt vergangene Agent-CLI-Transkripte auf diesem Rechner (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) und meldet, wie oft der Agent Dinge getan hat, die failproofai unterbinden soll – Env-Var-Prüfungen, Force-Pushes, redundante `cd `-Präfixe, Sleep-Polling-Schleifen, erneutes Einlesen gerade bearbeiteter Dateien und mehr. +Das Dashboard scannt vergangene Agent-CLI-Transkripte auf diesem Rechner (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) und meldet, wie oft der Agent Dinge getan hat, die failproofai unterbinden soll – Env-Var-Prüfungen, Force-Pushes, redundante `cd `-Präfixe, Sleep-Polling-Schleifen, erneutes Einlesen gerade bearbeiteter Dateien und mehr. Für jedes Transkript wird jedes Tool-Use-Ereignis durch die 39 eingebauten Richtlinien **und** durch 8 Audit-exklusive Detektoren abgespielt, die Muster erkennen, die noch nicht von Laufzeit-Richtlinien abgedeckt werden. Die Zählungen werden pro Richtlinie bzw. Detektor über alle Sitzungen hinweg aggregiert. diff --git a/docs/de/configuration.mdx b/docs/de/configuration.mdx index a0b1ad6a..95dae70a 100644 --- a/docs/de/configuration.mdx +++ b/docs/de/configuration.mdx @@ -196,13 +196,12 @@ Die Befehle `policies --install` und `policies --uninstall` schreiben in die Hoo - **OpenAI Codex**: `~/.codex/hooks.json` (Benutzer), `/.codex/hooks.json` (Projekt) – Codex hat keinen `local`-Scope - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (Benutzer), `/.github/hooks/failproofai.json` (Projekt) – Copilot hat keinen `local`-Scope. Hook-Einträge verwenden Copilots betriebssystemspezifische `bash`/`powershell`-Befehlsfelder mit `timeoutSec`; die Datei enthält einen `version: 1`-Marker auf oberster Ebene. Die Unterstützung von Copilot CLI ist **beta**, während wir das `events.jsonl`-Aufzeichnungsschema (das in der öffentlichen Dokumentation nicht spezifiziert ist) anhand weiterer realer Sitzungen überprüfen. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (Benutzer), `/.cursor/hooks.json` (Projekt) – Cursor hat keinen `local`-Scope. Hook-Einträge verwenden die Claude-ähnliche `{type, command, timeout}`-Form (ohne `bash`/`powershell`-Aufteilung), werden aber unter camelCase-Ereignisschlüsseln (`preToolUse`, `beforeSubmitPrompt`, …) in einem flachen Array gemäß Cursors [Hooks-Schema](https://cursor.com/docs/hooks) gespeichert; die Datei enthält einen `version: 1`-Marker auf oberster Ebene. Der Handler kanonisiert camelCase → PascalCase über `CURSOR_EVENT_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Die Unterstützung von Cursor Agent ist **beta**, während wir Cursors On-Disk-Transkriptformat (in der öffentlichen Dokumentation nicht spezifiziert) anhand weiterer realer Installationen überprüfen. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (Benutzer), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (Projekt) – OpenCode hat keinen `local`-Scope. Im Gegensatz zu den anderen sechs CLIs verfügt OpenCode über **kein externes Befehls-Hook-System**: Es lädt In-Process-JS/TS-Plugins, die explizit über das `plugin: []`-Array in `opencode.json` registriert werden (automatische Erkennung aus `.opencode/plugins/` ist **nicht** die Art, wie Plugins in opencode v1.14.33 geladen werden). Die Installation legt ein kleines generiertes Plugin-Shim ab, das den failproofai-Binary als Subprozess aufruft und die JSON-Antwort im Claude-Format des Binaries zurück in Plugin-Semantik übersetzt: `throw new Error()` für tool-event deny (bricht den Tool-Aufruf ab), `client.session.prompt(...)` für instruct UND für `Stop` / `SubagentStop` deny (reicht den Ablehnungsgrund als nächste Benutzernachricht ein – der einzige Force-Retry-Kanal, da `session.idle` nur eine Benachrichtigung ist und das Werfen einer Exception dort ein No-op ist), und No-op für allow. Das Shim kanonisiert sowohl Tool-Namen (Kleinbuchstaben → PascalCase über `OPENCODE_TOOL_MAP`) als auch Tool-Input-Argumentschlüssel (camelCase → snake_case über `OPENCODE_TOOL_INPUT_MAP` für `Read` / `Write` / `Edit`, z. B. `filePath` → `file_path`, `oldString` → `old_string`), bevor es an das Binary weiterleitet, sodass pfadprüfende Builtins wie `block-read-outside-cwd`, `block-env-files` und `block-secrets-write` bei OpenCode-Tool-Aufrufen unverändert ausgelöst werden. Sitzungen werden in OpenCodes SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` gespeichert; der Session-Viewer des Dashboards liest sie über `opencode db --format json` und `opencode export `. Die OpenCode-Unterstützung ist **beta**, während wir das Verhalten versionsübergreifend und anhand weiterer realer Sitzungen überprüfen. Siehe die [OpenCode-Plugin-Dokumentation](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (Benutzer), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (Projekt) – OpenCode hat keinen `local`-Scope. Im Gegensatz zu den anderen fünf CLIs verfügt OpenCode über **kein externes Befehls-Hook-System**: Es lädt In-Process-JS/TS-Plugins, die explizit über das `plugin: []`-Array in `opencode.json` registriert werden (automatische Erkennung aus `.opencode/plugins/` ist **nicht** die Art, wie Plugins in opencode v1.14.33 geladen werden). Die Installation legt ein kleines generiertes Plugin-Shim ab, das den failproofai-Binary als Subprozess aufruft und die JSON-Antwort im Claude-Format des Binaries zurück in Plugin-Semantik übersetzt: `throw new Error()` für tool-event deny (bricht den Tool-Aufruf ab), `client.session.prompt(...)` für instruct UND für `Stop` / `SubagentStop` deny (reicht den Ablehnungsgrund als nächste Benutzernachricht ein – der einzige Force-Retry-Kanal, da `session.idle` nur eine Benachrichtigung ist und das Werfen einer Exception dort ein No-op ist), und No-op für allow. Das Shim kanonisiert sowohl Tool-Namen (Kleinbuchstaben → PascalCase über `OPENCODE_TOOL_MAP`) als auch Tool-Input-Argumentschlüssel (camelCase → snake_case über `OPENCODE_TOOL_INPUT_MAP` für `Read` / `Write` / `Edit`, z. B. `filePath` → `file_path`, `oldString` → `old_string`), bevor es an das Binary weiterleitet, sodass pfadprüfende Builtins wie `block-read-outside-cwd`, `block-env-files` und `block-secrets-write` bei OpenCode-Tool-Aufrufen unverändert ausgelöst werden. Sitzungen werden in OpenCodes SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` gespeichert; der Session-Viewer des Dashboards liest sie über `opencode db --format json` und `opencode export `. Die OpenCode-Unterstützung ist **beta**, während wir das Verhalten versionsübergreifend und anhand weiterer realer Sitzungen überprüfen. Siehe die [OpenCode-Plugin-Dokumentation](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (Benutzer), `/.pi/settings.json` (Projekt) – Pi hat keinen `local`-Scope. Pi lädt TypeScript-Erweiterungspakete beim Start; die Einstellungsdatei ist ein flaches String-Array `{"packages": ["./relative/path", …]}`. failproofai schreibt einen einzelnen packages-Array-Eintrag, der auf sein gebündeltes `pi-extension/`-Verzeichnis zeigt. Die Erweiterung abonniert intern Pis `tool_call` / `user_bash` / `input` / `session_start`-Ereignisse und ruft `failproofai --hook --cli pi` als Shell-Befehl auf; der Handler kanonisiert Ereignisse über `PI_EVENT_MAP` von underscore_lower_snake_case → PascalCase, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Tool-Input-Argumente werden ebenfalls über `PI_TOOL_INPUT_MAP` kanonisiert (Pis Read / Write / Edit liefern `path` statt `file_path`; die Zuordnung des obersten Schlüssels lässt `block-env-files` und `block-secrets-write` auslösen – `block-read-outside-cwd` hatte bereits einen `path`-Fallback). Die Pi-Unterstützung ist **beta**, während sich Pis Erweiterungs-API und das Sitzungslog-Layout stabilisieren. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (Benutzer), `/.gemini/settings.json` (Projekt) – Gemini hat keinen `local`-Scope (es dokumentiert einen `system`-Scope unter `/etc/gemini-cli/settings.json`, den failproofai nicht verfügbar macht). Hook-Einträge verwenden Claudes `{type, command, timeout}`-Form, eingebettet in Geminis `{matcher, hooks: [...]}`-Matcher-Schema mit standardmäßig `matcher: "*"`. Ereignisse sind PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); der Handler ordnet sie über `GEMINI_EVENT_MAP` kanonischen Claude-Namen zu. Tool-Namen sind snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) – der Handler kanonisiert über `GEMINI_TOOL_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Der Richtlinienauswerter gibt Geminis flache `{decision: "deny", reason}`-Form aus (bevorzugt gemäß Geminis „Goldener Regel" exit-0-Vertrag), `{hookSpecificOutput: {hookEventName, additionalContext}}` für Kontext-Injection bei BeforeAgent / AfterTool / SessionStart, und `{decision: "block", reason}` bei AfterAgent für Force-Retry-Semantik. Die Gemini CLI-Unterstützung ist **beta**, während wir die reale Abdeckung ausweiten. Siehe die [Gemini CLI Hooks-Dokumentation](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**nur Benutzer-Scope** – Hermes hat keine Projekt-/lokale Konfiguration). Hermes ist ein Slack/Telegram-**Gateway**, daher fängt eine Installation Tool-Aufrufe von jeder Plattform (Slack/Telegram/cli/cron) **und** internen Subagenten ab. Hook-Einträge sind ein `{command, timeout}`-Paar (Timeout in **Sekunden**) unter einem `hooks:`-Map, der nach Hermes' snake_case-Ereignissen (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) geordnet ist; der Handler kanonisiert Ereignisse über `HERMES_EVENT_MAP` und Tool-Namen über `HERMES_TOOL_MAP`, sodass integrierte Richtlinien unverändert ausgelöst werden. Die Konfiguration wird durch einen kommentarerhaltenden YAML-`Document`-Round-trip bearbeitet, sodass die anderen Einstellungen des Betreibers erhalten bleiben, und die Installation setzt `hooks_auto_accept: true`, sodass das kopflose Gateway (kein TTY) die Hooks ohne Zustimmungsaufforderung ausführt. Der Auswerter gibt Hermes' stdout-Vertrag `{"decision":"block","reason"}` aus (Hermes ignoriert Exit-Codes). **Einschränkungen:** Hermes hat kein turn-end-`Stop`-Ereignis, daher werden die `require-*-before-stop`-Builtins für Hermes nie ausgelöst (nicht anwendbar, nicht defekt); `instruct` wird zu allow-with-logged-note herabgestuft (kein additional-context-Kanal); und Output-Secret-Redaktion (`sanitize-*`) kann Tool-Output über den Shell-Hook-Vertrag nicht umschreiben. Hermes ist **auch** eine Offline-**Audit**-Quelle – das Dashboard liest seine Gateway-Sitzungen direkt aus `~/.hermes/state.db`. - **`policies-config.json`** – teilt failproofai mit, welche Richtlinien ausgewertet werden sollen und mit welchen Parametern (geteilt über alle Agenten-CLIs) -Übergeben Sie `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes`, um einen bestimmten Agenten anzusprechen (durch Leerzeichen getrennt oder wiederholt für eine beliebige Teilmenge): +Übergeben Sie `--cli claude|codex|copilot|cursor|opencode|pi|hermes`, um einen bestimmten Agenten anzusprechen (durch Leerzeichen getrennt oder wiederholt für eine beliebige Teilmenge): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Wenn `--cli` weggelassen wird, erkennt `failproofai` automatisch, welche Agenten-CLIs installiert sind (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Wenn `--cli` weggelassen wird, erkennt `failproofai` automatisch, welche Agenten-CLIs installiert sind (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Eine CLI erkannt** – wählt diese CLI automatisch ohne Rückfrage aus. - **Mehrere CLIs erkannt** in einem interaktiven Terminal – zeigt eine Einzelauswahl-Eingabeaufforderung mit Pfeiltasten an, die in einen Abschnitt `Erkannt (N)` (mit einer `Für alle N erkannten installieren`-Sammelzeile + jeder erkannten CLI einzeln) und einen Abschnitt `Nicht installiert (M) · Hooks vorab installieren` unterteilt ist, der alle nicht erkannten unterstützten CLIs als Vorwärts-Installationsoption auflistet (↑↓ zum Bewegen, Enter zum Auswählen, ^C zum Beenden). Der Deinstallationsablauf zeigt nur den Abschnitt „Erkannt" an. diff --git a/docs/de/dashboard.mdx b/docs/de/dashboard.mdx index 610aaa73..9f8069d2 100644 --- a/docs/de/dashboard.mdx +++ b/docs/de/dashboard.mdx @@ -24,11 +24,11 @@ Das Dashboard liest direkt vom Dateisystem – aus Ihren Claude Code-Projektordn ### Projekte -Listet alle Claude Code-, OpenAI Codex-, GitHub Copilot CLI- _(Beta)_, Cursor Agent- _(Beta)_, OpenCode- _(Beta)_, Pi- _(Beta)_, Gemini CLI- _(Beta)_ und Hermes-Projekte auf, die auf Ihrem Rechner gefunden wurden. Claude-Projekte werden aus `~/.claude/projects/` erkannt (oder dem über `CLAUDE_PROJECTS_PATH` festgelegten Pfad); Codex-Projekte werden durch Scannen aller Transkripte unter `~/.codex/sessions///
/*.jsonl` ermittelt und nach dem `cwd` des ersten Eintrags jeder Sitzung gruppiert; Copilot CLI-Projekte werden durch Scannen von `~/.copilot/session-state//workspace.yaml` (konfigurierbar über `COPILOT_HOME`) und Gruppierung nach dem dortigen `cwd`-Feld erkannt; Cursor Agent-Projekte werden durch Scannen der sitzungsspezifischen Metadaten unter `~/.cursor/agent-sessions//` (konfigurierbar über `CURSOR_HOME`, mit `conversations/` und `sessions/` als Fallbacks) nach einem `cwd`-Skalar in `meta.json` / `session.json` / `workspace.yaml` erkannt; OpenCode-Projekte werden durch Abfrage der SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` via `opencode db --format json` ermittelt (dabei werden die Tabellen `session` und `project` gelesen und nach `project_id` gruppiert); Pi-Projekte werden durch Scannen von sitzungsspezifischen JSONL-Transkripten unter `~/.pi/agent/sessions//_.jsonl` (konfigurierbar über `PI_SESSIONS_DIR`) und Auslesen des `cwd` aus dem ersten Eintrag jeder Sitzung erkannt; Gemini CLI-Projekte werden durch Scannen von `~/.gemini/tmp//chats/session--.jsonl` (konfigurierbar über `GEMINI_SESSIONS_DIR`) und Rückgewinnung des kanonischen cwd aus dem benachbarten `.project_root`-Textmarker erkannt; Hermes-Gateway-Sitzungen werden direkt aus dem SQLite-Store unter `~/.hermes/state.db` (konfigurierbar über `HERMES_DB_PATH`) gelesen und nach `source` (Slack/Telegram/cli/cron — Gateway-Sitzungen haben kein cwd) in `hermes-`-Projekte gruppiert. Ein Projekt, das von mehreren CLIs genutzt wurde, wird als einzelne Zeile mit allen zugehörigen Badges angezeigt. Verwenden Sie das **CLI**-Dropdown über der Tabelle, um nach einer bestimmten Agenten-CLI zu filtern; die URL speichert Ihre Auswahl als `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Listet alle Claude Code-, OpenAI Codex-, GitHub Copilot CLI- _(Beta)_, Cursor Agent- _(Beta)_, OpenCode- _(Beta)_, Pi- _(Beta)_ und Hermes-Projekte auf, die auf Ihrem Rechner gefunden wurden. Claude-Projekte werden aus `~/.claude/projects/` erkannt (oder dem über `CLAUDE_PROJECTS_PATH` festgelegten Pfad); Codex-Projekte werden durch Scannen aller Transkripte unter `~/.codex/sessions///
/*.jsonl` ermittelt und nach dem `cwd` des ersten Eintrags jeder Sitzung gruppiert; Copilot CLI-Projekte werden durch Scannen von `~/.copilot/session-state//workspace.yaml` (konfigurierbar über `COPILOT_HOME`) und Gruppierung nach dem dortigen `cwd`-Feld erkannt; Cursor Agent-Projekte werden durch Scannen der sitzungsspezifischen Metadaten unter `~/.cursor/agent-sessions//` (konfigurierbar über `CURSOR_HOME`, mit `conversations/` und `sessions/` als Fallbacks) nach einem `cwd`-Skalar in `meta.json` / `session.json` / `workspace.yaml` erkannt; OpenCode-Projekte werden durch Abfrage der SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` via `opencode db --format json` ermittelt (dabei werden die Tabellen `session` und `project` gelesen und nach `project_id` gruppiert); Pi-Projekte werden durch Scannen von sitzungsspezifischen JSONL-Transkripten unter `~/.pi/agent/sessions//_.jsonl` (konfigurierbar über `PI_SESSIONS_DIR`) und Auslesen des `cwd` aus dem ersten Eintrag jeder Sitzung erkannt; Hermes-Gateway-Sitzungen werden direkt aus dem SQLite-Store unter `~/.hermes/state.db` (konfigurierbar über `HERMES_DB_PATH`) gelesen und nach `source` (Slack/Telegram/cli/cron — Gateway-Sitzungen haben kein cwd) in `hermes-`-Projekte gruppiert. Ein Projekt, das von mehreren CLIs genutzt wurde, wird als einzelne Zeile mit allen zugehörigen Badges angezeigt. Verwenden Sie das **CLI**-Dropdown über der Tabelle, um nach einer bestimmten Agenten-CLI zu filtern; die URL speichert Ihre Auswahl als `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Jedes Projekt zeigt: - Projektname (abgeleitet vom Ordnerpfad) -- Ein CLI-Badge — `Claude Code` (orange), `OpenAI Codex` (lila), `GitHub Copilot` (blau), `Cursor Agent` (smaragd), `OpenCode` (bernstein), `Pi` (pink), `Gemini CLI` (himmelblau) und/oder `Hermes` (indigo) +- Ein CLI-Badge — `Claude Code` (orange), `OpenAI Codex` (lila), `GitHub Copilot` (blau), `Cursor Agent` (smaragd), `OpenCode` (bernstein), `Pi` (pink) und/oder `Hermes` (indigo) - Datum der letzten Sitzungsaktivität Klicken Sie auf ein Projekt, um dessen Sitzungen anzuzeigen. @@ -47,7 +47,7 @@ Klicken Sie auf eine Sitzung, um den Sitzungsviewer zu öffnen. ### Sitzungsviewer -Der Sitzungsviewer beantwortet die zentrale Frage bei autonomen Agenten: Was hat der Agent getan, und ist er auf Kurs geblieben? Ein CLI-Badge neben der Überschrift zeigt an, ob es sich um ein Claude Code-, OpenAI Codex-, GitHub Copilot CLI-, Cursor Agent-, OpenCode-, Pi-, Gemini CLI- oder Hermes-Transkript handelt. Er zeigt eine Zeitleiste aller Ereignisse einer Sitzung: +Der Sitzungsviewer beantwortet die zentrale Frage bei autonomen Agenten: Was hat der Agent getan, und ist er auf Kurs geblieben? Ein CLI-Badge neben der Überschrift zeigt an, ob es sich um ein Claude Code-, OpenAI Codex-, GitHub Copilot CLI-, Cursor Agent-, OpenCode-, Pi- oder Hermes-Transkript handelt. Er zeigt eine Zeitleiste aller Ereignisse einer Sitzung: - **Nachrichten** – Claudes Textantworten und Benutzeranfragen - **Tool-Aufrufe** – Jedes von Claude aufgerufene Tool mit Ein- und Ausgabe @@ -55,7 +55,7 @@ Der Sitzungsviewer beantwortet die zentrale Frage bei autonomen Agenten: Was hat Die Statistikleiste oben zeigt Sitzungsdauer, Gesamtzahl der Tool-Aufrufe und eine Zusammenfassung der Hook-Entscheidungen (allow / deny / instruct-Anzahl). -Klicken Sie auf **Logs herunterladen**, um die Sitzung zu exportieren. Für Claude Code-, Codex-, Copilot-, Cursor-, Pi- und Gemini-Sitzungen erhalten Sie das originale JSONL-Transkript vom Datenträger byte-genau; für OpenCode (dessen Sitzungen in SQLite und nicht auf dem Datenträger gespeichert sind) erhalten Sie ein JSON-Dokument, das die zugrundeliegenden Tabellen `session` / `messages` / `parts` widerspiegelt. +Klicken Sie auf **Logs herunterladen**, um die Sitzung zu exportieren. Für Claude Code-, Codex-, Copilot-, Cursor- und Pi-Sitzungen erhalten Sie das originale JSONL-Transkript vom Datenträger byte-genau; für OpenCode (dessen Sitzungen in SQLite und nicht auf dem Datenträger gespeichert sind) erhalten Sie ein JSON-Dokument, das die zugrundeliegenden Tabellen `session` / `messages` / `parts` widerspiegelt. ### Audit @@ -75,16 +75,16 @@ Eine zweiseitige Seite zur Verwaltung von Richtlinien und Überprüfung der Akti - - Wählen Sie in einem einzelnen Panel aus, welche Agenten-CLIs failproofai schützt — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI und Hermes haben jeweils eine Zeile mit Installationsstatus (`Active` / `Detected` / `Inactive`), dem benutzerbereichs-spezifischen Einstellungspfad und einem markenfarbigen Akzent. Aktivieren oder deaktivieren Sie die gewünschten CLIs und klicken Sie auf `Apply changes`, um die Änderungen in einem Schritt zu installieren/deinstallieren. CLIs, deren Binärdatei im PATH erkannt wird, sind vorab aktiviert. + - Wählen Sie in einem einzelnen Panel aus, welche Agenten-CLIs failproofai schützt — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi und Hermes haben jeweils eine Zeile mit Installationsstatus (`Active` / `Detected` / `Inactive`), dem benutzerbereichs-spezifischen Einstellungspfad und einem markenfarbigen Akzent. Aktivieren oder deaktivieren Sie die gewünschten CLIs und klicken Sie auf `Apply changes`, um die Änderungen in einem Schritt zu installieren/deinstallieren. CLIs, deren Binärdatei im PATH erkannt wird, sind vorab aktiviert. - Aktivieren oder deaktivieren Sie einzelne Richtlinien mit einem einzigen Klick (schreibt in `~/.failproofai/policies-config.json` — gemeinsam genutzt von allen installierten CLIs) - Erweitern Sie eine Richtlinie, um ihre Parameter zu konfigurieren (für Richtlinien, die `policyParams` unterstützen) - Legen Sie einen benutzerdefinierten Richtliniendateipfad fest - Vollständige paginierte Historie aller Hook-Ereignisse, die in allen Sitzungen ausgelöst wurden - - Filtern nach Entscheidung, Ereignistyp, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(Beta)_ / Cursor Agent _(Beta)_ / OpenCode _(Beta)_ / Pi _(Beta)_ / Gemini CLI _(Beta)_ / Hermes), Richtlinienname oder Sitzungs-ID - - Jede Zeile zeigt: Zeitstempel, Richtlinienname, Entscheidung, CLI-Badge (orange = Claude Code, lila = OpenAI Codex, blau = GitHub Copilot, smaragd = Cursor Agent, bernstein = OpenCode, pink = Pi, himmelblau = Gemini CLI, indigo = Hermes), Tool-Name, Sitzungs-ID und den Grund für deny/instruct-Entscheidungen - - Klicken Sie auf eine Sitzungs-ID, um das zugehörige Transkript zu öffnen — der Viewer erkennt automatisch, welche CLI den Hook ausgelöst hat (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) und zeigt das passende CLI-Badge in der Überschrift an + - Filtern nach Entscheidung, Ereignistyp, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(Beta)_ / Cursor Agent _(Beta)_ / OpenCode _(Beta)_ / Pi _(Beta)_ / Hermes), Richtlinienname oder Sitzungs-ID + - Jede Zeile zeigt: Zeitstempel, Richtlinienname, Entscheidung, CLI-Badge (orange = Claude Code, lila = OpenAI Codex, blau = GitHub Copilot, smaragd = Cursor Agent, bernstein = OpenCode, pink = Pi, indigo = Hermes), Tool-Name, Sitzungs-ID und den Grund für deny/instruct-Entscheidungen + - Klicken Sie auf eine Sitzungs-ID, um das zugehörige Transkript zu öffnen — der Viewer erkennt automatisch, welche CLI den Hook ausgelöst hat (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) und zeigt das passende CLI-Badge in der Überschrift an diff --git a/docs/de/getting-started.mdx b/docs/de/getting-started.mdx index 4499b6f3..ca314e92 100644 --- a/docs/de/getting-started.mdx +++ b/docs/de/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Damit werden Hook-Einträge in die installierten Agenten-CLIs geschrieben (Claude Codes `~/.claude/settings.json`, OpenAI Codex' `~/.codex/hooks.json`, GitHub Copilot CLIs `~/.copilot/hooks/failproofai.json`, Cursor Agents `~/.cursor/hooks.json`, OpenCodes generiertem Plugin-Shim unter `~/.config/opencode/plugins/failproofai.mjs` sowie einem Registrierungseintrag im `plugin`-Array von `~/.config/opencode/opencode.json`, Pis `~/.pi/agent/settings.json`, Gemini CLIs `~/.gemini/settings.json` oder Hermes' `~/.hermes/config.yaml`). Sind mehrere installiert, wirst du zur Auswahl aufgefordert; übergib `--cli claude codex copilot cursor opencode pi gemini hermes` (beliebige Teilmenge), um die Abfrage zu überspringen. + Damit werden Hook-Einträge in die installierten Agenten-CLIs geschrieben (Claude Codes `~/.claude/settings.json`, OpenAI Codex' `~/.codex/hooks.json`, GitHub Copilot CLIs `~/.copilot/hooks/failproofai.json`, Cursor Agents `~/.cursor/hooks.json`, OpenCodes generiertem Plugin-Shim unter `~/.config/opencode/plugins/failproofai.mjs` sowie einem Registrierungseintrag im `plugin`-Array von `~/.config/opencode/opencode.json`, Pis `~/.pi/agent/settings.json` oder Hermes' `~/.hermes/config.yaml`). Sind mehrere installiert, wirst du zur Auswahl aufgefordert; übergib `--cli claude codex copilot cursor opencode pi hermes` (beliebige Teilmenge), um die Abfrage zu überspringen. - Unterstützung für GitHub Copilot CLI, Cursor Agent, OpenCode, Pi und Gemini CLI ist **Beta** – Installation mit `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` oder `--cli gemini`. Hermes (hermes-agent, ein Slack/Telegram-Gateway) wird im Benutzerbereich mit `--cli hermes` installiert und ist **ebenfalls** eine Offline-Auditquelle. + Unterstützung für GitHub Copilot CLI, Cursor Agent, OpenCode und Pi ist **Beta** – Installation mit `--cli copilot`, `--cli cursor`, `--cli opencode` oder `--cli pi`. Hermes (hermes-agent, ein Slack/Telegram-Gateway) wird im Benutzerbereich mit `--cli hermes` installiert und ist **ebenfalls** eine Offline-Auditquelle. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/de/introduction.mdx b/docs/de/introduction.mdx index c0c06daa..1ed93753 100644 --- a/docs/de/introduction.mdx +++ b/docs/de/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI gibt KI-Agenten 39 integrierte Fehlerrichtlinien, die [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks und Richtlinien für **KI-Fehlerbehandlung**, **Fehlerbehebung** und **LLM-Zuverlässigkeit**. Halten Sie Ihre KI-Agenten zuverlässig und autonom am Laufen – für **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** und das **Agents SDK**. +Hooks und Richtlinien für **KI-Fehlerbehandlung**, **Fehlerbehebung** und **LLM-Zuverlässigkeit**. Halten Sie Ihre KI-Agenten zuverlässig und autonom am Laufen – für **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** und das **Agents SDK**. KI-Agenten scheitern auf vorhersehbare Weisen. Sie führen destruktive Befehle aus, geben Secrets preis, weichen von ihrer Aufgabe ab, stecken in Schleifen fest oder pushen direkt in den main-Branch. Werden diese Fehler nicht behoben, können kleine Probleme zu Ausfällen, geleakten Zugangsdaten und verlorenem Code führen. diff --git a/docs/es/built-in-policies.mdx b/docs/es/built-in-policies.mdx index 5644f1c6..67e4b297 100644 --- a/docs/es/built-in-policies.mdx +++ b/docs/es/built-in-policies.mdx @@ -710,7 +710,7 @@ Todas las políticas de flujo de trabajo son **fail-open**: si la herramienta re ### Semántica de Stop por CLI -La aplicación del Stop se ve ligeramente diferente entre los siete CLIs compatibles porque cada uno expone un contrato de hook distinto para "el agente ha terminado". El **resultado** es el mismo — el agente no puede detenerse mientras una condición de flujo de trabajo esté fallando — pero los **mecanismos** difieren. La tabla a continuación resume esto; solo Pi tiene un comportamiento visible para el usuario que vale la pena entender antes de habilitar una política `require-*-before-stop`. +La aplicación del Stop se ve ligeramente diferente entre los seis CLIs compatibles porque cada uno expone un contrato de hook distinto para "el agente ha terminado". El **resultado** es el mismo — el agente no puede detenerse mientras una condición de flujo de trabajo esté fallando — pero los **mecanismos** difieren. La tabla a continuación resume esto; solo Pi tiene un comportamiento visible para el usuario que vale la pena entender antes de habilitar una política `require-*-before-stop`. | CLI | Cuándo se activa la condición | Lo que ves | |---|---|---| @@ -718,20 +718,19 @@ La aplicación del Stop se ve ligeramente diferente entre los siete CLIs compati | Codex | En el mismo bucle del agente, inmediatamente | Igual que Claude. | | GitHub Copilot CLI | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal de reintento `{decision:"block", reason}` de Copilot — verificado empíricamente contra Copilot CLI 1.0.41). | | Cursor Agent | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal `{followup_message}` de Cursor — limitado a `loop_limit`, por defecto 5 reintentos). | -| Gemini CLI | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal `{decision:"block", reason}` de Gemini en `AfterAgent`). | | OpenCode | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa la llamada SDK `client.session.prompt(...)` de OpenCode enrutada a través de `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **En el siguiente turno del usuario** | **Pi se detiene visiblemente** cuando se activa la condición — su bucle de agente termina y se te devuelve el prompt. La condición se activa la próxima vez que envíes un prompt: failproofai antepone una directiva `MANDATORY ACTION REQUIRED` al system prompt de ese turno, instruyendo al LLM a completar el paso del flujo de trabajo (commit, push, etc.) antes de hacer lo que pediste. | -**Limitación de Pi.** El `AgentEndEvent` de Pi (el equivalente upstream del hook `Stop` de Claude) no tiene tipo Result — para cuando se activa, el bucle del agente de Pi ya ha terminado. Pi no puede ser forzado a reintentar el mismo bucle como Claude / Copilot / Cursor / Gemini / OpenCode. failproofai traslada la condición al evento `before_agent_start` de Pi (que se activa después del siguiente prompt del usuario) para que la comprobación del flujo de trabajo siga siendo efectiva, solo en el siguiente turno en lugar del actual. +**Limitación de Pi.** El `AgentEndEvent` de Pi (el equivalente upstream del hook `Stop` de Claude) no tiene tipo Result — para cuando se activa, el bucle del agente de Pi ya ha terminado. Pi no puede ser forzado a reintentar el mismo bucle como Claude / Copilot / Cursor / OpenCode. failproofai traslada la condición al evento `before_agent_start` de Pi (que se activa después del siguiente prompt del usuario) para que la comprobación del flujo de trabajo siga siendo efectiva, solo en el siguiente turno en lugar del actual. **Lo que esto significa en la práctica:** - Después de que Pi se detenga, el motivo de la denegación se captura en memoria indexado por el id de sesión de Pi. El siguiente prompt que envíes en el mismo proceso de Pi lo drena: el LLM ve la directiva `MANDATORY ACTION REQUIRED` al inicio de su system prompt, hace el commit (o push / abre el PR / espera a CI), y solo entonces continúa con tu solicitud. El motivo de denegación capturado es de un solo uso — una vez drenado, la condición queda libre. -- La condición está limitada por el tiempo de vida del proceso de Pi. Si haces `Ctrl+C` en Pi o sales entre turnos, la entrada en memoria se descarta junto con el proceso y la condición se pierde. Claude, Copilot, Cursor, Gemini y OpenCode tienen el mismo límite (matar el agente hace que se pierda la condición) — Pi simplemente lo hace más visible porque el agente termina visiblemente antes de que se active la condición. +- La condición está limitada por el tiempo de vida del proceso de Pi. Si haces `Ctrl+C` en Pi o sales entre turnos, la entrada en memoria se descarta junto con el proceso y la condición se pierde. Claude, Copilot, Cursor y OpenCode tienen el mismo límite (matar el agente hace que se pierda la condición) — Pi simplemente lo hace más visible porque el agente termina visiblemente antes de que se active la condición. - Una denegación pendiente también se limpia en `session_shutdown` por cualquier motivo (`new` / `resume` / `fork` / `quit`), de modo que una condición obsoleta de una sesión anterior no puede filtrarse a una sesión nueva iniciada en el mismo proceso de Pi. -Si necesitas el reintento en el mismo bucle al estilo Claude, ejecuta tus políticas de `Stop` bajo cualquiera de los otros seis CLIs compatibles. Estamos siguiendo Pi upstream para un futuro tipo Result en `AgentEndEvent` que nos permitiría cerrar esta brecha. +Si necesitas el reintento en el mismo bucle al estilo Claude, ejecuta tus políticas de `Stop` bajo cualquiera de los otros cinco CLIs compatibles. Estamos siguiendo Pi upstream para un futuro tipo Result en `AgentEndEvent` que nos permitiría cerrar esta brecha. ### `require-commit-before-stop` diff --git a/docs/es/cli/audit.mdx b/docs/es/cli/audit.mdx index 0694d437..33aa661d 100644 --- a/docs/es/cli/audit.mdx +++ b/docs/es/cli/audit.mdx @@ -52,7 +52,7 @@ failproofai sin conexión** — no requiere cuenta ni red — y el panel sigue activo hasta que lo detengas con `Ctrl+C`. -El panel analiza las transcripciones pasadas del agente CLI en esta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e informa con qué frecuencia el agente hizo cosas que failproofai está diseñado para detener — comprobaciones de variables de entorno, push forzados, prefijos `cd ` redundantes, bucles de sleep-polling, releer archivos recién editados y más. +El panel analiza las transcripciones pasadas del agente CLI en esta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e informa con qué frecuencia el agente hizo cosas que failproofai está diseñado para detener — comprobaciones de variables de entorno, push forzados, prefijos `cd ` redundantes, bucles de sleep-polling, releer archivos recién editados y más. Por cada transcripción, cada evento de uso de herramienta se reproduce a través de las 39 políticas integradas **y** a través de 8 detectores exclusivos de auditoría que capturan patrones que aún no están cubiertos por las políticas en tiempo real. Los recuentos se agregan por política / detector en todas las sesiones. diff --git a/docs/es/configuration.mdx b/docs/es/configuration.mdx index 591ada62..47c4236c 100644 --- a/docs/es/configuration.mdx +++ b/docs/es/configuration.mdx @@ -196,13 +196,12 @@ Los comandos `policies --install` y `policies --uninstall` escriben en el archiv - **OpenAI Codex**: `~/.codex/hooks.json` (usuario), `/.codex/hooks.json` (proyecto) — Codex no tiene ámbito `local` - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuario), `/.github/hooks/failproofai.json` (proyecto) — Copilot no tiene ámbito `local`. Las entradas de hook usan los campos de comando `bash`/`powershell` de Copilot según el sistema operativo con `timeoutSec`; el archivo lleva un marcador `version: 1` de nivel superior. El soporte de Copilot CLI está en **beta** mientras verificamos el esquema de registros `events.jsonl` (que la documentación pública no especifica) con más sesiones reales. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuario), `/.cursor/hooks.json` (proyecto) — Cursor no tiene ámbito `local`. Las entradas de hook usan la forma de Claude `{type, command, timeout}` (sin división `bash`/`powershell`), pero almacenadas bajo claves de evento en camelCase (`preToolUse`, `beforeSubmitPrompt`, …) en un array plano según el [esquema de hooks de Cursor](https://cursor.com/docs/hooks); el archivo lleva un marcador `version: 1` de nivel superior. El manejador canonicaliza camelCase → PascalCase mediante `CURSOR_EVENT_MAP`, de modo que las políticas integradas existentes se activan sin cambios. El soporte de Cursor Agent está en **beta** mientras verificamos el formato en disco de la transcripción de Cursor (no especificado en la documentación pública) con más instalaciones reales. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuario), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proyecto) — OpenCode no tiene ámbito `local`. A diferencia de las otras seis CLIs, OpenCode **no tiene un sistema de hooks de comandos externos**: carga plugins JS/TS en proceso registrados explícitamente mediante el array `plugin: []` en `opencode.json` (el autodescubrimiento desde `.opencode/plugins/` **no** es cómo se cargan los plugins en opencode v1.14.33). La instalación coloca un pequeño shim de plugin generado que llama al binario failproofai como subproceso y traduce la respuesta JSON de forma Claude del binario de vuelta a la semántica del plugin: `throw new Error()` para denegar eventos de herramienta (cancela la llamada a la herramienta), `client.session.prompt(...)` para instruct Y para `Stop` / `SubagentStop` deny (envía el motivo de denegación como el siguiente mensaje del usuario — el único canal de reintento forzado, ya que `session.idle` es solo notificación y lanzar desde él es un no-op), y no-op para allow. El shim canonicaliza tanto los nombres de herramientas (minúsculas → PascalCase mediante `OPENCODE_TOOL_MAP`) como las claves de argumentos de entrada de herramientas (camelCase → snake_case mediante `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, p. ej. `filePath` → `file_path`, `oldString` → `old_string`) antes de reenviar al binario, de modo que las políticas integradas de verificación de rutas como `block-read-outside-cwd`, `block-env-files` y `block-secrets-write` se activan sin cambios en las llamadas a herramientas de OpenCode. Las sesiones viven en la base de datos SQLite de opencode en `~/.local/share/opencode/opencode.db`; el visor de sesiones del panel las lee mediante `opencode db --format json` y `opencode export `. El soporte de OpenCode está en **beta** mientras verificamos el comportamiento en distintas versiones y con más sesiones reales. Consulta la [documentación de plugins de OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuario), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proyecto) — OpenCode no tiene ámbito `local`. A diferencia de las otras cinco CLIs, OpenCode **no tiene un sistema de hooks de comandos externos**: carga plugins JS/TS en proceso registrados explícitamente mediante el array `plugin: []` en `opencode.json` (el autodescubrimiento desde `.opencode/plugins/` **no** es cómo se cargan los plugins en opencode v1.14.33). La instalación coloca un pequeño shim de plugin generado que llama al binario failproofai como subproceso y traduce la respuesta JSON de forma Claude del binario de vuelta a la semántica del plugin: `throw new Error()` para denegar eventos de herramienta (cancela la llamada a la herramienta), `client.session.prompt(...)` para instruct Y para `Stop` / `SubagentStop` deny (envía el motivo de denegación como el siguiente mensaje del usuario — el único canal de reintento forzado, ya que `session.idle` es solo notificación y lanzar desde él es un no-op), y no-op para allow. El shim canonicaliza tanto los nombres de herramientas (minúsculas → PascalCase mediante `OPENCODE_TOOL_MAP`) como las claves de argumentos de entrada de herramientas (camelCase → snake_case mediante `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, p. ej. `filePath` → `file_path`, `oldString` → `old_string`) antes de reenviar al binario, de modo que las políticas integradas de verificación de rutas como `block-read-outside-cwd`, `block-env-files` y `block-secrets-write` se activan sin cambios en las llamadas a herramientas de OpenCode. Las sesiones viven en la base de datos SQLite de opencode en `~/.local/share/opencode/opencode.db`; el visor de sesiones del panel las lee mediante `opencode db --format json` y `opencode export `. El soporte de OpenCode está en **beta** mientras verificamos el comportamiento en distintas versiones y con más sesiones reales. Consulta la [documentación de plugins de OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuario), `/.pi/settings.json` (proyecto) — Pi no tiene ámbito `local`. Pi carga paquetes de extensiones TypeScript al inicio; el archivo de configuración es un array de cadenas plano `{"packages": ["./relative/path", …]}`. failproofai escribe una única entrada en el array de packages apuntando a su directorio `pi-extension/` integrado. La extensión se suscribe internamente a los eventos `tool_call` / `user_bash` / `input` / `session_start` de Pi y ejecuta `failproofai --hook --cli pi` como proceso hijo; el manejador canonicaliza eventos de snake_case en minúsculas → PascalCase mediante `PI_EVENT_MAP` para que las políticas integradas existentes se activen sin cambios. Los argumentos de entrada de herramientas también se canonizan mediante `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit entregan `path` en lugar de `file_path`; mapear la clave de nivel superior permite que `block-env-files` y `block-secrets-write` se activen — `block-read-outside-cwd` ya tenía un respaldo con `path`). El soporte de Pi está en **beta** mientras la API de extensiones de Pi y el diseño del registro de sesiones se estabilizan. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (usuario), `/.gemini/settings.json` (proyecto) — Gemini no tiene ámbito `local` (documenta un ámbito `system` en `/etc/gemini-cli/settings.json` que failproofai no expone). Las entradas de hook usan la forma de Claude `{type, command, timeout}` envuelta en el esquema de matcher de Gemini `{matcher, hooks: [...]}` con `matcher: "*"` por defecto. Los eventos están en PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); el manejador los mapea a nombres canónicos de Claude mediante `GEMINI_EVENT_MAP`. Los nombres de herramientas están en snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — el manejador los canonicaliza mediante `GEMINI_TOOL_MAP` para que las políticas integradas existentes se activen sin cambios. El evaluador de políticas emite la forma plana de Gemini `{decision: "deny", reason}` (preferida según el contrato exit-0 de la "Regla de Oro" de Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` para inyección de contexto en BeforeAgent / AfterTool / SessionStart, y `{decision: "block", reason}` en AfterAgent para semántica de reintento forzado. El soporte de Gemini CLI está en **beta** mientras ampliamos la cobertura en el mundo real. Consulta la [documentación de hooks de Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**solo ámbito de usuario** — Hermes no tiene configuración de proyecto/local). Hermes es una **pasarela** de Slack/Telegram, por lo que una instalación intercepta las llamadas a herramientas de todas las plataformas (Slack/Telegram/cli/cron) **y** de los subagentes internos. Las entradas de hook son un par `{command, timeout}` (tiempo de espera en **segundos**) bajo un mapa `hooks:` indexado por los eventos snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); el manejador canonicaliza los eventos mediante `HERMES_EVENT_MAP` y los nombres de herramientas mediante `HERMES_TOOL_MAP` para que las políticas integradas se activen sin cambios. La configuración se edita mediante un round-trip YAML `Document` que preserva los comentarios, de modo que los demás ajustes del operador sobreviven, y la instalación establece `hooks_auto_accept: true` para que la pasarela sin cabeza (sin TTY) ejecute los hooks sin solicitud de consentimiento. El evaluador emite el contrato stdout `{"decision":"block","reason"}` de Hermes (Hermes ignora los códigos de salida). **Limitaciones:** Hermes no tiene un evento `Stop` de fin de turno, por lo que las políticas integradas `require-*-before-stop` nunca se activan para él (no aplicable, no roto); `instruct` degrada a allow con nota registrada (sin canal de contexto adicional); y la redacción de secretos en la salida (`sanitize-*`) no puede reescribir la salida de herramientas a través del contrato de hook de shell. Hermes es también una fuente de **auditoría** sin conexión — el panel lee sus sesiones de pasarela directamente desde `~/.hermes/state.db`. - **`policies-config.json`** — indica a failproofai qué políticas evaluar y con qué parámetros (compartido entre todas las CLIs de agentes) -Pasa `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` para apuntar a un agente específico (separados por espacios o repetidos para cualquier subconjunto): +Pasa `--cli claude|codex|copilot|cursor|opencode|pi|hermes` para apuntar a un agente específico (separados por espacios o repetidos para cualquier subconjunto): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Cuando se omite `--cli`, `failproofai` detecta qué CLIs de agentes están instaladas (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Cuando se omite `--cli`, `failproofai` detecta qué CLIs de agentes están instaladas (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Una CLI detectada** — la selecciona automáticamente sin solicitar confirmación. - **Múltiples CLIs detectadas** en un terminal interactivo — muestra un prompt de selección única con teclas de flecha, agrupado en una sección `Detected (N)` (con una fila agregada `Install for all N detected` + cada CLI detectada individualmente) y una sección `Not installed (M) · install hooks ahead of time` que lista cada CLI compatible no detectada como opción de instalación anticipada (↑↓ para moverse, Enter para seleccionar, ^C para salir). El flujo de desinstalación muestra solo la sección Detected. diff --git a/docs/es/dashboard.mdx b/docs/es/dashboard.mdx index b08f724b..8cb83822 100644 --- a/docs/es/dashboard.mdx +++ b/docs/es/dashboard.mdx @@ -24,11 +24,11 @@ El dashboard lee directamente desde el sistema de archivos: las carpetas de proy ### Proyectos -Lista todos los proyectos de Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ y Hermes encontrados en tu máquina. Los proyectos de Claude se descubren desde `~/.claude/projects/` (o la ruta definida por `CLAUDE_PROJECTS_PATH`); los proyectos de Codex se descubren escaneando todas las transcripciones en `~/.codex/sessions///
/*.jsonl` y agrupándolas por el `cwd` registrado en el primer registro de cada sesión; los proyectos de Copilot CLI se descubren escaneando cada `~/.copilot/session-state//workspace.yaml` (configurable mediante `COPILOT_HOME`) y agrupándolos por su campo `cwd`; los proyectos de Cursor Agent se descubren escaneando metadatos por sesión en `~/.cursor/agent-sessions//` (configurable mediante `CURSOR_HOME`, con `conversations/` y `sessions/` como alternativas de búsqueda) para un escalar `cwd` en `meta.json` / `session.json` / `workspace.yaml`; los proyectos de OpenCode se descubren consultando su base de datos SQLite en `~/.local/share/opencode/opencode.db` mediante `opencode db --format json` (leemos las tablas `session` y `project` y agrupamos por `project_id`); los proyectos de Pi se descubren escaneando transcripciones JSONL por sesión en `~/.pi/agent/sessions//_.jsonl` (configurable mediante `PI_SESSIONS_DIR`) y extrayendo el `cwd` del primer registro de cada sesión; los proyectos de Gemini CLI se descubren escaneando `~/.gemini/tmp//chats/session--.jsonl` (configurable mediante `GEMINI_SESSIONS_DIR`) y recuperando el cwd canónico desde el marcador de texto `.project_root` adyacente; las sesiones del gateway de Hermes se leen directamente desde su almacén SQLite en `~/.hermes/state.db` (configurable mediante `HERMES_DB_PATH`) y se agrupan en proyectos `hermes-` por `source` (Slack/Telegram/cli/cron — las sesiones del gateway no tienen cwd). Un proyecto que haya sido utilizado por múltiples CLIs se muestra como una sola fila con todas las insignias correspondientes. Usa el menú desplegable **CLI** sobre la tabla para filtrar por un agente CLI específico; la URL conserva tu selección como `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lista todos los proyectos de Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ y Hermes encontrados en tu máquina. Los proyectos de Claude se descubren desde `~/.claude/projects/` (o la ruta definida por `CLAUDE_PROJECTS_PATH`); los proyectos de Codex se descubren escaneando todas las transcripciones en `~/.codex/sessions///
/*.jsonl` y agrupándolas por el `cwd` registrado en el primer registro de cada sesión; los proyectos de Copilot CLI se descubren escaneando cada `~/.copilot/session-state//workspace.yaml` (configurable mediante `COPILOT_HOME`) y agrupándolos por su campo `cwd`; los proyectos de Cursor Agent se descubren escaneando metadatos por sesión en `~/.cursor/agent-sessions//` (configurable mediante `CURSOR_HOME`, con `conversations/` y `sessions/` como alternativas de búsqueda) para un escalar `cwd` en `meta.json` / `session.json` / `workspace.yaml`; los proyectos de OpenCode se descubren consultando su base de datos SQLite en `~/.local/share/opencode/opencode.db` mediante `opencode db --format json` (leemos las tablas `session` y `project` y agrupamos por `project_id`); los proyectos de Pi se descubren escaneando transcripciones JSONL por sesión en `~/.pi/agent/sessions//_.jsonl` (configurable mediante `PI_SESSIONS_DIR`) y extrayendo el `cwd` del primer registro de cada sesión; las sesiones del gateway de Hermes se leen directamente desde su almacén SQLite en `~/.hermes/state.db` (configurable mediante `HERMES_DB_PATH`) y se agrupan en proyectos `hermes-` por `source` (Slack/Telegram/cli/cron — las sesiones del gateway no tienen cwd). Un proyecto que haya sido utilizado por múltiples CLIs se muestra como una sola fila con todas las insignias correspondientes. Usa el menú desplegable **CLI** sobre la tabla para filtrar por un agente CLI específico; la URL conserva tu selección como `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Cada proyecto muestra: - Nombre del proyecto (derivado de la ruta de la carpeta) -- Una insignia de CLI — `Claude Code` (naranja), `OpenAI Codex` (morado), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (ámbar), `Pi` (rosa), `Gemini CLI` (celeste) y/o `Hermes` (índigo) +- Una insignia de CLI — `Claude Code` (naranja), `OpenAI Codex` (morado), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (ámbar), `Pi` (rosa) y/o `Hermes` (índigo) - Fecha de la actividad de sesión más reciente Haz clic en un proyecto para ver sus sesiones. @@ -47,7 +47,7 @@ Haz clic en una sesión para abrir el visor de sesión. ### Visor de sesión -El visor de sesión responde la pregunta clave para los agentes autónomos: ¿qué hizo el agente y se mantuvo en curso? Una insignia de CLI junto al encabezado indica si la sesión es una transcripción de Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI o Hermes. Muestra una línea de tiempo de todo lo que ocurrió en una sesión: +El visor de sesión responde la pregunta clave para los agentes autónomos: ¿qué hizo el agente y se mantuvo en curso? Una insignia de CLI junto al encabezado indica si la sesión es una transcripción de Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi o Hermes. Muestra una línea de tiempo de todo lo que ocurrió en una sesión: - **Mensajes** - Respuestas de texto de Claude y prompts del usuario - **Llamadas a herramientas** - Cada herramienta que Claude invocó, con su entrada y salida @@ -55,7 +55,7 @@ El visor de sesión responde la pregunta clave para los agentes autónomos: ¿qu La barra de estadísticas en la parte superior muestra la duración de la sesión, el total de llamadas a herramientas y un resumen de las decisiones de los hooks (recuentos de allow / deny / instruct). -Haz clic en el botón **Descargar Logs** para exportar la sesión. Para sesiones de Claude Code, Codex, Copilot, Cursor, Pi y Gemini obtienes la transcripción JSONL original en disco byte a byte; para OpenCode (cuyas sesiones residen en SQLite, no en disco) obtienes un documento JSON que refleja las tablas subyacentes `session` / `messages` / `parts`. +Haz clic en el botón **Descargar Logs** para exportar la sesión. Para sesiones de Claude Code, Codex, Copilot, Cursor y Pi obtienes la transcripción JSONL original en disco byte a byte; para OpenCode (cuyas sesiones residen en SQLite, no en disco) obtienes un documento JSON que refleja las tablas subyacentes `session` / `messages` / `parts`. ### Auditoría @@ -75,16 +75,16 @@ Una página de dos pestañas para gestionar políticas y revisar actividad. - - Selección múltiple de los CLIs de agentes que failproofai protege desde un único panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI y Hermes tienen una fila con el estado de instalación (`Active` / `Detected` / `Inactive`), la ruta de configuración de alcance de usuario y un acento de color de marca. Marca o desmarca los CLIs que desees y haz clic en `Apply changes` para instalar/desinstalar la diferencia en un solo paso. Los CLIs cuyo binario se detecta en PATH se marcan previamente. + - Selección múltiple de los CLIs de agentes que failproofai protege desde un único panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi y Hermes tienen una fila con el estado de instalación (`Active` / `Detected` / `Inactive`), la ruta de configuración de alcance de usuario y un acento de color de marca. Marca o desmarca los CLIs que desees y haz clic en `Apply changes` para instalar/desinstalar la diferencia en un solo paso. Los CLIs cuyo binario se detecta en PATH se marcan previamente. - Activa o desactiva políticas individuales con un solo clic (escribe en `~/.failproofai/policies-config.json` — compartido entre cada CLI instalado) - Expande una política para configurar sus parámetros (para políticas que admiten `policyParams`) - Establece una ruta de archivo de políticas personalizadas - Historial completo paginado de cada evento de hook que se ha activado en todas las sesiones - - Filtra por decisión, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nombre de política o ID de sesión - - Cada fila muestra: marca de tiempo, nombre de política, decisión, insignia de CLI (naranja = Claude Code, morado = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, ámbar = OpenCode, rosa = Pi, celeste = Gemini CLI, índigo = Hermes), nombre de herramienta, ID de sesión y el motivo de las decisiones deny/instruct - - Haz clic en un ID de sesión para abrir su transcripción — el visor detecta automáticamente qué CLI activó el hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) y renderiza la insignia de CLI correspondiente en el encabezado + - Filtra por decisión, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), nombre de política o ID de sesión + - Cada fila muestra: marca de tiempo, nombre de política, decisión, insignia de CLI (naranja = Claude Code, morado = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, ámbar = OpenCode, rosa = Pi, índigo = Hermes), nombre de herramienta, ID de sesión y el motivo de las decisiones deny/instruct + - Haz clic en un ID de sesión para abrir su transcripción — el visor detecta automáticamente qué CLI activó el hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) y renderiza la insignia de CLI correspondiente en el encabezado diff --git a/docs/es/getting-started.mdx b/docs/es/getting-started.mdx index 51f88320..0ed8095c 100644 --- a/docs/es/getting-started.mdx +++ b/docs/es/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Esto escribe entradas de hooks en los CLIs de agentes instalados (el `~/.claude/settings.json` de Claude Code, el `~/.codex/hooks.json` de OpenAI Codex, el `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, el `~/.cursor/hooks.json` de Cursor Agent, el shim de plugin generado de OpenCode en `~/.config/opencode/plugins/failproofai.mjs` junto con una entrada de registro en el array `plugin` de `~/.config/opencode/opencode.json`, el `~/.pi/agent/settings.json` de Pi, el `~/.gemini/settings.json` de Gemini CLI, o el `~/.hermes/config.yaml` de Hermes). Si hay más de uno presente, se te pedirá que elijas; pasa `--cli claude codex copilot cursor opencode pi gemini hermes` (cualquier subconjunto) para omitir la pregunta. + Esto escribe entradas de hooks en los CLIs de agentes instalados (el `~/.claude/settings.json` de Claude Code, el `~/.codex/hooks.json` de OpenAI Codex, el `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, el `~/.cursor/hooks.json` de Cursor Agent, el shim de plugin generado de OpenCode en `~/.config/opencode/plugins/failproofai.mjs` junto con una entrada de registro en el array `plugin` de `~/.config/opencode/opencode.json`, el `~/.pi/agent/settings.json` de Pi, o el `~/.hermes/config.yaml` de Hermes). Si hay más de uno presente, se te pedirá que elijas; pasa `--cli claude codex copilot cursor opencode pi hermes` (cualquier subconjunto) para omitir la pregunta. - El soporte para GitHub Copilot CLI, Cursor Agent, OpenCode, Pi y Gemini CLI es **beta** — instala con `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` o `--cli gemini`. Hermes (hermes-agent, una puerta de enlace para Slack/Telegram) se instala con alcance de usuario mediante `--cli hermes` y es **también** una fuente de auditoría sin conexión. + El soporte para GitHub Copilot CLI, Cursor Agent, OpenCode y Pi es **beta** — instala con `--cli copilot`, `--cli cursor`, `--cli opencode` o `--cli pi`. Hermes (hermes-agent, una puerta de enlace para Slack/Telegram) se instala con alcance de usuario mediante `--cli hermes` y es **también** una fuente de auditoría sin conexión. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/es/introduction.mdx b/docs/es/introduction.mdx index b3eabeed..a8a915a7 100644 --- a/docs/es/introduction.mdx +++ b/docs/es/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI ofrece a los agentes de IA 39 políticas de fallo inte [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks y políticas para **manejo de fallos de IA**, **recuperación de errores** y **fiabilidad de LLM**. Mantén tus agentes de IA fiables y funcionando de forma autónoma en **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** y el **Agents SDK**. +Hooks y políticas para **manejo de fallos de IA**, **recuperación de errores** y **fiabilidad de LLM**. Mantén tus agentes de IA fiables y funcionando de forma autónoma en **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** y el **Agents SDK**. Los agentes de IA fallan de maneras predecibles. Ejecutan comandos destructivos, filtran secretos, se desvían de sus tareas, quedan atrapados en bucles o hacen push directamente a main. Sin supervisión, los pequeños fallos se convierten en interrupciones del servicio, credenciales expuestas y trabajo perdido. diff --git a/docs/fr/built-in-policies.mdx b/docs/fr/built-in-policies.mdx index edefb9c4..8f3bceda 100644 --- a/docs/fr/built-in-policies.mdx +++ b/docs/fr/built-in-policies.mdx @@ -704,7 +704,7 @@ Toutes les politiques de workflow sont **fail-open** : si l'outil requis n'est p ### Sémantique Stop par CLI -L'application du Stop se présente légèrement différemment selon les sept CLI supportés, car chacun expose un contrat de hook "agent terminé" différent. Le **résultat** est le même — l'agent ne peut pas s'arrêter tant qu'une porte de workflow est en échec — mais les **mécanismes** diffèrent. Le tableau ci-dessous résume la situation ; seul Pi présente une particularité visible par l'utilisateur qu'il convient de comprendre avant d'activer une politique `require-*-before-stop`. +L'application du Stop se présente légèrement différemment selon les six CLI supportés, car chacun expose un contrat de hook "agent terminé" différent. Le **résultat** est le même — l'agent ne peut pas s'arrêter tant qu'une porte de workflow est en échec — mais les **mécanismes** diffèrent. Le tableau ci-dessous résume la situation ; seul Pi présente une particularité visible par l'utilisateur qu'il convient de comprendre avant d'activer une politique `require-*-before-stop`. | CLI | Quand la porte se déclenche | Ce que vous voyez | |---|---|---| @@ -712,20 +712,19 @@ L'application du Stop se présente légèrement différemment selon les sept CLI | Codex | Dans la même boucle agent, immédiatement | Identique à Claude. | | GitHub Copilot CLI | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal de relance `{decision:"block", reason}` de Copilot — vérifié empiriquement contre Copilot CLI 1.0.41). | | Cursor Agent | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal `{followup_message}` de Cursor — limité à `loop_limit`, 5 relances par défaut). | -| Gemini CLI | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal `{decision:"block", reason}` de Gemini sur `AfterAgent`). | | OpenCode | Dans la même boucle agent, immédiatement | Identique à Claude (utilise l'appel SDK `client.session.prompt(...)` d'OpenCode acheminé via `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Au prochain tour utilisateur** | **Pi s'arrête visiblement** lorsque la porte se déclenche — sa boucle agent se termine et vous êtes renvoyé au prompt. La porte se déclenche ensuite la prochaine fois que vous soumettez un prompt : failproofai ajoute en tête du system prompt de ce tour une directive `MANDATORY ACTION REQUIRED`, demandant au LLM de compléter l'étape de workflow (commit, push, etc.) avant de faire ce que vous avez demandé. | -**Limitation de Pi.** L'`AgentEndEvent` de Pi (l'équivalent upstream du hook `Stop` de Claude) n'a pas de type Result — au moment où il se déclenche, la boucle agent de Pi a déjà terminé. Pi ne peut pas être forcé à relancer la même boucle comme Claude / Copilot / Cursor / Gemini / OpenCode le peuvent. failproofai déplace la porte vers l'événement `before_agent_start` de Pi (qui se déclenche après le prochain prompt utilisateur) afin que la vérification de workflow s'applique quand même, simplement au tour suivant plutôt qu'au tour courant. +**Limitation de Pi.** L'`AgentEndEvent` de Pi (l'équivalent upstream du hook `Stop` de Claude) n'a pas de type Result — au moment où il se déclenche, la boucle agent de Pi a déjà terminé. Pi ne peut pas être forcé à relancer la même boucle comme Claude / Copilot / Cursor / OpenCode le peuvent. failproofai déplace la porte vers l'événement `before_agent_start` de Pi (qui se déclenche après le prochain prompt utilisateur) afin que la vérification de workflow s'applique quand même, simplement au tour suivant plutôt qu'au tour courant. **Ce que cela signifie en pratique :** - Après l'arrêt de Pi, la raison du deny est capturée en mémoire, indexée par l'identifiant de session Pi. Le tout prochain prompt soumis dans le même processus Pi la draine : le LLM voit la directive `MANDATORY ACTION REQUIRED` en tête de son system prompt, effectue le commit (ou le push / ouvre la PR / attend le CI), puis continue avec votre demande. La raison du deny capturée est à usage unique — une fois drainée, la porte est levée. -- La porte est bornée par la durée de vie du processus Pi. Si vous faites `Ctrl+C` sur Pi ou quittez entre deux tours, l'entrée en mémoire est perdue avec le processus et la porte est manquée. Claude, Copilot, Cursor, Gemini et OpenCode ont la même contrainte (tuer l'agent fait manquer la porte) — Pi la rend simplement plus visible car l'agent se termine visiblement avant que la porte ne se déclenche. +- La porte est bornée par la durée de vie du processus Pi. Si vous faites `Ctrl+C` sur Pi ou quittez entre deux tours, l'entrée en mémoire est perdue avec le processus et la porte est manquée. Claude, Copilot, Cursor et OpenCode ont la même contrainte (tuer l'agent fait manquer la porte) — Pi la rend simplement plus visible car l'agent se termine visiblement avant que la porte ne se déclenche. - Un deny en attente est également effacé à `session_shutdown` pour toute raison (`new` / `resume` / `fork` / `quit`), afin qu'une porte périmée d'une session précédente ne puisse pas fuiter dans une nouvelle session démarrée dans le même processus Pi. -Si vous avez besoin d'une relance dans la même boucle à la manière de Claude, exécutez vos politiques `Stop` sous l'un des six autres CLI supportés. Nous suivons l'évolution de Pi en amont pour un futur type Result sur `AgentEndEvent` qui nous permettrait de combler cet écart. +Si vous avez besoin d'une relance dans la même boucle à la manière de Claude, exécutez vos politiques `Stop` sous l'un des cinq autres CLI supportés. Nous suivons l'évolution de Pi en amont pour un futur type Result sur `AgentEndEvent` qui nous permettrait de combler cet écart. ### `require-commit-before-stop` diff --git a/docs/fr/cli/audit.mdx b/docs/fr/cli/audit.mdx index 50e38288..938f30c6 100644 --- a/docs/fr/cli/audit.mdx +++ b/docs/fr/cli/audit.mdx @@ -57,7 +57,7 @@ failproofai `Ctrl+C`. -Le tableau de bord analyse les transcriptions passées de l'agent CLI sur cette machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) et indique à quelle fréquence l'agent a effectué des actions que failproofai est conçu pour bloquer — vérifications de variables d'environnement, push forcés, préfixes `cd ` redondants, boucles de polling avec sleep, relecture de fichiers venant d'être édités, et bien d'autres. +Le tableau de bord analyse les transcriptions passées de l'agent CLI sur cette machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) et indique à quelle fréquence l'agent a effectué des actions que failproofai est conçu pour bloquer — vérifications de variables d'environnement, push forcés, préfixes `cd ` redondants, boucles de polling avec sleep, relecture de fichiers venant d'être édités, et bien d'autres. Pour chaque transcription, chaque événement d'utilisation d'outil est rejoué à travers les 39 politiques intégrées **et** à travers 8 détecteurs exclusifs à l'audit qui repèrent des motifs non encore couverts par les politiques en temps réel. Les comptages sont agrégés par politique / détecteur sur l'ensemble des sessions. diff --git a/docs/fr/configuration.mdx b/docs/fr/configuration.mdx index 81c44d79..28427cba 100644 --- a/docs/fr/configuration.mdx +++ b/docs/fr/configuration.mdx @@ -196,13 +196,12 @@ Les commandes `policies --install` et `policies --uninstall` écrivent dans le f - **OpenAI Codex** : `~/.codex/hooks.json` (utilisateur), `/.codex/hooks.json` (projet) — Codex n'a pas de niveau `local` - **GitHub Copilot CLI _(bêta)_** : `~/.copilot/hooks/failproofai.json` (utilisateur), `/.github/hooks/failproofai.json` (projet) — Copilot n'a pas de niveau `local`. Les entrées de hook utilisent les champs de commande `bash`/`powershell` à clé OS de Copilot avec `timeoutSec` ; le fichier porte un marqueur `version: 1` au niveau racine. La prise en charge de Copilot CLI est en **bêta** pendant que nous vérifions le schéma d'enregistrement `events.jsonl` (que la documentation publique ne spécifie pas) contre davantage de sessions réelles. - **Cursor Agent _(bêta)_** : `~/.cursor/hooks.json` (utilisateur), `/.cursor/hooks.json` (projet) — Cursor n'a pas de niveau `local`. Les entrées de hook utilisent la forme `{type, command, timeout}` inspirée de Claude (sans séparation `bash`/`powershell`), mais stockées sous des clés d'événement en camelCase (`preToolUse`, `beforeSubmitPrompt`, …) dans un tableau plat selon le [schéma de hooks](https://cursor.com/docs/hooks) de Cursor ; le fichier porte un marqueur `version: 1` au niveau racine. Le gestionnaire canonicalise camelCase → PascalCase via `CURSOR_EVENT_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. La prise en charge de Cursor Agent est en **bêta** pendant que nous vérifions le format de transcription sur disque de Cursor (non spécifié dans la documentation publique) contre davantage d'installations réelles. - - **OpenCode _(bêta)_** : `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (utilisateur), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projet) — OpenCode n'a pas de niveau `local`. Contrairement aux six autres CLI, OpenCode **n'a pas de système de hook par commande externe** : il charge des plugins JS/TS en cours de processus explicitement enregistrés via le tableau `plugin: []` dans `opencode.json` (la découverte automatique depuis `.opencode/plugins/` **n'est pas** le mode de chargement des plugins sur opencode v1.14.33). L'installation dépose un petit shim de plugin généré qui appelle le binaire failproofai en sous-processus et traduit la réponse JSON en forme Claude du binaire vers la sémantique du plugin : `throw new Error()` pour le refus d'événement outil (annule l'appel d'outil), `client.session.prompt(...)` pour instruct ET pour le refus `Stop` / `SubagentStop` (soumet le motif de refus comme prochain message utilisateur — le seul canal de nouvelle tentative forcée puisque `session.idle` est uniquement pour les notifications et qu'une exception levée depuis celui-ci est un no-op), et no-op pour allow. Le shim canonicalise les noms d'outils (minuscules → PascalCase via `OPENCODE_TOOL_MAP`) et les clés d'arguments d'entrée d'outil (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` pour `Read` / `Write` / `Edit`, par exemple `filePath` → `file_path`, `oldString` → `old_string`) avant de transmettre au binaire, de sorte que les politiques intégrées de vérification de chemin comme `block-read-outside-cwd`, `block-env-files` et `block-secrets-write` se déclenchent sans modification sur les appels d'outils OpenCode. Les sessions vivent dans la base de données SQLite d'opencode à `~/.local/share/opencode/opencode.db` ; la visionneuse de sessions du tableau de bord les lit via `opencode db --format json` et `opencode export `. La prise en charge d'OpenCode est en **bêta** pendant que nous vérifions le comportement entre les versions et contre davantage de sessions réelles. Consultez la [documentation des plugins OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(bêta)_** : `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (utilisateur), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projet) — OpenCode n'a pas de niveau `local`. Contrairement aux cinq autres CLI, OpenCode **n'a pas de système de hook par commande externe** : il charge des plugins JS/TS en cours de processus explicitement enregistrés via le tableau `plugin: []` dans `opencode.json` (la découverte automatique depuis `.opencode/plugins/` **n'est pas** le mode de chargement des plugins sur opencode v1.14.33). L'installation dépose un petit shim de plugin généré qui appelle le binaire failproofai en sous-processus et traduit la réponse JSON en forme Claude du binaire vers la sémantique du plugin : `throw new Error()` pour le refus d'événement outil (annule l'appel d'outil), `client.session.prompt(...)` pour instruct ET pour le refus `Stop` / `SubagentStop` (soumet le motif de refus comme prochain message utilisateur — le seul canal de nouvelle tentative forcée puisque `session.idle` est uniquement pour les notifications et qu'une exception levée depuis celui-ci est un no-op), et no-op pour allow. Le shim canonicalise les noms d'outils (minuscules → PascalCase via `OPENCODE_TOOL_MAP`) et les clés d'arguments d'entrée d'outil (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` pour `Read` / `Write` / `Edit`, par exemple `filePath` → `file_path`, `oldString` → `old_string`) avant de transmettre au binaire, de sorte que les politiques intégrées de vérification de chemin comme `block-read-outside-cwd`, `block-env-files` et `block-secrets-write` se déclenchent sans modification sur les appels d'outils OpenCode. Les sessions vivent dans la base de données SQLite d'opencode à `~/.local/share/opencode/opencode.db` ; la visionneuse de sessions du tableau de bord les lit via `opencode db --format json` et `opencode export `. La prise en charge d'OpenCode est en **bêta** pendant que nous vérifions le comportement entre les versions et contre davantage de sessions réelles. Consultez la [documentation des plugins OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(bêta)_** : `~/.pi/agent/settings.json` (utilisateur), `/.pi/settings.json` (projet) — Pi n'a pas de niveau `local`. Pi charge des packages d'extension TypeScript au démarrage ; le fichier de paramètres est un tableau de chaînes plat `{"packages": ["./relative/path", …]}`. failproofai écrit une seule entrée dans le tableau packages pointant vers son répertoire `pi-extension/` intégré. L'extension s'abonne en interne aux événements `tool_call` / `user_bash` / `input` / `session_start` de Pi et exécute `failproofai --hook --cli pi` en shell ; le gestionnaire canonicalise les événements underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. Les arguments d'entrée d'outil sont également canonicalisés via `PI_TOOL_INPUT_MAP` (les commandes Read / Write / Edit de Pi livrent `path` plutôt que `file_path` ; mapper la clé de niveau supérieur permet à `block-env-files` et `block-secrets-write` de se déclencher — `block-read-outside-cwd` avait déjà un fallback `path`). La prise en charge de Pi est en **bêta** pendant que l'API d'extension de Pi et la disposition du journal de session se stabilisent. - - **Gemini CLI _(bêta)_** : `~/.gemini/settings.json` (utilisateur), `/.gemini/settings.json` (projet) — Gemini n'a pas de niveau `local` (il documente un niveau `system` à `/etc/gemini-cli/settings.json` que failproofai n'expose pas). Les entrées de hook utilisent la forme `{type, command, timeout}` de Claude enveloppée dans le schéma de correspondance `{matcher, hooks: [...]}` de Gemini avec `matcher: "*"` par défaut. Les événements sont en PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`) ; le gestionnaire mappe vers les noms canoniques Claude via `GEMINI_EVENT_MAP`. Les noms d'outils sont en snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — le gestionnaire canonicalise via `GEMINI_TOOL_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. L'évaluateur de politiques émet la forme plate `{decision: "deny", reason}` de Gemini (recommandée selon la règle d'or exit-0 de Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` pour l'injection de contexte sur BeforeAgent / AfterTool / SessionStart, et `{decision: "block", reason}` sur AfterAgent pour la sémantique de nouvelle tentative forcée. La prise en charge de Gemini CLI est en **bêta** pendant que nous élargissons la couverture réelle. Consultez la [documentation des hooks Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)** : `~/.hermes/config.yaml` (**niveau utilisateur uniquement** — Hermes n'a pas de configuration projet/local). Hermes est une **passerelle** Slack/Telegram, donc une seule installation intercepte les appels d'outils de toutes les plateformes (Slack/Telegram/cli/cron) **et** des sous-agents internes. Les entrées de hook sont une paire `{command, timeout}` (timeout en **secondes**) sous une map `hooks:` indexée par les événements snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) ; le gestionnaire canonicalise les événements via `HERMES_EVENT_MAP` et les noms d'outils via `HERMES_TOOL_MAP` afin que les politiques intégrées se déclenchent sans modification. La configuration est modifiée via un aller-retour `Document` YAML préservant les commentaires, de sorte que les autres paramètres de l'opérateur survivent, et l'installation définit `hooks_auto_accept: true` pour que la passerelle sans tête (sans TTY) exécute les hooks sans invite de consentement. L'évaluateur émet le contrat stdout `{"decision":"block","reason"}` de Hermes (Hermes ignore les codes de sortie). **Limitations :** Hermes n'a pas d'événement `Stop` de fin de tour, donc les politiques intégrées `require-*-before-stop` ne se déclenchent jamais pour lui (non applicable, pas cassé) ; `instruct` se dégrade en allow-avec-note-journalisée (pas de canal de contexte supplémentaire) ; et la redaction des secrets en sortie (`sanitize-*`) ne peut pas réécrire la sortie d'outil via le contrat de hook shell. Hermes est **également** une source d'**audit** hors ligne — le tableau de bord lit ses sessions de passerelle directement depuis `~/.hermes/state.db`. - **`policies-config.json`** — indique à failproofai quelles politiques évaluer et avec quels paramètres (partagé entre toutes les CLI agent) -Passez `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` pour cibler un agent spécifique (séparé par des espaces ou répété pour tout sous-ensemble) : +Passez `--cli claude|codex|copilot|cursor|opencode|pi|hermes` pour cibler un agent spécifique (séparé par des espaces ou répété pour tout sous-ensemble) : ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Lorsque `--cli` est omis, `failproofai` détecte quelles CLI agent sont installées (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`) : +Lorsque `--cli` est omis, `failproofai` détecte quelles CLI agent sont installées (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`) : - **Une CLI détectée** — sélectionne automatiquement cette CLI sans demander de confirmation. - **Plusieurs CLI détectées** dans un terminal interactif — affiche une invite de sélection unique par touches fléchées regroupée en une section `Detected (N)` (avec une ligne agrégée `Install for all N detected` + chaque CLI détectée individuellement) et une section `Not installed (M) · install hooks ahead of time` listant chaque CLI prise en charge non détectée comme option d'installation anticipée (↑↓ pour déplacer, Entrée pour sélectionner, ^C pour quitter). Le flux de désinstallation n'affiche que la section Detected. diff --git a/docs/fr/dashboard.mdx b/docs/fr/dashboard.mdx index 1e76570b..1b463a02 100644 --- a/docs/fr/dashboard.mdx +++ b/docs/fr/dashboard.mdx @@ -24,11 +24,11 @@ Le tableau de bord lit directement depuis le système de fichiers — vos dossie ### Projets -Liste tous les projets Claude Code, OpenAI Codex, GitHub Copilot CLI _(bêta)_, Cursor Agent _(bêta)_, OpenCode _(bêta)_, Pi _(bêta)_, Gemini CLI _(bêta)_ et Hermes trouvés sur votre machine. Les projets Claude sont découverts depuis `~/.claude/projects/` (ou le chemin défini par `CLAUDE_PROJECTS_PATH`) ; les projets Codex sont découverts en analysant chaque transcription sous `~/.codex/sessions///
/*.jsonl` et en les regroupant par le `cwd` enregistré dans le premier enregistrement de chaque session ; les projets Copilot CLI sont découverts en analysant chaque `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) et en les regroupant par leur champ `cwd` ; les projets Cursor Agent sont découverts en analysant les métadonnées par session sous `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, avec `conversations/` et `sessions/` comme solutions de repli) pour un scalaire `cwd` dans `meta.json` / `session.json` / `workspace.yaml` ; les projets OpenCode sont découverts en interrogeant sa base de données SQLite à `~/.local/share/opencode/opencode.db` via `opencode db --format json` (nous lisons les tables `session` et `project` et les regroupons par `project_id`) ; les projets Pi sont découverts en analysant les transcriptions JSONL par session sous `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) et en extrayant le `cwd` du premier enregistrement de chaque session ; les projets Gemini CLI sont découverts en analysant `~/.gemini/tmp//chats/session--.jsonl` (configurable via `GEMINI_SESSIONS_DIR`) et en récupérant le répertoire de travail canonique depuis le marqueur texte `.project_root` associé ; les sessions de la passerelle Hermes sont lues directement depuis son stockage SQLite à `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) et regroupées en projets `hermes-` par `source` (Slack/Telegram/cli/cron — les sessions de passerelle n'ont pas de cwd). Un projet utilisé par plusieurs interfaces CLI s'affiche sur une seule ligne avec tous les badges correspondants. Utilisez le menu déroulant **CLI** au-dessus du tableau pour filtrer par interface CLI spécifique ; l'URL conserve votre sélection sous la forme `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Liste tous les projets Claude Code, OpenAI Codex, GitHub Copilot CLI _(bêta)_, Cursor Agent _(bêta)_, OpenCode _(bêta)_, Pi _(bêta)_ et Hermes trouvés sur votre machine. Les projets Claude sont découverts depuis `~/.claude/projects/` (ou le chemin défini par `CLAUDE_PROJECTS_PATH`) ; les projets Codex sont découverts en analysant chaque transcription sous `~/.codex/sessions///
/*.jsonl` et en les regroupant par le `cwd` enregistré dans le premier enregistrement de chaque session ; les projets Copilot CLI sont découverts en analysant chaque `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) et en les regroupant par leur champ `cwd` ; les projets Cursor Agent sont découverts en analysant les métadonnées par session sous `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, avec `conversations/` et `sessions/` comme solutions de repli) pour un scalaire `cwd` dans `meta.json` / `session.json` / `workspace.yaml` ; les projets OpenCode sont découverts en interrogeant sa base de données SQLite à `~/.local/share/opencode/opencode.db` via `opencode db --format json` (nous lisons les tables `session` et `project` et les regroupons par `project_id`) ; les projets Pi sont découverts en analysant les transcriptions JSONL par session sous `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) et en extrayant le `cwd` du premier enregistrement de chaque session ; les sessions de la passerelle Hermes sont lues directement depuis son stockage SQLite à `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) et regroupées en projets `hermes-` par `source` (Slack/Telegram/cli/cron — les sessions de passerelle n'ont pas de cwd). Un projet utilisé par plusieurs interfaces CLI s'affiche sur une seule ligne avec tous les badges correspondants. Utilisez le menu déroulant **CLI** au-dessus du tableau pour filtrer par interface CLI spécifique ; l'URL conserve votre sélection sous la forme `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Chaque projet affiche : - Le nom du projet (dérivé du chemin du dossier) -- Un badge CLI — `Claude Code` (orange), `OpenAI Codex` (violet), `GitHub Copilot` (bleu), `Cursor Agent` (émeraude), `OpenCode` (ambre), `Pi` (rose), `Gemini CLI` (bleu ciel) et/ou `Hermes` (indigo) +- Un badge CLI — `Claude Code` (orange), `OpenAI Codex` (violet), `GitHub Copilot` (bleu), `Cursor Agent` (émeraude), `OpenCode` (ambre), `Pi` (rose) et/ou `Hermes` (indigo) - La date de la dernière activité de session Cliquez sur un projet pour afficher ses sessions. @@ -47,7 +47,7 @@ Cliquez sur une session pour ouvrir le visualiseur de session. ### Visualiseur de session -Le visualiseur de session répond à la question essentielle pour les agents autonomes : qu'a fait l'agent, et est-il resté dans les limites prévues ? Un badge CLI à côté de l'en-tête indique si la session est une transcription Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI ou Hermes. Il affiche une chronologie de tout ce qui s'est passé lors d'une session : +Le visualiseur de session répond à la question essentielle pour les agents autonomes : qu'a fait l'agent, et est-il resté dans les limites prévues ? Un badge CLI à côté de l'en-tête indique si la session est une transcription Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ou Hermes. Il affiche une chronologie de tout ce qui s'est passé lors d'une session : - **Messages** - Les réponses textuelles de Claude et les invites utilisateur - **Appels d'outils** - Chaque outil invoqué par Claude, avec ses entrées et sorties @@ -55,7 +55,7 @@ Le visualiseur de session répond à la question essentielle pour les agents aut La barre de statistiques en haut affiche la durée de la session, le nombre total d'appels d'outils et un résumé des décisions de hook (nombre de allow / deny / instruct). -Cliquez sur le bouton **Télécharger les journaux** pour exporter la session. Pour les sessions Claude Code, Codex, Copilot, Cursor, Pi et Gemini, vous obtenez la transcription JSONL originale sur disque octet par octet ; pour OpenCode (dont les sessions résident dans SQLite et non sur disque), vous obtenez un document JSON reproduisant les tables sous-jacentes `session` / `messages` / `parts`. +Cliquez sur le bouton **Télécharger les journaux** pour exporter la session. Pour les sessions Claude Code, Codex, Copilot, Cursor et Pi, vous obtenez la transcription JSONL originale sur disque octet par octet ; pour OpenCode (dont les sessions résident dans SQLite et non sur disque), vous obtenez un document JSON reproduisant les tables sous-jacentes `session` / `messages` / `parts`. ### Audit @@ -75,16 +75,16 @@ Une page à deux onglets pour gérer les politiques et examiner l'activité. - - Sélectionnez plusieurs interfaces CLI d'agents que failproofai protège depuis un seul panneau — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI et Hermes disposent chacun d'une ligne avec le statut d'installation (`Active` / `Detected` / `Inactive`), le chemin des paramètres de portée utilisateur et un accent coloré à la marque. Cochez ou décochez les CLI souhaités et cliquez sur `Apply changes` pour installer/désinstaller les différences en une seule étape. Les CLI dont le binaire est détecté dans le PATH sont pré-cochés. + - Sélectionnez plusieurs interfaces CLI d'agents que failproofai protège depuis un seul panneau — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi et Hermes disposent chacun d'une ligne avec le statut d'installation (`Active` / `Detected` / `Inactive`), le chemin des paramètres de portée utilisateur et un accent coloré à la marque. Cochez ou décochez les CLI souhaités et cliquez sur `Apply changes` pour installer/désinstaller les différences en une seule étape. Les CLI dont le binaire est détecté dans le PATH sont pré-cochés. - Activez ou désactivez des politiques individuelles d'un simple clic (écrit dans `~/.failproofai/policies-config.json` — partagé entre tous les CLI installés) - Développez une politique pour configurer ses paramètres (pour les politiques prenant en charge `policyParams`) - Définissez un chemin de fichier de politiques personnalisé - Historique paginé complet de chaque événement de hook déclenché dans toutes les sessions - - Filtrer par décision, type d'événement, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(bêta)_ / Cursor Agent _(bêta)_ / OpenCode _(bêta)_ / Pi _(bêta)_ / Gemini CLI _(bêta)_ / Hermes), nom de politique ou identifiant de session - - Chaque ligne affiche : horodatage, nom de la politique, décision, badge CLI (orange = Claude Code, violet = OpenAI Codex, bleu = GitHub Copilot, émeraude = Cursor Agent, ambre = OpenCode, rose = Pi, bleu ciel = Gemini CLI, indigo = Hermes), nom de l'outil, identifiant de session et la raison des décisions deny/instruct - - Cliquez sur un identifiant de session pour ouvrir sa transcription — le visualiseur détecte automatiquement quel CLI a déclenché le hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) et affiche le badge CLI correspondant dans l'en-tête + - Filtrer par décision, type d'événement, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(bêta)_ / Cursor Agent _(bêta)_ / OpenCode _(bêta)_ / Pi _(bêta)_ / Hermes), nom de politique ou identifiant de session + - Chaque ligne affiche : horodatage, nom de la politique, décision, badge CLI (orange = Claude Code, violet = OpenAI Codex, bleu = GitHub Copilot, émeraude = Cursor Agent, ambre = OpenCode, rose = Pi, indigo = Hermes), nom de l'outil, identifiant de session et la raison des décisions deny/instruct + - Cliquez sur un identifiant de session pour ouvrir sa transcription — le visualiseur détecte automatiquement quel CLI a déclenché le hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) et affiche le badge CLI correspondant dans l'en-tête diff --git a/docs/fr/getting-started.mdx b/docs/fr/getting-started.mdx index 38af4f5f..41db3c71 100644 --- a/docs/fr/getting-started.mdx +++ b/docs/fr/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Cette commande inscrit des entrées de hook dans vos CLIs d'agent installés (le `~/.claude/settings.json` de Claude Code, le `~/.codex/hooks.json` d'OpenAI Codex, le `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, le `~/.cursor/hooks.json` de Cursor Agent, le shim de plugin généré par OpenCode à `~/.config/opencode/plugins/failproofai.mjs` ainsi qu'une entrée d'enregistrement dans le tableau `plugin` de `~/.config/opencode/opencode.json`, le `~/.pi/agent/settings.json` de Pi, le `~/.gemini/settings.json` de Gemini CLI, ou le `~/.hermes/config.yaml` de Hermes). Si plusieurs sont présents, une invite s'affichera ; passez `--cli claude codex copilot cursor opencode pi gemini hermes` (tout sous-ensemble) pour ignorer l'invite. + Cette commande inscrit des entrées de hook dans vos CLIs d'agent installés (le `~/.claude/settings.json` de Claude Code, le `~/.codex/hooks.json` d'OpenAI Codex, le `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, le `~/.cursor/hooks.json` de Cursor Agent, le shim de plugin généré par OpenCode à `~/.config/opencode/plugins/failproofai.mjs` ainsi qu'une entrée d'enregistrement dans le tableau `plugin` de `~/.config/opencode/opencode.json`, le `~/.pi/agent/settings.json` de Pi, ou le `~/.hermes/config.yaml` de Hermes). Si plusieurs sont présents, une invite s'affichera ; passez `--cli claude codex copilot cursor opencode pi hermes` (tout sous-ensemble) pour ignorer l'invite. - La prise en charge de GitHub Copilot CLI, Cursor Agent, OpenCode, Pi et Gemini CLI est en **bêta** — installez avec `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` ou `--cli gemini`. Hermes (hermes-agent, une passerelle Slack/Telegram) s'installe en portée utilisateur avec `--cli hermes` et constitue **également** une source d'audit hors ligne. + La prise en charge de GitHub Copilot CLI, Cursor Agent, OpenCode et Pi est en **bêta** — installez avec `--cli copilot`, `--cli cursor`, `--cli opencode` ou `--cli pi`. Hermes (hermes-agent, une passerelle Slack/Telegram) s'installe en portée utilisateur avec `--cli hermes` et constitue **également** une source d'audit hors ligne. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/fr/introduction.mdx b/docs/fr/introduction.mdx index 7bafb798..cca8707d 100644 --- a/docs/fr/introduction.mdx +++ b/docs/fr/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI offre aux agents IA 39 politiques de sécurité intég [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks et politiques pour la **gestion des défaillances IA**, la **récupération après erreur** et la **fiabilité des LLM**. Gardez vos agents IA fiables et autonomes sur **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** et l'**Agents SDK**. +Hooks et politiques pour la **gestion des défaillances IA**, la **récupération après erreur** et la **fiabilité des LLM**. Gardez vos agents IA fiables et autonomes sur **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** et l'**Agents SDK**. Les agents IA échouent de manière prévisible. Ils exécutent des commandes destructrices, exposent des secrets, dérivent hors de leur tâche, se retrouvent bloqués dans des boucles ou poussent directement sur la branche principale. Laissées sans surveillance, de petites défaillances se transforment en pannes, en identifiants compromis et en travail perdu. diff --git a/docs/getting-started.mdx b/docs/getting-started.mdx index ae2179be..4dd58bc8 100644 --- a/docs/getting-started.mdx +++ b/docs/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - This writes hook entries into your installed agent CLIs (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, or Hermes's `~/.hermes/config.yaml`). When more than one is present you'll be prompted; pass `--cli claude codex copilot cursor opencode pi gemini hermes` (any subset) to skip the prompt. + This writes hook entries into your installed agent CLIs (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Hermes's `~/.hermes/config.yaml`, OpenClaw's `~/.openclaw/openclaw.json`, Factory Droid's `~/.factory/hooks.json`, Devin CLI's `~/.config/devin/config.json`, Antigravity CLI's `~/.gemini/config/hooks.json`, or Goose's auto-discovered plugin dir at `~/.agents/plugins/failproofai/hooks/hooks.json`). When more than one is present you'll be prompted; pass `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (any subset) to skip the prompt. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, and Gemini CLI support are **beta** — install with `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, or `--cli gemini`. Hermes (hermes-agent, a Slack/Telegram gateway) installs user-scope with `--cli hermes` and is **also** an offline audit source. + GitHub Copilot CLI, Cursor Agent, OpenCode, and Pi support are **beta** — install with `--cli copilot`, `--cli cursor`, `--cli opencode`, or `--cli pi`. Hermes (hermes-agent, a Slack/Telegram gateway) installs user-scope with `--cli hermes` and is **also** an offline audit source. OpenClaw (openclaw gateway, a self-hosted multi-channel assistant) installs user-scope with `--cli openclaw` — enforcement runs through its in-process plugin hooks (`before_agent_finalize` is a real turn-end gate, so the `require-*-before-stop` builtins enforce) — and is **also** an offline audit source. Factory Droid (`droid`) installs with `--cli factory` (user + project scope) and is **also** an offline audit source. Devin CLI (`devin`, Cognition) installs with `--cli devin` (user + project scope) and is **also** an offline audit source. Antigravity CLI (`agy`) installs with `--cli antigravity` (user + project scope) and is **also** an offline audit source. Goose (codename goose, Block) installs with `--cli goose` (user + project scope) — the installer just drops a plugin dir at `~/.agents/plugins/failproofai/` that Goose auto-discovers, and it is **also** an offline audit source. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/he/built-in-policies.mdx b/docs/he/built-in-policies.mdx index 38dfc8bc..1b418f5d 100644 --- a/docs/he/built-in-policies.mdx +++ b/docs/he/built-in-policies.mdx @@ -710,7 +710,7 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### סמנטיקה Stop של לפי-CLI -אכיפת Stop נראית שונה במעט על פני שבעת ה-CLI הנתמכים כי לכל אחד יש חוזה hook של סיום סוכן שונה. ה-**outcome** זהה — הסוכן לא יוצא עם עצירה בזמן שער זרימת עבודה נכשל — אך ה-**mechanics** שונים. הטבלה להלן מסכמת; רק Pi יש פרמיה המשתמש בעיר שכדאי להבין לפני שתאפשר מדיניות `require-*-before-stop`. +אכיפת Stop נראית שונה במעט על פני ששת ה-CLI הנתמכים כי לכל אחד יש חוזה hook של סיום סוכן שונה. ה-**outcome** זהה — הסוכן לא יוצא עם עצירה בזמן שער זרימת עבודה נכשל — אך ה-**mechanics** שונים. הטבלה להלן מסכמת; רק Pi יש פרמיה המשתמש בעיר שכדאי להבין לפני שתאפשר מדיניות `require-*-before-stop`. | CLI | כשעוצר השער | מה שאתה רואה | |---|---|---| @@ -718,20 +718,19 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ | Codex | אותו לולאת סוכן, מיד | זהה ל-Claude. | | GitHub Copilot CLI | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ ממשכה `{decision:"block", reason}` של Copilot — מאומת אמפיריות נגד Copilot CLI 1.0.41). | | Cursor Agent | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ `{followup_message}` של Cursor — מתוקבל ב-`loop_limit`, ברירת מחדל 5 ניסיונות חוזרים). | -| Gemini CLI | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ `{decision:"block", reason}` של Gemini על `AfterAgent`). | | OpenCode | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בקריאת SDK `client.session.prompt(...)` של OpenCode מנוטרלת דרך `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **תור משתמש הבא** | **Pi עוצר בצורה נראית** כשהשער עוצר — לולאת הסוכן שלו יוצאת ואתה חוזר ללתזמון. השער אז עוצר בפעם הבאה שאתה שולח תזמון: failproofai מקדים הנחיה `MANDATORY ACTION REQUIRED` לתזמון הסיסטם של הסיבוב הזה, נוקט את ה-LLM להשלים את שלב זרימת העבודה (commit, push, וכו') לפני עשיית מה שביקשת. | -**מגבלה של Pi.** `AgentEndEvent` של Pi (המקבילה הזרם של אירוע `Stop` של Claude) אין סוג תוצאה — ברגע שהוא עוצר, לולאת הסוכן של Pi כבר יצאה. Pi לא יכול להילחם להחזור לאותה לולאה בדרך שClaude / Copilot / Cursor / Gemini / OpenCode יכולים. failproofai מעביר את השער לאירוע `before_agent_start` של Pi (שעוצר אחרי התזמון הבא של המשתמש) כדי שבדיקת זרימת העבודה עדיין אוכפת, רק בסיבוב הבא במקום הנוכחי. +**מגבלה של Pi.** `AgentEndEvent` של Pi (המקבילה הזרם של אירוע `Stop` של Claude) אין סוג תוצאה — ברגע שהוא עוצר, לולאת הסוכן של Pi כבר יצאה. Pi לא יכול להילחם להחזור לאותה לולאה בדרך שClaude / Copilot / Cursor / OpenCode יכולים. failproofai מעביר את השער לאירוע `before_agent_start` של Pi (שעוצר אחרי התזמון הבא של המשתמש) כדי שבדיקת זרימת העבודה עדיין אוכפת, רק בסיבוב הבא במקום הנוכחי. **מה זה אומר בפרקטיקה:** - אחרי שPi עוצר, סיבת ה-deny נתפסה בזיכרון מפתח אחרי מזהה סשן Pi. התזמון הבא בדיוק שאתה שולח באותו תהליך Pi סוך את זה: ה-LLM רואה את ההנחיה `MANDATORY ACTION REQUIRED` בחלק העליון של תזמון הסיסטם שלו, commits (או דוחף / פותח את ה-PR / מחכה ל-CI), רק אחרי כן ממשיך עם בקשתך. סיבת ה-deny שתפסה היא one-shot — ברגע שסוך, השער ברור. -- השער מותחם על ידי חיי תהליך של Pi. אם `Ctrl+C` Pi או יוצא בין סיבובים, הערך בזיכרון בזיכרון מושלך יחד עם התהליך ואת השער מיסה. Claude, Copilot, Cursor, Gemini ו-OpenCode יש את אותו כולמן (הרוג את הסוכן ואת השער מיסה) — Pi פשוט עושה את זה יותר נראית כי הסוכן יוצא בצורה נראית לפני ש-פיר עוצר. +- השער מותחם על ידי חיי תהליך של Pi. אם `Ctrl+C` Pi או יוצא בין סיבובים, הערך בזיכרון בזיכרון מושלך יחד עם התהליך ואת השער מיסה. Claude, Copilot, Cursor ו-OpenCode יש את אותו כולמן (הרוג את הסוכן ואת השער מיסה) — Pi פשוט עושה את זה יותר נראית כי הסוכן יוצא בצורה נראית לפני ש-פיר עוצר. - deny ממתין הוא גם ברור על `session_shutdown` לכל סיבה (`new` / `resume` / `fork` / `quit`), כך שערט שנגרד מסשן קודם לא יכול לדלוף לסשן טרי שהחל באותו תהליך Pi. -אם אתה צריך retry זהה לClaude של אותו לולאה, הרץ את המדיניויות `Stop` שלך תחת כל אחד משש ה-CLI הנתמכים האחרים. אנחנו עוקבים אחרי Pi קודם לעתיד סוג תוצאה על `AgentEndEvent` שיתן לנו לסגור את הפער הזה. +אם אתה צריך retry זהה לClaude של אותו לולאה, הרץ את המדיניויות `Stop` שלך תחת כל אחד מחמש ה-CLI הנתמכים האחרים. אנחנו עוקבים אחרי Pi קודם לעתיד סוג תוצאה על `AgentEndEvent` שיתן לנו לסגור את הפער הזה. ### `require-commit-before-stop` diff --git a/docs/he/cli/audit.mdx b/docs/he/cli/audit.mdx index b77abfba..d4abe139 100644 --- a/docs/he/cli/audit.mdx +++ b/docs/he/cli/audit.mdx @@ -52,7 +52,7 @@ failproofai עד שתעצור אותו עם `Ctrl+C`. -לוח המחוונים סורק תמלילי agent CLI קודמים במכונה זו (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) ודיווח כמה פעמים הסוכן עשה דברים שמבנה failproofai כדי לעצור — בדיקות משתנות סביבה, כפיות דחיפה, קידומות `cd ` מיותרות, לולאות sleep-polling, קריאה חוזרת של קבצים שנערכו זה עתה, ועוד. +לוח המחוונים סורק תמלילי agent CLI קודמים במכונה זו (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) ודיווח כמה פעמים הסוכן עשה דברים שמבנה failproofai כדי לעצור — בדיקות משתנות סביבה, כפיות דחיפה, קידומות `cd ` מיותרות, לולאות sleep-polling, קריאה חוזרת של קבצים שנערכו זה עתה, ועוד. לכל תמליל, כל אירוע tool-use משמר מחדש דרך 39 המדיניויות המובנות **וגם** דרך 8 גלאים audit-only שתופסים דפוסים שעדיין לא מכוסים על ידי מדיניויות זמן ריצה. הספירות מצטברות לכל מדיניות / גלאי על פני כל הפעלות. diff --git a/docs/he/configuration.mdx b/docs/he/configuration.mdx index 24e3cda4..f1f81270 100644 --- a/docs/he/configuration.mdx +++ b/docs/he/configuration.mdx @@ -196,13 +196,12 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← יורד לכלל ה - **OpenAI Codex**: `~/.codex/hooks.json` (משתמש), `/.codex/hooks.json` (פרויקט) — Codex אין לו היקף `local` - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (משתמש), `/.github/hooks/failproofai.json` (פרויקט) — Copilot אין לו היקף `local`. רשומות Hook משתמשות בשדות פקודה `bash`/`powershell` של Copilot עם מפתח OS עם `timeoutSec`; הקובץ נושא סימן `version: 1` ברמה העליונה. תמיכת Copilot CLI היא **beta** בעודנו מאמתים את סכימת רשומת `events.jsonl` (שהדוקים הציבוריים אינם מציינים) מול יותר ישיבות בעולם האמיתי. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (משתמש), `/.cursor/hooks.json` (פרויקט) — Cursor אין לו היקף `local`. רשומות Hook משתמשות בצורה בעיצוב Claude `{type, command, timeout}` (לא פיצול `bash`/`powershell`), אך מאוחסנות תחת מפתחות אירוע camelCase (`preToolUse`, `beforeSubmitPrompt`, …) במערך שטוח לכל [סכימת hooks של Cursor](https://cursor.com/docs/hooks); הקובץ נושא סימן `version: 1` ברמה העליונה. המטפל מנרמל camelCase → PascalCase דרך `CURSOR_EVENT_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. תמיכת Cursor Agent היא **beta** בעודנו מאמתים את קובץ הטרנסקריפט של Cursor (לא מצוין בדוקים הציבוריים) מול יותר התקנות בעולם האמיתי. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (משתמש), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (פרויקט) — OpenCode אין לו היקף `local`. בשונה משש ה-CLI האחרים, OpenCode **אין לו מערכת hook פקודה חיצונית**: הוא טוען בתוך התהליך תוספי JS/TS שנרשמו במפורש דרך מערך `plugin: []` ב`opencode.json` (גילוי אוטומטי מ`.opencode/plugins/` **אינו** כיצד תוספים נטענים ב-opencode v1.14.33). ההתקנה מושכת שים של תוספון שנוצר בזריעה שקוראות ב-subprocess את הבינארי failproofai ומתרגמת את התגובה JSON בעיצוב Claude של הבינארי חזרה לסמנטיקה של תוספון: `throw new Error()` עבור deny של אירוע כלי (מבטל את קריאת הכלי), `client.session.prompt(...)` עבור instruct וגם עבור deny של `Stop` / `SubagentStop` (משדרת את סיבת הreject כהודעת המשתמש הבאה — הערוץ היחיד כלומל-retry מכיוון ש`session.idle` הוא התראה בלבד ו-throwing ממנו הוא no-op), ו-no-op עבור allow. השם מנרמל גם שמות כלים (אותיות קטנות → PascalCase דרך `OPENCODE_TOOL_MAP`) וגם מפתחות טיעון קלט כלי (camelCase → snake_case דרך `OPENCODE_TOOL_INPUT_MAP` עבור `Read` / `Write` / `Edit`, לדוגמה `filePath` → `file_path`, `oldString` → `old_string`) לפני שליחה קדימה לבינארי, כך שבדיקות נתיב מובנות כמו `block-read-outside-cwd`, `block-env-files`, ו`block-secrets-write` נשרפות ללא שינוי בקריאות כלים OpenCode. ישיבות חיות בבסיס נתונים SQLite של opencode ב`~/.local/share/opencode/opencode.db`; צופה הישיבה של הדשבורד קורא להם דרך `opencode db --format json` ו`opencode export `. תמיכת OpenCode היא **beta** בעודנו מאמתים התנהגות על פני גרסאות ומול יותר ישיבות בעולם האמיתי. ראה את [דוקים של תוספי OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (משתמש), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (פרויקט) — OpenCode אין לו היקף `local`. בשונה מחמש ה-CLI האחרים, OpenCode **אין לו מערכת hook פקודה חיצונית**: הוא טוען בתוך התהליך תוספי JS/TS שנרשמו במפורש דרך מערך `plugin: []` ב`opencode.json` (גילוי אוטומטי מ`.opencode/plugins/` **אינו** כיצד תוספים נטענים ב-opencode v1.14.33). ההתקנה מושכת שים של תוספון שנוצר בזריעה שקוראות ב-subprocess את הבינארי failproofai ומתרגמת את התגובה JSON בעיצוב Claude של הבינארי חזרה לסמנטיקה של תוספון: `throw new Error()` עבור deny של אירוע כלי (מבטל את קריאת הכלי), `client.session.prompt(...)` עבור instruct וגם עבור deny של `Stop` / `SubagentStop` (משדרת את סיבת הreject כהודעת המשתמש הבאה — הערוץ היחיד כלומל-retry מכיוון ש`session.idle` הוא התראה בלבד ו-throwing ממנו הוא no-op), ו-no-op עבור allow. השם מנרמל גם שמות כלים (אותיות קטנות → PascalCase דרך `OPENCODE_TOOL_MAP`) וגם מפתחות טיעון קלט כלי (camelCase → snake_case דרך `OPENCODE_TOOL_INPUT_MAP` עבור `Read` / `Write` / `Edit`, לדוגמה `filePath` → `file_path`, `oldString` → `old_string`) לפני שליחה קדימה לבינארי, כך שבדיקות נתיב מובנות כמו `block-read-outside-cwd`, `block-env-files`, ו`block-secrets-write` נשרפות ללא שינוי בקריאות כלים OpenCode. ישיבות חיות בבסיס נתונים SQLite של opencode ב`~/.local/share/opencode/opencode.db`; צופה הישיבה של הדשבורד קורא להם דרך `opencode db --format json` ו`opencode export `. תמיכת OpenCode היא **beta** בעודנו מאמתים התנהגות על פני גרסאות ומול יותר ישיבות בעולם האמיתי. ראה את [דוקים של תוספי OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (משתמש), `/.pi/settings.json` (פרויקט) — Pi אין לו היקף `local`. Pi טוען חבילות הרחבה TypeScript בעת ההתחלה; קובץ ההגדרות הוא מערך מחרוזות שטוח `{"packages": ["./relative/path", …]}`. failproofai כותב רשומת מערך פקיות אחת המצביעה על תיקיית `pi-extension/` המכוסה שלה. ההרחבה מחתום פנימית על אירועי `tool_call` / `user_bash` / `input` / `session_start` של Pi ופורקת `failproofai --hook --cli pi`; המטפל מנרמל underscore_lower_snake_case → PascalCase דרך `PI_EVENT_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. טיעון קלט כלי מנורמל גם דרך `PI_TOOL_INPUT_MAP` (Read / Write / Edit של Pi משדרות `path` ולא `file_path`; מיפוי המפתח ברמה העליונה מאפשר ל`block-env-files` ו`block-secrets-write` נשרפות — `block-read-outside-cwd` כבר היה פנייה חוזרת של `path`). תמיכת Pi היא **beta** בזמן שה-API הרחבה של Pi וסכימת יומן הישיבה מתייצבות. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (משתמש), `/.gemini/settings.json` (פרויקט) — Gemini אין לו היקף `local` (הוא מתעד היקף `system` ב`/etc/gemini-cli/settings.json` שfalieproofai אינו חושף). רשומות Hook משתמשות בצורה `{type, command, timeout}` של Claude מגולפת בסכימת matcher של Gemini `{matcher, hooks: [...]}` עם `matcher: "*"` כברירת מחדל. אירועים הם PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); המטפל ממפה לשמות הקנוניים של Claude דרך `GEMINI_EVENT_MAP`. שמות כלים הם snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — המטפל מנרמל דרך `GEMINI_TOOL_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. מעריך המדיניות משדרת צורה שטוחה של Gemini `{decision: "deny", reason}` (מעדיפה לפי הכלל הזהב של Gemini exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` להזרקת הקשר על BeforeAgent / AfterTool / SessionStart, ו`{decision: "block", reason}` על AfterAgent עבור סמנטיקת כפיית retry. תמיכת Gemini CLI היא **beta** בעודנו מרחיבים כיסוי בעולם אמיתי. ראה את [דוקים של hooks של Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**היקף משתמש בלבד** — Hermes אין לו תצורת פרויקט/מקומית). Hermes הוא **שער** Slack/Telegram, כך שהתקנה אחת מיירטת קריאות כלים מכל פלטפורמה (Slack/Telegram/cli/cron) **וגם** תוך-אג'נטים. רשומות Hook הן זוג `{command, timeout}` (timeout בשניות) תחת מפת `hooks:` שבאופן events snake_case של Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); המטפל מנרמל אירועים דרך `HERMES_EVENT_MAP` וגם שמות כלים דרך `HERMES_TOOL_MAP` כך שמדיניות מובנות נשרפות ללא שינוי. התצורה נערכת דרך תעודת YAML דורכת-שומרת-הערות `Document` כך שהגדרות אחרות של המנהל שורדות, והתקנה מוגדרת `hooks_auto_accept: true` כך השער חסר-TTY מריץ את ה-hooks ללא בקשת הסכמה. המעריך משדרת חוזה `{"decision":"block","reason"}` stdout של Hermes (Hermes מתעלם מקודי יציאה). **מגבלות:** Hermes אין להשקע stop `Stop` של turn-end, כך שה`require-*-before-stop` מובנה לעולם לא נשרפים עבורו (בלא הגבלה, לא שבור); `instruct` מדרדר ל-allow-עם-logged-note (אין ערוץ הקשר נוסף); ו-redaction-secret של פלט (`sanitize-*`) לא יכול לשכתב פלט כלים דרך חוזה shell-hook. Hermes הוא **גם** מקור ביקורת **offline** — הדשבורד קורא ישיבות שער שלו ישירות מ`~/.hermes/state.db`. - **`policies-config.json`** — אומר ל-failproofai איזו מדיניות להעריך ועם אילו פרמטרים (משותף על פני כל ה-CLI של ה-agent) -עבור `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` למטרה סוכן ספציפי (space-separated או חוזר לכל תת-קבוצה): +עבור `--cli claude|codex|copilot|cursor|opencode|pi|hermes` למטרה סוכן ספציפי (space-separated או חוזר לכל תת-קבוצה): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -כאשר `--cli` מושמט, `failproofai` מגלה אילו CLI של agent מותקנות (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +כאשר `--cli` מושמט, `failproofai` מגלה אילו CLI של agent מותקנות (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **CLI אחד זוהה** — בחירה אוטומטית של ה-CLI הזה ללא הנחיות. - **מספר CLI זוהו** בטרמינל אינטראקטיבי — מציג הנחיות בחירה חד-בחירה בחצי-מקלדת מקובצות לחלק `Detected (N)` (עם שורה מצומצמת `Install for all N detected` + כל CLI זוהה בנפרד) וחלק `Not installed (M) · install hooks ahead of time` הרשום כל CLI לא זוהה שנתמך כאפשרות התקנה קדימה (↑↓ להזיז, Enter בחר, ^C יצא). זרימת ההסרה מציגה רק את החלק Detected. diff --git a/docs/he/dashboard.mdx b/docs/he/dashboard.mdx index 50ffc990..b3591357 100644 --- a/docs/he/dashboard.mdx +++ b/docs/he/dashboard.mdx @@ -25,11 +25,11 @@ failproofai ### Projects -מפרט את כל Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, ו-Hermes שנמצאו במחשב שלך. פרויקטי Claude מגולים מ-`~/.claude/projects/` (או הנתיב שנקבע על ידי `CLAUDE_PROJECTS_PATH`); פרויקטי Codex מגולים על ידי סריקת כל תמליל תחת `~/.codex/sessions///
/*.jsonl` וקיבוץ לפי `cwd` שנרשם בתיעוד הראשון של ההפעלה; פרויקטי Copilot CLI מגולים על ידי סריקת כל `~/.copilot/session-state//workspace.yaml` (ניתן להגדיר דרך `COPILOT_HOME`) וקיבוץ לפי שדה `cwd` שלו; פרויקטי Cursor Agent מגולים על ידי סריקת מטא-נתונים לכל הפעלה תחת `~/.cursor/agent-sessions//` (ניתן להגדיר דרך `CURSOR_HOME`, עם סדרי גיבוי `conversations/` ו-`sessions/`) עבור סקלר `cwd` ב-`meta.json` / `session.json` / `workspace.yaml`; פרויקטי OpenCode מגולים על ידי שאילתת SQLite DB שלה ב-`~/.local/share/opencode/opencode.db` דרך `opencode db --format json` (אנו קוראים את טבלאות `session` ו-`project` וקיבוץ לפי `project_id`); פרויקטי Pi מגולים על ידי סריקת תמליל JSONL לכל הפעלה תחת `~/.pi/agent/sessions//_.jsonl` (ניתן להגדיר דרך `PI_SESSIONS_DIR`) ושליפת `cwd` מתיעוד הראשון של כל הפעלה; פרויקטי Gemini CLI מגולים על ידי סריקת `~/.gemini/tmp//chats/session--.jsonl` (ניתן להגדיר דרך `GEMINI_SESSIONS_DIR`) והחזרת ה-cwd הקנוני ממסמן `.project_root` הסמוך; הפעלות שער Hermes נקראות ישירות מחנות SQLite שלה ב-`~/.hermes/state.db` (ניתן להגדיר דרך `HERMES_DB_PATH`) וקיבוץ לפרויקטי `hermes-` לפי `source` (Slack/Telegram/cli/cron — להפעלות שער אין cwd). פרויקט ששימש מספר CLIs מרואה כשורה יחידה עם כל התגים המתאימים. השתמש בתפריט **CLI** מעל הטבלה לסינון לפי סוכן CLI ספציפי; ה-URL משמר את הבחירה שלך כ-`?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +מפרט את כל Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, ו-Hermes שנמצאו במחשב שלך. פרויקטי Claude מגולים מ-`~/.claude/projects/` (או הנתיב שנקבע על ידי `CLAUDE_PROJECTS_PATH`); פרויקטי Codex מגולים על ידי סריקת כל תמליל תחת `~/.codex/sessions///
/*.jsonl` וקיבוץ לפי `cwd` שנרשם בתיעוד הראשון של ההפעלה; פרויקטי Copilot CLI מגולים על ידי סריקת כל `~/.copilot/session-state//workspace.yaml` (ניתן להגדיר דרך `COPILOT_HOME`) וקיבוץ לפי שדה `cwd` שלו; פרויקטי Cursor Agent מגולים על ידי סריקת מטא-נתונים לכל הפעלה תחת `~/.cursor/agent-sessions//` (ניתן להגדיר דרך `CURSOR_HOME`, עם סדרי גיבוי `conversations/` ו-`sessions/`) עבור סקלר `cwd` ב-`meta.json` / `session.json` / `workspace.yaml`; פרויקטי OpenCode מגולים על ידי שאילתת SQLite DB שלה ב-`~/.local/share/opencode/opencode.db` דרך `opencode db --format json` (אנו קוראים את טבלאות `session` ו-`project` וקיבוץ לפי `project_id`); פרויקטי Pi מגולים על ידי סריקת תמליל JSONL לכל הפעלה תחת `~/.pi/agent/sessions//_.jsonl` (ניתן להגדיר דרך `PI_SESSIONS_DIR`) ושליפת `cwd` מתיעוד הראשון של כל הפעלה; הפעלות שער Hermes נקראות ישירות מחנות SQLite שלה ב-`~/.hermes/state.db` (ניתן להגדיר דרך `HERMES_DB_PATH`) וקיבוץ לפרויקטי `hermes-` לפי `source` (Slack/Telegram/cli/cron — להפעלות שער אין cwd). פרויקט ששימש מספר CLIs מרואה כשורה יחידה עם כל התגים המתאימים. השתמש בתפריט **CLI** מעל הטבלה לסינון לפי סוכן CLI ספציפי; ה-URL משמר את הבחירה שלך כ-`?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. כל פרויקט מציג: - שם הפרויקט (מגובש מנתיב התיקייה) -- תג CLI — `Claude Code` (כתום), `OpenAI Codex` (סגול), `GitHub Copilot` (כחול), `Cursor Agent` (אזמרגד), `OpenCode` (ענבר), `Pi` (ורוד), `Gemini CLI` (שמיים), ו/או `Hermes` (אינדיגו) +- תג CLI — `Claude Code` (כתום), `OpenAI Codex` (סגול), `GitHub Copilot` (כחול), `Cursor Agent` (אזמרגד), `OpenCode` (ענבר), `Pi` (ורוד), ו/או `Hermes` (אינדיגו) - תאריך של פעילות הפעלה האחרונה לחץ על פרויקט כדי לראות את הפעלות שלו. @@ -48,7 +48,7 @@ failproofai ### מצפה הפעלה -מצפה הפעלה עונה על השאלה המרכזית לסוכנים אוטונומיים: מה עשה הסוכן, והאם הוא נשאר בעקוב? תג CLI ליד הכותרת מציין אם ההפעלה היא Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, או תמליל Hermes. הוא מציג ציר הזמן של כל מה שקרה בהפעלה: +מצפה הפעלה עונה על השאלה המרכזית לסוכנים אוטונומיים: מה עשה הסוכן, והאם הוא נשאר בעקוב? תג CLI ליד הכותרת מציין אם ההפעלה היא Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, או תמליל Hermes. הוא מציג ציר הזמן של כל מה שקרה בהפעלה: - **הודעות** - תגובות טקסט של Claude והנחיות משתמש - **קריאות כלים** - כל כלי שקרא Claude, עם הקלט והפלט שלו @@ -56,7 +56,7 @@ failproofai סרגל הנתונים בחלק העליון מציג משך הפעלה, סה"כ קריאות כלים, וסיכום החלטות קורא (ספירות allow / deny / instruct). -לחץ על כפתור **Download Logs** כדי לייצא את ההפעלה. עבור Claude Code, Codex, Copilot, Cursor, Pi, ו-Gemini תקבל את תמליל JSONL המקורי על הדיסק בדיוק כפי שהוא; עבור OpenCode (שהפעלות שלה חיות ב-SQLite, לא על הדיסק) תקבל מסמך JSON המשקף את טבלאות `session` / `messages` / `parts` הבסיסיות. +לחץ על כפתור **Download Logs** כדי לייצא את ההפעלה. עבור Claude Code, Codex, Copilot, Cursor, ו-Pi תקבל את תמליל JSONL המקורי על הדיסק בדיוק כפי שהוא; עבור OpenCode (שהפעלות שלה חיות ב-SQLite, לא על הדיסק) תקבל מסמך JSON המשקף את טבלאות `session` / `messages` / `parts` הבסיסיות. ### Audit @@ -76,16 +76,16 @@ failproofai - - בחר מספר כלים את סוכני ה-CLI שעליהם failproofai מגן מלוח יחיד — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, ו-Hermes כולם בעלי שורה עם סטטוס התקנה (`Active` / `Detected` / `Inactive`), נתיב הגדרות הטווח השנייה משתמש, והדגש צבע ממותג. בדוק או בטל את בדיקת ה-CLIs שאתה רוצה לחץ על `Apply changes` כדי להתקין/הסר את ההבדל בשלב אחד. CLIs שהבינארית שלהם מגולה ב-PATH מסומנים מראש. + - בחר מספר כלים את סוכני ה-CLI שעליהם failproofai מגן מלוח יחיד — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, ו-Hermes כולם בעלי שורה עם סטטוס התקנה (`Active` / `Detected` / `Inactive`), נתיב הגדרות הטווח השנייה משתמש, והדגש צבע ממותג. בדוק או בטל את בדיקת ה-CLIs שאתה רוצה לחץ על `Apply changes` כדי להתקין/הסר את ההבדל בשלב אחד. CLIs שהבינארית שלהם מגולה ב-PATH מסומנים מראש. - כיבוי או הדלקת מדיניות בודדות בלחיצה יחידה (כתיבה ל-`~/.failproofai/policies-config.json` — משותפת לכל CLI מותקן) - הרחב מדיניות כדי להגדיר את הפרמטרים שלה (עבור מדיניות התומכות `policyParams`) - קבע נתיב קובץ מדיניות מותאם - מלא היסטוריית עמודים של כל אירוע קורא שנשדר על כל הפעלות - - סנן לפי החלטה, סוג אירוע, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), שם מדיניות, או מזהה הפעלה - - כל שורה מציגה: חותמת זמן, שם מדיניות, החלטה, תג CLI (כתום = Claude Code, סגול = OpenAI Codex, כחול = GitHub Copilot, אזמרגד = Cursor Agent, ענבר = OpenCode, ורוד = Pi, שמיים = Gemini CLI, אינדיגו = Hermes), שם כלים, מזהה הפעלה, והסיבה להחלטות deny/instruct - - לחץ על מזהה הפעלה כדי לפתוח את התמליל שלה — מצפה גילוי אוטומטי אילו CLI נשדרה קורא (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) ומעניק את תג ה-CLI התואם בכותרת + - סנן לפי החלטה, סוג אירוע, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), שם מדיניות, או מזהה הפעלה + - כל שורה מציגה: חותמת זמן, שם מדיניות, החלטה, תג CLI (כתום = Claude Code, סגול = OpenAI Codex, כחול = GitHub Copilot, אזמרגד = Cursor Agent, ענבר = OpenCode, ורוד = Pi, אינדיגו = Hermes), שם כלים, מזהה הפעלה, והסיבה להחלטות deny/instruct + - לחץ על מזהה הפעלה כדי לפתוח את התמליל שלה — מצפה גילוי אוטומטי אילו CLI נשדרה קורא (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) ומעניק את תג ה-CLI התואם בכותרת diff --git a/docs/he/getting-started.mdx b/docs/he/getting-started.mdx index 90d45c29..7a1b25fb 100644 --- a/docs/he/getting-started.mdx +++ b/docs/he/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - זה כותב ערכי hook ל-CLI של סוכנים מותקנים (Claude Code של `~/.claude/settings.json`, OpenAI Codex של `~/.codex/hooks.json`, GitHub Copilot CLI של `~/.copilot/hooks/failproofai.json`, Cursor Agent של `~/.cursor/hooks.json`, OpenCode של plugin shim שנוצר ב-`~/.config/opencode/plugins/failproofai.mjs` בתוספת ערך רישום במערך `plugin` של `~/.config/opencode/opencode.json`, Pi של `~/.pi/agent/settings.json`, Gemini CLI של `~/.gemini/settings.json`, או Hermes של `~/.hermes/config.yaml`). כאשר יותר מאחד קיים תתבקע לבחור; העבר `--cli claude codex copilot cursor opencode pi gemini hermes` (כל קבוצה משנית) כדי לדלג על ההודעה. + זה כותב ערכי hook ל-CLI של סוכנים מותקנים (Claude Code של `~/.claude/settings.json`, OpenAI Codex של `~/.codex/hooks.json`, GitHub Copilot CLI של `~/.copilot/hooks/failproofai.json`, Cursor Agent של `~/.cursor/hooks.json`, OpenCode של plugin shim שנוצר ב-`~/.config/opencode/plugins/failproofai.mjs` בתוספת ערך רישום במערך `plugin` של `~/.config/opencode/opencode.json`, Pi של `~/.pi/agent/settings.json`, או Hermes של `~/.hermes/config.yaml`). כאשר יותר מאחד קיים תתבקע לבחור; העבר `--cli claude codex copilot cursor opencode pi hermes` (כל קבוצה משנית) כדי לדלג על ההודעה. - תמיכה ב-GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ו-Gemini CLI היא **בטא** — התקן עם `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, או `--cli gemini`. Hermes (hermes-agent, שער Slack/Telegram) מותקן בטווח משתמש עם `--cli hermes` והוא **גם** מקור ביקורת לא מקוון. + תמיכה ב-GitHub Copilot CLI, Cursor Agent, OpenCode ו-Pi היא **בטא** — התקן עם `--cli copilot`, `--cli cursor`, `--cli opencode`, או `--cli pi`. Hermes (hermes-agent, שער Slack/Telegram) מותקן בטווח משתמש עם `--cli hermes` והוא **גם** מקור ביקורת לא מקוון. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/he/introduction.mdx b/docs/he/introduction.mdx index 90dc6a3d..cc81a290 100644 --- a/docs/he/introduction.mdx +++ b/docs/he/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI מספקת לסוכני AI 39 מדיניויות כש [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -hooks ומדיניויות ל**טיפול בכשלי AI**, **התאוששות משגיאות**, ו**אמינות LLM**. שמור על סוכני ה-AI שלך אמינים ופועלים באופן אוטונומי על פני **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, וה-**Agents SDK**. +hooks ומדיניויות ל**טיפול בכשלי AI**, **התאוששות משגיאות**, ו**אמינות LLM**. שמור על סוכני ה-AI שלך אמינים ופועלים באופן אוטונומי על פני **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, וה-**Agents SDK**. סוכני AI נכשלים בדרכים צפויות. הם מפעילים פקודות הרסניות, מדליפים סודות, חורגים מהמטלה, תקועים בלולאות, או דוחפים ישירות לענף הראשי. אם משאירים ללא פקוח עין, כשלים קטנים מתגברים להפסקות, דליפות אישורים, והפסד עבודה. diff --git a/docs/hi/built-in-policies.mdx b/docs/hi/built-in-policies.mdx index a2350188..3c54c713 100644 --- a/docs/hi/built-in-policies.mdx +++ b/docs/hi/built-in-policies.mdx @@ -705,7 +705,7 @@ detect करें जब एजेंट stuck हों या unexpectedly b ### Per-CLI Stop semantics -Stop enforcement सातों supported CLIs में थोड़ा अलग दिखता है क्योंकि प्रत्येक एक अलग "agent finished" hook contract expose करता है। **outcome** same है — एजेंट workflow gate failing होने पर stop नहीं हो सकता — लेकिन **mechanics** अलग हैं। नीचे की table summarize करती है; केवल Pi के पास एक user-visible quirk है जो समझने के लायक है इससे पहले आप एक `require-*-before-stop` नीति को enable करें। +Stop enforcement छहों supported CLIs में थोड़ा अलग दिखता है क्योंकि प्रत्येक एक अलग "agent finished" hook contract expose करता है। **outcome** same है — एजेंट workflow gate failing होने पर stop नहीं हो सकता — लेकिन **mechanics** अलग हैं। नीचे की table summarize करती है; केवल Pi के पास एक user-visible quirk है जो समझने के लायक है इससे पहले आप एक `require-*-before-stop` नीति को enable करें। | CLI | जब gate fires | आप क्या देखते हैं | |---|---|---| @@ -713,20 +713,19 @@ Stop enforcement सातों supported CLIs में थोड़ा अल | Codex | Same agent loop, immediately | Claude के समान। | | GitHub Copilot CLI | Same agent loop, immediately | Claude के समान (Copilot के `{decision:"block", reason}` retry channel का उपयोग करता है — Copilot CLI 1.0.41 के विरुद्ध empirically verified)। | | Cursor Agent | Same agent loop, immediately | Claude के समान (Cursor के `{followup_message}` channel का उपयोग करता है — `loop_limit` द्वारा capped, default 5 retries)। | -| Gemini CLI | Same agent loop, immediately | Claude के समान (Gemini के `{decision:"block", reason}` channel का उपयोग करता है `AfterAgent` पर)। | | OpenCode | Same agent loop, immediately | Claude के समान (OpenCode के `client.session.prompt(...)` SDK call का उपयोग करता है `hookSpecificOutput.additionalContext` के through routed)। | | **Pi (pi-coding-agent)** | **Next user turn** | **Pi visibly stops** जब gate fires — इसका agent loop exit होता है और आपको prompt में वापस किया जाता है। Gate फिर next time fires जब आप एक prompt submit करते हैं: failproofai एक `MANDATORY ACTION REQUIRED` directive को उस turn के system prompt में prepend करता है, LLM को instruct करते हुए workflow step (commit, push, आदि) को complete करने के लिए आप जो माँगते हैं उससे पहले। | -**Pi limitation.** Pi के `AgentEndEvent` (Claude के `Stop` hook के upstream equivalent) के पास कोई Result type नहीं है — जब यह fires, Pi के agent loop पहले ही exit हो चुका है। Pi को Claude / Copilot / Cursor / Gemini / OpenCode के तरीके से same loop को retry के लिए force नहीं किया जा सकता। failproofai gate को Pi के `before_agent_start` event में shift करता है (जो next user prompt के बाद fires) ताकि workflow check अभी भी enforce हो, बस next turn पर current के बजाय। +**Pi limitation.** Pi के `AgentEndEvent` (Claude के `Stop` hook के upstream equivalent) के पास कोई Result type नहीं है — जब यह fires, Pi के agent loop पहले ही exit हो चुका है। Pi को Claude / Copilot / Cursor / OpenCode के तरीके से same loop को retry के लिए force नहीं किया जा सकता। failproofai gate को Pi के `before_agent_start` event में shift करता है (जो next user prompt के बाद fires) ताकि workflow check अभी भी enforce हो, बस next turn पर current के बजाय। **इसका व्यावहारिक मतलब क्या है:** - Pi stop करने के बाद, deny reason को in-memory में Pi session id द्वारा keyed capture किया जाता है। बिल्कुल next prompt आप same Pi process में submit करते हैं drains it: LLM को अपने system prompt के top में `MANDATORY ACTION REQUIRED` directive दिखाई देता है, commit करता है (या push / PR खोलता है / CI wait करता है), और फिर ही आपके request के साथ continue करता है। Captured deny reason एक one-shot है — एक बार drain होने के बाद, gate clear है। -- Gate Pi के process lifetime द्वारा bounded है। यदि आप Pi को `Ctrl+C` करते हैं या turns के बीच quit करते हैं, in-memory entry process के साथ drop हो जाता है और gate miss हो जाता है। Claude, Copilot, Cursor, Gemini, और OpenCode के पास same bound है (एजेंट को kill करो और gate miss हो जाता है) — Pi बस इसे अधिक visible बनाता है क्योंकि एजेंट visibly exit होता है gate firing से पहले। +- Gate Pi के process lifetime द्वारा bounded है। यदि आप Pi को `Ctrl+C` करते हैं या turns के बीच quit करते हैं, in-memory entry process के साथ drop हो जाता है और gate miss हो जाता है। Claude, Copilot, Cursor, और OpenCode के पास same bound है (एजेंट को kill करो और gate miss हो जाता है) — Pi बस इसे अधिक visible बनाता है क्योंकि एजेंट visibly exit होता है gate firing से पहले। - Pending deny भी `session_shutdown` पर किसी भी कारण के लिए clear किया जाता है (`new` / `resume` / `fork` / `quit`), तो prior session से एक stale gate same Pi process में started fresh session में leak नहीं हो सकता। -यदि आपको Claude-style same-loop retry चाहिए, run अपनी `Stop` नीतियों के अंतर्गत किसी और छः supported CLIs के। हम Pi upstream को track कर रहे हैं एक future Result type के लिए `AgentEndEvent` पर जो हमें इस gap को close करने देगा। +यदि आपको Claude-style same-loop retry चाहिए, run अपनी `Stop` नीतियों के अंतर्गत किसी और पाँच supported CLIs के। हम Pi upstream को track कर रहे हैं एक future Result type के लिए `AgentEndEvent` पर जो हमें इस gap को close करने देगा। ### `require-commit-before-stop` diff --git a/docs/hi/cli/audit.mdx b/docs/hi/cli/audit.mdx index 8bbfbf96..1e2217bb 100644 --- a/docs/hi/cli/audit.mdx +++ b/docs/hi/cli/audit.mdx @@ -47,7 +47,7 @@ failproofai उपयोग देखने के लिए `failproofai audit -h` (या `--help`) चलाएं। ऑडिट **पूरी तरह ऑफलाइन** चलता है — कोई खाता या नेटवर्क आवश्यक नहीं — और डैशबोर्ड तब तक सेवा देता रहता है जब तक आप इसे `Ctrl+C` से रोक न दें। -डैशबोर्ड इस मशीन पर पिछले एजेंट CLI ट्रांसक्रिप्ट्स को स्कैन करता है (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) और रिपोर्ट करता है कि एजेंट ने कितनी बार ऐसी चीजें कीं जिन्हें रोकने के लिए failproofai बनाया गया है — env-var चेक, force push, अनावश्यक `cd ` प्रिफिक्स, sleep-polling लूप, अभी-अभी edited फाइलें दोबारा पढ़ना, और अन्य। +डैशबोर्ड इस मशीन पर पिछले एजेंट CLI ट्रांसक्रिप्ट्स को स्कैन करता है (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) और रिपोर्ट करता है कि एजेंट ने कितनी बार ऐसी चीजें कीं जिन्हें रोकने के लिए failproofai बनाया गया है — env-var चेक, force push, अनावश्यक `cd ` प्रिफिक्स, sleep-polling लूप, अभी-अभी edited फाइलें दोबारा पढ़ना, और अन्य। प्रत्येक ट्रांसक्रिप्ट के लिए, हर tool-use इवेंट 39 builtin policies के माध्यम से **और** 8 audit-only डिटेक्टर्स के माध्यम से फिर से चलाया जाता है जो ऐसे पैटर्न को पकड़ते हैं जो अभी तक runtime policies द्वारा कवर नहीं हैं। गिनती सभी सत्रों में प्रति policy/डिटेक्टर एकत्र की जाती है। diff --git a/docs/hi/configuration.mdx b/docs/hi/configuration.mdx index 0f0fae5b..f19342cc 100644 --- a/docs/hi/configuration.mdx +++ b/docs/hi/configuration.mdx @@ -196,13 +196,12 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo - **OpenAI Codex**: `~/.codex/hooks.json` (उपयोगकर्ता), `/.codex/hooks.json` (प्रोजेक्ट) — Codex के पास `local` स्कोप नहीं है - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (उपयोगकर्ता), `/.github/hooks/failproofai.json` (प्रोजेक्ट) — Copilot के पास कोई `local` स्कोप नहीं है। हुक एंट्रीज़ Copilot के OS-keyed `bash`/`powershell` कमांड फ़ील्ड का उपयोग करते हैं `timeoutSec` के साथ; फ़ाइल एक टॉप-लेवल `version: 1` मार्कर ले जाती है। Copilot CLI समर्थन **beta** है जबकि हम `events.jsonl` रिकॉर्ड स्कीमा को सत्यापित करते हैं (जिसे सार्वजनिक दस्तावेज़ निर्दिष्ट नहीं करते) अधिक वास्तविक-दुनिया सत्रों के विरुद्ध। - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (उपयोगकर्ता), `/.cursor/hooks.json` (प्रोजेक्ट) — Cursor के पास कोई `local` स्कोप नहीं है। हुक एंट्रीज़ Claude-shaped `{type, command, timeout}` फॉर्म का उपयोग करते हैं (कोई `bash`/`powershell` विभाजन नहीं), लेकिन camelCase ईवेंट कुंजियों के तहत संग्रहीत (`preToolUse`, `beforeSubmitPrompt`, …) Cursor के [hooks schema](https://cursor.com/docs/hooks) के अनुसार एक फ्लैट ऐरे में; फ़ाइल एक टॉप-लेवल `version: 1` मार्कर ले जाती है। हैंडलर camelCase → PascalCase को `CURSOR_EVENT_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। Cursor Agent समर्थन **beta** है जबकि हम Cursor के ट्रांसक्रिप्ट को सत्यापित करते हैं (सार्वजनिक दस्तावेज़ में निर्दिष्ट नहीं) अधिक वास्तविक-दुनिया इंस्टॉल्स के विरुद्ध। - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (उपयोगकर्ता), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (प्रोजेक्ट) — OpenCode के पास कोई `local` स्कोप नहीं है। अन्य छह CLI के विपरीत, OpenCode के पास **कोई बाहरी-कमांड हुक सिस्टम नहीं है**: यह JS/TS प्लगइन को `opencode.json` में `plugin: []` ऐरे के माध्यम से स्पष्ट रूप से पंजीकृत करके इन-प्रॉसेस लोड करता है (`.opencode/plugins/` से ऑटो-डिस्कवरी **नहीं** है कि प्लगइन opencode v1.14.33 पर कैसे लोड होते हैं)। इंस्टॉल एक छोटा जेनरेटेड प्लगइन शिम छोड़ता है जो failproofai बाइनरी को subprocess-कॉल करता है और बाइनरी के Claude-shape JSON प्रतिक्रिया को प्लगइन शब्दावली में वापस अनुवाद करता है: `throw new Error()` टूल-ईवेंट deny के लिए (टूल कॉल को रद्द करता है), `client.session.prompt(...)` instruct AND के लिए `Stop` / `SubagentStop` deny (deny कारण को अगले उपयोगकर्ता संदेश के रूप में जमा करता है — एकमात्र force-retry चैनल क्योंकि `session.idle` केवल-अधिसूचना है और इससे throw करना एक no-op है), और allow के लिए no-op। शिम both टूल नाम (lowercase → PascalCase `OPENCODE_TOOL_MAP` के माध्यम से) और tool-input arg कुंजियां (camelCase → snake_case `OPENCODE_TOOL_INPUT_MAP` के माध्यम से `Read` / `Write` / `Edit` के लिए, उदा. `filePath` → `file_path`, `oldString` → `old_string`) कैनोनिकलाइज़ करता है बाइनरी में अग्रेषित करने से पहले, इसलिए path-checking builtins जैसे `block-read-outside-cwd`, `block-env-files`, और `block-secrets-write` OpenCode tool कॉल पर अपरिवर्तित रूप से चलते हैं। सत्र opencode के SQLite DB में `~/.local/share/opencode/opencode.db` में रहते हैं; डैशबोर्ड का सत्र दर्शक `opencode db --format json` और `opencode export ` के माध्यम से उन्हें पढ़ता है। OpenCode समर्थन **beta** है जबकि हम संस्करणों में व्यवहार को सत्यापित करते हैं और अधिक वास्तविक-दुनिया सत्रों के विरुद्ध। [OpenCode plugins docs](https://opencode.ai/docs/plugins/) देखें। + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (उपयोगकर्ता), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (प्रोजेक्ट) — OpenCode के पास कोई `local` स्कोप नहीं है। अन्य पाँच CLI के विपरीत, OpenCode के पास **कोई बाहरी-कमांड हुक सिस्टम नहीं है**: यह JS/TS प्लगइन को `opencode.json` में `plugin: []` ऐरे के माध्यम से स्पष्ट रूप से पंजीकृत करके इन-प्रॉसेस लोड करता है (`.opencode/plugins/` से ऑटो-डिस्कवरी **नहीं** है कि प्लगइन opencode v1.14.33 पर कैसे लोड होते हैं)। इंस्टॉल एक छोटा जेनरेटेड प्लगइन शिम छोड़ता है जो failproofai बाइनरी को subprocess-कॉल करता है और बाइनरी के Claude-shape JSON प्रतिक्रिया को प्लगइन शब्दावली में वापस अनुवाद करता है: `throw new Error()` टूल-ईवेंट deny के लिए (टूल कॉल को रद्द करता है), `client.session.prompt(...)` instruct AND के लिए `Stop` / `SubagentStop` deny (deny कारण को अगले उपयोगकर्ता संदेश के रूप में जमा करता है — एकमात्र force-retry चैनल क्योंकि `session.idle` केवल-अधिसूचना है और इससे throw करना एक no-op है), और allow के लिए no-op। शिम both टूल नाम (lowercase → PascalCase `OPENCODE_TOOL_MAP` के माध्यम से) और tool-input arg कुंजियां (camelCase → snake_case `OPENCODE_TOOL_INPUT_MAP` के माध्यम से `Read` / `Write` / `Edit` के लिए, उदा. `filePath` → `file_path`, `oldString` → `old_string`) कैनोनिकलाइज़ करता है बाइनरी में अग्रेषित करने से पहले, इसलिए path-checking builtins जैसे `block-read-outside-cwd`, `block-env-files`, और `block-secrets-write` OpenCode tool कॉल पर अपरिवर्तित रूप से चलते हैं। सत्र opencode के SQLite DB में `~/.local/share/opencode/opencode.db` में रहते हैं; डैशबोर्ड का सत्र दर्शक `opencode db --format json` और `opencode export ` के माध्यम से उन्हें पढ़ता है। OpenCode समर्थन **beta** है जबकि हम संस्करणों में व्यवहार को सत्यापित करते हैं और अधिक वास्तविक-दुनिया सत्रों के विरुद्ध। [OpenCode plugins docs](https://opencode.ai/docs/plugins/) देखें। - **Pi _(beta)_**: `~/.pi/agent/settings.json` (उपयोगकर्ता), `/.pi/settings.json` (प्रोजेक्ट) — Pi के पास कोई `local` स्कोप नहीं है। Pi स्टार्टअप पर TypeScript extension पैकेज लोड करता है; सेटिंग्स फ़ाइल एक फ्लैट स्ट्रिंग ऐरे `{"packages": ["./relative/path", …]}` है। failproofai एक single packages-array एंट्री लिखता है जो अपनी bundled `pi-extension/` निर्देशिका की ओर इशारा करता है। एक्सटेंशन आंतरिक रूप से Pi के `tool_call` / `user_bash` / `input` / `session_start` ईवेंट्स की सदस्यता लेता है और `failproofai --hook --cli pi` के लिए shell बाहर निकालता है; हैंडलर underscore_lower_snake_case → PascalCase को `PI_EVENT_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। Tool input args को `PI_TOOL_INPUT_MAP` के माध्यम से भी कैनोनिकलाइज़ किया जाता है (Pi के Read / Write / Edit `path` के बजाय `file_path` प्रदान करते हैं; शीर्ष-स्तरीय कुंजी को मैप करना `block-env-files` और `block-secrets-write` को चलने देता है — `block-read-outside-cwd` पहले से ही एक `path` fallback था)। Pi समर्थन **beta** है जबकि Pi का एक्सटेंशन API और session-log लेआउट स्थिर होता है। - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (उपयोगकर्ता), `/.gemini/settings.json` (प्रोजेक्ट) — Gemini के पास कोई `local` स्कोप नहीं है (यह `/etc/gemini-cli/settings.json` पर एक `system` स्कोप दस्तावेज़ित करता है जो failproofai उजागर नहीं करता)। हुक एंट्रीज़ Claude के `{type, command, timeout}` फॉर्म का उपयोग करते हैं Gemini के `{matcher, hooks: [...]}` matcher स्कीमा में लपेटा गया `matcher: "*"` के साथ डिफ़ॉल्ट रूप से। ईवेंट्स PascalCase हैं (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); हैंडलर `GEMINI_EVENT_MAP` के माध्यम से Claude canonical नामों में मैप करता है। टूल नाम snake_case हैं (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — हैंडलर `GEMINI_TOOL_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। नीति मूल्यांकनकर्ता Gemini का फ्लैट `{decision: "deny", reason}` shape (Gemini के "Golden Rule" exit-0 contract के अनुसार पसंद किया जाता है), `{hookSpecificOutput: {hookEventName, additionalContext}}` context injection के लिए BeforeAgent / AfterTool / SessionStart पर, और `{decision: "block", reason}` AfterAgent पर force-retry semantics के लिए उत्सर्जित करता है। Gemini CLI समर्थन **beta** है जबकि हम वास्तविक-दुनिया कवरेज को चौड़ा करते हैं। [Gemini CLI hooks docs](https://geminicli.com/docs/hooks/) देखें। - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**उपयोगकर्ता स्कोप केवल** — Hermes के पास कोई project/local कॉन्फ़िग नहीं है)। Hermes एक Slack/Telegram **गेटवे** है, इसलिए एक इंस्टॉल हर प्लेटफॉर्म (Slack/Telegram/cli/cron) **और** आंतरिक subagents से tool कॉल को इंटरसेप्ट करता है। हुक एंट्रीज़ एक `{command, timeout}` pair (**सेकंड में** timeout) हैं एक `hooks:` map के तहत Hermes के snake_case ईवेंट्स द्वारा keyed (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); हैंडलर ईवेंट्स को `HERMES_EVENT_MAP` के माध्यम से और टूल नाम को `HERMES_TOOL_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। कॉन्फ़िग एक comment-preserving YAML `Document` round-trip के माध्यम से संपादित किया जाता है ताकि ऑपरेटर की अन्य सेटिंग्स जीवित रहें, और install `hooks_auto_accept: true` सेट करता है ताकि headless gateway (कोई TTY नहीं) consent प्रॉम्प्ट के बिना हुक चलाए। मूल्यांकनकर्ता Hermes के `{"decision":"block","reason"}` stdout contract उत्सर्जित करता है (Hermes exit कोड को अनदेखा करता है)। **सीमाएं:** Hermes के पास कोई turn-end `Stop` ईवेंट नहीं है, इसलिए `require-*-before-stop` builtins कभी इसके लिए नहीं चलते (inapplicable, broken नहीं); `instruct` allow-with-logged-note में degrade होता है (कोई additional-context चैनल नहीं); और output-secret redaction (`sanitize-*`) shell-hook contract के ऊपर tool output को rewrite नहीं कर सकता। Hermes **भी** एक offline **audit** स्रोत है — डैशबोर्ड अपने gateway सत्रों को सीधे `~/.hermes/state.db` से पढ़ता है। - **`policies-config.json`** — failproofai को बताता है कि कौन सी नीतियों का मूल्यांकन करना है और किस पैरामीटर के साथ (सभी एजेंट CLIs में साझा) -एक विशिष्ट एजेंट को target करने के लिए `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` पास करें (space-separated या repeated किसी भी subset के लिए): +एक विशिष्ट एजेंट को target करने के लिए `--cli claude|codex|copilot|cursor|opencode|pi|hermes` पास करें (space-separated या repeated किसी भी subset के लिए): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -जब `--cli` omit किया जाता है, `failproofai` पता लगाता है कि कौन से एजेंट CLIs installed हैं (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +जब `--cli` omit किया जाता है, `failproofai` पता लगाता है कि कौन से एजेंट CLIs installed हैं (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **एक CLI detected** — prompt के बिना उस CLI को auto-select करता है। - **Multiple CLIs detected** एक interactive terminal में — एक arrow-key single-select प्रॉम्प्ट दिखाता है एक `Detected (N)` section (एक `Install for all N detected` aggregate row + प्रत्येक detected CLI individually के साथ) और एक `Not installed (M) · install hooks ahead of time` section में grouped (हर undetected supported CLI को एक forward-install विकल्प के रूप में सूचीबद्ध करता है (↑↓ move करने के लिए, Enter select करने के लिए, ^C quit करने के लिए))। uninstall flow केवल Detected section दिखाता है। diff --git a/docs/hi/dashboard.mdx b/docs/hi/dashboard.mdx index b3a6c202..1297d046 100644 --- a/docs/hi/dashboard.mdx +++ b/docs/hi/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### प्रोजेक्ट -आपकी मशीन पर मिले सभी Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, और Hermes प्रोजेक्ट सूचीबद्ध करता है। Claude प्रोजेक्ट `~/.claude/projects/` से खोजे जाते हैं (या `CLAUDE_PROJECTS_PATH` द्वारा निर्धारित पथ); Codex प्रोजेक्ट `~/.codex/sessions///
/*.jsonl` के तहत प्रत्येक ट्रांसक्रिप्ट को स्कैन करके और प्रत्येक सेशन के पहले रिकॉर्ड में दर्ज `cwd` के अनुसार समूहबद्ध करके खोजे जाते हैं; Copilot CLI प्रोजेक्ट प्रत्येक `~/.copilot/session-state//workspace.yaml` को स्कैन करके खोजे जाते हैं (`COPILOT_HOME` के माध्यम से कॉन्फ़िगर करने योग्य) और इसके `cwd` फील्ड के अनुसार समूहबद्ध किए जाते हैं; Cursor Agent प्रोजेक्ट `~/.cursor/agent-sessions//` के तहत प्रति-सेशन मेटाडेटा को स्कैन करके खोजे जाते हैं (`CURSOR_HOME` के माध्यम से कॉन्फ़िगर करने योग्य, `conversations/` और `sessions/` को फॉलबैक के रूप में जांचा जाता है) `meta.json` / `session.json` / `workspace.yaml` में `cwd` स्केलर के लिए; OpenCode प्रोजेक्ट `~/.local/share/opencode/opencode.db` पर इसके SQLite DB को `opencode db --format json` के माध्यम से क्वेरी करके खोजे जाते हैं (हम `session` और `project` तालिकाएं पढ़ते हैं और `project_id` के अनुसार समूहबद्ध करते हैं); Pi प्रोजेक्ट `~/.pi/agent/sessions//_.jsonl` के तहत प्रति-सेशन JSONL ट्रांसक्रिप्ट को स्कैन करके खोजे जाते हैं (`PI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और प्रत्येक सेशन के पहले रिकॉर्ड से `cwd` निकाला जाता है; Gemini CLI प्रोजेक्ट `~/.gemini/tmp//chats/session--.jsonl` को स्कैन करके खोजे जाते हैं (`GEMINI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और अनुवर्ती `.project_root` टेक्स्ट मार्कर से विहित cwd को पुनः प्राप्त किया जाता है; Hermes गेटवे सेशन सीधे इसके SQLite स्टोर से `~/.hermes/state.db` पर पढ़े जाते हैं (`HERMES_DB_PATH` के माध्यम से कॉन्फ़िगर करने योग्य) और `source` के अनुसार `hermes-` प्रोजेक्ट में समूहबद्ध किए जाते हैं (Slack/Telegram/cli/cron — गेटवे सेशन का कोई cwd नहीं है)। एक प्रोजेक्ट जिसे कई CLI द्वारा उपयोग किया गया है, एक एकल पंक्ति के रूप में सभी मेल खाने वाले बैज के साथ प्रदर्शित होता है। सारणी के ऊपर **CLI** ड्रॉपडाउन का उपयोग करके किसी विशिष्ट एजेंट CLI द्वारा फ़िल्टर करें; URL आपके चयन को `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` के रूप में संरक्षित करता है। +आपकी मशीन पर मिले सभी Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, और Hermes प्रोजेक्ट सूचीबद्ध करता है। Claude प्रोजेक्ट `~/.claude/projects/` से खोजे जाते हैं (या `CLAUDE_PROJECTS_PATH` द्वारा निर्धारित पथ); Codex प्रोजेक्ट `~/.codex/sessions///
/*.jsonl` के तहत प्रत्येक ट्रांसक्रिप्ट को स्कैन करके और प्रत्येक सेशन के पहले रिकॉर्ड में दर्ज `cwd` के अनुसार समूहबद्ध करके खोजे जाते हैं; Copilot CLI प्रोजेक्ट प्रत्येक `~/.copilot/session-state//workspace.yaml` को स्कैन करके खोजे जाते हैं (`COPILOT_HOME` के माध्यम से कॉन्फ़िगर करने योग्य) और इसके `cwd` फील्ड के अनुसार समूहबद्ध किए जाते हैं; Cursor Agent प्रोजेक्ट `~/.cursor/agent-sessions//` के तहत प्रति-सेशन मेटाडेटा को स्कैन करके खोजे जाते हैं (`CURSOR_HOME` के माध्यम से कॉन्फ़िगर करने योग्य, `conversations/` और `sessions/` को फॉलबैक के रूप में जांचा जाता है) `meta.json` / `session.json` / `workspace.yaml` में `cwd` स्केलर के लिए; OpenCode प्रोजेक्ट `~/.local/share/opencode/opencode.db` पर इसके SQLite DB को `opencode db --format json` के माध्यम से क्वेरी करके खोजे जाते हैं (हम `session` और `project` तालिकाएं पढ़ते हैं और `project_id` के अनुसार समूहबद्ध करते हैं); Pi प्रोजेक्ट `~/.pi/agent/sessions//_.jsonl` के तहत प्रति-सेशन JSONL ट्रांसक्रिप्ट को स्कैन करके खोजे जाते हैं (`PI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और प्रत्येक सेशन के पहले रिकॉर्ड से `cwd` निकाला जाता है; Hermes गेटवे सेशन सीधे इसके SQLite स्टोर से `~/.hermes/state.db` पर पढ़े जाते हैं (`HERMES_DB_PATH` के माध्यम से कॉन्फ़िगर करने योग्य) और `source` के अनुसार `hermes-` प्रोजेक्ट में समूहबद्ध किए जाते हैं (Slack/Telegram/cli/cron — गेटवे सेशन का कोई cwd नहीं है)। एक प्रोजेक्ट जिसे कई CLI द्वारा उपयोग किया गया है, एक एकल पंक्ति के रूप में सभी मेल खाने वाले बैज के साथ प्रदर्शित होता है। सारणी के ऊपर **CLI** ड्रॉपडाउन का उपयोग करके किसी विशिष्ट एजेंट CLI द्वारा फ़िल्टर करें; URL आपके चयन को `?cli=claude|codex|copilot|cursor|opencode|pi|hermes` के रूप में संरक्षित करता है। प्रत्येक प्रोजेक्ट दिखाता है: - प्रोजेक्ट नाम (फोल्डर पथ से व्युत्पन्न) -- एक CLI बैज — `Claude Code` (नारंगी), `OpenAI Codex` (बैंगनी), `GitHub Copilot` (नीला), `Cursor Agent` (पन्ना), `OpenCode` (एम्बर), `Pi` (गुलाबी), `Gemini CLI` (आसमानी), और/या `Hermes` (गहरा नीला) +- एक CLI बैज — `Claude Code` (नारंगी), `OpenAI Codex` (बैंगनी), `GitHub Copilot` (नीला), `Cursor Agent` (पन्ना), `OpenCode` (एम्बर), `Pi` (गुलाबी), और/या `Hermes` (गहरा नीला) - सबसे हाल की सेशन गतिविधि की तारीख एक प्रोजेक्ट पर क्लिक करके इसके सेशन देखें। @@ -47,7 +47,7 @@ failproofai ### सेशन दर्शक -सेशन दर्शक स्वायत्त एजेंट के लिए मुख्य प्रश्न का उत्तर देता है: एजेंट ने क्या किया, और क्या वह ट्रैक पर रहा? शीर्षलेख के बगल में एक CLI बैज इंगित करता है कि सेशन Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, या Hermes ट्रांसक्रिप्ट है। यह एक सेशन में हुई हर चीज की एक टाइमलाइन दिखाता है: +सेशन दर्शक स्वायत्त एजेंट के लिए मुख्य प्रश्न का उत्तर देता है: एजेंट ने क्या किया, और क्या वह ट्रैक पर रहा? शीर्षलेख के बगल में एक CLI बैज इंगित करता है कि सेशन Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, या Hermes ट्रांसक्रिप्ट है। यह एक सेशन में हुई हर चीज की एक टाइमलाइन दिखाता है: - **संदेश** - Claude के टेक्स्ट प्रतिक्रियाएं और उपयोगकर्ता संकेत - **टूल कॉल** - हर टूल जो Claude ने आह्वान किया, इसके इनपुट और आउटपुट के साथ @@ -55,7 +55,7 @@ failproofai शीर्ष पर सांख्यिकी बार सेशन की अवधि, कुल टूल कॉल, और हुक निर्णयों का सारांश दिखाता है (अनुमति / अस्वीकृति / निर्देश गणना)। -सेशन निर्यात करने के लिए **डाउनलोड लॉग** बटन पर क्लिक करें। Claude Code, Codex, Copilot, Cursor, Pi, और Gemini सेशन के लिए आप मूल ऑन-डिस्क JSONL ट्रांसक्रिप्ट बाइट-दर-बाइट प्राप्त करते हैं; OpenCode के लिए (जिसके सेशन SQLite में रहते हैं, डिस्क पर नहीं) आप एक JSON दस्तावेज प्राप्त करते हैं जो अंतर्निहित `session` / `messages` / `parts` तालिकाओं को प्रतिबिंबित करता है। +सेशन निर्यात करने के लिए **डाउनलोड लॉग** बटन पर क्लिक करें। Claude Code, Codex, Copilot, Cursor, और Pi सेशन के लिए आप मूल ऑन-डिस्क JSONL ट्रांसक्रिप्ट बाइट-दर-बाइट प्राप्त करते हैं; OpenCode के लिए (जिसके सेशन SQLite में रहते हैं, डिस्क पर नहीं) आप एक JSON दस्तावेज प्राप्त करते हैं जो अंतर्निहित `session` / `messages` / `parts` तालिकाओं को प्रतिबिंबित करता है। ### ऑडिट @@ -75,16 +75,16 @@ failproofai - - एकल पैनल से failproofai किस एजेंट CLI की रक्षा करता है, इसे बहु-चयन करें — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, और Hermes सभी के पास स्थापना स्थिति (`Active` / `Detected` / `Inactive`) वाली एक पंक्ति है, उपयोगकर्ता-स्कोप सेटिंग्स पथ, और एक ब्रांड-रंगीन उच्चारण। आप जिन CLI चाहते हैं उन्हें चेक करें या अनचेक करें और `Apply changes` पर क्लिक करके एक चरण में इंस्टॉल/अनइंस्टॉल करने के लिए अंतर लागू करें। CLI जिनके बाइनरी को PATH पर पता चला है, पूर्व-जांच किए जाते हैं। + - एकल पैनल से failproofai किस एजेंट CLI की रक्षा करता है, इसे बहु-चयन करें — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, और Hermes सभी के पास स्थापना स्थिति (`Active` / `Detected` / `Inactive`) वाली एक पंक्ति है, उपयोगकर्ता-स्कोप सेटिंग्स पथ, और एक ब्रांड-रंगीन उच्चारण। आप जिन CLI चाहते हैं उन्हें चेक करें या अनचेक करें और `Apply changes` पर क्लिक करके एक चरण में इंस्टॉल/अनइंस्टॉल करने के लिए अंतर लागू करें। CLI जिनके बाइनरी को PATH पर पता चला है, पूर्व-जांच किए जाते हैं। - एकल क्लिक के साथ व्यक्तिगत नीतियों को चालू या बंद करें (`~/.failproofai/policies-config.json` में लिखते हैं — हर इंस्टॉल किए गए CLI में साझा) - एक नीति का विस्तार करके इसके पैरामीटर को कॉन्फ़िगर करें (उन नीतियों के लिए जो `policyParams` को समर्थन करती हैं) - एक कस्टम नीति फाइल पथ सेट करें - सभी सेशन में फायर किए गए प्रत्येक हुक ईवेंट का पूर्ण पृष्ठांकित इतिहास - - निर्णय, ईवेंट प्रकार, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), नीति नाम, या सेशन ID द्वारा फ़िल्टर करें - - प्रत्येक पंक्ति दिखाती है: टाइमस्टैम्प, नीति नाम, निर्णय, CLI बैज (नारंगी = Claude Code, बैंगनी = OpenAI Codex, नीला = GitHub Copilot, पन्ना = Cursor Agent, एम्बर = OpenCode, गुलाबी = Pi, आसमानी = Gemini CLI, गहरा नीला = Hermes), टूल नाम, सेशन ID, और अस्वीकृति/निर्देश निर्णयों का कारण - - ट्रांसक्रिप्ट खोलने के लिए एक सेशन ID पर क्लिक करें — दर्शक स्वचालित रूप से पता लगाता है कि कौन सा CLI हुक को आग लगाया (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) और शीर्षलेख में मेल खाने वाले CLI बैज को प्रदान करता है + - निर्णय, ईवेंट प्रकार, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), नीति नाम, या सेशन ID द्वारा फ़िल्टर करें + - प्रत्येक पंक्ति दिखाती है: टाइमस्टैम्प, नीति नाम, निर्णय, CLI बैज (नारंगी = Claude Code, बैंगनी = OpenAI Codex, नीला = GitHub Copilot, पन्ना = Cursor Agent, एम्बर = OpenCode, गुलाबी = Pi, गहरा नीला = Hermes), टूल नाम, सेशन ID, और अस्वीकृति/निर्देश निर्णयों का कारण + - ट्रांसक्रिप्ट खोलने के लिए एक सेशन ID पर क्लिक करें — दर्शक स्वचालित रूप से पता लगाता है कि कौन सा CLI हुक को आग लगाया (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) और शीर्षलेख में मेल खाने वाले CLI बैज को प्रदान करता है diff --git a/docs/hi/getting-started.mdx b/docs/hi/getting-started.mdx index b7f3787d..4d641af3 100644 --- a/docs/hi/getting-started.mdx +++ b/docs/hi/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - यह आपके इंस्टॉल किए गए agent CLIs में hook entries लिखता है (Claude Code के `~/.claude/settings.json`, OpenAI Codex के `~/.codex/hooks.json`, GitHub Copilot CLI के `~/.copilot/hooks/failproofai.json`, Cursor Agent के `~/.cursor/hooks.json`, OpenCode के generated plugin shim में `~/.config/opencode/plugins/failproofai.mjs` plus `~/.config/opencode/opencode.json` के `plugin` array में एक registration entry, Pi के `~/.pi/agent/settings.json`, Gemini CLI के `~/.gemini/settings.json`, या Hermes के `~/.hermes/config.yaml`)। जब एक से अधिक मौजूद हों तो आपसे prompt किया जाएगा; prompt को छोड़ने के लिए `--cli claude codex copilot cursor opencode pi gemini hermes` (कोई भी subset) पास करें। + यह आपके इंस्टॉल किए गए agent CLIs में hook entries लिखता है (Claude Code के `~/.claude/settings.json`, OpenAI Codex के `~/.codex/hooks.json`, GitHub Copilot CLI के `~/.copilot/hooks/failproofai.json`, Cursor Agent के `~/.cursor/hooks.json`, OpenCode के generated plugin shim में `~/.config/opencode/plugins/failproofai.mjs` plus `~/.config/opencode/opencode.json` के `plugin` array में एक registration entry, Pi के `~/.pi/agent/settings.json`, या Hermes के `~/.hermes/config.yaml`)। जब एक से अधिक मौजूद हों तो आपसे prompt किया जाएगा; prompt को छोड़ने के लिए `--cli claude codex copilot cursor opencode pi hermes` (कोई भी subset) पास करें। - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, और Gemini CLI सपोर्ट **beta** है — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, या `--cli gemini` के साथ इंस्टॉल करें। Hermes (hermes-agent, एक Slack/Telegram gateway) user-scope के साथ `--cli hermes` के साथ इंस्टॉल होता है और **साथ ही** एक offline audit source है। + GitHub Copilot CLI, Cursor Agent, OpenCode, और Pi सपोर्ट **beta** है — `--cli copilot`, `--cli cursor`, `--cli opencode`, या `--cli pi` के साथ इंस्टॉल करें। Hermes (hermes-agent, एक Slack/Telegram gateway) user-scope के साथ `--cli hermes` के साथ इंस्टॉल होता है और **साथ ही** एक offline audit source है। ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/hi/introduction.mdx b/docs/hi/introduction.mdx index 1055e6cc..3dc3ada1 100644 --- a/docs/hi/introduction.mdx +++ b/docs/hi/introduction.mdx @@ -6,7 +6,7 @@ description: "FailproofAI आपके AI एजेंट्स को 39 बि [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI फेलियर हैंडलिंग**, **एरर रिकवरी**, और **LLM रिलायबिलिटी** के लिए हुक्स और पॉलिसीज। अपने AI एजेंट्स को **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, और **Agents SDK** में विश्वसनीय और स्वायत्त रूप से चलाते रहें। +**AI फेलियर हैंडलिंग**, **एरर रिकवरी**, और **LLM रिलायबिलिटी** के लिए हुक्स और पॉलिसीज। अपने AI एजेंट्स को **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, और **Agents SDK** में विश्वसनीय और स्वायत्त रूप से चलाते रहें। AI एजेंट्स पूर्वानुमानित तरीकों से फेल होते हैं। वे डिस्ट्रक्टिव कमांड्स चलाते हैं, सीक्रेट्स लीक करते हैं, अपने टास्क से भटकते हैं, लूप्स में फंसते हैं, या सीधे मेन में पुश करते हैं। जब बिना निरीक्षण के छोड़ दिया जाता है, तो छोटी-मोटी विफलताएं आउटेजेस, लीक किए गए क्रेडेंशियल्स और खोए हुए कार्य में बदल जाती हैं। diff --git a/docs/i18n/README.ar.md b/docs/i18n/README.ar.md index e5f60f40..61f83367 100644 --- a/docs/i18n/README.ar.md +++ b/docs/i18n/README.ar.md @@ -74,13 +74,6 @@        - - - - Gemini CLI - - -        @@ -89,7 +82,7 @@

-> تثبيت الخطافات لواحدة أو أي مزيج: `failproofai policies --install --cli opencode pi gemini` (أو `--cli claude codex copilot cursor opencode pi gemini hermes`). احذف `--cli` للكشف التلقائي عن واجهات سطر الأوامر المثبتة والمطالبة. +> تثبيت الخطافات لواحدة أو أي مزيج: `failproofai policies --install --cli opencode pi` (أو `--cli claude codex copilot cursor opencode pi hermes`). احذف `--cli` للكشف التلقائي عن واجهات سطر الأوامر المثبتة والمطالبة. > > **Hermes** (hermes-agent، بوابة Slack/Telegram) مدعومة لكل من **فرض الخطاف الحي** (`--cli hermes` — التثبيت الواحد يعترض استدعاءات الأدوات من كل منصة ووكيل فرعي) والتدقيق غير المتصل **إعادة تشغيل** لجلسات البوابة من قاعدة البيانات الواحدة `~/.hermes/state.db`. diff --git a/docs/i18n/README.de.md b/docs/i18n/README.de.md index 5c6f03dd..d4540a7c 100644 --- a/docs/i18n/README.de.md +++ b/docs/i18n/README.de.md @@ -72,13 +72,6 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal.        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal.

-> Hooks für eine oder eine beliebige Kombination installieren: `failproofai policies --install --cli opencode pi gemini` (oder `--cli claude codex copilot cursor opencode pi gemini hermes`). `--cli` weglassen, um installierte CLIs automatisch zu erkennen und zur Auswahl aufzufordern. +> Hooks für eine oder eine beliebige Kombination installieren: `failproofai policies --install --cli opencode pi` (oder `--cli claude codex copilot cursor opencode pi hermes`). `--cli` weglassen, um installierte CLIs automatisch zu erkennen und zur Auswahl aufzufordern. > > **Hermes** (hermes-agent, ein Slack/Telegram-Gateway) wird sowohl für **Live-Hook-Durchsetzung** (`--cli hermes` — eine Installation fängt Tool-Aufrufe von jeder Plattform und jedem Subagenten ab) als auch für das Offline-**Audit**-Replay seiner Gateway-Sitzungen aus der einzelnen `~/.hermes/state.db` unterstützt. diff --git a/docs/i18n/README.es.md b/docs/i18n/README.es.md index 8859f6b9..7ee277d5 100644 --- a/docs/i18n/README.es.md +++ b/docs/i18n/README.es.md @@ -72,13 +72,6 @@ antes de que se conviertan en incidentes. Cero latencia. Se ejecuta localmente.        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ antes de que se conviertan en incidentes. Cero latencia. Se ejecuta localmente.

-> Instala hooks para uno o cualquier combinación: `failproofai policies --install --cli opencode pi gemini` (o `--cli claude codex copilot cursor opencode pi gemini hermes`). Omite `--cli` para detectar automáticamente los CLIs instalados y recibir una solicitud de confirmación. +> Instala hooks para uno o cualquier combinación: `failproofai policies --install --cli opencode pi` (o `--cli claude codex copilot cursor opencode pi hermes`). Omite `--cli` para detectar automáticamente los CLIs instalados y recibir una solicitud de confirmación. > > **Hermes** (hermes-agent, una pasarela de Slack/Telegram) es compatible tanto con la **aplicación de hooks en vivo** (`--cli hermes` — una sola instalación intercepta las llamadas a herramientas desde cada plataforma y subagente) como con la **auditoría** offline de sus sesiones de pasarela desde el único `~/.hermes/state.db`. diff --git a/docs/i18n/README.fr.md b/docs/i18n/README.fr.md index 47f8ff7e..f17bd886 100644 --- a/docs/i18n/README.fr.md +++ b/docs/i18n/README.fr.md @@ -72,13 +72,6 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local.        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local.

-> Installez les hooks pour un ou plusieurs CLI au choix : `failproofai policies --install --cli opencode pi gemini` (ou `--cli claude codex copilot cursor opencode pi gemini hermes`). Omettez `--cli` pour détecter automatiquement les CLI installés et recevoir une invite de sélection. +> Installez les hooks pour un ou plusieurs CLI au choix : `failproofai policies --install --cli opencode pi` (ou `--cli claude codex copilot cursor opencode pi hermes`). Omettez `--cli` pour détecter automatiquement les CLI installés et recevoir une invite de sélection. > > **Hermes** (hermes-agent, une passerelle Slack/Telegram) est pris en charge à la fois pour l'**application des hooks en temps réel** (`--cli hermes` — une seule installation intercepte les appels d'outils de chaque plateforme et sous-agent) et pour la **relecture d'audit** hors ligne de ses sessions de passerelle depuis l'unique `~/.hermes/state.db`. diff --git a/docs/i18n/README.he.md b/docs/i18n/README.he.md index 7022d350..365cf06c 100644 --- a/docs/i18n/README.he.md +++ b/docs/i18n/README.he.md @@ -74,13 +74,6 @@        - - - - Gemini CLI - - -        @@ -89,7 +82,7 @@

-> התקן hooks לאחד או לכל שילוב: `failproofai policies --install --cli opencode pi gemini` (או `--cli claude codex copilot cursor opencode pi gemini hermes`). השמט `--cli` לגילוי אוטומטי של CLIs מותקנים ולהנחיה. +> התקן hooks לאחד או לכל שילוב: `failproofai policies --install --cli opencode pi` (או `--cli claude codex copilot cursor opencode pi hermes`). השמט `--cli` לגילוי אוטומטי של CLIs מותקנים ולהנחיה. > > **Hermes** (hermes-agent, שער Slack/Telegram) נתמך גם ל**אכיפת hook חי** (`--cli hermes` — התקנה אחת מיירטת קריאות כלים מכל פלטפורמה וסוכן משנה) וגם **ביקורת** במצב לא מקוון של הפעלות השער שלו מ`~/.hermes/state.db` הבודד. diff --git a/docs/i18n/README.hi.md b/docs/i18n/README.hi.md index d25e5512..4f9cce51 100644 --- a/docs/i18n/README.hi.md +++ b/docs/i18n/README.hi.md @@ -72,13 +72,6 @@ Claude Code और Codex में हुक करता है। लूप,        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ Claude Code और Codex में हुक करता है। लूप,

-> एक या किसी भी संयोजन के लिए हुक इंस्टॉल करें: `failproofai policies --install --cli opencode pi gemini` (या `--cli claude codex copilot cursor opencode pi gemini hermes`)। स्वचालित रूप से स्थापित CLIs का पता लगाने और संकेत देने के लिए `--cli` को छोड़ दें। +> एक या किसी भी संयोजन के लिए हुक इंस्टॉल करें: `failproofai policies --install --cli opencode pi` (या `--cli claude codex copilot cursor opencode pi hermes`)। स्वचालित रूप से स्थापित CLIs का पता लगाने और संकेत देने के लिए `--cli` को छोड़ दें। > > **Hermes** (hermes-agent, एक Slack/Telegram गेटवे) **लाइव-हुक प्रवर्तन** (`--cli hermes` — एक इंस्टॉल प्रत्येक प्लेटफॉर्म और सबएजेंट से टूल कॉल को रोकता है) और इसके गेटवे सत्रों की ऑफलाइन **ऑडिट** रिप्ले दोनों के लिए समर्थित है। diff --git a/docs/i18n/README.it.md b/docs/i18n/README.it.md index c6a4bac7..4091c1a7 100644 --- a/docs/i18n/README.it.md +++ b/docs/i18n/README.it.md @@ -72,13 +72,6 @@ prima che diventino incidenti. Latenza zero. Eseguito localmente.        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ prima che diventino incidenti. Latenza zero. Eseguito localmente.

-> Installa gli hook per uno o qualsiasi combinazione: `failproofai policies --install --cli opencode pi gemini` (o `--cli claude codex copilot cursor opencode pi gemini hermes`). Ometti `--cli` per rilevare automaticamente le CLI installate e ricevere un prompt. +> Installa gli hook per uno o qualsiasi combinazione: `failproofai policies --install --cli opencode pi` (o `--cli claude codex copilot cursor opencode pi hermes`). Ometti `--cli` per rilevare automaticamente le CLI installate e ricevere un prompt. > > **Hermes** (hermes-agent, un gateway Slack/Telegram) è supportato sia per l'**applicazione dei hook in diretta** (`--cli hermes` — un'unica installazione intercetta le chiamate ai tool da ogni piattaforma e subagente) che per il **controllo** offline della riproduzione delle sue sessioni gateway dal singolo `~/.hermes/state.db`. diff --git a/docs/i18n/README.ja.md b/docs/i18n/README.ja.md index 521e8204..9ef5129b 100644 --- a/docs/i18n/README.ja.md +++ b/docs/i18n/README.ja.md @@ -72,13 +72,6 @@ Claude Code と Codex にフックして、ループ・危険な操作・シー        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ Claude Code と Codex にフックして、ループ・危険な操作・シー

-> 1つまたは任意の組み合わせでフックをインストールできます: `failproofai policies --install --cli opencode pi gemini`(または `--cli claude codex copilot cursor opencode pi gemini hermes`)。`--cli` を省略するとインストール済み CLI を自動検出してプロンプトを表示します。 +> 1つまたは任意の組み合わせでフックをインストールできます: `failproofai policies --install --cli opencode pi`(または `--cli claude codex copilot cursor opencode pi hermes`)。`--cli` を省略するとインストール済み CLI を自動検出してプロンプトを表示します。 > > **Hermes**(hermes-agent、Slack/Telegram ゲートウェイ)は、**ライブフック強制実行**(`--cli hermes` — 1回のインストールですべてのプラットフォームとサブエージェントのツール呼び出しをインターセプト)と、単一の `~/.hermes/state.db` からのゲートウェイセッションのオフライン**監査**リプレイの両方に対応しています。 diff --git a/docs/i18n/README.ko.md b/docs/i18n/README.ko.md index 2b49b7e7..b38c022b 100644 --- a/docs/i18n/README.ko.md +++ b/docs/i18n/README.ko.md @@ -72,13 +72,6 @@ Claude Code 및 Codex에 연동됩니다. 루프, 위험한 동작, 시크릿        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ Claude Code 및 Codex에 연동됩니다. 루프, 위험한 동작, 시크릿

-> 하나 또는 여러 CLI를 조합하여 훅을 설치할 수 있습니다: `failproofai policies --install --cli opencode pi gemini` (또는 `--cli claude codex copilot cursor opencode pi gemini hermes`). `--cli`를 생략하면 설치된 CLI를 자동으로 감지하고 선택을 안내합니다. +> 하나 또는 여러 CLI를 조합하여 훅을 설치할 수 있습니다: `failproofai policies --install --cli opencode pi` (또는 `--cli claude codex copilot cursor opencode pi hermes`). `--cli`를 생략하면 설치된 CLI를 자동으로 감지하고 선택을 안내합니다. > > **Hermes** (hermes-agent, Slack/Telegram 게이트웨이)는 **실시간 훅 적용** (`--cli hermes` — 한 번의 설치로 모든 플랫폼과 서브에이전트의 툴 호출을 가로챔)과 단일 `~/.hermes/state.db`의 게이트웨이 세션 오프라인 **감사** 재생을 모두 지원합니다. diff --git a/docs/i18n/README.pt-br.md b/docs/i18n/README.pt-br.md index 967087e9..4d0a4f7d 100644 --- a/docs/i18n/README.pt-br.md +++ b/docs/i18n/README.pt-br.md @@ -72,13 +72,6 @@ antes que se tornem incidentes. Latência zero. Roda localmente.        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ antes que se tornem incidentes. Latência zero. Roda localmente.

-> Instale hooks para um ou qualquer combinação: `failproofai policies --install --cli opencode pi gemini` (ou `--cli claude codex copilot cursor opencode pi gemini hermes`). Omita `--cli` para detectar automaticamente os CLIs instalados e ser solicitado a escolher. +> Instale hooks para um ou qualquer combinação: `failproofai policies --install --cli opencode pi` (ou `--cli claude codex copilot cursor opencode pi hermes`). Omita `--cli` para detectar automaticamente os CLIs instalados e ser solicitado a escolher. > > **Hermes** (hermes-agent, um gateway para Slack/Telegram) é suportado tanto para **aplicação de hooks em tempo real** (`--cli hermes` — uma única instalação intercepta chamadas de ferramentas de todas as plataformas e subagentes) quanto para **auditoria** offline a partir de sessões do gateway gravadas no `~/.hermes/state.db`. diff --git a/docs/i18n/README.ru.md b/docs/i18n/README.ru.md index e84b9461..cdd69b6b 100644 --- a/docs/i18n/README.ru.md +++ b/docs/i18n/README.ru.md @@ -72,13 +72,6 @@        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@

-> Установите hooks для одного или любой комбинации: `failproofai policies --install --cli opencode pi gemini` (или `--cli claude codex copilot cursor opencode pi gemini hermes`). Опустите `--cli` для автоматического обнаружения установленных CLI и подсказок. +> Установите hooks для одного или любой комбинации: `failproofai policies --install --cli opencode pi` (или `--cli claude codex copilot cursor opencode pi hermes`). Опустите `--cli` для автоматического обнаружения установленных CLI и подсказок. > > **Hermes** (hermes-agent, шлюз Slack/Telegram) поддерживается как для **live-hook принудительного исполнения** (`--cli hermes` — одна установка перехватывает вызовы инструментов с каждой платформы и субагента), так и для автономного **аудита** воспроизведения сессий шлюза из отдельного `~/.hermes/state.db`. diff --git a/docs/i18n/README.tr.md b/docs/i18n/README.tr.md index 579f34ba..314e3504 100644 --- a/docs/i18n/README.tr.md +++ b/docs/i18n/README.tr.md @@ -72,13 +72,6 @@ olaylar haline gelmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ olaylar haline gelmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır

-> Bir veya herhangi bir kombinasyon için kanca yükleyin: `failproofai policies --install --cli opencode pi gemini` (veya `--cli claude codex copilot cursor opencode pi gemini hermes`). Yüklü CLI'ları otomatik olarak algılamak ve istemek için `--cli` öğesini atlayın. +> Bir veya herhangi bir kombinasyon için kanca yükleyin: `failproofai policies --install --cli opencode pi` (veya `--cli claude codex copilot cursor opencode pi hermes`). Yüklü CLI'ları otomatik olarak algılamak ve istemek için `--cli` öğesini atlayın. > > **Hermes** (hermes-agent, bir Slack/Telegram ağ geçidi) hem **canlı kanca uygulaması** (`--cli hermes` — bir kurulum her platformdan ve alt ajantan araç çağrılarını keser) hem de çevrimdışı **denetim** için desteklenir. tek `~/.hermes/state.db` dosyasından ağ geçidi oturumlarının tekrar oynatılması. diff --git a/docs/i18n/README.vi.md b/docs/i18n/README.vi.md index d0ff72b8..c84f2b3e 100644 --- a/docs/i18n/README.vi.md +++ b/docs/i18n/README.vi.md @@ -72,13 +72,6 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c        - - - - Gemini CLI - - -        @@ -87,7 +80,7 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c

-> Cài đặt hooks cho một hoặc bất kỳ tổ hợp nào: `failproofai policies --install --cli opencode pi gemini` (hoặc `--cli claude codex copilot cursor opencode pi gemini hermes`). Bỏ qua `--cli` để tự động phát hiện các CLI được cài đặt và nhắc lựa chọn. +> Cài đặt hooks cho một hoặc bất kỳ tổ hợp nào: `failproofai policies --install --cli opencode pi` (hoặc `--cli claude codex copilot cursor opencode pi hermes`). Bỏ qua `--cli` để tự động phát hiện các CLI được cài đặt và nhắc lựa chọn. > > **Hermes** (hermes-agent, một gateway Slack/Telegram) được hỗ trợ cho cả **thực thi live-hook** (`--cli hermes` — một cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng và subagent) và **kiểm toán** ngoại tuyến của các phiên gateway của nó từ `~/.hermes/state.db` duy nhất. diff --git a/docs/i18n/README.zh.md b/docs/i18n/README.zh.md index b6112fe9..32269ce7 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -71,13 +71,6 @@        - - - - Gemini CLI - - -        @@ -86,7 +79,7 @@

-> 可为一个或多个 CLI 安装 hooks:`failproofai policies --install --cli opencode pi gemini`(或 `--cli claude codex copilot cursor opencode pi gemini hermes`)。省略 `--cli` 参数将自动检测已安装的 CLI 并提示选择。 +> 可为一个或多个 CLI 安装 hooks:`failproofai policies --install --cli opencode pi`(或 `--cli claude codex copilot cursor opencode pi hermes`)。省略 `--cli` 参数将自动检测已安装的 CLI 并提示选择。 > > **Hermes**(hermes-agent,一个 Slack/Telegram 网关)同时支持**实时 hook 执行**(`--cli hermes` — 一次安装即可拦截所有平台和子智能体的工具调用)以及离线**审计**回放,可从单一的 `~/.hermes/state.db` 文件回放其网关会话。 diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 3d19c679..71a591e4 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI gives AI agents 39 built-in failure policies that catc [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks and policies for **AI failure handling**, **error recovery**, and **LLM reliability**. Keep your AI agents reliable and running autonomously across **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, and the **Agents SDK**. +Hooks and policies for **AI failure handling**, **error recovery**, and **LLM reliability**. Keep your AI agents reliable and running autonomously across **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, and the **Agents SDK**. AI agents fail in predictable ways. They run destructive commands, leak secrets, drift off-task, get stuck in loops, or push directly to main. Left unattended, small failures cascade into outages, leaked credentials, and lost work. diff --git a/docs/it/built-in-policies.mdx b/docs/it/built-in-policies.mdx index b13f76c4..287dc107 100644 --- a/docs/it/built-in-policies.mdx +++ b/docs/it/built-in-policies.mdx @@ -712,20 +712,19 @@ L'applicazione di Stop varia leggermente tra i sette CLI supportati perché ognu | Codex | Stesso loop dell'agent, immediatamente | Come Claude. | | GitHub Copilot CLI | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale di retry `{decision:"block", reason}` di Copilot — verificato empiricamente contro Copilot CLI 1.0.41). | | Cursor Agent | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale `{followup_message}` di Cursor — limitato a `loop_limit`, default 5 retry). | -| Gemini CLI | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale `{decision:"block", reason}` di Gemini su `AfterAgent`). | | OpenCode | Stesso loop dell'agent, immediatamente | Come Claude (usa la chiamata SDK `client.session.prompt(...)` di OpenCode instradato tramite `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Turno utente successivo** | **Pi si ferma visibilmente** quando il gate si attiva — il suo loop di agent esce e sei riportato al prompt. Il gate si attiva quindi la prossima volta che invii un prompt: failproofai prepone una direttiva `MANDATORY ACTION REQUIRED` al prompt di sistema di quel turno, istruendo il LLM a completare il passo del workflow (commit, push, ecc.) prima di fare tutto quello che hai chiesto. | -**Limitazione di Pi.** L'evento `AgentEndEvent` di Pi (l'equivalente upstream dell'hook `Stop` di Claude) non ha un tipo Result — nel momento in cui si attiva, il loop di agent di Pi è già uscito. Pi non può essere forzato a riprovare lo stesso loop nel modo in cui Claude / Copilot / Cursor / Gemini / OpenCode possono. failproofai sposta il gate all'evento `before_agent_start` di Pi (che si attiva dopo il prossimo prompt dell'utente) in modo che il controllo del workflow ancora si applichi, solo al turno successivo piuttosto che al turno corrente. +**Limitazione di Pi.** L'evento `AgentEndEvent` di Pi (l'equivalente upstream dell'hook `Stop` di Claude) non ha un tipo Result — nel momento in cui si attiva, il loop di agent di Pi è già uscito. Pi non può essere forzato a riprovare lo stesso loop nel modo in cui Claude / Copilot / Cursor / OpenCode possono. failproofai sposta il gate all'evento `before_agent_start` di Pi (che si attiva dopo il prossimo prompt dell'utente) in modo che il controllo del workflow ancora si applichi, solo al turno successivo piuttosto che al turno corrente. **Cosa significa nella pratica:** - Dopo che Pi si ferma, il motivo della negazione viene catturato in memoria keyed dall'ID sessione di Pi. Il prossimo prompt che invii nello stesso processo Pi lo scarica: l'LLM vede la direttiva `MANDATORY ACTION REQUIRED` in cima al suo prompt di sistema, fa il commit (o push / apre il PR / aspetta CI), e solo allora continua con la tua richiesta. Il motivo della negazione catturato è monouso — una volta scaricato, il gate è pulito. -- Il gate è limitato dalla durata del processo di Pi. Se fai `Ctrl+C` su Pi o esci tra i turni, la voce in memoria viene eliminata insieme al processo e il gate viene mancato. Claude, Copilot, Cursor, Gemini e OpenCode hanno lo stesso limite (uccidi l'agent e il gate viene mancato) — Pi lo rende solo più visibile perché l'agent si ferma visibilmente prima che il gate si attivi. +- Il gate è limitato dalla durata del processo di Pi. Se fai `Ctrl+C` su Pi o esci tra i turni, la voce in memoria viene eliminata insieme al processo e il gate viene mancato. Claude, Copilot, Cursor e OpenCode hanno lo stesso limite (uccidi l'agent e il gate viene mancato) — Pi lo rende solo più visibile perché l'agent si ferma visibilmente prima che il gate si attivi. - Una negazione in sospeso viene anche cancellata su `session_shutdown` per qualsiasi motivo (`new` / `resume` / `fork` / `quit`), quindi un gate stantio da una sessione precedente non può fuoriuscire in una sessione fresca avviata nello stesso processo Pi. -Se hai bisogno del retry dello stesso loop nello stile di Claude, esegui le tue politiche di `Stop` sotto uno dei sei altri CLI supportati. Stiamo monitorando Pi upstream per un tipo Result futuro su `AgentEndEvent` che ci permetterebbe di chiudere questo gap. +Se hai bisogno del retry dello stesso loop nello stile di Claude, esegui le tue politiche di `Stop` sotto uno dei cinque altri CLI supportati. Stiamo monitorando Pi upstream per un tipo Result futuro su `AgentEndEvent` che ci permetterebbe di chiudere questo gap. ### `require-commit-before-stop` diff --git a/docs/it/cli/audit.mdx b/docs/it/cli/audit.mdx index 7e463043..08b68e37 100644 --- a/docs/it/cli/audit.mdx +++ b/docs/it/cli/audit.mdx @@ -52,7 +52,7 @@ failproofai finché non lo arresti con `Ctrl+C`. -Il dashboard scansiona i transcript passati da agent CLI su questa macchina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e segnala con che frequenza l'agente ha fatto cose che failproofai è costruito per bloccare — controlli di variabili d'ambiente, push forzati, prefissi `cd ` ridondanti, loop di polling con sleep, ri-letture di file appena modificati, e altro. +Il dashboard scansiona i transcript passati da agent CLI su questa macchina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e segnala con che frequenza l'agente ha fatto cose che failproofai è costruito per bloccare — controlli di variabili d'ambiente, push forzati, prefissi `cd ` ridondanti, loop di polling con sleep, ri-letture di file appena modificati, e altro. Per ogni transcript, ogni evento tool-use viene rieseguito attraverso le 39 policy integrate **e** attraverso 8 rilevatori solo audit che catturano pattern non ancora coperti da policy runtime. I conteggi vengono aggregati per policy / rilevatore in tutte le sessioni. diff --git a/docs/it/configuration.mdx b/docs/it/configuration.mdx index ad260ca3..e9d6f33e 100644 --- a/docs/it/configuration.mdx +++ b/docs/it/configuration.mdx @@ -196,13 +196,12 @@ I comandi `policies --install` e `policies --uninstall` scrivono nel file di imp - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex non ha un ambito `local` - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot non ha un ambito `local`. Le voci hook usano i campi di comando `bash`/`powershell` di Copilot con chiave OS e `timeoutSec`; il file porta un marcatore `version: 1` di alto livello. Il supporto di Copilot CLI è **beta** mentre verifichiamo lo schema del record `events.jsonl` (che la documentazione pubblica non specifica) rispetto a più sessioni del mondo reale. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor non ha un ambito `local`. Le voci hook usano la forma `{type, command, timeout}` a forma di Claude (senza split `bash`/`powershell`), ma memorizzate sotto chiavi di evento camelCase (`preToolUse`, `beforeSubmitPrompt`, …) in un array piatto per lo [schema degli hook](https://cursor.com/docs/hooks) di Cursor; il file porta un marcatore `version: 1` di alto livello. Il gestore canonicalizza camelCase → PascalCase tramite `CURSOR_EVENT_MAP` quindi le policy built-in esistenti si attivano invariate. Il supporto di Cursor Agent è **beta** mentre verifichiamo il formato del transcript di Cursor su disco (non specificato nella documentazione pubblica) rispetto a più installazioni del mondo reale. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode non ha un ambito `local`. A differenza degli altri sei CLI, OpenCode ha **nessun sistema di hook per comando esterno**: carica plugin JS/TS in-process esplicitamente registrati tramite l'array `plugin: []` in `opencode.json` (l'auto-discovery da `.opencode/plugins/` **non** è come i plugin vengono caricati su opencode v1.14.33). L'installazione rilascia un piccolo shim plugin generato che subprocess-chiama il binario failproofai e traduce la risposta JSON a forma di Claude del binario di nuovo in semantica plugin: `throw new Error()` per tool-event deny (cancella la chiamata dello strumento), `client.session.prompt(...)` per instruct E per deny di `Stop` / `SubagentStop` (invia la ragione di deny come prossimo messaggio utente — l'unico canale force-retry dal momento che `session.idle` è notification-only e gettare da essa è un no-op), e no-op per allow. Lo shim canonicalizza sia i nomi di strumento (lowercase → PascalCase tramite `OPENCODE_TOOL_MAP`) che le chiavi degli argomenti di input dello strumento (camelCase → snake_case tramite `OPENCODE_TOOL_INPUT_MAP` per `Read` / `Write` / `Edit`, ad es. `filePath` → `file_path`, `oldString` → `old_string`) prima di inoltrarsi al binario, così il controllo dei percorsi built-in come `block-read-outside-cwd`, `block-env-files`, e `block-secrets-write` si attivano invariate sulle chiamate agli strumenti di OpenCode. Le sessioni vivono nel DB SQLite di opencode presso `~/.local/share/opencode/opencode.db`; il visualizzatore di sessioni della dashboard li legge tramite `opencode db --format json` e `opencode export `. Il supporto di OpenCode è **beta** mentre verifichiamo il comportamento attraverso versioni e rispetto a più sessioni del mondo reale. Vedi la [documentazione dei plugin di OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode non ha un ambito `local`. A differenza degli altri cinque CLI, OpenCode ha **nessun sistema di hook per comando esterno**: carica plugin JS/TS in-process esplicitamente registrati tramite l'array `plugin: []` in `opencode.json` (l'auto-discovery da `.opencode/plugins/` **non** è come i plugin vengono caricati su opencode v1.14.33). L'installazione rilascia un piccolo shim plugin generato che subprocess-chiama il binario failproofai e traduce la risposta JSON a forma di Claude del binario di nuovo in semantica plugin: `throw new Error()` per tool-event deny (cancella la chiamata dello strumento), `client.session.prompt(...)` per instruct E per deny di `Stop` / `SubagentStop` (invia la ragione di deny come prossimo messaggio utente — l'unico canale force-retry dal momento che `session.idle` è notification-only e gettare da essa è un no-op), e no-op per allow. Lo shim canonicalizza sia i nomi di strumento (lowercase → PascalCase tramite `OPENCODE_TOOL_MAP`) che le chiavi degli argomenti di input dello strumento (camelCase → snake_case tramite `OPENCODE_TOOL_INPUT_MAP` per `Read` / `Write` / `Edit`, ad es. `filePath` → `file_path`, `oldString` → `old_string`) prima di inoltrarsi al binario, così il controllo dei percorsi built-in come `block-read-outside-cwd`, `block-env-files`, e `block-secrets-write` si attivano invariate sulle chiamate agli strumenti di OpenCode. Le sessioni vivono nel DB SQLite di opencode presso `~/.local/share/opencode/opencode.db`; il visualizzatore di sessioni della dashboard li legge tramite `opencode db --format json` e `opencode export `. Il supporto di OpenCode è **beta** mentre verifichiamo il comportamento attraverso versioni e rispetto a più sessioni del mondo reale. Vedi la [documentazione dei plugin di OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi non ha un ambito `local`. Pi carica pacchetti di estensioni TypeScript all'avvio; il file di impostazioni è un array di stringhe piatto `{"packages": ["./relative/path", …]}`. failproofai scrive una singola voce dell'array dei pacchetti che punta alla sua directory `pi-extension/` in bundle. L'estensione internamente si sottoscrive agli eventi `tool_call` / `user_bash` / `input` / `session_start` di Pi e guscio fuori a `failproofai --hook --cli pi`; il gestore canonicalizza underscore_lower_snake_case → PascalCase tramite `PI_EVENT_MAP` quindi le policy built-in esistenti si attivano invariate. Gli argomenti di input dello strumento sono anche canonicalizzati tramite `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit forniscono `path` piuttosto che `file_path`; mappare la chiave di top-level lascia che `block-env-files` e `block-secrets-write` si attivino — `block-read-outside-cwd` già aveva un fallback `path`). Il supporto di Pi è **beta** mentre l'API di estensione di Pi e il layout del log di sessione si stabilizzano. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini non ha un ambito `local` (documenta un ambito `system` presso `/etc/gemini-cli/settings.json` che failproofai non espone). Le voci hook usano la forma `{type, command, timeout}` di Claude avvolta nello schema matcher `{matcher, hooks: [...]}` di Gemini con `matcher: "*"` di default. Gli eventi sono PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); il gestore mappa ai nomi canonici Claude tramite `GEMINI_EVENT_MAP`. I nomi di strumento sono snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — il gestore canonicalizza tramite `GEMINI_TOOL_MAP` quindi le policy built-in esistenti si attivano invariate. L'evaluator di policy emette la forma piatta di Gemini `{decision: "deny", reason}` (preferita per il contratto Golden Rule di Gemini exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` per l'iniezione di contesto su BeforeAgent / AfterTool / SessionStart, e `{decision: "block", reason}` su AfterAgent per la semantica force-retry. Il supporto di Gemini CLI è **beta** mentre allargheremo la copertura del mondo reale. Vedi la [documentazione degli hook di Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**ambito utente solo** — Hermes non ha configurazione project/local). Hermes è un gateway **Slack/Telegram**, quindi un'installazione intercetta le chiamate di strumento da ogni piattaforma (Slack/Telegram/cli/cron) **e** subagent interni. Le voci hook sono una coppia `{command, timeout}` (timeout in **secondi**) sotto una mappa `hooks:` codificata dagli eventi snake_case di Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); il gestore canonicalizza gli eventi tramite `HERMES_EVENT_MAP` e i nomi di strumento tramite `HERMES_TOOL_MAP` quindi le policy built-in si attivano invariate. La configurazione è modificata tramite una `Document` YAML di preservazione dei commenti round-trip in modo che le altre impostazioni dell'operatore sopravvivano, e l'installazione imposta `hooks_auto_accept: true` così il gateway headless (no TTY) esegue gli hook senza un prompt di consenso. L'evaluator emette il contratto stdout `{"decision":"block","reason"}` di Hermes (Hermes ignora i codici di uscita). **Limitazioni:** Hermes non ha un evento end-turn `Stop`, quindi le policy built-in `require-*-before-stop` non si attivano mai per esso (inapplicabile, non rotto); `instruct` degrada a allow-with-logged-note (nessun canale additional-context); e la redazione di secret di output (`sanitize-*`) non può riscrivere l'output dello strumento sul contratto dell'hook di shell. Hermes è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni di gateway direttamente da `~/.hermes/state.db`. - **`policies-config.json`** — dice a failproofai quali policy valutare e con quali parametri (condiviso su tutti gli agent CLI) -Passa `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` per indirizzare un agent specifico (space-separated o ripetuto per qualsiasi subset): +Passa `--cli claude|codex|copilot|cursor|opencode|pi|hermes` per indirizzare un agent specifico (space-separated o ripetuto per qualsiasi subset): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Quando `--cli` è omesso, `failproofai` rileva quali agent CLI sono installati (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Quando `--cli` è omesso, `failproofai` rileva quali agent CLI sono installati (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Un CLI rilevato** — auto-seleziona quel CLI senza chiedere. - **Più CLI rilevati** in un terminale interattivo — mostra un prompt single-select con tasti freccia raggruppati in una sezione `Detected (N)` (con una riga aggregata `Install for all N detected` + ogni CLI rilevato singolarmente) e una sezione `Not installed (M) · install hooks ahead of time` che elenca ogni CLI non rilevato supportato come opzione forward-install (↑↓ per muoversi, Enter per selezionare, ^C per uscire). Il flusso di disinstallazione mostra solo la sezione Detected. diff --git a/docs/it/dashboard.mdx b/docs/it/dashboard.mdx index a4dcc440..7ee94550 100644 --- a/docs/it/dashboard.mdx +++ b/docs/it/dashboard.mdx @@ -24,11 +24,11 @@ Il dashboard legge direttamente dal filesystem - le tue cartelle di progetti Cla ### Progetti -Elenca tutti i progetti Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ e Hermes trovati sulla tua macchina. I progetti Claude vengono rilevati da `~/.claude/projects/` (o dal percorso impostato da `CLAUDE_PROJECTS_PATH`); i progetti Codex vengono rilevati scansionando ogni trascrizione in `~/.codex/sessions///
/*.jsonl` e raggruppando per il `cwd` registrato nel primo record di ogni sessione; i progetti Copilot CLI vengono rilevati scansionando ogni `~/.copilot/session-state//workspace.yaml` (configurabile tramite `COPILOT_HOME`) e raggruppando per il suo campo `cwd`; i progetti Cursor Agent vengono rilevati scansionando i metadati per sessione in `~/.cursor/agent-sessions//` (configurabile tramite `CURSOR_HOME`, con `conversations/` e `sessions/` testati come fallback) per uno scalare `cwd` in `meta.json` / `session.json` / `workspace.yaml`; i progetti OpenCode vengono rilevati interrogando il suo DB SQLite in `~/.local/share/opencode/opencode.db` tramite `opencode db --format json` (leggiamo le tabelle `session` e `project` e raggruppiamo per `project_id`); i progetti Pi vengono rilevati scansionando trascrizioni JSONL per sessione in `~/.pi/agent/sessions//_.jsonl` (configurabile tramite `PI_SESSIONS_DIR`) e estraendo il `cwd` dal primo record di ogni sessione; i progetti Gemini CLI vengono rilevati scansionando `~/.gemini/tmp//chats/session--.jsonl` (configurabile tramite `GEMINI_SESSIONS_DIR`) e recuperando il cwd canonico dal marcatore di testo `.project_root` adiacente; le sessioni del gateway Hermes vengono lette direttamente dal suo archivio SQLite in `~/.hermes/state.db` (configurabile tramite `HERMES_DB_PATH`) e raggruppate in progetti `hermes-` per `source` (Slack/Telegram/cli/cron — le sessioni del gateway non hanno cwd). Un progetto utilizzato da più CLI viene visualizzato come una singola riga con tutti i badge corrispondenti. Utilizza il dropdown **CLI** sopra la tabella per filtrare per uno specifico agente CLI; l'URL preserva la tua selezione come `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Elenca tutti i progetti Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ e Hermes trovati sulla tua macchina. I progetti Claude vengono rilevati da `~/.claude/projects/` (o dal percorso impostato da `CLAUDE_PROJECTS_PATH`); i progetti Codex vengono rilevati scansionando ogni trascrizione in `~/.codex/sessions///
/*.jsonl` e raggruppando per il `cwd` registrato nel primo record di ogni sessione; i progetti Copilot CLI vengono rilevati scansionando ogni `~/.copilot/session-state//workspace.yaml` (configurabile tramite `COPILOT_HOME`) e raggruppando per il suo campo `cwd`; i progetti Cursor Agent vengono rilevati scansionando i metadati per sessione in `~/.cursor/agent-sessions//` (configurabile tramite `CURSOR_HOME`, con `conversations/` e `sessions/` testati come fallback) per uno scalare `cwd` in `meta.json` / `session.json` / `workspace.yaml`; i progetti OpenCode vengono rilevati interrogando il suo DB SQLite in `~/.local/share/opencode/opencode.db` tramite `opencode db --format json` (leggiamo le tabelle `session` e `project` e raggruppiamo per `project_id`); i progetti Pi vengono rilevati scansionando trascrizioni JSONL per sessione in `~/.pi/agent/sessions//_.jsonl` (configurabile tramite `PI_SESSIONS_DIR`) e estraendo il `cwd` dal primo record di ogni sessione; le sessioni del gateway Hermes vengono lette direttamente dal suo archivio SQLite in `~/.hermes/state.db` (configurabile tramite `HERMES_DB_PATH`) e raggruppate in progetti `hermes-` per `source` (Slack/Telegram/cli/cron — le sessioni del gateway non hanno cwd). Un progetto utilizzato da più CLI viene visualizzato come una singola riga con tutti i badge corrispondenti. Utilizza il dropdown **CLI** sopra la tabella per filtrare per uno specifico agente CLI; l'URL preserva la tua selezione come `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Ogni progetto mostra: - Nome del progetto (derivato dal percorso della cartella) -- Un badge CLI — `Claude Code` (arancione), `OpenAI Codex` (viola), `GitHub Copilot` (blu), `Cursor Agent` (smeraldo), `OpenCode` (ambra), `Pi` (rosa), `Gemini CLI` (cielo), e/o `Hermes` (indaco) +- Un badge CLI — `Claude Code` (arancione), `OpenAI Codex` (viola), `GitHub Copilot` (blu), `Cursor Agent` (smeraldo), `OpenCode` (ambra), `Pi` (rosa), e/o `Hermes` (indaco) - Data dell'attività di sessione più recente Fai clic su un progetto per vedere le sue sessioni. @@ -47,7 +47,7 @@ Fai clic su una sessione per aprire il visualizzatore di sessione. ### Visualizzatore di sessione -Il visualizzatore di sessione risponde alla domanda chiave per gli agenti autonomi: cosa ha fatto l'agente e ha mantenuto il percorso corretto? Un badge CLI accanto all'intestazione indica se la sessione è una trascrizione di Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI o Hermes. Mostra una cronologia di tutto ciò che è accaduto in una sessione: +Il visualizzatore di sessione risponde alla domanda chiave per gli agenti autonomi: cosa ha fatto l'agente e ha mantenuto il percorso corretto? Un badge CLI accanto all'intestazione indica se la sessione è una trascrizione di Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi o Hermes. Mostra una cronologia di tutto ciò che è accaduto in una sessione: - **Messaggi** - Risposte di testo di Claude e prompt dell'utente - **Chiamate agli strumenti** - Ogni strumento invocato da Claude, con il suo input e output @@ -55,7 +55,7 @@ Il visualizzatore di sessione risponde alla domanda chiave per gli agenti autono La barra delle statistiche in alto mostra la durata della sessione, il totale delle chiamate agli strumenti e un riepilogo delle decisioni hook (conteggi allow / deny / instruct). -Fai clic sul pulsante **Download Logs** per esportare la sessione. Per le sessioni Claude Code, Codex, Copilot, Cursor, Pi e Gemini ricevi la trascrizione JSONL originale su disco byte-per-byte; per OpenCode (le cui sessioni si trovano in SQLite, non su disco) ricevi un documento JSON che rispecchia le tabelle `session` / `messages` / `parts` sottostanti. +Fai clic sul pulsante **Download Logs** per esportare la sessione. Per le sessioni Claude Code, Codex, Copilot, Cursor e Pi ricevi la trascrizione JSONL originale su disco byte-per-byte; per OpenCode (le cui sessioni si trovano in SQLite, non su disco) ricevi un documento JSON che rispecchia le tabelle `session` / `messages` / `parts` sottostanti. ### Audit @@ -75,16 +75,16 @@ Una pagina con due schede per gestire i criteri e rivedere l'attività. - - Seleziona quale agenti CLI failproofai protegge da un singolo pannello — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI e Hermes hanno tutti una riga con stato di installazione (`Active` / `Detected` / `Inactive`), il percorso delle impostazioni dell'ambito utente e un accento di colore del marchio. Seleziona o deseleziona i CLI che desideri e fai clic su `Apply changes` per installare/disinstallare il diff in un unico passaggio. I CLI il cui binario viene rilevato su PATH sono pre-selezionati. + - Seleziona quale agenti CLI failproofai protegge da un singolo pannello — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi e Hermes hanno tutti una riga con stato di installazione (`Active` / `Detected` / `Inactive`), il percorso delle impostazioni dell'ambito utente e un accento di colore del marchio. Seleziona o deseleziona i CLI che desideri e fai clic su `Apply changes` per installare/disinstallare il diff in un unico passaggio. I CLI il cui binario viene rilevato su PATH sono pre-selezionati. - Attiva o disattiva i singoli criteri con un singolo clic (scrive su `~/.failproofai/policies-config.json` — condiviso tra ogni CLI installata) - Espandi un criterio per configurare i suoi parametri (per i criteri che supportano `policyParams`) - Imposta un percorso file criteri personalizzato - Cronologia completa impaginata di ogni evento hook che si è attivato in tutte le sessioni - - Filtra per decisione, tipo di evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nome del criterio o ID della sessione - - Ogni riga mostra: timestamp, nome del criterio, decisione, badge CLI (arancione = Claude Code, viola = OpenAI Codex, blu = GitHub Copilot, smeraldo = Cursor Agent, ambra = OpenCode, rosa = Pi, cielo = Gemini CLI, indaco = Hermes), nome dello strumento, ID della sessione e il motivo delle decisioni deny/instruct - - Fai clic su un ID della sessione per aprire la sua trascrizione — il visualizzatore rileva automaticamente quale CLI ha attivato l'hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) e visualizza il badge CLI corrispondente nell'intestazione + - Filtra per decisione, tipo di evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), nome del criterio o ID della sessione + - Ogni riga mostra: timestamp, nome del criterio, decisione, badge CLI (arancione = Claude Code, viola = OpenAI Codex, blu = GitHub Copilot, smeraldo = Cursor Agent, ambra = OpenCode, rosa = Pi, indaco = Hermes), nome dello strumento, ID della sessione e il motivo delle decisioni deny/instruct + - Fai clic su un ID della sessione per aprire la sua trascrizione — il visualizzatore rileva automaticamente quale CLI ha attivato l'hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) e visualizza il badge CLI corrispondente nell'intestazione diff --git a/docs/it/getting-started.mdx b/docs/it/getting-started.mdx index fb583f43..eb79afe0 100644 --- a/docs/it/getting-started.mdx +++ b/docs/it/getting-started.mdx @@ -38,9 +38,9 @@ bun add -g failproofai failproofai policies --install ``` - Questo scrive voci di hook nei tuoi agent CLI installati (il file `~/.claude/settings.json` di Claude Code, il file `~/.codex/hooks.json` di OpenAI Codex, il file `~/.copilot/hooks/failproofai.json` di GitHub Copilot CLI, il file `~/.cursor/hooks.json` di Cursor Agent, lo shim del plugin generato di OpenCode in `~/.config/opencode/plugins/failproofai.mjs` più una voce di registrazione nell'array `plugin` di `~/.config/opencode/opencode.json`, il file `~/.pi/agent/settings.json` di Pi, il file `~/.gemini/settings.json` di Gemini CLI, o il file `~/.hermes/config.yaml` di Hermes). Quando è presente più di uno, ti verrà chiesto; passa `--cli claude codex copilot cursor opencode pi gemini hermes` (qualsiasi sottoinsieme) per saltare la richiesta. + Questo scrive voci di hook nei tuoi agent CLI installati (il file `~/.claude/settings.json` di Claude Code, il file `~/.codex/hooks.json` di OpenAI Codex, il file `~/.copilot/hooks/failproofai.json` di GitHub Copilot CLI, il file `~/.cursor/hooks.json` di Cursor Agent, lo shim del plugin generato di OpenCode in `~/.config/opencode/plugins/failproofai.mjs` più una voce di registrazione nell'array `plugin` di `~/.config/opencode/opencode.json`, il file `~/.pi/agent/settings.json` di Pi, o il file `~/.hermes/config.yaml` di Hermes). Quando è presente più di uno, ti verrà chiesto; passa `--cli claude codex copilot cursor opencode pi hermes` (qualsiasi sottoinsieme) per saltare la richiesta. - Il supporto per GitHub Copilot CLI, Cursor Agent, OpenCode, Pi e Gemini CLI è in **beta** — installa con `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` o `--cli gemini`. Hermes (hermes-agent, un gateway Slack/Telegram) si installa con ambito utente con `--cli hermes` ed è **anche** una fonte di audit offline. + Il supporto per GitHub Copilot CLI, Cursor Agent, OpenCode e Pi è in **beta** — installa con `--cli copilot`, `--cli cursor`, `--cli opencode` o `--cli pi`. Hermes (hermes-agent, un gateway Slack/Telegram) si installa con ambito utente con `--cli hermes` ed è **anche** una fonte di audit offline. ```bash failproofai policies --install --scope project @@ -49,7 +49,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/it/introduction.mdx b/docs/it/introduction.mdx index 0a1d097f..4ac02107 100644 --- a/docs/it/introduction.mdx +++ b/docs/it/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI fornisce agli agenti AI 39 politiche di fallimento int [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hook e politiche per **gestione dei fallimenti dell'AI**, **recupero degli errori** e **affidabilità dell'LLM**. Mantieni i tuoi agenti AI affidabili e in esecuzione autonoma su **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** e **Agents SDK**. +Hook e politiche per **gestione dei fallimenti dell'AI**, **recupero degli errori** e **affidabilità dell'LLM**. Mantieni i tuoi agenti AI affidabili e in esecuzione autonoma su **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** e **Agents SDK**. Gli agenti AI falliscono in modi prevedibili. Eseguono comandi distruttivi, perdono segreti, si allontanano dall'obiettivo, rimangono bloccati in loop, o effettuano push direttamente al main. Se non controllati, piccoli fallimenti si trasformano in interruzioni, credenziali compromesse e lavoro perso. diff --git a/docs/ja/built-in-policies.mdx b/docs/ja/built-in-policies.mdx index f36abfd2..f0b1b435 100644 --- a/docs/ja/built-in-policies.mdx +++ b/docs/ja/built-in-policies.mdx @@ -704,7 +704,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ### CLI ごとの Stop セマンティクス -Stop の強制は、サポートされている7つの CLI によって若干異なります。各 CLI が異なる「エージェント終了」フックコントラクトを公開しているためです。**結果**は同じです(ワークフローゲートが失敗している間、エージェントは停止できません)が、**仕組み**は異なります。以下の表に要約します。`require-*-before-stop` ポリシーを有効にする前に理解しておく価値のある、ユーザーに見える挙動があるのは Pi のみです。 +Stop の強制は、サポートされている6つの CLI によって若干異なります。各 CLI が異なる「エージェント終了」フックコントラクトを公開しているためです。**結果**は同じです(ワークフローゲートが失敗している間、エージェントは停止できません)が、**仕組み**は異なります。以下の表に要約します。`require-*-before-stop` ポリシーを有効にする前に理解しておく価値のある、ユーザーに見える挙動があるのは Pi のみです。 | CLI | ゲートが発火するタイミング | 表示される内容 | |---|---|---| @@ -712,20 +712,19 @@ Stop の強制は、サポートされている7つの CLI によって若干異 | Codex | 同じエージェントループ内で即座に | Claude と同じです。 | | GitHub Copilot CLI | 同じエージェントループ内で即座に | Claude と同じです(Copilot の `{decision:"block", reason}` リトライチャネルを使用 — Copilot CLI 1.0.41 で実証的に検証済み)。 | | Cursor Agent | 同じエージェントループ内で即座に | Claude と同じです(Cursor の `{followup_message}` チャネルを使用 — デフォルト5回の `loop_limit` に上限あり)。 | -| Gemini CLI | 同じエージェントループ内で即座に | Claude と同じです(`AfterAgent` 上の Gemini の `{decision:"block", reason}` チャネルを使用)。 | | OpenCode | 同じエージェントループ内で即座に | Claude と同じです(`hookSpecificOutput.additionalContext` を通じてルーティングされた OpenCode の `client.session.prompt(...)` SDK 呼び出しを使用)。 | | **Pi (pi-coding-agent)** | **次のユーザーターン** | **Pi はゲートが発火すると目に見えて停止します** — エージェントループが終了し、プロンプトに戻ります。次にプロンプトを送信した際にゲートが発火します:failproofai はそのターンのシステムプロンプトの先頭に `MANDATORY ACTION REQUIRED` ディレクティブを付加し、あなたのリクエストを実行する前にワークフローステップ(コミット、プッシュなど)を完了するよう LLM に指示します。 | -**Pi の制限事項。** Pi の `AgentEndEvent`(Claude の `Stop` フックに相当するアップストリーム)には Result タイプがありません。発火した時点で Pi のエージェントループはすでに終了しています。Claude / Copilot / Cursor / Gemini / OpenCode のように Pi を同じループで再試行させることはできません。failproofai はゲートを Pi の `before_agent_start` イベント(次のユーザープロンプトの後に発火)にシフトするため、ワークフローチェックは依然として強制されますが、現在のターンではなく次のターンで適用されます。 +**Pi の制限事項。** Pi の `AgentEndEvent`(Claude の `Stop` フックに相当するアップストリーム)には Result タイプがありません。発火した時点で Pi のエージェントループはすでに終了しています。Claude / Copilot / Cursor / OpenCode のように Pi を同じループで再試行させることはできません。failproofai はゲートを Pi の `before_agent_start` イベント(次のユーザープロンプトの後に発火)にシフトするため、ワークフローチェックは依然として強制されますが、現在のターンではなく次のターンで適用されます。 **実際の動作:** - Pi が停止した後、deny の理由は Pi のセッション ID をキーとしてメモリ内に保存されます。同じ Pi プロセスで次に送信したプロンプトがそれを消費します:LLM はシステムプロンプトの先頭で `MANDATORY ACTION REQUIRED` ディレクティブを確認し、コミット(またはプッシュ / PR 作成 / CI 待機)してから、あなたのリクエストを続行します。保存された deny の理由は一度消費されるとクリアされ、ゲートは解除されます。 -- ゲートは Pi のプロセスの存続期間に縛られます。ターンの間に Pi を `Ctrl+C` で終了するか終了した場合、メモリ内のエントリはプロセスとともに削除され、ゲートは失われます。Claude、Copilot、Cursor、Gemini、OpenCode も同じ制約があります(エージェントを強制終了するとゲートは失われます)。Pi はエージェントがゲートの発火前に目に見えて終了するため、これがより顕著に現れます。 +- ゲートは Pi のプロセスの存続期間に縛られます。ターンの間に Pi を `Ctrl+C` で終了するか終了した場合、メモリ内のエントリはプロセスとともに削除され、ゲートは失われます。Claude、Copilot、Cursor、OpenCode も同じ制約があります(エージェントを強制終了するとゲートは失われます)。Pi はエージェントがゲートの発火前に目に見えて終了するため、これがより顕著に現れます。 - 保留中の deny は、任意の理由(`new` / `resume` / `fork` / `quit`)による `session_shutdown` でもクリアされるため、前のセッションの古いゲートが同じ Pi プロセスで開始された新しいセッションに漏れることはありません。 -Claude スタイルの同ループ再試行が必要な場合は、他の6つのサポートされている CLI のいずれかで `Stop` ポリシーを実行してください。`AgentEndEvent` に Result タイプを追加するためのアップストリームの Pi の更新を追跡しており、これによりこのギャップを解消できる可能性があります。 +Claude スタイルの同ループ再試行が必要な場合は、他の5つのサポートされている CLI のいずれかで `Stop` ポリシーを実行してください。`AgentEndEvent` に Result タイプを追加するためのアップストリームの Pi の更新を追跡しており、これによりこのギャップを解消できる可能性があります。 ### `require-commit-before-stop` diff --git a/docs/ja/cli/audit.mdx b/docs/ja/cli/audit.mdx index 4b218e71..06d249d1 100644 --- a/docs/ja/cli/audit.mdx +++ b/docs/ja/cli/audit.mdx @@ -47,7 +47,7 @@ failproofai 使い方を確認するには `failproofai audit -h`(または `--help`)を実行してください。監査は**完全オフライン**で動作し、アカウントやネットワーク接続は不要です。`Ctrl+C` で停止するまでダッシュボードはサービスを継続します。 -ダッシュボードはこのマシン上の過去のエージェント CLI トランスクリプト(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi、Gemini)をスキャンし、failproofai が防止するように設計された操作の発生頻度を報告します。対象は環境変数チェック、フォースプッシュ、冗長な `cd ` プレフィックス、スリープポーリングループ、編集直後のファイル再読み込みなどです。 +ダッシュボードはこのマシン上の過去のエージェント CLI トランスクリプト(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi)をスキャンし、failproofai が防止するように設計された操作の発生頻度を報告します。対象は環境変数チェック、フォースプッシュ、冗長な `cd ` プレフィックス、スリープポーリングループ、編集直後のファイル再読み込みなどです。 各トランスクリプトについて、すべてのツール使用イベントが 39 のビルトインポリシー**および** 8 つの監査専用検出器で再実行されます(後者はランタイムポリシーでまだカバーされていないパターンを検出します)。カウントはポリシー・検出器ごとにすべてのセッションで集計されます。 diff --git a/docs/ja/configuration.mdx b/docs/ja/configuration.mdx index 9c428489..3249b28b 100644 --- a/docs/ja/configuration.mdx +++ b/docs/ja/configuration.mdx @@ -196,13 +196,12 @@ AI 呼び出しを行うポリシーのための LLM クライアント設定。 - **OpenAI Codex**: `~/.codex/hooks.json`(ユーザー)、`/.codex/hooks.json`(プロジェクト)— Codex には `local` スコープがありません - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json`(ユーザー)、`/.github/hooks/failproofai.json`(プロジェクト)— Copilot には `local` スコープがありません。フックエントリは Copilot の OS キー付き `bash`/`powershell` コマンドフィールドと `timeoutSec` を使用し、ファイルにはトップレベルの `version: 1` マーカーが付きます。`events.jsonl` レコードスキーマ(公開ドキュメントに記載なし)を実際の使用環境で検証中のため、Copilot CLI のサポートは**ベータ版**です。 - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json`(ユーザー)、`/.cursor/hooks.json`(プロジェクト)— Cursor には `local` スコープがありません。フックエントリは Claude 形式の `{type, command, timeout}` を使用しますが、Cursor の[フックスキーマ](https://cursor.com/docs/hooks)に従いキャメルケースのイベントキー(`preToolUse`、`beforeSubmitPrompt` など)のフラット配列として保存され、ファイルにはトップレベルの `version: 1` マーカーが付きます。ハンドラーは `CURSOR_EVENT_MAP` を通じてキャメルケース → PascalCase に正規化するため、既存の組み込みポリシーはそのまま動作します。Cursor のトランスクリプトのオンディスクフォーマット(公開ドキュメントに未記載)を実際の環境で検証中のため、Cursor Agent のサポートは**ベータ版**です。 - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(ユーザー)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(プロジェクト)— OpenCode には `local` スコープがありません。他の6つの CLI とは異なり、OpenCode には**外部コマンドフックシステムがありません**。`opencode.json` の `plugin: []` 配列で明示的に登録された JS/TS プラグインをインプロセスでロードします(`.opencode/plugins/` からの自動検出は opencode v1.14.33 でのプラグインロード方法では**ありません**)。インストール時に小さな生成プラグインシムが配置され、failproofai バイナリをサブプロセスで呼び出し、バイナリの Claude 形式 JSON レスポンスをプラグインセマンティクスに変換します:ツールイベントの deny には `throw new Error()`(ツール呼び出しをキャンセル)、instruct および `Stop` / `SubagentStop` の deny には `client.session.prompt(...)`(deny の理由を次のユーザーメッセージとして送信 — `session.idle` が通知専用で例外をスローしても無効なため、強制リトライの唯一のチャネル)、allow には no-op を使用します。シムはツール名(小文字 → `OPENCODE_TOOL_MAP` を通じた PascalCase)とツール入力引数のキー(`OPENCODE_TOOL_INPUT_MAP` を通じたキャメルケース → スネークケース:`Read` / `Write` / `Edit` の `filePath` → `file_path`、`oldString` → `old_string` など)を正規化してからバイナリに転送するため、`block-read-outside-cwd`、`block-env-files`、`block-secrets-write` などのパスチェック組み込みポリシーは OpenCode のツール呼び出しでもそのまま動作します。セッションは `~/.local/share/opencode/opencode.db` の OpenCode の SQLite DB に保存され、ダッシュボードのセッションビューアーは `opencode db --format json` と `opencode export ` を通じて読み取ります。バージョン間の動作や実際の使用環境での検証中のため、OpenCode のサポートは**ベータ版**です。[OpenCode プラグインドキュメント](https://opencode.ai/docs/plugins/)を参照してください。 + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(ユーザー)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(プロジェクト)— OpenCode には `local` スコープがありません。他の5つの CLI とは異なり、OpenCode には**外部コマンドフックシステムがありません**。`opencode.json` の `plugin: []` 配列で明示的に登録された JS/TS プラグインをインプロセスでロードします(`.opencode/plugins/` からの自動検出は opencode v1.14.33 でのプラグインロード方法では**ありません**)。インストール時に小さな生成プラグインシムが配置され、failproofai バイナリをサブプロセスで呼び出し、バイナリの Claude 形式 JSON レスポンスをプラグインセマンティクスに変換します:ツールイベントの deny には `throw new Error()`(ツール呼び出しをキャンセル)、instruct および `Stop` / `SubagentStop` の deny には `client.session.prompt(...)`(deny の理由を次のユーザーメッセージとして送信 — `session.idle` が通知専用で例外をスローしても無効なため、強制リトライの唯一のチャネル)、allow には no-op を使用します。シムはツール名(小文字 → `OPENCODE_TOOL_MAP` を通じた PascalCase)とツール入力引数のキー(`OPENCODE_TOOL_INPUT_MAP` を通じたキャメルケース → スネークケース:`Read` / `Write` / `Edit` の `filePath` → `file_path`、`oldString` → `old_string` など)を正規化してからバイナリに転送するため、`block-read-outside-cwd`、`block-env-files`、`block-secrets-write` などのパスチェック組み込みポリシーは OpenCode のツール呼び出しでもそのまま動作します。セッションは `~/.local/share/opencode/opencode.db` の OpenCode の SQLite DB に保存され、ダッシュボードのセッションビューアーは `opencode db --format json` と `opencode export ` を通じて読み取ります。バージョン間の動作や実際の使用環境での検証中のため、OpenCode のサポートは**ベータ版**です。[OpenCode プラグインドキュメント](https://opencode.ai/docs/plugins/)を参照してください。 - **Pi _(beta)_**: `~/.pi/agent/settings.json`(ユーザー)、`/.pi/settings.json`(プロジェクト)— Pi には `local` スコープがありません。Pi は起動時に TypeScript 拡張パッケージをロードします。設定ファイルはフラットな文字列配列 `{"packages": ["./relative/path", …]}` です。failproofai はバンドルされた `pi-extension/` ディレクトリを指す単一の packages 配列エントリを書き込みます。拡張機能は内部で Pi の `tool_call` / `user_bash` / `input` / `session_start` イベントを購読し、`failproofai --hook --cli pi` をシェルアウトします。ハンドラーは `PI_EVENT_MAP` を通じてアンダースコア付き小文字スネークケース → PascalCase に正規化するため、既存の組み込みポリシーはそのまま動作します。ツール入力引数も `PI_TOOL_INPUT_MAP` を通じて正規化されます(Pi の Read / Write / Edit は `file_path` ではなく `path` を使用。トップレベルキーのマッピングにより `block-env-files` と `block-secrets-write` が動作します — `block-read-outside-cwd` にはすでに `path` フォールバックがあります)。Pi の拡張 API とセッションログのレイアウトが安定化するまで Pi のサポートは**ベータ版**です。 - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json`(ユーザー)、`/.gemini/settings.json`(プロジェクト)— Gemini には `local` スコープがありません(failproofai が公開していない `/etc/gemini-cli/settings.json` の `system` スコープを文書化しています)。フックエントリは Claude の `{type, command, timeout}` 形式を Gemini の `{matcher, hooks: [...]}` マッチャースキーマでラップし、デフォルトで `matcher: "*"` を使用します。イベントは PascalCase(`SessionStart`、`BeforeAgent`、`AfterAgent`、`BeforeModel`、`AfterModel`、`BeforeToolSelection`、`BeforeTool`、`AfterTool`、`PreCompress`、`Notification`、`SessionEnd`)で、ハンドラーは `GEMINI_EVENT_MAP` を通じて Claude の標準名にマッピングします。ツール名はスネークケース(`run_shell_command`、`read_file`、`write_file`、`replace` など)で、ハンドラーは `GEMINI_TOOL_MAP` を通じて正規化するため、既存の組み込みポリシーはそのまま動作します。ポリシー評価器は Gemini のフラットな `{decision: "deny", reason}` 形式(Gemini の「ゴールデンルール」exit-0 契約に基づく推奨)、BeforeAgent / AfterTool / SessionStart でのコンテキスト注入用 `{hookSpecificOutput: {hookEventName, additionalContext}}`、AfterAgent での強制リトライセマンティクス用 `{decision: "block", reason}` を出力します。実際の使用環境でのカバレッジを拡大中のため、Gemini CLI のサポートは**ベータ版**です。[Gemini CLI フックドキュメント](https://geminicli.com/docs/hooks/)を参照してください。 - **Hermes (hermes-agent)**: `~/.hermes/config.yaml`(**ユーザースコープのみ** — Hermes にはプロジェクト/ローカル設定がありません)。Hermes は Slack/Telegram の**ゲートウェイ**であるため、1回のインストールでSlack/Telegram/cli/cron など全プラットフォームからのツール呼び出しと内部サブエージェントを傍受します。フックエントリは Hermes のスネークケースイベント(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`)をキーとする `hooks:` マップ下の `{command, timeout}` ペア(タイムアウトは**秒**単位)です。ハンドラーは `HERMES_EVENT_MAP` でイベントを、`HERMES_TOOL_MAP` でツール名を正規化するため、組み込みポリシーはそのまま動作します。設定はコメントを保持する YAML `Document` のラウンドトリップで編集されるため、オペレーターの他の設定は保持されます。インストール時に `hooks_auto_accept: true` が設定されるため、ヘッドレスゲートウェイ(TTY なし)は同意プロンプトなしでフックを実行します。評価器は Hermes の `{"decision":"block","reason"}` stdout 契約を出力します(Hermes は終了コードを無視)。**制限事項:** Hermes にはターン終了の `Stop` イベントがないため、`require-*-before-stop` 組み込みポリシーは動作しません(非適用、バグではありません)。`instruct` は allow-with-logged-note に降格します(追加コンテキストチャネルなし)。出力シークレットのリダクション(`sanitize-*`)はシェルフックの契約上ツール出力を書き換えられません。Hermes は**オフライン監査**ソースでもあり、ダッシュボードはゲートウェイセッションを `~/.hermes/state.db` から直接読み取ります。 - **`policies-config.json`** — failproofai が評価するポリシーとそのパラメーターを指定します(すべてのエージェント CLI で共有) -特定のエージェントを対象にするには `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` を渡します(スペース区切りまたは繰り返しで複数指定可能): +特定のエージェントを対象にするには `--cli claude|codex|copilot|cursor|opencode|pi|hermes` を渡します(スペース区切りまたは繰り返しで複数指定可能): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -`--cli` を省略すると、`failproofai` はインストール済みのエージェント CLI を自動検出します(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli` を省略すると、`failproofai` はインストール済みのエージェント CLI を自動検出します(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **CLI が1つ検出された場合** — プロンプトなしでその CLI を自動選択します。 - **複数の CLI が検出され、インタラクティブターミナルの場合** — `Detected (N)` セクション(`Install for all N detected` の集約行と検出された各 CLI)と `Not installed (M) · install hooks ahead of time` セクション(検出されなかったサポート対象 CLI を前もってインストールするオプションとして一覧表示)にグループ化された矢印キー操作の単一選択プロンプトを表示します(↑↓で移動、Enterで選択、^Cで終了)。アンインストールフローでは Detected セクションのみ表示されます。 diff --git a/docs/ja/dashboard.mdx b/docs/ja/dashboard.mdx index 5462eed4..e05c80fd 100644 --- a/docs/ja/dashboard.mdx +++ b/docs/ja/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### プロジェクト -マシン上で見つかったすべての Claude Code、OpenAI Codex、GitHub Copilot CLI _(ベータ)_、Cursor Agent _(ベータ)_、OpenCode _(ベータ)_、Pi _(ベータ)_、Gemini CLI _(ベータ)_、および Hermes プロジェクトを一覧表示します。Claude プロジェクトは `~/.claude/projects/`(または `CLAUDE_PROJECTS_PATH` で設定されたパス)から検出されます。Codex プロジェクトは `~/.codex/sessions///
/*.jsonl` 以下のすべてのトランスクリプトをスキャンし、各セッションの最初のレコードに記録された `cwd` でグループ化することで検出されます。Copilot CLI プロジェクトは各 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME` で設定可能)をスキャンし、`cwd` フィールドでグループ化することで検出されます。Cursor Agent プロジェクトは `~/.cursor/agent-sessions//`(`CURSOR_HOME` で設定可能。`conversations/` と `sessions/` をフォールバックとして探索)以下のセッションごとのメタデータをスキャンし、`meta.json` / `session.json` / `workspace.yaml` 内の `cwd` スカラーから検出されます。OpenCode プロジェクトは `opencode db --format json` を通じて `~/.local/share/opencode/opencode.db` の SQLite DB を照会することで検出されます(`session` テーブルと `project` テーブルを読み取り、`project_id` でグループ化)。Pi プロジェクトは `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR` で設定可能)以下のセッションごとの JSONL トランスクリプトをスキャンし、各セッションの最初のレコードから `cwd` を取得することで検出されます。Gemini CLI プロジェクトは `~/.gemini/tmp//chats/session--.jsonl`(`GEMINI_SESSIONS_DIR` で設定可能)をスキャンし、隣接する `.project_root` テキストマーカーから正規の cwd を復元することで検出されます。Hermes ゲートウェイセッションは `~/.hermes/state.db`(`HERMES_DB_PATH` で設定可能)の SQLite ストアから直接読み取られ、`source`(Slack/Telegram/cli/cron — ゲートウェイセッションには cwd がありません)によって `hermes-` プロジェクトにグループ化されます。複数の CLI で使用されたプロジェクトは、該当するすべてのバッジを付けた1行として表示されます。テーブル上部の **CLI** ドロップダウンを使用して特定のエージェント CLI でフィルタリングできます。URLには選択内容が `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` として保持されます。 +マシン上で見つかったすべての Claude Code、OpenAI Codex、GitHub Copilot CLI _(ベータ)_、Cursor Agent _(ベータ)_、OpenCode _(ベータ)_、Pi _(ベータ)_、および Hermes プロジェクトを一覧表示します。Claude プロジェクトは `~/.claude/projects/`(または `CLAUDE_PROJECTS_PATH` で設定されたパス)から検出されます。Codex プロジェクトは `~/.codex/sessions///
/*.jsonl` 以下のすべてのトランスクリプトをスキャンし、各セッションの最初のレコードに記録された `cwd` でグループ化することで検出されます。Copilot CLI プロジェクトは各 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME` で設定可能)をスキャンし、`cwd` フィールドでグループ化することで検出されます。Cursor Agent プロジェクトは `~/.cursor/agent-sessions//`(`CURSOR_HOME` で設定可能。`conversations/` と `sessions/` をフォールバックとして探索)以下のセッションごとのメタデータをスキャンし、`meta.json` / `session.json` / `workspace.yaml` 内の `cwd` スカラーから検出されます。OpenCode プロジェクトは `opencode db --format json` を通じて `~/.local/share/opencode/opencode.db` の SQLite DB を照会することで検出されます(`session` テーブルと `project` テーブルを読み取り、`project_id` でグループ化)。Pi プロジェクトは `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR` で設定可能)以下のセッションごとの JSONL トランスクリプトをスキャンし、各セッションの最初のレコードから `cwd` を取得することで検出されます。Hermes ゲートウェイセッションは `~/.hermes/state.db`(`HERMES_DB_PATH` で設定可能)の SQLite ストアから直接読み取られ、`source`(Slack/Telegram/cli/cron — ゲートウェイセッションには cwd がありません)によって `hermes-` プロジェクトにグループ化されます。複数の CLI で使用されたプロジェクトは、該当するすべてのバッジを付けた1行として表示されます。テーブル上部の **CLI** ドロップダウンを使用して特定のエージェント CLI でフィルタリングできます。URLには選択内容が `?cli=claude|codex|copilot|cursor|opencode|pi|hermes` として保持されます。 各プロジェクトには以下が表示されます: - プロジェクト名(フォルダパスから導出) -- CLI バッジ — `Claude Code`(オレンジ)、`OpenAI Codex`(パープル)、`GitHub Copilot`(ブルー)、`Cursor Agent`(エメラルド)、`OpenCode`(アンバー)、`Pi`(ピンク)、`Gemini CLI`(スカイ)、および/または `Hermes`(インディゴ) +- CLI バッジ — `Claude Code`(オレンジ)、`OpenAI Codex`(パープル)、`GitHub Copilot`(ブルー)、`Cursor Agent`(エメラルド)、`OpenCode`(アンバー)、`Pi`(ピンク)、および/または `Hermes`(インディゴ) - 最新のセッションアクティビティの日付 プロジェクトをクリックするとそのセッションが表示されます。 @@ -47,7 +47,7 @@ failproofai ### セッションビューアー -セッションビューアーは、自律エージェントにとっての核心的な問いに答えます:エージェントは何を行い、正しく動作していたか?ヘッダー横の CLI バッジは、セッションが Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI、または Hermes のトランスクリプトであるかを示します。セッション内で起きたすべてのことのタイムラインが表示されます: +セッションビューアーは、自律エージェントにとっての核心的な問いに答えます:エージェントは何を行い、正しく動作していたか?ヘッダー横の CLI バッジは、セッションが Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、または Hermes のトランスクリプトであるかを示します。セッション内で起きたすべてのことのタイムラインが表示されます: - **メッセージ** - Claude のテキスト応答とユーザープロンプト - **ツールコール** - Claude が呼び出したすべてのツール(入力と出力を含む) @@ -55,7 +55,7 @@ failproofai 上部のステータスバーには、セッション時間、総ツールコール数、フック判定のサマリー(allow / deny / instruct の件数)が表示されます。 -**ログをダウンロード** ボタンをクリックするとセッションをエクスポートできます。Claude Code、Codex、Copilot、Cursor、Pi、Gemini のセッションはディスク上の JSONL トランスクリプトをバイト単位でそのまま取得できます。OpenCode(セッションがディスク上ではなく SQLite に保存されている)の場合は、基礎となる `session` / `messages` / `parts` テーブルを反映した JSON ドキュメントが取得されます。 +**ログをダウンロード** ボタンをクリックするとセッションをエクスポートできます。Claude Code、Codex、Copilot、Cursor、Pi のセッションはディスク上の JSONL トランスクリプトをバイト単位でそのまま取得できます。OpenCode(セッションがディスク上ではなく SQLite に保存されている)の場合は、基礎となる `session` / `messages` / `parts` テーブルを反映した JSON ドキュメントが取得されます。 ### 監査 @@ -75,16 +75,16 @@ failproofai - - 1つのパネルから failproofai が保護するエージェント CLI を複数選択できます — Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、Gemini CLI、および Hermes にはそれぞれインストール状況(`Active` / `Detected` / `Inactive`)、ユーザースコープの設定パス、ブランドカラーのアクセントを持つ行があります。対象の CLI にチェックを入れるか外して `Apply changes` をクリックすると、差分を1ステップでインストール/アンインストールできます。PATH 上でバイナリが検出された CLI は事前にチェックされています。 + - 1つのパネルから failproofai が保護するエージェント CLI を複数選択できます — Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、および Hermes にはそれぞれインストール状況(`Active` / `Detected` / `Inactive`)、ユーザースコープの設定パス、ブランドカラーのアクセントを持つ行があります。対象の CLI にチェックを入れるか外して `Apply changes` をクリックすると、差分を1ステップでインストール/アンインストールできます。PATH 上でバイナリが検出された CLI は事前にチェックされています。 - 個別のポリシーをワンクリックで有効/無効に切り替えます(`~/.failproofai/policies-config.json` に書き込まれます — インストールされたすべての CLI で共有) - パラメーターをサポートするポリシーの設定を展開して変更します(`policyParams` をサポートするポリシーの場合) - カスタムポリシーファイルのパスを設定します - すべてのセッションで発動したすべてのフックイベントの完全なページ分割履歴 - - 判定、イベントタイプ、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(ベータ)_ / Cursor Agent _(ベータ)_ / OpenCode _(ベータ)_ / Pi _(ベータ)_ / Gemini CLI _(ベータ)_ / Hermes)、ポリシー名、またはセッション ID でフィルタリング - - 各行には:タイムスタンプ、ポリシー名、判定、CLI バッジ(オレンジ = Claude Code、パープル = OpenAI Codex、ブルー = GitHub Copilot、エメラルド = Cursor Agent、アンバー = OpenCode、ピンク = Pi、スカイ = Gemini CLI、インディゴ = Hermes)、ツール名、セッション ID、deny/instruct 判定の理由が表示されます - - セッション ID をクリックするとトランスクリプトが開きます — ビューアーはどの CLI がフックを発動させたかを自動検出し(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Gemini CLI `~/.gemini/tmp//chats/.jsonl`、Hermes `~/.hermes/state.db`)、ヘッダーに対応する CLI バッジを表示します + - 判定、イベントタイプ、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(ベータ)_ / Cursor Agent _(ベータ)_ / OpenCode _(ベータ)_ / Pi _(ベータ)_ / Hermes)、ポリシー名、またはセッション ID でフィルタリング + - 各行には:タイムスタンプ、ポリシー名、判定、CLI バッジ(オレンジ = Claude Code、パープル = OpenAI Codex、ブルー = GitHub Copilot、エメラルド = Cursor Agent、アンバー = OpenCode、ピンク = Pi、インディゴ = Hermes)、ツール名、セッション ID、deny/instruct 判定の理由が表示されます + - セッション ID をクリックするとトランスクリプトが開きます — ビューアーはどの CLI がフックを発動させたかを自動検出し(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Hermes `~/.hermes/state.db`)、ヘッダーに対応する CLI バッジを表示します diff --git a/docs/ja/getting-started.mdx b/docs/ja/getting-started.mdx index 59b11f83..2f26c6a0 100644 --- a/docs/ja/getting-started.mdx +++ b/docs/ja/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - このコマンドは、インストール済みのエージェント CLI にフックエントリを書き込みます(Claude Code の `~/.claude/settings.json`、OpenAI Codex の `~/.codex/hooks.json`、GitHub Copilot CLI の `~/.copilot/hooks/failproofai.json`、Cursor Agent の `~/.cursor/hooks.json`、OpenCode の `~/.config/opencode/plugins/failproofai.mjs` と `~/.config/opencode/opencode.json` の `plugin` 配列へのエントリ、Pi の `~/.pi/agent/settings.json`、Gemini CLI の `~/.gemini/settings.json`、または Hermes の `~/.hermes/config.yaml`)。複数が存在する場合はプロンプトで選択を求められます。`--cli claude codex copilot cursor opencode pi gemini hermes`(任意のサブセット)を渡すとプロンプトをスキップできます。 + このコマンドは、インストール済みのエージェント CLI にフックエントリを書き込みます(Claude Code の `~/.claude/settings.json`、OpenAI Codex の `~/.codex/hooks.json`、GitHub Copilot CLI の `~/.copilot/hooks/failproofai.json`、Cursor Agent の `~/.cursor/hooks.json`、OpenCode の `~/.config/opencode/plugins/failproofai.mjs` と `~/.config/opencode/opencode.json` の `plugin` 配列へのエントリ、Pi の `~/.pi/agent/settings.json`、または Hermes の `~/.hermes/config.yaml`)。複数が存在する場合はプロンプトで選択を求められます。`--cli claude codex copilot cursor opencode pi hermes`(任意のサブセット)を渡すとプロンプトをスキップできます。 - GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI のサポートは**ベータ版**です — それぞれ `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi`、`--cli gemini` でインストールしてください。Hermes(hermes-agent、Slack/Telegram ゲートウェイ)は `--cli hermes` でユーザースコープにインストールでき、オフライン監査ソースとしても機能します。 + GitHub Copilot CLI、Cursor Agent、OpenCode、Pi のサポートは**ベータ版**です — それぞれ `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi` でインストールしてください。Hermes(hermes-agent、Slack/Telegram ゲートウェイ)は `--cli hermes` でユーザースコープにインストールでき、オフライン監査ソースとしても機能します。 ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/ja/introduction.mdx b/docs/ja/introduction.mdx index aa59b0ff..e64e9beb 100644 --- a/docs/ja/introduction.mdx +++ b/docs/ja/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI は AI エージェントに39種類の組み込み障 [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI 障害ハンドリング**・**エラーリカバリー**・**LLM の信頼性**向上のためのフックとポリシー。**Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Gemini CLI**、**Hermes**、そして **Agents SDK** 上で、AI エージェントを安定かつ自律的に動作させ続けます。 +**AI 障害ハンドリング**・**エラーリカバリー**・**LLM の信頼性**向上のためのフックとポリシー。**Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Hermes**、そして **Agents SDK** 上で、AI エージェントを安定かつ自律的に動作させ続けます。 AI エージェントの障害は、予測可能なパターンで発生します。破壊的なコマンドの実行、シークレットの漏洩、タスクからの逸脱、ループへの陥没、main ブランチへの直接プッシュ——放置すれば、小さな障害がサービス停止、認証情報の流出、作業の消失へと連鎖します。 diff --git a/docs/ko/built-in-policies.mdx b/docs/ko/built-in-policies.mdx index 3ba3d9c5..bea77b5c 100644 --- a/docs/ko/built-in-policies.mdx +++ b/docs/ko/built-in-policies.mdx @@ -710,7 +710,7 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### CLI별 Stop 시맨틱 -Stop 적용은 지원되는 7개 CLI에서 각각 다른 "에이전트 완료" 훅 계약을 노출하기 때문에 약간씩 다르게 동작합니다. **결과**는 동일합니다 — 에이전트는 워크플로 게이트가 실패하는 동안 중단할 수 없습니다 — 하지만 **메커니즘**은 다릅니다. 아래 표에 요약되어 있습니다; `require-*-before-stop` 정책을 활성화하기 전에 이해할 가치가 있는 사용자에게 보이는 특이점은 Pi에만 있습니다. +Stop 적용은 지원되는 6개 CLI에서 각각 다른 "에이전트 완료" 훅 계약을 노출하기 때문에 약간씩 다르게 동작합니다. **결과**는 동일합니다 — 에이전트는 워크플로 게이트가 실패하는 동안 중단할 수 없습니다 — 하지만 **메커니즘**은 다릅니다. 아래 표에 요약되어 있습니다; `require-*-before-stop` 정책을 활성화하기 전에 이해할 가치가 있는 사용자에게 보이는 특이점은 Pi에만 있습니다. | CLI | 게이트 실행 시점 | 표시되는 내용 | |---|---|---| @@ -718,20 +718,19 @@ Stop 적용은 지원되는 7개 CLI에서 각각 다른 "에이전트 완료" | Codex | 동일한 에이전트 루프, 즉시 | Claude와 동일. | | GitHub Copilot CLI | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Copilot의 `{decision:"block", reason}` 재시도 채널 사용 — Copilot CLI 1.0.41에 대해 경험적으로 검증됨). | | Cursor Agent | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Cursor의 `{followup_message}` 채널 사용 — `loop_limit`으로 제한, 기본값 5회 재시도). | -| Gemini CLI | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Gemini의 `{decision:"block", reason}` 채널을 `AfterAgent`에서 사용). | | OpenCode | 동일한 에이전트 루프, 즉시 | Claude와 동일 (OpenCode의 `client.session.prompt(...)` SDK 호출을 `hookSpecificOutput.additionalContext`를 통해 라우팅). | | **Pi (pi-coding-agent)** | **다음 사용자 턴** | **Pi는 게이트가 실행될 때 눈에 띄게 중단됩니다** — 에이전트 루프가 종료되고 프롬프트로 돌아옵니다. 그런 다음 다음에 프롬프트를 제출할 때 게이트가 실행됩니다: failproofai는 해당 턴의 시스템 프롬프트에 `MANDATORY ACTION REQUIRED` 지시문을 앞에 추가하여 LLM이 요청한 작업을 수행하기 전에 워크플로 단계(커밋, 푸시 등)를 완료하도록 안내합니다. | -**Pi 제한사항.** Pi의 `AgentEndEvent`(Claude의 `Stop` 훅에 해당하는 업스트림)에는 Result 타입이 없습니다 — 실행될 때쯤이면 Pi의 에이전트 루프가 이미 종료된 상태입니다. Pi는 Claude / Copilot / Cursor / Gemini / OpenCode처럼 동일한 루프를 강제로 재시도할 수 없습니다. failproofai는 게이트를 Pi의 `before_agent_start` 이벤트(다음 사용자 프롬프트 후에 실행됨)로 이동하므로 워크플로 확인은 현재 턴이 아닌 다음 턴에 적용됩니다. +**Pi 제한사항.** Pi의 `AgentEndEvent`(Claude의 `Stop` 훅에 해당하는 업스트림)에는 Result 타입이 없습니다 — 실행될 때쯤이면 Pi의 에이전트 루프가 이미 종료된 상태입니다. Pi는 Claude / Copilot / Cursor / OpenCode처럼 동일한 루프를 강제로 재시도할 수 없습니다. failproofai는 게이트를 Pi의 `before_agent_start` 이벤트(다음 사용자 프롬프트 후에 실행됨)로 이동하므로 워크플로 확인은 현재 턴이 아닌 다음 턴에 적용됩니다. **실제로 의미하는 것:** - Pi가 중단된 후, 거부 이유는 Pi 세션 id로 키된 인메모리에 캡처됩니다. 동일한 Pi 프로세스에서 다음에 제출하는 프롬프트가 이를 소비합니다: LLM은 시스템 프롬프트 상단에 `MANDATORY ACTION REQUIRED` 지시문을 보고, 커밋(또는 푸시 / PR 열기 / CI 대기)을 수행한 후 요청을 계속합니다. 캡처된 거부 이유는 일회성입니다 — 소비되면 게이트가 해제됩니다. -- 게이트는 Pi의 프로세스 수명에 의해 제한됩니다. 턴 사이에 Pi를 `Ctrl+C`하거나 종료하면 인메모리 항목이 프로세스와 함께 삭제되고 게이트가 놓칩니다. Claude, Copilot, Cursor, Gemini, OpenCode도 동일한 제한이 있습니다(에이전트를 종료하면 게이트가 놓침) — Pi는 에이전트가 게이트가 실행되기 전에 눈에 띄게 종료되므로 더 명확하게 보입니다. +- 게이트는 Pi의 프로세스 수명에 의해 제한됩니다. 턴 사이에 Pi를 `Ctrl+C`하거나 종료하면 인메모리 항목이 프로세스와 함께 삭제되고 게이트가 놓칩니다. Claude, Copilot, Cursor, OpenCode도 동일한 제한이 있습니다(에이전트를 종료하면 게이트가 놓침) — Pi는 에이전트가 게이트가 실행되기 전에 눈에 띄게 종료되므로 더 명확하게 보입니다. - 보류 중인 거부는 어떤 이유로든(`new` / `resume` / `fork` / `quit`) `session_shutdown` 시에도 지워지므로, 이전 세션의 오래된 게이트가 동일한 Pi 프로세스에서 시작된 새 세션으로 누출될 수 없습니다. -동일 루프 재시도가 필요하다면 다른 6개의 지원 CLI 중 하나에서 `Stop` 정책을 실행하세요. 이 격차를 해소할 수 있는 `AgentEndEvent`의 향후 Result 타입에 대해 Pi 업스트림을 추적 중입니다. +동일 루프 재시도가 필요하다면 다른 5개의 지원 CLI 중 하나에서 `Stop` 정책을 실행하세요. 이 격차를 해소할 수 있는 `AgentEndEvent`의 향후 Result 타입에 대해 Pi 업스트림을 추적 중입니다. ### `require-commit-before-stop` diff --git a/docs/ko/cli/audit.mdx b/docs/ko/cli/audit.mdx index 2162ed39..e3f1a67a 100644 --- a/docs/ko/cli/audit.mdx +++ b/docs/ko/cli/audit.mdx @@ -54,7 +54,7 @@ failproofai 대시보드는 `Ctrl+C`로 중지할 때까지 계속 서비스됩니다. -대시보드는 이 머신의 과거 에이전트 CLI 트랜스크립트(Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini)를 스캔하고, failproofai가 막도록 설계된 작업들 — env-var 검사, 강제 푸시, 불필요한 `cd ` 접두사, sleep 폴링 루프, 방금 편집한 파일 재읽기 등 — 을 에이전트가 얼마나 자주 수행했는지 보고합니다. +대시보드는 이 머신의 과거 에이전트 CLI 트랜스크립트(Claude Code, Codex, Copilot, Cursor, OpenCode, Pi)를 스캔하고, failproofai가 막도록 설계된 작업들 — env-var 검사, 강제 푸시, 불필요한 `cd ` 접두사, sleep 폴링 루프, 방금 편집한 파일 재읽기 등 — 을 에이전트가 얼마나 자주 수행했는지 보고합니다. 각 트랜스크립트에 대해 모든 도구 사용 이벤트는 39개의 내장 정책 **및** 런타임 정책으로 아직 처리되지 않는 패턴을 잡아내는 8개의 감사 전용 감지기를 통해 재실행됩니다. 횟수는 모든 세션에 걸쳐 정책/감지기별로 집계됩니다. diff --git a/docs/ko/configuration.mdx b/docs/ko/configuration.mdx index c90507f9..d4a99ddf 100644 --- a/docs/ko/configuration.mdx +++ b/docs/ko/configuration.mdx @@ -196,13 +196,12 @@ AI 호출을 수행하는 정책을 위한 LLM 클라이언트 설정입니다. - **OpenAI Codex**: `~/.codex/hooks.json` (사용자), `/.codex/hooks.json` (프로젝트) — Codex는 `local` 범위가 없습니다 - **GitHub Copilot CLI _(베타)_**: `~/.copilot/hooks/failproofai.json` (사용자), `/.github/hooks/failproofai.json` (프로젝트) — Copilot에는 `local` 범위가 없습니다. 훅 항목은 Copilot의 OS별 `bash`/`powershell` 명령 필드와 `timeoutSec`를 사용하며, 파일 최상단에 `version: 1` 마커가 있습니다. `events.jsonl` 레코드 스키마(공개 문서에 명시되지 않음)를 더 많은 실제 세션을 통해 검증 중이므로 Copilot CLI 지원은 **베타** 상태입니다. - **Cursor Agent _(베타)_**: `~/.cursor/hooks.json` (사용자), `/.cursor/hooks.json` (프로젝트) — Cursor에는 `local` 범위가 없습니다. 훅 항목은 Claude 형식의 `{type, command, timeout}` 구조를 사용하지만(`bash`/`powershell` 분리 없음), Cursor의 [훅 스키마](https://cursor.com/docs/hooks)에 따라 camelCase 이벤트 키(`preToolUse`, `beforeSubmitPrompt` 등) 아래 플랫 배열로 저장되며 파일 최상단에 `version: 1` 마커가 있습니다. 핸들러는 `CURSOR_EVENT_MAP`을 통해 camelCase → PascalCase로 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. Cursor의 트랜스크립트 온디스크 형식(공개 문서에 명시되지 않음)을 더 많은 실제 설치를 통해 검증 중이므로 Cursor Agent 지원은 **베타** 상태입니다. - - **OpenCode _(베타)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (사용자), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (프로젝트) — OpenCode에는 `local` 범위가 없습니다. 다른 여섯 CLI와 달리 OpenCode에는 **외부 명령 훅 시스템이 없습니다**: `opencode.json`의 `plugin: []` 배열을 통해 명시적으로 등록된 인프로세스 JS/TS 플러그인을 로드합니다(`.opencode/plugins/`에서의 자동 검색은 opencode v1.14.33에서 플러그인이 로드되는 방식이 **아닙니다**). 설치 시 failproofai 바이너리를 서브프로세스로 호출하고 바이너리의 Claude 형식 JSON 응답을 플러그인 시맨틱으로 변환하는 작은 생성된 플러그인 심을 배치합니다: 도구 이벤트 거부 시 `throw new Error()`(도구 호출 취소), instruct와 `Stop`/`SubagentStop` 거부 시 `client.session.prompt(...)`(거부 이유를 다음 사용자 메시지로 제출 — `session.idle`은 알림 전용이고 거기서 throw는 no-op이므로 유일한 강제 재시도 채널), allow 시 no-op. 심은 도구 이름(소문자 → PascalCase, `OPENCODE_TOOL_MAP` 사용)과 도구 입력 인수 키(camelCase → snake_case, `Read`/`Write`/`Edit`용 `OPENCODE_TOOL_INPUT_MAP` 사용, 예: `filePath` → `file_path`, `oldString` → `old_string`)를 바이너리에 전달하기 전에 정규화하므로 `block-read-outside-cwd`, `block-env-files`, `block-secrets-write` 같은 경로 확인 기본 정책이 OpenCode 도구 호출에서도 변경 없이 동작합니다. 세션은 `~/.local/share/opencode/opencode.db`의 opencode SQLite DB에 저장되며, 대시보드의 세션 뷰어는 `opencode db --format json` 및 `opencode export `를 통해 읽습니다. 버전 간 동작 및 더 많은 실제 세션 검증 중이므로 OpenCode 지원은 **베타** 상태입니다. [OpenCode 플러그인 문서](https://opencode.ai/docs/plugins/)를 참고하세요. + - **OpenCode _(베타)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (사용자), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (프로젝트) — OpenCode에는 `local` 범위가 없습니다. 다른 다섯 CLI와 달리 OpenCode에는 **외부 명령 훅 시스템이 없습니다**: `opencode.json`의 `plugin: []` 배열을 통해 명시적으로 등록된 인프로세스 JS/TS 플러그인을 로드합니다(`.opencode/plugins/`에서의 자동 검색은 opencode v1.14.33에서 플러그인이 로드되는 방식이 **아닙니다**). 설치 시 failproofai 바이너리를 서브프로세스로 호출하고 바이너리의 Claude 형식 JSON 응답을 플러그인 시맨틱으로 변환하는 작은 생성된 플러그인 심을 배치합니다: 도구 이벤트 거부 시 `throw new Error()`(도구 호출 취소), instruct와 `Stop`/`SubagentStop` 거부 시 `client.session.prompt(...)`(거부 이유를 다음 사용자 메시지로 제출 — `session.idle`은 알림 전용이고 거기서 throw는 no-op이므로 유일한 강제 재시도 채널), allow 시 no-op. 심은 도구 이름(소문자 → PascalCase, `OPENCODE_TOOL_MAP` 사용)과 도구 입력 인수 키(camelCase → snake_case, `Read`/`Write`/`Edit`용 `OPENCODE_TOOL_INPUT_MAP` 사용, 예: `filePath` → `file_path`, `oldString` → `old_string`)를 바이너리에 전달하기 전에 정규화하므로 `block-read-outside-cwd`, `block-env-files`, `block-secrets-write` 같은 경로 확인 기본 정책이 OpenCode 도구 호출에서도 변경 없이 동작합니다. 세션은 `~/.local/share/opencode/opencode.db`의 opencode SQLite DB에 저장되며, 대시보드의 세션 뷰어는 `opencode db --format json` 및 `opencode export `를 통해 읽습니다. 버전 간 동작 및 더 많은 실제 세션 검증 중이므로 OpenCode 지원은 **베타** 상태입니다. [OpenCode 플러그인 문서](https://opencode.ai/docs/plugins/)를 참고하세요. - **Pi _(베타)_**: `~/.pi/agent/settings.json` (사용자), `/.pi/settings.json` (프로젝트) — Pi에는 `local` 범위가 없습니다. Pi는 시작 시 TypeScript 확장 패키지를 로드하며, 설정 파일은 `{"packages": ["./relative/path", …]}` 형식의 플랫 문자열 배열입니다. failproofai는 번들된 `pi-extension/` 디렉터리를 가리키는 단일 packages 배열 항목을 씁니다. 확장은 내부적으로 Pi의 `tool_call`/`user_bash`/`input`/`session_start` 이벤트를 구독하고 `failproofai --hook --cli pi`를 셸아웃합니다. 핸들러는 `PI_EVENT_MAP`을 통해 underscore_lower_snake_case → PascalCase로 이벤트를 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. 도구 입력 인수도 `PI_TOOL_INPUT_MAP`을 통해 정규화됩니다(Pi의 Read/Write/Edit는 `file_path` 대신 `path`를 전달하며, 최상위 키를 매핑하면 `block-env-files`와 `block-secrets-write`가 동작합니다 — `block-read-outside-cwd`는 이미 `path` 폴백이 있었습니다). Pi의 확장 API와 세션 로그 레이아웃이 안정화되는 동안 Pi 지원은 **베타** 상태입니다. - - **Gemini CLI _(베타)_**: `~/.gemini/settings.json` (사용자), `/.gemini/settings.json` (프로젝트) — Gemini에는 `local` 범위가 없습니다(failproofai가 노출하지 않는 `/etc/gemini-cli/settings.json`의 `system` 범위가 문서에 있습니다). 훅 항목은 Claude의 `{type, command, timeout}` 형식을 Gemini의 `{matcher, hooks: [...]}` 매처 스키마로 감싸며 기본적으로 `matcher: "*"`를 사용합니다. 이벤트는 PascalCase입니다(`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`). 핸들러는 `GEMINI_EVENT_MAP`을 통해 Claude 표준 이름으로 매핑합니다. 도구 이름은 snake_case입니다(`run_shell_command`, `read_file`, `write_file`, `replace` 등) — 핸들러는 `GEMINI_TOOL_MAP`을 통해 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. 정책 평가기는 Gemini의 플랫 `{decision: "deny", reason}` 형식(Gemini의 "Golden Rule" exit-0 계약에 따른 선호 형식), BeforeAgent/AfterTool/SessionStart의 컨텍스트 주입을 위한 `{hookSpecificOutput: {hookEventName, additionalContext}}`, 그리고 강제 재시도 시맨틱을 위한 AfterAgent의 `{decision: "block", reason}`을 반환합니다. 실제 적용 범위를 넓히는 동안 Gemini CLI 지원은 **베타** 상태입니다. [Gemini CLI 훅 문서](https://geminicli.com/docs/hooks/)를 참고하세요. - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**사용자 범위만** — Hermes에는 프로젝트/로컬 설정이 없습니다). Hermes는 Slack/Telegram **게이트웨이**이므로, 설치 한 번으로 모든 플랫폼(Slack/Telegram/cli/cron)과 내부 서브에이전트의 도구 호출을 가로챕니다. 훅 항목은 Hermes의 snake_case 이벤트(`pre_tool_call`/`post_tool_call`/`on_session_start`/`on_session_end`/`subagent_stop`)를 키로 하는 `hooks:` 맵 아래 `{command, timeout}` 쌍(timeout은 **초** 단위)입니다. 핸들러는 `HERMES_EVENT_MAP`으로 이벤트를, `HERMES_TOOL_MAP`으로 도구 이름을 정규화하므로 기본 제공 정책이 변경 없이 동작합니다. 설정은 주석 보존 YAML `Document` 라운드트립을 통해 편집되므로 운영자의 다른 설정이 유지되며, 설치 시 `hooks_auto_accept: true`로 설정되어 헤드리스 게이트웨이(TTY 없음)가 동의 프롬프트 없이 훅을 실행합니다. 평가기는 Hermes의 `{"decision":"block","reason"}` stdout 계약을 반환합니다(Hermes는 종료 코드를 무시합니다). **제한 사항:** Hermes에는 턴 종료 `Stop` 이벤트가 없으므로 `require-*-before-stop` 기본 정책은 동작하지 않습니다(해당 없음, 오류 아님). `instruct`는 allow-with-logged-note로 격하됩니다(추가 컨텍스트 채널 없음). 출력 시크릿 편집(`sanitize-*`)은 셸 훅 계약으로 도구 출력을 재작성할 수 없습니다. Hermes는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.hermes/state.db`에서 게이트웨이 세션을 직접 읽습니다. - **`policies-config.json`** — failproofai에게 어떤 정책을 어떤 파라미터로 평가할지 지시합니다(모든 에이전트 CLI에 공통 적용) -특정 에이전트를 대상으로 하려면 `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes`를 전달하세요(여러 개는 공백으로 구분하거나 반복 사용): +특정 에이전트를 대상으로 하려면 `--cli claude|codex|copilot|cursor|opencode|pi|hermes`를 전달하세요(여러 개는 공백으로 구분하거나 반복 사용): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -`--cli`를 생략하면 `failproofai`가 설치된 에이전트 CLI를 자동으로 감지합니다(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli`를 생략하면 `failproofai`가 설치된 에이전트 CLI를 자동으로 감지합니다(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **CLI 1개 감지** — 확인 없이 해당 CLI를 자동 선택합니다. - **여러 CLI 감지** (대화형 터미널) — 화살표 키 단일 선택 프롬프트를 표시합니다. `Detected (N)` 섹션(전체 감지 CLI에 대한 `Install for all N detected` 통합 행 + 각 감지된 CLI 개별 항목)과, 사전 설치를 위한 모든 미감지 지원 CLI를 나열하는 `Not installed (M) · install hooks ahead of time` 섹션으로 구성됩니다(↑↓로 이동, Enter로 선택, ^C로 종료). 제거 흐름은 Detected 섹션만 표시합니다. diff --git a/docs/ko/dashboard.mdx b/docs/ko/dashboard.mdx index eaa09fbc..18ef7da4 100644 --- a/docs/ko/dashboard.mdx +++ b/docs/ko/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### 프로젝트 -머신에서 발견된 모든 Claude Code, OpenAI Codex, GitHub Copilot CLI _(베타)_, Cursor Agent _(베타)_, OpenCode _(베타)_, Pi _(베타)_, Gemini CLI _(베타)_, Hermes 프로젝트를 나열합니다. Claude 프로젝트는 `~/.claude/projects/`(또는 `CLAUDE_PROJECTS_PATH`로 설정된 경로)에서 검색됩니다. Codex 프로젝트는 `~/.codex/sessions///
/*.jsonl` 아래의 모든 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에 기록된 `cwd`로 그룹화하여 검색됩니다. Copilot CLI 프로젝트는 각 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME`으로 구성 가능)을 스캔하고 `cwd` 필드로 그룹화하여 검색됩니다. Cursor Agent 프로젝트는 `~/.cursor/agent-sessions//`(`CURSOR_HOME`으로 구성 가능, `conversations/` 및 `sessions/`가 폴백으로 검색됨) 아래의 세션별 메타데이터를 스캔하여 `meta.json` / `session.json` / `workspace.yaml`의 `cwd` 스칼라로 검색됩니다. OpenCode 프로젝트는 `opencode db --format json`을 통해 `~/.local/share/opencode/opencode.db`의 SQLite DB를 쿼리하여 검색되며(`session` 및 `project` 테이블을 읽고 `project_id`로 그룹화), Pi 프로젝트는 `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR`으로 구성 가능) 아래의 세션별 JSONL 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에서 `cwd`를 가져와 검색됩니다. Gemini CLI 프로젝트는 `~/.gemini/tmp//chats/session--.jsonl`(`GEMINI_SESSIONS_DIR`으로 구성 가능)을 스캔하고 인접한 `.project_root` 텍스트 마커에서 정규 cwd를 복원하여 검색됩니다. Hermes 게이트웨이 세션은 `~/.hermes/state.db`(`HERMES_DB_PATH`으로 구성 가능)의 SQLite 저장소에서 직접 읽어오며 `source`(Slack/Telegram/cli/cron — 게이트웨이 세션에는 cwd가 없음)로 `hermes-` 프로젝트로 그룹화됩니다. 여러 CLI에서 사용된 프로젝트는 일치하는 모든 배지가 있는 단일 행으로 표시됩니다. 테이블 위의 **CLI** 드롭다운을 사용하여 특정 에이전트 CLI로 필터링하세요. URL은 선택 내용을 `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`로 보존합니다. +머신에서 발견된 모든 Claude Code, OpenAI Codex, GitHub Copilot CLI _(베타)_, Cursor Agent _(베타)_, OpenCode _(베타)_, Pi _(베타)_, Hermes 프로젝트를 나열합니다. Claude 프로젝트는 `~/.claude/projects/`(또는 `CLAUDE_PROJECTS_PATH`로 설정된 경로)에서 검색됩니다. Codex 프로젝트는 `~/.codex/sessions///
/*.jsonl` 아래의 모든 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에 기록된 `cwd`로 그룹화하여 검색됩니다. Copilot CLI 프로젝트는 각 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME`으로 구성 가능)을 스캔하고 `cwd` 필드로 그룹화하여 검색됩니다. Cursor Agent 프로젝트는 `~/.cursor/agent-sessions//`(`CURSOR_HOME`으로 구성 가능, `conversations/` 및 `sessions/`가 폴백으로 검색됨) 아래의 세션별 메타데이터를 스캔하여 `meta.json` / `session.json` / `workspace.yaml`의 `cwd` 스칼라로 검색됩니다. OpenCode 프로젝트는 `opencode db --format json`을 통해 `~/.local/share/opencode/opencode.db`의 SQLite DB를 쿼리하여 검색되며(`session` 및 `project` 테이블을 읽고 `project_id`로 그룹화), Pi 프로젝트는 `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR`으로 구성 가능) 아래의 세션별 JSONL 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에서 `cwd`를 가져와 검색됩니다. Hermes 게이트웨이 세션은 `~/.hermes/state.db`(`HERMES_DB_PATH`으로 구성 가능)의 SQLite 저장소에서 직접 읽어오며 `source`(Slack/Telegram/cli/cron — 게이트웨이 세션에는 cwd가 없음)로 `hermes-` 프로젝트로 그룹화됩니다. 여러 CLI에서 사용된 프로젝트는 일치하는 모든 배지가 있는 단일 행으로 표시됩니다. 테이블 위의 **CLI** 드롭다운을 사용하여 특정 에이전트 CLI로 필터링하세요. URL은 선택 내용을 `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`로 보존합니다. 각 프로젝트에는 다음이 표시됩니다: - 프로젝트 이름 (폴더 경로에서 파생) -- CLI 배지 — `Claude Code` (주황색), `OpenAI Codex` (보라색), `GitHub Copilot` (파란색), `Cursor Agent` (에메랄드), `OpenCode` (호박색), `Pi` (분홍색), `Gemini CLI` (하늘색), 및/또는 `Hermes` (남색) +- CLI 배지 — `Claude Code` (주황색), `OpenAI Codex` (보라색), `GitHub Copilot` (파란색), `Cursor Agent` (에메랄드), `OpenCode` (호박색), `Pi` (분홍색), 및/또는 `Hermes` (남색) - 가장 최근 세션 활동 날짜 프로젝트를 클릭하면 해당 세션이 표시됩니다. @@ -47,7 +47,7 @@ failproofai ### 세션 뷰어 -세션 뷰어는 자율 에이전트에 대한 핵심 질문에 답합니다: 에이전트가 무엇을 했으며, 제대로 작동했는가? 헤더 옆의 CLI 배지는 세션이 Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI 또는 Hermes 트랜스크립트인지 나타냅니다. 세션에서 발생한 모든 일의 타임라인을 보여줍니다: +세션 뷰어는 자율 에이전트에 대한 핵심 질문에 답합니다: 에이전트가 무엇을 했으며, 제대로 작동했는가? 헤더 옆의 CLI 배지는 세션이 Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi 또는 Hermes 트랜스크립트인지 나타냅니다. 세션에서 발생한 모든 일의 타임라인을 보여줍니다: - **메시지** - Claude의 텍스트 응답과 사용자 프롬프트 - **툴 호출** - Claude가 호출한 모든 툴, 입력 및 출력 포함 @@ -55,7 +55,7 @@ failproofai 상단의 통계 바에는 세션 지속 시간, 총 툴 호출 수, 훅 결정 요약(allow / deny / instruct 수)이 표시됩니다. -**로그 다운로드** 버튼을 클릭하여 세션을 내보냅니다. Claude Code, Codex, Copilot, Cursor, Pi, Gemini 세션의 경우 디스크의 원본 JSONL 트랜스크립트를 바이트 단위로 그대로 받을 수 있으며, OpenCode(세션이 디스크가 아닌 SQLite에 저장됨)의 경우 기본 `session` / `messages` / `parts` 테이블을 미러링하는 JSON 문서를 받습니다. +**로그 다운로드** 버튼을 클릭하여 세션을 내보냅니다. Claude Code, Codex, Copilot, Cursor, Pi 세션의 경우 디스크의 원본 JSONL 트랜스크립트를 바이트 단위로 그대로 받을 수 있으며, OpenCode(세션이 디스크가 아닌 SQLite에 저장됨)의 경우 기본 `session` / `messages` / `parts` 테이블을 미러링하는 JSON 문서를 받습니다. ### 감사 @@ -75,16 +75,16 @@ failproofai - - 단일 패널에서 failproofai가 보호할 에이전트 CLI를 다중 선택 — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, Hermes 각각에 설치 상태(`Active` / `Detected` / `Inactive`), 사용자 범위 설정 경로, 브랜드 색상 강조가 있는 행이 있습니다. 원하는 CLI를 체크 또는 체크 해제하고 `Apply changes`를 클릭하면 한 번에 차이를 설치/제거합니다. PATH에서 바이너리가 감지된 CLI는 미리 체크됩니다. + - 단일 패널에서 failproofai가 보호할 에이전트 CLI를 다중 선택 — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Hermes 각각에 설치 상태(`Active` / `Detected` / `Inactive`), 사용자 범위 설정 경로, 브랜드 색상 강조가 있는 행이 있습니다. 원하는 CLI를 체크 또는 체크 해제하고 `Apply changes`를 클릭하면 한 번에 차이를 설치/제거합니다. PATH에서 바이너리가 감지된 CLI는 미리 체크됩니다. - 단일 클릭으로 개별 정책을 켜거나 끕니다(`~/.failproofai/policies-config.json`에 기록 — 모든 설치된 CLI에서 공유됨) - 정책을 펼쳐 매개변수를 구성합니다(`policyParams`를 지원하는 정책의 경우) - 사용자 지정 정책 파일 경로 설정 - 모든 세션에서 실행된 모든 훅 이벤트의 전체 페이지네이션 기록 - - 결정, 이벤트 유형, CLI(Claude Code / OpenAI Codex / GitHub Copilot _(베타)_ / Cursor Agent _(베타)_ / OpenCode _(베타)_ / Pi _(베타)_ / Gemini CLI _(베타)_ / Hermes), 정책 이름 또는 세션 ID로 필터링 - - 각 행에는 타임스탬프, 정책 이름, 결정, CLI 배지(주황색 = Claude Code, 보라색 = OpenAI Codex, 파란색 = GitHub Copilot, 에메랄드 = Cursor Agent, 호박색 = OpenCode, 분홍색 = Pi, 하늘색 = Gemini CLI, 남색 = Hermes), 툴 이름, 세션 ID, deny/instruct 결정 이유가 표시됩니다 - - 세션 ID를 클릭하면 트랜스크립트가 열립니다 — 뷰어는 어떤 CLI가 훅을 실행했는지(Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`)를 자동으로 감지하고 헤더에 일치하는 CLI 배지를 렌더링합니다 + - 결정, 이벤트 유형, CLI(Claude Code / OpenAI Codex / GitHub Copilot _(베타)_ / Cursor Agent _(베타)_ / OpenCode _(베타)_ / Pi _(베타)_ / Hermes), 정책 이름 또는 세션 ID로 필터링 + - 각 행에는 타임스탬프, 정책 이름, 결정, CLI 배지(주황색 = Claude Code, 보라색 = OpenAI Codex, 파란색 = GitHub Copilot, 에메랄드 = Cursor Agent, 호박색 = OpenCode, 분홍색 = Pi, 남색 = Hermes), 툴 이름, 세션 ID, deny/instruct 결정 이유가 표시됩니다 + - 세션 ID를 클릭하면 트랜스크립트가 열립니다 — 뷰어는 어떤 CLI가 훅을 실행했는지(Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`)를 자동으로 감지하고 헤더에 일치하는 CLI 배지를 렌더링합니다 diff --git a/docs/ko/getting-started.mdx b/docs/ko/getting-started.mdx index 6b7ff502..c3a26343 100644 --- a/docs/ko/getting-started.mdx +++ b/docs/ko/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - 이 명령은 설치된 에이전트 CLI에 훅 항목을 기록합니다 (Claude Code의 `~/.claude/settings.json`, OpenAI Codex의 `~/.codex/hooks.json`, GitHub Copilot CLI의 `~/.copilot/hooks/failproofai.json`, Cursor Agent의 `~/.cursor/hooks.json`, OpenCode의 `~/.config/opencode/plugins/failproofai.mjs` 생성 플러그인 심 및 `~/.config/opencode/opencode.json`의 `plugin` 배열 등록 항목, Pi의 `~/.pi/agent/settings.json`, Gemini CLI의 `~/.gemini/settings.json`, Hermes의 `~/.hermes/config.yaml`). 둘 이상의 CLI가 설치되어 있으면 선택 프롬프트가 표시됩니다. `--cli claude codex copilot cursor opencode pi gemini hermes` (원하는 조합)를 전달하면 프롬프트를 건너뜁니다. + 이 명령은 설치된 에이전트 CLI에 훅 항목을 기록합니다 (Claude Code의 `~/.claude/settings.json`, OpenAI Codex의 `~/.codex/hooks.json`, GitHub Copilot CLI의 `~/.copilot/hooks/failproofai.json`, Cursor Agent의 `~/.cursor/hooks.json`, OpenCode의 `~/.config/opencode/plugins/failproofai.mjs` 생성 플러그인 심 및 `~/.config/opencode/opencode.json`의 `plugin` 배열 등록 항목, Pi의 `~/.pi/agent/settings.json`, Hermes의 `~/.hermes/config.yaml`). 둘 이상의 CLI가 설치되어 있으면 선택 프롬프트가 표시됩니다. `--cli claude codex copilot cursor opencode pi hermes` (원하는 조합)를 전달하면 프롬프트를 건너뜁니다. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI 지원은 **베타** 단계입니다 — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, 또는 `--cli gemini`로 설치하세요. Hermes (hermes-agent, Slack/Telegram 게이트웨이)는 `--cli hermes`로 사용자 범위에 설치되며 오프라인 감사 소스이기도 합니다. + GitHub Copilot CLI, Cursor Agent, OpenCode, Pi 지원은 **베타** 단계입니다 — `--cli copilot`, `--cli cursor`, `--cli opencode`, 또는 `--cli pi`로 설치하세요. Hermes (hermes-agent, Slack/Telegram 게이트웨이)는 `--cli hermes`로 사용자 범위에 설치되며 오프라인 감사 소스이기도 합니다. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/ko/introduction.mdx b/docs/ko/introduction.mdx index b48424a0..48222763 100644 --- a/docs/ko/introduction.mdx +++ b/docs/ko/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI는 단 한 번의 설치로 루프, 시크릿 유출, [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI 실패 처리**, **오류 복구**, **LLM 안정성**을 위한 훅과 정책 모음입니다. **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, **Agents SDK** 전반에 걸쳐 AI 에이전트를 안정적으로 자율 실행할 수 있도록 지원합니다. +**AI 실패 처리**, **오류 복구**, **LLM 안정성**을 위한 훅과 정책 모음입니다. **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **Agents SDK** 전반에 걸쳐 AI 에이전트를 안정적으로 자율 실행할 수 있도록 지원합니다. AI 에이전트는 예측 가능한 방식으로 실패합니다. 파괴적인 명령을 실행하거나, 시크릿을 유출하거나, 작업 범위를 벗어나거나, 루프에 빠지거나, main 브랜치에 직접 푸시하기도 합니다. 방치하면 사소한 실패가 서비스 장애, 자격 증명 유출, 작업 손실로 이어질 수 있습니다. diff --git a/docs/pt-br/built-in-policies.mdx b/docs/pt-br/built-in-policies.mdx index 6d84b6c4..d35046b7 100644 --- a/docs/pt-br/built-in-policies.mdx +++ b/docs/pt-br/built-in-policies.mdx @@ -712,20 +712,19 @@ A aplicação de Stop funciona de forma ligeiramente diferente entre os sete CLI | Codex | No mesmo loop do agente, imediatamente | Igual ao Claude. | | GitHub Copilot CLI | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal de retry `{decision:"block", reason}` do Copilot — verificado empiricamente no Copilot CLI 1.0.41). | | Cursor Agent | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal `{followup_message}` do Cursor — limitado ao `loop_limit`, padrão 5 tentativas). | -| Gemini CLI | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal `{decision:"block", reason}` do Gemini em `AfterAgent`). | | OpenCode | No mesmo loop do agente, imediatamente | Igual ao Claude (usa a chamada SDK `client.session.prompt(...)` do OpenCode roteada através de `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Próximo turno do usuário** | **O Pi para visivelmente** quando o gate é acionado — seu loop de agente sai e você retorna ao prompt. O gate é então acionado na próxima vez que você enviar um prompt: o failproofai antepõe uma diretiva `MANDATORY ACTION REQUIRED` ao prompt do sistema daquele turno, instruindo o LLM a concluir a etapa do fluxo de trabalho (commit, push, etc.) antes de fazer o que você pediu. | -**Limitação do Pi.** O `AgentEndEvent` do Pi (o equivalente upstream do hook `Stop` do Claude) não tem tipo Result — quando ele é acionado, o loop do agente do Pi já saiu. O Pi não pode ser forçado a repetir o mesmo loop da forma que Claude / Copilot / Cursor / Gemini / OpenCode podem. O failproofai desloca o gate para o evento `before_agent_start` do Pi (que é acionado após o próximo prompt do usuário), para que a verificação do fluxo de trabalho ainda seja aplicada, apenas no próximo turno em vez do atual. +**Limitação do Pi.** O `AgentEndEvent` do Pi (o equivalente upstream do hook `Stop` do Claude) não tem tipo Result — quando ele é acionado, o loop do agente do Pi já saiu. O Pi não pode ser forçado a repetir o mesmo loop da forma que Claude / Copilot / Cursor / OpenCode podem. O failproofai desloca o gate para o evento `before_agent_start` do Pi (que é acionado após o próximo prompt do usuário), para que a verificação do fluxo de trabalho ainda seja aplicada, apenas no próximo turno em vez do atual. **O que isso significa na prática:** - Após o Pi parar, o motivo da negação é capturado na memória, indexado pelo ID de sessão do Pi. O próximo prompt que você enviar no mesmo processo do Pi o consome: o LLM vê a diretiva `MANDATORY ACTION REQUIRED` no topo de seu prompt de sistema, faz o commit (ou push / abre o PR / aguarda o CI), e só então continua com sua solicitação. O motivo de negação capturado é de uso único — uma vez consumido, o gate é liberado. -- O gate é limitado ao tempo de vida do processo do Pi. Se você der `Ctrl+C` no Pi ou sair entre turnos, a entrada na memória é descartada junto com o processo e o gate é perdido. Claude, Copilot, Cursor, Gemini e OpenCode têm o mesmo limite (matar o agente faz o gate ser perdido) — o Pi apenas torna isso mais visível porque o agente sai visivelmente antes do gate ser acionado. +- O gate é limitado ao tempo de vida do processo do Pi. Se você der `Ctrl+C` no Pi ou sair entre turnos, a entrada na memória é descartada junto com o processo e o gate é perdido. Claude, Copilot, Cursor e OpenCode têm o mesmo limite (matar o agente faz o gate ser perdido) — o Pi apenas torna isso mais visível porque o agente sai visivelmente antes do gate ser acionado. - Uma negação pendente também é limpa no `session_shutdown` por qualquer motivo (`new` / `resume` / `fork` / `quit`), então um gate obsoleto de uma sessão anterior não pode vazar para uma nova sessão iniciada no mesmo processo do Pi. -Se você precisar do retry no mesmo loop no estilo Claude, execute suas políticas `Stop` em qualquer um dos outros seis CLIs suportados. Estamos acompanhando o upstream do Pi para um futuro tipo Result no `AgentEndEvent` que nos permitiria fechar essa lacuna. +Se você precisar do retry no mesmo loop no estilo Claude, execute suas políticas `Stop` em qualquer um dos outros cinco CLIs suportados. Estamos acompanhando o upstream do Pi para um futuro tipo Result no `AgentEndEvent` que nos permitiria fechar essa lacuna. ### `require-commit-before-stop` diff --git a/docs/pt-br/cli/audit.mdx b/docs/pt-br/cli/audit.mdx index 0886e980..6ca1a458 100644 --- a/docs/pt-br/cli/audit.mdx +++ b/docs/pt-br/cli/audit.mdx @@ -55,7 +55,7 @@ failproofai até você encerrá-lo com `Ctrl+C`. -O dashboard varre transcrições anteriores do agente CLI nesta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e relata com que frequência o agente fez coisas que o failproofai foi criado para impedir — verificações de variáveis de ambiente, force pushes, prefixos redundantes `cd `, loops de polling com sleep, releitura de arquivos recém-editados, e mais. +O dashboard varre transcrições anteriores do agente CLI nesta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e relata com que frequência o agente fez coisas que o failproofai foi criado para impedir — verificações de variáveis de ambiente, force pushes, prefixos redundantes `cd `, loops de polling com sleep, releitura de arquivos recém-editados, e mais. Para cada transcrição, cada evento de uso de ferramenta é reproduzido pelas 39 políticas integradas **e** pelos 8 detectores exclusivos do audit que capturam padrões ainda não cobertos pelas políticas em tempo real. As contagens são agregadas por política/detector em todas as sessões. diff --git a/docs/pt-br/configuration.mdx b/docs/pt-br/configuration.mdx index ba82f42c..f0d9db1c 100644 --- a/docs/pt-br/configuration.mdx +++ b/docs/pt-br/configuration.mdx @@ -196,13 +196,12 @@ Os comandos `policies --install` e `policies --uninstall` escrevem no arquivo de - **OpenAI Codex**: `~/.codex/hooks.json` (usuário), `/.codex/hooks.json` (projeto) — o Codex não possui escopo `local` - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuário), `/.github/hooks/failproofai.json` (projeto) — o Copilot não possui escopo `local`. As entradas de hook usam os campos de comando `bash`/`powershell` com chave por SO do Copilot com `timeoutSec`; o arquivo carrega um marcador `version: 1` no nível superior. O suporte ao Copilot CLI está em **beta** enquanto verificamos o esquema de registros `events.jsonl` (não especificado na documentação pública) em mais sessões reais. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuário), `/.cursor/hooks.json` (projeto) — o Cursor não possui escopo `local`. As entradas de hook usam o formato Claude `{type, command, timeout}` (sem divisão `bash`/`powershell`), mas armazenadas sob chaves de evento em camelCase (`preToolUse`, `beforeSubmitPrompt`, …) em um array plano, conforme o [esquema de hooks](https://cursor.com/docs/hooks) do Cursor; o arquivo carrega um marcador `version: 1` no nível superior. O handler canonicaliza camelCase → PascalCase via `CURSOR_EVENT_MAP`, de modo que as políticas integradas existentes disparam sem alteração. O suporte ao Cursor Agent está em **beta** enquanto verificamos o formato em disco da transcrição do Cursor (não especificado na documentação pública) em mais instalações reais. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuário), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projeto) — o OpenCode não possui escopo `local`. Diferentemente dos outros seis CLIs, o OpenCode **não possui sistema de hooks para comandos externos**: ele carrega plugins JS/TS em processo, explicitamente registrados pelo array `plugin: []` no `opencode.json` (a autodescoberta a partir de `.opencode/plugins/` **não** é como os plugins são carregados no opencode v1.14.33). A instalação deposita um pequeno shim de plugin gerado que chama o binário failproofai em subprocesso e traduz a resposta JSON no formato Claude do binário para a semântica do plugin: `throw new Error()` para negação em eventos de ferramenta (cancela a chamada da ferramenta), `client.session.prompt(...)` para instruct E para negação de `Stop` / `SubagentStop` (envia o motivo da negação como a próxima mensagem do usuário — o único canal de força de nova tentativa, já que `session.idle` é apenas de notificação e lançar exceção a partir dele é um no-op), e no-op para allow. O shim canonicaliza nomes de ferramentas (minúsculas → PascalCase via `OPENCODE_TOOL_MAP`) e chaves de argumentos de entrada de ferramentas (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, por exemplo `filePath` → `file_path`, `oldString` → `old_string`) antes de encaminhar ao binário, de modo que políticas integradas de verificação de caminho como `block-read-outside-cwd`, `block-env-files` e `block-secrets-write` disparam sem alteração em chamadas de ferramentas do OpenCode. As sessões ficam no banco de dados SQLite do opencode em `~/.local/share/opencode/opencode.db`; o visualizador de sessões do dashboard as lê via `opencode db --format json` e `opencode export `. O suporte ao OpenCode está em **beta** enquanto verificamos o comportamento entre versões e em mais sessões reais. Consulte a [documentação de plugins do OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuário), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projeto) — o OpenCode não possui escopo `local`. Diferentemente dos outros cinco CLIs, o OpenCode **não possui sistema de hooks para comandos externos**: ele carrega plugins JS/TS em processo, explicitamente registrados pelo array `plugin: []` no `opencode.json` (a autodescoberta a partir de `.opencode/plugins/` **não** é como os plugins são carregados no opencode v1.14.33). A instalação deposita um pequeno shim de plugin gerado que chama o binário failproofai em subprocesso e traduz a resposta JSON no formato Claude do binário para a semântica do plugin: `throw new Error()` para negação em eventos de ferramenta (cancela a chamada da ferramenta), `client.session.prompt(...)` para instruct E para negação de `Stop` / `SubagentStop` (envia o motivo da negação como a próxima mensagem do usuário — o único canal de força de nova tentativa, já que `session.idle` é apenas de notificação e lançar exceção a partir dele é um no-op), e no-op para allow. O shim canonicaliza nomes de ferramentas (minúsculas → PascalCase via `OPENCODE_TOOL_MAP`) e chaves de argumentos de entrada de ferramentas (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, por exemplo `filePath` → `file_path`, `oldString` → `old_string`) antes de encaminhar ao binário, de modo que políticas integradas de verificação de caminho como `block-read-outside-cwd`, `block-env-files` e `block-secrets-write` disparam sem alteração em chamadas de ferramentas do OpenCode. As sessões ficam no banco de dados SQLite do opencode em `~/.local/share/opencode/opencode.db`; o visualizador de sessões do dashboard as lê via `opencode db --format json` e `opencode export `. O suporte ao OpenCode está em **beta** enquanto verificamos o comportamento entre versões e em mais sessões reais. Consulte a [documentação de plugins do OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuário), `/.pi/settings.json` (projeto) — o Pi não possui escopo `local`. O Pi carrega pacotes de extensão TypeScript na inicialização; o arquivo de configurações é um array de strings plano `{"packages": ["./relative/path", …]}`. failproofai escreve uma única entrada no array de pacotes apontando para seu diretório `pi-extension/` empacotado. A extensão subscreve internamente aos eventos `tool_call` / `user_bash` / `input` / `session_start` do Pi e executa `failproofai --hook --cli pi` em shell; o handler canonicaliza eventos via `PI_EVENT_MAP` (underscore_lower_snake_case → PascalCase) para que as políticas integradas existentes disparem sem alteração. Os argumentos de entrada de ferramentas também são canonicalizados via `PI_TOOL_INPUT_MAP` (o Read / Write / Edit do Pi entregam `path` em vez de `file_path`; mapear a chave de nível superior permite que `block-env-files` e `block-secrets-write` disparem — `block-read-outside-cwd` já tinha um fallback para `path`). O suporte ao Pi está em **beta** enquanto a API de extensão do Pi e o layout do log de sessão se estabilizam. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (usuário), `/.gemini/settings.json` (projeto) — o Gemini não possui escopo `local` (ele documenta um escopo `system` em `/etc/gemini-cli/settings.json`, que failproofai não expõe). As entradas de hook usam o formato Claude `{type, command, timeout}` encapsulado no esquema de matcher do Gemini `{matcher, hooks: [...]}` com `matcher: "*"` por padrão. Os eventos são PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); o handler mapeia para nomes canônicos do Claude via `GEMINI_EVENT_MAP`. Os nomes de ferramentas são snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — o handler os canonicaliza via `GEMINI_TOOL_MAP` para que as políticas integradas existentes disparem sem alteração. O avaliador de políticas emite o formato plano `{decision: "deny", reason}` do Gemini (preferido conforme o contrato exit-0 da "Regra de Ouro" do Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` para injeção de contexto em BeforeAgent / AfterTool / SessionStart, e `{decision: "block", reason}` em AfterAgent para semântica de força de nova tentativa. O suporte ao Gemini CLI está em **beta** enquanto ampliamos a cobertura em situações reais. Consulte a [documentação de hooks do Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**somente escopo de usuário** — o Hermes não possui configuração de projeto/local). O Hermes é um **gateway** para Slack/Telegram, portanto uma única instalação intercepta chamadas de ferramentas de todas as plataformas (Slack/Telegram/cli/cron) **e** de subagentes internos. As entradas de hook são um par `{command, timeout}` (timeout em **segundos**) sob um mapa `hooks:` com chave pelos eventos snake_case do Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); o handler canonicaliza eventos via `HERMES_EVENT_MAP` e nomes de ferramentas via `HERMES_TOOL_MAP` para que as políticas integradas disparem sem alteração. A configuração é editada por meio de uma edição de ida e volta de `Document` YAML que preserva comentários, para que as outras configurações do operador sobrevivam, e a instalação define `hooks_auto_accept: true` para que o gateway headless (sem TTY) execute os hooks sem uma solicitação de consentimento. O avaliador emite o contrato stdout `{"decision":"block","reason"}` do Hermes (o Hermes ignora códigos de saída). **Limitações:** O Hermes não possui evento `Stop` de fim de turno, portanto as políticas integradas `require-*-before-stop` nunca disparam para ele (inaplicável, não quebrado); `instruct` é rebaixado para allow com nota registrada (sem canal de contexto adicional); e a redação de segredos na saída (`sanitize-*`) não pode reescrever a saída das ferramentas pelo contrato de hook de shell. O Hermes é **também** uma fonte de **auditoria** offline — o dashboard lê suas sessões de gateway diretamente de `~/.hermes/state.db`. - **`policies-config.json`** — informa ao failproofai quais políticas avaliar e com quais parâmetros (compartilhado entre todos os agentes CLI) -Passe `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` para direcionar um agente específico (separado por espaço ou repetido para qualquer subconjunto): +Passe `--cli claude|codex|copilot|cursor|opencode|pi|hermes` para direcionar um agente específico (separado por espaço ou repetido para qualquer subconjunto): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Quando `--cli` é omitido, `failproofai` detecta quais agentes CLI estão instalados (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Quando `--cli` é omitido, `failproofai` detecta quais agentes CLI estão instalados (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Um CLI detectado** — seleciona automaticamente esse CLI sem solicitar confirmação. - **Vários CLIs detectados** em um terminal interativo — exibe um prompt de seleção única com teclas de seta, agrupado em uma seção `Detected (N)` (com uma linha agregada `Install for all N detected` + cada CLI detectado individualmente) e uma seção `Not installed (M) · install hooks ahead of time` listando todos os CLIs suportados não detectados como opções de instalação antecipada (↑↓ para mover, Enter para selecionar, ^C para sair). O fluxo de desinstalação exibe apenas a seção Detected. diff --git a/docs/pt-br/dashboard.mdx b/docs/pt-br/dashboard.mdx index 7b2ed4d0..dd1a54d9 100644 --- a/docs/pt-br/dashboard.mdx +++ b/docs/pt-br/dashboard.mdx @@ -24,11 +24,11 @@ O dashboard lê diretamente do sistema de arquivos — suas pastas de projetos d ### Projetos -Lista todos os projetos Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ e Hermes encontrados na sua máquina. Os projetos Claude são descobertos em `~/.claude/projects/` (ou no caminho definido por `CLAUDE_PROJECTS_PATH`); os projetos Codex são descobertos varrendo todas as transcrições em `~/.codex/sessions///
/*.jsonl` e agrupando pelo `cwd` registrado no primeiro registro de cada sessão; os projetos Copilot CLI são descobertos varrendo cada `~/.copilot/session-state//workspace.yaml` (configurável via `COPILOT_HOME`) e agrupando pelo campo `cwd`; os projetos Cursor Agent são descobertos varrendo metadados por sessão em `~/.cursor/agent-sessions//` (configurável via `CURSOR_HOME`, com `conversations/` e `sessions/` como alternativas) em busca de um escalar `cwd` em `meta.json` / `session.json` / `workspace.yaml`; os projetos OpenCode são descobertos consultando seu banco SQLite em `~/.local/share/opencode/opencode.db` via `opencode db --format json` (lemos as tabelas `session` e `project` e agrupamos por `project_id`); os projetos Pi são descobertos varrendo transcrições JSONL por sessão em `~/.pi/agent/sessions//_.jsonl` (configurável via `PI_SESSIONS_DIR`) e extraindo o `cwd` do primeiro registro de cada sessão; os projetos Gemini CLI são descobertos varrendo `~/.gemini/tmp//chats/session--.jsonl` (configurável via `GEMINI_SESSIONS_DIR`) e recuperando o cwd canônico a partir do marcador de texto `.project_root` adjacente; as sessões do gateway Hermes são lidas diretamente do seu armazenamento SQLite em `~/.hermes/state.db` (configurável via `HERMES_DB_PATH`) e agrupadas em projetos `hermes-` por `source` (Slack/Telegram/cli/cron — sessões do gateway não possuem cwd). Um projeto utilizado por múltiplos CLIs é exibido como uma única linha com todos os badges correspondentes. Use o menu suspenso **CLI** acima da tabela para filtrar por um agente CLI específico; a URL preserva sua seleção como `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lista todos os projetos Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ e Hermes encontrados na sua máquina. Os projetos Claude são descobertos em `~/.claude/projects/` (ou no caminho definido por `CLAUDE_PROJECTS_PATH`); os projetos Codex são descobertos varrendo todas as transcrições em `~/.codex/sessions///
/*.jsonl` e agrupando pelo `cwd` registrado no primeiro registro de cada sessão; os projetos Copilot CLI são descobertos varrendo cada `~/.copilot/session-state//workspace.yaml` (configurável via `COPILOT_HOME`) e agrupando pelo campo `cwd`; os projetos Cursor Agent são descobertos varrendo metadados por sessão em `~/.cursor/agent-sessions//` (configurável via `CURSOR_HOME`, com `conversations/` e `sessions/` como alternativas) em busca de um escalar `cwd` em `meta.json` / `session.json` / `workspace.yaml`; os projetos OpenCode são descobertos consultando seu banco SQLite em `~/.local/share/opencode/opencode.db` via `opencode db --format json` (lemos as tabelas `session` e `project` e agrupamos por `project_id`); os projetos Pi são descobertos varrendo transcrições JSONL por sessão em `~/.pi/agent/sessions//_.jsonl` (configurável via `PI_SESSIONS_DIR`) e extraindo o `cwd` do primeiro registro de cada sessão; as sessões do gateway Hermes são lidas diretamente do seu armazenamento SQLite em `~/.hermes/state.db` (configurável via `HERMES_DB_PATH`) e agrupadas em projetos `hermes-` por `source` (Slack/Telegram/cli/cron — sessões do gateway não possuem cwd). Um projeto utilizado por múltiplos CLIs é exibido como uma única linha com todos os badges correspondentes. Use o menu suspenso **CLI** acima da tabela para filtrar por um agente CLI específico; a URL preserva sua seleção como `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Cada projeto exibe: - Nome do projeto (derivado do caminho da pasta) -- Um badge de CLI — `Claude Code` (laranja), `OpenAI Codex` (roxo), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (âmbar), `Pi` (rosa), `Gemini CLI` (celeste) e/ou `Hermes` (índigo) +- Um badge de CLI — `Claude Code` (laranja), `OpenAI Codex` (roxo), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (âmbar), `Pi` (rosa) e/ou `Hermes` (índigo) - Data da atividade mais recente da sessão Clique em um projeto para ver suas sessões. @@ -47,7 +47,7 @@ Clique em uma sessão para abrir o visualizador de sessão. ### Visualizador de sessão -O visualizador de sessão responde à pergunta central dos agentes autônomos: o que o agente fez, e ele se manteve no curso? Um badge de CLI ao lado do cabeçalho indica se a sessão é uma transcrição do Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI ou Hermes. Ele exibe uma linha do tempo de tudo que aconteceu em uma sessão: +O visualizador de sessão responde à pergunta central dos agentes autônomos: o que o agente fez, e ele se manteve no curso? Um badge de CLI ao lado do cabeçalho indica se a sessão é uma transcrição do Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ou Hermes. Ele exibe uma linha do tempo de tudo que aconteceu em uma sessão: - **Mensagens** — Respostas de texto do Claude e prompts do usuário - **Chamadas de ferramentas** — Cada ferramenta que o Claude invocou, com sua entrada e saída @@ -55,7 +55,7 @@ O visualizador de sessão responde à pergunta central dos agentes autônomos: o A barra de estatísticas no topo mostra a duração da sessão, total de chamadas de ferramentas e um resumo das decisões de hook (contagens de allow / deny / instruct). -Clique no botão **Download Logs** para exportar a sessão. Para sessões do Claude Code, Codex, Copilot, Cursor, Pi e Gemini, você recebe a transcrição JSONL original em disco byte a byte; para o OpenCode (cujas sessões ficam no SQLite, não em disco) você recebe um documento JSON espelhando as tabelas subjacentes `session` / `messages` / `parts`. +Clique no botão **Download Logs** para exportar a sessão. Para sessões do Claude Code, Codex, Copilot, Cursor e Pi, você recebe a transcrição JSONL original em disco byte a byte; para o OpenCode (cujas sessões ficam no SQLite, não em disco) você recebe um documento JSON espelhando as tabelas subjacentes `session` / `messages` / `parts`. ### Auditoria @@ -75,16 +75,16 @@ Uma página com duas abas para gerenciar políticas e revisar atividade. - - Selecione múltiplos CLIs de agentes que o failproofai protege em um único painel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI e Hermes têm uma linha com status de instalação (`Active` / `Detected` / `Inactive`), o caminho de configurações de escopo do usuário e um destaque com a cor da marca. Marque ou desmarque os CLIs desejados e clique em `Apply changes` para instalar/desinstalar as alterações em uma etapa. CLIs cujo binário é detectado no PATH são pré-selecionados. + - Selecione múltiplos CLIs de agentes que o failproofai protege em um único painel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi e Hermes têm uma linha com status de instalação (`Active` / `Detected` / `Inactive`), o caminho de configurações de escopo do usuário e um destaque com a cor da marca. Marque ou desmarque os CLIs desejados e clique em `Apply changes` para instalar/desinstalar as alterações em uma etapa. CLIs cujo binário é detectado no PATH são pré-selecionados. - Ative ou desative políticas individuais com um único clique (escreve em `~/.failproofai/policies-config.json` — compartilhado entre todos os CLIs instalados) - Expanda uma política para configurar seus parâmetros (para políticas que suportam `policyParams`) - Defina um caminho personalizado para o arquivo de políticas - Histórico paginado completo de cada evento de hook que foi acionado em todas as sessões - - Filtre por decisão, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nome da política ou ID de sessão - - Cada linha exibe: timestamp, nome da política, decisão, badge de CLI (laranja = Claude Code, roxo = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, âmbar = OpenCode, rosa = Pi, celeste = Gemini CLI, índigo = Hermes), nome da ferramenta, ID de sessão e o motivo das decisões deny/instruct - - Clique em um ID de sessão para abrir sua transcrição — o visualizador detecta automaticamente qual CLI acionou o hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) e renderiza o badge de CLI correspondente no cabeçalho + - Filtre por decisão, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), nome da política ou ID de sessão + - Cada linha exibe: timestamp, nome da política, decisão, badge de CLI (laranja = Claude Code, roxo = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, âmbar = OpenCode, rosa = Pi, índigo = Hermes), nome da ferramenta, ID de sessão e o motivo das decisões deny/instruct + - Clique em um ID de sessão para abrir sua transcrição — o visualizador detecta automaticamente qual CLI acionou o hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) e renderiza o badge de CLI correspondente no cabeçalho diff --git a/docs/pt-br/getting-started.mdx b/docs/pt-br/getting-started.mdx index 133c5565..f9091965 100644 --- a/docs/pt-br/getting-started.mdx +++ b/docs/pt-br/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Isso registra entradas de hook nos CLIs de agente instalados (o `~/.claude/settings.json` do Claude Code, o `~/.codex/hooks.json` do OpenAI Codex, o `~/.copilot/hooks/failproofai.json` do GitHub Copilot CLI, o `~/.cursor/hooks.json` do Cursor Agent, o shim de plugin gerado pelo OpenCode em `~/.config/opencode/plugins/failproofai.mjs` mais uma entrada de registro no array `plugin` de `~/.config/opencode/opencode.json`, o `~/.pi/agent/settings.json` do Pi, o `~/.gemini/settings.json` do Gemini CLI ou o `~/.hermes/config.yaml` do Hermes). Se mais de um estiver presente, você será solicitado a escolher; passe `--cli claude codex copilot cursor opencode pi gemini hermes` (qualquer subconjunto) para pular a seleção. + Isso registra entradas de hook nos CLIs de agente instalados (o `~/.claude/settings.json` do Claude Code, o `~/.codex/hooks.json` do OpenAI Codex, o `~/.copilot/hooks/failproofai.json` do GitHub Copilot CLI, o `~/.cursor/hooks.json` do Cursor Agent, o shim de plugin gerado pelo OpenCode em `~/.config/opencode/plugins/failproofai.mjs` mais uma entrada de registro no array `plugin` de `~/.config/opencode/opencode.json`, o `~/.pi/agent/settings.json` do Pi ou o `~/.hermes/config.yaml` do Hermes). Se mais de um estiver presente, você será solicitado a escolher; passe `--cli claude codex copilot cursor opencode pi hermes` (qualquer subconjunto) para pular a seleção. - O suporte ao GitHub Copilot CLI, Cursor Agent, OpenCode, Pi e Gemini CLI está em **beta** — instale com `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` ou `--cli gemini`. O Hermes (hermes-agent, um gateway Slack/Telegram) é instalado no escopo de usuário com `--cli hermes` e é **também** uma fonte de auditoria offline. + O suporte ao GitHub Copilot CLI, Cursor Agent, OpenCode e Pi está em **beta** — instale com `--cli copilot`, `--cli cursor`, `--cli opencode` ou `--cli pi`. O Hermes (hermes-agent, um gateway Slack/Telegram) é instalado no escopo de usuário com `--cli hermes` e é **também** uma fonte de auditoria offline. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/pt-br/introduction.mdx b/docs/pt-br/introduction.mdx index aaf26213..911908e0 100644 --- a/docs/pt-br/introduction.mdx +++ b/docs/pt-br/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI oferece 39 políticas de falha integradas para agentes [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks e políticas para **tratamento de falhas de IA**, **recuperação de erros** e **confiabilidade de LLMs**. Mantenha seus agentes de IA confiáveis e funcionando de forma autônoma no **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** e no **Agents SDK**. +Hooks e políticas para **tratamento de falhas de IA**, **recuperação de erros** e **confiabilidade de LLMs**. Mantenha seus agentes de IA confiáveis e funcionando de forma autônoma no **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** e no **Agents SDK**. Agentes de IA falham de maneiras previsíveis. Eles executam comandos destrutivos, vazam segredos, desviam da tarefa, ficam presos em loops ou fazem push direto para a branch principal. Sem supervisão, falhas pequenas evoluem para quedas de serviço, credenciais expostas e trabalho perdido. diff --git a/docs/ru/built-in-policies.mdx b/docs/ru/built-in-policies.mdx index 4a02f746..24211560 100644 --- a/docs/ru/built-in-policies.mdx +++ b/docs/ru/built-in-policies.mdx @@ -712,20 +712,19 @@ failproofai поставляется с 39 встроенными политик | Codex | Тот же цикл агента, сразу | То же самое, что Claude. | | GitHub Copilot CLI | Тот же цикл агента, сразу | То же самое, что Claude (использует канал повтора `{decision:"block", reason}` Copilot — проверено эмпирически на Copilot CLI 1.0.41). | | Cursor Agent | Тот же цикл агента, сразу | То же самое, что Claude (использует канал `{followup_message}` Cursor — ограничен `loop_limit`, по умолчанию 5 повторов). | -| Gemini CLI | Тот же цикл агента, сразу | То же самое, что Claude (использует канал `{decision:"block", reason}` Gemini на `AfterAgent`). | | OpenCode | Тот же цикл агента, сразу | То же самое, что Claude (использует вызов SDK `client.session.prompt(...)` OpenCode, маршрутизированный через `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Следующий ход пользователя** | **Pi видимо останавливается**, когда срабатывает шлюз — его цикл агента завершается и вы возвращаетесь к приглашению. Шлюз затем срабатывает при следующей отправке приглашения: failproofai добавляет директиву `MANDATORY ACTION REQUIRED` в системное приглашение того хода, инструктируя LLM завершить шаг рабочего процесса (commit, push и т. д.) перед выполнением запрашиваемого вами действия. | -**Ограничение Pi.** `AgentEndEvent` Pi (эквивалент `Stop` хука Claude) не имеет типа Result — по времени его срабатывания цикл агента Pi уже завершился. Pi не может быть принуждена повторить тот же цикл, как Claude / Copilot / Cursor / Gemini / OpenCode. failproofai смещает шлюз к событию `before_agent_start` Pi (которое срабатывает после следующего приглашения пользователя), чтобы проверка рабочего процесса всё ещё применялась, просто при следующем ходе вместо текущего. +**Ограничение Pi.** `AgentEndEvent` Pi (эквивалент `Stop` хука Claude) не имеет типа Result — по времени его срабатывания цикл агента Pi уже завершился. Pi не может быть принуждена повторить тот же цикл, как Claude / Copilot / Cursor / OpenCode. failproofai смещает шлюз к событию `before_agent_start` Pi (которое срабатывает после следующего приглашения пользователя), чтобы проверка рабочего процесса всё ещё применялась, просто при следующем ходе вместо текущего. **Что это означает на практике:** - После остановки Pi причина deny захватывается в памяти с ключом по id сессии Pi. Самое следующее приглашение, которое вы отправляете в той же сессии Pi, его извлекает: LLM видит директиву `MANDATORY ACTION REQUIRED` в верхней части своего системного приглашения, commit-ит (или push-ит / открывает PR / ждёт CI) и только затем продолжает с вашим запросом. Захваченная причина deny — одноразовая — после извлечения шлюз свободен. -- Шлюз ограничен временем жизни процесса Pi. Если вы `Ctrl+C` Pi или выход между ходами, запись в памяти удаляется вместе с процессом и шлюз пропускается. Claude, Copilot, Cursor, Gemini и OpenCode имеют то же самое ограничение (kill агента и шлюз пропускается) — Pi просто делает это более видимым, потому что агент видимо завершает работу перед срабатыванием шлюза. +- Шлюз ограничен временем жизни процесса Pi. Если вы `Ctrl+C` Pi или выход между ходами, запись в памяти удаляется вместе с процессом и шлюз пропускается. Claude, Copilot, Cursor и OpenCode имеют то же самое ограничение (kill агента и шлюз пропускается) — Pi просто делает это более видимым, потому что агент видимо завершает работу перед срабатыванием шлюза. - Ожидающий deny также очищается на `session_shutdown` по любой причине (`new` / `resume` / `fork` / `quit`), поэтому устаревший шлюз из предыдущей сессии не может утечь в свежую сессию, начатую в том же процессе Pi. -Если вам нужен повтор в том же цикле, как Claude, запустите ваши политики `Stop` в любом из шести других поддерживаемых CLI. Мы отслеживаем Pi upstream на предмет будущего типа Result на `AgentEndEvent`, который позволил бы нам закрыть этот пробел. +Если вам нужен повтор в том же цикле, как Claude, запустите ваши политики `Stop` в любом из пяти других поддерживаемых CLI. Мы отслеживаем Pi upstream на предмет будущего типа Result на `AgentEndEvent`, который позволил бы нам закрыть этот пробел. ### `require-commit-before-stop` diff --git a/docs/ru/cli/audit.mdx b/docs/ru/cli/audit.mdx index d3693eec..a140379d 100644 --- a/docs/ru/cli/audit.mdx +++ b/docs/ru/cli/audit.mdx @@ -52,7 +52,7 @@ failproofai до тех пор, пока вы не остановите её с помощью `Ctrl+C`. -Панель сканирует прошлые транскрипты агента CLI на этой машине (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) и сообщает, как часто агент выполнял операции, которые failproofai создан, чтобы остановить — проверки переменных окружения, force push, повторяющиеся префиксы `cd `, sleep-polling циклы, повторное чтение только что отредактированных файлов и многое другое. +Панель сканирует прошлые транскрипты агента CLI на этой машине (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) и сообщает, как часто агент выполнял операции, которые failproofai создан, чтобы остановить — проверки переменных окружения, force push, повторяющиеся префиксы `cd `, sleep-polling циклы, повторное чтение только что отредактированных файлов и многое другое. Для каждого транскрипта каждое событие использования инструмента воспроизводится через 39 встроенных политик **и** через 8 аудит-специфичных детекторов, которые выявляют паттерны, еще не покрытые политиками реального времени. Подсчеты агрегируются для каждой политики/детектора по всем сеансам. diff --git a/docs/ru/configuration.mdx b/docs/ru/configuration.mdx index 8a9c41e9..5445f018 100644 --- a/docs/ru/configuration.mdx +++ b/docs/ru/configuration.mdx @@ -196,13 +196,12 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← переходит - **OpenAI Codex**: `~/.codex/hooks.json` (пользователь), `/.codex/hooks.json` (проект) — Codex не имеет локальной области - **GitHub Copilot CLI _(бета)_**: `~/.copilot/hooks/failproofai.json` (пользователь), `/.github/hooks/failproofai.json` (проект) — Copilot не имеет локальной области. Записи хуков используют поля команд `bash`/`powershell` с ключом ОС и `timeoutSec` Copilot; файл содержит маркер `version: 1` верхнего уровня. Поддержка Copilot CLI находится в **бета-версии**, пока мы проверяем схему записи `events.jsonl` (которую общедоступные документы не указывают) против дополнительных реальных сессий. - **Cursor Agent _(бета)_**: `~/.cursor/hooks.json` (пользователь), `/.cursor/hooks.json` (проект) — Cursor не имеет локальной области. Записи хуков используют форму с Claude-подобной формой `{type, command, timeout}` (без разделения `bash`/`powershell`), но хранятся под camelCase ключами событий (`preToolUse`, `beforeSubmitPrompt`, …) в плоском массиве согласно [схеме хуков](https://cursor.com/docs/hooks) Cursor; файл содержит маркер `version: 1` верхнего уровня. Обработчик канонизирует camelCase → PascalCase через `CURSOR_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Поддержка Cursor Agent находится в **бета-версии**, пока мы проверяем транскрипт Cursor на диске (не указан в общедоступных документах) против дополнительных реальных установок. - - **OpenCode _(бета)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (пользователь), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (проект) — OpenCode не имеет локальной области. В отличие от остальных шести CLI, OpenCode **не имеет системы внешних команд для хуков**: он загружает в процессе плагины JS/TS, явно зарегистрированные через массив `plugin: []` в `opencode.json` (автообнаружение из `.opencode/plugins/` **не** это как загружаются плагины в opencode v1.14.33). Install помещает маленький сгенерированный шим плагина, который subprocess-вызывает бинарный файл failproofai и переводит JSON-ответ бинарного файла Claude-подобной формы обратно в семантику плагина: `throw new Error()` для отрицания tool-события (отменяет вызов инструмента), `client.session.prompt(...)` для instruct И для отрицания `Stop` / `SubagentStop` (отправляет причину отрицания как следующее пользовательское сообщение — единственный канал force-retry, так как `session.idle` только для уведомления и выброс из неё — это no-op), и no-op для allow. Шим канонизирует названия инструментов (lowercase → PascalCase через `OPENCODE_TOOL_MAP`) и ключи аргументов инструментов (camelCase → snake_case через `OPENCODE_TOOL_INPUT_MAP` для `Read` / `Write` / `Edit`, например `filePath` → `file_path`, `oldString` → `old_string`) перед отправкой в бинарный файл, поэтому встроенные проверки путей вроде `block-read-outside-cwd`, `block-env-files` и `block-secrets-write` срабатывают без изменений для вызовов инструментов OpenCode. Сессии живут в БД SQLite OpenCode в `~/.local/share/opencode/opencode.db`; средство просмотра сессий на панели инструментов читает их через `opencode db --format json` и `opencode export `. Поддержка OpenCode находится в **бета-версии**, пока мы проверяем поведение в разных версиях и против дополнительных реальных сессий. См. [документацию плагинов OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(бета)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (пользователь), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (проект) — OpenCode не имеет локальной области. В отличие от остальных пяти CLI, OpenCode **не имеет системы внешних команд для хуков**: он загружает в процессе плагины JS/TS, явно зарегистрированные через массив `plugin: []` в `opencode.json` (автообнаружение из `.opencode/plugins/` **не** это как загружаются плагины в opencode v1.14.33). Install помещает маленький сгенерированный шим плагина, который subprocess-вызывает бинарный файл failproofai и переводит JSON-ответ бинарного файла Claude-подобной формы обратно в семантику плагина: `throw new Error()` для отрицания tool-события (отменяет вызов инструмента), `client.session.prompt(...)` для instruct И для отрицания `Stop` / `SubagentStop` (отправляет причину отрицания как следующее пользовательское сообщение — единственный канал force-retry, так как `session.idle` только для уведомления и выброс из неё — это no-op), и no-op для allow. Шим канонизирует названия инструментов (lowercase → PascalCase через `OPENCODE_TOOL_MAP`) и ключи аргументов инструментов (camelCase → snake_case через `OPENCODE_TOOL_INPUT_MAP` для `Read` / `Write` / `Edit`, например `filePath` → `file_path`, `oldString` → `old_string`) перед отправкой в бинарный файл, поэтому встроенные проверки путей вроде `block-read-outside-cwd`, `block-env-files` и `block-secrets-write` срабатывают без изменений для вызовов инструментов OpenCode. Сессии живут в БД SQLite OpenCode в `~/.local/share/opencode/opencode.db`; средство просмотра сессий на панели инструментов читает их через `opencode db --format json` и `opencode export `. Поддержка OpenCode находится в **бета-версии**, пока мы проверяем поведение в разных версиях и против дополнительных реальных сессий. См. [документацию плагинов OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(бета)_**: `~/.pi/agent/settings.json` (пользователь), `/.pi/settings.json` (проект) — Pi не имеет локальной области. Pi загружает пакеты расширений TypeScript при запуске; файл параметров — это плоский массив строк `{"packages": ["./relative/path", …]}`. failproofai записывает одну запись packages-массива, указывающую на встроенную директорию `pi-extension/`. Расширение внутренне подписывается на события Pi `tool_call` / `user_bash` / `input` / `session_start` и shell-вызывает `failproofai --hook --cli pi`; обработчик канонизирует underscore_lower_snake_case → PascalCase через `PI_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Аргументы инструментов также канонизируются через `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit доставляют `path` вместо `file_path`; картирование верхнего уровня позволяет `block-env-files` и `block-secrets-write` срабатывать — `block-read-outside-cwd` уже имел fallback для `path`). Поддержка Pi находится в **бета-версии**, пока API расширений Pi и макет журнала сессий стабилизируются. - - **Gemini CLI _(бета)_**: `~/.gemini/settings.json` (пользователь), `/.gemini/settings.json` (проект) — Gemini не имеет локальной области (она документирует область `system` в `/etc/gemini-cli/settings.json`, которую failproofai не предоставляет). Записи хуков используют форму Claude's `{type, command, timeout}`, обёрнутую в схему matcher Gemini's `{matcher, hooks: [...]}` с `matcher: "*"` по умолчанию. События — PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); обработчик картирует на имена Claude canonical через `GEMINI_EVENT_MAP`. Названия инструментов — snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — обработчик канонизирует через `GEMINI_TOOL_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Оценщик политик выдаёт плоскую форму Gemini's `{decision: "deny", reason}` (предпочтено по Gemini's Golden Rule контракту exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` для внедрения контекста в BeforeAgent / AfterTool / SessionStart, и `{decision: "block", reason}` на AfterAgent для семантики force-retry. Поддержка Gemini CLI находится в **бета-версии**, пока мы расширяем реальное покрытие. См. [документацию хуков Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**только область пользователя** — Hermes не имеет конфига проекта/локально). Hermes — это **шлюз** Slack/Telegram, поэтому одна установка перехватывает вызовы инструментов от каждой платформы (Slack/Telegram/cli/cron) **и** внутренние подагенты. Записи хуков — это пара `{command, timeout}` (timeout в **секундах**) под картой `hooks:` с ключами от snake_case событий Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); обработчик канонизирует события через `HERMES_EVENT_MAP` и названия инструментов через `HERMES_TOOL_MAP`, поэтому встроенные политики срабатывают без изменений. Конфиг редактируется через коммент-сохраняющий YAML round-trip `Document`, поэтому остальные параметры оператора выживают, и install устанавливает `hooks_auto_accept: true`, чтобы headless шлюз (без TTY) запускал хуки без промпта согласия. Оценщик выдаёт контракт `{"decision":"block","reason"}` stdout Hermes (Hermes игнорирует коды выхода). **Ограничения:** Hermes не имеет event end-turn `Stop`, поэтому встроенные `require-*-before-stop` никогда не срабатывают для него (неприменимо, не сломано); `instruct` деградирует до allow-with-logged-note (нет канала дополнительного контекста); и переписывание выходных секретов (`sanitize-*`) не может переписать вывод инструмента через shell-hook контракт. Hermes — **также** оффлайн **audit** источник — панель инструментов читает сессии шлюза напрямую из `~/.hermes/state.db`. - **`policies-config.json`** — указывает failproofai, какие политики оценивать и с какими параметрами (общее для всех CLI агентов) -Передайте `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` для выбора конкретного агента (разделённые пробелом или повторённые для подмножества): +Передайте `--cli claude|codex|copilot|cursor|opencode|pi|hermes` для выбора конкретного агента (разделённые пробелом или повторённые для подмножества): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Когда `--cli` опущен, `failproofai` обнаруживает, какие CLI агентов установлены (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Когда `--cli` опущен, `failproofai` обнаруживает, какие CLI агентов установлены (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Один CLI обнаружен** — автоматически выбирает тот CLI без запроса. - **Несколько CLI обнаружено** в интерактивном терминале — показывает однострочный prompt выбора со стрелками, сгруппированный в раздел `Detected (N)` (с агрегированной строкой `Install for all N detected` + каждый обнаруженный CLI отдельно) и раздел `Not installed (M) · install hooks ahead of time`, перечисляющий каждый неподдерживаемый CLI как опцию forward-install (↑↓ для перемещения, Enter для выбора, ^C для выхода). Flow разустановки показывает только раздел Detected. diff --git a/docs/ru/dashboard.mdx b/docs/ru/dashboard.mdx index 416ba866..d9ccf3d5 100644 --- a/docs/ru/dashboard.mdx +++ b/docs/ru/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### Projects -Список всех найденных на вашем компьютере проектов Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ и Hermes. Проекты Claude обнаруживаются из `~/.claude/projects/` (или пути, установленного в `CLAUDE_PROJECTS_PATH`); проекты Codex обнаруживаются путём сканирования каждой транскрипции под `~/.codex/sessions///
/*.jsonl` и группировки по `cwd`, записанному в первой записи каждого сеанса; проекты Copilot CLI обнаруживаются путём сканирования каждого `~/.copilot/session-state//workspace.yaml` (настраивается через `COPILOT_HOME`) и группировки по полю `cwd`; проекты Cursor Agent обнаруживаются путём сканирования метаданных для каждого сеанса под `~/.cursor/agent-sessions//` (настраивается через `CURSOR_HOME`, со счётом `conversations/` и `sessions/` в качестве резервных вариантов) для скаляра `cwd` в `meta.json` / `session.json` / `workspace.yaml`; проекты OpenCode обнаруживаются путём запроса к его БД SQLite на `~/.local/share/opencode/opencode.db` через `opencode db --format json` (мы читаем таблицы `session` и `project` и группируем по `project_id`); проекты Pi обнаруживаются путём сканирования транскрипций JSONL для каждого сеанса под `~/.pi/agent/sessions//_.jsonl` (настраивается через `PI_SESSIONS_DIR`) и извлечения `cwd` из первой записи каждого сеанса; проекты Gemini CLI обнаруживаются путём сканирования `~/.gemini/tmp//chats/session--.jsonl` (настраивается через `GEMINI_SESSIONS_DIR`) и восстановления канонического cwd из текстового маркера `.project_root`; сеансы шлюза Hermes читаются непосредственно из его хранилища SQLite на `~/.hermes/state.db` (настраивается через `HERMES_DB_PATH`) и группируются в проекты `hermes-` по `source` (Slack/Telegram/cli/cron — сеансы шлюза не имеют cwd). Проект, который использовался несколькими CLI, отображается как одна строка со всеми соответствующими значками. Используйте выпадающее меню **CLI** над таблицей для фильтрации по конкретному агенту; URL сохраняет ваш выбор как `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Список всех найденных на вашем компьютере проектов Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ и Hermes. Проекты Claude обнаруживаются из `~/.claude/projects/` (или пути, установленного в `CLAUDE_PROJECTS_PATH`); проекты Codex обнаруживаются путём сканирования каждой транскрипции под `~/.codex/sessions///
/*.jsonl` и группировки по `cwd`, записанному в первой записи каждого сеанса; проекты Copilot CLI обнаруживаются путём сканирования каждого `~/.copilot/session-state//workspace.yaml` (настраивается через `COPILOT_HOME`) и группировки по полю `cwd`; проекты Cursor Agent обнаруживаются путём сканирования метаданных для каждого сеанса под `~/.cursor/agent-sessions//` (настраивается через `CURSOR_HOME`, со счётом `conversations/` и `sessions/` в качестве резервных вариантов) для скаляра `cwd` в `meta.json` / `session.json` / `workspace.yaml`; проекты OpenCode обнаруживаются путём запроса к его БД SQLite на `~/.local/share/opencode/opencode.db` через `opencode db --format json` (мы читаем таблицы `session` и `project` и группируем по `project_id`); проекты Pi обнаруживаются путём сканирования транскрипций JSONL для каждого сеанса под `~/.pi/agent/sessions//_.jsonl` (настраивается через `PI_SESSIONS_DIR`) и извлечения `cwd` из первой записи каждого сеанса; сеансы шлюза Hermes читаются непосредственно из его хранилища SQLite на `~/.hermes/state.db` (настраивается через `HERMES_DB_PATH`) и группируются в проекты `hermes-` по `source` (Slack/Telegram/cli/cron — сеансы шлюза не имеют cwd). Проект, который использовался несколькими CLI, отображается как одна строка со всеми соответствующими значками. Используйте выпадающее меню **CLI** над таблицей для фильтрации по конкретному агенту; URL сохраняет ваш выбор как `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Каждый проект показывает: - Имя проекта (производное от пути папки) -- Значок CLI — `Claude Code` (оранжевый), `OpenAI Codex` (фиолетовый), `GitHub Copilot` (синий), `Cursor Agent` (изумруд), `OpenCode` (янтарь), `Pi` (розовый), `Gemini CLI` (небесно-голубой) и/или `Hermes` (индиго) +- Значок CLI — `Claude Code` (оранжевый), `OpenAI Codex` (фиолетовый), `GitHub Copilot` (синий), `Cursor Agent` (изумруд), `OpenCode` (янтарь), `Pi` (розовый) и/или `Hermes` (индиго) - Дата последней активности сеанса Щёлкните по проекту, чтобы просмотреть его сеансы. @@ -47,7 +47,7 @@ failproofai ### Session viewer -Средство просмотра сеанса отвечает на ключевой вопрос для автономных агентов: что сделал агент и остался ли он на курсе? Значок CLI рядом с заголовком указывает, является ли сеанс транскрипцией Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI или Hermes. Он показывает временную шкалу всего, что произошло в сеансе: +Средство просмотра сеанса отвечает на ключевой вопрос для автономных агентов: что сделал агент и остался ли он на курсе? Значок CLI рядом с заголовком указывает, является ли сеанс транскрипцией Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi или Hermes. Он показывает временную шкалу всего, что произошло в сеансе: - **Messages** — текстовые ответы Claude и подсказки пользователя - **Tool calls** — каждый инструмент, который вызвал Claude, с его входными и выходными данными @@ -55,7 +55,7 @@ failproofai Панель статистики вверху показывает длительность сеанса, общее количество вызовов инструментов и сводку решений хуков (счётчики allow / deny / instruct). -Нажмите кнопку **Download Logs** для экспорта сеанса. Для сеансов Claude Code, Codex, Copilot, Cursor, Pi и Gemini вы получаете исходную транскрипцию JSONL на диске в исходном виде; для OpenCode (чьи сеансы хранятся в SQLite, а не на диске) вы получаете JSON-документ, отражающий основные таблицы `session` / `messages` / `parts`. +Нажмите кнопку **Download Logs** для экспорта сеанса. Для сеансов Claude Code, Codex, Copilot, Cursor и Pi вы получаете исходную транскрипцию JSONL на диске в исходном виде; для OpenCode (чьи сеансы хранятся в SQLite, а не на диске) вы получаете JSON-документ, отражающий основные таблицы `session` / `messages` / `parts`. ### Audit @@ -75,16 +75,16 @@ failproofai - - Выберите несколько агентов CLI, которых защищает failproofai, из одной панели — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI и Hermes все имеют строку со статусом установки (`Active` / `Detected` / `Inactive`), путём пользовательской области видимости и фирменный цветной акцент. Отметьте или снимите отметку с CLI, которые вы хотите, и нажмите `Apply changes` для установки/удаления разницы за один шаг. CLI, чьи двоичные файлы обнаружены в PATH, предварительно отмечены. + - Выберите несколько агентов CLI, которых защищает failproofai, из одной панели — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi и Hermes все имеют строку со статусом установки (`Active` / `Detected` / `Inactive`), путём пользовательской области видимости и фирменный цветной акцент. Отметьте или снимите отметку с CLI, которые вы хотите, и нажмите `Apply changes` для установки/удаления разницы за один шаг. CLI, чьи двоичные файлы обнаружены в PATH, предварительно отмечены. - Переключайте отдельные политики вкл/выкл одним щелчком (записывает в `~/.failproofai/policies-config.json` — общее для каждого установленного CLI) - Разверните политику для настройки её параметров (для политик, поддерживающих `policyParams`) - Установите путь пользовательского файла политик - Полная постраничная история каждого события хука, срабатывающего во всех сеансах - - Фильтруйте по решению, типу события, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), имени политики или ID сеанса - - Каждая строка показывает: временную метку, имя политики, решение, значок CLI (оранжевый = Claude Code, фиолетовый = OpenAI Codex, синий = GitHub Copilot, изумруд = Cursor Agent, янтарь = OpenCode, розовый = Pi, небесно-голубой = Gemini CLI, индиго = Hermes), имя инструмента, ID сеанса и причину решений deny/instruct - - Щёлкните по ID сеанса, чтобы открыть его транскрипцию — средство просмотра автоматически обнаруживает, какой CLI срабатил хук (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) и отображает соответствующий значок CLI в заголовке + - Фильтруйте по решению, типу события, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), имени политики или ID сеанса + - Каждая строка показывает: временную метку, имя политики, решение, значок CLI (оранжевый = Claude Code, фиолетовый = OpenAI Codex, синий = GitHub Copilot, изумруд = Cursor Agent, янтарь = OpenCode, розовый = Pi, индиго = Hermes), имя инструмента, ID сеанса и причину решений deny/instruct + - Щёлкните по ID сеанса, чтобы открыть его транскрипцию — средство просмотра автоматически обнаруживает, какой CLI срабатил хук (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) и отображает соответствующий значок CLI в заголовке diff --git a/docs/ru/getting-started.mdx b/docs/ru/getting-started.mdx index 26e9d490..fa1e20b0 100644 --- a/docs/ru/getting-started.mdx +++ b/docs/ru/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Эта команда записывает записи хуков в установленные CLI агентов (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, или Hermes's `~/.hermes/config.yaml`). Если присутствует несколько, вам будет предложено выбрать; передайте `--cli claude codex copilot cursor opencode pi gemini hermes` (любое подмножество), чтобы пропустить запрос. + Эта команда записывает записи хуков в установленные CLI агентов (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, или Hermes's `~/.hermes/config.yaml`). Если присутствует несколько, вам будет предложено выбрать; передайте `--cli claude codex copilot cursor opencode pi hermes` (любое подмножество), чтобы пропустить запрос. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi и Gemini CLI поддерживаются в режиме **бета** — установите с помощью `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` или `--cli gemini`. Hermes (hermes-agent, шлюз Slack/Telegram) устанавливается в область пользователя с помощью `--cli hermes` и также является источником автономного аудита. + GitHub Copilot CLI, Cursor Agent, OpenCode и Pi поддерживаются в режиме **бета** — установите с помощью `--cli copilot`, `--cli cursor`, `--cli opencode` или `--cli pi`. Hermes (hermes-agent, шлюз Slack/Telegram) устанавливается в область пользователя с помощью `--cli hermes` и также является источником автономного аудита. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/ru/introduction.mdx b/docs/ru/introduction.mdx index 4996d294..e02edcaf 100644 --- a/docs/ru/introduction.mdx +++ b/docs/ru/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI предоставляет AI агентам 39 вст [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Хуки и политики для **обработки сбоев AI**, **восстановления после ошибок** и **надёжности LLM**. Держите ваших AI агентов надёжными и работающими автономно на **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** и **Agents SDK**. +Хуки и политики для **обработки сбоев AI**, **восстановления после ошибок** и **надёжности LLM**. Держите ваших AI агентов надёжными и работающими автономно на **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** и **Agents SDK**. AI агенты падают предсказуемым образом. Они выполняют деструктивные команды, утекают секреты, отходят от задачи, застревают в циклах или пушат прямо в main. Без надзора, небольшие сбои каскадируют в отказы, утечки учётных данных и потерю работы. diff --git a/docs/styles/config/vocabularies/Mintlify/accept.txt b/docs/styles/config/vocabularies/Mintlify/accept.txt index c7f9498d..c0668800 100644 --- a/docs/styles/config/vocabularies/Mintlify/accept.txt +++ b/docs/styles/config/vocabularies/Mintlify/accept.txt @@ -4,7 +4,6 @@ Anthropic Codex Copilot Cursor -Gemini OpenCode PreToolUse PostToolUse diff --git a/docs/tr/built-in-policies.mdx b/docs/tr/built-in-policies.mdx index 240ec79d..936e1d40 100644 --- a/docs/tr/built-in-policies.mdx +++ b/docs/tr/built-in-policies.mdx @@ -712,20 +712,19 @@ Stop uygulaması yedi desteklenen CLI arasında biraz farklı görünür; çünk | Codex | Aynı ajan döngüsü, hemen | Claude ile aynı. | | GitHub Copilot CLI | Aynı ajan döngüsü, hemen | Claude ile aynı (Copilot'un `{decision:"block", reason}` yeniden deneme kanalını kullanır — ampirik olarak Copilot CLI 1.0.41'e karşı doğrulanmıştır). | | Cursor Agent | Aynı ajan döngüsü, hemen | Claude ile aynı (Cursor'un `{followup_message}` kanalını kullanır — `loop_limit`, varsayılan 5 yeniden denemeler ile sınırlandırılmış). | -| Gemini CLI | Aynı ajan döngüsü, hemen | Claude ile aynı (Gemini'nin `{decision:"block", reason}` kanalını kullanır; `AfterAgent` üzerinde). | | OpenCode | Aynı ajan döngüsü, hemen | Claude ile aynı (OpenCode'un `client.session.prompt(...)` SDK çağrısını kullanır; `hookSpecificOutput.additionalContext` aracılığıyla yönlendirilmiş). | | **Pi (pi-coding-agent)** | **Sonraki kullanıcı sırası** | **Kapı devreye girdiğinde Pi görünen şekilde durur** — ajan döngüsü çıkar ve komut isteminin başına dönersiniz. Kapı daha sonra bir sonraki iletişim gönderdiğinizde devreye girer: failproofai iş akışı adımını tamamlamadan önce (commit, push vb.) bir `MANDATORY ACTION REQUIRED` yönergesini o sıraya ait sistem komutunun başına ekler; ne istedinizi yapmadan önce. -**Pi sınırlaması.** Pi'nin `AgentEndEvent` (Claude'un `Stop` hook'unun yukarı akış eşdeğeri) hiçbir Result türü yoktur — Pi'nin ajan döngüsü zaten çıkmış olduğu süredir. Pi, Claude / Copilot / Cursor / Gemini / OpenCode'un yapabildiği şekilde aynı döngüyü yeniden denemeye zorlanamazı. failproofai kapıyı Pi'nin `before_agent_start` olayına kaydırır (sonraki kullanıcı iletişim sonrasında devreye girer) — iş akışı kontrolü hala uygulanır, yalnızca mevcut sıra yerine sonraki sıra üzerinde. +**Pi sınırlaması.** Pi'nin `AgentEndEvent` (Claude'un `Stop` hook'unun yukarı akış eşdeğeri) hiçbir Result türü yoktur — Pi'nin ajan döngüsü zaten çıkmış olduğu süredir. Pi, Claude / Copilot / Cursor / OpenCode'un yapabildiği şekilde aynı döngüyü yeniden denemeye zorlanamazı. failproofai kapıyı Pi'nin `before_agent_start` olayına kaydırır (sonraki kullanıcı iletişim sonrasında devreye girer) — iş akışı kontrolü hala uygulanır, yalnızca mevcut sıra yerine sonraki sıra üzerinde. **Bunu pratikte ne anlama gelir:** - Pi durundan sonra, reddetme nedeni oturum kimliği tarafından bellek içinde anahtarlanmış şekilde yakalanır. Aynı Pi işlemi içinde gönderdiğiniz çok sonraki istişare bunu boşaltır: LLM sistem komutunun üstünde `MANDATORY ACTION REQUIRED` yönergesini görür, commits (veya pushes / açıklık PR / CI'yi bekler) ve ancak o zaman istediğiniz şeye devam eder. Yakalanan reddetme nedeni tek atış — bir kez boşaltıldıktan sonra kapı açıktır. -- Kapı Pi'nin işlem ömrü tarafından sınırlandırılır. Turlar arasında Pi'yi `Ctrl+C` yaparsanız veya çıkarsanız, bellek içi giriş işlemle birlikte bırakılır ve kapı kaçırılır. Claude, Copilot, Cursor, Gemini ve OpenCode'un aynı sınırı vardır (ajanı öldürün ve kapı kaçırılır) — Pi sadece bunu daha görünür hale getirir; çünkü ajan kapı devreye girmeden önce görünen şekilde çıkar. +- Kapı Pi'nin işlem ömrü tarafından sınırlandırılır. Turlar arasında Pi'yi `Ctrl+C` yaparsanız veya çıkarsanız, bellek içi giriş işlemle birlikte bırakılır ve kapı kaçırılır. Claude, Copilot, Cursor ve OpenCode'un aynı sınırı vardır (ajanı öldürün ve kapı kaçırılır) — Pi sadece bunu daha görünür hale getirir; çünkü ajan kapı devreye girmeden önce görünen şekilde çıkar. - Beklemede olan bir reddetme herhangi bir nedenle `session_shutdown` üzerine de temizlenir (`new` / `resume` / `fork` / `quit`), bu nedenle önceki oturumdan eski bir kapı, aynı Pi işlemi içinde başlatılan yeni bir oturuma sızamaz. -Claude tarzı aynı döngü yeniden denemesine ihtiyacınız varsa, `Stop` ilkelerinizi desteklenen diğer altı CLI'den birinin altında çalıştırın. Pi yukarı akışını gelecek bir Result türü ile izliyoruz; `AgentEndEvent` üzerinde bu boşluğu kapatmamıza izin verecektir. +Claude tarzı aynı döngü yeniden denemesine ihtiyacınız varsa, `Stop` ilkelerinizi desteklenen diğer beş CLI'den birinin altında çalıştırın. Pi yukarı akışını gelecek bir Result türü ile izliyoruz; `AgentEndEvent` üzerinde bu boşluğu kapatmamıza izin verecektir. ### `require-commit-before-stop` diff --git a/docs/tr/cli/audit.mdx b/docs/tr/cli/audit.mdx index 3615d41a..608b0108 100644 --- a/docs/tr/cli/audit.mdx +++ b/docs/tr/cli/audit.mdx @@ -47,7 +47,7 @@ failproofai Kullanımı görmek için `failproofai audit -h` (veya `--help`) komutunu çalıştırın. Denetim **tamamen çevrimdışı** çalışır — hesap veya ağ gerekmez — ve kontrol paneli `Ctrl+C` ile durdurana kadar sunulmaya devam eder. -Kontrol paneli bu makinedeki geçmiş ajan CLI transkriptlerini tarar (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) ve ajanın failproofai'nin durdurmak için tasarlandığı şeyleri ne sıklıkla yaptığını bildirir — ortam değişkeni kontrolleri, zorla göndermeler, gereksiz `cd ` önekleri, uyku-yoklama döngüleri, yeni düzenlenen dosyaları yeniden okuma ve daha fazlası. +Kontrol paneli bu makinedeki geçmiş ajan CLI transkriptlerini tarar (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) ve ajanın failproofai'nin durdurmak için tasarlandığı şeyleri ne sıklıkla yaptığını bildirir — ortam değişkeni kontrolleri, zorla göndermeler, gereksiz `cd ` önekleri, uyku-yoklama döngüleri, yeni düzenlenen dosyaları yeniden okuma ve daha fazlası. Her transkript için, her araç-kullanım olayı 39 yerleşik politika **ve** henüz çalışma zamanı politikaları tarafından kapsanmayan desenleri yakalayan 8 denetim-yalnızca dedektörü aracılığıyla yeniden oynatılır. Sayılar tüm oturumlar arasında politika / dedektör başına toplanır. diff --git a/docs/tr/configuration.mdx b/docs/tr/configuration.mdx index 245b7f07..e426bd8a 100644 --- a/docs/tr/configuration.mdx +++ b/docs/tr/configuration.mdx @@ -196,13 +196,12 @@ AI çağrıları yapan politikalar için LLM istemci yapılandırması. Çoğu k - **OpenAI Codex**: `~/.codex/hooks.json` (kullanıcı), `/.codex/hooks.json` (proje) — Codex yerel kapsamı yok - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (kullanıcı), `/.github/hooks/failproofai.json` (proje) — Copilot yerel kapsamı yok. Hook girdileri Copilot'un OS anahtarlı `bash`/`powershell` komut alanlarını `timeoutSec` ile kullanır; dosya üst düzey `version: 1` işaretçisini taşır. Copilot CLI desteği **beta** durumundadır ve `events.jsonl` kayıt şemasını (halk belgeleri belirtmez) daha fazla gerçek dünya oturumuna karşı doğrularız. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (kullanıcı), `/.cursor/hooks.json` (proje) — Cursor yerel kapsamı yok. Hook girdileri Claude şeklinde `{type, command, timeout}` formunu kullanır (`bash`/`powershell` bölümü yok) ancak camelCase olay anahtarları (`preToolUse`, `beforeSubmitPrompt`, …) altında depolanır, Cursor'un [hooks şemasına](https://cursor.com/docs/hooks) göre düz dizi halinde; dosya üst düzey `version: 1` işaretçisini taşır. İşleyici, `CURSOR_EVENT_MAP` aracılığıyla camelCase → PascalCase'i kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Cursor Agent desteği **beta** durumundadır ve Cursor'un disk üzerindeki transkripti (açık belgelerde belirtilmez) daha fazla gerçek dünya kurulumuna karşı doğrularız. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (kullanıcı), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proje) — OpenCode yerel kapsamı yok. Diğer altı CLI'den farklı olarak, OpenCode **harici komut hook sistemi olmaz**: `plugin: []` dizisi aracılığıyla açıkça kaydedilen işlem içi JS/TS eklentilerini yükler (`opencode.json` içinde) (`.opencode/plugins/` dan otomatik keşif opencode v1.14.33'de eklentilerin nasıl yüklendiği **değildir**). Kurulum, ikili failproofai'yi subprocess olarak çağıran ve ikili'nin Claude şekli JSON yanıtını eklenti semantiğine geri çeviren küçük bir oluşturulan eklenti parçacığını bırakır: araç olayı reddi için `throw new Error()` (araç çağrısını iptal eder), `instruct` VE `Stop` / `SubagentStop` reddi için `client.session.prompt(...)` (reddi nedeni bir sonraki kullanıcı iletisi olarak gönderir — `session.idle` yalnızca bildirimdir ve bundan atmak no-op olduğundan tek zorla yeniden deneme kanalı), allow için no-op. Parçacık hem araç adlarını (küçük harf → PascalCase, `OPENCODE_TOOL_MAP` aracılığıyla) hem de araç giriş arg anahtarlarını (camelCase → snake_case, `OPENCODE_TOOL_INPUT_MAP` aracılığıyla `Read` / `Write` / `Edit` için, örn. `filePath` → `file_path`, `oldString` → `old_string`) kanonikleştirir, ikili'ye iletmeden önce, yol kontrol yerleşikleri gibi `block-read-outside-cwd`, `block-env-files` ve `block-secrets-write` OpenCode araç çağrılarında değişmeden çalışır. Oturumlar opencode'un SQLite DB'sinde yaşar `~/.local/share/opencode/opencode.db`; pano'nun oturum görüntüleyicisi onları `opencode db --format json` ve `opencode export ` aracılığıyla okur. OpenCode desteği **beta** durumundadır ve sürümler arasında ve daha fazla gerçek dünya oturumlarına karşı davranışı doğrularız. [OpenCode eklentileri belgeleri](https://opencode.ai/docs/plugins/) başlıklı sayfaya bakın. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (kullanıcı), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proje) — OpenCode yerel kapsamı yok. Diğer beş CLI'den farklı olarak, OpenCode **harici komut hook sistemi olmaz**: `plugin: []` dizisi aracılığıyla açıkça kaydedilen işlem içi JS/TS eklentilerini yükler (`opencode.json` içinde) (`.opencode/plugins/` dan otomatik keşif opencode v1.14.33'de eklentilerin nasıl yüklendiği **değildir**). Kurulum, ikili failproofai'yi subprocess olarak çağıran ve ikili'nin Claude şekli JSON yanıtını eklenti semantiğine geri çeviren küçük bir oluşturulan eklenti parçacığını bırakır: araç olayı reddi için `throw new Error()` (araç çağrısını iptal eder), `instruct` VE `Stop` / `SubagentStop` reddi için `client.session.prompt(...)` (reddi nedeni bir sonraki kullanıcı iletisi olarak gönderir — `session.idle` yalnızca bildirimdir ve bundan atmak no-op olduğundan tek zorla yeniden deneme kanalı), allow için no-op. Parçacık hem araç adlarını (küçük harf → PascalCase, `OPENCODE_TOOL_MAP` aracılığıyla) hem de araç giriş arg anahtarlarını (camelCase → snake_case, `OPENCODE_TOOL_INPUT_MAP` aracılığıyla `Read` / `Write` / `Edit` için, örn. `filePath` → `file_path`, `oldString` → `old_string`) kanonikleştirir, ikili'ye iletmeden önce, yol kontrol yerleşikleri gibi `block-read-outside-cwd`, `block-env-files` ve `block-secrets-write` OpenCode araç çağrılarında değişmeden çalışır. Oturumlar opencode'un SQLite DB'sinde yaşar `~/.local/share/opencode/opencode.db`; pano'nun oturum görüntüleyicisi onları `opencode db --format json` ve `opencode export ` aracılığıyla okur. OpenCode desteği **beta** durumundadır ve sürümler arasında ve daha fazla gerçek dünya oturumlarına karşı davranışı doğrularız. [OpenCode eklentileri belgeleri](https://opencode.ai/docs/plugins/) başlıklı sayfaya bakın. - **Pi _(beta)_**: `~/.pi/agent/settings.json` (kullanıcı), `/.pi/settings.json` (proje) — Pi yerel kapsamı yok. Pi başlangıçta TypeScript uzantı paketlerini yükler; ayarlar dosyası düz dize dizisidir `{"packages": ["./relative/path", …]}`. failproofai, paketlenmiş `pi-extension/` dizinine işaret eden tek bir packages-dizisi girişi yazar. Uzantı dahili olarak Pi'nin `tool_call` / `user_bash` / `input` / `session_start` olaylarına abone olur ve `failproofai --hook --cli pi`'ye shell çıkışı verir; işleyici underscore_lower_snake_case → PascalCase'i `PI_EVENT_MAP` aracılığıyla kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Araç giriş argları da `PI_TOOL_INPUT_MAP` aracılığıyla kanonikleştirilir (Pi'nin Read / Write / Edit `file_path` yerine `path` iletir; üst düzey anahtarı eşlemek `block-env-files` ve `block-secrets-write`'in çalışmasını sağlar — `block-read-outside-cwd` zaten bir `path` geri dönüşü içeriyordu). Pi desteği **beta** durumundadır, Pi'nin uzantı API'si ve oturum günlüğü düzeni stabilize olurken. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (kullanıcı), `/.gemini/settings.json` (proje) — Gemini yerel kapsamı yok (`/etc/gemini-cli/settings.json` içinde belgelenen bir `system` kapsamı vardır, failproofai bunu göstermez). Hook girdileri Claude'un `{type, command, timeout}` formunu Gemini'nin `{matcher, hooks: [...]}` eşleşme şemasında, varsayılan olarak `matcher: "*"` ile sarılı halde kullanır. Olaylar PascalCase'tir (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); işleyici `GEMINI_EVENT_MAP` aracılığıyla Claude kanonik adlarına eşlenir. Araç adları snake_case'tir (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — işleyici `GEMINI_TOOL_MAP` aracılığıyla kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Politika değerlendirici Gemini'nin düz `{decision: "deny", reason}` şeklini yayar (Gemini'nin "Altın Kural" exit-0 sözleşmesine göre tercih edilen), `{hookSpecificOutput: {hookEventName, additionalContext}}` BeforeAgent / AfterTool / SessionStart'ta bağlam enjeksiyonu için ve AfterAgent'ta `{decision: "block", reason}` zorla yeniden deneme semantiği için. Gemini CLI desteği **beta** durumundadır ve gerçek dünya kapsamsını genişletirken. [Gemini CLI hooks belgeleri](https://geminicli.com/docs/hooks/) başlıklı sayfaya bakın. - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**yalnızca kullanıcı kapsamı** — Hermes proje/yerel yapılandırması yok). Hermes bir Slack/Telegram **ağ geçididir**, bu nedenle bir kurulum her platformdan (Slack/Telegram/cli/cron) araç çağrılarını **ve** iç alt ajanları yakalar. Hook girdileri, Hermes'in snake_case olayları (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) tarafından anahtarlanan `hooks:` eşlemesi altında `{command, timeout}` çiftidir; işleyici `HERMES_EVENT_MAP` aracılığıyla olayları ve `HERMES_TOOL_MAP` aracılığıyla araç adlarını kanonikleştirir, böylece yerleşik politikalar değişmeden çalışır. Yapılandırma, yorum koruyan YAML `Document` turuna göre düzenlendiğinden işletmenin diğer ayarları kalır ve kurulum, başsız ağ geçidinin (TTY yok) hookları onay istemi olmadan çalıştırması için `hooks_auto_accept: true` ayarlar. Değerlendirici Hermes'in `{"decision":"block","reason"}` stdout sözleşmesini yayar (Hermes çıkış kodlarını yok sayar). **Sınırlamalar:** Hermes'in bir `Stop` olay sonu yoktur, bu nedenle `require-*-before-stop` yerleşikleri bunun için hiçbir zaman çalışmaz (uygulanamaz, kırık değil); `instruct` izin-not-ile-günlüğe-kaydedil'e degrades (ek bağlam kanalı yok); ve çıkış gizli redaksiyonu (`sanitize-*`) shell-hook sözleşmesi üzerinde araç çıkışını yeniden yazamaz. Hermes aynı zamanda çevrimdışı bir **denetim** kaynağıdır — pano, ağ geçidi oturumlarını doğrudan `~/.hermes/state.db`'den okur. - **`policies-config.json`** — failproofai'ye hangi politikaları değerlendireceğini ve hangi parametrelerle (tüm ajan CLI'ler arasında paylaşılan) söyler -Belirli bir ajanı hedeflemek için `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` geçin (boşlukla ayrılmış veya herhangi bir altküme için tekrarlanan): +Belirli bir ajanı hedeflemek için `--cli claude|codex|copilot|cursor|opencode|pi|hermes` geçin (boşlukla ayrılmış veya herhangi bir altküme için tekrarlanan): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -`--cli` atlandığında, `failproofai` hangi ajan CLI'lerin yüklendiğini algılar (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli` atlandığında, `failproofai` hangi ajan CLI'lerin yüklendiğini algılar (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Bir CLI algılandı** — sor olmadan o CLI'yi otomatik seçer. - **Etkileşimli bir terminalde birden fazla CLI algılandı** — `Detected (N)` bölümüne gruplandırılmış ok tuşu tek seçim istemi gösterir (algılanan tüm CLI'ler için bir `Tüm N tespit edileni yükle` toplu satırı + her algılanan CLI bireysel olarak) ve her desteklenen CLI'nin yüklenmemiş olan listesini gösteren `Yüklü olmayan (M) · hookları önceden kurma` bölümü (↑↓ taşımak, Enter seçmek, ^C bırakmak için). Kaldırma akışı yalnızca Algılanan bölümü gösterir. diff --git a/docs/tr/dashboard.mdx b/docs/tr/dashboard.mdx index 6b865387..fc29ce1c 100644 --- a/docs/tr/dashboard.mdx +++ b/docs/tr/dashboard.mdx @@ -24,11 +24,11 @@ Pano, dosya sisteminden doğrudan okur — Claude Code proje klasörlerinizi ve ### Projeler -Makinenizde bulunan tüm Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ ve Hermes projelerini listeler. Claude projeleri `~/.claude/projects/` adresinden keşfedilir (veya `CLAUDE_PROJECTS_PATH` tarafından ayarlanan yol); Codex projeleri `~/.codex/sessions///
/*.jsonl` altındaki her transkripti tarayarak ve her oturumun ilk kaydında kaydedilen `cwd` ye göre gruplandırılarak keşfedilir; Copilot CLI projeleri her `~/.copilot/session-state//workspace.yaml` tarayarak keşfedilir (`COPILOT_HOME` üzerinden yapılandırılabilir) ve `cwd` alanına göre gruplandırılır; Cursor Agent projeleri `~/.cursor/agent-sessions//` altındaki oturum başına meta verileri tarayarak keşfedilir (`CURSOR_HOME` üzerinden yapılandırılabilir, `conversations/` ve `sessions/` geri dönüş olarak problanır) `meta.json` / `session.json` / `workspace.yaml` içindeki `cwd` skaler değeri için; OpenCode projeleri `~/.local/share/opencode/opencode.db` adresindeki SQLite DB'sini `opencode db --format json` üzerinden sorgulayarak keşfedilir (`session` ve `project` tablolarını okuyuz ve `project_id` ye göre gruplandırırız); Pi projeleri `~/.pi/agent/sessions//_.jsonl` altındaki oturum başına JSONL transkriptlerini tarayarak keşfedilir (`PI_SESSIONS_DIR` üzerinden yapılandırılabilir) ve her oturumun ilk kaydından `cwd` yi çekeriz; Gemini CLI projeleri `~/.gemini/tmp//chats/session--.jsonl` tarayarak keşfedilir (`GEMINI_SESSIONS_DIR` üzerinden yapılandırılabilir) ve `.project_root` metin işaretçisinden kanonik cwd'yi kurtarırız; Hermes ağ geçidi oturumları doğrudan `~/.hermes/state.db` (`HERMES_DB_PATH` üzerinden yapılandırılabilir) adresindeki SQLite deposundan okunur ve `source` (Slack/Telegram/cli/cron — ağ geçidi oturumlarının cwd'si yoktur) tarafından `hermes-` projelerine gruplandırılır. Birden çok CLI tarafından kullanılan bir proje, tüm eşleşen rozetleriyle tek bir satır olarak işlenir. Belirli bir aracı CLI'ye göre filtrelemek için tablonun üstündeki **CLI** açılır menüsünü kullanın; URL seçiminizi `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` olarak korur. +Makinenizde bulunan tüm Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ ve Hermes projelerini listeler. Claude projeleri `~/.claude/projects/` adresinden keşfedilir (veya `CLAUDE_PROJECTS_PATH` tarafından ayarlanan yol); Codex projeleri `~/.codex/sessions///
/*.jsonl` altındaki her transkripti tarayarak ve her oturumun ilk kaydında kaydedilen `cwd` ye göre gruplandırılarak keşfedilir; Copilot CLI projeleri her `~/.copilot/session-state//workspace.yaml` tarayarak keşfedilir (`COPILOT_HOME` üzerinden yapılandırılabilir) ve `cwd` alanına göre gruplandırılır; Cursor Agent projeleri `~/.cursor/agent-sessions//` altındaki oturum başına meta verileri tarayarak keşfedilir (`CURSOR_HOME` üzerinden yapılandırılabilir, `conversations/` ve `sessions/` geri dönüş olarak problanır) `meta.json` / `session.json` / `workspace.yaml` içindeki `cwd` skaler değeri için; OpenCode projeleri `~/.local/share/opencode/opencode.db` adresindeki SQLite DB'sini `opencode db --format json` üzerinden sorgulayarak keşfedilir (`session` ve `project` tablolarını okuyuz ve `project_id` ye göre gruplandırırız); Pi projeleri `~/.pi/agent/sessions//_.jsonl` altındaki oturum başına JSONL transkriptlerini tarayarak keşfedilir (`PI_SESSIONS_DIR` üzerinden yapılandırılabilir) ve her oturumun ilk kaydından `cwd` yi çekeriz; Hermes ağ geçidi oturumları doğrudan `~/.hermes/state.db` (`HERMES_DB_PATH` üzerinden yapılandırılabilir) adresindeki SQLite deposundan okunur ve `source` (Slack/Telegram/cli/cron — ağ geçidi oturumlarının cwd'si yoktur) tarafından `hermes-` projelerine gruplandırılır. Birden çok CLI tarafından kullanılan bir proje, tüm eşleşen rozetleriyle tek bir satır olarak işlenir. Belirli bir aracı CLI'ye göre filtrelemek için tablonun üstündeki **CLI** açılır menüsünü kullanın; URL seçiminizi `?cli=claude|codex|copilot|cursor|opencode|pi|hermes` olarak korur. Her proje şunları gösterir: - Proje adı (klasör yolundan türetilmiş) -- CLI rozeti — `Claude Code` (turuncu), `OpenAI Codex` (mor), `GitHub Copilot` (mavi), `Cursor Agent` (zümrüt), `OpenCode` (kehribar), `Pi` (pembe), `Gemini CLI` (gökyüzü), ve/veya `Hermes` (çivit) +- CLI rozeti — `Claude Code` (turuncu), `OpenAI Codex` (mor), `GitHub Copilot` (mavi), `Cursor Agent` (zümrüt), `OpenCode` (kehribar), `Pi` (pembe), ve/veya `Hermes` (çivit) - En son oturum etkinliğinin tarihi Oturumlarını görmek için bir projeyi tıklayın. @@ -47,7 +47,7 @@ Oturum görüntüleyiciyi açmak için bir oturumu tıklayın. ### Oturum görüntüleyici -Oturum görüntüleyici, otonom aracılar için temel soruyu yanıtlar: aracı ne yaptı ve hız tuttu mu? Başlığın yanındaki CLI rozeti, oturumun Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI veya Hermes transkripti olup olmadığını gösterir. Bir oturumda gerçekleşen her şeyin bir zaman çizelgesini gösterir: +Oturum görüntüleyici, otonom aracılar için temel soruyu yanıtlar: aracı ne yaptı ve hız tuttu mu? Başlığın yanındaki CLI rozeti, oturumun Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi veya Hermes transkripti olup olmadığını gösterir. Bir oturumda gerçekleşen her şeyin bir zaman çizelgesini gösterir: - **İletiler** - Claude'un metin yanıtları ve kullanıcı istemleri - **Araç çağrıları** - Claude'un çağırdığı her araç, girişi ve çıktısıyla @@ -55,7 +55,7 @@ Oturum görüntüleyici, otonom aracılar için temel soruyu yanıtlar: aracı n Üstteki istatistik çubuğu oturum süresini, toplam araç çağrılarını ve kanca kararlarının bir özetini gösterir (allow / deny / instruct sayıları). -Oturumu dışa aktarmak için **İndirme Günlükleri** düğmesini tıklayın. Claude Code, Codex, Copilot, Cursor, Pi ve Gemini oturumları için orijinal disk üzerindeki JSONL transkriptini bayt-bayt alırsınız; OpenCode (oturumları diskte değil SQLite'de yaşayan) için temel `session` / `messages` / `parts` tablolarını yansıtan bir JSON belgesi alırsınız. +Oturumu dışa aktarmak için **İndirme Günlükleri** düğmesini tıklayın. Claude Code, Codex, Copilot, Cursor ve Pi oturumları için orijinal disk üzerindeki JSONL transkriptini bayt-bayt alırsınız; OpenCode (oturumları diskte değil SQLite'de yaşayan) için temel `session` / `messages` / `parts` tablolarını yansıtan bir JSON belgesi alırsınız. ### Denetim @@ -75,16 +75,16 @@ Politikaları yönetmek ve etkinliği gözden geçirmek için iki sekmeli bir sa - - Tek bir panelden hangi aracı CLI'lerin failproofai tarafından korunacağını çoklu seçim yapın — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI ve Hermes'in hepsinin yükleme durumu (`Active` / `Detected` / `Inactive`) olan bir satırı, kullanıcı kapsamı ayarları yolu ve marka renkli vurguyu vardır. İstediğiniz CLI'leri işaretleyin veya işareti kaldırın ve farkı bir adımda yüklemek/kaldırmak için `Apply changes` öğesine tıklayın. İkili PATH'de algılanan CLI'ler önceden işaretlenmiş. + - Tek bir panelden hangi aracı CLI'lerin failproofai tarafından korunacağını çoklu seçim yapın — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi ve Hermes'in hepsinin yükleme durumu (`Active` / `Detected` / `Inactive`) olan bir satırı, kullanıcı kapsamı ayarları yolu ve marka renkli vurguyu vardır. İstediğiniz CLI'leri işaretleyin veya işareti kaldırın ve farkı bir adımda yüklemek/kaldırmak için `Apply changes` öğesine tıklayın. İkili PATH'de algılanan CLI'ler önceden işaretlenmiş. - Tek tıklamayla bireysel politikaları açıp kapatın (`~/.failproofai/policies-config.json` adresine yazar — tüm yüklü CLI'ler arasında paylaşılır) - Parametrelerini yapılandırmak için bir politikayı genişletin (`policyParams` destekleyen politikalar için) - Özel politika dosyası yolunu ayarla - Tüm oturumlar arasında tetiklenen her kanca olayının tam sayfalı geçmişi - - Karar, olay türü, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), politika adı veya oturum ID'ye göre filtrele - - Her satır şunları gösterir: zaman damgası, politika adı, karar, CLI rozeti (turuncu = Claude Code, mor = OpenAI Codex, mavi = GitHub Copilot, zümrüt = Cursor Agent, kehribar = OpenCode, pembe = Pi, gökyüzü = Gemini CLI, çivit = Hermes), araç adı, oturum ID ve deny/instruct kararları için neden - - Transkripti açmak için bir oturum ID'sine tıklayın — görüntüleyici hangi CLI'nin kancayı tetiklediğini otomatik algılar (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) ve başlıkta eşleşen CLI rozetini işler + - Karar, olay türü, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), politika adı veya oturum ID'ye göre filtrele + - Her satır şunları gösterir: zaman damgası, politika adı, karar, CLI rozeti (turuncu = Claude Code, mor = OpenAI Codex, mavi = GitHub Copilot, zümrüt = Cursor Agent, kehribar = OpenCode, pembe = Pi, çivit = Hermes), araç adı, oturum ID ve deny/instruct kararları için neden + - Transkripti açmak için bir oturum ID'sine tıklayın — görüntüleyici hangi CLI'nin kancayı tetiklediğini otomatik algılar (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) ve başlıkta eşleşen CLI rozetini işler diff --git a/docs/tr/getting-started.mdx b/docs/tr/getting-started.mdx index 16429282..cfa11abf 100644 --- a/docs/tr/getting-started.mdx +++ b/docs/tr/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Bu, yüklü ajan CLI'lerinize hook girişleri yazar (Claude Code'un `~/.claude/settings.json`, OpenAI Codex'in `~/.codex/hooks.json`, GitHub Copilot CLI'nin `~/.copilot/hooks/failproofai.json`, Cursor Agent'ın `~/.cursor/hooks.json`, OpenCode'un `~/.config/opencode/plugins/failproofai.mjs` konumundaki oluşturulmuş plugin shim'i ve `~/.config/opencode/opencode.json` dosyasındaki `plugin` dizisinde bir kayıt girişi, Pi'nin `~/.pi/agent/settings.json`, Gemini CLI'nin `~/.gemini/settings.json` veya Hermes'in `~/.hermes/config.yaml` dosyası). Birden fazla varsa size sorulacak; `--cli claude codex copilot cursor opencode pi gemini hermes` (herhangi bir alt küme) geçerek sorguyu atlayabilirsiniz. + Bu, yüklü ajan CLI'lerinize hook girişleri yazar (Claude Code'un `~/.claude/settings.json`, OpenAI Codex'in `~/.codex/hooks.json`, GitHub Copilot CLI'nin `~/.copilot/hooks/failproofai.json`, Cursor Agent'ın `~/.cursor/hooks.json`, OpenCode'un `~/.config/opencode/plugins/failproofai.mjs` konumundaki oluşturulmuş plugin shim'i ve `~/.config/opencode/opencode.json` dosyasındaki `plugin` dizisinde bir kayıt girişi, Pi'nin `~/.pi/agent/settings.json` veya Hermes'in `~/.hermes/config.yaml` dosyası). Birden fazla varsa size sorulacak; `--cli claude codex copilot cursor opencode pi hermes` (herhangi bir alt küme) geçerek sorguyu atlayabilirsiniz. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ve Gemini CLI desteği **beta** aşamasındadır — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` veya `--cli gemini` ile kurun. Hermes (hermes-agent, bir Slack/Telegram ağ geçidi) `--cli hermes` ile kullanıcı kapsamında yüklenir ve **ayrıca** çevrimdışı bir denetim kaynağıdır. + GitHub Copilot CLI, Cursor Agent, OpenCode ve Pi desteği **beta** aşamasındadır — `--cli copilot`, `--cli cursor`, `--cli opencode` veya `--cli pi` ile kurun. Hermes (hermes-agent, bir Slack/Telegram ağ geçidi) `--cli hermes` ile kullanıcı kapsamında yüklenir ve **ayrıca** çevrimdışı bir denetim kaynağıdır. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/tr/introduction.mdx b/docs/tr/introduction.mdx index 526ec330..7d196194 100644 --- a/docs/tr/introduction.mdx +++ b/docs/tr/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI, AI ajanlarına döngüleri, gizli dizi sızıntılar [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI başarısızlık işleme**, **hata kurtarma** ve **LLM güvenilirliği** için hook'lar ve politikalar. AI ajanlarınızı **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** ve **Agents SDK** arasında güvenilir ve otonom halde tutun. +**AI başarısızlık işleme**, **hata kurtarma** ve **LLM güvenilirliği** için hook'lar ve politikalar. AI ajanlarınızı **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes** ve **Agents SDK** arasında güvenilir ve otonom halde tutun. AI ajanları tahmin edilebilir şekillerde başarısız olur. Yıkıcı komutlar çalıştırırlar, sırları sızıntıya uğratırlar, görevlerinden saparlar, döngülere takılırlar ya da doğrudan ana dala push yaparlar. Gözetimsiz bırakıldığında, küçük başarısızlıklar kesintilere, sızıntıya uğramış kimlik bilgilerine ve kayıp işlere dönüşür. diff --git a/docs/vi/built-in-policies.mdx b/docs/vi/built-in-policies.mdx index b7eb5873..a86d27e7 100644 --- a/docs/vi/built-in-policies.mdx +++ b/docs/vi/built-in-policies.mdx @@ -718,20 +718,19 @@ Thực thi Stop trông hơi khác nhau trên bảy CLI được hỗ trợ vì m | Codex | Cùng vòng lặp agent, ngay lập tức | Giống như Claude. | | GitHub Copilot CLI | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{decision:"block", reason}` retry của Copilot — đã xác minh theo kinh nghiệm đối với Copilot CLI 1.0.41). | | Cursor Agent | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{followup_message}` của Cursor — bị giới hạn ở `loop_limit`, mặc định 5 lần thử lại). | -| Gemini CLI | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{decision:"block", reason}` của Gemini trên `AfterAgent`). | | OpenCode | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng lệnh gọi SDK `client.session.prompt(...)` của OpenCode được định tuyến qua `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Lần tới người dùng** | **Pi dừng lại rõ ràng** khi cổng kích hoạt — vòng lặp agent của nó thoát và bạn quay lại dấu nhắc. Cổng sau đó kích hoạt lần tiếp theo bạn gửi dấu nhắc: failproofai thêm tiền tố `MANDATORY ACTION REQUIRED` vào lời nhắc hệ thống của lần đó, hướng dẫn LLM hoàn thành bước quy trình làm việc (commit, push, v.v.) trước khi làm bất cứ điều gì bạn yêu cầu. | -**Giới hạn Pi.** `AgentEndEvent` của Pi (tương đương thượng nguồn của hook `Stop` của Claude) không có loại Result — khi nó kích hoạt, vòng lặp agent của Pi đã thoát. Pi không thể bị buộc thử lại cùng một vòng lặp theo cách Claude / Copilot / Cursor / Gemini / OpenCode. failproofai thay đổi cổng sang sự kiện `before_agent_start` của Pi (được kích hoạt sau dấu nhắc người dùng tiếp theo) để kiểm tra quy trình làm việc vẫn thực thi, chỉ trên lần tới thay vì lần hiện tại. +**Giới hạn Pi.** `AgentEndEvent` của Pi (tương đương thượng nguồn của hook `Stop` của Claude) không có loại Result — khi nó kích hoạt, vòng lặp agent của Pi đã thoát. Pi không thể bị buộc thử lại cùng một vòng lặp theo cách Claude / Copilot / Cursor / OpenCode. failproofai thay đổi cổng sang sự kiện `before_agent_start` của Pi (được kích hoạt sau dấu nhắc người dùng tiếp theo) để kiểm tra quy trình làm việc vẫn thực thi, chỉ trên lần tới thay vì lần hiện tại. **Điều này có nghĩa gì trong thực tế:** - Sau khi Pi dừng lại, lý do từ chối được ghi vào bộ nhớ trong bằng id phiên Pi. Dấu nhắc rất tiếp theo bạn gửi trong cùng quy trình Pi lấy ra nó: LLM nhìn thấy chỉ thị `MANDATORY ACTION REQUIRED` ở đầu lời nhắc hệ thống của nó, commit (hoặc push / mở PR / chờ CI) và chỉ khi đó tiếp tục với yêu cầu của bạn. Lý do từ chối được ghi lại là một lần — sau khi lấy ra, cổng rõ ràng. -- Cổng bị ràng buộc bởi vòng đời quá trình Pi. Nếu bạn `Ctrl+C` Pi hoặc thoát giữa các lần, mục bộ nhớ trong được loại bỏ cùng với quá trình và cổng bị bỏ lỡ. Claude, Copilot, Cursor, Gemini và OpenCode có cùng ranh giới (giết agent và cổng bị bỏ lỡ) — Pi chỉ làm cho nó rõ ràng hơn vì agent rõ ràng thoát trước khi cổng kích hoạt. +- Cổng bị ràng buộc bởi vòng đời quá trình Pi. Nếu bạn `Ctrl+C` Pi hoặc thoát giữa các lần, mục bộ nhớ trong được loại bỏ cùng với quá trình và cổng bị bỏ lỡ. Claude, Copilot, Cursor và OpenCode có cùng ranh giới (giết agent và cổng bị bỏ lỡ) — Pi chỉ làm cho nó rõ ràng hơn vì agent rõ ràng thoát trước khi cổng kích hoạt. - Một từ chối đang chờ cũng bị xóa trên `session_shutdown` vì lý do gì đó (`new` / `resume` / `fork` / `quit`), vì vậy cổng cũ từ phiên trước không thể bị rò rỉ vào phiên mới được khởi động trong cùng quy trình Pi. -Nếu bạn cần thử lại cùng vòng lặp kiểu Claude, hãy chạy các chính sách `Stop` của bạn dưới bất kỳ sáu CLI được hỗ trợ khác. Chúng tôi đang theo dõi Pi thượng nguồn để có loại Result trong tương lai trên `AgentEndEvent` sẽ cho phép chúng tôi đóng khoảng cách này. +Nếu bạn cần thử lại cùng vòng lặp kiểu Claude, hãy chạy các chính sách `Stop` của bạn dưới bất kỳ năm CLI được hỗ trợ khác. Chúng tôi đang theo dõi Pi thượng nguồn để có loại Result trong tương lai trên `AgentEndEvent` sẽ cho phép chúng tôi đóng khoảng cách này. ### `require-commit-before-stop` diff --git a/docs/vi/cli/audit.mdx b/docs/vi/cli/audit.mdx index e7fcf00a..f93bed5d 100644 --- a/docs/vi/cli/audit.mdx +++ b/docs/vi/cli/audit.mdx @@ -47,7 +47,7 @@ failproofai Chạy `failproofai audit -h` (hoặc `--help`) để xem cách sử dụng. Công cụ kiểm toán chạy **hoàn toàn ngoại tuyến** — không cần tài khoản hay mạng — và dashboard tiếp tục hoạt động cho đến khi bạn dừng nó bằng `Ctrl+C`. -Dashboard quét các bản ghi agent CLI quá khứ trên máy này (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) và báo cáo tần suất agent làm những việc mà failproofai được xây dựng để ngăn chặn — kiểm tra biến môi trường, force push, tiền tố `cd ` dư thừa, vòng lặp sleep-polling, đọc lại tệp vừa chỉnh sửa, và nhiều hơn nữa. +Dashboard quét các bản ghi agent CLI quá khứ trên máy này (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) và báo cáo tần suất agent làm những việc mà failproofai được xây dựng để ngăn chặn — kiểm tra biến môi trường, force push, tiền tố `cd ` dư thừa, vòng lặp sleep-polling, đọc lại tệp vừa chỉnh sửa, và nhiều hơn nữa. Đối với mỗi bản ghi, mỗi sự kiện tool-use được phát lại thông qua 39 chính sách tích hợp **và** thông qua 8 detector chỉ dùng cho kiểm toán để phát hiện các mẫu chưa được bao phủ bởi các chính sách thời gian chạy. Các số được tổng hợp theo chính sách/detector trên tất cả các phiên. diff --git a/docs/vi/configuration.mdx b/docs/vi/configuration.mdx index d94dff4c..7b078039 100644 --- a/docs/vi/configuration.mdx +++ b/docs/vi/configuration.mdx @@ -196,13 +196,12 @@ Các lệnh `policies --install` và `policies --uninstall` ghi vào tệp cài - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex không có phạm vi `local` - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot không có phạm vi `local`. Các mục nhập hook sử dụng các trường lệnh `bash`/`powershell` được khóa bằng OS của Copilot với `timeoutSec`; tệp có dấu hiệu `version: 1` ở cấp cao nhất. Hỗ trợ Copilot CLI đang ở **beta** khi chúng tôi xác minh lược đồ bản ghi `events.jsonl` (không được tài liệu công khai chỉ định) so với các phiên làm việc thực tế hơn. - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor không có phạm vi `local`. Các mục nhập hook sử dụng dạng `{type, command, timeout}` tương tự Claude (không chia tách `bash`/`powershell`), nhưng được lưu trữ dưới các khóa sự kiện camelCase (`preToolUse`, `beforeSubmitPrompt`, …) trong một mảng phẳng theo [schemas hooks](https://cursor.com/docs/hooks) của Cursor; tệp có dấu hiệu `version: 1` ở cấp cao nhất. Trình xử lý chuẩn hóa camelCase → PascalCase qua `CURSOR_EVENT_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Hỗ trợ Cursor Agent đang ở **beta** khi chúng tôi xác minh định dạng transcript trên đĩa của Cursor (không được chỉ định trong tài liệu công khai) so với các cài đặt thực tế hơn. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode không có phạm vi `local`. Không giống như sáu CLI khác, OpenCode **không có hệ thống hook lệnh bên ngoài**: nó tải các plugin JS/TS in-process được đăng ký rõ ràng qua mảng `plugin: []` trong `opencode.json` (tự động phát hiện từ `.opencode/plugins/` **không** là cách các plugin tải trên opencode v1.14.33). Cài đặt thả một shim plugin nhỏ được tạo ra gọi đến nhị phân failproofai qua subprocess và dịch phản hồi JSON hình dạng Claude của nhị phân trở lại ngữ nghĩa plugin: `throw new Error()` cho tool-event deny (hủy lệnh gọi công cụ), `client.session.prompt(...)` cho instruct VÀ cho `Stop` / `SubagentStop` deny (gửi lý do từ chối dưới dạng thông báo người dùng tiếp theo — kênh thử lại buộc duy nhất vì `session.idle` chỉ là thông báo và ném từ nó là no-op), và no-op cho allow. Shim chuẩn hóa cả tên công cụ (chữ thường → PascalCase qua `OPENCODE_TOOL_MAP`) và khóa đối số đầu vào công cụ (camelCase → snake_case qua `OPENCODE_TOOL_INPUT_MAP` cho `Read` / `Write` / `Edit`, ví dụ: `filePath` → `file_path`, `oldString` → `old_string`) trước khi chuyển tiếp đến nhị phân, vì vậy các built-in kiểm tra đường dẫn như `block-read-outside-cwd`, `block-env-files` và `block-secrets-write` kích hoạt không thay đổi trên các lệnh gọi công cụ OpenCode. Các phiên tồn tại trong cơ sở dữ liệu SQLite của opencode tại `~/.local/share/opencode/opencode.db`; người xem phiên của bảng điều khiển đọc chúng qua `opencode db --format json` và `opencode export `. Hỗ trợ OpenCode đang ở **beta** khi chúng tôi xác minh hành vi trên các phiên bản và so với các phiên làm việc thực tế hơn. Xem [tài liệu plugins OpenCode](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode không có phạm vi `local`. Không giống như năm CLI khác, OpenCode **không có hệ thống hook lệnh bên ngoài**: nó tải các plugin JS/TS in-process được đăng ký rõ ràng qua mảng `plugin: []` trong `opencode.json` (tự động phát hiện từ `.opencode/plugins/` **không** là cách các plugin tải trên opencode v1.14.33). Cài đặt thả một shim plugin nhỏ được tạo ra gọi đến nhị phân failproofai qua subprocess và dịch phản hồi JSON hình dạng Claude của nhị phân trở lại ngữ nghĩa plugin: `throw new Error()` cho tool-event deny (hủy lệnh gọi công cụ), `client.session.prompt(...)` cho instruct VÀ cho `Stop` / `SubagentStop` deny (gửi lý do từ chối dưới dạng thông báo người dùng tiếp theo — kênh thử lại buộc duy nhất vì `session.idle` chỉ là thông báo và ném từ nó là no-op), và no-op cho allow. Shim chuẩn hóa cả tên công cụ (chữ thường → PascalCase qua `OPENCODE_TOOL_MAP`) và khóa đối số đầu vào công cụ (camelCase → snake_case qua `OPENCODE_TOOL_INPUT_MAP` cho `Read` / `Write` / `Edit`, ví dụ: `filePath` → `file_path`, `oldString` → `old_string`) trước khi chuyển tiếp đến nhị phân, vì vậy các built-in kiểm tra đường dẫn như `block-read-outside-cwd`, `block-env-files` và `block-secrets-write` kích hoạt không thay đổi trên các lệnh gọi công cụ OpenCode. Các phiên tồn tại trong cơ sở dữ liệu SQLite của opencode tại `~/.local/share/opencode/opencode.db`; người xem phiên của bảng điều khiển đọc chúng qua `opencode db --format json` và `opencode export `. Hỗ trợ OpenCode đang ở **beta** khi chúng tôi xác minh hành vi trên các phiên bản và so với các phiên làm việc thực tế hơn. Xem [tài liệu plugins OpenCode](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi không có phạm vi `local`. Pi tải các gói mở rộng TypeScript khi khởi động; tệp cài đặt là một mảng chuỗi phẳng `{"packages": ["./relative/path", …]}`. failproofai viết một mục nhập mảng package duy nhất trỏ vào thư mục `pi-extension/` được đóng gói của nó. Tiện ích mở rộng bên trong đăng ký các sự kiện `tool_call` / `user_bash` / `input` / `session_start` của Pi và shell ra `failproofai --hook --cli pi`; trình xử lý chuẩn hóa underscore_lower_snake_case → PascalCase qua `PI_EVENT_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Các đối số đầu vào công cụ cũng được chuẩn hóa qua `PI_TOOL_INPUT_MAP` (Read / Write / Edit của Pi cung cấp `path` thay vì `file_path`; ánh xạ khóa cấp cao nhất cho phép `block-env-files` và `block-secrets-write` kích hoạt — `block-read-outside-cwd` đã có fallback `path`). Hỗ trợ Pi đang ở **beta** khi Pi's extension API và layout nhật ký phiên ổn định. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini không có phạm vi `local` (nó ghi lại phạm vi `system` tại `/etc/gemini-cli/settings.json` mà failproofai không tiếp xúc). Các mục nhập hook sử dụng dạng `{type, command, timeout}` của Claude được bao bọc trong lược đồ matcher `{matcher, hooks: [...]}` của Gemini với `matcher: "*"` theo mặc định. Các sự kiện là PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); trình xử lý ánh xạ đến tên Claude canonical qua `GEMINI_EVENT_MAP`. Tên công cụ là snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — trình xử lý chuẩn hóa qua `GEMINI_TOOL_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Trình đánh giá chính sách phát hành hình dạng phẳng `{decision: "deny", reason}` của Gemini (ưu tiên theo Golden Rule exit-0 contract của Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` cho tiêm ngữ cảnh trên BeforeAgent / AfterTool / SessionStart, và `{decision: "block", reason}` trên AfterTool cho ngữ nghĩa thử lại buộc. Hỗ trợ Gemini CLI đang ở **beta** khi chúng tôi mở rộng phạm vi thế giới thực. Xem [tài liệu hooks Gemini CLI](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**phạm vi người dùng duy nhất** — Hermes không có cấu hình dự án/cục bộ). Hermes là một **cổng** Slack/Telegram, vì vậy một cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng (Slack/Telegram/cli/cron) **và** các subagent nội bộ. Các mục nhập hook là một cặp `{command, timeout}` (timeout tính bằng **giây**) dưới bản đồ `hooks:` được khóa bằng các sự kiện snake_case của Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); trình xử lý chuẩn hóa các sự kiện qua `HERMES_EVENT_MAP` và tên công cụ qua `HERMES_TOOL_MAP` vì vậy các chính sách built-in kích hoạt không thay đổi. Cấu hình được chỉnh sửa thông qua vòng quay YAML `Document` bảo tồn nhận xét vì vậy các cài đặt khác của nhà điều hành sống sót, và cài đặt đặt `hooks_auto_accept: true` vì vậy cổng headless (không TTY) chạy các hook mà không có lời nhắc đồng ý. Trình đánh giá phát hành hợp đồng stdout `{"decision":"block","reason"}` của Hermes (Hermes bỏ qua mã thoát). **Hạn chế:** Hermes không có sự kiện `Stop` kết thúc lượt, vì vậy các built-in `require-*-before-stop` không bao giờ kích hoạt cho nó (không áp dụng được, không bị hỏng); `instruct` suy giảm thành allow-with-logged-note (không có kênh ngữ cảnh bổ sung); và redaction bí mật đầu ra (`sanitize-*`) không thể viết lại đầu ra công cụ trên hợp đồng shell-hook. Hermes cũng là một nguồn **audit** **ngoại tuyến** — bảng điều khiển đọc các phiên cổng của nó trực tiếp từ `~/.hermes/state.db`. - **`policies-config.json`** — cho failproofai biết những chính sách nào cần đánh giá và với những tham số nào (chia sẻ trên tất cả các CLI agent) -Chuyển `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` để nhắm vào một agent cụ thể (cách nhau bằng dấu cách hoặc lặp lại cho bất kỳ tập con nào): +Chuyển `--cli claude|codex|copilot|cursor|opencode|pi|hermes` để nhắm vào một agent cụ thể (cách nhau bằng dấu cách hoặc lặp lại cho bất kỳ tập con nào): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -Khi `--cli` bị bỏ qua, `failproofai` phát hiện những agent CLI nào được cài đặt (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Khi `--cli` bị bỏ qua, `failproofai` phát hiện những agent CLI nào được cài đặt (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **Một CLI được phát hiện** — tự động chọn CLI đó mà không cần nhắc. - **Nhiều CLI được phát hiện** trong terminal tương tác — hiển thị lời nhắc lựa chọn đơn có mũi tên được nhóm thành phần Detected (N) (với hàng tổng hợp Cài đặt cho tất cả N detected + từng CLI được phát hiện riêng lẻ) và phần Not installed (M) · install hooks ahead of time liệt kê mỗi CLI được hỗ trợ không được phát hiện dưới dạng tùy chọn cài đặt trước (↑↓ để di chuyển, Enter để chọn, ^C để thoát). Dòng gỡ cài đặt chỉ hiển thị phần Detected. diff --git a/docs/vi/dashboard.mdx b/docs/vi/dashboard.mdx index 219cbd9b..3e1e0efd 100644 --- a/docs/vi/dashboard.mdx +++ b/docs/vi/dashboard.mdx @@ -25,11 +25,11 @@ Bảng điều khiển đọc trực tiếp từ hệ thống tệp - các thư ### Dự án -Liệt kê tất cả các dự án Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ và Hermes được tìm thấy trên máy của bạn. Các dự án Claude được phát hiện từ `~/.claude/projects/` (hoặc đường dẫn được đặt bởi `CLAUDE_PROJECTS_PATH`); các dự án Codex được phát hiện bằng cách quét mỗi bản ghi tạm dưới `~/.codex/sessions///
/*.jsonl` và nhóm theo `cwd` được ghi trong bản ghi đầu tiên của mỗi phiên; các dự án Copilot CLI được phát hiện bằng cách quét từng `~/.copilot/session-state//workspace.yaml` (có thể cấu hình qua `COPILOT_HOME`) và nhóm theo trường `cwd` của nó; các dự án Cursor Agent được phát hiện bằng cách quét siêu dữ liệu cho mỗi phiên dưới `~/.cursor/agent-sessions//` (có thể cấu hình qua `CURSOR_HOME`, với `conversations/` và `sessions/` được thử như giải pháp thay thế) cho một vô hướng `cwd` trong `meta.json` / `session.json` / `workspace.yaml`; các dự án OpenCode được phát hiện bằng cách truy vấn cơ sở dữ liệu SQLite của nó tại `~/.local/share/opencode/opencode.db` qua `opencode db --format json` (chúng tôi đọc các bảng `session` và `project` và nhóm theo `project_id`); các dự án Pi được phát hiện bằng cách quét bản ghi tạm JSONL cho mỗi phiên dưới `~/.pi/agent/sessions//_.jsonl` (có thể cấu hình qua `PI_SESSIONS_DIR`) và lấy `cwd` từ bản ghi đầu tiên của mỗi phiên; các dự án Gemini CLI được phát hiện bằng cách quét `~/.gemini/tmp//chats/session--.jsonl` (có thể cấu hình qua `GEMINI_SESSIONS_DIR`) và khôi phục cwd chính tắc từ dấu `.project_root` phía bên cạnh; các phiên cổng Hermes được đọc trực tiếp từ kho lưu trữ SQLite của nó tại `~/.hermes/state.db` (có thể cấu hình qua `HERMES_DB_PATH`) và được nhóm thành các dự án `hermes-` theo `source` (Slack/Telegram/cli/cron — các phiên cổng không có cwd). Một dự án đã được sử dụng bởi nhiều CLI được hiển thị dưới dạng một hàng duy nhất với tất cả các huy hiệu phù hợp. Sử dụng menu thả xuống **CLI** phía trên bảng để lọc theo một agent CLI cụ thể; URL lưu lựa chọn của bạn dưới dạng `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Liệt kê tất cả các dự án Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_ và Hermes được tìm thấy trên máy của bạn. Các dự án Claude được phát hiện từ `~/.claude/projects/` (hoặc đường dẫn được đặt bởi `CLAUDE_PROJECTS_PATH`); các dự án Codex được phát hiện bằng cách quét mỗi bản ghi tạm dưới `~/.codex/sessions///
/*.jsonl` và nhóm theo `cwd` được ghi trong bản ghi đầu tiên của mỗi phiên; các dự án Copilot CLI được phát hiện bằng cách quét từng `~/.copilot/session-state//workspace.yaml` (có thể cấu hình qua `COPILOT_HOME`) và nhóm theo trường `cwd` của nó; các dự án Cursor Agent được phát hiện bằng cách quét siêu dữ liệu cho mỗi phiên dưới `~/.cursor/agent-sessions//` (có thể cấu hình qua `CURSOR_HOME`, với `conversations/` và `sessions/` được thử như giải pháp thay thế) cho một vô hướng `cwd` trong `meta.json` / `session.json` / `workspace.yaml`; các dự án OpenCode được phát hiện bằng cách truy vấn cơ sở dữ liệu SQLite của nó tại `~/.local/share/opencode/opencode.db` qua `opencode db --format json` (chúng tôi đọc các bảng `session` và `project` và nhóm theo `project_id`); các dự án Pi được phát hiện bằng cách quét bản ghi tạm JSONL cho mỗi phiên dưới `~/.pi/agent/sessions//_.jsonl` (có thể cấu hình qua `PI_SESSIONS_DIR`) và lấy `cwd` từ bản ghi đầu tiên của mỗi phiên; các phiên cổng Hermes được đọc trực tiếp từ kho lưu trữ SQLite của nó tại `~/.hermes/state.db` (có thể cấu hình qua `HERMES_DB_PATH`) và được nhóm thành các dự án `hermes-` theo `source` (Slack/Telegram/cli/cron — các phiên cổng không có cwd). Một dự án đã được sử dụng bởi nhiều CLI được hiển thị dưới dạng một hàng duy nhất với tất cả các huy hiệu phù hợp. Sử dụng menu thả xuống **CLI** phía trên bảng để lọc theo một agent CLI cụ thể; URL lưu lựa chọn của bạn dưới dạng `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`. Mỗi dự án hiển thị: - Tên dự án (được lấy từ đường dẫn thư mục) -- Một huy hiệu CLI — `Claude Code` (cam), `OpenAI Codex` (tím), `GitHub Copilot` (xanh), `Cursor Agent` (lục bảo), `OpenCode` (hổ phách), `Pi` (hồng), `Gemini CLI` (xanh da trời) và/hoặc `Hermes` (chàm) +- Một huy hiệu CLI — `Claude Code` (cam), `OpenAI Codex` (tím), `GitHub Copilot` (xanh), `Cursor Agent` (lục bảo), `OpenCode` (hổ phách), `Pi` (hồng) và/hoặc `Hermes` (chàm) - Ngày của hoạt động phiên gần đây nhất Nhấp vào một dự án để xem các phiên của nó. @@ -48,7 +48,7 @@ Nhấp vào một phiên để mở trình xem phiên. ### Trình xem phiên -Trình xem phiên trả lời câu hỏi quan trọng cho các agent tự động: agent đã làm gì, và nó có duy trì được theo dõi không? Một huy hiệu CLI bên cạnh tiêu đề cho biết phiên là bản ghi Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI hay Hermes. Nó hiển thị một dòng thời gian của mọi thứ đã xảy ra trong một phiên: +Trình xem phiên trả lời câu hỏi quan trọng cho các agent tự động: agent đã làm gì, và nó có duy trì được theo dõi không? Một huy hiệu CLI bên cạnh tiêu đề cho biết phiên là bản ghi Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi hay Hermes. Nó hiển thị một dòng thời gian của mọi thứ đã xảy ra trong một phiên: - **Tin nhắn** - Các phản hồi văn bản và lời nhắc của người dùng từ Claude - **Cuộc gọi công cụ** - Mọi công cụ mà Claude gọi, cùng với đầu vào và đầu ra @@ -56,7 +56,7 @@ Trình xem phiên trả lời câu hỏi quan trọng cho các agent tự độn Thanh thống kê ở phía trên cùng hiển thị thời lượng phiên, tổng số lệnh gọi công cụ và tóm tắt các quyết định hook (số lượng allow / deny / instruct). -Nhấp vào nút **Download Logs** để xuất phiên. Đối với các phiên Claude Code, Codex, Copilot, Cursor, Pi và Gemini, bạn sẽ nhận được bản ghi JSONL trên đĩa nguyên gốc byte-for-byte; đối với OpenCode (các phiên của nó nằm trong SQLite, không phải trên đĩa), bạn sẽ nhận được một tài liệu JSON phản ánh các bảng `session` / `messages` / `parts` cơ bản. +Nhấp vào nút **Download Logs** để xuất phiên. Đối với các phiên Claude Code, Codex, Copilot, Cursor và Pi, bạn sẽ nhận được bản ghi JSONL trên đĩa nguyên gốc byte-for-byte; đối với OpenCode (các phiên của nó nằm trong SQLite, không phải trên đĩa), bạn sẽ nhận được một tài liệu JSON phản ánh các bảng `session` / `messages` / `parts` cơ bản. ### Kiểm toán @@ -76,16 +76,16 @@ Một trang hai tab để quản lý chính sách và xem xét hoạt động. - - Chọn nhiều agent CLI nào mà failproofai bảo vệ từ một bảng điều khiển duy nhất — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI và Hermes đều có một hàng với trạng thái cài đặt (`Active` / `Detected` / `Inactive`), đường dẫn cài đặt phạm vi người dùng và một điểm nhấn có thương hiệu. Chọn hoặc bỏ chọn các CLI bạn muốn và nhấp `Apply changes` để cài đặt/gỡ cài đặt chênh lệch trong một bước. Các CLI có tệp nhị phân được phát hiện trên PATH được tính sẵn. + - Chọn nhiều agent CLI nào mà failproofai bảo vệ từ một bảng điều khiển duy nhất — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi và Hermes đều có một hàng với trạng thái cài đặt (`Active` / `Detected` / `Inactive`), đường dẫn cài đặt phạm vi người dùng và một điểm nhấn có thương hiệu. Chọn hoặc bỏ chọn các CLI bạn muốn và nhấp `Apply changes` để cài đặt/gỡ cài đặt chênh lệch trong một bước. Các CLI có tệp nhị phân được phát hiện trên PATH được tính sẵn. - Bật hoặc tắt các chính sách riêng lẻ bằng một lần nhấp (ghi vào `~/.failproofai/policies-config.json` — được chia sẻ trên mọi CLI được cài đặt) - Mở rộng một chính sách để cấu hình các tham số của nó (đối với các chính sách hỗ trợ `policyParams`) - Đặt đường dẫn tệp chính sách tùy chỉnh - Lịch sử được phân trang đầy đủ của mọi sự kiện hook đã được kích hoạt trên tất cả các phiên - - Lọc theo quyết định, loại sự kiện, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), tên chính sách hoặc ID phiên - - Mỗi hàng hiển thị: dấu thời gian, tên chính sách, quyết định, huy hiệu CLI (cam = Claude Code, tím = OpenAI Codex, xanh = GitHub Copilot, lục bảo = Cursor Agent, hổ phách = OpenCode, hồng = Pi, xanh da trời = Gemini CLI, chàm = Hermes), tên công cụ, ID phiên và lý do cho các quyết định deny/instruct - - Nhấp vào ID phiên để mở bản ghi của nó — trình xem tự động phát hiện CLI nào được kích hoạt hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) và hiển thị huy hiệu CLI phù hợp trong tiêu đề + - Lọc theo quyết định, loại sự kiện, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes), tên chính sách hoặc ID phiên + - Mỗi hàng hiển thị: dấu thời gian, tên chính sách, quyết định, huy hiệu CLI (cam = Claude Code, tím = OpenAI Codex, xanh = GitHub Copilot, lục bảo = Cursor Agent, hổ phách = OpenCode, hồng = Pi, chàm = Hermes), tên công cụ, ID phiên và lý do cho các quyết định deny/instruct + - Nhấp vào ID phiên để mở bản ghi của nó — trình xem tự động phát hiện CLI nào được kích hoạt hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`) và hiển thị huy hiệu CLI phù hợp trong tiêu đề diff --git a/docs/vi/getting-started.mdx b/docs/vi/getting-started.mdx index f81b0633..5800980a 100644 --- a/docs/vi/getting-started.mdx +++ b/docs/vi/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - Lệnh này ghi các hook entries vào CLI agents đã cài đặt của bạn (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, or Hermes's `~/.hermes/config.yaml`). Khi có nhiều hơn một cái có mặt, bạn sẽ được nhắc; truyền `--cli claude codex copilot cursor opencode pi gemini hermes` (bất kỳ tập hợp con nào) để bỏ qua lời nhắc. + Lệnh này ghi các hook entries vào CLI agents đã cài đặt của bạn (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, or Hermes's `~/.hermes/config.yaml`). Khi có nhiều hơn một cái có mặt, bạn sẽ được nhắc; truyền `--cli claude codex copilot cursor opencode pi hermes` (bất kỳ tập hợp con nào) để bỏ qua lời nhắc. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, và Gemini CLI support là **beta** — cài đặt với `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, hoặc `--cli gemini`. Hermes (hermes-agent, một gateway Slack/Telegram) cài đặt user-scope với `--cli hermes` và là **cũng** một nguồn audit offline. + GitHub Copilot CLI, Cursor Agent, OpenCode, và Pi support là **beta** — cài đặt với `--cli copilot`, `--cli cursor`, `--cli opencode`, hoặc `--cli pi`. Hermes (hermes-agent, một gateway Slack/Telegram) cài đặt user-scope với `--cli hermes` và là **cũng** một nguồn audit offline. ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/vi/introduction.mdx b/docs/vi/introduction.mdx index daaf6270..cd0d7efe 100644 --- a/docs/vi/introduction.mdx +++ b/docs/vi/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI cung cấp 39 chính sách xử lý lỗi tích hợp [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks và chính sách cho **xử lý lỗi AI**, **phục hồi lỗi**, và **độ tin cậy LLM**. Giữ cho các AI agents của bạn luôn đáng tin cậy và hoạt động tự trị trên **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, và **Agents SDK**. +Hooks và chính sách cho **xử lý lỗi AI**, **phục hồi lỗi**, và **độ tin cậy LLM**. Giữ cho các AI agents của bạn luôn đáng tin cậy và hoạt động tự trị trên **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, và **Agents SDK**. Các AI agents thất bại theo những cách có thể dự đoán được. Chúng chạy các lệnh tàn phá, rò rỉ bí mật, lạc khỏi nhiệm vụ, mắc kẹt trong các vòng lặp, hoặc push trực tiếp lên main. Nếu không được giám sát, những lỗi nhỏ sẽ dẫn đến sự cố toàn hệ thống, rò rỉ thông tin xác thực, và mất công việc. diff --git a/docs/zh/built-in-policies.mdx b/docs/zh/built-in-policies.mdx index 8e2bd6da..8633a07b 100644 --- a/docs/zh/built-in-policies.mdx +++ b/docs/zh/built-in-policies.mdx @@ -704,7 +704,7 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### 各 CLI 的 Stop 语义 -由于七种受支持的 CLI 各自暴露不同的"Agent 完成"Hook 合约,Stop 强制执行在各 CLI 上的表现略有不同。**结果**是相同的——Agent 在工作流门控未通过时无法停止——但**机制**有所差异。下表作出了总结;只有 Pi 存在一个值得您在启用 `require-*-before-stop` 策略前了解的用户可见差异。 +由于六种受支持的 CLI 各自暴露不同的"Agent 完成"Hook 合约,Stop 强制执行在各 CLI 上的表现略有不同。**结果**是相同的——Agent 在工作流门控未通过时无法停止——但**机制**有所差异。下表作出了总结;只有 Pi 存在一个值得您在启用 `require-*-before-stop` 策略前了解的用户可见差异。 | CLI | 门控触发时机 | 您看到的效果 | |---|---|---| @@ -712,20 +712,19 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 | Codex | 同一 Agent 循环,立即触发 | 与 Claude 相同。 | | GitHub Copilot CLI | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Copilot 的 `{decision:"block", reason}` 重试通道——已针对 Copilot CLI 1.0.41 实证验证)。 | | Cursor Agent | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Cursor 的 `{followup_message}` 通道——上限为 `loop_limit`,默认 5 次重试)。 | -| Gemini CLI | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Gemini 的 `{decision:"block", reason}` 通道,位于 `AfterAgent`)。 | | OpenCode | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 OpenCode 的 `client.session.prompt(...)` SDK 调用,通过 `hookSpecificOutput.additionalContext` 路由)。 | | **Pi (pi-coding-agent)** | **下一个用户轮次** | **Pi 会明显停止**——当门控触发时,其 Agent 循环退出,控制权回到提示符。下次您提交提示时门控才会触发:failproofai 会在该轮次的系统提示开头附加一条 `MANDATORY ACTION REQUIRED` 指令,要求 LLM 在执行您请求的操作之前先完成工作流步骤(提交、推送等)。 | -**Pi 的限制。** Pi 的 `AgentEndEvent`(上游等效于 Claude 的 `Stop` Hook)没有 Result 类型——当它触发时,Pi 的 Agent 循环已经退出。Pi 无法像 Claude / Copilot / Cursor / Gemini / OpenCode 那样被强制重试同一循环。failproofai 将门控转移到 Pi 的 `before_agent_start` 事件(在下一个用户提示后触发),这样工作流检查依然会被执行,只是在下一轮而非当前轮次。 +**Pi 的限制。** Pi 的 `AgentEndEvent`(上游等效于 Claude 的 `Stop` Hook)没有 Result 类型——当它触发时,Pi 的 Agent 循环已经退出。Pi 无法像 Claude / Copilot / Cursor / OpenCode 那样被强制重试同一循环。failproofai 将门控转移到 Pi 的 `before_agent_start` 事件(在下一个用户提示后触发),这样工作流检查依然会被执行,只是在下一轮而非当前轮次。 **实际影响:** - Pi 停止后,拒绝原因会以 Pi 会话 ID 为键存储在内存中。您在同一 Pi 进程中提交的下一个提示会消费它:LLM 在系统提示顶部看到 `MANDATORY ACTION REQUIRED` 指令,先完成提交(或推送/开 PR/等待 CI),然后才继续您的请求。该拒绝原因是一次性的——消费后门控即清除。 -- 门控的生命周期受 Pi 进程生命周期限制。如果您在两次轮次之间 `Ctrl+C` 或退出 Pi,内存中的条目会随进程一起丢失,门控也就错过了。Claude、Copilot、Cursor、Gemini 和 OpenCode 有相同的限制(杀掉 Agent 则门控错过)——只是 Pi 更为明显,因为 Agent 在门控触发之前就已可见地退出了。 +- 门控的生命周期受 Pi 进程生命周期限制。如果您在两次轮次之间 `Ctrl+C` 或退出 Pi,内存中的条目会随进程一起丢失,门控也就错过了。Claude、Copilot、Cursor 和 OpenCode 有相同的限制(杀掉 Agent 则门控错过)——只是 Pi 更为明显,因为 Agent 在门控触发之前就已可见地退出了。 - 待处理的拒绝在任何原因导致的 `session_shutdown` 时也会被清除(`new` / `resume` / `fork` / `quit`),因此来自之前会话的过期门控不会泄漏到在同一 Pi 进程中启动的新会话中。 -如果您需要类似 Claude 的同循环重试,请在其他六种受支持的 CLI 下运行您的 `Stop` 策略。我们正在跟踪 Pi 上游,等待 `AgentEndEvent` 上未来的 Result 类型以弥补这一差距。 +如果您需要类似 Claude 的同循环重试,请在其他五种受支持的 CLI 下运行您的 `Stop` 策略。我们正在跟踪 Pi 上游,等待 `AgentEndEvent` 上未来的 Result 类型以弥补这一差距。 ### `require-commit-before-stop` diff --git a/docs/zh/cli/audit.mdx b/docs/zh/cli/audit.mdx index d6d90c87..59abec2e 100644 --- a/docs/zh/cli/audit.mdx +++ b/docs/zh/cli/audit.mdx @@ -48,7 +48,7 @@ failproofai 运行 `failproofai audit -h`(或 `--help`)查看使用说明。审计**完全离线**运行——无需账号或网络——仪表板会持续运行,直到您按 `Ctrl+C` 停止。 -仪表板会扫描本机上过去的智能体 CLI 记录(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi、Gemini),并报告智能体执行了哪些 failproofai 旨在阻止的操作——环境变量检查、强制推送、冗余的 `cd ` 前缀、轮询 sleep 循环、重复读取刚编辑的文件等。 +仪表板会扫描本机上过去的智能体 CLI 记录(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi),并报告智能体执行了哪些 failproofai 旨在阻止的操作——环境变量检查、强制推送、冗余的 `cd ` 前缀、轮询 sleep 循环、重复读取刚编辑的文件等。 对于每条记录,每个工具调用事件都会通过 39 条内置策略以及 8 个仅限审计的检测器进行回放——这些检测器可识别运行时策略尚未覆盖的模式。计数按策略/检测器维度在所有会话中汇总。 diff --git a/docs/zh/configuration.mdx b/docs/zh/configuration.mdx index 21fbaf5f..0202acdc 100644 --- a/docs/zh/configuration.mdx +++ b/docs/zh/configuration.mdx @@ -196,13 +196,12 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global - **OpenAI Codex**:`~/.codex/hooks.json`(用户级)、`/.codex/hooks.json`(项目级)——Codex 没有 `local` 作用域 - **GitHub Copilot CLI _(beta)_**:`~/.copilot/hooks/failproofai.json`(用户级)、`/.github/hooks/failproofai.json`(项目级)——Copilot 没有 `local` 作用域。Hook 条目使用 Copilot 基于操作系统的 `bash`/`powershell` 命令字段,并带有 `timeoutSec`;文件顶层包含 `version: 1` 标记。Copilot CLI 支持目前为 **beta** 版本,我们正在针对更多实际会话验证 `events.jsonl` 记录模式(公开文档中未作说明)。 - **Cursor Agent _(beta)_**:`~/.cursor/hooks.json`(用户级)、`/.cursor/hooks.json`(项目级)——Cursor 没有 `local` 作用域。Hook 条目使用 Claude 风格的 `{type, command, timeout}` 格式(无 `bash`/`powershell` 拆分),但按照 Cursor 的 [hooks schema](https://cursor.com/docs/hooks) 以驼峰式事件键(`preToolUse`、`beforeSubmitPrompt` 等)存储在扁平数组中;文件顶层包含 `version: 1` 标记。处理器通过 `CURSOR_EVENT_MAP` 将驼峰式键规范化为帕斯卡式,使现有内置策略能够正常触发。Cursor Agent 支持目前为 **beta** 版本,我们正在针对更多实际安装验证 Cursor 的磁盘上转录格式(公开文档未作说明)。 - - **OpenCode _(beta)_**:`~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(用户级)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(项目级)——OpenCode 没有 `local` 作用域。与其他六种 CLI 不同,OpenCode **没有外部命令 hook 系统**:它通过 `opencode.json` 的 `plugin: []` 数组显式注册来加载进程内 JS/TS 插件(自动发现 `.opencode/plugins/` 目录**不是** opencode v1.14.33 插件的加载方式)。安装时会生成一个小型插件 shim,以子进程方式调用 failproofai 二进制文件,并将二进制文件的 Claude 风格 JSON 响应转换回插件语义:工具事件拒绝时 `throw new Error()`(取消工具调用);instruct 以及 `Stop` / `SubagentStop` 拒绝时调用 `client.session.prompt(...)`(将拒绝原因作为下一条用户消息提交——这是唯一的强制重试通道,因为 `session.idle` 仅用于通知,从中抛出异常无效);allow 时不执行任何操作。该 shim 在转发给二进制文件前会规范化工具名称(小写 → 帕斯卡式,通过 `OPENCODE_TOOL_MAP`)和工具输入参数键(驼峰式 → 下划线式,通过 `OPENCODE_TOOL_INPUT_MAP` 适用于 `Read` / `Write` / `Edit`,例如 `filePath` → `file_path`、`oldString` → `old_string`),从而使 `block-read-outside-cwd`、`block-env-files` 和 `block-secrets-write` 等路径检查内置策略在 OpenCode 工具调用中正常触发。会话存储在 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库中;仪表盘的会话查看器通过 `opencode db --format json` 和 `opencode export ` 读取它们。OpenCode 支持目前为 **beta** 版本,我们正在跨版本和更多实际会话中验证其行为。详见 [OpenCode plugins 文档](https://opencode.ai/docs/plugins/)。 + - **OpenCode _(beta)_**:`~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(用户级)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(项目级)——OpenCode 没有 `local` 作用域。与其他五种 CLI 不同,OpenCode **没有外部命令 hook 系统**:它通过 `opencode.json` 的 `plugin: []` 数组显式注册来加载进程内 JS/TS 插件(自动发现 `.opencode/plugins/` 目录**不是** opencode v1.14.33 插件的加载方式)。安装时会生成一个小型插件 shim,以子进程方式调用 failproofai 二进制文件,并将二进制文件的 Claude 风格 JSON 响应转换回插件语义:工具事件拒绝时 `throw new Error()`(取消工具调用);instruct 以及 `Stop` / `SubagentStop` 拒绝时调用 `client.session.prompt(...)`(将拒绝原因作为下一条用户消息提交——这是唯一的强制重试通道,因为 `session.idle` 仅用于通知,从中抛出异常无效);allow 时不执行任何操作。该 shim 在转发给二进制文件前会规范化工具名称(小写 → 帕斯卡式,通过 `OPENCODE_TOOL_MAP`)和工具输入参数键(驼峰式 → 下划线式,通过 `OPENCODE_TOOL_INPUT_MAP` 适用于 `Read` / `Write` / `Edit`,例如 `filePath` → `file_path`、`oldString` → `old_string`),从而使 `block-read-outside-cwd`、`block-env-files` 和 `block-secrets-write` 等路径检查内置策略在 OpenCode 工具调用中正常触发。会话存储在 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库中;仪表盘的会话查看器通过 `opencode db --format json` 和 `opencode export ` 读取它们。OpenCode 支持目前为 **beta** 版本,我们正在跨版本和更多实际会话中验证其行为。详见 [OpenCode plugins 文档](https://opencode.ai/docs/plugins/)。 - **Pi _(beta)_**:`~/.pi/agent/settings.json`(用户级)、`/.pi/settings.json`(项目级)——Pi 没有 `local` 作用域。Pi 在启动时加载 TypeScript 扩展包;设置文件是一个扁平字符串数组 `{"packages": ["./relative/path", …]}`。failproofai 在 packages 数组中写入一个指向其捆绑的 `pi-extension/` 目录的条目。该扩展内部订阅 Pi 的 `tool_call` / `user_bash` / `input` / `session_start` 事件,并调用 `failproofai --hook --cli pi`;处理器通过 `PI_EVENT_MAP` 将下划线小写蛇形命名规范化为帕斯卡式,使现有内置策略正常触发。工具输入参数也通过 `PI_TOOL_INPUT_MAP` 规范化(Pi 的 Read / Write / Edit 使用 `path` 而非 `file_path`;映射顶层键后 `block-env-files` 和 `block-secrets-write` 可正常触发——`block-read-outside-cwd` 本身已有 `path` 的回退逻辑)。Pi 支持目前为 **beta** 版本,有待 Pi 的扩展 API 和会话日志格式稳定。 - - **Gemini CLI _(beta)_**:`~/.gemini/settings.json`(用户级)、`/.gemini/settings.json`(项目级)——Gemini 没有 `local` 作用域(其文档记录了 `/etc/gemini-cli/settings.json` 的 `system` 作用域,failproofai 未对外暴露该作用域)。Hook 条目使用 Claude 的 `{type, command, timeout}` 格式,包裹在 Gemini 的 `{matcher, hooks: [...]}` 匹配器模式中,默认 `matcher: "*"`。事件采用帕斯卡式(`SessionStart`、`BeforeAgent`、`AfterAgent`、`BeforeModel`、`AfterModel`、`BeforeToolSelection`、`BeforeTool`、`AfterTool`、`PreCompress`、`Notification`、`SessionEnd`);处理器通过 `GEMINI_EVENT_MAP` 映射到 Claude 规范名称。工具名称采用蛇形命名(`run_shell_command`、`read_file`、`write_file`、`replace` 等)——处理器通过 `GEMINI_TOOL_MAP` 规范化,使现有内置策略正常触发。策略评估器输出 Gemini 的扁平 `{decision: "deny", reason}` 格式(符合 Gemini 的"黄金规则"exit-0 约定),在 BeforeAgent / AfterTool / SessionStart 时输出 `{hookSpecificOutput: {hookEventName, additionalContext}}` 进行上下文注入,在 AfterAgent 时输出 `{decision: "block", reason}` 实现强制重试语义。Gemini CLI 支持目前为 **beta** 版本,我们正在扩大实际场景覆盖范围。详见 [Gemini CLI hooks 文档](https://geminicli.com/docs/hooks/)。 - **Hermes (hermes-agent)**:`~/.hermes/config.yaml`(**仅用户作用域**——Hermes 没有项目/本地配置)。Hermes 是一个 Slack/Telegram **网关**,因此一次安装即可拦截来自所有平台(Slack/Telegram/cli/cron)**以及**内部子代理的工具调用。Hook 条目是 `hooks:` 映射下的 `{command, timeout}` 对(timeout 单位为**秒**),以 Hermes 的蛇形命名事件为键(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`);处理器通过 `HERMES_EVENT_MAP` 规范化事件,通过 `HERMES_TOOL_MAP` 规范化工具名称,使内置策略正常触发。配置通过保留注释的 YAML `Document` 往返编辑,以确保操作者的其他设置不受影响;安装时将 `hooks_auto_accept: true` 设置为 true,以便无头网关(无 TTY)在无需确认提示的情况下运行 hook。评估器输出 Hermes 的 `{"decision":"block","reason"}` stdout 约定(Hermes 忽略退出码)。**限制:** Hermes 没有会话结束 `Stop` 事件,因此 `require-*-before-stop` 内置策略永远不会为其触发(不适用,并非故障);`instruct` 降级为允许并记录日志(无额外上下文通道);输出密钥清理(`sanitize-*`)无法通过 shell hook 约定重写工具输出。Hermes **同时**也是一个离线**审计**数据源——仪表盘直接从 `~/.hermes/state.db` 读取其网关会话。 - **`policies-config.json`** — 告知 failproofai 评估哪些策略及其参数(在所有代理 CLI 之间共享) -通过 `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` 指定目标代理(可用空格分隔或重复指定多个): +通过 `--cli claude|codex|copilot|cursor|opencode|pi|hermes` 指定目标代理(可用空格分隔或重复指定多个): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +209,11 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli claude codex copilot cursor opencode pi ``` -省略 `--cli` 时,`failproofai` 会自动检测已安装的代理 CLI(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +省略 `--cli` 时,`failproofai` 会自动检测已安装的代理 CLI(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes`): - **检测到一个 CLI** — 自动选择该 CLI,无需提示。 - **在交互式终端中检测到多个 CLI** — 显示方向键单选菜单,分为 `Detected (N)` 区域(包含一个"为所有 N 个已检测到的 CLI 安装"的聚合行及各个已检测 CLI)和 `Not installed (M) · install hooks ahead of time` 区域(列出所有未检测到的受支持 CLI 作为提前安装选项)(↑↓ 移动,回车选择,^C 退出)。卸载流程仅显示 Detected 区域。 diff --git a/docs/zh/dashboard.mdx b/docs/zh/dashboard.mdx index 721b39e2..d28f794b 100644 --- a/docs/zh/dashboard.mdx +++ b/docs/zh/dashboard.mdx @@ -24,11 +24,11 @@ failproofai ### 项目 -列出在你的机器上发现的所有 Claude Code、OpenAI Codex、GitHub Copilot CLI _(beta)_、Cursor Agent _(beta)_、OpenCode _(beta)_、Pi _(beta)_、Gemini CLI _(beta)_ 和 Hermes 项目。Claude 项目从 `~/.claude/projects/`(或由 `CLAUDE_PROJECTS_PATH` 设置的路径)中发现;Codex 项目通过扫描 `~/.codex/sessions///
/*.jsonl` 下的所有记录,并按每个会话第一条记录中的 `cwd` 字段分组发现;Copilot CLI 项目通过扫描 `~/.copilot/session-state//workspace.yaml`(可通过 `COPILOT_HOME` 配置),并按其 `cwd` 字段分组发现;Cursor Agent 项目通过扫描 `~/.cursor/agent-sessions//`(可通过 `CURSOR_HOME` 配置,并以 `conversations/` 和 `sessions/` 作为备选路径)下的逐会话元数据,从 `meta.json` / `session.json` / `workspace.yaml` 中的 `cwd` 标量发现;OpenCode 项目通过 `opencode db --format json` 查询位于 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库发现(读取 `session` 和 `project` 表并按 `project_id` 分组);Pi 项目通过扫描 `~/.pi/agent/sessions//_.jsonl`(可通过 `PI_SESSIONS_DIR` 配置)下的逐会话 JSONL 记录,并从每个会话的第一条记录中提取 `cwd` 发现;Gemini CLI 项目通过扫描 `~/.gemini/tmp//chats/session--.jsonl`(可通过 `GEMINI_SESSIONS_DIR` 配置),并从同级 `.project_root` 文本标记中恢复规范化 cwd 发现;Hermes 网关会话直接从 `~/.hermes/state.db`(可通过 `HERMES_DB_PATH` 配置)的 SQLite 存储中读取,并按 `source`(Slack/Telegram/cli/cron——网关会话没有 cwd)分组为 `hermes-` 项目。被多个 CLI 使用的项目在同一行显示,并附上所有匹配的徽章。使用表格上方的 **CLI** 下拉菜单按特定 Agent CLI 筛选;URL 会将你的选择保存为 `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`。 +列出在你的机器上发现的所有 Claude Code、OpenAI Codex、GitHub Copilot CLI _(beta)_、Cursor Agent _(beta)_、OpenCode _(beta)_、Pi _(beta)_ 和 Hermes 项目。Claude 项目从 `~/.claude/projects/`(或由 `CLAUDE_PROJECTS_PATH` 设置的路径)中发现;Codex 项目通过扫描 `~/.codex/sessions///
/*.jsonl` 下的所有记录,并按每个会话第一条记录中的 `cwd` 字段分组发现;Copilot CLI 项目通过扫描 `~/.copilot/session-state//workspace.yaml`(可通过 `COPILOT_HOME` 配置),并按其 `cwd` 字段分组发现;Cursor Agent 项目通过扫描 `~/.cursor/agent-sessions//`(可通过 `CURSOR_HOME` 配置,并以 `conversations/` 和 `sessions/` 作为备选路径)下的逐会话元数据,从 `meta.json` / `session.json` / `workspace.yaml` 中的 `cwd` 标量发现;OpenCode 项目通过 `opencode db --format json` 查询位于 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库发现(读取 `session` 和 `project` 表并按 `project_id` 分组);Pi 项目通过扫描 `~/.pi/agent/sessions//_.jsonl`(可通过 `PI_SESSIONS_DIR` 配置)下的逐会话 JSONL 记录,并从每个会话的第一条记录中提取 `cwd` 发现;Hermes 网关会话直接从 `~/.hermes/state.db`(可通过 `HERMES_DB_PATH` 配置)的 SQLite 存储中读取,并按 `source`(Slack/Telegram/cli/cron——网关会话没有 cwd)分组为 `hermes-` 项目。被多个 CLI 使用的项目在同一行显示,并附上所有匹配的徽章。使用表格上方的 **CLI** 下拉菜单按特定 Agent CLI 筛选;URL 会将你的选择保存为 `?cli=claude|codex|copilot|cursor|opencode|pi|hermes`。 每个项目显示: - 项目名称(从文件夹路径派生) -- CLI 徽章——`Claude Code`(橙色)、`OpenAI Codex`(紫色)、`GitHub Copilot`(蓝色)、`Cursor Agent`(翠绿色)、`OpenCode`(琥珀色)、`Pi`(粉色)、`Gemini CLI`(天蓝色)和/或 `Hermes`(靛蓝色) +- CLI 徽章——`Claude Code`(橙色)、`OpenAI Codex`(紫色)、`GitHub Copilot`(蓝色)、`Cursor Agent`(翠绿色)、`OpenCode`(琥珀色)、`Pi`(粉色)和/或 `Hermes`(靛蓝色) - 最近一次会话活动的日期 点击项目可查看其会话列表。 @@ -47,7 +47,7 @@ failproofai ### 会话查看器 -会话查看器回答了自主 Agent 的核心问题:Agent 做了什么,是否保持在正轨上?页眉旁的 CLI 徽章指示该会话是 Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI 还是 Hermes 的记录。它以时间线形式展示会话中发生的所有事件: +会话查看器回答了自主 Agent 的核心问题:Agent 做了什么,是否保持在正轨上?页眉旁的 CLI 徽章指示该会话是 Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi 还是 Hermes 的记录。它以时间线形式展示会话中发生的所有事件: - **消息** - Claude 的文本回复和用户提示 - **工具调用** - Claude 调用的每个工具,包含其输入和输出 @@ -55,7 +55,7 @@ failproofai 顶部的统计栏显示会话时长、工具调用总数,以及 Hook 决策摘要(allow / deny / instruct 计数)。 -点击**下载日志**按钮可导出会话。对于 Claude Code、Codex、Copilot、Cursor、Pi 和 Gemini 会话,你将获得原始的磁盘 JSONL 记录文件(逐字节原样);对于 OpenCode(其会话存储在 SQLite 而非磁盘上),你将获得一个 JSON 文档,镜像底层的 `session` / `messages` / `parts` 表。 +点击**下载日志**按钮可导出会话。对于 Claude Code、Codex、Copilot、Cursor 和 Pi 会话,你将获得原始的磁盘 JSONL 记录文件(逐字节原样);对于 OpenCode(其会话存储在 SQLite 而非磁盘上),你将获得一个 JSON 文档,镜像底层的 `session` / `messages` / `parts` 表。 ### 审计 @@ -75,16 +75,16 @@ failproofai - - 在单一面板中多选 failproofai 保护哪些 Agent CLI——Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、Gemini CLI 和 Hermes 各有一行,显示安装状态(`Active` / `Detected` / `Inactive`)、用户范围设置路径,以及品牌色强调。勾选或取消勾选你想要的 CLI,点击 `Apply changes` 一步完成安装/卸载差异。已在 PATH 中检测到二进制文件的 CLI 会被预先勾选。 + - 在单一面板中多选 failproofai 保护哪些 Agent CLI——Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi 和 Hermes 各有一行,显示安装状态(`Active` / `Detected` / `Inactive`)、用户范围设置路径,以及品牌色强调。勾选或取消勾选你想要的 CLI,点击 `Apply changes` 一步完成安装/卸载差异。已在 PATH 中检测到二进制文件的 CLI 会被预先勾选。 - 一键开启或关闭单个策略(写入 `~/.failproofai/policies-config.json`——所有已安装的 CLI 共享) - 展开策略以配置其参数(适用于支持 `policyParams` 的策略) - 设置自定义策略文件路径 - 所有会话中触发的每个 Hook 事件的完整分页历史记录 - - 按决策、事件类型、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes)、策略名称或会话 ID 筛选 - - 每行显示:时间戳、策略名称、决策、CLI 徽章(橙色 = Claude Code,紫色 = OpenAI Codex,蓝色 = GitHub Copilot,翠绿色 = Cursor Agent,琥珀色 = OpenCode,粉色 = Pi,天蓝色 = Gemini CLI,靛蓝色 = Hermes)、工具名称、会话 ID,以及 deny/instruct 决策的原因 - - 点击会话 ID 可打开其记录——查看器自动检测触发 Hook 的 CLI(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Gemini CLI `~/.gemini/tmp//chats/.jsonl`、Hermes `~/.hermes/state.db`),并在页眉中渲染对应的 CLI 徽章 + - 按决策、事件类型、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes)、策略名称或会话 ID 筛选 + - 每行显示:时间戳、策略名称、决策、CLI 徽章(橙色 = Claude Code,紫色 = OpenAI Codex,蓝色 = GitHub Copilot,翠绿色 = Cursor Agent,琥珀色 = OpenCode,粉色 = Pi,靛蓝色 = Hermes)、工具名称、会话 ID,以及 deny/instruct 决策的原因 + - 点击会话 ID 可打开其记录——查看器自动检测触发 Hook 的 CLI(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Hermes `~/.hermes/state.db`),并在页眉中渲染对应的 CLI 徽章 diff --git a/docs/zh/getting-started.mdx b/docs/zh/getting-started.mdx index 92ed9c45..5c98ba47 100644 --- a/docs/zh/getting-started.mdx +++ b/docs/zh/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - 此命令会将 hook 条目写入已安装的 Agent CLI 配置文件中(Claude Code 的 `~/.claude/settings.json`、OpenAI Codex 的 `~/.codex/hooks.json`、GitHub Copilot CLI 的 `~/.copilot/hooks/failproofai.json`、Cursor Agent 的 `~/.cursor/hooks.json`、OpenCode 在 `~/.config/opencode/plugins/failproofai.mjs` 生成的插件 shim 及 `~/.config/opencode/opencode.json` 的 `plugin` 数组注册项、Pi 的 `~/.pi/agent/settings.json`、Gemini CLI 的 `~/.gemini/settings.json`,或 Hermes 的 `~/.hermes/config.yaml`)。若检测到多个 CLI,系统会提示你选择;也可以通过 `--cli claude codex copilot cursor opencode pi gemini hermes`(任意子集)跳过提示。 + 此命令会将 hook 条目写入已安装的 Agent CLI 配置文件中(Claude Code 的 `~/.claude/settings.json`、OpenAI Codex 的 `~/.codex/hooks.json`、GitHub Copilot CLI 的 `~/.copilot/hooks/failproofai.json`、Cursor Agent 的 `~/.cursor/hooks.json`、OpenCode 在 `~/.config/opencode/plugins/failproofai.mjs` 生成的插件 shim 及 `~/.config/opencode/opencode.json` 的 `plugin` 数组注册项、Pi 的 `~/.pi/agent/settings.json`,或 Hermes 的 `~/.hermes/config.yaml`)。若检测到多个 CLI,系统会提示你选择;也可以通过 `--cli claude codex copilot cursor opencode pi hermes`(任意子集)跳过提示。 - GitHub Copilot CLI、Cursor Agent、OpenCode、Pi 和 Gemini CLI 的支持目前处于 **beta** 阶段 — 请分别使用 `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi` 或 `--cli gemini` 进行安装。Hermes(hermes-agent,一个 Slack/Telegram 网关)使用 `--cli hermes` 安装用户级作用域,同时也是一个**离线**审计数据源。 + GitHub Copilot CLI、Cursor Agent、OpenCode 和 Pi 的支持目前处于 **beta** 阶段 — 请分别使用 `--cli copilot`、`--cli cursor`、`--cli opencode` 或 `--cli pi` 进行安装。Hermes(hermes-agent,一个 Slack/Telegram 网关)使用 `--cli hermes` 安装用户级作用域,同时也是一个**离线**审计数据源。 ```bash failproofai policies --install --scope project @@ -48,7 +48,6 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/zh/introduction.mdx b/docs/zh/introduction.mdx index b741ec58..2caefee6 100644 --- a/docs/zh/introduction.mdx +++ b/docs/zh/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI 为 AI 智能体提供 39 条内置故障策略,一 [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -专为 **AI 故障处理**、**错误恢复**和 **LLM 可靠性**设计的 Hooks 与策略系统。让你的 AI 智能体在 **Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Gemini CLI**、**Hermes** 以及 **Agents SDK** 上稳定运行、持续自主工作。 +专为 **AI 故障处理**、**错误恢复**和 **LLM 可靠性**设计的 Hooks 与策略系统。让你的 AI 智能体在 **Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Hermes** 以及 **Agents SDK** 上稳定运行、持续自主工作。 AI 智能体的失败往往有迹可循:执行破坏性命令、泄露密钥、偏离任务、陷入死循环,或直接推送到主分支。一旦无人看管,小故障就会滚雪球般演变成服务中断、凭据泄露和数据丢失。 diff --git a/lib/antigravity-projects.ts b/lib/antigravity-projects.ts new file mode 100644 index 00000000..0069c76a --- /dev/null +++ b/lib/antigravity-projects.ts @@ -0,0 +1,224 @@ +/** + * Antigravity (agy) project discovery + session enumeration — AUDIT-ONLY. + * + * Antigravity keeps a SQLite index of conversations at + * `~/.gemini/antigravity-cli/conversation_summaries.db` (table + * `conversation_summaries`: conversation_id, title, preview, step_count, + * workspace_uris, project_id, last_modified_time, agent_name, …) and one + * plain-JSONL transcript per conversation under `brain//…`. Verified live + * against agy v1.1.2. + * + * The on-disk `brain/` transcripts are the source of truth for a conversation's + * EXISTENCE (the summaries DB can lag / be checkpointed empty), so we enumerate + * from disk (lib/antigravity-sessions.ts) and ENRICH each with title + cwd from + * the SQLite index when a row is present. `workspace_uris` gives the project cwd + * → per-project grouping; when absent we recover cwd from the transcript's first + * `run_command` Cwd, else fall back to a synthetic "antigravity" project. + * + * DB / home override: set `ANTIGRAVITY_HOME` (used by tests). + */ +import { join } from "node:path"; +import { openSqliteReadonly } from "./sqlite-reader"; +import { + antigravityHome, + listAntigravityTranscripts, + getAntigravitySessionLog, +} from "./antigravity-sessions"; +import { runtimeCache } from "./runtime-cache"; +import type { ProjectFolder, SessionFile } from "./projects"; +import { encodeFolderName, decodeFolderName } from "./paths"; +import { formatDate } from "./format-date"; +import { logWarn } from "./logger"; + +/** Absolute path to the conversation-index SQLite DB. */ +export function antigravitySummariesDbPath(): string { + return join(antigravityHome(), "conversation_summaries.db"); +} + +interface SummaryRow { + conversation_id: string; + title: string | null; + step_count: number | null; + workspace_uris: string | null; + last_modified_time: string | number | null; +} + +export interface AntigravityIndexMeta { + title?: string; + cwd?: string; + stepCount?: number; + lastMs?: number; +} + +/** Parse the first workspace URI (a JSON array, or a plain string) into a cwd, + * stripping any `file://` scheme. */ +function parseWorkspaceCwd(raw: string | null): string | undefined { + if (!raw) return undefined; + let first: string | undefined; + try { + const parsed = JSON.parse(raw); + if (Array.isArray(parsed) && typeof parsed[0] === "string") first = parsed[0]; + else if (typeof parsed === "string") first = parsed; + } catch { + first = raw; + } + if (!first) return undefined; + const stripped = first.replace(/^file:\/\//, ""); + return stripped.length > 0 ? stripped : undefined; +} + +function toMs(value: string | number | null): number | undefined { + if (typeof value === "number" && Number.isFinite(value)) { + return value > 1e12 ? value : value > 1e9 ? value * 1000 : undefined; + } + if (typeof value === "string") { + const ms = Date.parse(value); + if (!Number.isNaN(ms)) return ms; + } + return undefined; +} + +/** Read the conversation index → conversationId → metadata. Returns an empty + * map when the DB is missing/unreadable/empty (fail-open). */ +export async function getAntigravityIndex(): Promise> { + const out = new Map(); + const db = await openSqliteReadonly(antigravitySummariesDbPath()); + if (!db) return out; + try { + const rows = db.query( + "SELECT conversation_id, title, step_count, workspace_uris, last_modified_time FROM conversation_summaries", + ); + for (const r of rows) { + if (!r.conversation_id) continue; + out.set(r.conversation_id, { + title: r.title ?? undefined, + cwd: parseWorkspaceCwd(r.workspace_uris), + stepCount: typeof r.step_count === "number" ? r.step_count : undefined, + lastMs: toMs(r.last_modified_time), + }); + } + } catch { + // corrupt / unexpected schema — fall open with whatever we have + } finally { + db.close(); + } + return out; +} + +interface AntigravityConversation { + conversationId: string; + cwd: string | null; + title?: string; + mtimeMs: number; +} + +/** Resolve every on-disk conversation to {cwd, title, mtime}, enriched from the + * SQLite index (cwd/title/lastMs) and, when the index lacks a cwd, from the + * transcript's first run_command Cwd. */ +async function resolveConversations(): Promise { + let transcripts; + try { + transcripts = listAntigravityTranscripts(); + } catch (error) { + logWarn("Failed to scan Antigravity brain dir:", error); + return []; + } + const index = await getAntigravityIndex(); + + const out: AntigravityConversation[] = []; + for (const t of transcripts) { + const meta = index.get(t.conversationId); + let cwd = meta?.cwd ?? null; + if (!cwd) { + // No index cwd — recover it from the transcript itself (best-effort). + try { + const log = await getAntigravitySessionLog(t.conversationId); + cwd = log?.cwd ?? null; + } catch { + cwd = null; + } + } + out.push({ + conversationId: t.conversationId, + cwd, + title: meta?.title, + mtimeMs: meta?.lastMs ?? t.mtimeMs, + }); + } + return out; +} + +/** Synthetic project name for conversations whose cwd could not be resolved. */ +const ANTIGRAVITY_UNGROUPED = "antigravity"; + +/** Returns one ProjectFolder per resolved cwd (grouped), plus a synthetic + * "antigravity" project for conversations without a cwd. */ +export async function getAntigravityProjects(): Promise { + const conversations = await resolveConversations(); + + const byName = new Map(); + for (const c of conversations) { + const name = c.cwd ? encodeFolderName(c.cwd) : ANTIGRAVITY_UNGROUPED; + const path = c.cwd ?? "antigravity"; + const existing = byName.get(name); + if (!existing || c.mtimeMs > existing.latest) { + byName.set(name, { latest: c.mtimeMs, path }); + } + } + + const folders: ProjectFolder[] = []; + for (const [name, { latest, path }] of byName) { + const lastModified = new Date(latest); + folders.push({ + name, + path, + isDirectory: true, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + cli: ["antigravity"], + }); + } + folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); + return folders; +} + +export interface AntigravityProjectByName { + cwd: string | null; + sessions: SessionFile[]; +} + +/** Resolve the Antigravity conversations for a project URL slug (an encoded-cwd + * folder name, or the synthetic "antigravity" bucket). */ +export async function getAntigravitySessionsByEncodedName( + name: string, +): Promise { + const conversations = await resolveConversations(); + const matched = conversations.filter((c) => { + const encoded = c.cwd ? encodeFolderName(c.cwd) : ANTIGRAVITY_UNGROUPED; + return encoded === name; + }); + if (matched.length === 0) return { cwd: null, sessions: [] }; + + const sorted = [...matched].sort((a, b) => b.mtimeMs - a.mtimeMs); + const cwd = sorted.find((c) => c.cwd)?.cwd ?? (name === ANTIGRAVITY_UNGROUPED ? null : decodeFolderName(name)); + + const sessions: SessionFile[] = sorted.map((c) => { + const lastModified = new Date(c.mtimeMs); + return { + name: c.title ?? c.conversationId, + path: `antigravity://${c.conversationId}`, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + sessionId: c.conversationId, + cli: "antigravity" as const, + }; + }); + return { cwd, sessions }; +} + +export const getCachedAntigravityProjects = runtimeCache(getAntigravityProjects, 30); +export const getCachedAntigravitySessionsByEncodedName = runtimeCache( + (name: string) => getAntigravitySessionsByEncodedName(name), + 30, + { maxSize: 50 }, +); diff --git a/lib/antigravity-sessions.ts b/lib/antigravity-sessions.ts new file mode 100644 index 00000000..798e9c2c --- /dev/null +++ b/lib/antigravity-sessions.ts @@ -0,0 +1,283 @@ +/** + * Antigravity (agy) session transcript loader + parser. + * + * AUDIT-ONLY (Pillar 2). Antigravity writes one plain-JSONL transcript per + * conversation at + * `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` + * (one step per line). Verified live against agy v1.1.2. Sibling + * `.trajectory.jsonl` / `.trajectory-path.json` files are + * IGNORED — we only read `transcript_full.jsonl`. + * + * Each transcript line is a step: + * {step_index, source, type, status, created_at, content?, tool_calls?} + * The `type` enum (uppercase) drives parsing: + * • USER_INPUT — content = user text + * • PLANNER_RESPONSE — content = assistant text, OR tool_calls = + * [{name:"run_command", args:{CommandLine, Cwd, …}}] + * • (e.g. RUN_COMMAND) — content = the tool result string; the + * `type` is the uppercased tool name, so we pair it + * with the preceding PLANNER_RESPONSE tool_call of + * the same name. + * • CONVERSATION_HISTORY / CHECKPOINT — metadata (skipped). + * + * `antigravityLinesToLogEntries` is PURE (a function of the parsed line + * objects), so it is unit-testable without touching disk. + * + * Home override: set `ANTIGRAVITY_HOME` (used by tests / to point at a copied + * brain dir). Default: `~/.gemini/antigravity-cli`. + */ +import { readFile } from "node:fs/promises"; +import { readdirSync, statSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import { runtimeCache } from "./runtime-cache"; +import { + baseEntry, + formatTimestamp, + parseRawLines, + type LogEntry, + type UserEntry, + type AssistantEntry, + type GenericEntry, + type ContentBlock, + type ToolUseBlock, + type LogSource, +} from "./log-entries"; +import { formatDuration } from "./format-duration"; + +/** Antigravity conversations are UUID-named directories. */ +export const ANTIGRAVITY_CONVERSATION_ID_RE = + /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; + +/** Step `type` values that are metadata, not turns. */ +const ANTIGRAVITY_META_STEP_TYPES = new Set(["CONVERSATION_HISTORY", "CHECKPOINT"]); + +/** Absolute path to Antigravity's config home (override with ANTIGRAVITY_HOME). */ +export function antigravityHome(): string { + return process.env.ANTIGRAVITY_HOME || join(homedir(), ".gemini", "antigravity-cli"); +} + +/** Absolute path to the `brain/` root (one subdir per conversation). */ +export function antigravityBrainRoot(): string { + return join(antigravityHome(), "brain"); +} + +/** Relative path of a conversation's full transcript inside its brain dir. */ +export function antigravityTranscriptRelPath(): string { + return join(".system_generated", "logs", "transcript_full.jsonl"); +} + +// ── Parsing helpers ── + +function isPlainObject(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); +} + +function toDate(value: unknown, fallbackMs: number): Date { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return new Date(value); + if (value > 1e9) return new Date(value * 1000); + } + if (typeof value === "string") { + const ms = Date.parse(value); + if (!Number.isNaN(ms)) return new Date(ms); + } + return new Date(fallbackMs); +} + +// ── Pure parser: transcript lines → LogEntry[] ── + +/** + * Convert Antigravity transcript JSONL lines (parsed objects, in file order) + * into `LogEntry[]`. USER_INPUT → user turns; PLANNER_RESPONSE → assistant + * turns (text and/or `tool_use` blocks); a following tool-result step + * (type === uppercased tool name, e.g. RUN_COMMAND) is paired back onto the + * matching `tool_use` block. Metadata steps (CONVERSATION_HISTORY, CHECKPOINT) + * are skipped. Pure — unit-testable with plain line objects. + */ +export function antigravityLinesToLogEntries( + lines: Record[], + source: LogSource = "session", +): LogEntry[] { + const entries: LogEntry[] = []; + // FIFO of pending tool_use blocks keyed by uppercased tool name, so a later + // RUN_COMMAND-type result step attaches to the right run_command call. + const pendingByType = new Map>(); + const baseMs = Date.now(); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!isPlainObject(line)) continue; + const type = typeof line.type === "string" ? line.type : ""; + if (!type || ANTIGRAVITY_META_STEP_TYPES.has(type)) continue; + + const date = toDate(line.created_at, baseMs + i); + const timestamp = date.toISOString(); + const stepIndex = typeof line.step_index === "number" ? line.step_index : i; + const raw: Record = { + uuid: `antigravity-${stepIndex}`, + parentUuid: null, + }; + const base = baseEntry(raw, timestamp, date, source); + + if (type === "USER_INPUT") { + const text = typeof line.content === "string" ? line.content : ""; + entries.push({ + type: "user", + ...base, + message: { role: "user", content: text }, + } satisfies UserEntry); + continue; + } + + if (type === "PLANNER_RESPONSE") { + const blocks: ContentBlock[] = []; + if (typeof line.content === "string" && line.content.length > 0) { + blocks.push({ type: "text", text: line.content }); + } + if (Array.isArray(line.tool_calls)) { + for (let j = 0; j < line.tool_calls.length; j++) { + const call = line.tool_calls[j]; + if (!isPlainObject(call)) continue; + const name = typeof call.name === "string" ? call.name : "tool"; + const input = isPlainObject(call.args) ? call.args : {}; + const id = `${name}-${stepIndex}-${j}`; + const block: ToolUseBlock = { type: "tool_use", id, name, input }; + blocks.push(block); + const key = name.toUpperCase(); + const queue = pendingByType.get(key) ?? []; + queue.push({ block, startMs: date.getTime() }); + pendingByType.set(key, queue); + } + } + if (blocks.length === 0) continue; + entries.push({ + type: "assistant", + ...base, + message: { role: "assistant", content: blocks }, + } satisfies AssistantEntry); + continue; + } + + // Any other step type is a tool-result step whose `type` is the uppercased + // tool name (e.g. RUN_COMMAND for a run_command call). Pair it back onto the + // oldest matching pending tool_use block. + const queue = pendingByType.get(type); + if (queue && queue.length > 0) { + const { block, startMs } = queue.shift()!; + const durationMs = Math.max(0, date.getTime() - startMs); + block.result = { + timestamp, + timestampFormatted: formatTimestamp(date), + content: typeof line.content === "string" ? line.content : "", + durationMs, + durationFormatted: formatDuration(durationMs), + }; + continue; + } + // Unpaired non-meta step — record as generic so nothing is silently lost. + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + + entries.sort((a, b) => a.timestampMs - b.timestampMs); + return entries; +} + +/** Best-effort cwd recovery: the first `run_command` tool_call's `Cwd` arg. */ +function recoverCwd(lines: Record[]): string | undefined { + for (const line of lines) { + if (!isPlainObject(line) || !Array.isArray(line.tool_calls)) continue; + for (const call of line.tool_calls) { + if (!isPlainObject(call) || !isPlainObject(call.args)) continue; + const cwd = call.args.Cwd ?? call.args.cwd; + if (typeof cwd === "string" && cwd.length > 0) return cwd; + } + } + return undefined; +} + +// ── Discovery + file loader ── + +export interface AntigravityTranscriptFile { + conversationId: string; + transcriptPath: string; + mtimeMs: number; + sizeBytes: number; +} + +/** Enumerate `brain//.system_generated/logs/transcript_full.jsonl` + * transcripts. Skips conversation dirs without a full transcript. */ +export function listAntigravityTranscripts(): AntigravityTranscriptFile[] { + const root = antigravityBrainRoot(); + const rel = antigravityTranscriptRelPath(); + const out: AntigravityTranscriptFile[] = []; + let convoDirs: import("node:fs").Dirent[]; + try { + convoDirs = readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()); + } catch { + return out; + } + for (const dir of convoDirs) { + const conversationId = dir.name; + if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId)) continue; + const transcriptPath = join(root, conversationId, rel); + try { + const st = statSync(transcriptPath); + if (!st.isFile()) continue; + out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size }); + } catch { + // no full transcript for this conversation yet — skip + } + } + return out; +} + +/** Resolve a conversation UUID to its on-disk transcript path (host-side). + * Guards against traversal by requiring a UUID. Shared by the audit adapter, + * the hook transcript resolver, and download-session. Synchronous. */ +export function findAntigravityTranscript(conversationId: string): string | null { + if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId)) return null; + const transcriptPath = join( + antigravityBrainRoot(), + conversationId, + antigravityTranscriptRelPath(), + ); + try { + if (statSync(transcriptPath).isFile()) return transcriptPath; + } catch { + // fall through + } + return null; +} + +export interface AntigravitySessionLogData { + entries: LogEntry[]; + rawLines: Record[]; + cwd?: string; + filePath: string; +} + +/** Load and parse one conversation transcript by UUID. Returns `null` when the + * file is missing/unreadable or the id fails validation. */ +export async function getAntigravitySessionLog( + conversationId: string, +): Promise { + const filePath = findAntigravityTranscript(conversationId); + if (!filePath) return null; + let content: string; + try { + content = await readFile(filePath, "utf-8"); + } catch { + return null; + } + const rawLines = parseRawLines(content, "session"); + const entries = antigravityLinesToLogEntries(rawLines, "session"); + const cwd = recoverCwd(rawLines); + return { entries, rawLines, cwd, filePath }; +} + +export const getCachedAntigravitySessionLog = runtimeCache( + (conversationId: string) => getAntigravitySessionLog(conversationId), + 60, + { maxSize: 50 }, +); diff --git a/lib/cli-registry.ts b/lib/cli-registry.ts index d7c0c517..031aea4c 100644 --- a/lib/cli-registry.ts +++ b/lib/cli-registry.ts @@ -27,7 +27,7 @@ import type { IntegrationType } from "@/src/hooks/types"; /** Canonical CLI ids the registry knows about. Mirrors `INTEGRATION_TYPES`. */ -export const KNOWN_CLI_IDS = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"] as const satisfies readonly IntegrationType[]; +export const KNOWN_CLI_IDS = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"] as const satisfies readonly IntegrationType[]; export type CliId = (typeof KNOWN_CLI_IDS)[number]; /** Per-CLI metadata consumed by the dashboard. */ @@ -69,16 +69,36 @@ const CLI_ENTRIES: Record = { label: "Pi", badgeClasses: "bg-pink-500/10 text-pink-400 border-pink-500/20", }, - gemini: { - id: "gemini", - label: "Gemini CLI", - badgeClasses: "bg-sky-500/10 text-sky-400 border-sky-500/20", - }, hermes: { id: "hermes", label: "Hermes", badgeClasses: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20", }, + openclaw: { + id: "openclaw", + label: "OpenClaw", + badgeClasses: "bg-teal-500/10 text-teal-400 border-teal-500/20", + }, + factory: { + id: "factory", + label: "Factory Droid", + badgeClasses: "bg-rose-500/10 text-rose-400 border-rose-500/20", + }, + devin: { + id: "devin", + label: "Devin CLI", + badgeClasses: "bg-violet-500/10 text-violet-400 border-violet-500/20", + }, + antigravity: { + id: "antigravity", + label: "Antigravity CLI", + badgeClasses: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20", + }, + goose: { + id: "goose", + label: "Goose", + badgeClasses: "bg-lime-500/10 text-lime-400 border-lime-500/20", + }, }; export function getCliEntry(id: string): CliEntry | undefined { diff --git a/lib/devin-projects.ts b/lib/devin-projects.ts new file mode 100644 index 00000000..b3c44d36 --- /dev/null +++ b/lib/devin-projects.ts @@ -0,0 +1,141 @@ +/** + * Devin CLI (Cognition) session enumeration — AUDIT-ONLY. + * + * Reads the `sessions` table directly from `~/.local/share/devin/cli/sessions.db` + * via the bundled sql.js reader. Unlike Hermes (cwd-less, grouped by channel), + * each Devin session carries a real `working_directory`, so Devin sessions group + * by project cwd like Claude/Factory — one `ProjectFolder` per encoded cwd, and + * a cwd present in both Claude and Devin stores merges on the shared encoded + * slug (see `mergeProjectFolders` in lib/projects.ts). + */ +import { openSqliteReadonly } from "./sqlite-reader"; +import { devinDbPath, devinEpochToMs } from "./devin-sessions"; +import { encodeFolderName } from "./paths"; +import { runtimeCache } from "./runtime-cache"; +import type { ProjectFolder, SessionFile } from "./projects"; +import { formatDate } from "./format-date"; + +export interface DevinSessionRef { + sessionId: string; + cwd?: string; + title?: string; + /** Encoded-cwd folder slug (matches Claude's `-home-user-project` scheme). */ + projectName: string; + /** From `last_activity_at` (falls back to `created_at`) — epoch ms. */ + mtimeMs: number; +} + +interface SessionRow { + id: string; + working_directory: string | null; + title: string | null; + created_at: number | null; + last_activity_at: number | null; + hidden: number | null; +} + +/** + * List every Devin session. Returns `[]` when the DB is missing or unreadable + * (fail-open — the audit just skips Devin). Hidden sessions are excluded. + */ +export async function getDevinSessions(): Promise { + const db = await openSqliteReadonly(devinDbPath()); + if (!db) return []; + try { + const rows = db.query( + "SELECT id, working_directory, title, created_at, last_activity_at, hidden " + + "FROM sessions ORDER BY last_activity_at DESC", + ); + return rows + .filter((r) => !r.hidden) + .map((r) => { + const cwd = r.working_directory ?? undefined; + return { + sessionId: r.id, + cwd, + title: r.title ?? undefined, + projectName: cwd ? encodeFolderName(cwd) : "devin", + mtimeMs: devinEpochToMs(r.last_activity_at ?? r.created_at), + }; + }); + } catch { + return []; + } finally { + db.close(); + } +} + +export const getCachedDevinSessions = runtimeCache(getDevinSessions, 2); + +// ── Dashboard history browser (projects list + project-detail sessions) ── + +/** One `ProjectFolder` per encoded-cwd discovered in the Devin DB. */ +export async function getDevinProjects(): Promise { + const sessions = await getDevinSessions(); + const byName = new Map(); + for (const s of sessions) { + if (!s.cwd) continue; + const existing = byName.get(s.projectName); + if (!existing || s.mtimeMs > existing.latest) { + byName.set(s.projectName, { latest: s.mtimeMs, cwd: s.cwd, name: s.projectName }); + } + } + const folders: ProjectFolder[] = []; + for (const { name, cwd, latest } of byName.values()) { + const lastModified = new Date(latest); + folders.push({ + name, + path: cwd, + isDirectory: true, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + cli: ["devin"], + }); + } + folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); + return folders; +} + +export interface DevinProjectByName { + /** Canonical cwd recovered from the session's `working_directory`. */ + cwd: string | null; + sessions: SessionFile[]; +} + +/** + * Resolve the Devin sessions for a project URL slug (the encoded-cwd folder + * name). Because Devin's `working_directory` re-encodes to the same slug Claude + * uses, the slug matches directly and the canonical cwd is the session's real + * `working_directory` (no lossy folder-decode needed). + */ +export async function getDevinSessionsByEncodedName( + name: string, +): Promise { + const sessions = await getDevinSessions(); + const matched = sessions.filter((s) => s.cwd && s.projectName === name); + if (matched.length === 0) return { cwd: null, sessions: [] }; + + const sorted = [...matched].sort((a, b) => b.mtimeMs - a.mtimeMs); + const cwd = sorted[0].cwd ?? null; + return { + cwd, + sessions: sorted.map((s) => { + const lastModified = new Date(s.mtimeMs); + return { + name: s.title ?? s.sessionId, + path: `devin-db://${s.sessionId}`, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + sessionId: s.sessionId, + cli: "devin" as const, + }; + }), + }; +} + +export const getCachedDevinProjects = runtimeCache(getDevinProjects, 2); +export const getCachedDevinSessionsByEncodedName = runtimeCache( + (name: string) => getDevinSessionsByEncodedName(name), + 2, + { maxSize: 50 }, +); diff --git a/lib/devin-sessions.ts b/lib/devin-sessions.ts new file mode 100644 index 00000000..d0ef4c2b --- /dev/null +++ b/lib/devin-sessions.ts @@ -0,0 +1,343 @@ +/** + * Devin CLI (Cognition) session transcript loader + parser. + * + * AUDIT-ONLY (Pillar 2). Devin stores every session in one SQLite DB at + * `~/.local/share/devin/cli/sessions.db`. We read it DIRECTLY via the bundled + * sql.js driver (lib/sqlite-reader.ts) — the same reusable path Hermes/OpenClaw + * use. Unlike Hermes (which is cwd-less), each Devin `sessions` row carries a + * real `working_directory`, so Devin sessions group by project cwd like Claude. + * + * Schema (verified live against devin v3000.1.27): + * sessions(id, working_directory, backend_type, model, agent_mode, + * created_at INT, last_activity_at INT, title, workspace_dirs, metadata) + * message_nodes(row_id, session_id, node_id, parent_node_id, + * chat_message TEXT=JSON, created_at INT, metadata) + * + * `chat_message` is OpenAI-style JSON: `{role, content, tool_calls?, + * tool_call_id?, thinking?, metadata?}`. Assistant tool calls are flat + * `tool_calls[].{id, name, arguments}` (arguments is already an object, NOT a + * JSON string as in the OpenAI wire format), and results are separate + * `role:"tool"` rows keyed by `tool_call_id`. `devinRowsToLogEntries` pairs them + * (mirrors lib/hermes-sessions.ts) and is a PURE function of the parsed message + * objects, so it is unit-testable without a DB. + * + * Home override: set `DEVIN_HOME` (used by tests / to point at a copied Devin + * data dir) or `DEVIN_DB_PATH` (points directly at a sessions.db). + */ +import { homedir } from "node:os"; +import { join } from "node:path"; +import { openSqliteReadonly } from "./sqlite-reader"; +import { runtimeCache } from "./runtime-cache"; +import { + baseEntry, + formatTimestamp, + type LogEntry, + type UserEntry, + type AssistantEntry, + type GenericEntry, + type ContentBlock, + type ToolUseBlock, + type LogSource, +} from "./log-entries"; +import { formatDuration } from "./format-duration"; + +/** Devin session IDs are word-slug style (e.g. `estimated-seeker`). */ +export const DEVIN_SESSION_ID_RE = /^[A-Za-z0-9_-]+$/; + +/** Absolute path to Devin's data home (override with DEVIN_HOME). */ +export function devinHome(): string { + return process.env.DEVIN_HOME || join(homedir(), ".local", "share", "devin"); +} + +/** Absolute path to Devin's SQLite DB (override with DEVIN_DB_PATH). */ +export function devinDbPath(): string { + return process.env.DEVIN_DB_PATH || join(devinHome(), "cli", "sessions.db"); +} + +/** Coerce a Devin epoch value (seconds or ms) to epoch ms. Devin stores + * `created_at`/`last_activity_at` as INTEGER epoch seconds. */ +export function devinEpochToMs(value: unknown): number { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return value; // already ms + if (value > 1e9) return value * 1000; // seconds + } + return Date.now(); +} + +// ── Parsing helpers ── + +function safeJsonParse(s: unknown): unknown { + if (typeof s !== "string" || s.length === 0) return undefined; + try { + return JSON.parse(s); + } catch { + return undefined; + } +} + +function isPlainObject(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); +} + +/** Text from a `content` field that may be a string or an array of + * `{ type:"text", text }` blocks. */ +function extractText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : "")) + .filter(Boolean) + .join("\n"); + } + return ""; +} + +function toDate(value: unknown, fallbackMs: number): Date { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return new Date(value); + if (value > 1e9) return new Date(value * 1000); + } + if (typeof value === "string") { + const ms = Date.parse(value); + if (!Number.isNaN(ms)) return new Date(ms); + } + return new Date(fallbackMs); +} + +interface NormalizedToolCall { + id: string; + name: string; + input: Record; +} + +/** Normalize Devin `tool_calls` into `{ id, name, input }[]`. Devin's shape is + * flat: `{ id, name, arguments }` where `arguments` is already an object. Also + * tolerates the OpenAI wire shape `{ id|call_id, function:{ name, arguments }}` + * (arguments as a JSON string) for forward-compat. */ +function normalizeDevinToolCalls(raw: unknown): NormalizedToolCall[] { + const arr = Array.isArray(raw) ? raw : safeJsonParse(raw); + if (!Array.isArray(arr)) return []; + const out: NormalizedToolCall[] = []; + for (const tc of arr) { + if (!isPlainObject(tc)) continue; + const fn = isPlainObject(tc.function) ? tc.function : {}; + const name = + typeof tc.name === "string" + ? tc.name + : typeof fn.name === "string" + ? (fn.name as string) + : "tool"; + const id = + (typeof tc.id === "string" && tc.id) || + (typeof tc.call_id === "string" && tc.call_id) || + `${name}-${out.length}`; + const rawArgs = tc.arguments ?? fn.arguments; + const parsedArgs = isPlainObject(rawArgs) ? rawArgs : safeJsonParse(rawArgs); + out.push({ id, name, input: isPlainObject(parsedArgs) ? parsedArgs : {} }); + } + return out; +} + +/** Epoch ms for a parsed chat_message: prefer its high-precision + * `metadata.created_at` ISO string, else the DB row's injected `_created_at` + * (epoch seconds), else the fallback. */ +function messageDate(m: Record, fallbackMs: number): Date { + const meta = isPlainObject(m.metadata) ? m.metadata : undefined; + if (meta && meta.created_at != null) return toDate(meta.created_at, fallbackMs); + if (m._created_at != null) return toDate(m._created_at, fallbackMs); + return new Date(fallbackMs); +} + +// ── Pure parser: parsed chat_message objects → LogEntry[] ── + +/** + * Convert parsed `chat_message` objects (in node order) into `LogEntry[]`. + * Pairs each assistant `tool_calls` entry with its later `role:"tool"` result + * by `tool_call_id`. Roles other than user/assistant/tool (e.g. `system`) + * become generic system entries so nothing is dropped. Pure — unit-testable + * with plain message objects. Each object may carry an injected `_created_at` + * (the DB row's epoch-seconds timestamp) used when `metadata.created_at` is + * absent. + */ +export function devinRowsToLogEntries( + rows: Record[], + source: LogSource = "session", +): LogEntry[] { + const entries: LogEntry[] = []; + const toolUseById = new Map(); + const toolUseStartMs = new Map(); + const baseMs = Date.now(); + + for (let i = 0; i < rows.length; i++) { + const m = rows[i]; + if (!isPlainObject(m)) continue; + + const role = typeof m.role === "string" ? m.role : "system"; + const date = messageDate(m, baseMs + i); + const timestamp = date.toISOString(); + const raw: Record = { + uuid: m.message_id != null ? String(m.message_id) : `devin-${i}`, + parentUuid: null, + }; + const base = baseEntry(raw, timestamp, date, source); + + if (role === "user") { + entries.push({ + type: "user", + ...base, + message: { role: "user", content: extractText(m.content) }, + } satisfies UserEntry); + continue; + } + + if (role === "assistant") { + const blocks: ContentBlock[] = []; + const text = extractText(m.content); + if (text) blocks.push({ type: "text", text }); + for (const tc of normalizeDevinToolCalls(m.tool_calls)) { + const block: ToolUseBlock = { type: "tool_use", id: tc.id, name: tc.name, input: tc.input }; + blocks.push(block); + toolUseById.set(tc.id, block); + toolUseStartMs.set(tc.id, date.getTime()); + } + if (blocks.length === 0) continue; // empty assistant turn + entries.push({ + type: "assistant", + ...base, + message: { + role: "assistant", + content: blocks, + model: typeof m.model === "string" ? m.model : undefined, + }, + } satisfies AssistantEntry); + continue; + } + + if (role === "tool") { + const callId = typeof m.tool_call_id === "string" ? m.tool_call_id : undefined; + const block = callId ? toolUseById.get(callId) : undefined; + if (block) { + const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime(); + const durationMs = Math.max(0, date.getTime() - startMs); + block.result = { + timestamp, + timestampFormatted: formatTimestamp(date), + content: extractText(m.content), + durationMs, + durationFormatted: formatDuration(durationMs), + }; + continue; + } + // Orphan tool result — fall through to a system entry. + } + + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + + entries.sort((a, b) => a.timestampMs - b.timestampMs); + return entries; +} + +// ── DB loader ── + +export interface DevinSessionLogData { + entries: LogEntry[]; + rawLines: Record[]; + cwd?: string; + filePath: string; // synthetic — devin keeps sessions in a DB; we use devin-db:// +} + +interface DevinMessageNodeRow { + node_id: number | null; + parent_node_id: number | null; + chat_message: string | null; + created_at: number | null; +} + +/** + * Devin stores a session's messages as a FOREST, not a flat list: each turn is a + * node (`node_id`) linked to its `parent_node_id`, and Devin replays earlier + * context under fresh roots on later turns — so the table holds many branches + * that repeat the same messages (verified live: 29 nodes / 11 distinct messages + * for a 10-message conversation). Reading every node duplicates each message + * 2-4×. The real conversation is the single path from the NEWEST leaf back to its + * root. Because Devin appends nodes in order (a child's `node_id` always exceeds + * its parent's), the newest leaf is simply the max `node_id`; walk its + * `parent_node_id` chain to the root and reverse to get root→leaf order. + */ +export function devinActiveConversationPath(rows: DevinMessageNodeRow[]): DevinMessageNodeRow[] { + if (rows.length === 0) return rows; + const byId = new Map(); + for (const r of rows) if (typeof r.node_id === "number") byId.set(r.node_id, r); + // Newest leaf = highest node_id (a leaf, since children always have a higher id). + let cur: DevinMessageNodeRow | undefined = rows.reduce((a, b) => + (a.node_id ?? -1) > (b.node_id ?? -1) ? a : b, + ); + const path: DevinMessageNodeRow[] = []; + const seen = new Set(); + while (cur && typeof cur.node_id === "number" && !seen.has(cur.node_id)) { + seen.add(cur.node_id); + path.push(cur); + cur = cur.parent_node_id != null ? byId.get(cur.parent_node_id) : undefined; + } + return path.reverse(); // root → leaf = conversation order +} + +/** Parse a session's `message_nodes` rows into the message objects the pure + * parser consumes, injecting each row's `created_at` as `_created_at`. */ +function parseNodeRows(rows: DevinMessageNodeRow[]): Record[] { + const out: Record[] = []; + for (const r of rows) { + const parsed = safeJsonParse(r.chat_message); + if (!isPlainObject(parsed)) continue; + if (r.created_at != null && parsed._created_at == null) parsed._created_at = r.created_at; + out.push(parsed); + } + return out; +} + +/** + * Load one session by ID from `sessions.db`. Returns `null` when the DB is + * unavailable or the session doesn't exist. + */ +export async function getDevinSessionLog( + sessionId: string, +): Promise { + if (!sessionId || !DEVIN_SESSION_ID_RE.test(sessionId)) return null; + const db = await openSqliteReadonly(devinDbPath()); + if (!db) return null; + try { + const sessionRows = db.query<{ working_directory: string | null }>( + "SELECT working_directory FROM sessions WHERE id = ?", + [sessionId], + ); + if (sessionRows.length === 0) return null; + const realCwd = sessionRows[0].working_directory; + + const nodeRows = db.query( + "SELECT node_id, parent_node_id, chat_message, created_at FROM message_nodes " + + "WHERE session_id = ? ORDER BY node_id ASC", + [sessionId], + ); + // Reconstruct the active conversation path (drop replayed branch duplicates). + const rawLines = parseNodeRows(devinActiveConversationPath(nodeRows)); + const entries = devinRowsToLogEntries(rawLines, "session"); + const cwd = realCwd && realCwd.length > 0 ? realCwd : undefined; + return { + entries, + rawLines, + cwd, + filePath: `devin-db://${sessionId}`, + }; + } catch { + return null; + } finally { + db.close(); + } +} + +export const getCachedDevinSessionLog = runtimeCache( + (sessionId: string) => getDevinSessionLog(sessionId), + 2, + { maxSize: 50 }, +); diff --git a/lib/download-session.ts b/lib/download-session.ts index 235812fc..1eea27f5 100644 --- a/lib/download-session.ts +++ b/lib/download-session.ts @@ -20,6 +20,18 @@ export const OPENCODE_SESSION_RE = /^ses_[A-Za-z0-9]+$/; * its download with `RangeError("Invalid session ID")`. */ export const HERMES_SESSION_RE = /^[A-Za-z0-9_-]+$/; +/** OpenClaw sessions are UUID-named files. Kept in sync with + * OPENCLAW_SESSION_ID_RE in lib/openclaw-sessions.ts. */ +export const OPENCLAW_SESSION_RE = /^[0-9a-fA-F-]{36}$/; + +/** Devin session IDs are word-slug style (e.g. `estimated-seeker`). Kept in + * sync with DEVIN_SESSION_ID_RE in lib/devin-sessions.ts. */ +export const DEVIN_SESSION_RE = /^[A-Za-z0-9_-]+$/; + +/** Goose session IDs are date-prefixed counters (e.g. `20260714_3`). Kept in + * sync with GOOSE_SESSION_ID_RE in lib/goose-sessions.ts. */ +export const GOOSE_SESSION_RE = /^\d{8}_\d+$/; + export type DownloadSource = | { kind: "file"; path: string } | { kind: "synthesized"; body: string; contentType: string; extension: string }; @@ -29,6 +41,9 @@ export type DownloadSource = export function isValidSessionId(cli: CliId, sessionId: string): boolean { if (cli === "opencode") return OPENCODE_SESSION_RE.test(sessionId); if (cli === "hermes") return HERMES_SESSION_RE.test(sessionId); + if (cli === "openclaw") return OPENCLAW_SESSION_RE.test(sessionId); + if (cli === "devin") return DEVIN_SESSION_RE.test(sessionId); + if (cli === "goose") return GOOSE_SESSION_RE.test(sessionId); return UUID_RE.test(sessionId); } @@ -74,11 +89,6 @@ export async function resolveDownloadSource( const path = findPiTranscript(sessionId); return path ? { kind: "file", path } : null; } - if (cli === "gemini") { - const { findGeminiTranscript } = await import("./gemini-sessions"); - const path = findGeminiTranscript(sessionId); - return path ? { kind: "file", path } : null; - } if (cli === "opencode") { // OpenCode keeps sessions in SQLite (~/.local/share/opencode/opencode.db) // across three tables: session / message / part. Export all three so @@ -101,6 +111,47 @@ export async function resolveDownloadSource( return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" }; } + if (cli === "openclaw") { + // OpenClaw writes real JSONL transcripts on disk — stream the file verbatim. + const { findOpenClawTranscript } = await import("./openclaw-sessions"); + const path = findOpenClawTranscript(sessionId); + return path ? { kind: "file", path } : null; + } + + if (cli === "factory") { + // Factory (droid) writes real JSONL transcripts on disk — stream verbatim. + const { findFactoryTranscript } = await import("./factory-sessions"); + const path = findFactoryTranscript(sessionId); + return path ? { kind: "file", path } : null; + } + + if (cli === "devin") { + // Devin keeps sessions in SQLite (~/.local/share/devin/cli/sessions.db). + // Synthesize a JSONL export of the session's raw chat_message rows. + const { getDevinSessionLog } = await import("./devin-sessions"); + const result = await getDevinSessionLog(sessionId); + if (!result) return null; + const body = result.rawLines.map((r) => JSON.stringify(r)).join("\n") + "\n"; + return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" }; + } + + if (cli === "antigravity") { + // Antigravity (agy) writes real JSONL transcripts on disk — stream verbatim. + const { findAntigravityTranscript } = await import("./antigravity-sessions"); + const path = findAntigravityTranscript(sessionId); + return path ? { kind: "file", path } : null; + } + + if (cli === "goose") { + // Goose keeps sessions in SQLite (~/.local/share/goose/sessions/sessions.db). + // Synthesize a JSONL export of the session's raw `messages` rows. + const { getGooseSessionLog } = await import("./goose-sessions"); + const result = await getGooseSessionLog(sessionId); + if (!result) return null; + const body = result.rawLines.map((r) => JSON.stringify(r)).join("\n") + "\n"; + return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" }; + } + // Exhaustive — but TypeScript can't always see CliId is exhausted across the // if-chain above, so guard with a runtime fallback. const _exhaustive: never = cli; diff --git a/lib/factory-projects.ts b/lib/factory-projects.ts new file mode 100644 index 00000000..e17c9bd2 --- /dev/null +++ b/lib/factory-projects.ts @@ -0,0 +1,109 @@ +/** + * Factory (droid) project discovery. + * + * droid stores transcripts at `~/.factory/sessions//.jsonl`, + * using the same Claude-style encoded-cwd folder names (`-home-user-project`) + * as Claude Code. The encoded folder doubles as the URL slug for + * `/project/[name]`, so a cwd present in both stores naturally produces the same + * `name` and merges on the Claude side (see `mergeProjectFolders` in + * lib/projects.ts). + */ +import { decodeFolderName } from "./paths"; +import { listFactoryTranscripts, getFactorySessionLog } from "./factory-sessions"; +import type { ProjectFolder, SessionFile } from "./projects"; +import { runtimeCache } from "./runtime-cache"; +import { formatDate } from "./format-date"; +import { logWarn } from "./logger"; + +/** Returns one ProjectFolder per encoded-cwd folder discovered under + * ~/.factory/sessions/. */ +export async function getFactoryProjects(): Promise { + let transcripts; + try { + transcripts = listFactoryTranscripts(); + } catch (error) { + logWarn("Failed to scan Factory sessions:", error); + return []; + } + + const byName = new Map(); + for (const t of transcripts) { + const existing = byName.get(t.projectName); + if (!existing || t.mtimeMs > existing.latest) { + byName.set(t.projectName, { latest: t.mtimeMs, cwd: t.cwd, name: t.projectName }); + } + } + + const folders: ProjectFolder[] = []; + for (const { name, cwd, latest } of byName.values()) { + const lastModified = new Date(latest); + folders.push({ + name, + path: cwd, + isDirectory: true, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + cli: ["factory"], + }); + } + folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); + return folders; +} + +export interface FactoryProjectByName { + /** Canonical cwd recovered from a session's `session_start` line (the folder + * decode is lossy). Null when no session could be read. */ + cwd: string | null; + sessions: SessionFile[]; +} + +/** + * Look up Factory sessions for a project URL slug (the encoded-cwd folder name). + * Because droid names its folders with the same encoding Claude uses, the slug + * matches the folder directly. The canonical cwd is recovered from the newest + * session's `session_start` record (folder decode is lossy for cwds with `-`). + */ +export async function getFactorySessionsByEncodedName( + name: string, +): Promise { + let transcripts; + try { + transcripts = listFactoryTranscripts().filter((t) => t.projectName === name); + } catch (error) { + logWarn("Failed to scan Factory sessions:", error); + return { cwd: null, sessions: [] }; + } + if (transcripts.length === 0) return { cwd: null, sessions: [] }; + + const sorted = [...transcripts].sort((a, b) => b.mtimeMs - a.mtimeMs); + + // Recover the canonical cwd from the newest transcript's session_start line. + let cwd: string | null = null; + try { + const log = await getFactorySessionLog(sorted[0].sessionId); + cwd = log?.cwd ?? null; + } catch { + // best-effort — fall back to the lossy decode below + } + if (!cwd) cwd = decodeFolderName(name); + + const sessions: SessionFile[] = sorted.map((t) => { + const lastModified = new Date(t.mtimeMs); + return { + name: t.sessionId, + path: t.transcriptPath, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + sessionId: t.sessionId, + cli: "factory" as const, + }; + }); + return { cwd, sessions }; +} + +export const getCachedFactoryProjects = runtimeCache(getFactoryProjects, 30); +export const getCachedFactorySessionsByEncodedName = runtimeCache( + (name: string) => getFactorySessionsByEncodedName(name), + 30, + { maxSize: 50 }, +); diff --git a/lib/factory-sessions.ts b/lib/factory-sessions.ts new file mode 100644 index 00000000..cbaeea5b --- /dev/null +++ b/lib/factory-sessions.ts @@ -0,0 +1,312 @@ +/** + * Factory (droid) session transcript loader + parser. + * + * AUDIT-ONLY (Pillar 2). droid writes one JSONL transcript per session at + * `~/.factory/sessions//.jsonl` (Claude-style + * encoded-cwd folders — e.g. `-home-chetan-project`), alongside a + * `.settings.json` sibling we IGNORE. Verified live against droid + * v0.171.0. + * + * The transcript is type-discriminated JSONL: + * {type:"session_start", id, cwd, …} — header (carries cwd) + * {type:"message", timestamp, message:{role, content, visibility}} — the turns + * {type:"compaction_state", …} — metadata (skipped) + * + * Message content is Claude-style: a string (user text) or an array of + * {type:"text",text} / {type:"tool_use",id,name,input} / {type:"tool_result", + * tool_use_id,content} blocks. `factoryLinesToLogEntries` pairs each assistant + * `tool_use` with its later `tool_result` by id (mirrors lib/openclaw-sessions.ts) + * and is PURE, so it is unit-testable with plain line objects. + * + * Home override: set `FACTORY_HOME` (used by tests / to point at a copied + * sessions dir). + */ +import { readFile } from "node:fs/promises"; +import { readdirSync, statSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import { decodeFolderName } from "./paths"; +import { runtimeCache } from "./runtime-cache"; +import { + baseEntry, + formatTimestamp, + parseRawLines, + type LogEntry, + type UserEntry, + type AssistantEntry, + type GenericEntry, + type ContentBlock, + type ToolUseBlock, + type LogSource, +} from "./log-entries"; +import { formatDuration } from "./format-duration"; + +/** Factory sessions are stored under UUID filenames. */ +export const FACTORY_SESSION_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/; + +/** Absolute path to Factory's config home (override with FACTORY_HOME). */ +export function factoryHome(): string { + return process.env.FACTORY_HOME || join(homedir(), ".factory"); +} + +/** Absolute path to the Factory sessions root. */ +export function factorySessionsRoot(): string { + return join(factoryHome(), "sessions"); +} + +// ── Parsing helpers ── + +function isPlainObject(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); +} + +/** Text from a `content` field that may be a string or an array of + * `{ type:"text", text }` blocks. */ +function extractText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : "")) + .filter(Boolean) + .join("\n"); + } + return ""; +} + +function toDate(value: unknown, fallbackMs: number): Date { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return new Date(value); + if (value > 1e9) return new Date(value * 1000); + } + if (typeof value === "string") { + const ms = Date.parse(value); + if (!Number.isNaN(ms)) return new Date(ms); + } + return new Date(fallbackMs); +} + +// ── Pure parser: transcript lines → LogEntry[] ── + +/** + * Convert Factory transcript JSONL lines (parsed objects, in file order) into + * `LogEntry[]`. Only `type:"message"` lines carry turns; `session_start` / + * `compaction_state` / other metadata lines are skipped. Assistant `tool_use` + * blocks are paired with their later `tool_result` (delivered on a user/tool + * message) by tool_use id. Pure — unit-testable with plain line objects. + */ +export function factoryLinesToLogEntries( + lines: Record[], + source: LogSource = "session", +): LogEntry[] { + const entries: LogEntry[] = []; + const toolUseById = new Map(); + const toolUseStartMs = new Map(); + const baseMs = Date.now(); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!isPlainObject(line)) continue; + if (line.type !== "message") continue; // skip session_start / compaction_state / … + + const m = isPlainObject(line.message) ? line.message : undefined; + if (!m) continue; + const role = typeof m.role === "string" ? m.role : "system"; + + const date = toDate(line.timestamp ?? m.timestamp, baseMs + i); + const timestamp = date.toISOString(); + const raw: Record = { + uuid: line.id != null ? String(line.id) : `factory-${i}`, + parentUuid: line.parentId != null ? String(line.parentId) : null, + }; + const base = baseEntry(raw, timestamp, date, source); + const content = m.content; + + if (role === "assistant") { + const blocks: ContentBlock[] = []; + if (Array.isArray(content)) { + for (const b of content) { + if (!isPlainObject(b)) continue; + if (b.type === "text" && typeof b.text === "string") { + blocks.push({ type: "text", text: b.text }); + } else if (b.type === "tool_use") { + const id = typeof b.id === "string" ? b.id : `${String(b.name ?? "tool")}-${blocks.length}`; + const name = typeof b.name === "string" ? b.name : "tool"; + const input = isPlainObject(b.input) ? b.input : {}; + const block: ToolUseBlock = { type: "tool_use", id, name, input }; + blocks.push(block); + toolUseById.set(id, block); + toolUseStartMs.set(id, date.getTime()); + } + } + } else { + const text = extractText(content); + if (text) blocks.push({ type: "text", text }); + } + if (blocks.length === 0) continue; // empty / failed assistant turn + entries.push({ + type: "assistant", + ...base, + message: { role: "assistant", content: blocks, model: typeof m.model === "string" ? m.model : undefined }, + } satisfies AssistantEntry); + continue; + } + + // user / tool role: may carry tool_result blocks and/or text. + if (Array.isArray(content)) { + let attachedAny = false; + const textParts: string[] = []; + for (const b of content) { + if (!isPlainObject(b)) continue; + if (b.type === "tool_result") { + const callId = + typeof b.tool_use_id === "string" + ? (b.tool_use_id as string) + : typeof b.toolUseId === "string" + ? (b.toolUseId as string) + : undefined; + const block = callId ? toolUseById.get(callId) : undefined; + if (block) { + const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime(); + const durationMs = Math.max(0, date.getTime() - startMs); + block.result = { + timestamp, + timestampFormatted: formatTimestamp(date), + content: extractText(b.content), + durationMs, + durationFormatted: formatDuration(durationMs), + }; + attachedAny = true; + continue; + } + } + if (b.type === "text" && typeof b.text === "string") textParts.push(b.text); + } + if (textParts.length > 0) { + entries.push({ + type: "user", + ...base, + message: { role: "user", content: textParts.join("\n") }, + } satisfies UserEntry); + } else if (!attachedAny) { + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + continue; + } + + if (role === "user") { + entries.push({ + type: "user", + ...base, + message: { role: "user", content: extractText(content) }, + } satisfies UserEntry); + continue; + } + + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + + entries.sort((a, b) => a.timestampMs - b.timestampMs); + return entries; +} + +// ── Discovery + file loader ── + +export interface FactoryTranscriptFile { + /** Encoded folder name on disk (e.g. "-home-user-project"). */ + projectName: string; + /** Decoded cwd of the project (lossy; canonical cwd lives in session_start). */ + cwd: string; + sessionId: string; + transcriptPath: string; + mtimeMs: number; + sizeBytes: number; +} + +/** Enumerate `sessions//.jsonl` transcripts, skipping the + * `.settings.json` sibling files. */ +export function listFactoryTranscripts(): FactoryTranscriptFile[] { + const root = factorySessionsRoot(); + const out: FactoryTranscriptFile[] = []; + let projectDirs: import("node:fs").Dirent[]; + try { + projectDirs = readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()); + } catch { + return out; + } + for (const dir of projectDirs) { + const projectName = dir.name; + const cwd = decodeFolderName(projectName); + const projectPath = join(root, projectName); + let files: string[]; + try { + files = readdirSync(projectPath); + } catch { + continue; + } + for (const file of files) { + // Only `.jsonl` — not `.settings.json`. + if (!file.endsWith(".jsonl")) continue; + const sessionId = file.slice(0, -".jsonl".length); + if (!FACTORY_SESSION_ID_RE.test(sessionId)) continue; + const transcriptPath = join(projectPath, file); + try { + const st = statSync(transcriptPath); + out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size }); + } catch { + // skip unreadable + } + } + } + return out; +} + +/** Resolve a session UUID to its on-disk transcript path (host-side). Guards + * against traversal by requiring a UUID filename. Shared by the audit adapter, + * the hook transcript resolver, and download-session. Synchronous so the hook + * hot path can call it without awaits. */ +export function findFactoryTranscript(sessionId: string): string | null { + if (!FACTORY_SESSION_ID_RE.test(sessionId)) return null; + for (const t of listFactoryTranscripts()) { + if (t.sessionId === sessionId) return t.transcriptPath; + } + return null; +} + +export interface FactorySessionLogData { + entries: LogEntry[]; + rawLines: Record[]; + cwd?: string; + filePath: string; +} + +/** Load and parse one session transcript by UUID. Returns `null` when the file + * is missing/unreadable or the id fails validation. */ +export async function getFactorySessionLog( + sessionId: string, +): Promise { + const filePath = findFactoryTranscript(sessionId); + if (!filePath) return null; + let content: string; + try { + content = await readFile(filePath, "utf-8"); + } catch { + return null; + } + const rawLines = parseRawLines(content, "session"); + const entries = factoryLinesToLogEntries(rawLines, "session"); + // cwd lives on the `type:"session_start"` header line. + let cwd: string | undefined; + for (const line of rawLines) { + if (isPlainObject(line) && line.type === "session_start" && typeof line.cwd === "string" && line.cwd.length > 0) { + cwd = line.cwd; + break; + } + } + return { entries, rawLines, cwd, filePath }; +} + +export const getCachedFactorySessionLog = runtimeCache( + (sessionId: string) => getFactorySessionLog(sessionId), + 60, + { maxSize: 50 }, +); diff --git a/lib/gemini-projects.ts b/lib/gemini-projects.ts deleted file mode 100644 index 49071fbd..00000000 --- a/lib/gemini-projects.ts +++ /dev/null @@ -1,243 +0,0 @@ -/** - * Gemini CLI project discovery. - * - * Empirically verified against gemini-cli v0.40.1: - * - * • Session-state root: `~/.gemini/tmp//`. Each subdir - * corresponds to one project. The basename is the cwd's last path segment - * (lossy when two projects share a basename — but every dir carries a - * `.project_root` text file with the absolute cwd to disambiguate). - * • Project list registry: `~/.gemini/projects.json` maps absolute cwd → - * basename. Authoritative when present, but we read each `.project_root` - * anyway so the dashboard tolerates partially-pruned registries. - * • Per-session file: `~/.gemini/tmp//chats/session--.jsonl`. - * A sidecar `.jsonl.tool-calls.json` may sit alongside. - * • File format: JSONL. First line is metadata - * `{sessionId, projectHash, startTime, lastUpdated, kind}`; subsequent - * lines are message records `{id, timestamp, type, content: [{text}]}` - * and `{$set: {...}}` partial updates. - * - * As with Cursor / Pi / OpenCode, this module is intentionally permissive — a - * missing `~/.gemini/` returns `[]`, malformed JSONL falls open without - * surfacing the session. - */ -import { open, readdir, readFile, stat } from "node:fs/promises"; -import { homedir } from "node:os"; -import { join } from "node:path"; -import type { ProjectFolder, SessionFile } from "./projects"; -import { runtimeCache } from "./runtime-cache"; -import { batchAll } from "./concurrency"; -import { formatDate } from "./format-date"; -import { encodeFolderName } from "./paths"; -import { logWarn } from "./logger"; - -/** Filename pattern for a Gemini session JSONL: - * `session--<8-hex-uuid-prefix>.jsonl`. */ -const SESSION_FILE_RE = /^session-(\d{4}-\d{2}-\d{2}T\d{2}-\d{2})-([0-9a-f]{8})\.jsonl$/i; -/** Full UUID — the filename only embeds the first 8 hex chars; the rest is on - * the JSONL metadata header line. The session detail route requires a full - * UUID, so links built from the truncated filename prefix 404. */ -const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; -/** Metadata header sits on line 1 and is well under 1 KB; 4 KB covers it - * comfortably without slurping a multi-MB transcript. */ -const FIRST_LINE_CHUNK_BYTES = 4 * 1024; - -/** Override for tests. Defaults to the live Gemini session-state root. */ -function getGeminiTmpRoot(): string { - return process.env.GEMINI_SESSIONS_DIR - || join(homedir(), ".gemini", "tmp"); -} - -interface GeminiSessionMeta { - filePath: string; - sessionFilename: string; - cwd: string; - fileMtime: Date; - /** Full UUID parsed from the JSONL metadata header (line 1). Undefined when - * the header is missing, malformed, or carries a non-UUID `sessionId`; - * callers fall through to rendering an un-linked row. */ - sessionId?: string; -} - -async function safeReaddir(dir: string) { - try { - return await readdir(dir, { withFileTypes: true }); - } catch { - return null; - } -} - -async function statMtime(path: string): Promise { - try { - return (await stat(path)).mtime; - } catch { - return null; - } -} - -/** Read the first newline-delimited line of `filePath` without slurping the - * rest. Mirrors `lib/codex-projects.ts`'s readFirstLine; the Gemini metadata - * header is always on line 1. */ -async function readFirstLine(filePath: string): Promise { - let fh: Awaited> | null = null; - try { - fh = await open(filePath, "r"); - const buf = Buffer.alloc(FIRST_LINE_CHUNK_BYTES); - const { bytesRead } = await fh.read(buf, 0, FIRST_LINE_CHUNK_BYTES, 0); - if (bytesRead === 0) return null; - const slice = buf.subarray(0, bytesRead); - const nl = slice.indexOf(0x0a); // '\n' - const end = nl === -1 ? bytesRead : nl; - return slice.subarray(0, end).toString("utf-8"); - } catch { - return null; - } finally { - if (fh) await fh.close().catch(() => {}); - } -} - -/** Extract a full-UUID `sessionId` from a JSONL metadata header line. Returns - * undefined on parse failure, missing field, or a non-UUID value. */ -function extractFullSessionId(line: string | null): string | undefined { - if (!line) return undefined; - try { - const meta = JSON.parse(line) as { sessionId?: unknown }; - if (typeof meta.sessionId !== "string") return undefined; - return UUID_RE.test(meta.sessionId) ? meta.sessionId : undefined; - } catch { - return undefined; - } -} - -/** Read `.project_root` to recover the absolute cwd for a basename folder. - * Returns null if missing or empty (caller treats the folder as un-mappable). */ -async function readProjectRoot(projectDir: string): Promise { - try { - const text = await readFile(join(projectDir, ".project_root"), "utf-8"); - const trimmed = text.trim(); - return trimmed.length > 0 ? trimmed : null; - } catch { - return null; - } -} - -async function scanGeminiSessions(): Promise { - const root = getGeminiTmpRoot(); - const projectDirs = await safeReaddir(root); - if (!projectDirs) return []; - - const out: GeminiSessionMeta[] = []; - - await batchAll( - projectDirs - .filter((d) => d.isDirectory()) - .map((d) => async () => { - const projectDir = join(root, d.name); - const cwd = await readProjectRoot(projectDir); - if (!cwd) return; - - const chatsDir = join(projectDir, "chats"); - const files = await safeReaddir(chatsDir); - if (!files) return; - - for (const f of files) { - if (!f.isFile()) continue; - if (!SESSION_FILE_RE.test(f.name)) continue; - const filePath = join(chatsDir, f.name); - const mtime = await statMtime(filePath); - if (!mtime) continue; - const sessionId = extractFullSessionId(await readFirstLine(filePath)); - out.push({ filePath, sessionFilename: f.name, cwd, fileMtime: mtime, sessionId }); - } - }), - 16, - ); - - return out; -} - -/** Returns one ProjectFolder per unique cwd that has at least one session file. - * `name` is the encoded full-cwd slug (`encodeFolderName(cwd)`), matching the - * routing scheme used by the dashboard's project URL — `mergeProjectFolders` - * unions by `name`, and `getGeminiSessionsByEncodedName` looks up by the same - * slug, so every cross-CLI merge and Gemini-only project link round-trips. */ -export async function getGeminiProjects(): Promise { - const sessions = await scanGeminiSessions(); - const byCwd = new Map(); - for (const s of sessions) { - const existing = byCwd.get(s.cwd); - if (!existing || s.fileMtime.getTime() > existing.mtime.getTime()) { - byCwd.set(s.cwd, { mtime: s.fileMtime }); - } - } - const folders: ProjectFolder[] = [...byCwd.entries()].map(([cwd, { mtime }]) => ({ - name: encodeFolderName(cwd), - path: cwd, - isDirectory: true, - lastModified: mtime, - lastModifiedFormatted: formatDate(mtime), - cli: ["gemini"], - })); - folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); - return folders; -} - -/** Returns SessionFile entries for the given absolute cwd. Empty if none. */ -export async function getGeminiSessionsForCwd(cwd: string): Promise { - const sessions = await scanGeminiSessions(); - const matches = sessions.filter((s) => s.cwd === cwd); - const files: SessionFile[] = matches.map((s) => ({ - name: s.sessionFilename, - path: s.filePath, - lastModified: s.fileMtime, - lastModifiedFormatted: formatDate(s.fileMtime), - sessionId: s.sessionId, - cli: "gemini", - })); - files.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); - return files; -} - -export interface GeminiProjectByName { - cwd: string | null; - sessions: SessionFile[]; -} - -/** - * Looks up Gemini sessions for a project URL slug. `decodeFolderName` is lossy - * on cwds containing `-`, so we re-encode each session's cwd via - * `encodeFolderName` and match in that direction. Returns both the canonical - * cwd and the matching sessions. When two distinct cwds collapse to the same - * encoded slug we return null to avoid mis-labeling the project. - */ -export async function getGeminiSessionsByEncodedName(name: string): Promise { - let metas: GeminiSessionMeta[]; - try { - metas = await scanGeminiSessions(); - } catch (error) { - logWarn("Failed to scan Gemini sessions:", error); - return { cwd: null, sessions: [] }; - } - const matches = metas.filter((m) => encodeFolderName(m.cwd) === name); - const uniqueCwds = Array.from(new Set(matches.map((m) => m.cwd))); - if (uniqueCwds.length !== 1) { - return { cwd: null, sessions: [] }; - } - const sessions = matches.map((s) => ({ - name: s.sessionFilename, - path: s.filePath, - lastModified: s.fileMtime, - lastModifiedFormatted: formatDate(s.fileMtime), - sessionId: s.sessionId, - cli: "gemini" as const, - })); - sessions.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); - return { cwd: uniqueCwds[0], sessions }; -} - -export const getCachedGeminiProjects = runtimeCache(getGeminiProjects, 30); -export const getCachedGeminiSessionsByEncodedName = runtimeCache( - (name: string) => getGeminiSessionsByEncodedName(name), - 30, - { maxSize: 50 }, -); diff --git a/lib/gemini-sessions.ts b/lib/gemini-sessions.ts deleted file mode 100644 index 601aa034..00000000 --- a/lib/gemini-sessions.ts +++ /dev/null @@ -1,365 +0,0 @@ -/** - * Gemini CLI session transcript discovery + JSONL parser. - * - * Empirically verified against gemini-cli v0.40.1: - * - * Session files live at - * `~/.gemini/tmp//chats/session--<8-hex-uuid-prefix>.jsonl` - * with a sidecar `.jsonl.tool-calls.json` of tool-call records. - * The basename component is just the cwd's last path segment; the canonical - * cwd lives at `~/.gemini/tmp//.project_root`. - * - * JSONL record schema (observed): - * • Line 1 (metadata): `{sessionId, projectHash, startTime, lastUpdated, kind}` - * • Subsequent lines: - * `{id, timestamp, type: "user" | "assistant" | ..., content: [{text}]}` (messages) - * `{$set: {lastUpdated: "..."}}` (partial update) - * - * Parser is intentionally permissive — unknown record types degrade to - * "system" entries; malformed lines are skipped without aborting; and the - * loader fall-opens (returns null) on any I/O or parse failure. - */ -import { closeSync, openSync, readFileSync, readSync, readdirSync, existsSync, statSync } from "node:fs"; -import { readFile } from "node:fs/promises"; -import { join, resolve, sep } from "node:path"; -import { homedir } from "node:os"; -import { runtimeCache } from "./runtime-cache"; -import { - baseEntry, - type LogEntry, - type UserEntry, - type AssistantEntry, - type GenericEntry, - type QueueOperationEntry, - type ContentBlock, - type LogSource, -} from "./log-entries"; - -// ── Paths ── - -const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; -/** Matches `session--<8-hex-uuid-prefix>.jsonl`. - * Empirically gemini-cli v0.40.1 emits minute-precision (`YYYY-MM-DDTHH-mm`), - * but the documented format includes seconds (`YYYY-MM-DDTHH-mm:ss`) and may - * evolve further. The first-line `sessionId` validation in findGeminiTranscript - * is the load-bearing safety check, so we accept any timestamp shape. */ -const SESSION_FILE_RE = /^session-(.+)-([0-9a-f]{8})\.jsonl$/i; - -/** Root directory for Gemini session state, honoring GEMINI_SESSIONS_DIR. */ -export function getGeminiSessionStateRoot(): string { - return process.env.GEMINI_SESSIONS_DIR - || join(homedir(), ".gemini", "tmp"); -} - -/** Reject a sessionId that isn't a UUID — defends against path traversal. */ -function isSafeSessionId(sessionId: string): boolean { - return UUID_RE.test(sessionId); -} - -/** - * Read up to the first newline from `path` without loading the whole file. - * Used by `findGeminiTranscript` to inspect the JSONL metadata header on - * candidate matches; the typical header is well under 1KB and we cap at 4KB - * for safety so a degenerate single-line file can't blow memory. - * - * Returns the first line as a UTF-8 string, or null on read failure / empty - * file. If the first 4KB contain no newline, returns whatever was read so the - * JSON.parse caller can still attempt — JSON.parse will fail for a truncated - * object, which findGeminiTranscript treats as a malformed-header miss. - */ -function readFirstLineSync(path: string): string | null { - let fd: number; - try { - fd = openSync(path, "r"); - } catch { - return null; - } - try { - const buf = Buffer.alloc(4096); - const bytesRead = readSync(fd, buf, 0, buf.length, 0); - if (bytesRead === 0) return null; - const text = buf.subarray(0, bytesRead).toString("utf-8"); - const nl = text.indexOf("\n"); - return nl >= 0 ? text.slice(0, nl) : text; - } catch { - return null; - } finally { - try { closeSync(fd); } catch { /* best-effort */ } - } -} - -/** - * Find the JSONL transcript for `sessionId`. Walks every per-project subdir's - * `chats/` directory, matches the 8-hex prefix, and verifies the first record's - * full `sessionId` field matches. Rejects path-traversal sessionIds and - * verifies resolved paths stay under the root. Returns null on miss. - */ -export function findGeminiTranscript(sessionId: string): string | null { - if (!isSafeSessionId(sessionId)) return null; - const root = resolve(getGeminiSessionStateRoot()); - const wantPrefix = sessionId.slice(0, 8).toLowerCase(); - - let projectDirs: string[]; - try { - projectDirs = readdirSync(root); - } catch { - return null; - } - - for (const projectDir of projectDirs) { - const projectPath = resolve(root, projectDir); - if (!projectPath.startsWith(`${root}${sep}`)) continue; - - const chatsDir = resolve(projectPath, "chats"); - let files: string[]; - try { - files = readdirSync(chatsDir); - } catch { - continue; - } - - for (const f of files) { - const m = SESSION_FILE_RE.exec(f); - if (!m || m[2].toLowerCase() !== wantPrefix) continue; - const candidate = resolve(chatsDir, f); - if (!candidate.startsWith(`${chatsDir}${sep}`)) continue; - if (!existsSync(candidate)) continue; - // Confirm the full sessionId — the 8-hex prefix isn't unique on its own. - // Read only the first ~4KB so large transcripts don't bloat memory; the - // metadata header sits on line 1 well within that bound. The full file - // is re-read in getGeminiSessionLog() once we've matched. - const firstLine = readFirstLineSync(candidate); - if (!firstLine) continue; - try { - const meta = JSON.parse(firstLine) as { sessionId?: unknown }; - if (typeof meta.sessionId === "string" && meta.sessionId.toLowerCase() === sessionId.toLowerCase()) { - return candidate; - } - } catch { - // Malformed first record — try next file. - continue; - } - } - } - return null; -} - -// ── Parser ── - -interface GeminiSessionRecord { - // Metadata-line fields (line 1) - sessionId?: string; - projectHash?: string; - startTime?: string; - lastUpdated?: string; - kind?: string; - // Message-line fields - id?: string; - timestamp?: string; - type?: string; - content?: Array>; - // Partial-update line: `{$set: {...}}` - $set?: Record; -} - -interface GeminiParseResult { - entries: LogEntry[]; - rawLines: Record[]; - /** Working directory pulled from the sidecar `.project_root` if available. */ - cwd?: string; -} - -function extractMessageText(content: Array> | undefined): string { - if (!Array.isArray(content)) return ""; - const parts: string[] = []; - for (const block of content) { - if (typeof block?.text === "string") parts.push(block.text); - } - return parts.join("\n\n"); -} - -function buildAssistantContent(content: Array> | undefined): ContentBlock[] { - if (!Array.isArray(content)) return []; - const blocks: ContentBlock[] = []; - for (const block of content) { - if (typeof block?.text === "string" && block.text.length > 0) { - blocks.push({ type: "text", text: block.text }); - } - } - return blocks; -} - -/** - * Parse a Gemini JSONL transcript into `LogEntry[]` plus the raw lines. - * Yields to the event loop every 200 lines so big transcripts don't block - * the request. - */ -export async function parseGeminiLog( - fileContent: string, - source: LogSource = "session", - cwdHint?: string, -): Promise { - const lines = fileContent.split("\n").filter((line) => line.trim() !== ""); - const entries: LogEntry[] = []; - const rawLines: Record[] = []; - let cwd: string | undefined = cwdHint; - let seenStart = false; - - for (let i = 0; i < lines.length; i++) { - if (i > 0 && i % 200 === 0) await new Promise((r) => setImmediate(r)); - - const line = lines[i]; - let raw: GeminiSessionRecord; - try { - raw = JSON.parse(line) as GeminiSessionRecord; - } catch { - continue; - } - - const rawCopy = { ...(raw as Record), _source: source }; - rawLines.push(rawCopy); - - // Metadata line — derive a synthetic "Session Started" entry from startTime. - if (typeof raw.sessionId === "string" && typeof raw.startTime === "string") { - const date = new Date(raw.startTime); - if (!Number.isNaN(date.getTime())) { - const label: QueueOperationEntry["label"] = seenStart ? "Session Resumed" : "Session Started"; - seenStart = true; - entries.push({ - type: "queue-operation", - ...baseEntry(rawCopy, date.toISOString(), date, source), - label, - } satisfies QueueOperationEntry); - } - continue; - } - - // Partial-update line — preserve in raw but skip rendering. - if (raw.$set) continue; - - const timestampStr = raw.timestamp; - if (!timestampStr) continue; - const date = new Date(timestampStr); - if (Number.isNaN(date.getTime())) continue; - const timestamp = date.toISOString(); - - const recType = raw.type; - - if (recType === "user") { - const text = extractMessageText(raw.content); - if (!text) continue; - entries.push({ - type: "user", - ...baseEntry(rawCopy, timestamp, date, source), - message: { role: "user", content: text }, - } satisfies UserEntry); - continue; - } - - if (recType === "assistant" || recType === "model") { - const blocks = buildAssistantContent(raw.content); - if (blocks.length === 0) { - entries.push({ - type: "system", - ...baseEntry(rawCopy, timestamp, date, source), - raw: rawCopy, - } satisfies GenericEntry); - continue; - } - entries.push({ - type: "assistant", - ...baseEntry(rawCopy, timestamp, date, source), - message: { role: "assistant", content: blocks }, - } satisfies AssistantEntry); - continue; - } - - // Unknown type — preserve raw. - entries.push({ - type: "system", - ...baseEntry(rawCopy, timestamp, date, source), - raw: rawCopy, - } satisfies GenericEntry); - } - - if (entries.length > 500) await new Promise((r) => setImmediate(r)); - entries.sort((a, b) => a.timestampMs - b.timestampMs); - - return { entries, rawLines, cwd }; -} - -// ── Public loader ── - -export interface GeminiSessionLogData { - entries: LogEntry[]; - rawLines: Record[]; - cwd?: string; - filePath: string; -} - -/** Read `.project_root` next to the chats dir to recover the absolute cwd. */ -function readSiblingProjectRoot(transcriptPath: string): string | undefined { - // transcriptPath = ...//chats/.jsonl - const chatsDir = resolve(transcriptPath, ".."); - const projectDir = resolve(chatsDir, ".."); - const rootFile = join(projectDir, ".project_root"); - try { - const text = readFileSync(rootFile, "utf-8").trim(); - return text.length > 0 ? text : undefined; - } catch { - return undefined; - } -} - -export async function getGeminiSessionLog(sessionId: string): Promise { - const filePath = findGeminiTranscript(sessionId); - if (!filePath) return null; - let fileContent: string; - try { - fileContent = await readFile(filePath, "utf-8"); - } catch { - return null; - } - const cwdHint = readSiblingProjectRoot(filePath); - let parsed: GeminiParseResult; - try { - parsed = await parseGeminiLog(fileContent, "session", cwdHint); - } catch { - return null; - } - return { - entries: parsed.entries, - rawLines: parsed.rawLines, - cwd: parsed.cwd, - filePath, - }; -} - -export const getCachedGeminiSessionLog = runtimeCache( - (sessionId: string) => getGeminiSessionLog(sessionId), - 60, - { maxSize: 50 }, -); - -// ── Test helpers ── - -export function _statGeminiTranscript(sessionId: string): { mtimeMs: number } | null { - const path = findGeminiTranscript(sessionId); - if (!path) return null; - try { - const s = statSync(path); - return { mtimeMs: s.mtimeMs }; - } catch { - return null; - } -} - -export function readGeminiTranscriptSync(sessionId: string): string | null { - const path = findGeminiTranscript(sessionId); - if (!path) return null; - try { - return readFileSync(path, "utf-8"); - } catch { - return null; - } -} diff --git a/lib/goose-projects.ts b/lib/goose-projects.ts new file mode 100644 index 00000000..20c8f57e --- /dev/null +++ b/lib/goose-projects.ts @@ -0,0 +1,148 @@ +/** + * Goose (codename goose, Block) session enumeration — AUDIT-ONLY. + * + * Reads the `sessions` table directly from + * `~/.local/share/goose/sessions/sessions.db` via the bundled sql.js reader. + * Like Devin (and unlike the cwd-less Hermes gateway), each Goose session + * carries a real `working_dir`, so Goose sessions group by project cwd like + * Claude/Factory/Devin — one `ProjectFolder` per encoded cwd, and a cwd present + * in multiple stores merges on the shared encoded slug (see `mergeProjectFolders` + * in lib/projects.ts). + * + * `session_type = 'hidden'` rows are `goose run --no-session` scratch runs and + * are excluded (mirrors Devin's `hidden` filter). + */ +import { openSqliteReadonly } from "./sqlite-reader"; +import { gooseDbPath, gooseTimestampToMs } from "./goose-sessions"; +import { encodeFolderName } from "./paths"; +import { runtimeCache } from "./runtime-cache"; +import type { ProjectFolder, SessionFile } from "./projects"; +import { formatDate } from "./format-date"; + +export interface GooseSessionRef { + sessionId: string; + cwd?: string; + title?: string; + /** Encoded-cwd folder slug (matches Claude's `-home-user-project` scheme). */ + projectName: string; + /** From `updated_at` (falls back to `created_at`) — epoch ms. */ + mtimeMs: number; +} + +interface SessionRow { + id: string; + working_dir: string | null; + description: string | null; + name: string | null; + session_type: string | null; + created_at: string | null; + updated_at: string | null; +} + +/** + * List every Goose session. Returns `[]` when the DB is missing or unreadable + * (fail-open — the audit just skips Goose). `hidden` (no-session) rows are + * excluded. + */ +export async function getGooseSessions(): Promise { + const db = await openSqliteReadonly(gooseDbPath()); + if (!db) return []; + try { + const rows = db.query( + "SELECT id, working_dir, description, name, session_type, created_at, updated_at " + + "FROM sessions ORDER BY updated_at DESC", + ); + return rows + .filter((r) => r.session_type !== "hidden") + .map((r) => { + const cwd = r.working_dir ?? undefined; + const title = (r.description && r.description.length > 0 ? r.description : r.name) ?? undefined; + return { + sessionId: r.id, + cwd, + title: title && title.length > 0 ? title : undefined, + projectName: cwd ? encodeFolderName(cwd) : "goose", + mtimeMs: gooseTimestampToMs(r.updated_at ?? r.created_at), + }; + }); + } catch { + return []; + } finally { + db.close(); + } +} + +export const getCachedGooseSessions = runtimeCache(getGooseSessions, 2); + +// ── Dashboard history browser (projects list + project-detail sessions) ── + +/** One `ProjectFolder` per encoded-cwd discovered in the Goose DB. */ +export async function getGooseProjects(): Promise { + const sessions = await getGooseSessions(); + const byName = new Map(); + for (const s of sessions) { + if (!s.cwd) continue; + const existing = byName.get(s.projectName); + if (!existing || s.mtimeMs > existing.latest) { + byName.set(s.projectName, { latest: s.mtimeMs, cwd: s.cwd, name: s.projectName }); + } + } + const folders: ProjectFolder[] = []; + for (const { name, cwd, latest } of byName.values()) { + const lastModified = new Date(latest); + folders.push({ + name, + path: cwd, + isDirectory: true, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + cli: ["goose"], + }); + } + folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); + return folders; +} + +export interface GooseProjectByName { + /** Canonical cwd recovered from the session's `working_dir`. */ + cwd: string | null; + sessions: SessionFile[]; +} + +/** + * Resolve the Goose sessions for a project URL slug (the encoded-cwd folder + * name). Goose's `working_dir` re-encodes to the same slug Claude uses, so the + * slug matches directly and the canonical cwd is the session's real + * `working_dir`. + */ +export async function getGooseSessionsByEncodedName( + name: string, +): Promise { + const sessions = await getGooseSessions(); + const matched = sessions.filter((s) => s.cwd && s.projectName === name); + if (matched.length === 0) return { cwd: null, sessions: [] }; + + const sorted = [...matched].sort((a, b) => b.mtimeMs - a.mtimeMs); + const cwd = sorted[0].cwd ?? null; + return { + cwd, + sessions: sorted.map((s) => { + const lastModified = new Date(s.mtimeMs); + return { + name: s.title ?? s.sessionId, + path: `goose-db://${s.sessionId}`, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + sessionId: s.sessionId, + cli: "goose" as const, + }; + }), + }; +} + +export const getCachedGooseProjects = runtimeCache(getGooseProjects, 2); +export const getCachedGooseSessionsByEncodedName = runtimeCache( + (name: string) => getGooseSessionsByEncodedName(name), + 2, + { maxSize: 50 }, +); diff --git a/lib/goose-sessions.ts b/lib/goose-sessions.ts new file mode 100644 index 00000000..222cc646 --- /dev/null +++ b/lib/goose-sessions.ts @@ -0,0 +1,296 @@ +/** + * Goose (codename goose, Block) session transcript loader + parser. + * + * AUDIT-ONLY (Pillar 2). Goose (≥ v1.10.0) stores every session in one SQLite DB + * at `~/.local/share/goose/sessions/sessions.db`. We read it DIRECTLY via the + * bundled sql.js driver (lib/sqlite-reader.ts) — the same reusable path + * Devin/Hermes/OpenClaw use. Like Devin (and unlike the cwd-less Hermes gateway), + * each Goose `sessions` row carries a real `working_dir`, so Goose sessions group + * by project cwd like Claude/Factory/Devin. + * + * Schema (verified live against goose v1.43.0, schema_version 15): + * sessions(id TEXT `YYYYMMDD_N`, name, description, session_type + * (user|hidden|subagent|scheduled|terminal|acp), working_dir, + * created_at TIMESTAMP, updated_at TIMESTAMP, total_tokens, …) + * messages(id INTEGER PK, session_id, role (user|assistant), + * content_json TEXT=JSON-array-of-blocks, created_timestamp INT, …) + * + * `content_json` is a Claude-style typed-block array (NOT OpenAI-style like + * Devin): `{type:"text",text}`, `{type:"toolRequest",id,toolCall:{value:{name, + * arguments}},_meta:{goose_extension}}`, and `{type:"toolResponse",id,toolResult: + * {value:{content:[{type:"text",text}],isError}}}`. Tool RESULTS are stored in + * `role:"user"` rows (Claude convention). `gooseRowsToLogEntries` pairs each + * toolRequest with its later toolResponse by id and is a PURE function of the + * parsed rows, so it is unit-testable without a DB. + * + * `session_type = 'hidden'` rows are `goose run --no-session` scratch runs — the + * enumerator (lib/goose-projects.ts) filters them out. + * + * Home override: set `GOOSE_HOME` (the data dir that contains `sessions/`, used + * by tests) or `GOOSE_DB_PATH` (points directly at a sessions.db). + */ +import { homedir } from "node:os"; +import { join } from "node:path"; +import { openSqliteReadonly } from "./sqlite-reader"; +import { runtimeCache } from "./runtime-cache"; +import { + baseEntry, + formatTimestamp, + type LogEntry, + type UserEntry, + type AssistantEntry, + type GenericEntry, + type ContentBlock, + type ToolUseBlock, + type LogSource, +} from "./log-entries"; +import { formatDuration } from "./format-duration"; + +/** Goose session IDs are date-prefixed counters, e.g. `20260714_3`. */ +export const GOOSE_SESSION_ID_RE = /^\d{8}_\d+$/; + +/** Absolute path to Goose's data home (override with GOOSE_HOME; respects + * XDG_DATA_HOME otherwise). */ +export function gooseHome(): string { + if (process.env.GOOSE_HOME) return process.env.GOOSE_HOME; + const xdg = process.env.XDG_DATA_HOME; + return join(xdg && xdg.length > 0 ? xdg : join(homedir(), ".local", "share"), "goose"); +} + +/** Absolute path to Goose's SQLite DB (override with GOOSE_DB_PATH). */ +export function gooseDbPath(): string { + return process.env.GOOSE_DB_PATH || join(gooseHome(), "sessions", "sessions.db"); +} + +/** Coerce a Goose timestamp to epoch ms. `messages.created_timestamp` is an + * INTEGER epoch (seconds or ms); `sessions.created_at`/`updated_at` are SQLite + * `CURRENT_TIMESTAMP` strings ("YYYY-MM-DD HH:MM:SS", UTC). */ +export function gooseTimestampToMs(value: unknown): number { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return value; // already ms + if (value > 1e9) return value * 1000; // seconds + } + if (typeof value === "string" && value.length > 0) { + // SQLite CURRENT_TIMESTAMP has no zone and is UTC — normalize to ISO-Z so + // Date.parse doesn't treat it as local time. + const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value) + ? value.replace(" ", "T") + "Z" + : value; + const ms = Date.parse(iso); + if (!Number.isNaN(ms)) return ms; + } + return Date.now(); +} + +// ── Parsing helpers ── + +function safeJsonParse(s: unknown): unknown { + if (typeof s !== "string" || s.length === 0) return undefined; + try { + return JSON.parse(s); + } catch { + return undefined; + } +} + +function isPlainObject(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); +} + +/** Text from a `content` field that may be a string or an array of + * `{ type:"text", text }` blocks. */ +function extractText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : "")) + .filter(Boolean) + .join("\n"); + } + return ""; +} + +function toDate(value: unknown, fallbackMs: number): Date { + const ms = typeof value === "number" || typeof value === "string" ? gooseTimestampToMs(value) : NaN; + return Number.isNaN(ms) ? new Date(fallbackMs) : new Date(ms); +} + +/** Pull `{ id, name, input }` from a Goose `toolRequest` block: + * `{id, toolCall:{status, value:{name, arguments}}}`. */ +function extractToolRequest( + block: Record, + idx: number, +): { id: string; name: string; input: Record } { + const id = typeof block.id === "string" && block.id ? block.id : `goose-tool-${idx}`; + const toolCall = isPlainObject(block.toolCall) ? block.toolCall : {}; + const value = isPlainObject(toolCall.value) ? toolCall.value : {}; + const name = typeof value.name === "string" ? value.name : "tool"; + const input = isPlainObject(value.arguments) ? value.arguments : {}; + return { id, name, input }; +} + +/** Text of a Goose `toolResponse` block: + * `{id, toolResult:{status, value:{content:[{type:"text",text}], …}}}`. */ +function extractToolResult(block: Record): string { + const toolResult = isPlainObject(block.toolResult) ? block.toolResult : {}; + const value = toolResult.value; + if (isPlainObject(value) && Array.isArray(value.content)) return extractText(value.content); + if (typeof value === "string") return value; + if (Array.isArray(value)) return extractText(value); + return ""; +} + +// ── Pure parser: message rows → LogEntry[] ── + +export interface GooseMessageRow { + role: string | null; + content_json: string | null; + created_timestamp: number | null; +} + +/** + * Convert Goose `messages` rows (in insertion order) into `LogEntry[]`. Each + * row's `content_json` is a typed-block array; `toolRequest` blocks become + * `tool_use` blocks on an assistant entry, and later `toolResponse` blocks + * (which arrive in `role:"user"` rows) attach as the matching tool_use's result + * by id. Pure — unit-testable with plain rows. + */ +export function gooseRowsToLogEntries( + rows: GooseMessageRow[], + source: LogSource = "session", +): LogEntry[] { + const entries: LogEntry[] = []; + const toolUseById = new Map(); + const toolUseStartMs = new Map(); + const baseMs = Date.now(); + + for (let i = 0; i < rows.length; i++) { + const r = rows[i]; + const parsed = safeJsonParse(r.content_json); + if (!Array.isArray(parsed)) continue; + + const role = typeof r.role === "string" ? r.role : "system"; + const date = toDate(r.created_timestamp, baseMs + i); + const timestamp = date.toISOString(); + const raw: Record = { uuid: `goose-${i}`, parentUuid: null }; + const base = baseEntry(raw, timestamp, date, source); + + const textParts: string[] = []; + const toolReqs: Record[] = []; + const toolResps: Record[] = []; + for (const b of parsed) { + if (!isPlainObject(b)) continue; + if (b.type === "text" && typeof b.text === "string") textParts.push(b.text); + else if (b.type === "toolRequest") toolReqs.push(b); + else if (b.type === "toolResponse") toolResps.push(b); + } + + // Attach tool results to their earlier tool_use blocks (results arrive in + // role:"user" rows, so this runs before we consider the row a user turn). + for (const tr of toolResps) { + const callId = typeof tr.id === "string" ? tr.id : undefined; + const block = callId ? toolUseById.get(callId) : undefined; + if (!block) continue; + const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime(); + const durationMs = Math.max(0, date.getTime() - startMs); + block.result = { + timestamp, + timestampFormatted: formatTimestamp(date), + content: extractToolResult(tr), + durationMs, + durationFormatted: formatDuration(durationMs), + }; + } + + const text = textParts.join("\n").trim(); + + if (toolReqs.length > 0 || (role === "assistant" && text)) { + const blocks: ContentBlock[] = []; + if (text) blocks.push({ type: "text", text }); + for (const req of toolReqs) { + const { id, name, input } = extractToolRequest(req, blocks.length); + const block: ToolUseBlock = { type: "tool_use", id, name, input }; + blocks.push(block); + toolUseById.set(id, block); + toolUseStartMs.set(id, date.getTime()); + } + if (blocks.length === 0) continue; + entries.push({ + type: "assistant", + ...base, + message: { role: "assistant", content: blocks }, + } satisfies AssistantEntry); + continue; + } + + if (role === "user" && text) { + entries.push({ + type: "user", + ...base, + message: { role: "user", content: text }, + } satisfies UserEntry); + continue; + } + + // Pure tool-result rows (no text, no requests) produced no new entry above. + if (text) { + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + } + + entries.sort((a, b) => a.timestampMs - b.timestampMs); + return entries; +} + +// ── DB loader ── + +export interface GooseSessionLogData { + entries: LogEntry[]; + rawLines: Record[]; + cwd?: string; + filePath: string; // synthetic — goose keeps sessions in a DB; we use goose-db:// +} + +/** + * Load one session by ID from `sessions.db`. Returns `null` when the DB is + * unavailable or the session doesn't exist. + */ +export async function getGooseSessionLog( + sessionId: string, +): Promise { + if (!sessionId || !GOOSE_SESSION_ID_RE.test(sessionId)) return null; + const db = await openSqliteReadonly(gooseDbPath()); + if (!db) return null; + try { + const sessionRows = db.query<{ working_dir: string | null }>( + "SELECT working_dir FROM sessions WHERE id = ?", + [sessionId], + ); + if (sessionRows.length === 0) return null; + const realCwd = sessionRows[0].working_dir; + + const msgRows = db.query( + "SELECT role, content_json, created_timestamp FROM messages " + + "WHERE session_id = ? ORDER BY id ASC", + [sessionId], + ); + const entries = gooseRowsToLogEntries(msgRows, "session"); + const cwd = realCwd && realCwd.length > 0 ? realCwd : undefined; + return { + entries, + rawLines: msgRows as unknown as Record[], + cwd, + filePath: `goose-db://${sessionId}`, + }; + } catch { + return null; + } finally { + db.close(); + } +} + +export const getCachedGooseSessionLog = runtimeCache( + (sessionId: string) => getGooseSessionLog(sessionId), + 2, + { maxSize: 50 }, +); diff --git a/lib/openclaw-projects.ts b/lib/openclaw-projects.ts new file mode 100644 index 00000000..18ed6036 --- /dev/null +++ b/lib/openclaw-projects.ts @@ -0,0 +1,182 @@ +/** + * OpenClaw (openclaw gateway) session enumeration — AUDIT-ONLY. + * + * Surfaces the on-disk transcripts (agents//sessions/.jsonl) as + * synthetic dashboard "projects" grouped by agentId. The per-agent + * `sessions.json` index maps sessionKey → {sessionId, timestamps}; we read it to + * recover the sessionKey (which encodes the channel for gateway sessions) and a + * reliable last-activity time. Verified live against openclaw v2026.7.1. + */ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; +import { runtimeCache } from "./runtime-cache"; +import { listOpenClawTranscripts, openclawHome } from "./openclaw-sessions"; +import type { ProjectFolder, SessionFile } from "./projects"; +import { formatDate } from "./format-date"; + +export interface OpenClawSessionRef { + sessionId: string; + agentId: string; + /** Channel/source the session last ran in (from sessions.json metadata) — + * e.g. "telegram", "slack", or "local" for a CLI session. Drives grouping. */ + channel: string; + /** Human-readable label from `origin.label` (e.g. "Chetan (@chhhee10) id:…"). */ + label?: string; + /** Chat id (e.g. "telegram:8674922496") + type ("direct"/"group") for the + * gateway-metadata columns. */ + chatId?: string; + chatType?: string; + mtimeMs: number; + sizeBytes: number; +} + +interface SessionIndexMeta { + lastMs?: number; + channel?: string; + chatType?: string; + label?: string; + chatId?: string; +} + +function str(v: unknown): string | undefined { + return typeof v === "string" && v.length > 0 ? v : undefined; +} + +/** Read the per-agent sessions.json index → sessionId → routing metadata. + * OpenClaw routes gateway sessions through the agent's default key + * (`agent::main`) and records the channel in metadata fields + * (`lastChannel`, `chatType`, `origin.{label,provider,from}`, `lastTo`) rather + * than in the key — verified live against v2026.7.1. */ +function readSessionsIndex(agentId: string): Map { + const out = new Map(); + const indexPath = join(openclawHome(), "agents", agentId, "sessions", "sessions.json"); + let raw: unknown; + try { + raw = JSON.parse(readFileSync(indexPath, "utf-8")); + } catch { + return out; + } + if (!raw || typeof raw !== "object") return out; + for (const v of Object.values(raw as Record)) { + if (!v || typeof v !== "object") continue; + const e = v as Record; + const sessionId = str(e.sessionId); + if (!sessionId) continue; + const origin = (e.origin && typeof e.origin === "object" ? e.origin : {}) as Record; + const lastMs = + typeof e.lastInteractionAt === "number" + ? e.lastInteractionAt + : typeof e.updatedAt === "number" + ? (e.updatedAt as number) + : undefined; + out.set(sessionId, { + lastMs, + channel: str(e.lastChannel) ?? str(origin.provider) ?? str(origin.surface), + chatType: str(e.chatType) ?? str(origin.chatType), + label: str(origin.label), + chatId: str(e.lastTo) ?? str(origin.from), + }); + } + return out; +} + +/** List every OpenClaw session across all agents. Fail-open ([] on any error). */ +export async function getOpenClawSessions(): Promise { + const transcripts = listOpenClawTranscripts(); + const indexByAgent = new Map>(); + const refs: OpenClawSessionRef[] = []; + for (const t of transcripts) { + let idx = indexByAgent.get(t.agentId); + if (!idx) { + idx = readSessionsIndex(t.agentId); + indexByAgent.set(t.agentId, idx); + } + const meta = idx.get(t.sessionId); + refs.push({ + sessionId: t.sessionId, + agentId: t.agentId, + // Gateway sessions group by channel; CLI/local runs have none. + channel: meta?.channel ?? "local", + label: meta?.label, + chatType: meta?.chatType, + chatId: meta?.chatId, + mtimeMs: meta?.lastMs ?? t.mtimeMs, + sizeBytes: t.sizeBytes, + }); + } + refs.sort((a, b) => b.mtimeMs - a.mtimeMs); + return refs; +} + +export const getCachedOpenClawSessions = runtimeCache(getOpenClawSessions, 2); + +// ── Dashboard history browser (projects list + project-detail sessions) ── + +/** + * Surface OpenClaw sessions as synthetic "projects" grouped by **channel** + * (telegram/slack/…/local) — gateway sessions run per channel, not in a host + * repo. Mirrors Hermes's group-by-source. One ProjectFolder per channel; its + * `name` is `openclaw-`, reversed in `getOpenClawSessionsByEncodedName`. + */ +export async function getOpenClawProjects(): Promise { + const sessions = await getOpenClawSessions(); + const latestByChannel = new Map(); + for (const s of sessions) { + latestByChannel.set(s.channel, Math.max(latestByChannel.get(s.channel) ?? 0, s.mtimeMs)); + } + const out: ProjectFolder[] = []; + for (const [channel, latest] of latestByChannel) { + const lastModified = new Date(latest); + out.push({ + name: `openclaw-${channel}`, + path: `openclaw:${channel}`, + isDirectory: true, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + cli: ["openclaw"], + }); + } + out.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime()); + return out; +} + +export interface OpenClawProjectByName { + cwd: string | null; + sessions: SessionFile[]; +} + +/** Resolve the OpenClaw sessions for a synthetic project name + * (`openclaw-`), for the project-detail page. Session names use the + * human-readable `origin.label` (e.g. "Chetan (@chhhee10) id:…") rather than + * the raw session key. */ +export async function getOpenClawSessionsByEncodedName( + name: string, +): Promise { + if (!name.startsWith("openclaw-")) return { cwd: null, sessions: [] }; + const channel = name.slice("openclaw-".length); + const sessions = await getOpenClawSessions(); + const matched = sessions.filter((s) => s.channel === channel); + return { + cwd: `openclaw:${channel}`, + sessions: matched.map((s) => { + const lastModified = new Date(s.mtimeMs); + return { + name: s.label ?? s.chatId ?? s.sessionId, + path: s.sessionId, + lastModified, + lastModifiedFormatted: formatDate(lastModified), + sessionId: s.sessionId, + cli: "openclaw" as const, + channelId: s.chatId, + channelType: s.chatType, + }; + }), + }; +} + +export const getCachedOpenClawProjects = runtimeCache(getOpenClawProjects, 2); +export const getCachedOpenClawSessionsByEncodedName = runtimeCache( + (name: string) => getOpenClawSessionsByEncodedName(name), + 2, + { maxSize: 50 }, +); diff --git a/lib/openclaw-sessions.ts b/lib/openclaw-sessions.ts new file mode 100644 index 00000000..fdebd2d3 --- /dev/null +++ b/lib/openclaw-sessions.ts @@ -0,0 +1,284 @@ +/** + * OpenClaw (openclaw gateway) session transcript loader + parser. + * + * AUDIT-ONLY (Pillar 2). OpenClaw writes one JSONL transcript per session at + * `~/.openclaw/agents//sessions/.jsonl` (sessionId is a + * UUID), alongside a much larger `.trajectory.jsonl` OTel trace we + * IGNORE, and a `sessions.json` index keyed by sessionKey. Verified live + * against openclaw v2026.7.1. + * + * The transcript is type-discriminated JSONL: + * {type:"session", cwd, …} — header (carries cwd) + * {type:"model_change" | "thinking_level_change" | "custom", …} — metadata + * {type:"message", timestamp, message:{role, content, …}} — the turns, where + * role ∈ "user" (content string) | "assistant" (content = list of + * {type:"text",text} / {type:"toolCall", id, name, arguments}) | + * "toolResult" ({toolCallId, toolName, content, details, isError}). + * `openclawLinesToLogEntries` pairs each assistant `toolCall` with its later + * `toolResult` by `toolCallId` (mirrors lib/hermes-sessions.ts) and is PURE, so + * it is unit-testable with plain line objects. + * + * Home override: set `OPENCLAW_HOME` (used by tests / to point at a copied + * gateway config dir). + */ +import { readFile } from "node:fs/promises"; +import { readdirSync, statSync } from "node:fs"; +import { homedir } from "node:os"; +import { join } from "node:path"; +import { runtimeCache } from "./runtime-cache"; +import { + baseEntry, + formatTimestamp, + parseRawLines, + type LogEntry, + type UserEntry, + type AssistantEntry, + type GenericEntry, + type ContentBlock, + type ToolUseBlock, + type LogSource, +} from "./log-entries"; +import { formatDuration } from "./format-duration"; + +/** OpenClaw sessions are stored under UUID filenames. */ +export const OPENCLAW_SESSION_ID_RE = /^[0-9a-fA-F-]{36}$/; + +/** Absolute path to OpenClaw's config home (override with OPENCLAW_HOME). */ +export function openclawHome(): string { + return process.env.OPENCLAW_HOME || join(homedir(), ".openclaw"); +} + +// ── Parsing helpers ── + +function isPlainObject(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); +} + +/** Text from a `content` field that may be a string or an array of + * `{ type:"text", text }` blocks. */ +function extractText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : "")) + .filter(Boolean) + .join("\n"); + } + return ""; +} + +function toDate(value: unknown, fallbackMs: number): Date { + if (typeof value === "number" && Number.isFinite(value)) { + if (value > 1e12) return new Date(value); + if (value > 1e9) return new Date(value * 1000); + } + if (typeof value === "string") { + const ms = Date.parse(value); + if (!Number.isNaN(ms)) return new Date(ms); + } + return new Date(fallbackMs); +} + +// ── Pure parser: transcript lines → LogEntry[] ── + +/** + * Convert OpenClaw transcript JSONL lines (parsed objects, in file order) into + * `LogEntry[]`. Only `type:"message"` lines carry turns; `session` / + * `model_change` / `thinking_level_change` / `custom` lines are metadata and + * are skipped (they'd otherwise clutter the audit with empty system entries). + * Assistant `toolCall` blocks are paired with their later `toolResult` message + * by `toolCallId`. Pure — unit-testable with plain line objects. + */ +export function openclawLinesToLogEntries( + lines: Record[], + source: LogSource = "session", +): LogEntry[] { + const entries: LogEntry[] = []; + const toolUseById = new Map(); + const toolUseStartMs = new Map(); + const baseMs = Date.now(); + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (!isPlainObject(line)) continue; + if (line.type !== "message") continue; // skip session/model_change/custom/… + + const m = isPlainObject(line.message) ? line.message : undefined; + if (!m) continue; + const role = typeof m.role === "string" ? m.role : "system"; + + // Outer line `timestamp` is an ISO string; message.timestamp is epoch ms. + const date = toDate(line.timestamp ?? m.timestamp, baseMs + i); + const timestamp = date.toISOString(); + const raw: Record = { + uuid: line.id != null ? String(line.id) : `openclaw-${i}`, + parentUuid: line.parentId != null ? String(line.parentId) : null, + }; + const base = baseEntry(raw, timestamp, date, source); + + if (role === "user") { + entries.push({ + type: "user", + ...base, + message: { role: "user", content: extractText(m.content) }, + } satisfies UserEntry); + continue; + } + + if (role === "assistant") { + const blocks: ContentBlock[] = []; + const content = m.content; + if (Array.isArray(content)) { + for (const b of content) { + if (!isPlainObject(b)) continue; + if (b.type === "text" && typeof b.text === "string") { + blocks.push({ type: "text", text: b.text }); + } else if (b.type === "toolCall") { + const id = typeof b.id === "string" ? b.id : `${String(b.name ?? "tool")}-${blocks.length}`; + const name = typeof b.name === "string" ? b.name : "tool"; + const input = isPlainObject(b.arguments) ? b.arguments : {}; + const block: ToolUseBlock = { type: "tool_use", id, name, input }; + blocks.push(block); + toolUseById.set(id, block); + toolUseStartMs.set(id, date.getTime()); + } + } + } else { + const text = extractText(content); + if (text) blocks.push({ type: "text", text }); + } + if (blocks.length === 0) continue; // empty / failed assistant turn + entries.push({ + type: "assistant", + ...base, + message: { role: "assistant", content: blocks, model: typeof m.model === "string" ? m.model : undefined }, + } satisfies AssistantEntry); + continue; + } + + if (role === "toolResult") { + const callId = typeof m.toolCallId === "string" ? m.toolCallId : undefined; + const block = callId ? toolUseById.get(callId) : undefined; + if (block) { + const details = isPlainObject(m.details) ? m.details : undefined; + const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime(); + const durationMs = + details && typeof details.durationMs === "number" + ? details.durationMs + : Math.max(0, date.getTime() - startMs); + block.result = { + timestamp, + timestampFormatted: formatTimestamp(date), + content: extractText(m.content), + durationMs, + durationFormatted: formatDuration(durationMs), + }; + continue; + } + // Orphan tool result — fall through to a system entry. + } + + entries.push({ type: "system", ...base, raw } satisfies GenericEntry); + } + + entries.sort((a, b) => a.timestampMs - b.timestampMs); + return entries; +} + +// ── Discovery + file loader ── + +export interface OpenClawTranscriptFile { + agentId: string; + sessionId: string; + transcriptPath: string; + mtimeMs: number; + sizeBytes: number; +} + +/** Enumerate `agents//sessions/.jsonl` transcripts, skipping the + * heavy `.trajectory.jsonl` OTel traces and pointer files. */ +export function listOpenClawTranscripts(): OpenClawTranscriptFile[] { + const agentsDir = join(openclawHome(), "agents"); + const out: OpenClawTranscriptFile[] = []; + let agentIds: string[]; + try { + agentIds = readdirSync(agentsDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name); + } catch { + return out; + } + for (const agentId of agentIds) { + const sessionsDir = join(agentsDir, agentId, "sessions"); + let files: string[]; + try { + files = readdirSync(sessionsDir); + } catch { + continue; + } + for (const file of files) { + // Only `.jsonl` — not `.trajectory.jsonl` / `.trajectory-path.json`. + if (!file.endsWith(".jsonl") || file.endsWith(".trajectory.jsonl")) continue; + const sessionId = file.slice(0, -".jsonl".length); + if (!OPENCLAW_SESSION_ID_RE.test(sessionId)) continue; + const transcriptPath = join(sessionsDir, file); + try { + const st = statSync(transcriptPath); + out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size }); + } catch { + // skip unreadable + } + } + } + return out; +} + +/** Resolve a session UUID to its on-disk transcript path (host-side). Guards + * against traversal by requiring a UUID filename. Shared by the audit adapter + * and download-session. */ +export function findOpenClawTranscript(sessionId: string): string | null { + if (!OPENCLAW_SESSION_ID_RE.test(sessionId)) return null; + for (const t of listOpenClawTranscripts()) { + if (t.sessionId === sessionId) return t.transcriptPath; + } + return null; +} + +export interface OpenClawSessionLogData { + entries: LogEntry[]; + rawLines: Record[]; + cwd?: string; + filePath: string; +} + +/** Load and parse one session transcript by UUID. Returns `null` when the file + * is missing/unreadable or the id fails validation. */ +export async function getOpenClawSessionLog( + sessionId: string, +): Promise { + const filePath = findOpenClawTranscript(sessionId); + if (!filePath) return null; + let content: string; + try { + content = await readFile(filePath, "utf-8"); + } catch { + return null; + } + const rawLines = parseRawLines(content, "session"); + const entries = openclawLinesToLogEntries(rawLines, "session"); + // cwd lives on the `type:"session"` header line. + let cwd: string | undefined; + for (const line of rawLines) { + if (isPlainObject(line) && line.type === "session" && typeof line.cwd === "string" && line.cwd.length > 0) { + cwd = line.cwd; + break; + } + } + return { entries, rawLines, cwd, filePath }; +} + +export const getCachedOpenClawSessionLog = runtimeCache( + (sessionId: string) => getOpenClawSessionLog(sessionId), + 2, + { maxSize: 50 }, +); diff --git a/lib/projects.ts b/lib/projects.ts index f6ffeb81..fa1afeb4 100644 --- a/lib/projects.ts +++ b/lib/projects.ts @@ -16,7 +16,7 @@ import { formatDate } from "./format-date"; export const UUID_RE = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/; export const PATH_TRAVERSAL_RE = /(^|[\\/])\.\.($|[\\/])/; -export type ProjectCli = "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "gemini" | "hermes"; +export type ProjectCli = "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "hermes" | "openclaw" | "factory" | "devin" | "antigravity" | "goose"; export interface ProjectFolder { name: string; @@ -143,18 +143,26 @@ export async function getProjectFolders(): Promise { { getCursorProjects }, { getOpenCodeProjects }, { getPiProjects }, - { getGeminiProjects }, { getHermesProjects }, + { getOpenClawProjects }, + { getFactoryProjects }, + { getDevinProjects }, + { getAntigravityProjects }, + { getGooseProjects }, ] = await Promise.all([ import("./codex-projects"), import("./copilot-projects"), import("./cursor-projects"), import("./opencode-projects"), import("./pi-projects"), - import("./gemini-projects"), import("./hermes-projects"), + import("./openclaw-projects"), + import("./factory-projects"), + import("./devin-projects"), + import("./antigravity-projects"), + import("./goose-projects"), ]); - const [claude, codex, copilot, cursor, opencode, pi, gemini, hermes] = await Promise.all([ + const [claude, codex, copilot, cursor, opencode, pi, hermes, openclaw, factory, devin, antigravity, goose] = await Promise.all([ getClaudeProjectFolders(), getCodexProjects().catch((error) => { logError("Error reading Codex projects:", error); @@ -176,16 +184,32 @@ export async function getProjectFolders(): Promise { logError("Error reading Pi projects:", error); return [] as ProjectFolder[]; }), - getGeminiProjects().catch((error) => { - logError("Error reading Gemini projects:", error); - return [] as ProjectFolder[]; - }), getHermesProjects().catch((error) => { logError("Error reading Hermes projects:", error); return [] as ProjectFolder[]; }), + getOpenClawProjects().catch((error) => { + logError("Error reading OpenClaw projects:", error); + return [] as ProjectFolder[]; + }), + getFactoryProjects().catch((error) => { + logError("Error reading Factory projects:", error); + return [] as ProjectFolder[]; + }), + getDevinProjects().catch((error) => { + logError("Error reading Devin projects:", error); + return [] as ProjectFolder[]; + }), + getAntigravityProjects().catch((error) => { + logError("Error reading Antigravity projects:", error); + return [] as ProjectFolder[]; + }), + getGooseProjects().catch((error) => { + logError("Error reading Goose projects:", error); + return [] as ProjectFolder[]; + }), ]); - return mergeProjectFolders(claude, codex, copilot, cursor, opencode, pi, gemini, hermes); + return mergeProjectFolders(claude, codex, copilot, cursor, opencode, pi, hermes, openclaw, factory, devin, antigravity, goose); } /** diff --git a/openclaw-plugin/index.js b/openclaw-plugin/index.js new file mode 100644 index 00000000..869d8a24 --- /dev/null +++ b/openclaw-plugin/index.js @@ -0,0 +1,223 @@ +/** + * failproofai policy bridge for OpenClaw (openclaw gateway). + * + * Loaded in-process by the gateway (registered via `plugins.load.paths` + + * `plugins.entries.failproofai` in ~/.openclaw/openclaw.json). It subscribes to + * OpenClaw's typed PLUGIN hooks — the only surface that can block; OpenClaw's + * file-based "internal hooks" are observation-only — and forwards each to the + * failproofai binary as `failproofai --hook --cli openclaw`. failproofai + * prints a flat `{permission, reason}` verdict on stdout; this shim maps it to + * each hook's native return shape. + * + * Marker comment for failproofai's installer detection (do not remove): + * __failproofai_hook__: true + * + * Design notes (verified live against openclaw v2026.7.1): + * • ASYNC spawn, never spawnSync — the gateway is a long-running multi-channel + * process; a synchronous spawn on every hook would stall every channel. + * 30s guard timer; fail-open on any error (never block on infra failure). + * • Raw forwarding — we send the raw tool name / params and a Claude-shaped + * stdin (params→tool_input, toolName→tool_name, transcriptPath→ + * transcript_path, stopHookActive→stop_hook_active, sessionKey→session_id). + * The binary canonicalizes via OPENCLAW_* maps (single source of truth); the + * shim ships NO inline maps (unlike the OpenCode/Pi shims). + * • No top-level `await` — OpenClaw's plugin loader rejects it; all async work + * happens inside register()'s handlers. + * + * Binary resolution mirrors pi-extension/index.ts: prefer the bundled + * dist/cli.mjs (node-compatible), fall back to bin/failproofai.mjs with bun for + * dev; honor FAILPROOFAI_BINARY_OVERRIDE. Paths resolve relative to this file + * via import.meta.url (the gateway spawns plugins with an undefined cwd). + */ +import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry"; +import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; +import { resolve, dirname } from "node:path"; +import { fileURLToPath } from "node:url"; + +const HERE = dirname(fileURLToPath(import.meta.url)); +const DIST_BIN = resolve(HERE, "..", "dist", "cli.mjs"); +const SRC_BIN = resolve(HERE, "..", "bin", "failproofai.mjs"); + +function resolveSpawn() { + if (process.env.FAILPROOFAI_BINARY_OVERRIDE) { + return { cmd: "node", args: [process.env.FAILPROOFAI_BINARY_OVERRIDE] }; + } + if (existsSync(DIST_BIN)) { + return { cmd: "node", args: [DIST_BIN] }; + } + return { cmd: "bun", args: [SRC_BIN] }; +} + +function debug(msg) { + if (process.env.FAILPROOFAI_OPENCLAW_DEBUG === "1") { + process.stderr.write(`[failproofai-openclaw-shim] ${msg}\n`); + } +} + +/** + * Spawn `failproofai --hook --cli openclaw`, write the JSON payload + * to stdin, and resolve the parsed flat `{permission, reason}` verdict. Async + + * fail-open: any spawn/parse error or timeout resolves to `{permission:"allow"}` + * so a failproofai fault never blocks the gateway. + */ +function callPolicy(rawEvent, payload) { + return new Promise((done) => { + const { cmd, args } = resolveSpawn(); + let child; + try { + child = spawn(cmd, [...args, "--hook", rawEvent, "--cli", "openclaw"], { + stdio: ["pipe", "pipe", "pipe"], + }); + } catch (err) { + debug(`spawn threw: ${err && err.message ? err.message : String(err)}`); + done({ permission: "allow" }); + return; + } + let out = ""; + let settled = false; + const finish = (verdict) => { + if (settled) return; + settled = true; + clearTimeout(timer); + done(verdict); + }; + const timer = setTimeout(() => { + debug(`timeout on ${rawEvent}; killing child`); + try { child.kill(); } catch { /* ignore */ } + finish({ permission: "allow" }); + }, 30_000); + child.stdout.on("data", (d) => { out += d; }); + child.on("error", (err) => { + debug(`child error: ${err && err.message ? err.message : String(err)}`); + finish({ permission: "allow" }); + }); + child.on("close", () => { + const stdout = out.trim(); + if (!stdout) { finish({ permission: "allow" }); return; } + try { + finish(JSON.parse(stdout)); + } catch (err) { + debug(`parse error: ${err && err.message ? err.message : String(err)}`); + finish({ permission: "allow" }); + } + }); + try { + child.stdin.end(JSON.stringify(payload)); + } catch (err) { + debug(`stdin write failed: ${err && err.message ? err.message : String(err)}`); + finish({ permission: "allow" }); + } + }); +} + +/** Claude-shaped stdin base. Extra keys are ignored by the binary's payload + * parser; they're forwarded for future use / activity attribution. */ +function baseMeta(payload, ctx) { + const p = payload || {}; + const c = ctx || {}; + return { + session_id: c.sessionId ?? p.sessionId ?? c.sessionKey ?? p.sessionKey, + cwd: p.cwd ?? c.workspaceDir ?? process.cwd(), + transcript_path: p.transcriptPath, + stop_hook_active: p.stopHookActive === true, + openclaw: { + agentId: c.agentId, + sessionKey: c.sessionKey ?? p.sessionKey, + runId: c.runId ?? p.runId, + provider: p.provider, + model: p.model, + }, + }; +} + +export default definePluginEntry({ + id: "failproofai", + name: "failproofai", + description: "Real-time policy enforcement for OpenClaw by failproofai", + register(api) { + // before_tool_call → PreToolUse. Full deny: return {block:true, blockReason}. + api.on( + "before_tool_call", + async (payload, ctx) => { + const p = payload || {}; + const verdict = await callPolicy("before_tool_call", { + ...baseMeta(payload, ctx), + tool_name: p.toolName, + tool_input: p.params, + hook_event_name: "before_tool_call", + }); + if (verdict.permission === "deny") { + return { block: true, blockReason: verdict.reason || "Blocked by failproofai" }; + } + return undefined; + }, + { priority: 100, timeoutMs: 60_000 }, + ); + + // before_agent_run → UserPromptSubmit. Deny: return {outcome:"block", reason}. + api.on( + "before_agent_run", + async (payload, ctx) => { + const p = payload || {}; + const verdict = await callPolicy("before_agent_run", { + ...baseMeta(payload, ctx), + prompt: p.prompt, + hook_event_name: "before_agent_run", + }); + if (verdict.permission === "deny") { + return { outcome: "block", reason: verdict.reason || "Blocked by failproofai" }; + } + return undefined; + }, + { priority: 100, timeoutMs: 60_000 }, + ); + + // before_agent_finalize → Stop. The real turn-end gate: a deny becomes a + // revise so the agent runs another pass. The evaluator supplies the + // MANDATORY ACTION wording; the payload's stop_hook_active guards the + // require-*-before-stop builtins against infinite loops. + api.on( + "before_agent_finalize", + async (payload, ctx) => { + const verdict = await callPolicy("before_agent_finalize", { + ...baseMeta(payload, ctx), + hook_event_name: "before_agent_finalize", + }); + if (verdict.permission === "deny") { + return { action: "revise", reason: verdict.reason || "Action required by failproofai" }; + } + return undefined; + }, + { priority: 100, timeoutMs: 60_000 }, + ); + + // Observation hooks — await so activity ordering is stable, ignore verdict. + // after_tool_call → PostToolUse; session_start/end → SessionStart/End; + // subagent_ended → SubagentStop (obs only); before_compaction → PreCompact. + for (const ev of [ + "after_tool_call", + "session_start", + "session_end", + "subagent_ended", + "before_compaction", + ]) { + api.on( + ev, + async (payload, ctx) => { + const p = payload || {}; + await callPolicy(ev, { + ...baseMeta(payload, ctx), + tool_name: p.toolName, + tool_input: p.params, + tool_response: p.result, + reason: p.reason, + hook_event_name: ev, + }); + return undefined; + }, + { priority: 100, timeoutMs: 60_000 }, + ); + } + }, +}); diff --git a/openclaw-plugin/openclaw.plugin.json b/openclaw-plugin/openclaw.plugin.json new file mode 100644 index 00000000..879fcde1 --- /dev/null +++ b/openclaw-plugin/openclaw.plugin.json @@ -0,0 +1,6 @@ +{ + "id": "failproofai", + "name": "failproofai", + "description": "Real-time policy enforcement for OpenClaw by failproofai", + "configSchema": {} +} diff --git a/openclaw-plugin/package.json b/openclaw-plugin/package.json new file mode 100644 index 00000000..c3dc0f89 --- /dev/null +++ b/openclaw-plugin/package.json @@ -0,0 +1,12 @@ +{ + "name": "@failproofai/openclaw-plugin", + "version": "0.0.1", + "description": "failproofai policy bridge for OpenClaw (openclaw gateway)", + "type": "module", + "main": "./index.js", + "private": true, + "keywords": [ + "openclaw-plugin", + "failproofai" + ] +} diff --git a/package.json b/package.json index b59c8550..26e4cd49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "failproofai", - "version": "0.0.13", + "version": "0.0.14-beta.1", "description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK", "bin": { "failproofai": "./dist/cli.mjs" @@ -11,6 +11,7 @@ "scripts/", "lib/", "pi-extension/", + "openclaw-plugin/", ".next/standalone/", "dist/", "README.md" diff --git a/scripts/sync-agent-cli-harnesses-prompt.md b/scripts/sync-agent-cli-harnesses-prompt.md index 550e4107..90fd5eed 100644 --- a/scripts/sync-agent-cli-harnesses-prompt.md +++ b/scripts/sync-agent-cli-harnesses-prompt.md @@ -32,7 +32,6 @@ tracked in `src/hooks/types.ts` and written to disk by `src/hooks/integrations.t | Cursor Agent | `CURSOR_HOOK_EVENT_TYPES` | `CURSOR_EVENT_MAP` | `.cursor/hooks.json` | | OpenCode | `OPENCODE_HOOK_EVENT_TYPES` | `OPENCODE_EVENT_MAP` | `.opencode/opencode.json` + `.opencode/plugins/failproofai.mjs` | | Pi | `PI_HOOK_EVENT_TYPES` | `PI_EVENT_MAP` | `.pi/settings.json` | -| Gemini CLI | `GEMINI_HOOK_EVENT_TYPES` | `GEMINI_EVENT_MAP` | `.gemini/settings.json` | ## What "drift" means — three scopes @@ -62,7 +61,7 @@ For each verified CLI, compare the upstream docs to this repo across three scope when you only need to **inspect** a committed fixture, prefer `git show HEAD:` (e.g. `git show HEAD:.codex/hooks.json`) — it is never blocked and is the reliable way to read `.claude/settings.json`, `.codex/hooks.json`, - `.cursor/hooks.json`, `.github/hooks/failproofai.json`, `.gemini/settings.json`, + `.cursor/hooks.json`, `.github/hooks/failproofai.json`, `.pi/settings.json`, and `.opencode/*`. - Do **NOT** run `failproofai policies --install` (or any `failproofai` subcommand) to regenerate a fixture — it is blocked. Edit fixtures by hand. @@ -76,7 +75,7 @@ Spawn one subagent per CLI (seven, in parallel). Each subagent, for its CLI: **settings-file schema** (top-level keys, per-entry shape, command field name, timeout field name **and unit**, and whether `matcher` / `version` / `$schema` are present). **Use upstream casing exactly** — Codex snake_case, Cursor - camelCase, OpenCode dot.namespaced, Pi snake_case, Claude/Copilot/Gemini + camelCase, OpenCode dot.namespaced, Pi snake_case, Claude/Copilot PascalCase. Do **not** normalize. 2. Compare against this repo: the CLI's `*HOOK_EVENT_TYPES` array + paired `*EVENT_MAP` (scope 1); its `*_TOOL_MAP` / `*_TOOL_INPUT_MAP` and its branch in @@ -98,7 +97,6 @@ surface is documented in the package source, not a clean enumeration). | Cursor | https://cursor.com/docs/hooks | | OpenCode | https://opencode.ai/docs/plugins/ | | Pi | https://www.npmjs.com/package/@mariozechner/pi-coding-agent | -| Gemini | https://geminicli.com/docs/hooks/ · https://geminicli.com/docs/reference/tools/ (tool names) | ## Phase 2 — Decide what to do (do this BEFORE editing any files) @@ -122,7 +120,6 @@ changes that block a clean stop on the comment / no-op paths below. > This open sync PR is missing newly-detected drift: > - **Cursor**: upstream added event `afterEdit` — append to `CURSOR_HOOK_EVENT_TYPES` (+ a `CURSOR_EVENT_MAP` entry). - > - **Gemini**: the `run_shell_command` tool was renamed to `shell` — the `GEMINI_TOOL_MAP` key is stale. > > (hook-sync bot — please fold these into this PR rather than opening a second sync PR.) @@ -140,7 +137,7 @@ requires. - **Append** new events just before `] as const`, preserving upstream casing. - **Delete** removed events; if the CLI has an `*EVENT_MAP`, also delete the same key from that map (the `Record` is exhaustive — a stale key fails `tsc`). -- For **map-bearing CLIs** (Codex, Cursor, OpenCode, Pi, Gemini), do **NOT** invent +- For **map-bearing CLIs** (Codex, Cursor, OpenCode, Pi), do **NOT** invent the canonical mapping for a newly-added event — leave it out of the `*EVENT_MAP` so `tsc` fails intentionally, and add a reviewer-checklist item to the PR body (see below). For **Claude and Copilot** (no map), the build stays green. @@ -148,9 +145,9 @@ requires. - If `HOOK_EVENT_TYPES` (Claude) changed: in `__tests__/hooks/manager.test.ts`, update the `installs hooks for all event types` description AND both `expect(Object.keys(written.hooks)).toHaveLength()` assertions. - - If `GEMINI_HOOK_EVENT_TYPES` changed: in `__tests__/hooks/integrations.test.ts`, - update the `expect(gemini.eventTypes).toHaveLength()` assertion AND the - matching description string. + - If a CLI's `*_HOOK_EVENT_TYPES` changed: in `__tests__/hooks/integrations.test.ts`, + update the matching `expect(.eventTypes).toHaveLength()` assertion AND the + description string. - Locate these by searching for the current count number. ### Scope 2 / Scope 3 (tool schema / settings-file shape) @@ -211,7 +208,7 @@ The PR **body** must contain, in order: `__tests__/e2e/hooks/-integration.e2e.test.ts`, the seven dogfood fixtures (`.claude/settings.json`, `.codex/hooks.json`, `.cursor/hooks.json`, `.github/hooks/failproofai.json`, `.opencode/opencode.json`, - `.opencode/plugins/failproofai.mjs`, `.pi/settings.json`, `.gemini/settings.json`), + `.opencode/plugins/failproofai.mjs`, `.pi/settings.json`), and `CHANGELOG.md`. - Do **NOT** edit `.failproofai/policies-config.json` (the entrypoint manages it), `src/hooks/handler.ts`, `src/hooks/manager.ts`, or any other source file. diff --git a/src/audit/cli-adapters/antigravity.ts b/src/audit/cli-adapters/antigravity.ts new file mode 100644 index 00000000..fd02c694 --- /dev/null +++ b/src/audit/cli-adapters/antigravity.ts @@ -0,0 +1,87 @@ +/** + * Antigravity (agy) transcript adapter — AUDIT (Pillar 2). + * + * Antigravity writes plain-JSONL transcripts at + * `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` + * (one step per line), with a SQLite conversation index at + * `conversation_summaries.db`. Verified live against agy v1.1.2. + * lib/antigravity-sessions.ts enumerates + parses the transcripts into the + * shared LogEntry[] shape; lib/antigravity-projects.ts reads the SQLite index + * for cwd/title enrichment. `logEntriesToEvents` handles the rest (tool-name + + * tool-input canonicalization via the ANTIGRAVITY_* maps). + */ +import { readFile } from "node:fs/promises"; +import { + listAntigravityTranscripts, + antigravityLinesToLogEntries, +} from "../../../lib/antigravity-sessions"; +import { getAntigravityIndex } from "../../../lib/antigravity-projects"; +import { parseRawLines } from "../../../lib/log-entries"; +import { encodeFolderName } from "../../../lib/paths"; +import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; +import type { ListOpts } from "./claude"; +import { logEntriesToEvents } from "./shared"; + +export async function listAntigravityTranscriptMetadata( + opts: ListOpts = {}, +): Promise { + const projectFilter = opts.projects ? new Set(opts.projects) : null; + const sinceMs = opts.sinceMs ?? 0; + const out: TranscriptMetadata[] = []; + + const index = await getAntigravityIndex(); + + for (const t of listAntigravityTranscripts()) { + if (t.mtimeMs < sinceMs) continue; + const cwd = index.get(t.conversationId)?.cwd; + // `audit --project ` filters on the conversation's workspace cwd. + if (projectFilter && (!cwd || !projectFilter.has(cwd))) continue; + out.push({ + cli: "antigravity", + projectName: cwd ? encodeFolderName(cwd) : "antigravity", + sessionId: t.conversationId, + transcriptPath: t.transcriptPath, + mtimeMs: t.mtimeMs, + sizeBytes: t.sizeBytes, + }); + } + return out; +} + +export async function streamAntigravityEvents( + meta: TranscriptMetadata, +): Promise { + let content: string; + try { + content = await readFile(meta.transcriptPath, "utf-8"); + } catch { + return []; + } + + const rawLines = parseRawLines(content, "session"); + const entries = antigravityLinesToLogEntries(rawLines, "session"); + + // Recover cwd from the transcript's first run_command Cwd (falls back to ""). + let cwd = ""; + for (const line of rawLines) { + if (!line || typeof line !== "object") continue; + const calls = (line as Record).tool_calls; + if (!Array.isArray(calls)) continue; + for (const call of calls) { + const args = call && typeof call === "object" ? (call as Record).args : undefined; + const c = args && typeof args === "object" ? (args as Record).Cwd : undefined; + if (typeof c === "string" && c.length > 0) { + cwd = c; + break; + } + } + if (cwd) break; + } + + return logEntriesToEvents(entries, { + cli: "antigravity", + sessionId: meta.sessionId, + transcriptPath: meta.transcriptPath, + cwd, + }); +} diff --git a/src/audit/cli-adapters/devin.ts b/src/audit/cli-adapters/devin.ts new file mode 100644 index 00000000..1d4b692b --- /dev/null +++ b/src/audit/cli-adapters/devin.ts @@ -0,0 +1,53 @@ +/** + * Devin CLI (Cognition) transcript adapter — AUDIT-ONLY (Pillar 2). + * + * Devin keeps every session in one SQLite DB at + * `~/.local/share/devin/cli/sessions.db`. We read it directly via the bundled + * sql.js reader (lib/devin-projects.ts enumerates the `sessions` table; + * lib/devin-sessions.ts parses each session's `message_nodes`), producing the + * same LogEntry[] shape the other adapters do — so `logEntriesToEvents` handles + * the rest. Unlike Hermes, each Devin session carries a real + * `working_directory`, so `audit --project ` filters work. + */ +import { getDevinSessions } from "../../../lib/devin-projects"; +import { getDevinSessionLog } from "../../../lib/devin-sessions"; +import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; +import type { ListOpts } from "./claude"; +import { logEntriesToEvents } from "./shared"; + +export async function listDevinTranscriptMetadata( + opts: ListOpts = {}, +): Promise { + const projectFilter = opts.projects ? new Set(opts.projects) : null; + const sinceMs = opts.sinceMs ?? 0; + const sessions = await getDevinSessions(); + const out: TranscriptMetadata[] = []; + for (const s of sessions) { + if (s.mtimeMs < sinceMs) continue; + // `audit --project ` filters on the session's working directory. + if (projectFilter && (!s.cwd || !projectFilter.has(s.cwd))) continue; + out.push({ + cli: "devin", + projectName: s.projectName, + sessionId: s.sessionId, + transcriptPath: `devin-db://${s.sessionId}`, + mtimeMs: s.mtimeMs, + // mtime advances on each message, so (mtime) forms a real cache key. + sizeBytes: 0, + }); + } + return out; +} + +export async function streamDevinEvents( + meta: TranscriptMetadata, +): Promise { + const log = await getDevinSessionLog(meta.sessionId); + if (!log) return []; + return logEntriesToEvents(log.entries, { + cli: "devin", + sessionId: meta.sessionId, + transcriptPath: meta.transcriptPath, + cwd: log.cwd ?? "", + }); +} diff --git a/src/audit/cli-adapters/factory.ts b/src/audit/cli-adapters/factory.ts new file mode 100644 index 00000000..c2f66be8 --- /dev/null +++ b/src/audit/cli-adapters/factory.ts @@ -0,0 +1,75 @@ +/** + * Factory (droid) transcript adapter — AUDIT (Pillar 2). + * + * droid writes real JSONL transcripts at + * `~/.factory/sessions//.jsonl` (Claude-style + * encoded-cwd folders; verified live against droid v0.171.0). + * lib/factory-sessions.ts enumerates and parses them into the shared + * LogEntry[] shape, so `logEntriesToEvents` handles the rest. + */ +import { readFile } from "node:fs/promises"; +import { + listFactoryTranscripts, + factoryLinesToLogEntries, +} from "../../../lib/factory-sessions"; +import { parseRawLines } from "../../../lib/log-entries"; +import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; +import type { ListOpts } from "./claude"; +import { logEntriesToEvents } from "./shared"; + +export async function listFactoryTranscriptMetadata( + opts: ListOpts = {}, +): Promise { + const projectFilter = opts.projects ? new Set(opts.projects) : null; + const sinceMs = opts.sinceMs ?? 0; + const out: TranscriptMetadata[] = []; + + for (const t of listFactoryTranscripts()) { + if (t.mtimeMs < sinceMs) continue; + // `audit --project ` filters on the decoded working directory. + if (projectFilter && !projectFilter.has(t.cwd)) continue; + out.push({ + cli: "factory", + projectName: t.projectName, + sessionId: t.sessionId, + transcriptPath: t.transcriptPath, + mtimeMs: t.mtimeMs, + sizeBytes: t.sizeBytes, + }); + } + return out; +} + +export async function streamFactoryEvents( + meta: TranscriptMetadata, +): Promise { + let content: string; + try { + content = await readFile(meta.transcriptPath, "utf-8"); + } catch { + return []; + } + + const rawLines = parseRawLines(content, "session"); + const entries = factoryLinesToLogEntries(rawLines, "session"); + + // cwd lives on the `type:"session_start"` header line — recover the canonical + // value rather than re-decoding the (lossy) folder name. + let cwd = ""; + for (const line of rawLines) { + if (line && typeof line === "object" && (line as Record).type === "session_start") { + const c = (line as Record).cwd; + if (typeof c === "string" && c.length > 0) { + cwd = c; + break; + } + } + } + + return logEntriesToEvents(entries, { + cli: "factory", + sessionId: meta.sessionId, + transcriptPath: meta.transcriptPath, + cwd, + }); +} diff --git a/src/audit/cli-adapters/gemini.ts b/src/audit/cli-adapters/gemini.ts deleted file mode 100644 index 2253afac..00000000 --- a/src/audit/cli-adapters/gemini.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Gemini CLI transcript adapter. - */ -import { statSync } from "node:fs"; -import { getGeminiProjects, getGeminiSessionsByEncodedName } from "../../../lib/gemini-projects"; -import { getGeminiSessionLog } from "../../../lib/gemini-sessions"; -import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; -import type { ListOpts } from "./claude"; -import { logEntriesToEvents } from "./shared"; - -export async function listGeminiTranscriptMetadata( - opts: ListOpts = {}, -): Promise { - const projectFilter = opts.projects ? new Set(opts.projects) : null; - const sinceMs = opts.sinceMs ?? 0; - const out: TranscriptMetadata[] = []; - - const projects = await getGeminiProjects(); - for (const project of projects) { - const { cwd, sessions } = await getGeminiSessionsByEncodedName(project.name); - const effectiveCwd = cwd ?? ""; - if (projectFilter && !projectFilter.has(effectiveCwd)) continue; - for (const s of sessions) { - const mtimeMs = s.lastModified.getTime(); - if (mtimeMs < sinceMs) continue; - let sizeBytes = 0; - try { sizeBytes = statSync(s.path).size; } catch { /* unreadable */ } - if (!s.sessionId) continue; - out.push({ - cli: "gemini", - projectName: project.name, - sessionId: s.sessionId, - transcriptPath: s.path, - mtimeMs, - sizeBytes, - }); - } - } - return out; -} - -export async function streamGeminiEvents(meta: TranscriptMetadata): Promise { - const log = await getGeminiSessionLog(meta.sessionId); - if (!log) return []; - return logEntriesToEvents(log.entries, { - cli: "gemini", - sessionId: meta.sessionId, - transcriptPath: meta.transcriptPath, - cwd: log.cwd ?? "", - }); -} diff --git a/src/audit/cli-adapters/goose.ts b/src/audit/cli-adapters/goose.ts new file mode 100644 index 00000000..5d951825 --- /dev/null +++ b/src/audit/cli-adapters/goose.ts @@ -0,0 +1,53 @@ +/** + * Goose (codename goose, Block) transcript adapter — AUDIT-ONLY (Pillar 2). + * + * Goose keeps every session in one SQLite DB at + * `~/.local/share/goose/sessions/sessions.db`. We read it directly via the + * bundled sql.js reader (lib/goose-projects.ts enumerates the `sessions` table; + * lib/goose-sessions.ts parses each session's `messages`), producing the same + * LogEntry[] shape the other adapters do — so `logEntriesToEvents` handles the + * rest. Like Devin, each Goose session carries a real `working_dir`, so + * `audit --project ` filters work (unlike the cwd-less Hermes gateway). + */ +import { getGooseSessions } from "../../../lib/goose-projects"; +import { getGooseSessionLog } from "../../../lib/goose-sessions"; +import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; +import type { ListOpts } from "./claude"; +import { logEntriesToEvents } from "./shared"; + +export async function listGooseTranscriptMetadata( + opts: ListOpts = {}, +): Promise { + const projectFilter = opts.projects ? new Set(opts.projects) : null; + const sinceMs = opts.sinceMs ?? 0; + const sessions = await getGooseSessions(); + const out: TranscriptMetadata[] = []; + for (const s of sessions) { + if (s.mtimeMs < sinceMs) continue; + // `audit --project ` filters on the session's working directory. + if (projectFilter && (!s.cwd || !projectFilter.has(s.cwd))) continue; + out.push({ + cli: "goose", + projectName: s.projectName, + sessionId: s.sessionId, + transcriptPath: `goose-db://${s.sessionId}`, + mtimeMs: s.mtimeMs, + // mtime advances on each message, so (mtime) forms a real cache key. + sizeBytes: 0, + }); + } + return out; +} + +export async function streamGooseEvents( + meta: TranscriptMetadata, +): Promise { + const log = await getGooseSessionLog(meta.sessionId); + if (!log) return []; + return logEntriesToEvents(log.entries, { + cli: "goose", + sessionId: meta.sessionId, + transcriptPath: meta.transcriptPath, + cwd: log.cwd ?? "", + }); +} diff --git a/src/audit/cli-adapters/index.ts b/src/audit/cli-adapters/index.ts index fbc4b8aa..52fbe950 100644 --- a/src/audit/cli-adapters/index.ts +++ b/src/audit/cli-adapters/index.ts @@ -17,8 +17,12 @@ import { listCopilotTranscriptMetadata, streamCopilotEvents } from "./copilot"; import { listCursorTranscriptMetadata, streamCursorEvents } from "./cursor"; import { listOpenCodeTranscriptMetadata, streamOpenCodeEvents } from "./opencode"; import { listPiTranscriptMetadata, streamPiEvents } from "./pi"; -import { listGeminiTranscriptMetadata, streamGeminiEvents } from "./gemini"; import { listHermesTranscriptMetadata, streamHermesEvents } from "./hermes"; +import { listOpenClawTranscriptMetadata, streamOpenClawEvents } from "./openclaw"; +import { listFactoryTranscriptMetadata, streamFactoryEvents } from "./factory"; +import { listAntigravityTranscriptMetadata, streamAntigravityEvents } from "./antigravity"; +import { listDevinTranscriptMetadata, streamDevinEvents } from "./devin"; +import { listGooseTranscriptMetadata, streamGooseEvents } from "./goose"; export type { ListOpts }; @@ -59,16 +63,36 @@ export const ADAPTERS: Record = { listTranscripts: listPiTranscriptMetadata, streamEvents: streamPiEvents, }, - gemini: { - cli: "gemini", - listTranscripts: listGeminiTranscriptMetadata, - streamEvents: streamGeminiEvents, - }, hermes: { cli: "hermes", listTranscripts: listHermesTranscriptMetadata, streamEvents: streamHermesEvents, }, + openclaw: { + cli: "openclaw", + listTranscripts: listOpenClawTranscriptMetadata, + streamEvents: streamOpenClawEvents, + }, + factory: { + cli: "factory", + listTranscripts: listFactoryTranscriptMetadata, + streamEvents: streamFactoryEvents, + }, + devin: { + cli: "devin", + listTranscripts: listDevinTranscriptMetadata, + streamEvents: streamDevinEvents, + }, + antigravity: { + cli: "antigravity", + listTranscripts: listAntigravityTranscriptMetadata, + streamEvents: streamAntigravityEvents, + }, + goose: { + cli: "goose", + listTranscripts: listGooseTranscriptMetadata, + streamEvents: streamGooseEvents, + }, }; export function getAdapter(cli: IntegrationType): CliAdapter { diff --git a/src/audit/cli-adapters/openclaw.ts b/src/audit/cli-adapters/openclaw.ts new file mode 100644 index 00000000..01bd1dd9 --- /dev/null +++ b/src/audit/cli-adapters/openclaw.ts @@ -0,0 +1,56 @@ +/** + * OpenClaw (openclaw gateway) transcript adapter — AUDIT (Pillar 2). + * + * OpenClaw writes real JSONL transcripts at + * `~/.openclaw/agents//sessions/.jsonl` (verified live against + * v2026.7.1). lib/openclaw-sessions.ts enumerates and parses them into the + * shared LogEntry[] shape, so `logEntriesToEvents` handles the rest. + * + * Gateway sessions run in the container workspace, not a host repo, so they + * group by agentId (`openclaw:`) and contribute nothing to a + * cwd-scoped audit. + */ +import { + listOpenClawTranscripts, + getOpenClawSessionLog, +} from "../../../lib/openclaw-sessions"; +import type { NormalizedToolEvent, TranscriptMetadata } from "../types"; +import type { ListOpts } from "./claude"; +import { logEntriesToEvents } from "./shared"; + +export async function listOpenClawTranscriptMetadata( + opts: ListOpts = {}, +): Promise { + // `audit --project ` filters on working directory; gateway sessions run + // in the container workspace, not a host repo, so OpenClaw contributes + // nothing to a cwd-scoped audit. + if (opts.projects && opts.projects.length > 0) return []; + + const sinceMs = opts.sinceMs ?? 0; + const out: TranscriptMetadata[] = []; + for (const t of listOpenClawTranscripts()) { + if (t.mtimeMs < sinceMs) continue; + out.push({ + cli: "openclaw", + projectName: `openclaw:${t.agentId}`, + sessionId: t.sessionId, + transcriptPath: t.transcriptPath, + mtimeMs: t.mtimeMs, + sizeBytes: t.sizeBytes, + }); + } + return out; +} + +export async function streamOpenClawEvents( + meta: TranscriptMetadata, +): Promise { + const log = await getOpenClawSessionLog(meta.sessionId); + if (!log) return []; + return logEntriesToEvents(log.entries, { + cli: "openclaw", + sessionId: meta.sessionId, + transcriptPath: meta.transcriptPath, + cwd: log.cwd ?? "", + }); +} diff --git a/src/audit/cli.ts b/src/audit/cli.ts index cc7f9dd2..66653c9c 100644 --- a/src/audit/cli.ts +++ b/src/audit/cli.ts @@ -49,7 +49,7 @@ USAGE WHAT IT DOES 1. Scans past sessions from every installed agent CLI (Claude, Codex, Cursor, - Copilot, OpenCode, Pi, Gemini) — entirely on your machine. + Copilot, OpenCode, Pi) — entirely on your machine. 2. Starts the local dashboard and opens http://localhost:${DASHBOARD_PORT}/audit with your results. diff --git a/src/audit/report.ts b/src/audit/report.ts index 3bf7dea7..aec9f666 100644 --- a/src/audit/report.ts +++ b/src/audit/report.ts @@ -273,7 +273,7 @@ export function formatMarkdown(result: AuditResult): string { ); } out.push(""); - out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, and Gemini CLI. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped."); + out.push("> [failproofai](https://github.com/FailproofAI/failproofai) is a hook-based policy engine for Claude Code, Codex, Copilot, Cursor, OpenCode, and Pi. The `audit` command replays past agent sessions through every builtin policy to surface patterns that were (or could've been) stopped."); out.push(""); if (totalHits === 0) return out.join("\n"); diff --git a/src/audit/types.ts b/src/audit/types.ts index 33529188..3d42bd42 100644 --- a/src/audit/types.ts +++ b/src/audit/types.ts @@ -24,7 +24,7 @@ export interface NormalizedToolEvent { toolName: string; /** Canonicalized tool input (snake_case keys for OpenCode/Pi). */ toolInput: Record; - /** Pre-canonicalization tool name (e.g. "run_shell_command" for Gemini). */ + /** Pre-canonicalization tool name (e.g. "exec" for OpenClaw). */ rawToolName: string; /** * Result text from the matching tool_result block, if present in the diff --git a/src/hooks/builtin-policies.ts b/src/hooks/builtin-policies.ts index d57fc5fa..b5bfebb8 100644 --- a/src/hooks/builtin-policies.ts +++ b/src/hooks/builtin-policies.ts @@ -53,9 +53,9 @@ function isAgentInternalPath(resolved: string): boolean { * • Pi: `.pi/settings.json` (project) and `.pi/agent/settings.json` * (user); also the Pi-managed extension dir * `.pi/extensions/` / `.pi/agent/extensions/`. - * • Gemini CLI: `.gemini/settings.json` (both project and user scope — - * user is `~/.gemini/settings.json`); also the Gemini-managed - * hooks scripts dir `.gemini/hooks/`. + * • Antigravity CLI (agy): reuses `~/.gemini/` — `~/.gemini/settings.json` + * and the customization-root hook config + * `~/.gemini/config/hooks.json`. * These must NEVER be edited by the agent itself — that would let it disable * its own protections. */ @@ -74,9 +74,9 @@ function isAgentSettingsFile(resolved: string): boolean { // Pi: settings + extensions dirs (project and user-scope variants). if (/[\\/]\.pi[\\/](?:agent[\\/])?settings\.json$/.test(resolved)) return true; if (/[\\/]\.pi[\\/](?:agent[\\/])?extensions[\\/]/.test(resolved)) return true; - // Gemini: settings.json + hooks dir referenced by `command: $GEMINI_PROJECT_DIR/.gemini/hooks/...`. + // Antigravity (agy) reuses ~/.gemini/: settings.json + the customization-root hooks.json. if (/[\\/]\.gemini[\\/]settings\.json$/.test(resolved)) return true; - if (/[\\/]\.gemini[\\/]hooks[\\/]/.test(resolved)) return true; + if (/[\\/]\.gemini[\\/]config[\\/]hooks\.json$/.test(resolved)) return true; return false; } diff --git a/src/hooks/handler.ts b/src/hooks/handler.ts index 3160c47b..7ee80770 100644 --- a/src/hooks/handler.ts +++ b/src/hooks/handler.ts @@ -12,15 +12,17 @@ import type { CodexHookEventType, CursorHookEventType, PiHookEventType, - GeminiHookEventType, HermesHookEventType, + OpenClawHookEventType, + AntigravityHookEventType, } from "./types"; import { CODEX_EVENT_MAP, CURSOR_EVENT_MAP, PI_EVENT_MAP, - GEMINI_EVENT_MAP, HERMES_EVENT_MAP, + OPENCLAW_EVENT_MAP, + ANTIGRAVITY_EVENT_MAP, } from "./types"; import { canonicalizeToolName, canonicalizeToolInput } from "./tool-name-canonicalize"; import type { PolicyFunction, PolicyResult } from "./policy-types"; @@ -45,9 +47,7 @@ import { hookLogInfo, hookLogWarn } from "./hook-logger"; * `session_start`); Claude Code sends PascalCase. Copilot CLI is installed * in "VS Code compatible" PascalCase mode (see integrations.ts), so its event * NAMES arrive PascalCase already (note: tool names are a separate matter and - * are canonicalized in canonicalizeToolName below). Gemini also sends - * PascalCase event names but with different spellings (`BeforeTool`, - * `BeforeAgent`, `AfterAgent`); we map via GEMINI_EVENT_MAP. The internal + * are canonicalized in canonicalizeToolName below). The internal * registry, builtin policies, and policy.match.events all key on PascalCase. */ function canonicalizeEventType(raw: string, cli: IntegrationType): HookEventType { @@ -63,16 +63,25 @@ function canonicalizeEventType(raw: string, cli: IntegrationType): HookEventType const mapped = PI_EVENT_MAP[raw as PiHookEventType]; if (mapped) return mapped; } - if (cli === "gemini") { - const mapped = GEMINI_EVENT_MAP[raw as GeminiHookEventType]; - if (mapped) return mapped; - } if (cli === "hermes") { // Hermes sends snake_case event names (pre_tool_call, on_session_start, …); // map to PascalCase. Has no turn-end Stop event, so no Stop mapping exists. const mapped = HERMES_EVENT_MAP[raw as HermesHookEventType]; if (mapped) return mapped; } + if (cli === "openclaw") { + // The openclaw-plugin shim forwards raw snake_case plugin-hook names + // (before_tool_call, before_agent_finalize, …); map to PascalCase. + // before_agent_finalize is the real turn-end gate → Stop. + const mapped = OPENCLAW_EVENT_MAP[raw as OpenClawHookEventType]; + if (mapped) return mapped; + } + if (cli === "antigravity") { + // Antigravity's --hook args are PreToolUse|PostToolUse|PreInvocation|Stop. + // PreInvocation (before-model) → UserPromptSubmit. Verified agy v1.1.2. + const mapped = ANTIGRAVITY_EVENT_MAP[raw as AntigravityHookEventType]; + if (mapped) return mapped; + } // claude / copilot / unknown — already PascalCase, pass through. // HOOK_EVENT_TYPES type-checks downstream. return raw as HookEventType; @@ -139,6 +148,36 @@ export async function handleHookEvent( } } + // Antigravity (agy) pipes a camelCase protojson payload; normalize the fields + // the handler downstream reads to canonical snake_case BEFORE any + // canonicalization runs. `toolCall.{name,args}` → `tool_name`/`tool_input`, + // `conversationId` → `session_id`, `workspacePaths[0]` → `cwd`, + // `transcriptPath` → `transcript_path`. Verified against agy v1.1.2. + if (cli === "antigravity") { + const tc = parsed.toolCall as { name?: string; args?: unknown } | undefined; + if (tc && typeof tc === "object") { + if (tc.name !== undefined) parsed.tool_name = tc.name; + if (tc.args !== undefined) parsed.tool_input = tc.args; + } + if (typeof parsed.conversationId === "string") parsed.session_id = parsed.conversationId; + if (Array.isArray(parsed.workspacePaths) && typeof parsed.workspacePaths[0] === "string") { + parsed.cwd = parsed.workspacePaths[0]; + } + if (typeof parsed.transcriptPath === "string") parsed.transcript_path = parsed.transcriptPath; + } + + // Goose pipes `event` / `working_dir` instead of Claude's `hook_event_name` / + // `cwd` (its `tool_name` / `tool_input` are already canonical field names). + // Normalize both so resolveCwd keeps its cwd (block-read-outside-cwd) and the + // round-tripped event name is available. The --hook arg is already PascalCase, + // so canonicalizeEventType needs no goose branch. Verified goose v1.43.0. + if (cli === "goose") { + if (typeof parsed.working_dir === "string") parsed.cwd = parsed.working_dir; + if (typeof parsed.event === "string" && parsed.hook_event_name === undefined) { + parsed.hook_event_name = parsed.event; + } + } + // Canonicalize event name (Codex sends snake_case; internals expect PascalCase) const canonicalEventType = canonicalizeEventType(eventType, cli); @@ -173,8 +212,8 @@ export async function handleHookEvent( hookEventName: parsed.hook_event_name as string | undefined, // Preserve the raw CLI-side event name (eventType arg) before // canonicalization. Response shapes that round-trip the agent-emitted - // event name (e.g. Gemini's `hookSpecificOutput.hookEventName`) prefer - // this over the canonicalized form when stdin omits hook_event_name. + // event name prefer this over the canonicalized form when stdin omits + // hook_event_name. rawHookEventName: eventType, cli, }; diff --git a/src/hooks/install-prompt.ts b/src/hooks/install-prompt.ts index 1e04009b..93c3f915 100644 --- a/src/hooks/install-prompt.ts +++ b/src/hooks/install-prompt.ts @@ -82,14 +82,14 @@ export async function resolveTargetClis( // Uninstall flow: no agent CLIs detected — nothing to remove from. Default to // claude so removeHooks operates over Claude's scopes (no-op if no settings file). console.log( - "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi, gemini). " + + "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi)." + "Defaulting to Claude Code; nothing will be removed if no settings file exists.\x1B[0m", ); fireDetectionEvent(["claude"], "defaulted_to_claude"); return ["claude"]; } console.log( - "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi, gemini). " + + "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi)." + "Defaulting to Claude Code; hooks will activate when an agent is installed.\x1B[0m", ); fireDetectionEvent(["claude"], "defaulted_to_claude"); diff --git a/src/hooks/integrations.ts b/src/hooks/integrations.ts index b932ffd0..011b93bf 100644 --- a/src/hooks/integrations.ts +++ b/src/hooks/integrations.ts @@ -26,10 +26,18 @@ import { OPENCODE_HOOK_SCOPES, PI_HOOK_EVENT_TYPES, PI_HOOK_SCOPES, - GEMINI_HOOK_EVENT_TYPES, - GEMINI_HOOK_SCOPES, HERMES_HOOK_EVENT_TYPES, HERMES_HOOK_SCOPES, + OPENCLAW_HOOK_EVENT_TYPES, + OPENCLAW_HOOK_SCOPES, + FACTORY_HOOK_EVENT_TYPES, + FACTORY_HOOK_SCOPES, + DEVIN_HOOK_EVENT_TYPES, + DEVIN_HOOK_SCOPES, + ANTIGRAVITY_HOOK_EVENT_TYPES, + ANTIGRAVITY_HOOK_SCOPES, + GOOSE_HOOK_EVENT_TYPES, + GOOSE_HOOK_SCOPES, FAILPROOFAI_HOOK_MARKER, INTEGRATION_TYPES, type IntegrationType, @@ -310,8 +318,7 @@ export const codex: Integration = { type: "command", // Codex reads `timeout` in SECONDS (the field is literally `timeout`, // default 600 per https://developers.openai.com/codex/hooks) — same unit as - // Claude/Cursor/Copilot, and unlike Gemini, whose `timeout` is in - // milliseconds (default 60000). 60 = 60s, not 60000ms (~16.7h). + // Claude/Cursor/Copilot. 60 = 60s. command, timeout: 60, [FAILPROOFAI_HOOK_MARKER]: true, @@ -1286,61 +1293,456 @@ function makePiProjectRelativeEntry(extPath: string): string { // works for the local user. return extResolved; } -// ── Gemini CLI integration ────────────────────────────────────────────────── -// -// Gemini's hook contract is the closest thing to a Claude Code clone we've -// shipped: same `{matcher, hooks: [{type, command, timeout}]}` settings shape, -// PascalCase event names, snake_case stdin payload field names (session_id, -// tool_name, tool_input, hook_event_name, cwd, transcript_path), subprocess -// execution model, and `$CLAUDE_PROJECT_DIR` env-var alias on top of its own -// `$GEMINI_PROJECT_DIR`. The integration is structurally identical to -// claudeCode below, with three deltas: -// -// • Settings paths: ~/.gemini/settings.json (user) / /.gemini/settings.json (project). -// System scope (/etc/gemini-cli/settings.json) is documented but not exposed. -// -// • Matcher field: each Gemini matcher entry carries an explicit `matcher` -// regex (e.g. `"write_file|replace"`). We default to `"*"` so policies fire -// on every tool call, mirroring the failproofai default of "every event, -// every tool". Users can hand-edit settings.json to scope tighter; we -// preserve their `matcher` field across re-installs by NOT replacing -// entries that aren't failproofai-marked. -// -// • Tool name canonicalization happens in handler.ts (snake_case → -// PascalCase via GEMINI_TOOL_MAP) so policies match unchanged; not the -// install layer's concern. +// ── Hermes (hermes-agent) — live hooks (Pillar 1) ──────────────────────────── // -// Detected via the `gemini` binary on PATH. +// External-command CLI like codex/cursor, but its config is YAML +// (`~/.hermes/config.yaml`) under a `hooks:` map, so the I/O layer uses the yaml +// Document API (comment-preserving). Flat per-event arrays like cursor: +// `hooks: { pre_tool_call: [ { command, timeout, } ], … }`. Hermes +// reads a `{"decision":"block",…}` JSON response on stdout (see +// policy-evaluator.ts); exit codes are ignored. User-scope only. + +/** One hook entry as stored under a `hooks:` event key in config.yaml. */ +interface HermesHookEntry { + command: string; + timeout?: number; + [key: string]: unknown; +} + +export const hermes: Integration = { + id: "hermes", + displayName: "Hermes", + scopes: HERMES_HOOK_SCOPES, + eventTypes: HERMES_HOOK_EVENT_TYPES, + + // Hermes config is USER-scope only (`~/.hermes/config.yaml`); there is no + // project/local file, so scope/cwd are irrelevant here. + getSettingsPath() { + return resolve(homedir(), ".hermes", "config.yaml"); + }, + + readSettings(settingsPath) { + // Return the yaml Document (cast) so writeHookEntries/writeSettings can + // round-trip it while preserving the user's other keys + comments. + return readYamlDoc(settingsPath) as unknown as Record; + }, + + writeSettings(settingsPath, settings) { + writeYamlDoc(settingsPath, settings as unknown as Document); + }, + + buildHookEntry(binaryPath, eventType, scope) { + // No matcher → fires for ALL tools / all platforms (slack/telegram/cli/cron) + // and internal subagents. `timeout` is in seconds; Hermes runs the command + // via shlex.split (shell=false). + const command = + scope === "project" + ? `npx -y failproofai --hook ${eventType} --cli hermes` + : `"${binaryPath}" --hook ${eventType} --cli hermes`; + return { + command, + timeout: 30, + [FAILPROOFAI_HOOK_MARKER]: true, + }; + }, + + isFailproofaiHook: isMarkedHook, + + writeHookEntries(settings, binaryPath, scope) { + const doc = settings as unknown as Document; + // Read the current hooks map as plain JS, then re-set ONLY the `hooks` key — + // preserving comments on every other part of config.yaml. + const js = (doc.toJS() ?? {}) as { hooks?: Record }; + const hooks: Record = + js.hooks && typeof js.hooks === "object" ? js.hooks : {}; + + for (const eventType of HERMES_HOOK_EVENT_TYPES) { + const entry = this.buildHookEntry(binaryPath, eventType, scope) as unknown as HermesHookEntry; + const arr = Array.isArray(hooks[eventType]) ? hooks[eventType] : []; + const idx = arr.findIndex((h) => isMarkedHook(h)); + if (idx >= 0) arr[idx] = entry; + else arr.push(entry); + hooks[eventType] = arr; + } + doc.set("hooks", hooks); + // The headless gateway has no TTY to answer Hermes's first-use hook-consent + // prompt, so auto-accept declared hooks. Tradeoff: also auto-accepts any + // other hook the operator adds; a targeted `shell-hooks-allowlist.json` + // pre-seed is a future refinement. + doc.set("hooks_auto_accept", true); + }, + + removeHooksFromFile(settingsPath) { + if (!existsSync(settingsPath)) return 0; + const doc = readYamlDoc(settingsPath); + const js = (doc.toJS() ?? {}) as { hooks?: Record }; + const hooks = js.hooks; + + let removed = 0; + if (hooks && typeof hooks === "object") { + for (const eventType of Object.keys(hooks)) { + const entries = hooks[eventType]; + if (!Array.isArray(entries)) continue; + const before = entries.length; + const filtered = entries.filter((h) => !isMarkedHook(h)); + removed += before - filtered.length; + if (filtered.length === 0) delete hooks[eventType]; + else hooks[eventType] = filtered; + } + if (removed > 0) { + if (Object.keys(hooks).length === 0) doc.delete("hooks"); + else doc.set("hooks", hooks); + } + } + + // Always drop our headless-consent flag on uninstall — even if the hooks were + // already removed manually — so it can't silently auto-accept future operator + // hooks. `doc.delete` returns true iff the key was present. + const droppedAutoAccept = doc.delete("hooks_auto_accept"); + if (removed > 0 || droppedAutoAccept) writeYamlDoc(settingsPath, doc); + return removed; + }, + + hooksInstalledInSettings(scope, cwd) { + const settingsPath = this.getSettingsPath(scope, cwd); + if (!existsSync(settingsPath)) return false; + try { + const doc = readYamlDoc(settingsPath); + const js = (doc.toJS() ?? {}) as { hooks?: Record }; + const hooks = js.hooks; + if (!hooks || typeof hooks !== "object") return false; + for (const entries of Object.values(hooks)) { + if (Array.isArray(entries) && entries.some((h) => isMarkedHook(h))) return true; + } + } catch { + // Corrupt config — treat as not installed. + } + return false; + }, + + detectInstalled() { + return binaryExists("hermes"); + }, +}; + +// ── OpenClaw integration ──────────────────────────────────────────────────── // -// Ref: https://geminicli.com/docs/hooks/ +// OpenClaw is a self-hosted assistant gateway. Enforcement is via its in-process +// PLUGIN hooks (file-based "internal hooks" are observation-only), so failproofai +// ships a static plugin package (`openclaw-plugin/`, like Pi's pi-extension) that +// async-spawns the binary and maps verdicts back. Install registers the plugin in +// `~/.openclaw/openclaw.json` (JSON): +// • plugins.load.paths[] → the shipped openclaw-plugin dir (absolute path) +// • plugins.entries.failproofai = { enabled: true, hooks: { allowConversationAccess: true } } +// (allowConversationAccess is required for the raw-conversation hooks +// before_agent_run / before_agent_finalize; verified live v2026.7.1). +// USER scope only — OpenClaw has no project config (workspace plugins are +// disabled by default). We NEVER delete the shipped plugin dir on uninstall +// (unlike OpenCode's generated shim) — uninstall only edits openclaw.json. +// Detected via the `openclaw` binary on PATH. + +const OPENCLAW_PLUGIN_ID = "failproofai"; + +interface OpenClawPluginsSection { + load?: { paths?: string[]; [k: string]: unknown }; + entries?: Record>; + allow?: string[]; + deny?: string[]; + [k: string]: unknown; +} +interface OpenClawSettingsFile { + plugins?: OpenClawPluginsSection; + [k: string]: unknown; +} -interface GeminiHookMatcher { - matcher?: string; - hooks?: Array>; +/** Absolute path to the failproofai-shipped OpenClaw plugin package. */ +function getOpenClawPluginPath(): string { + const fromEnv = process.env.FAILPROOFAI_PACKAGE_ROOT; + if (fromEnv) return resolve(fromEnv, "openclaw-plugin"); + return resolve(fileURLToPath(import.meta.url), "..", "..", "..", "openclaw-plugin"); } -interface GeminiSettingsFile { - hooks?: Record; - [key: string]: unknown; +/** True iff a plugins.load.paths entry was written by failproofai. */ +function isFailproofaiOpenClawPath(p: unknown): boolean { + if (typeof p !== "string") return false; + return /(?:^|\/)openclaw-plugin\/?$/.test(p) || (p.includes("openclaw-plugin") && p.includes("failproofai")); } -export const gemini: Integration = { - id: "gemini", - displayName: "Gemini CLI", - scopes: GEMINI_HOOK_SCOPES, - eventTypes: GEMINI_HOOK_EVENT_TYPES, +export const openclaw: Integration = { + id: "openclaw", + displayName: "OpenClaw", + scopes: OPENCLAW_HOOK_SCOPES, + eventTypes: OPENCLAW_HOOK_EVENT_TYPES, + + // USER scope only (~/.openclaw/openclaw.json); OpenClaw has no project config. + getSettingsPath() { + return resolve(homedir(), ".openclaw", "openclaw.json"); + }, + + readSettings(settingsPath) { + return readJsonFile(settingsPath); + }, + + writeSettings(settingsPath, settings) { + writeJsonFile(settingsPath, settings); + }, + + buildHookEntry() { + // OpenClaw registers plugins at the package level — one registration covers + // all hooks (the plugin's index.js wires every api.on(...) handler). This + // sentinel satisfies the interface; writeHookEntries does the real work. + return { + [FAILPROOFAI_HOOK_MARKER]: true, + _openclawPluginPath: getOpenClawPluginPath(), + }; + }, + + isFailproofaiHook(hook) { + if (typeof hook === "string") return isFailproofaiOpenClawPath(hook); + if (!hook || typeof hook !== "object") return false; + const h = hook as Record; + if (h[FAILPROOFAI_HOOK_MARKER] === true) return true; + if (typeof h.source === "string") return isFailproofaiOpenClawPath(h.source); + return false; + }, + + writeHookEntries(settings) { + const s = settings as OpenClawSettingsFile; + const plugins = (s.plugins ??= {}); + const load = (plugins.load ??= {}); + if (!Array.isArray(load.paths)) load.paths = []; + const dir = getOpenClawPluginPath(); + // Idempotent: replace any existing failproofai path, otherwise append. + const idx = load.paths.findIndex((p) => isFailproofaiOpenClawPath(p)); + if (idx >= 0) load.paths[idx] = dir; + else load.paths.push(dir); + + // Enable the plugin + grant conversation access (needed for before_agent_run + // / before_agent_finalize). Only set our own keys — operator config on this + // entry (e.g. hooks.timeouts.) and other entries are preserved. + const entries = (plugins.entries ??= {}); + const entry = (entries[OPENCLAW_PLUGIN_ID] ??= {}); + entry.enabled = true; + const hooks = ((entry.hooks as Record) ??= {}); + hooks.allowConversationAccess = true; + }, + + removeHooksFromFile(settingsPath) { + if (!existsSync(settingsPath)) return 0; + const settings = this.readSettings(settingsPath) as OpenClawSettingsFile; + const plugins = settings.plugins; + if (!plugins) return 0; + let removed = 0; + + if (Array.isArray(plugins.load?.paths)) { + const before = plugins.load.paths.length; + plugins.load.paths = plugins.load.paths.filter((p) => !isFailproofaiOpenClawPath(p)); + removed += before - plugins.load.paths.length; + if (plugins.load.paths.length === 0) delete plugins.load.paths; + if (plugins.load && Object.keys(plugins.load).length === 0) delete plugins.load; + } + if (plugins.entries && OPENCLAW_PLUGIN_ID in plugins.entries) { + delete plugins.entries[OPENCLAW_PLUGIN_ID]; + removed += 1; + if (Object.keys(plugins.entries).length === 0) delete plugins.entries; + } + // Prune an empty plugins object so uninstall leaves openclaw.json clean. + if (Object.keys(plugins).length === 0) delete settings.plugins; + + this.writeSettings(settingsPath, settings as Record); + return removed; + }, + + hooksInstalledInSettings(scope, cwd) { + const settingsPath = this.getSettingsPath(scope, cwd); + if (!existsSync(settingsPath)) return false; + try { + const settings = this.readSettings(settingsPath) as OpenClawSettingsFile; + const paths = settings.plugins?.load?.paths; + const pathPresent = Array.isArray(paths) && paths.some((p) => isFailproofaiOpenClawPath(p)); + const entryEnabled = settings.plugins?.entries?.[OPENCLAW_PLUGIN_ID]?.enabled === true; + return pathPresent && entryEnabled; + } catch { + return false; + } + }, + + detectInstalled() { + return binaryExists("openclaw"); + }, +}; + +// ── Factory Droid (droid) integration ─────────────────────────────────────── +// +// Factory's droid CLI uses a Claude-compatible external-command hook system, +// but its hooks.json puts event names at the TOP LEVEL — there is NO `"hooks"` +// wrapper (the file IS the events object). Verified live against droid +// v0.171.0: a `{"hooks":{…}}` wrapper is rejected with `WARN Ignoring unknown +// hook event keys keys:["hooks"]`. Tool events (PreToolUse / PostToolUse) carry +// `"matcher": "*"`; non-tool events omit the matcher. Deny is exit-2 + stderr +// (see policy-evaluator.ts). Event names are already PascalCase, so no event +// canonicalization is needed. Settings paths: ~/.factory/hooks.json (user) and +// /.factory/hooks.json (project); no "local" scope. + +interface FactoryHookMatcher { + matcher?: string; + hooks: Array>; +} + +/** The Factory settings file IS the top-level events map (no wrapper key). */ +type FactorySettingsFile = Record; + +export const factory: Integration = { + id: "factory", + displayName: "Factory Droid", + scopes: FACTORY_HOOK_SCOPES, + eventTypes: FACTORY_HOOK_EVENT_TYPES, + + getSettingsPath(scope, cwd) { + const base = cwd ? resolve(cwd) : process.cwd(); + switch (scope) { + case "user": + return resolve(homedir(), ".factory", "hooks.json"); + case "project": + return resolve(base, ".factory", "hooks.json"); + case "local": + // Factory has no "local" scope; the CLI rejects --cli factory --scope + // local before reaching here, but fall back to project so callers don't + // crash. + return resolve(base, ".factory", "hooks.json"); + } + }, + + readSettings(settingsPath) { + return readJsonFile(settingsPath); + }, + + writeSettings(settingsPath, settings) { + writeJsonFile(settingsPath, settings); + }, + + buildHookEntry(binaryPath, eventType, scope) { + const command = + scope === "project" + ? `npx -y failproofai --hook ${eventType} --cli factory` + : `"${binaryPath}" --hook ${eventType} --cli factory`; + return { + type: "command", + command, + // droid reads `timeout` in SECONDS (verified against droid v0.171.0). 30s. + timeout: 30, + [FAILPROOFAI_HOOK_MARKER]: true, + }; + }, + + isFailproofaiHook: isMarkedHook, + + writeHookEntries(settings, binaryPath, scope) { + const s = settings as Record; + + for (const eventType of FACTORY_HOOK_EVENT_TYPES) { + const hookEntry = this.buildHookEntry(binaryPath, eventType, scope) as unknown as ClaudeHookEntry; + if (!Array.isArray(s[eventType])) s[eventType] = []; + const matchers: FactoryHookMatcher[] = s[eventType]; + + let found = false; + for (const matcher of matchers) { + if (!matcher.hooks) continue; + const idx = matcher.hooks.findIndex((h) => isMarkedHook(h as Record)); + if (idx >= 0) { + matcher.hooks[idx] = hookEntry; + found = true; + break; + } + } + if (!found) { + // Tool events match all tools via `matcher: "*"`; non-tool events carry + // no matcher (verified live against droid v0.171.0). + const isToolEvent = eventType === "PreToolUse" || eventType === "PostToolUse"; + matchers.push(isToolEvent ? { matcher: "*", hooks: [hookEntry] } : { hooks: [hookEntry] }); + } + } + }, + + removeHooksFromFile(settingsPath) { + const settings = this.readSettings(settingsPath) as FactorySettingsFile; + + let removed = 0; + for (const eventType of Object.keys(settings)) { + const matchers = settings[eventType]; + if (!Array.isArray(matchers)) continue; + for (let i = matchers.length - 1; i >= 0; i--) { + const matcher = matchers[i] as FactoryHookMatcher; + if (!matcher || !matcher.hooks) continue; + const before = matcher.hooks.length; + matcher.hooks = matcher.hooks.filter((h) => !isMarkedHook(h as Record)); + removed += before - matcher.hooks.length; + if (matcher.hooks.length === 0) matchers.splice(i, 1); + } + if (matchers.length === 0) delete settings[eventType]; + } + + this.writeSettings(settingsPath, settings as Record); + return removed; + }, + + hooksInstalledInSettings(scope, cwd) { + const settingsPath = this.getSettingsPath(scope, cwd); + if (!existsSync(settingsPath)) return false; + try { + const settings = this.readSettings(settingsPath) as FactorySettingsFile; + for (const matchers of Object.values(settings)) { + if (!Array.isArray(matchers)) continue; + for (const matcher of matchers as FactoryHookMatcher[]) { + if (!matcher || !matcher.hooks) continue; + if (matcher.hooks.some((h) => isMarkedHook(h as Record))) return true; + } + } + } catch { + // Corrupt settings — treat as not installed + } + return false; + }, + + detectInstalled() { + return binaryExists("droid"); + }, +}; + +// ── Devin CLI (devin) integration ──────────────────────────────────────────── +// +// Devin's CLI (Cognition) is a **pure Claude-clone** external-command hook +// system, verified live against devin v3000.1.27. It uses the standard Claude +// `"hooks"`-wrapper schema, so this Integration mirrors `claudeCode` verbatim — +// only the settings paths and the `--cli devin` command flag differ. The +// config file also carries the operator's own keys (`org_id`, `theme_mode`, +// …), so readSettings/writeSettings use the merge-preserving JSON helpers. +// +// Settings paths (verified against devin v3000.1.27): +// user → ~/.config/devin/config.json (the `"hooks"` key) +// project → /.devin/config.json (the `"hooks"` key) +// No "local" scope. Event names are already PascalCase (no event map / no +// handler branch); the stdin payload is Claude snake_case (no normalization). +// Deny/instruct semantics live in policy-evaluator.ts's `cli === "devin"` +// branch (`{decision:"block", reason}` on stdout at exit 0). + +export const devin: Integration = { + id: "devin", + displayName: "Devin CLI", + scopes: DEVIN_HOOK_SCOPES, + eventTypes: DEVIN_HOOK_EVENT_TYPES, getSettingsPath(scope, cwd) { const base = cwd ? resolve(cwd) : process.cwd(); switch (scope) { case "user": - return resolve(homedir(), ".gemini", "settings.json"); + return resolve(homedir(), ".config", "devin", "config.json"); case "project": - return resolve(base, ".gemini", "settings.json"); + return resolve(base, ".devin", "config.json"); case "local": - // Gemini has no "local" scope; CLI rejects --cli gemini --scope local + // Devin has no "local" scope; the CLI rejects --cli devin --scope local // before reaching here, but fall back to project so callers don't crash. - return resolve(base, ".gemini", "settings.json"); + return resolve(base, ".devin", "config.json"); } }, @@ -1355,12 +1757,13 @@ export const gemini: Integration = { buildHookEntry(binaryPath, eventType, scope) { const command = scope === "project" - ? `npx -y failproofai --hook ${eventType} --cli gemini` - : `"${binaryPath}" --hook ${eventType} --cli gemini`; + ? `npx -y failproofai --hook ${eventType} --cli devin` + : `"${binaryPath}" --hook ${eventType} --cli devin`; return { type: "command", command, - timeout: 60_000, + // Devin reads `timeout` in SECONDS like Claude. 60 = 60s. + timeout: 60, [FAILPROOFAI_HOOK_MARKER]: true, }; }, @@ -1368,19 +1771,14 @@ export const gemini: Integration = { isFailproofaiHook: isMarkedHook, writeHookEntries(settings, binaryPath, scope) { - const s = settings as GeminiSettingsFile; + const s = settings as ClaudeSettings; if (!s.hooks) s.hooks = {}; - for (const eventType of GEMINI_HOOK_EVENT_TYPES) { + for (const eventType of DEVIN_HOOK_EVENT_TYPES) { const hookEntry = this.buildHookEntry(binaryPath, eventType, scope) as unknown as ClaudeHookEntry; if (!s.hooks[eventType]) s.hooks[eventType] = []; - const matchers: GeminiHookMatcher[] = s.hooks[eventType]; + const matchers: ClaudeHookMatcher[] = s.hooks[eventType]; - // Idempotent: replace an existing failproofai-marked entry inside our - // own matcher; otherwise append a new `{matcher: "*", hooks: [...]}`. - // Hand-written matchers (with their own `matcher` regex) are never - // touched — we identify our matcher by checking whether ANY of its - // inner hooks are failproofai-marked. let found = false; for (const matcher of matchers) { if (!matcher.hooks) continue; @@ -1391,12 +1789,12 @@ export const gemini: Integration = { break; } } - if (!found) matchers.push({ matcher: "*", hooks: [hookEntry] }); + if (!found) matchers.push({ hooks: [hookEntry] }); } }, removeHooksFromFile(settingsPath) { - const settings = this.readSettings(settingsPath) as GeminiSettingsFile; + const settings = this.readSettings(settingsPath) as ClaudeSettings; if (!settings.hooks) return 0; let removed = 0; @@ -1423,7 +1821,7 @@ export const gemini: Integration = { const settingsPath = this.getSettingsPath(scope, cwd); if (!existsSync(settingsPath)) return false; try { - const settings = this.readSettings(settingsPath) as GeminiSettingsFile; + const settings = this.readSettings(settingsPath) as ClaudeSettings; if (!settings.hooks) return false; for (const matchers of Object.values(settings.hooks)) { if (!Array.isArray(matchers)) continue; @@ -1439,58 +1837,77 @@ export const gemini: Integration = { }, detectInstalled() { - return binaryExists("gemini"); + return binaryExists("devin"); }, }; -// ── Hermes (hermes-agent) — live hooks (Pillar 1) ──────────────────────────── +// ── Antigravity CLI (antigravity) integration ──────────────────────────────── // -// External-command CLI like codex/cursor, but its config is YAML -// (`~/.hermes/config.yaml`) under a `hooks:` map, so the I/O layer uses the yaml -// Document API (comment-preserving). Flat per-event arrays like cursor: -// `hooks: { pre_tool_call: [ { command, timeout, } ], … }`. Hermes -// reads a `{"decision":"block",…}` JSON response on stdout (see -// policy-evaluator.ts); exit codes are ignored. User-scope only. - -/** One hook entry as stored under a `hooks:` event key in config.yaml. */ -interface HermesHookEntry { - command: string; - timeout?: number; - [key: string]: unknown; +// Antigravity's `agy` CLI uses a NAMED-hook schema: the hooks.json top-level key +// is a hook *name* ("failproofai"), whose value is an event→handlers map. Tool +// events (PreToolUse / PostToolUse) wrap handlers in `{matcher, hooks:[…]}`; +// non-tool events (PreInvocation / Stop) are FLAT arrays of handler objects. +// Verified live against agy v1.1.2. Settings paths: +// user → ~/.gemini/config/hooks.json +// project → /.agents/hooks.json +// No "local" scope. Deny/instruct semantics live in policy-evaluator.ts's +// `cli === "antigravity"` branch (Antigravity's OWN `{decision:"deny"}` / +// `{decision:"continue"}` / `{injectSteps}` shapes — NOT Claude's). + +/** The Antigravity settings file is `{ "": { : … } }`. Our + * named hook is "failproofai". */ +const ANTIGRAVITY_HOOK_NAME = "failproofai"; + +interface AntigravityToolMatcher { + matcher?: string; + hooks: Array>; } +/** An Antigravity named-hook body: tool events → `{matcher, hooks}[]`; flat + * events (PreInvocation / Stop) → `handler[]`. */ +type AntigravityNamedHook = Record< + string, + AntigravityToolMatcher[] | Array> +>; -export const hermes: Integration = { - id: "hermes", - displayName: "Hermes", - scopes: HERMES_HOOK_SCOPES, - eventTypes: HERMES_HOOK_EVENT_TYPES, +const ANTIGRAVITY_TOOL_EVENTS = new Set(["PreToolUse", "PostToolUse"]); - // Hermes config is USER-scope only (`~/.hermes/config.yaml`); there is no - // project/local file, so scope/cwd are irrelevant here. - getSettingsPath() { - return resolve(homedir(), ".hermes", "config.yaml"); +export const antigravity: Integration = { + id: "antigravity", + displayName: "Antigravity CLI", + scopes: ANTIGRAVITY_HOOK_SCOPES, + eventTypes: ANTIGRAVITY_HOOK_EVENT_TYPES, + + getSettingsPath(scope, cwd) { + const base = cwd ? resolve(cwd) : process.cwd(); + switch (scope) { + case "user": + return resolve(homedir(), ".gemini", "config", "hooks.json"); + case "project": + return resolve(base, ".agents", "hooks.json"); + case "local": + // Antigravity has no "local" scope; the CLI rejects it before reaching + // here, but fall back to project so callers don't crash. + return resolve(base, ".agents", "hooks.json"); + } }, readSettings(settingsPath) { - // Return the yaml Document (cast) so writeHookEntries/writeSettings can - // round-trip it while preserving the user's other keys + comments. - return readYamlDoc(settingsPath) as unknown as Record; + return readJsonFile(settingsPath); }, writeSettings(settingsPath, settings) { - writeYamlDoc(settingsPath, settings as unknown as Document); + writeJsonFile(settingsPath, settings); }, buildHookEntry(binaryPath, eventType, scope) { - // No matcher → fires for ALL tools / all platforms (slack/telegram/cli/cron) - // and internal subagents. `timeout` is in seconds; Hermes runs the command - // via shlex.split (shell=false). const command = scope === "project" - ? `npx -y failproofai --hook ${eventType} --cli hermes` - : `"${binaryPath}" --hook ${eventType} --cli hermes`; + ? `npx -y failproofai --hook ${eventType} --cli antigravity` + : `"${binaryPath}" --hook ${eventType} --cli antigravity`; return { + type: "command", command, + // Antigravity reads `timeout` in SECONDS (verified agy v1.1.2). 30s. timeout: 30, [FAILPROOFAI_HOOK_MARKER]: true, }; @@ -1499,57 +1916,235 @@ export const hermes: Integration = { isFailproofaiHook: isMarkedHook, writeHookEntries(settings, binaryPath, scope) { - const doc = settings as unknown as Document; - // Read the current hooks map as plain JS, then re-set ONLY the `hooks` key — - // preserving comments on every other part of config.yaml. - const js = (doc.toJS() ?? {}) as { hooks?: Record }; - const hooks: Record = - js.hooks && typeof js.hooks === "object" ? js.hooks : {}; + const s = settings as Record; + if (!s[ANTIGRAVITY_HOOK_NAME] || typeof s[ANTIGRAVITY_HOOK_NAME] !== "object") { + s[ANTIGRAVITY_HOOK_NAME] = {}; + } + const named = s[ANTIGRAVITY_HOOK_NAME] as AntigravityNamedHook; - for (const eventType of HERMES_HOOK_EVENT_TYPES) { - const entry = this.buildHookEntry(binaryPath, eventType, scope) as unknown as HermesHookEntry; - const arr = Array.isArray(hooks[eventType]) ? hooks[eventType] : []; - const idx = arr.findIndex((h) => isMarkedHook(h)); - if (idx >= 0) arr[idx] = entry; - else arr.push(entry); - hooks[eventType] = arr; + for (const eventType of ANTIGRAVITY_HOOK_EVENT_TYPES) { + const hookEntry = this.buildHookEntry(binaryPath, eventType, scope) as unknown as ClaudeHookEntry; + const isToolEvent = ANTIGRAVITY_TOOL_EVENTS.has(eventType); + + if (isToolEvent) { + if (!Array.isArray(named[eventType])) named[eventType] = [] as AntigravityToolMatcher[]; + const matchers = named[eventType] as AntigravityToolMatcher[]; + let found = false; + for (const matcher of matchers) { + if (!matcher.hooks) continue; + const idx = matcher.hooks.findIndex((h) => isMarkedHook(h as Record)); + if (idx >= 0) { + matcher.hooks[idx] = hookEntry; + found = true; + break; + } + } + if (!found) matchers.push({ matcher: "*", hooks: [hookEntry] }); + } else { + // Flat array of handler objects (PreInvocation / Stop). + if (!Array.isArray(named[eventType])) named[eventType] = [] as Array>; + const handlers = named[eventType] as Array>; + const idx = handlers.findIndex((h) => isMarkedHook(h as Record)); + if (idx >= 0) handlers[idx] = hookEntry; + else handlers.push(hookEntry); + } } - doc.set("hooks", hooks); - // The headless gateway has no TTY to answer Hermes's first-use hook-consent - // prompt, so auto-accept declared hooks. Tradeoff: also auto-accepts any - // other hook the operator adds; a targeted `shell-hooks-allowlist.json` - // pre-seed is a future refinement. - doc.set("hooks_auto_accept", true); }, removeHooksFromFile(settingsPath) { - if (!existsSync(settingsPath)) return 0; - const doc = readYamlDoc(settingsPath); - const js = (doc.toJS() ?? {}) as { hooks?: Record }; - const hooks = js.hooks; + const settings = this.readSettings(settingsPath) as Record; + const named = settings[ANTIGRAVITY_HOOK_NAME]; + if (!named || typeof named !== "object") { + this.writeSettings(settingsPath, settings); + return 0; + } + const namedHook = named as AntigravityNamedHook; let removed = 0; - if (hooks && typeof hooks === "object") { - for (const eventType of Object.keys(hooks)) { - const entries = hooks[eventType]; - if (!Array.isArray(entries)) continue; - const before = entries.length; - const filtered = entries.filter((h) => !isMarkedHook(h)); + for (const eventType of Object.keys(namedHook)) { + const value = namedHook[eventType]; + if (!Array.isArray(value)) continue; + if (ANTIGRAVITY_TOOL_EVENTS.has(eventType)) { + const matchers = value as AntigravityToolMatcher[]; + for (let i = matchers.length - 1; i >= 0; i--) { + const matcher = matchers[i]; + if (!matcher || !matcher.hooks) continue; + const before = matcher.hooks.length; + matcher.hooks = matcher.hooks.filter((h) => !isMarkedHook(h as Record)); + removed += before - matcher.hooks.length; + if (matcher.hooks.length === 0) matchers.splice(i, 1); + } + if (matchers.length === 0) delete namedHook[eventType]; + } else { + const handlers = value as Array>; + const before = handlers.length; + const filtered = handlers.filter((h) => !isMarkedHook(h)); removed += before - filtered.length; - if (filtered.length === 0) delete hooks[eventType]; - else hooks[eventType] = filtered; + if (filtered.length === 0) delete namedHook[eventType]; + else namedHook[eventType] = filtered as Array>; } - if (removed > 0) { - if (Object.keys(hooks).length === 0) doc.delete("hooks"); - else doc.set("hooks", hooks); + } + // Drop the named hook entirely if it has no remaining events. + if (Object.keys(namedHook).length === 0) delete settings[ANTIGRAVITY_HOOK_NAME]; + + this.writeSettings(settingsPath, settings); + return removed; + }, + + hooksInstalledInSettings(scope, cwd) { + const settingsPath = this.getSettingsPath(scope, cwd); + if (!existsSync(settingsPath)) return false; + try { + const settings = this.readSettings(settingsPath) as Record; + const named = settings[ANTIGRAVITY_HOOK_NAME]; + if (!named || typeof named !== "object") return false; + for (const value of Object.values(named as AntigravityNamedHook)) { + if (!Array.isArray(value)) continue; + for (const item of value) { + if (isMarkedHook(item as Record)) return true; + const matcher = item as AntigravityToolMatcher; + if (matcher && Array.isArray(matcher.hooks) && matcher.hooks.some((h) => isMarkedHook(h as Record))) { + return true; + } + } } + } catch { + // Corrupt settings — treat as not installed } + return false; + }, - // Always drop our headless-consent flag on uninstall — even if the hooks were - // already removed manually — so it can't silently auto-accept future operator - // hooks. `doc.delete` returns true iff the key was present. - const droppedAutoAccept = doc.delete("hooks_auto_accept"); - if (removed > 0 || droppedAutoAccept) writeYamlDoc(settingsPath, doc); + detectInstalled() { + return binaryExists("agy"); + }, +}; + +// ── Goose (codename goose, Block) integration ──────────────────────────────── +// +// Goose's "hooks" system follows the cross-agent Open Plugins spec: a plugin +// directory whose hooks/hooks.json wires shell commands into agent events. +// failproofai owns the entire `failproofai` plugin dir and writes an Open +// Plugins hooks.json — `{"hooks": {: [{"hooks": [{type, command}]}]}}`. +// Two differences from Factory (verified live against goose v1.43.0): +// 1. the schema DOES carry the top-level "hooks" wrapper (like Claude), and +// 2. the matcher is OMITTED on every event — a bare "*" is an invalid regex +// that matches NOTHING (omitted = match all tools). +// Entries are the clean `{type, command}` shape with NO marker field — Goose +// parses this file, so we identify our hooks by the `--cli goose` command +// substring instead of injecting `__failproofai_hook__`. Goose auto-discovers +// the dir at startup (no config edit) and self-registers it into +// ~/.config/goose/config.yaml; uninstall clears our entries (the emptied +// hooks.json and the auto-added config `plugins:` entry are left for Goose to +// reconcile on next start — it logs the empty plugin and continues, harmless). +// Deny is PreToolUse-only JSON (see policy-evaluator.ts). Settings paths: +// ~/.agents/plugins/failproofai/hooks/hooks.json (user) and +// /.agents/plugins/failproofai/hooks/hooks.json (project); no "local" scope. + +interface GooseHookMatcher { + matcher?: string; + hooks: Array>; +} +/** The Open Plugins hooks file: { "hooks": { : GooseHookMatcher[] } }. */ +interface GooseHooksFile { + hooks?: Record; + [key: string]: unknown; +} + +/** failproofai owns the `failproofai` Goose plugin dir; identify our hook + * entries by the `--cli goose` command substring (the file is Goose-parsed, so + * entries stay the clean {type, command} shape with no marker field). */ +function isGooseFailproofaiHook(hook: unknown): boolean { + if (!hook || typeof hook !== "object") return false; + const cmd = (hook as { command?: unknown }).command; + return typeof cmd === "string" && cmd.includes("failproofai") && cmd.includes("--cli goose"); +} + +export const goose: Integration = { + id: "goose", + displayName: "Goose", + scopes: GOOSE_HOOK_SCOPES, + eventTypes: GOOSE_HOOK_EVENT_TYPES, + + getSettingsPath(scope, cwd) { + const base = cwd ? resolve(cwd) : process.cwd(); + switch (scope) { + case "user": + return resolve(homedir(), ".agents", "plugins", "failproofai", "hooks", "hooks.json"); + case "project": + return resolve(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json"); + case "local": + // Goose has no "local" scope; the CLI rejects --scope local before + // reaching here, but fall back to project so callers don't crash. + return resolve(base, ".agents", "plugins", "failproofai", "hooks", "hooks.json"); + } + }, + + readSettings(settingsPath) { + return readJsonFile(settingsPath); + }, + + writeSettings(settingsPath, settings) { + writeJsonFile(settingsPath, settings); + }, + + buildHookEntry(binaryPath, eventType, scope) { + const command = + scope === "project" + ? `npx -y failproofai --hook ${eventType} --cli goose` + : `"${binaryPath}" --hook ${eventType} --cli goose`; + // Open Plugins command entry: { type, command } only (Goose applies its own + // timeout; no marker field — see isGooseFailproofaiHook). + return { type: "command", command }; + }, + + isFailproofaiHook: isGooseFailproofaiHook, + + writeHookEntries(settings, binaryPath, scope) { + const s = settings as GooseHooksFile; + if (!s.hooks) s.hooks = {}; + + for (const eventType of GOOSE_HOOK_EVENT_TYPES) { + const hookEntry = this.buildHookEntry(binaryPath, eventType, scope); + if (!Array.isArray(s.hooks[eventType])) s.hooks[eventType] = []; + const matchers: GooseHookMatcher[] = s.hooks[eventType]; + + let found = false; + for (const matcher of matchers) { + if (!matcher.hooks) continue; + const idx = matcher.hooks.findIndex((h) => isGooseFailproofaiHook(h)); + if (idx >= 0) { + matcher.hooks[idx] = hookEntry; + found = true; + break; + } + } + // matcher OMITTED on every event (a bare "*" matches nothing; omitted = + // match all tools — verified live against goose v1.43.0). + if (!found) matchers.push({ hooks: [hookEntry] }); + } + }, + + removeHooksFromFile(settingsPath) { + const settings = this.readSettings(settingsPath) as GooseHooksFile; + if (!settings.hooks) return 0; + + let removed = 0; + for (const eventType of Object.keys(settings.hooks)) { + const matchers = settings.hooks[eventType]; + if (!Array.isArray(matchers)) continue; + for (let i = matchers.length - 1; i >= 0; i--) { + const matcher = matchers[i]; + if (!matcher || !matcher.hooks) continue; + const before = matcher.hooks.length; + matcher.hooks = matcher.hooks.filter((h) => !isGooseFailproofaiHook(h)); + removed += before - matcher.hooks.length; + if (matcher.hooks.length === 0) matchers.splice(i, 1); + } + if (matchers.length === 0) delete settings.hooks[eventType]; + } + if (Object.keys(settings.hooks).length === 0) delete settings.hooks; + + this.writeSettings(settingsPath, settings as Record); return removed; }, @@ -1557,21 +2152,23 @@ export const hermes: Integration = { const settingsPath = this.getSettingsPath(scope, cwd); if (!existsSync(settingsPath)) return false; try { - const doc = readYamlDoc(settingsPath); - const js = (doc.toJS() ?? {}) as { hooks?: Record }; - const hooks = js.hooks; - if (!hooks || typeof hooks !== "object") return false; - for (const entries of Object.values(hooks)) { - if (Array.isArray(entries) && entries.some((h) => isMarkedHook(h))) return true; + const settings = this.readSettings(settingsPath) as GooseHooksFile; + if (!settings.hooks) return false; + for (const matchers of Object.values(settings.hooks)) { + if (!Array.isArray(matchers)) continue; + for (const matcher of matchers) { + if (!matcher || !matcher.hooks) continue; + if (matcher.hooks.some((h) => isGooseFailproofaiHook(h))) return true; + } } } catch { - // Corrupt config — treat as not installed. + // Corrupt settings — treat as not installed } return false; }, detectInstalled() { - return binaryExists("hermes"); + return binaryExists("goose"); }, }; @@ -1589,8 +2186,12 @@ const INTEGRATIONS: Partial> = { cursor, opencode, pi, - gemini, hermes, + openclaw, + factory, + devin, + antigravity, + goose, }; export function getIntegration(id: IntegrationType): Integration { diff --git a/src/hooks/policy-evaluator.ts b/src/hooks/policy-evaluator.ts index c5064d81..6e6a511b 100644 --- a/src/hooks/policy-evaluator.ts +++ b/src/hooks/policy-evaluator.ts @@ -164,8 +164,7 @@ export async function evaluatePolicies( // — that shape is only honored on tool events. The only force-retry // channel for Stop/SubagentStop is `{followup_message}` on stdout // (exit 0); Cursor auto-submits the text as the next user message - // (capped at `loop_limit`, default 5). Mirrors the Copilot Stop - // branch at line ~279 and the Gemini AfterAgent branch at line ~188. + // (capped at `loop_limit`, default 5). Mirrors the Copilot Stop branch. // Without this branch, the 5 `require-*-before-stop` builtins were // observation-only on Cursor — the deny was logged but the agent // stopped cleanly. Ref: https://cursor.com/docs/hooks @@ -202,7 +201,7 @@ export async function evaluatePolicies( // same flat shape — except Stop, where we emit the MANDATORY ACTION // wording so the shim can re-inject it as a system-prompt suffix on // the next before_agent_start (Pi cannot veto agent_end directly). - // Mirrors the Cursor/Gemini/Copilot/OpenCode Stop branches above. + // Mirrors the Cursor/Copilot/OpenCode Stop branches above. if (session?.cli === "pi") { if (eventType === "Stop") { const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; @@ -229,33 +228,6 @@ export async function evaluatePolicies( }; } - // Gemini CLI: flat `{decision: "deny", reason}` for non-Stop events - // (preferred per Gemini's "Golden Rule" — exit 0 with structured JSON). - // For Stop (AfterAgent), use `{decision: "block", reason}` to force-retry, - // mirroring Claude's exit-2-from-Stop "do this before stopping" semantics. - // Ref: https://geminicli.com/docs/hooks/ - if (session?.cli === "gemini") { - if (eventType === "Stop") { - const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: reasonText }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - return { - exitCode: 0, - stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }), - stderr: "", - policyName: policy.name, - reason, - decision: "deny", - }; - } - // Hermes: the block contract is `{"decision":"block","reason"}` on stdout; // Hermes IGNORES exit codes, so the JSON is the only channel. This one // return covers every Hermes event we install (PreToolUse / PostToolUse / @@ -275,6 +247,36 @@ export async function evaluatePolicies( }; } + // OpenClaw: the shipped openclaw-plugin parses a flat {permission, reason} + // verdict and maps it per plugin-hook — before_tool_call → {block:true, + // blockReason}; before_agent_run → {outcome:"block", reason}; + // before_agent_finalize (Stop) → {action:"revise", reason}. For Stop we + // emit the MANDATORY ACTION wording so the revise loop carries the + // directive. Observation hooks (after_tool_call / session_* / + // subagent_ended / before_compaction) ignore stdout, so the flat deny is + // logged but cannot veto — a documented limitation. Mirrors the Pi branch. + if (session?.cli === "openclaw") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + return { + exitCode: 0, + stdout: JSON.stringify({ permission: "deny", reason: blockedMessage }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + // OpenCode: `session.idle` is a notification-only bus event — by the // time the plugin handler fires, OpenCode has already gone idle and // throwing from the handler does not force-retry. The only working @@ -283,8 +285,8 @@ export async function evaluatePolicies( // shim already routes `hookSpecificOutput.additionalContext` through // that path (see buildOpenCodePluginShim's applyDecision), so we emit // the deny reason as additionalContext instead of exit-2. Mirrors the - // Cursor `followup_message` (line ~157) and Copilot `{decision:"block"}` - // (line ~299) Stop branches. SubagentStop is widened in for forward + // Cursor `followup_message` and Copilot `{decision:"block"}` Stop + // branches. SubagentStop is widened in for forward // compat — OpenCode doesn't yet expose subagent boundaries to plugins. if (session?.cli === "opencode") { if (eventType === "Stop" || eventType === "SubagentStop") { @@ -303,6 +305,105 @@ export async function evaluatePolicies( // for tool events. } + // Factory droid: droid drives tool blocking off EXIT CODE 2 (it ignores a + // JSON `{decision:…}` on tool events — verified live against droid + // v0.171.0: `Hook returned exit code 2, throwing ToolExecutionControlError`). + // The one exception is `Stop`, where droid does NOT honor exit-2 + // force-retry; there it reads `{decision:"block", reason}` on stdout at + // exit 0 ("if decision is block, Droid does not stop"). So: Stop → JSON + // block; every other event (PreToolUse / PostToolUse / UserPromptSubmit / + // SubagentStop / …) → exit 2 + the blocked message on stderr. + if (session?.cli === "factory") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + return { + exitCode: 2, + stdout: "", + stderr: blockedMessage + "\n", + policyName: policy.name, + reason, + decision: "deny", + }; + } + + // Devin CLI: a pure Claude-clone that honors `{decision:"block", reason}` + // on stdout at exit 0 for EVERY event (verified live against devin + // v3000.1.27 — the block overrode `--permission-mode dangerous`). On Stop + // the reason carries the MANDATORY-ACTION force-retry wording; on other + // events it's the plain blocked message. One branch covers all events. + if (session?.cli === "devin") { + const reasonText = + eventType === "Stop" + ? `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.` + : blockedMessage; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + + // Antigravity CLI: its OWN response shapes (NOT Claude's) — verified live + // against agy v1.1.2. Tool/prompt events honor `{decision:"deny", reason}` + // on stdout at exit 0 (hard block). The Stop event has no exit-2 retry; + // instead `{decision:"continue", reason}` re-enters the loop and injects + // the reason as a system message — that is how the 5 require-*-before-stop + // builtins enforce on Antigravity. + if (session?.cli === "antigravity") { + if (eventType === "Stop") { + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (policy: ${policy.name}): ${reason}\n\nYou MUST complete the above action NOW. Do NOT ask the user for confirmation — execute the required action, then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "continue", reason: reasonText }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "deny", reason: blockedMessage }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + + // Goose: the deny contract is `{"decision":"block","reason"}` on stdout at + // exit 0, honored on PreToolUse ONLY (shipped goose ≥ v1.37.0, PR + // block/goose#9304; exit 2 also blocks but JSON carries the reason + // cleanly). Goose has NO Stop event (the 5 require-*-before-stop builtins + // never fire for it — see CLAUDE.md) and does NOT honor deny on + // UserPromptSubmit/PostToolUse (observation) — a block emitted on those + // events is ignored (fail-open), a documented limitation. PreToolUse fires + // for the shell tool AND inside delegated subagents, so this one branch + // covers the entire enforceable surface. Mirrors the Hermes branch (no + // turn-end event to special-case). Verified live against goose v1.43.0. + if (session?.cli === "goose") { + return { + exitCode: 0, + stdout: JSON.stringify({ decision: "block", reason: blockedMessage }), + stderr: "", + policyName: policy.name, + reason, + decision: "deny", + }; + } + if (eventType === "PreToolUse") { const response = { hookSpecificOutput: { @@ -429,8 +530,8 @@ export async function evaluatePolicies( // Branch first so the rest of the function only handles Claude-shaped // responses. We match both Stop and SubagentStop so custom policies // subscribing to SubagentStop on Cursor get the same force-retry - // semantics — mirrors the cli==="copilot" Stop|SubagentStop widening - // at line ~472. Ref: https://cursor.com/docs/hooks (Stdout Response Format). + // semantics — mirrors the cli==="copilot" Stop|SubagentStop widening. + // Ref: https://cursor.com/docs/hooks (Stdout Response Format). if (session?.cli === "cursor") { if (eventType === "Stop" || eventType === "SubagentStop") { const response = { @@ -499,15 +600,35 @@ export async function evaluatePolicies( }; } - // Gemini CLI: - // • Stop (AfterAgent) → {decision: "block", reason: "MANDATORY ACTION..."} - // mirrors Claude's exit-2-from-Stop "force retry" semantics. - // • UserPromptSubmit/PostToolUse/SessionStart/PreToolUse → context - // injection via {hookSpecificOutput: {hookEventName, additionalContext}} - // where hookEventName is the GEMINI event name (BeforeAgent/AfterTool/ - // SessionStart/BeforeTool), not the canonical PascalCase form. - // • Other events → stderr only (no stdout JSON shape supported). - if (session?.cli === "gemini") { + // Hermes: no additional-context channel on any event (the only actionable + // response is `{"decision":"block"}`). So instruct degrades to allow + + // log — we emit a non-blocking `{decision:"allow", reason}` (Hermes lets + // the tool run) and surface the note on stderr for the operator's logs. + // Documented limitation; there is no Stop event to force-retry into. + if (session?.cli === "hermes") { + const stderrMsg = instructEntries + .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) + .join("\n"); + return { + exitCode: 0, + stdout: JSON.stringify({ + decision: "allow", + reason: `Instruction from failproofai: ${combined}`, + }), + stderr: stderrMsg + "\n", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", + }; + } + + // OpenClaw: Stop (before_agent_finalize) can force a revise, so we emit the + // MANDATORY ACTION wording as a flat deny — the shim maps it to + // {action:"revise", reason}. Every other event lacks an additional-context + // channel (before_tool_call's return is {params,block,blockReason} only), so + // instruct degrades to allow + stderr note, like Hermes. + if (session?.cli === "openclaw") { if (eventType === "Stop") { const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` @@ -515,7 +636,7 @@ export async function evaluatePolicies( const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stdout: JSON.stringify({ permission: "deny", reason: reasonText }), stderr: "", policyName: policyNames[0], policyNames, @@ -523,31 +644,58 @@ export async function evaluatePolicies( decision: "instruct", }; } - // Map back from canonical → Gemini event name. Prefer the raw event name - // off the session (handler.ts populates it from parsed.hook_event_name) - // so we don't have to maintain a reverse lookup table. - const supportsContext = - eventType === "UserPromptSubmit" || - eventType === "PreToolUse" || - eventType === "PostToolUse" || - eventType === "SessionStart"; - if (supportsContext) { - // Round-trip the agent-emitted event name so Gemini sees `BeforeTool`, - // `BeforeAgent`, etc. (NOT the canonical Claude form). Prefer the - // stdin payload's `hook_event_name` when present; fall back to the raw - // CLI `--hook` arg captured by handler.ts; only use the canonical - // event as a last resort (would never round-trip correctly, but better - // than emitting nothing). - const hookEventName = session?.hookEventName ?? session?.rawHookEventName ?? eventType; - const response = { - hookSpecificOutput: { - hookEventName, - additionalContext: `Instruction from failproofai: ${combined}`, - }, + const stderrMsg = instructEntries + .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) + .join("\n"); + return { + exitCode: 0, + stdout: JSON.stringify({ + permission: "allow", + reason: `Instruction from failproofai: ${combined}`, + }), + stderr: stderrMsg + "\n", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", + }; + } + + // OpenCode: same rationale as the deny branch above — emit + // additionalContext so the shim submits a follow-up via + // client.session.prompt instead of throwing into a dead handler. + if (session?.cli === "opencode") { + if (eventType === "Stop" || eventType === "SubagentStop") { + const policyAttribution = policyNames.length === 1 + ? `policy: ${policyNames[0]}` + : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; + return { + exitCode: 0, + stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", }; + } + } + + // Factory droid: on Stop, emit the MANDATORY ACTION wording as a + // `{decision:"block", reason}` on stdout (exit 0) — droid's only turn-end + // force-retry channel. Every other event lacks an additional-context + // channel (droid honors JSON only for the Stop block), so instruct degrades + // to allow + stderr note, like Hermes. + if (session?.cli === "factory") { + if (eventType === "Stop") { + const policyAttribution = policyNames.length === 1 + ? `policy: ${policyNames[0]}` + : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify(response), + stdout: JSON.stringify({ decision: "block", reason: reasonText }), stderr: "", policyName: policyNames[0], policyNames, @@ -555,8 +703,6 @@ export async function evaluatePolicies( decision: "instruct", }; } - // No context-injection channel for SessionEnd/PreCompress/Notification/ - // BeforeModel/AfterModel/BeforeToolSelection — surface via stderr only. const stderrMsg = instructEntries .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) .join("\n"); @@ -571,22 +717,20 @@ export async function evaluatePolicies( }; } - // Hermes: no additional-context channel on any event (the only actionable - // response is `{"decision":"block"}`). So instruct degrades to allow + - // log — we emit a non-blocking `{decision:"allow", reason}` (Hermes lets - // the tool run) and surface the note on stderr for the operator's logs. - // Documented limitation; there is no Stop event to force-retry into. - if (session?.cli === "hermes") { - const stderrMsg = instructEntries - .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) - .join("\n"); + // Devin CLI: a pure Claude-clone. On Stop, emit the MANDATORY ACTION + // wording as `{decision:"block", reason}` on stdout (exit 0) — Devin's + // turn-end force-retry channel (its exit-2 is not a force-retry). Every + // other event falls through to the generic Claude additionalContext path + // below (Devin honors `hookSpecificOutput.additionalContext`). + if (session?.cli === "devin" && eventType === "Stop") { + const policyAttribution = policyNames.length === 1 + ? `policy: ${policyNames[0]}` + : `policies: ${policyNames.join(", ")}`; + const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ - decision: "allow", - reason: `Instruction from failproofai: ${combined}`, - }), - stderr: stderrMsg + "\n", + stdout: JSON.stringify({ decision: "block", reason: reasonText }), + stderr: "", policyName: policyNames[0], policyNames, reason: combined, @@ -594,18 +738,36 @@ export async function evaluatePolicies( }; } - // OpenCode: same rationale as the deny branch above — emit - // additionalContext so the shim submits a follow-up via - // client.session.prompt instead of throwing into a dead handler. - if (session?.cli === "opencode") { - if (eventType === "Stop" || eventType === "SubagentStop") { + // Antigravity CLI: its OWN instruct shapes (verified live agy v1.1.2). + // • UserPromptSubmit (canonical for PreInvocation) → `{injectSteps:[{ + // ephemeralMessage}]}` injects the instruction as a transient system + // message before the model runs. + // • Stop → `{decision:"continue", reason}` re-enters the loop with the + // MANDATORY-ACTION directive (Antigravity's only turn-end channel). + // • Every other event lacks an additional-context channel → degrade to + // allow + stderr note, like Hermes. + if (session?.cli === "antigravity") { + if (eventType === "UserPromptSubmit") { + return { + exitCode: 0, + stdout: JSON.stringify({ + injectSteps: [{ ephemeralMessage: `Instruction from failproofai: ${combined}` }], + }), + stderr: "", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", + }; + } + if (eventType === "Stop") { const policyAttribution = policyNames.length === 1 ? `policy: ${policyNames[0]}` : `policies: ${policyNames.join(", ")}`; const reasonText = `MANDATORY ACTION REQUIRED from failproofai (${policyAttribution}): ${combined}\n\nYou MUST complete the above action(s) NOW. Do NOT ask the user for confirmation — execute the required action(s), then attempt to finish your task again.`; return { exitCode: 0, - stdout: JSON.stringify({ hookSpecificOutput: { additionalContext: reasonText } }), + stdout: JSON.stringify({ decision: "continue", reason: reasonText }), stderr: "", policyName: policyNames[0], policyNames, @@ -613,6 +775,36 @@ export async function evaluatePolicies( decision: "instruct", }; } + const stderrMsg = instructEntries + .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) + .join("\n"); + return { + exitCode: 0, + stdout: "", + stderr: stderrMsg + "\n", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", + }; + } + + // Goose: a non-block PreToolUse decision injects nothing (verified live — no + // additional-context channel), and Goose has no Stop event, so instruct + // degrades to allow + stderr note, like Hermes / Factory non-Stop events. + if (session?.cli === "goose") { + const stderrMsg = instructEntries + .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) + .join("\n"); + return { + exitCode: 0, + stdout: "", + stderr: stderrMsg + "\n", + policyName: policyNames[0], + policyNames, + reason: combined, + decision: "instruct", + }; } if (eventType === "Stop" || eventType === "SubagentStop") { @@ -629,7 +821,7 @@ export async function evaluatePolicies( // `[WARNING] Hook warning: ...` but does NOT trigger retry. The // documented retry shape is `{decision: "block", reason}` JSON on // stdout (exit 0). Mirrors the cli==="copilot" branch in the deny - // path at line ~279 so custom instruct policies enforce on Copilot. + // path so custom instruct policies enforce on Copilot. if (session?.cli === "copilot") { return { exitCode: 0, @@ -715,39 +907,20 @@ export async function evaluatePolicies( }; } - // Gemini: mirror the instruct context-injection shape for events that - // support it; stderr-only for everything else. - if (session?.cli === "gemini") { - const supportsContext = - eventType === "UserPromptSubmit" || - eventType === "PreToolUse" || - eventType === "PostToolUse" || - eventType === "SessionStart"; + // OpenClaw: same flat shape as Pi — {permission:"allow", reason}. The shim + // returns undefined (no block) for an allow verdict regardless, so the note + // surfaces via stderr; keeping the flat stdout shape keeps the shim's parse + // path uniform across every verdict. + if (session?.cli === "openclaw") { const stderrMsg = allowEntries .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) .join("\n"); - if (supportsContext) { - // Same fallback chain as the instruct path above — see comment there. - const hookEventName = session?.hookEventName ?? session?.rawHookEventName ?? eventType; - const response = { - hookSpecificOutput: { - hookEventName, - additionalContext: `Note from failproofai: ${combined}`, - }, - }; - return { - exitCode: 0, - stdout: JSON.stringify(response), - stderr: stderrMsg + "\n", - policyName: policyNames[0], - policyNames, - reason: combined, - decision: "allow", - }; - } return { exitCode: 0, - stdout: "", + stdout: JSON.stringify({ + permission: "allow", + reason: `Note from failproofai: ${combined}`, + }), stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, @@ -761,13 +934,20 @@ export async function evaluatePolicies( eventType === "PostToolUse" || eventType === "UserPromptSubmit" || eventType === "PermissionRequest"; - const response = supportsHookSpecificOutput - ? { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } } - : { reason: combined }; const stderrMsg = allowEntries .map((e) => `[failproofai] ${e.policyName}: ${e.reason}`) .join("\n"); - return { exitCode: 0, stdout: JSON.stringify(response), stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" }; + // Only events with a real additional-context channel carry the allow-note + // to the agent. Everything else (Stop, SubagentStop, Session*, PreCompact, …) + // has NO channel, so we keep informational allow-notes OUT of stdout — a + // bare `{reason}` there is rendered as noise (e.g. droid printing a Stop's + // "…skipping commit check…skipping PR check…" wall on a perfectly fine turn). + // The note is still logged to stderr + the activity store for diagnostics. + if (supportsHookSpecificOutput) { + const response = { hookSpecificOutput: { hookEventName: eventType, additionalContext: `Note from failproofai: ${combined}` } }; + return { exitCode: 0, stdout: JSON.stringify(response), stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" }; + } + return { exitCode: 0, stdout: "", stderr: stderrMsg + "\n", policyName: policyNames[0], policyNames, reason: combined, decision: "allow" }; } return { exitCode: 0, stdout: "", stderr: "", policyName: null, reason: null, decision: "allow" }; } diff --git a/src/hooks/resolve-cwd.ts b/src/hooks/resolve-cwd.ts index 0246182c..a59ec5e9 100644 --- a/src/hooks/resolve-cwd.ts +++ b/src/hooks/resolve-cwd.ts @@ -13,7 +13,7 @@ * the dashboard renders an em-dash, and `readMergedHooksConfig(cwd)` / * `loadAllCustomHooks({ sessionCwd })` skip project-scope discovery. * - * • Claude / Codex / Copilot / Gemini / Pi / OpenCode: stdin's top-level + * • Claude / Codex / Copilot / Pi / OpenCode: stdin's top-level * `cwd` is reliable for every event; passthrough. * * Mirrors the dispatch pattern of `resolve-permission-mode.ts` and diff --git a/src/hooks/resolve-permission-mode.ts b/src/hooks/resolve-permission-mode.ts index d90e3734..120e9203 100644 --- a/src/hooks/resolve-permission-mode.ts +++ b/src/hooks/resolve-permission-mode.ts @@ -32,10 +32,6 @@ * `tool_call` handlers always run with the same authority. Falls back to * "default" via the same final branch as Copilot/Cursor. * - * • Gemini CLI: hook payload doesn't carry a permission-mode field today. - * Falls back to "default" via the same final branch as Copilot/Cursor/ - * OpenCode/Pi. Revisit when Gemini's hook protocol exposes a per-session - * authority signal (the docs as of 2026-04-13 do not). */ import { readFileSync } from "node:fs"; import { findCodexTranscript } from "../../lib/codex-sessions"; @@ -54,7 +50,7 @@ export function resolvePermissionMode( return resolveCodexMode(sessionId) ?? "default"; } - // copilot, cursor, opencode, pi, gemini, unknown integrations, or codex without a sessionId + // copilot, cursor, opencode, pi, unknown integrations, or codex without a sessionId return "default"; } diff --git a/src/hooks/resolve-transcript-path.ts b/src/hooks/resolve-transcript-path.ts index 8cae75b5..6a19e326 100644 --- a/src/hooks/resolve-transcript-path.ts +++ b/src/hooks/resolve-transcript-path.ts @@ -22,10 +22,6 @@ * • Pi: shim doesn't forward transcript_path. Discover at * ~/.pi/agent/sessions//_.jsonl. * - * • Gemini: docs say stdin carries transcript_path, but coverage is uneven - * across versions. Trust stdin first; fall back to discovery under - * ~/.gemini/tmp//chats/.json. - * * Mirrors the dispatch pattern of `resolve-permission-mode.ts`. Each * `find*Transcript` helper performs its own existsSync + path-traversal * containment check, so passing in a malformed sessionId is safe (returns @@ -35,7 +31,8 @@ import { findCodexTranscript } from "../../lib/codex-sessions"; import { findCopilotTranscript } from "../../lib/copilot-sessions"; import { findCursorTranscript } from "../../lib/cursor-sessions"; import { findPiTranscript } from "../../lib/pi-sessions"; -import { findGeminiTranscript } from "../../lib/gemini-sessions"; +import { findFactoryTranscript } from "../../lib/factory-sessions"; +import { findAntigravityTranscript } from "../../lib/antigravity-sessions"; import type { IntegrationType } from "./types"; export function resolveTranscriptPath( @@ -59,14 +56,35 @@ export function resolveTranscriptPath( return findCursorTranscript(sessionId) ?? undefined; case "pi": return findPiTranscript(sessionId) ?? undefined; - case "gemini": - return findGeminiTranscript(sessionId) ?? undefined; + case "factory": + // Factory writes real JSONL at + // ~/.factory/sessions//.jsonl (Claude-style). + return findFactoryTranscript(sessionId) ?? undefined; + case "antigravity": + // Antigravity writes real JSONL at ~/.gemini/antigravity-cli/brain/ + // /.system_generated/logs/transcript_full.jsonl. + return findAntigravityTranscript(sessionId) ?? undefined; + case "devin": + // Devin keeps sessions in SQLite (~/.local/share/devin/cli/sessions.db); + // there is no on-disk transcript file, so hand back a virtual path (like + // opencode) — audit/download read the DB directly. + return `devin-db://${sessionId}`; + case "goose": + // Goose keeps sessions in SQLite (~/.local/share/goose/sessions/sessions.db); + // its live-hook payload carries no transcript file, so hand back a virtual + // path (like devin) — audit/download read the DB directly. + return `goose-db://${sessionId}`; case "opencode": return `opencode-db://${sessionId}`; case "hermes": // Hermes live-hook payloads carry no transcript file; the audit path // reads sessions straight from ~/.hermes/state.db (see hermes-sessions.ts). return undefined; + case "openclaw": + // OpenClaw's plugin shim forwards transcript_path in stdin (handled by the + // early return above); its audit path reads the real JSONL sessions + // directly via lib/openclaw-sessions.ts, so no discovery is needed here. + return undefined; default: return undefined; } diff --git a/src/hooks/tool-name-canonicalize.ts b/src/hooks/tool-name-canonicalize.ts index 6681b721..94985332 100644 --- a/src/hooks/tool-name-canonicalize.ts +++ b/src/hooks/tool-name-canonicalize.ts @@ -14,9 +14,16 @@ import { OPENCODE_TOOL_INPUT_MAP, PI_TOOL_MAP, PI_TOOL_INPUT_MAP, - GEMINI_TOOL_MAP, HERMES_TOOL_MAP, HERMES_TOOL_INPUT_MAP, + OPENCLAW_TOOL_MAP, + OPENCLAW_TOOL_INPUT_MAP, + FACTORY_TOOL_MAP, + DEVIN_TOOL_MAP, + ANTIGRAVITY_TOOL_MAP, + ANTIGRAVITY_TOOL_INPUT_MAP, + GOOSE_TOOL_MAP, + GOOSE_TOOL_INPUT_MAP, } from "./types"; /** @@ -32,10 +39,22 @@ export function canonicalizeToolName( if (cli === "copilot") return COPILOT_TOOL_MAP[raw] ?? raw; if (cli === "cursor") return CURSOR_TOOL_MAP[raw] ?? raw; if (cli === "codex") return CODEX_TOOL_MAP[raw] ?? raw; - if (cli === "gemini") return GEMINI_TOOL_MAP[raw] ?? raw; if (cli === "opencode") return OPENCODE_TOOL_MAP[raw] ?? raw; if (cli === "pi") return PI_TOOL_MAP[raw] ?? raw; if (cli === "hermes") return HERMES_TOOL_MAP[raw] ?? raw; + if (cli === "openclaw") return OPENCLAW_TOOL_MAP[raw] ?? raw; + // Factory droid: Execute→Bash, Create→Write, FetchUrl→WebFetch, … (verified + // live against droid v0.171.0). tool_input keys are already canonical. + if (cli === "factory") return FACTORY_TOOL_MAP[raw] ?? raw; + // Devin CLI: exec→Bash (verified live against devin v3000.1.27). + // tool_input.command is already canonical. + if (cli === "devin") return DEVIN_TOOL_MAP[raw] ?? raw; + // Antigravity CLI: run_command→Bash (verified agy v1.1.2), view_file→Read, … + // (best-effort). tool_input keys are PascalCase → ANTIGRAVITY_TOOL_INPUT_MAP. + if (cli === "antigravity") return ANTIGRAVITY_TOOL_MAP[raw] ?? raw; + // Goose: shell→Bash, write/edit/view→file ops, todo__todo_write→TodoWrite, … + // (verified live against goose v1.43.0). Handles bare + `__` names. + if (cli === "goose") return GOOSE_TOOL_MAP[raw] ?? raw; return raw; } @@ -62,6 +81,15 @@ export function canonicalizeToolInput( // Hermes read_file/write_file/patch deliver the file path as `path`; map it to // `file_path` so path/content builtins fire (verified against a live state.db). else if (cli === "hermes") perToolMap = HERMES_TOOL_INPUT_MAP[toolName]; + // OpenClaw file tools (read/write/edit) deliver the path as `path`; exec + // already delivers `command`. Map path → file_path so path builtins fire. + else if (cli === "openclaw") perToolMap = OPENCLAW_TOOL_INPUT_MAP[toolName]; + // Antigravity's run_command args are PascalCase (`CommandLine`, `Cwd`); map + // to `command`/`cwd` so Bash builtins fire (verified agy v1.1.2). + else if (cli === "antigravity") perToolMap = ANTIGRAVITY_TOOL_INPUT_MAP[toolName]; + // Goose file tools (write/edit/view) deliver the path as `path`, read_image as + // `source`; map to `file_path` so path builtins fire (verified goose v1.43.0). + else if (cli === "goose") perToolMap = GOOSE_TOOL_INPUT_MAP[toolName]; if (!perToolMap) return rawInput; const out: Record = {}; for (const [k, v] of Object.entries(rawInput as Record)) { diff --git a/src/hooks/types.ts b/src/hooks/types.ts index 6bfb3b77..31636f26 100644 --- a/src/hooks/types.ts +++ b/src/hooks/types.ts @@ -1,11 +1,11 @@ /** - * Constants and interfaces for agent CLI hooks integrations (Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, …). + * Constants and interfaces for agent CLI hooks integrations (Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, …). */ export const HOOK_SCOPES = ["user", "project", "local"] as const; export type HookScope = (typeof HOOK_SCOPES)[number]; -export const INTEGRATION_TYPES = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"] as const; +export const INTEGRATION_TYPES = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"] as const; export type IntegrationType = (typeof INTEGRATION_TYPES)[number]; export const CODEX_HOOK_SCOPES = ["user", "project"] as const; @@ -510,115 +510,435 @@ export const PI_TOOL_INPUT_MAP: Record> = { Edit: { path: "file_path" }, }; -// ── Gemini CLI ───────────────────────────────────────────────────────────── -// -// Gemini CLI's hook contract is the closest thing to a Claude Code clone we've -// seen: same `{matcher, hooks: [{type, command, timeout}]}` settings shape, -// PascalCase event names, snake_case stdin payload field names (session_id, -// tool_name, tool_input, hook_event_name, cwd, transcript_path), subprocess -// execution model, and a `$CLAUDE_PROJECT_DIR` env-var alias on top of its own -// `$GEMINI_PROJECT_DIR` for back-compat. The integration is modeled on -// claudeCode in integrations.ts; only three translation layers differ: -// -// 1. Event names — Gemini uses BeforeTool/AfterTool/BeforeAgent/AfterAgent/ -// PreCompress/Notification/SessionStart/SessionEnd/BeforeModel/AfterModel/ -// BeforeToolSelection. We install all 11 events but only 8 have a Claude -// canonical equivalent; the other 3 (BeforeModel/AfterModel/ -// BeforeToolSelection) pass through unchanged (no policy matches today, -// but the binary still records activity). -// -// 2. Tool names — Gemini's tools are snake_case (run_shell_command, read_file, -// write_file, replace, glob, grep_search, list_directory, web_fetch, -// google_web_search, write_todos, save_memory, read_many_files, ask_user). -// The handler canonicalizes via GEMINI_TOOL_MAP (run_shell_command → Bash, -// read_file → Read, etc.) so existing builtin policies fire unchanged. -// Unknown tools (extensions, MCP `mcp_*` names) pass through. -// -// 3. Response shape — Gemini emits flat `{decision: "deny", reason}` for -// blocks (NOT Claude's `{hookSpecificOutput: {permissionDecision: "deny", -// permissionDecisionReason}}`), and `{hookSpecificOutput: {hookEventName, -// additionalContext}}` for context injection on BeforeAgent / AfterTool / -// SessionStart only. policy-evaluator.ts handles this via a `cli === -// "gemini"` branch. +// ── OpenClaw (openclaw gateway) ───────────────────────────────────────────── // -// Settings paths: -// user → ~/.gemini/settings.json -// project → /.gemini/settings.json -// Gemini also documents a system scope (/etc/gemini-cli/settings.json) but we -// don't expose it (matches Codex/Copilot/Cursor/OpenCode/Pi: user|project only). -// -// **Per-event capability** (from Gemini docs as of 2026-04-13): -// • BeforeTool → PreToolUse · CAN block via `{decision: "deny"}` -// · CAN rewrite via `hookSpecificOutput.tool_input` -// • AfterTool → PostToolUse · CAN observe; `additionalContext` injection -// • BeforeAgent → UserPromptSubmit · CAN block; `additionalContext` injection -// • AfterAgent → Stop · CAN force-retry via `{decision: "block"}` -// (closest to Claude's exit-2-from-Stop) -// • SessionStart → SessionStart · `additionalContext` injection -// • SessionEnd → SessionEnd · observation only -// • PreCompress → PreCompact · observation only -// • Notification → Notification · observation only -// • BeforeModel → BeforeModel · Gemini-only; no canonical, observation -// • AfterModel → AfterModel · Gemini-only; no canonical, observation -// • BeforeToolSelection → BeforeToolSelection · Gemini-only; no canonical, observation -// -// Ref: https://geminicli.com/docs/hooks/ - -export const GEMINI_HOOK_SCOPES = ["user", "project"] as const; -export type GeminiHookScope = (typeof GEMINI_HOOK_SCOPES)[number]; - -export const GEMINI_HOOK_EVENT_TYPES = [ +// OpenClaw is a self-hosted assistant gateway (23+ chat channels). Like Hermes +// it is a dual-pillar integration (live hooks + audit) and USER-scope only +// (`~/.openclaw/openclaw.json`; workspace plugins are disabled by default). +// +// Enforcement is via OpenClaw's IN-PROCESS PLUGIN hooks (its file-based +// "internal hooks" are observation-only and cannot block) — so failproofai +// ships a plugin (`openclaw-plugin/`) that async-spawns the binary and maps a +// flat `{permission, reason}` verdict back to each hook's native return shape. +// The shim forwards a Claude-shaped stdin (params→tool_input, toolName→ +// tool_name, transcriptPath→transcript_path, stopHookActive→stop_hook_active), +// so the handler + builtins work unchanged; canonicalization stays binary-side +// via the maps below (no inline maps in the shim, unlike OpenCode/Pi). +// +// Per-hook capability (verified live against openclaw v2026.7.1): +// before_tool_call → PreToolUse ✅ deny ({block:true, blockReason}) +// after_tool_call → PostToolUse observation +// before_agent_run → UserPromptSubmit ✅ deny ({outcome:"block", reason}) +// before_agent_finalize → Stop ✅ revise ({action:"revise", reason}); +// carries transcriptPath + stopHookActive (≈ Claude Stop) +// session_start/end → SessionStart/End observation +// subagent_ended → SubagentStop observation only (cannot veto) +// before_compaction → PreCompact observation +// Omitted: agent_end (would double-fire Stop); message_sending (outbound-msg +// cancel gate — OpenClaw-only capability, deferred). +export const OPENCLAW_HOOK_SCOPES = ["user"] as const; +export type OpenClawHookScope = (typeof OPENCLAW_HOOK_SCOPES)[number]; + +export const OPENCLAW_HOOK_EVENT_TYPES = [ + "before_tool_call", + "after_tool_call", + "before_agent_run", + "before_agent_finalize", + "session_start", + "session_end", + "subagent_ended", + "before_compaction", +] as const; +export type OpenClawHookEventType = (typeof OPENCLAW_HOOK_EVENT_TYPES)[number]; + +export const OPENCLAW_EVENT_MAP: Record = { + before_tool_call: "PreToolUse", + after_tool_call: "PostToolUse", + before_agent_run: "UserPromptSubmit", + before_agent_finalize: "Stop", + session_start: "SessionStart", + session_end: "SessionEnd", + subagent_ended: "SubagentStop", + before_compaction: "PreCompact", +}; + +// OpenClaw native tool ids (verified against source src/agents/tool-catalog.ts +// and a live before_tool_call payload: tool `exec`, params `{command}`). Names +// with a Claude canonical are mapped so builtin policies fire; OpenClaw-specific +// tools (process, apply_patch, memory_*, sessions_*, browser, canvas, …) pass +// through unchanged so they still appear in the audit, just unmatched. +export const OPENCLAW_TOOL_MAP: Record = { + exec: "Bash", + read: "Read", + write: "Write", + edit: "Edit", + grep: "Grep", + glob: "Glob", + web_search: "WebSearch", + web_fetch: "WebFetch", +}; + +// OpenClaw tool-INPUT key canonicalization, keyed by the *canonical* tool name +// (the handler canonicalizes the name before calling canonicalizeToolInput). +// `exec` already delivers `command` (matches Bash builtins), so no entry; the +// file tools deliver the path as `path`, which Claude builtins read as +// `file_path`. Mirrors HERMES_TOOL_INPUT_MAP / PI_TOOL_INPUT_MAP. +export const OPENCLAW_TOOL_INPUT_MAP: Record> = { + Read: { path: "file_path" }, + Write: { path: "file_path" }, + Edit: { path: "file_path" }, +}; + +// ── Factory Droid (droid) ─────────────────────────────────────────────────── +// +// Factory's droid CLI ships a Claude-compatible external-command hook system, +// but with two schema quirks verified LIVE against droid v0.171.0: +// +// 1. **Event names live at the TOP LEVEL of hooks.json — there is NO `"hooks"` +// wrapper.** The published docs are wrong; droid rejects a `{"hooks":{…}}` +// wrapper with `WARN Ignoring unknown hook event keys keys:["hooks"]`. The +// correct shape is: +// { "PreToolUse": [ { "matcher": "*", "hooks": [ { … } ] } ], +// "Stop": [ { "hooks": [ { … } ] } ] } +// Tool events (PreToolUse / PostToolUse) MUST carry `"matcher": "*"` +// (matches all tools); non-tool events omit the matcher. +// +// 2. **Deny is driven by EXIT CODE 2 + stderr, NOT a JSON decision.** droid +// ignores a `{decision:…}` object on tool events and blocks purely on +// exit code 2 (verified live: `Hook returned exit code 2, throwing +// ToolExecutionControlError`). The one exception is the `Stop` event, +// where droid does NOT support exit-2 force-retry — there we emit +// `{decision:"block", reason}` JSON on stdout at exit 0 (docs: "if +// decision is block, Droid does not stop"). Both branches live in +// policy-evaluator.ts's `cli === "factory"` handling. +// +// Event names are already PascalCase (matching Claude's canonical set), so +// there is NO FACTORY_EVENT_MAP and NO handler.ts canonicalization branch — the +// binary sees the events verbatim. The stdin payload is Claude snake_case +// (`session_id`, `transcript_path`, `cwd`, `permission_mode`, `hook_event_name`, +// `tool_name`, `tool_input:{command,…}`), so no payload normalization is needed +// either. +// +// Settings paths (verified against droid v0.171.0): +// user → ~/.factory/hooks.json +// project → /.factory/hooks.json +// +// Audit pillar: sessions at ~/.factory/sessions//.jsonl +// (Claude-style encoded-cwd folders), one JSONL per session alongside a +// `.settings.json` sibling we ignore. See lib/factory-sessions.ts. + +export const FACTORY_HOOK_SCOPES = ["user", "project"] as const; +export type FactoryHookScope = (typeof FACTORY_HOOK_SCOPES)[number]; + +export const FACTORY_HOOK_EVENT_TYPES = [ "SessionStart", - "SessionEnd", - "BeforeAgent", - "AfterAgent", - "BeforeModel", - "AfterModel", - "BeforeToolSelection", - "BeforeTool", - "AfterTool", - "PreCompress", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", "Notification", + "Stop", + "SubagentStop", + "PreCompact", + "SessionEnd", ] as const; -export type GeminiHookEventType = (typeof GEMINI_HOOK_EVENT_TYPES)[number]; - -/** Gemini event → canonical PascalCase HookEventType. Three Gemini-only events - * (BeforeModel, AfterModel, BeforeToolSelection) have no Claude equivalent and - * pass through unchanged. */ -export const GEMINI_EVENT_MAP: Record = { - SessionStart: "SessionStart", - SessionEnd: "SessionEnd", - BeforeAgent: "UserPromptSubmit", - AfterAgent: "Stop", - BeforeTool: "PreToolUse", - AfterTool: "PostToolUse", - PreCompress: "PreCompact", - Notification: "Notification", - // No canonical Claude equivalent — passthrough so the binary still records - // activity but `getPoliciesForEvent` returns [] (no-op fast path). - BeforeModel: "BeforeModel" as HookEventType, - AfterModel: "AfterModel" as HookEventType, - BeforeToolSelection: "BeforeToolSelection" as HookEventType, +export type FactoryHookEventType = (typeof FACTORY_HOOK_EVENT_TYPES)[number]; + +/** + * Factory droid's tool names → Claude PascalCase canonical names so existing + * builtin policies (which match `toolName === "Bash"`, etc.) fire unchanged. + * Verified against droid v0.171.0: shell runs as `Execute`, file writes as + * `Create`, URL fetches as `FetchUrl`. `tool_input.command` is already the + * canonical Bash key, so there is NO FACTORY_TOOL_INPUT_MAP. Unknown tools + * (MCP, extensions) pass through unchanged via the `?? raw` fallback. + */ +export const FACTORY_TOOL_MAP: Record = { + Execute: "Bash", + Read: "Read", + Edit: "Edit", + Create: "Write", + Grep: "Grep", + Glob: "Glob", + LS: "LS", + FetchUrl: "WebFetch", + WebSearch: "WebSearch", + TodoWrite: "TodoWrite", + Task: "Task", }; -/** Gemini's snake_case tool names → Claude PascalCase canonical names so existing - * builtin policies (which match `toolName === "Bash"`, etc.) fire unchanged on - * Gemini sessions. Unknown tools (MCP `mcp_*`, extensions, Skills) pass through - * unchanged. Per https://geminicli.com/docs/reference/tools/ as of 2026-04-13. */ -export const GEMINI_TOOL_MAP: Record = { - run_shell_command: "Bash", +// ── Devin CLI (devin) ─────────────────────────────────────────────────────── +// +// Devin's CLI (Cognition) is a **pure Claude-clone** external-command hook +// system — verified LIVE against devin v3000.1.27. Unlike Factory, it uses the +// standard Claude `"hooks"`-wrapper schema (its config.json also holds +// `org_id`, `theme_mode`, etc., so writes are merge-preserving via +// readJsonFile/writeJsonFile). No quirks: +// +// • Config lives under a `"hooks"` key exactly like Claude's settings.json: +// user → ~/.config/devin/config.json (the `"hooks"` key) +// project → /.devin/config.json (the `"hooks"` key) +// • Event names are already PascalCase (matching Claude's canonical set), so +// there is NO DEVIN_EVENT_MAP and NO handler.ts canonicalization branch. +// • The stdin payload is pure Claude snake_case (no normalization needed): +// PreToolUse → {hook_event_name, tool_name:"exec", tool_input:{command}, tool_use_id} +// PostToolUse → adds tool_response:{success, output, error} +// Stop → {stop_hook_active} +// • Deny contract = `{"decision":"block","reason"}` JSON on stdout at exit 0 +// (VERIFIED live — it blocked and overrode `--permission-mode dangerous`). +// Both non-Stop and Stop use the same `{decision:"block"}` shape (Stop's +// reason carries the MANDATORY-ACTION force-retry wording). Devin is +// Claude-compatible, so instruct on context-injection events emits +// `{hookSpecificOutput:{hookEventName, additionalContext}}`. See +// policy-evaluator.ts's `cli === "devin"` branch. +// +// Audit pillar: sessions live in SQLite at +// ~/.local/share/devin/cli/sessions.db (tables `sessions` — one row per +// session WITH a `working_directory` — and `message_nodes`, whose +// `chat_message` column is OpenAI-style JSON `{role, content, tool_calls?, +// tool_call_id?}`). See lib/devin-sessions.ts. `DEVIN_HOME` overrides the home +// dir for tests. + +export const DEVIN_HOOK_SCOPES = ["user", "project"] as const; +export type DevinHookScope = (typeof DEVIN_HOOK_SCOPES)[number]; + +export const DEVIN_HOOK_EVENT_TYPES = [ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "PermissionRequest", + "Stop", + "SessionEnd", +] as const; +export type DevinHookEventType = (typeof DEVIN_HOOK_EVENT_TYPES)[number]; + +/** + * Devin's tool names → Claude PascalCase canonical names so existing builtin + * policies (which match `toolName === "Bash"`, etc.) fire unchanged. Verified + * live against devin v3000.1.27: the shell tool runs as `exec` and its + * `tool_input.command` is already the canonical Bash key, so there is NO + * DEVIN_TOOL_INPUT_MAP. All other Devin tool names pass through unchanged via + * the `?? raw` fallback. + */ +export const DEVIN_TOOL_MAP: Record = { + exec: "Bash", +}; + +// ── Antigravity CLI (antigravity) ──────────────────────────────────────────── +// +// Antigravity's `agy` CLI has its OWN hook contract — it is NOT a Claude-clone. +// Verified LIVE against agy v1.1.2 (shipped docs at +// ~/.gemini/antigravity-cli/builtin/skills/agy-customizations/docs/hooks.md): +// +// 1. **hooks.json is a NAMED-hook schema.** Each top-level key is a hook +// *name* ("failproofai"), whose value is an event→handlers map. Tool events +// (PreToolUse / PostToolUse) use a `{matcher, hooks:[…]}` wrapper; +// non-tool events (PreInvocation / Stop) are FLAT arrays of handler +// objects: +// { "failproofai": { +// "PreToolUse": [ { "matcher":"*", "hooks":[ {type,command,timeout} ] } ], +// "PreInvocation": [ { type, command, timeout } ], +// "Stop": [ { type, command, timeout } ] } } +// Multiple named hooks merge; `"enabled": false` disables a named hook. +// +// 2. **camelCase (protojson) stdin payload.** Antigravity pipes camelCase +// fields (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, +// `transcriptPath`, `stepIdx`, `modelName`) — handler.ts normalizes these +// to canonical snake_case (`tool_name`, `tool_input`, `session_id`, `cwd`, +// `transcript_path`) right after JSON.parse. Tool `args` are PascalCase +// (`CommandLine`, `Cwd`) — canonicalized via ANTIGRAVITY_TOOL_INPUT_MAP. +// +// 3. **Antigravity's OWN response shapes** (policy-evaluator.ts +// `cli === "antigravity"` branch): +// • Deny (tool events) → exit 0, `{decision:"deny", reason}` on stdout. +// • Deny on Stop → exit 0, `{decision:"continue", reason}` — +// "continue" re-enters the loop (how require-*-before-stop enforces). +// • Instruct on UserPromptSubmit (canonical for PreInvocation) → exit 0, +// `{injectSteps:[{ephemeralMessage:"Instruction from failproofai: …"}]}`. +// • Instruct on Stop → `{decision:"continue", reason}`. +// • Other instruct events → stderr note only (degrade like Hermes). +// +// 4. **ANTIGRAVITY_EVENT_MAP** maps the `--hook` arg to a canonical event: +// PreToolUse→PreToolUse, PostToolUse→PostToolUse, +// PreInvocation→UserPromptSubmit, Stop→Stop. +// +// Settings paths (verified against agy v1.1.2): +// user → ~/.gemini/config/hooks.json +// project → /.agents/hooks.json +// +// Audit pillar: plain JSONL transcripts at +// ~/.gemini/antigravity-cli/brain//.system_generated/logs/ +// transcript_full.jsonl (one step per line); the conversation index lives in +// SQLite at ~/.gemini/antigravity-cli/conversation_summaries.db. See +// lib/antigravity-sessions.ts + lib/antigravity-projects.ts. `ANTIGRAVITY_HOME` +// overrides the home dir for tests. + +export const ANTIGRAVITY_HOOK_SCOPES = ["user", "project"] as const; +export type AntigravityHookScope = (typeof ANTIGRAVITY_HOOK_SCOPES)[number]; + +/** The events failproofai installs into Antigravity's hooks.json. Tool events + * use the `{matcher, hooks}` wrapper; PreInvocation / Stop are flat arrays. */ +export const ANTIGRAVITY_HOOK_EVENT_TYPES = [ + "PreToolUse", + "PostToolUse", + "PreInvocation", + "Stop", +] as const; +export type AntigravityHookEventType = (typeof ANTIGRAVITY_HOOK_EVENT_TYPES)[number]; + +/** Antigravity `--hook` arg → canonical HookEventType. PreInvocation is + * Antigravity's before-model event → maps to UserPromptSubmit (where instruct + * injects `injectSteps`). Verified against agy v1.1.2. */ +export const ANTIGRAVITY_EVENT_MAP: Record = { + PreToolUse: "PreToolUse", + PostToolUse: "PostToolUse", + PreInvocation: "UserPromptSubmit", + Stop: "Stop", +}; + +/** + * Antigravity's tool names → Claude PascalCase canonical names so existing + * builtin policies (which match `toolName === "Bash"`, etc.) fire unchanged. + * Tool names VERIFIED against the agy binary's tool registry + live transcripts: + * the file tool is `write_to_file` (NOT `write_file`), listing is `list_dir` + * (NOT `list_directory`), and glob is `find_by_name` (NOT `find_filepath`) — the + * earlier best-effort names were wrong, so `block-env-files`/`block-secrets-write` + * silently no-op'd on Antigravity file writes. Unknown tools pass through via the + * `?? raw` fallback. + */ +export const ANTIGRAVITY_TOOL_MAP: Record = { + run_command: "Bash", + write_to_file: "Write", read_file: "Read", - read_many_files: "Read", - write_file: "Write", - replace: "Edit", - glob: "Glob", + view_file: "Read", + edit_file: "Edit", + replace_file_content: "Edit", + list_dir: "LS", + find_by_name: "Glob", grep_search: "Grep", - list_directory: "LS", - web_fetch: "WebFetch", - google_web_search: "WebSearch", - write_todos: "TodoWrite", - save_memory: "Memory", - ask_user: "AskUser", + read_url_content: "WebFetch", + search_web: "WebSearch", +}; + +/** + * Antigravity tool args are PascalCase. Keyed by the CANONICAL tool name + * (canonicalizeToolInput runs after canonicalizeToolName). VERIFIED live: + * `run_command` delivers `CommandLine`/`Cwd`; `write_to_file` delivers the path + * as `TargetFile` and body as `CodeContent`. Without the Write/Edit/Read entries + * the path/content builtins (`block-env-files`, `block-secrets-write`, + * `block-read-outside-cwd`) never saw a `file_path` and silently no-op'd on + * Antigravity file operations. Read/Edit path keys are best-effort within the + * same tool family (all file tools operate on `TargetFile`); extra keys are + * harmless (only remapped when present). + */ +export const ANTIGRAVITY_TOOL_INPUT_MAP: Record> = { + Bash: { CommandLine: "command", Cwd: "cwd" }, + Write: { TargetFile: "file_path", CodeContent: "content" }, + Edit: { TargetFile: "file_path" }, + Read: { TargetFile: "file_path", AbsolutePath: "file_path", File: "file_path" }, +}; + +// ── Goose (codename goose, Block) ──────────────────────────────────────────── +// +// Goose is Block's open-source Rust MCP agent — a LOCAL dev-agent CLI (like +// Claude/Factory/Devin, NOT a gateway). Dual-pillar: external shell-hook +// enforcement + SQLite audit. The entire contract below was verified LIVE +// against goose v1.43.0. +// +// Enforcement is via Goose's "hooks" system (the cross-agent Open Plugins spec): +// a plugin directory whose `hooks/hooks.json` `command` runs +// `failproofai --hook --cli goose`. Goose AUTO-DISCOVERS the dir at +// startup (no config edit needed) and self-registers it into config.yaml. +// +// 1. **Deny contract = `PreToolUse` ONLY** (shipped in goose ≥ v1.37.0, +// PR block/goose#9304). A hook blocks a tool via `{"decision":"block", +// "reason"}` on stdout at exit 0 (exit 2 + stderr also works); ANY other +// error/timeout → fail-open (allow). Verified live: the reason reaches the +// model and "do not retry" is appended. Goose has NO `Stop` event, so the 5 +// `require-*-before-stop` builtins never fire (inapplicable, like Hermes). +// `UserPromptSubmit` deny is NOT honored (observation only). `PreToolUse` +// fires for the shell tool AND inside delegated subagents, so it is the +// single sufficient deny point. +// +// 2. **Event names are already PascalCase** (matching Claude's canonical set), +// so there is NO `GOOSE_EVENT_MAP` and NO handler.ts event-canonicalization +// branch. The stdin payload, however, uses `event` (not `hook_event_name`) +// and `working_dir` (not `cwd`) — handler.ts normalizes `working_dir`→`cwd` +// for goose so `block-read-outside-cwd` keeps its cwd. `tool_name` / +// `tool_input` are already the canonical field names. +// +// 3. Tool names arrive BOTH bare (`shell`, `write`, `edit`, `view`, +// `read_image`, `tree`, `delegate`) AND `__` namespaced +// (`todo__todo_write`); GOOSE_TOOL_MAP covers both forms, unknown tools +// pass through via the `?? raw` fallback. Path-bearing tools deliver the +// path as `path` (or `source` for read_image), so GOOSE_TOOL_INPUT_MAP maps +// it to `file_path`. Shell's `command` is already canonical. +// +// 4. **Instruct has no channel** — a non-block PreToolUse decision injects +// nothing (verified live), so instruct() degrades to allow + stderr note +// (like Factory/Hermes on non-Stop events). policy-evaluator.ts's +// `cli === "goose"` branch: PreToolUse deny → `{"decision":"block",reason}` +// JSON at exit 0; no Stop branch. +// +// Settings paths (verified against goose v1.43.0): +// user → ~/.agents/plugins/failproofai/hooks/hooks.json +// project → /.agents/plugins/failproofai/hooks/hooks.json +// +// Audit pillar: sessions in SQLite at +// ~/.local/share/goose/sessions/sessions.db (schema v15). `sessions` rows carry +// a real `working_dir`, so `audit --project ` filters like Devin (NOT +// grouped-by-source like Hermes); `messages` rows hold Claude-style typed-block +// `content_json`. See lib/goose-sessions.ts. `GOOSE_HOME` overrides the data +// dir for tests. + +export const GOOSE_HOOK_SCOPES = ["user", "project"] as const; +export type GooseHookScope = (typeof GOOSE_HOOK_SCOPES)[number]; + +export const GOOSE_HOOK_EVENT_TYPES = [ + "SessionStart", + "UserPromptSubmit", + "PreToolUse", + "PostToolUse", + "SessionEnd", +] as const; +export type GooseHookEventType = (typeof GOOSE_HOOK_EVENT_TYPES)[number]; + +/** + * Goose's tool names → Claude PascalCase canonical names so existing builtin + * policies (which match `toolName === "Bash"`, etc.) fire unchanged. Verified + * live against goose v1.43.0: the developer extension exposes `shell` (Bash), + * `write`/`edit`/`view` (file ops), `read_image`, `glob`/`grep`, plus + * `tree`/`delegate`; other extensions namespace their tools (`todo__todo_write`). + * Unknown tools (MCP, other extensions) pass through unchanged via the `?? raw` + * fallback in handler.ts:canonicalizeToolName. + */ +export const GOOSE_TOOL_MAP: Record = { + shell: "Bash", + write: "Write", + edit: "Edit", + view: "Read", + read_image: "Read", + glob: "Glob", + grep: "Grep", + tree: "LS", + delegate: "Task", + todo__todo_write: "TodoWrite", +}; + +/** + * Per-tool input-key translation, keyed by the *canonical* tool name (the + * handler canonicalizes the name before calling canonicalizeToolInput). + * Verified live: goose's file tools deliver the path as `path` (`read_image` + * uses `source`), but Claude builtins read `file_path` (block-env-files, + * block-secrets-write, block-read-outside-cwd) — so map it. `shell` already + * delivers `command` (canonical), so Bash needs no entry. `edit` delivers + * `before`/`after` (not `old_string`/`new_string`); only the top-level `path` + * is mapped (no builtin inspects the edit body), mirroring PI_TOOL_INPUT_MAP. + */ +export const GOOSE_TOOL_INPUT_MAP: Record> = { + Read: { path: "file_path", source: "file_path" }, + Write: { path: "file_path" }, + Edit: { path: "file_path" }, + LS: { path: "file_path" }, }; export const HOOK_EVENT_TYPES = [ @@ -685,15 +1005,15 @@ export interface SessionMetadata { cwd?: string; permissionMode?: string; /** Read from the stdin payload's `hook_event_name` field. Carries the raw - * agent-emitted event name (e.g. Gemini's `BeforeTool`, Cursor's - * `preToolUse`, Pi's `tool_call`). May be undefined when stdin omits it. */ + * agent-emitted event name (e.g. Cursor's `preToolUse`, Pi's `tool_call`). + * May be undefined when stdin omits it. */ hookEventName?: string; /** The raw event name passed on the CLI's `--hook` flag, BEFORE any - * per-CLI canonicalization to PascalCase (e.g. `BeforeTool` for Gemini, - * `preToolUse` for Cursor). Use this for round-tripping the agent-side - * event name in response shapes when stdin doesn't include `hook_event_name`. */ + * per-CLI canonicalization to PascalCase (e.g. `preToolUse` for Cursor). + * Use this for round-tripping the agent-side event name in response shapes + * when stdin doesn't include `hook_event_name`. */ rawHookEventName?: string; - /** Which agent CLI fired this hook (claude | codex | copilot | cursor | opencode | pi | gemini). Set by handler.ts from --cli. */ + /** Which agent CLI fired this hook (claude | codex | copilot | cursor | opencode | pi | hermes | openclaw | factory | devin | antigravity | goose). Set by handler.ts from --cli. */ cli?: IntegrationType; } From 132660aa7384c05f6e57f496d60e4f6e66417e4f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 12:08:07 +0530 Subject: [PATCH 4/8] docs: update translations for changed English sources (#513) Co-authored-by: github-actions[bot] --- docs/ko/agenteye/audits.mdx | 111 ++++++------ docs/ko/agenteye/cli-recipes.mdx | 86 ++++----- docs/ko/agenteye/deployment.mdx | 231 ++++++++++++------------ docs/ko/agenteye/getting-started.mdx | 94 +++++----- docs/ko/agenteye/managed-deployment.mdx | 131 +++++++------- 5 files changed, 326 insertions(+), 327 deletions(-) diff --git a/docs/ko/agenteye/audits.mdx b/docs/ko/agenteye/audits.mdx index 19f0dc9e..141083d3 100644 --- a/docs/ko/agenteye/audits.mdx +++ b/docs/ko/agenteye/audits.mdx @@ -1,107 +1,106 @@ --- -title: "감사 — 에이전틱 개선 탐지" -description: "AgentEye 감사 — 에이전틱 개선 탐지 문서." +title: "감사(Audits) — 에이전트 개선 사항 탐지" +description: "AgentEye Audits — 에이전트 개선 사항 탐지 문서입니다." --- -감사(Audit)는 **세션 전반**에 걸쳐 에이전트 로그를 분석해 개선할 사항을 찾아내는 반복 실행 작업입니다. 알림(alert)이 이미 알고 있는 특정 지표를 거의 실시간으로 감시한다면, 감사는 *조사*를 수행합니다. 설정한 일정에 따라 해당 기간에 대한 결정적(deterministic) 정책 검사를 실행한 뒤, **AI 신뢰성 에이전트**를 세션에 풀어 데이터를 직접 쿼리하고, 의심스러운 대화록을 읽으며, 필요한 경우 간단한 분석 스크립트를 실행합니다. 그 결과로 각 근거가 뒷받침된 **개선 권고사항**을 작성합니다. +감사(Audit)는 **여러 세션에 걸쳐** 에이전트 로그를 분석하여 개선이 필요한 사항을 찾아내는 반복 실행 작업입니다. 알림(alert)이 이미 알고 있는 특정 지표를 거의 실시간으로 감시하는 것과 달리, 감사는 *조사*를 수행합니다. 설정한 일정에 따라 해당 기간 동안 결정론적 정책 검사를 실행한 뒤, **AI 안정성 에이전트**를 세션 전반에 걸쳐 자유롭게 투입합니다. 에이전트는 데이터를 직접 쿼리하고 의심스러운 트랜스크립트를 읽으며, 필요한 경우 소규모 분석 스크립트를 실행한 후 각 항목의 근거와 함께 **개선 권고사항**을 작성합니다. -감사는 "내 에이전트에서 무엇을 수정하거나 개선해야 하는가?"라는 질문에 답하고, 알림은 특정 임계값이 넘는 순간 즉시 알려줍니다. 모든 개선 사항은 배경이 된 정확한 세션과 쿼리로 연결되며, 클릭 한 번으로 재발을 감지하는 알림을 미리 채워진 상태로 생성할 수 있습니다. +감사는 "내 에이전트에서 무엇을 수정하거나 개선해야 하는가?"라는 질문에 답하는 데 활용하고, 알림은 특정 임계값이 초과되는 순간 즉시 통보받기 위해 사용하세요. 모든 개선 사항은 근거가 된 정확한 세션 및 쿼리와 연결되며, 클릭 한 번으로 재발을 감지하는 알림을 미리 채워진 상태로 생성할 수 있습니다. -대시보드 화면은 **`//audits`** (사이드바 → *분석* → *감사*)이며, `audits:read` / `audits:write` 권한이 필요합니다. +대시보드 화면은 **`//audits`** (사이드바 → *분석* → *감사*)이며, `audits:read` / `audits:write` 권한으로 접근을 제한합니다. --- ## 실행 방식 -각 실행은 결정적(deterministic) 기반 레이어와 에이전틱 조사 레이어, 두 단계로 구성됩니다. +각 실행은 결정론적 기반 계층과 에이전트 조사 계층, 두 가지 단계로 구성됩니다. -### 1. 정책 검사 (결정적) +### 1. 정책 검사 (결정론적) -어떤 모델도 실행되기 전에, 감사는 해당 기간에 대해 소규모 **SQL 정책 검사** 카탈로그를 실행합니다. 이 카탈로그는 경계가 있는 집계 쿼리로 알려진 문제 패턴을 플래그하고, 일치하는 텍스트 자체가 아닌 *몇 건의* 이벤트 / *어느* 세션이 해당되는지를 보고합니다. 카탈로그 항목은 다음과 같습니다: +어떤 모델도 실행되기 전에, 감사는 해당 기간에 대해 소규모 **SQL 정책 검사** 카탈로그를 실행합니다. 이는 알려진 문제 패턴을 감지하고 일치하는 이벤트 *수* / 세션이 *무엇인지*를 보고하는 범위가 제한된 집계 쿼리이며, 일치한 텍스트 자체는 보고하지 않습니다. 카탈로그에는 다음이 포함됩니다: -- 이벤트 페이로드의 **비밀 / 자격증명 유출** — AWS 액세스 키, `sk-…` API 키, PEM 개인 키, JWT / 베어러 토큰, `KEY=…` 자격증명 할당 -- **프롬프트 주입 마커** — "이전 지침을 무시하라", "시스템 프롬프트를 공개하라" 등 -- **개인식별정보(PII)** — 주민등록번호 형식 숫자(휴리스틱) -- **도구 권한 거부** 및 **도구 호출 루프 폭주** +- 이벤트 페이로드의 **비밀/자격증명 유출** — AWS 액세스 키, `sk-…` API 키, PEM 개인 키, JWT / 베어러 토큰, `KEY=…` 형식의 자격증명 할당. +- **프롬프트 인젝션 마커** — "이전 지시를 무시하라", "시스템 프롬프트를 공개하라" 등 유사한 표현. +- **개인식별정보(PII)** — SSN 형식의 숫자 (휴리스틱 기반). +- **도구 권한 거부** 및 **무한 도구 호출 루프**. -정책 위반은 (종류: `policy`) 발견 사항으로 저장되며, **항상 표시**됩니다(실행별 상한선에 의해 제거되지 않음). 또한 AI 에이전트에 초기 단서로 전달됩니다. 이 레이어는 모델이 필요 없으므로, AI 에이전트를 사용할 수 없는 경우에도 감사는 가장 중요한 보안 신호를 생성합니다. +정책 적중 사항은 (`policy` 종류의) 발견 사항으로 영속 저장되며 **항상 표시됩니다** (실행당 상한선에 의해 잘리지 않습니다). 또한 AI 에이전트에게 초기 단서로 전달됩니다. 이 계층은 모델이 필요하지 않기 때문에, AI 에이전트를 사용할 수 없는 경우에도 감사는 가장 중요한 보안 신호를 계속 생성합니다. -### 2. 에이전틱 조사 (AI) +### 2. 에이전트 조사 (AI) -감사는 이어서 **자율 신뢰성 에이전트**(대시보드 어시스턴트를 구동하는 것과 동일한 Claude Agent SDK 서비스이며, 감사 전용 프롬프트 적용)를 실행합니다. 에이전트는 감사의 **범위**(선택된 에이전트 × 환경)와 **시간 창**을 바탕으로: +이후 감사는 **자율 안정성 에이전트**(대시보드 어시스턴트를 구동하는 것과 동일한 Claude Agents SDK 서비스에 감사 전용 프롬프트 적용)를 실행합니다. 에이전트는 감사의 **범위** (선택된 에이전트 × 환경) 및 **기간**을 기반으로 다음을 수행합니다: -- 분석 테이블에 대해 읽기 전용 SQL 쿼리를 실행하고, -- 대표적인 세션 대화록 일부를 읽으며, -- SQL로 표현할 수 없는 분석(오류 클러스터링, 분포 계산, 이미 가져온 페이로드 스윕 등)을 위해 **네트워크와 파일시스템 접근이 차단된 인-팟 샌드박스** (비밀 정보 제거)에서 짧은 **Python 스크립트**를 작성·실행하고, -- 근거가 충분히 확인된 **개선 사항**을 기록합니다. +- 분석 테이블에 대해 읽기 전용 SQL 쿼리 실행, +- 대표적인 세션 트랜스크립트 일부 읽기, +- SQL로 표현할 수 없는 분석(오류 클러스터링, 분포 계산, 이미 가져온 페이로드 스위핑)을 위해 필요시 **격리된 인팟(in-pod) 샌드박스**에서 짧은 **Python 스크립트를 작성하고 실행** (네트워크 없음, 파일시스템 접근 없음, 비밀 정보 제거), +- 충분한 근거가 있는 각 **개선 사항** 기록. -에이전트는 감사의 **민감도**(낮음 / 보통 / 높음)에 따라 오류 클러스터링, 기준선 대비 드리프트, 대화록의 목표 실패, 도구 오용, 품질/비용 균형, 커버리지 공백 등 여러 조사 방향을 탐색합니다. 모든 개선 사항에는 **반드시 근거가 있어야 합니다**: 에이전트가 실제로 검사한 세션 ID 및/또는 실행한 SQL. 서버는 인용된 세션의 존재를 검증하고 **근거가 없는 개선 사항은 폐기**하므로, 에이전트는 조사하지만 결코 꾸며내지 않습니다. +에이전트는 감사의 **민감도** (낮음 / 중간 / 높음)에 따라 오류 클러스터링, 기준선 대비 드리프트, 트랜스크립트의 목표 달성 실패, 도구 오용, 품질/비용 절충, 커버리지 공백 등 여러 조사 항목을 검토합니다. 모든 개선 사항은 **근거를 인용해야** 합니다. 즉, 에이전트가 실제로 검사한 세션 ID 및/또는 실행한 SQL이 있어야 합니다. 서버는 인용된 세션이 존재하는지 검증하고, **유효한 근거가 없는 개선 사항은 폐기**합니다. 에이전트는 조사하지만 결코 날조하지 않습니다. 각 개선 사항에는 다음이 포함됩니다: -- **권고사항** (구체적인 변경 내용 — 프롬프트 수정, 도구 스키마 수정, 재시도 정책, 가드레일, 평가 커버리지 확대), -- **예상 영향** 및 **노력** 추정치 (낮음 / 보통 / 높음), -- **중요도** — `big` (운영자에게 즉시 알림 필요), `medium` (실행 보고서에 포함), `small` (대시보드 컨텍스트 수준), -- 안정적인 **핑거프린트** (이번 실행의 세션이 아닌 이슈의 카테고리 + 범위 기반) — 근거가 바뀌어도 실행에 걸쳐 동일 이슈를 추적 가능, -- 재발을 감지할 수 있는 간단한 결정적 감시자를 만들 수 있을 때, 클릭 한 번으로 생성 가능한 **알림 제안**. +- **권고사항** (구체적인 변경 내용 — 프롬프트 수정, 도구 스키마 수정, 재시도 정책, 가드레일, 추가 평가 커버리지), +- **예상 효과** 및 **작업량** 추정치 (낮음 / 중간 / 높음), +- **중요도** — `big` (운영자에게 즉시 알림 필요), `medium` (실행 보고서에 포함), `small` (대시보드 컨텍스트), +- 안정적인 **지문** (이번 실행의 세션이 아닌 이슈의 카테고리 + 범위 기반) — 근거가 바뀌더라도 동일한 이슈를 실행 간에 추적할 수 있도록, +- 재발을 감지할 수 있는 단순한 결정론적 감시가 가능한 경우, 클릭 한 번으로 생성할 수 있는 **제안 알림**. -> **AI 레이어는 선택 사항이지만 권장됩니다.** 감사 파이프라인에 AI 에이전트가 구성되어 있지 않아도 실행은 계속되며, 정책 발견 사항은 저장됩니다. 에이전틱 레이어에 대해서는 조용히 통과시키는 대신 "분석 불가"로 정직하게 보고합니다. +> **AI 계층은 선택 사항이지만 권장됩니다.** 감사 파이프라인에 AI 에이전트가 구성되어 있지 않더라도 실행은 계속되며, 정책 발견 사항은 영속 저장됩니다. 에이전트 계층에 대해서는 조용히 통과시키는 대신 "분석 불가"로 정직하게 보고합니다. ### 실패 모드 -개선 사항은 조직의 영속적인 **실패 모드 카탈로그**로 분류되거나 새로운 모드를 제안합니다. 모드는 실행 전반과 장기적인 재발 추적에 걸쳐 패턴에 안정적인 정체성을 부여합니다. +개선 사항은 조직의 영속적인 **실패 모드 카탈로그**로 분류되거나 새로운 모드를 제안합니다. 모드는 실행 간 및 장기적인 재발 추적에서 패턴에 안정적인 식별자를 부여합니다. -## 심사(Triage) 라이프사이클 +## 분류 생명주기 -발견 사항 페이지 (`/audits//findings/`)에서: +발견 사항 페이지(`/audits//findings/`)에서: -| 액션 | 효과 | +| 작업 | 효과 | |---|---| -| **인지(acknowledge)** | 발견 사항을 계속 표시하되 우선순위를 절반으로 낮춥니다. | -| **해결(resolve)** | 수정 완료로 표시합니다. 이후 패턴이 실제로 다시 나타나면 **신규**로 재오픈됩니다 — 회귀가 조용히 기록에 묻히지 않고 눈에 띄게 표시됩니다. | -| **음소거(mute)** / **기각(dismiss)** | 영구 억제: 패턴의 핑거프린트가 기억되어 실행 전반에 걸쳐 다시 표시되지 않습니다. mute는 "알고 있으며 수용함", dismiss는 "유용하지 않음"에 사용합니다. | -| **재오픈(reopen)** | 억제 / 해결을 취소하고 패턴의 우선순위를 다시 부여합니다. | -| **할당(assign)** | 소유권을 위해 발견 사항을 운영자(조직 멤버)에게 라우팅합니다. 우선순위와 억제 상태는 변경되지 않습니다. | +| **acknowledge(확인)** | 발견 사항을 표시 상태로 유지하되 우선순위를 절반으로 낮춥니다. | +| **resolve(해결)** | 수정된 것으로 표시합니다. 이후 해당 패턴이 실제로 재발하면 **신규**로 재개됩니다 — 회귀가 조용히 기록에 묻히지 않고 명확히 드러납니다. | +| **mute(음소거)** / **dismiss(무시)** | 영속적 억제: 패턴의 지문이 기억되어 실행이 바뀌어도 다시 표시되지 않습니다. mute는 "알려진, 수용된 문제"에, dismiss는 "유용하지 않은 항목"에 사용하세요. | +| **reopen(재열기)** | 억제/해결을 해제하고 패턴의 순위를 다시 적용합니다. | -저신호 노이즈는 에이전틱 개선에 대한 실행별 발견 사항 상한선(`top_k`)으로 감사별 제어됩니다. 정책 발견 사항은 보안 관련 항목으로 항상 표시되며 상한선을 우회합니다. 상한선에 의해 잘린 항목은 실행 통계에 포함되며, 조용히 삭제되지 않습니다. +저신호 노이즈는 에이전트 개선 사항에 대한 실행당 발견 상한선(`top_k`)으로 감사별로 제어됩니다. 정책 발견 사항은 보안과 관련이 있어 항상 표시되므로 상한선을 적용받지 않습니다. 상한선으로 제외된 항목은 실행 통계에 집계되며, 아무것도 조용히 삭제되지 않습니다. ## 스케줄링 -- **주기** (`schedule_interval_secs`): 매시간부터 매주까지; **기본값은 매일**. 감사는 의도적으로 알림보다 주기가 깁니다 — 에이전틱 조사는 전체 창을 스캔하며 수 분이 소요됩니다. -- **창(Window)**: 고정된 롤링 룩백(예: "각 실행은 지난 7일을 스캔") 또는 **마지막 실행 이후**(기본값) — 각 실행은 이전 성공적인 실행이 끝난 지점부터 시작하며, 경계 이벤트를 놓치지 않기 위해 작은 겹침(overlap)이 있습니다. -- 다음 실행은 이전 실행이 **완료된** 후 전체 주기만큼 지나 예약되므로, 느린 실행이 동일 감사의 두 번째 동시 실행을 쌓지 않습니다. -- 감사 페이지의 **지금 실행**을 누르면 즉시 실행 예약됩니다. +- **주기** (`schedule_interval_secs`): 시간별부터 주별; **기본값은 일별**입니다. 감사는 의도적으로 알림보다 주기가 깁니다 — 에이전트 조사는 전체 기간을 스캔하며 수 분이 소요됩니다. +- **기간**: 고정 롤링 룩백(예: "각 실행은 지난 7일을 스캔") 또는 **마지막 실행 이후**(기본값) — 각 실행은 이전의 성공적인 실행이 끝난 지점부터 소폭 겹치는 구간을 포함하여 시작하므로 경계 이벤트를 놓치지 않습니다. +- 다음 실행은 이전 실행이 **완료된** 후 전체 주기만큼 지난 시점에 예약되므로, 느린 실행이 동일한 감사의 두 번째 동시 실행을 생성하지 않습니다. +- 감사 페이지의 **지금 실행**을 클릭하면 즉시 실행 대기 상태가 됩니다. ## 모델 선택 -감사를 생성할 때 **운영자가 에이전트 서비스에 구성한 모델 목록**에서 조사에 사용할 모델을 선택할 수 있습니다. 단일 모델이 구성된 경우 선택기는 해당 모델을 캡션으로 표시하며, 여러 모델이 있으면 선택할 수 있습니다. 설정하지 않으면 구성된 기본값이 사용됩니다. +감사를 생성할 때 조사에 사용할 모델을 **운영자가 에이전트 서비스에 구성한 모델 목록**에서 선택할 수 있습니다. 모델이 하나만 구성된 경우 선택기는 해당 모델을 캡션으로 표시하고, 여러 개인 경우 직접 선택합니다. 설정하지 않으면 구성된 기본값을 사용합니다. ## 알림 -실행에서 **신규** 발견 사항이 나타나면, 감사는 조직의 구성된 채널에 알림을 보냅니다 — 알림 파이프라인이 사용하는 것과 동일한 `alerts.enabled_channels` 게이트 및 설정: +실행에서 **신규** 발견 사항이 나타나면 감사는 조직에 구성된 채널로 알림을 전송합니다. 알림 파이프라인과 동일한 `alerts.enabled_channels` 게이트 및 설정을 사용합니다: -- **Slack** — 중요한(`big`) 신규 항목 요약과 딥 링크 -- **이메일** — 감사에 **이메일** 채널이 연결되어 있고 신규 발견 사항이 하나 이상 있을 때, 새로운 개선 사항(최고 심각도, 항목별 권고사항, 딥 링크)을 나열한 **감사 보고서**를 전송 +- **Slack** — 중요한(`big`) 신규 항목 요약과 딥 링크. +- **이메일** — 신규 개선 사항(최고 심각도, 항목별 권고사항, 딥 링크)을 정리한 **감사 보고서**. 감사에 **이메일** 채널이 연결되어 있고 신규 발견 사항이 하나 이상 있을 때 전송됩니다. -반복되지만 알려진 발견 사항은 재알림을 보내지 않습니다. +이미 알려진 반복 발견 사항은 재알림을 보내지 않습니다. ## 구성 참조 -감사 정의는 대시보드(`/audits/new`) 또는 API를 통해 관리합니다. 감사별 설정에는 스케줄 주기와 창, 범위(`{"environments": [...], "agent_ids": [...]}`), 민감도(`low` / `medium` / `high`), 알림 채널, 실행별 발견 사항 상한선(`top_k`), 모델(`llm_budget.model`을 통해)이 포함됩니다. 운영자 수준 서버 설정(타임아웃, 샌드박스, 에이전트 서비스 URL)은 [deployment.md](/ko/agenteye/deployment)에 문서화되어 있습니다. +감사 정의는 대시보드(`/audits/new`) 또는 API를 통해 관리합니다. 감사별 설정에는 스케줄 주기 및 기간, 범위(`{"environments": [...], "agent_ids": [...]}`), 민감도(`low` / `medium` / `high`), 알림 채널, 실행당 발견 상한선(`top_k`), 모델(`llm_budget.model` 경유)이 포함됩니다. 운영자 수준 서버 설정(타임아웃, 샌드박스, 에이전트 서비스 URL)은 [deployment.md](/ko/agenteye/deployment)에 문서화되어 있습니다. ## API -모든 엔드포인트는 조직 범위이며 표준 베어러 키 인증을 따릅니다([api-keys.md](/ko/agenteye/api-keys) 참조). +모든 엔드포인트는 조직 범위로 제한되며 표준 베어러 키 인증을 따릅니다([api-keys.md](/ko/agenteye/api-keys) 참조). | 엔드포인트 | 권한 | 목적 | |---|---|---| -| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | 감사 정의 목록 조회 / 생성 | -| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | 감사 조회, 수정, 삭제 | -| `POST /audits/:id/run` | `audits:write` | 감사를 즉시 실행 예약 | -| `GET /audits/:id/runs` | `audits:read` | 실행 기록 (창, 상태, 통계, 발견 사항 수) | -| `GET /audits/findings` | `audits:read` | 조직 전체 발견 사항, `audit_id`, `status`로 필터링 가능; 우선순위 순 정렬 | -| `GET /audits/findings/:fid` | `audits:read` | 발견 사항 전체 상세 정보 (권고사항, 근거, 우선순위) | -| `POST /audits/findings/:fid/status` | `audits:write` | 심사: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}` | - -"감사를 실행했지만 아무것도 찾지 못함", "코드 샌드박스가 비활성화됨", "감사 이메일이 전달되지 않음"에 대해서는 [troubleshooting.md](/ko/agenteye/troubleshooting#audits)를 참조하세요. \ No newline at end of file +| `GET /audits` · `POST /audits` | `audits:read` / `audits:write` | 감사 정의 목록 조회 / 생성. | +| `GET` / `PUT` / `DELETE /audits/:id` | read / write / write | 감사 조회, 수정, 삭제. | +| `POST /audits/:id/run` | `audits:write` | 감사를 즉시 실행 대기 상태로 만듭니다. | +| `GET /audits/:id/runs` | `audits:read` | 실행 기록 (기간, 상태, 통계, 발견 사항 수). | +| `GET /audits/findings` | `audits:read` | 조직 전체 발견 사항 — `audit_id`, `status`로 필터링 가능, 우선순위 순 정렬. | +| `GET /audits/findings/:fid` | `audits:read` | 발견 사항 전체 상세 정보 (권고사항, 근거, 우선순위). | +| `POST /audits/findings/:fid/status` | `audits:write` | 분류: `{"action": "ack" \| "mute" \| "dismiss" \| "resolve" \| "reopen" \| "assign"}`. | + +"감사가 실행되었으나 아무것도 발견하지 못한 경우", "코드 샌드박스가 비활성화된 경우", "감사 이메일이 전달되지 않은 경우"에 대해서는 [troubleshooting.md](/ko/agenteye/troubleshooting#audits)를 참조하세요. \ No newline at end of file diff --git a/docs/ko/agenteye/cli-recipes.mdx b/docs/ko/agenteye/cli-recipes.mdx index a066eb9b..f79e2bbf 100644 --- a/docs/ko/agenteye/cli-recipes.mdx +++ b/docs/ko/agenteye/cli-recipes.mdx @@ -1,30 +1,30 @@ --- -title: "에이전트용 CLI 레시피" +title: "에이전트를 위한 CLI 레시피" description: "에이전트를 위한 AgentEye CLI 레시피 문서." --- -스크립트나 코딩 에이전트에서 직접 세션, 이벤트, 평가 데이터를 가져오고(재평가 트리거 포함), `jq`로 바로 파이프할 수 있는 깔끔한 JSON을 stdout에 출력합니다. 이 레시피들은 AgentEye의 관측 가능성 데이터를 터미널 사용자나 AI 코딩 에이전트(Claude Code, Cursor)가 대시보드를 클릭하지 않고도 조회하고 자동화할 수 있는 형태로 변환합니다. +스크립트나 코딩 에이전트에서 세션, 이벤트, 평가 데이터를 직접 가져오고(재평가도 트리거할 수 있으며), `jq`로 바로 파이프할 수 있는 깔끔한 JSON을 stdout에 출력합니다. 이 레시피들은 AgentEye의 관찰 가능성 데이터를 터미널 사용자나 AI 코딩 에이전트(Claude Code, Cursor)가 대시보드를 클릭하지 않고도 쿼리하고 자동화할 수 있는 형태로 만들어 줍니다. 아래 패턴들은 AgentEye CLI(`agenteye`)에서 바로 복사해서 사용할 수 있습니다. 설치, 인증, 전체 옵션 목록은 [CLI](/ko/agenteye/cli)를 참고하세요. 내장 도움말은 `agenteye -h` 또는 `agenteye -h`로 확인할 수 있습니다. ## 기본 원칙 -1. **전역 옵션은 커맨드 *앞에* 붙입니다.** `agenteye --json sessions`가 올바른 형태이며, `agenteye sessions --json`은 올바르지 않습니다. 전역 옵션은 `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`입니다. -2. **출력을 파싱할 때는 반드시 `--json`을 전달합니다.** 데이터는 JSON 형태로 **stdout**에 출력되고, 상태 메시지와 오류는 **stderr**로 출력되어 stdout을 `jq`로 파이프하기 깔끔하게 유지됩니다. -3. **stderr 텍스트가 아닌 종료 코드를 기준으로 분기합니다.** `0` 성공 · `2` 잘못된 인수 · `3` 대시보드 연결 불가 · `4` 미로그인 또는 세션 만료 · `5` 권한 없음. -4. **`-h`로 탐색합니다.** 모든 커맨드에서 필터, 값 형식, JSON 형태를 문서로 확인할 수 있습니다. +1. **전역 옵션은 명령어 *앞*에 붙입니다.** `agenteye --json sessions`가 올바른 형태이며, `agenteye sessions --json`은 올바르지 않습니다. 전역 옵션은 `--json`, `--base-url`, `--org`, `--token`, `--insecure`/`--secure`, `--timeout`, `--quiet`, `--no-color`입니다. +2. **출력을 파싱할 때는 반드시 `--json`을 전달하세요.** 데이터는 JSON 형태로 **stdout**에 출력되고, 사람이 읽는 상태 메시지와 오류는 **stderr**로 출력되므로 stdout은 `jq`로 파이프하기에 깔끔한 상태를 유지합니다. +3. **stderr 텍스트가 아닌 종료 코드로 분기하세요.** `0` 성공 · `2` 잘못된 인수 · `3` 대시보드에 연결할 수 없음 · `4` 로그인되지 않았거나 만료됨 · `5` 권한 없음. +4. **`-h`로 탐색하세요.** 모든 명령어는 필터, 값 형식, JSON 구조를 문서화하고 있습니다. -## 초기 설정 +## 최초 설정 ```bash -export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # --base-url을 반복하지 않아도 됨 +export AGENTEYE_DASHBOARD_URL=https://agenteye.example.com # --base-url을 반복하지 않아도 됩니다 agenteye login --email you@example.com # 이메일로 받은 코드를 붙여넣기; 약 24시간 유효 ``` ## 작업 전 인증 확인 -`whoami`는 세션이 없거나 만료된 경우에도 오류를 발생시키지 않고 `logged_in:false`를 반환하므로, 에이전트가 인증 상태를 안전하게 확인할 수 있습니다. (단, 베이스 URL이 설정되지 않았거나 대시보드에 연결할 수 없는 경우에는 여전히 비정상 종료될 수 있습니다.) +`whoami`는 세션이 없거나 만료된 경우에도 오류를 발생시키지 않고 `logged_in:false`를 반환하므로, 에이전트가 안전하게 인증 상태를 확인할 수 있습니다. (베이스 URL이 설정되지 않았거나 대시보드에 연결할 수 없는 경우에는 여전히 non-zero로 종료될 수 있습니다.) ```bash if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then @@ -32,44 +32,44 @@ if [ "$(agenteye --json whoami | jq -r .logged_in)" != "true" ]; then fi ``` -## 실패하거나 낮은 점수의 세션 찾기 +## 실패하거나 점수가 낮은 세션 찾기 ```bash -# 평가가 오류 상태인 최근 24시간 세션 +# 지난 24시간 내 평가가 오류인 세션 agenteye --json sessions --since 24h --status error | jq -r '.sessions[].session_id' -# 특정 에이전트에서 helpfulness 점수가 0.5 이하인 평가 +# 특정 에이전트에서 도움성 점수가 0.5 이하인 평가 agenteye --json evals --agent-id checkout-bot --score helpfulness:..0.5 \ | jq '.evaluations[] | {session_id, scores}' ``` -점수 필터링은 `sessions`가 아닌 **`evals`**에서 적용됩니다. `--score KEY:MIN..MAX`는 반복 사용 가능하며 AND 조건으로 결합됩니다. 양쪽 경계값은 선택 사항입니다(`..0.5`는 ≤ 0.5, `0.9..`는 ≥ 0.9를 의미합니다). 요청당 최대 20개의 점수 필터를 전달할 수 있으며, 초과하면 HTTP 400이 반환됩니다. `sessions`는 `evals`와 `--env`, `--status`, `--agent-id`, `--session-id`, 시간 범위 필터를 공유하지만 `--score`는 없습니다. +점수 필터링은 `sessions`가 아닌 **`evals`**에서 처리됩니다. `--score KEY:MIN..MAX`는 반복 사용 가능하며 AND 조건으로 결합됩니다. 각 경계는 선택 사항입니다(`..0.5`는 ≤ 0.5, `0.9..`는 ≥ 0.9를 의미합니다). 요청당 최대 20개의 점수 필터를 전달할 수 있으며, 그 이상이면 HTTP 400을 반환합니다. `sessions`는 `evals`와 `--env`, `--status`, `--agent-id`, `--session-id`, 시간 범위 필터를 공유하지만 `--score`는 없습니다. -## 하나의 세션 전체 읽기 +## 세션 전체 읽기 -단일 `session show` 커맨드는 없으며, 이벤트 이력과 세션 평가를 조합합니다. +단일 `session show` 명령어는 없습니다 — 이벤트 기록과 세션 평가를 조합하세요: ```bash # 세션의 최신 평가 (상태 + 점수) agenteye --json evals --session-id run-001 | jq '.evaluations[0] | {status, scores}' -# 실행의 모든 이벤트 (전체 조회를 위해 --limit 늘리기) +# 실행의 모든 이벤트 (전체 조회를 위해 --limit 값을 높이세요) agenteye --json events --session-id run-001 --all --limit 1000 | jq '.events[] | {ts, event_type}' -# 세션에서 도구 호출만 +# 세션 내 도구 호출만 조회 agenteye --json events --session-id run-001 --event-type tool_use,tool_result --all \ | jq '.events[].payload' ``` -## 전체 데이터 가져오기 (페이지네이션) +## 전체 가져오기 (페이지네이션) -결과는 최신순으로 정렬되며 커서 기반 페이지네이션을 사용합니다. +결과는 최신순으로 반환되며 커서 기반 페이지네이션을 사용합니다. ```bash -# 한 번에: 200행 페이지 단위로 최대 500행 가져오기 +# 한 번에: 200행 단위 페이지로 최대 500행 가져오기 agenteye --json events --session-id run-001 --limit 500 --all > events.json -# 수동 페이지 이동: next_cursor를 다시 전달 +# 수동 페이징: next_cursor를 다시 전달 page=$(agenteye --json events --limit 100) cursor=$(echo "$page" | jq -r '.next_cursor // empty') [ -n "$cursor" ] && agenteye --json events --limit 100 --cursor "$cursor" @@ -77,62 +77,62 @@ cursor=$(echo "$page" | jq -r '.next_cursor // empty') ## --fields로 출력 줄이기 -에이전트가 읽어야 할 내용을 줄이기 위해 키를 제한합니다(테이블과 `--json` 모두 적용). +에이전트가 읽어야 할 양을 줄이기 위해 키를 제한합니다(테이블과 `--json` 모두 적용). ```bash agenteye --json sessions --since 7d --fields session_id,status,scores | jq -c '.sessions[]' agenteye --json events --session-id run-001 --fields ts,event_type --all ``` -알 수 없는 필드 이름은 유효한 목록과 함께 거부됩니다(종료 코드 `2`). 이를 통해 필드 이름을 간편하게 탐색할 수 있습니다. +알 수 없는 필드명은 유효한 목록과 함께 거부됩니다(종료 코드 `2`). 필드명을 확인하는 간편한 방법입니다. ## 유효한 필터 값 탐색 ```bash -agenteye --json list envs | jq -r '.values[]' # --env에 사용할 값 +agenteye --json list envs | jq -r '.values[]' # --env 값 목록 agenteye --json list tools | jq -r '.values[]' # 도구 이름; agents, models, event_types 등도 가능 agenteye --json list score_filters | jq -r '.values[]' # --score KEY:MIN..MAX의 유효한 KEY ``` ## 조직 선택 (멀티 테넌트) -둘 이상의 조직에 속해 있는 경우, 로그인 시 활성 테넌트를 선택합니다(저장됨): +여러 조직에 속한 경우, 로그인 시 활성 테넌트를 선택할 수 있습니다(저장됩니다): ```bash agenteye login --org acme --email you@corp.com # 로그인과 동시에 테넌트 설정 agenteye --json orgs list | jq -r '.orgs[].org_slug' -agenteye --org globex --json sessions --since 24h # 단일 커맨드에 대해 재정의 +agenteye --org globex --json sessions --since 24h # 단일 명령어에 대해 재정의 ``` -`--org` 없이 여러 조직에 로그인하면 비정상 종료되며 선택 가능한 조직 목록이 출력됩니다. +`--org` 없이 여러 조직에 로그인하면 non-zero로 종료되고 선택 가능한 조직 목록이 출력됩니다. -## SDK/콜렉터용 API 키 발급 +## SDK/수집기용 API 키 생성 ```bash -# 시크릿은 한 번만 출력됨 — --json 사용 시 .key 필드에서 확인 +# 시크릿은 한 번만 출력됩니다 — --json 사용 시 .key 필드에 있습니다 key=$(agenteye --json keys create ci-bot --add events:read.add | jq -r '.key') -agenteye keys regenerate ci-bot --yes # 키 교체; 폐기는 agenteye keys disable ci-bot --yes +agenteye keys regenerate ci-bot --yes # 교체; 폐기하려면 agenteye keys disable ci-bot --yes ``` -## 저장된 쿼리 또는 임시 쿼리 실행 +## 저장된 쿼리 또는 즉석 쿼리 실행 ```bash agenteye --json query run --sql "select count(*) from analytics.events" | jq '.rows' agenteye --json query run errs --arg prod | jq '.rows' # 저장된 쿼리 + 위치 인수 $1 ``` -## 인시던트 비대화형 트리아지 +## 인시던트 비대화형으로 처리 ```bash id=$(agenteye --json incidents list --state firing | jq -r '.incidents[0].id') agenteye incidents ack "$id" -agenteye incidents assign "$id" you@corp.com +agenteye incidents assign "$id" --assignee you@corp.com agenteye incidents resolve "$id" --yes ``` -> 뮤테이션은 `--json` 사용 시 또는 stdin이 TTY가 아닌 경우 확인 프롬프트를 자동으로 건너뜁니다. 따라서 에이전트가 멈추는 일이 없으며, 다른 곳에서 명시적으로 건너뛰려면 `--yes`/`-y`를 전달하세요. +> 변경(mutation) 명령어는 `--json` 사용 시 또는 stdin이 TTY가 아닐 때 확인 프롬프트를 자동으로 건너뛰므로 에이전트가 멈추지 않습니다. 다른 상황에서 명시적으로 건너뛰려면 `--yes`/`-y`를 전달하세요. -## 스크립트에서 종료 코드 처리 +## 스크립트에서의 종료 코드 처리 ```bash out=$(agenteye --json sessions --since 1h) || code=$? @@ -145,9 +145,9 @@ case "${code:-0}" in esac ``` -## JSON 출력 형태 +## JSON 출력 구조 -| 커맨드 | stdout JSON (`--json` 사용 시) | +| 명령어 | stdout JSON (`--json` 사용 시) | |---|---| | `whoami` | `{"logged_in": true, "id", "email", "is_instance_admin", "active_org", "permissions": [...], "memberships": [...]}` 또는 `{"logged_in": false}` | | `orgs list` | `{"active_org", "orgs": [{"org_slug","org_name","permission_set","permissions"}]}` | @@ -160,11 +160,11 @@ esac | `query run` | `{columns: [{name,type}], rows: [[...]], truncated, elapsed_ms}` | | `users list` / `settings list` | `{"users": [...]}` / `{"settings": [...]}` | | `alerts list` / `incidents list` | `{"alerts": [...]}` / `{"incidents": [...]}` | -| create/update/delete (모두) | 리소스 객체, 또는 삭제 시 `{"deleted": true, "id"}` | -| 실패 (모두, `--json` 사용 시) | stdout에 `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | +| create/update/delete (모든 경우) | 리소스 객체, 또는 삭제 시 `{"deleted": true, "id"}` | +| 실패 (모든 경우, `--json` 사용 시) | stdout에 `{"error": "...", "exit_code": , "status"?: , "hint"?: "..."}` | -- **이벤트** 항목(`events`) 각각: `id, session_id, agent_id, event_type, ts, payload, environment`. -- **평가** 항목(`evals`) 각각: `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. -- **세션** 항목(`sessions`) 각각: `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. +- 각 **이벤트** 항목(`events`): `id, session_id, agent_id, event_type, ts, payload, environment`. +- 각 **평가** 항목(`evals`): `id, session_id, agent_id, environment, status, scores, reasoning, summary, error, attempt_count, duration_ms, completed_at, created_at`. +- 각 **세션** 항목(`sessions`): `session_id, agent_id, environment, status, scores, event_count, started_at, last_event_at, first_event_id, last_event_id, latest_evaluation`. -각 커맨드의 `--fields`는 해당 항목의 필드 이름만 허용합니다. `sessions`와 `evals`는 필드 집합이 다르므로, 한쪽에서 유효한 이름이 다른 쪽에서는 거부될 수 있습니다. \ No newline at end of file +각 명령어의 `--fields`는 해당 항목의 필드명만 허용합니다 — `sessions`와 `evals`의 필드 집합이 다르므로, 한쪽에서 유효한 이름이 다른 쪽에서는 거부될 수 있습니다. \ No newline at end of file diff --git a/docs/ko/agenteye/deployment.mdx b/docs/ko/agenteye/deployment.mdx index 58cb9e4d..db6afa7a 100644 --- a/docs/ko/agenteye/deployment.mdx +++ b/docs/ko/agenteye/deployment.mdx @@ -1,6 +1,6 @@ --- title: "배포" -description: "AgentEye 배포 문서" +description: "AgentEye 배포 문서." --- 이 가이드는 프로덕션 환경에서 AgentEye 서버와 대시보드를 배포하는 방법을 다룹니다. @@ -29,12 +29,12 @@ description: "AgentEye 배포 문서" +-----------+ ``` -- **Server**: Rust HTTP 서비스. 이벤트 배치를 수신하여 ClickHouse에 기록하고, PostgreSQL에 관계형 상태를 유지합니다. +- **Server**: Rust HTTP 서비스. 이벤트 배치를 수신하고 ClickHouse에 기록하며 PostgreSQL에서 관계형 상태를 유지합니다. - **Dashboard**: Next.js 웹 앱. 서버 API를 통해서만 읽기/쓰기를 수행합니다. - **agenteye-collector**: 서버 호스트가 아닌 에이전트 머신에 배포됩니다. -- **Postgres 15+**: **필수.** (멀티테넌트 릴리스에서 14에서 15로 상향됨. org-membership 스키마에서 컬럼 목록 `ON DELETE SET NULL` 외래 키를 사용하는데, 이는 Postgres 15+에서만 지원됩니다. 이 버전을 배포하기 전에 Postgres를 업그레이드하세요.) OLTP 상태를 저장합니다: `api_keys`, `users`, `sessions`, `evaluation_jobs` (큐), `dashboards`, `saved_queries`, `otp_codes`, 그리고 멀티테넌트 테이블 `orgs`, `org_memberships`, `org_settings`. -- **ClickHouse 24+**: **필수.** 수집된 모든 이벤트에 대한 분석 저장소입니다. 엔진: `ReplacingMergeTree`, 월별 파티션, `(session_id, ts, dedup_key)` 순서로 정렬됩니다. 서버는 `CLICKHOUSE_URL`을 통해 연결됩니다. 번들로 제공되는 `deploy/base/clickhouse/`는 성능이 최적화된 단일 노드 구성을 포함합니다. **멀티테넌트 요구사항:** 번들 구성은 SQL 접근 관리와 `users_without_row_policies_can_read_rows=false`를 활성화하여, 서버가 조직별로 읽기 전용 ClickHouse 사용자와 행 정책을 생성할 수 있도록 합니다(SQL 편집기와 AI 에이전트에 대한 엔진 수준의 격리 경계). 직접 ClickHouse 구성을 제공하는 경우 이 설정을 유지하세요(`deploy/base/clickhouse/configmap.yaml` 참조). -- **Redis 7+**: *선택 사항*인 공유 캐시 + 속도 제한 백엔드입니다. 서버와 대시보드 모두 `REDIS_URL`을 통해 연결합니다. 없는 경우 두 서비스 모두 Postgres 전용 경로로 자연스럽게 폴백합니다. 아래의 **Redis(선택 사항 캐시)** 섹션을 참조하세요. +- **Postgres 15+**: 필수 항목입니다. (멀티테넌트 릴리스에서 14에서 상향; org 멤버십 스키마가 Postgres 15+ 전용인 컬럼 목록 `ON DELETE SET NULL` 외래 키를 사용합니다. 이 버전 배포 전에 Postgres를 업그레이드하세요.) OLTP 상태를 저장합니다: `api_keys`, `users`, `sessions`, `evaluation_jobs`(큐), `dashboards`, `saved_queries`, `otp_codes`, 그리고 멀티테넌트 테이블 `orgs`, `org_memberships`, `org_settings`. +- **ClickHouse 24+**: 필수 항목입니다. 수집된 모든 이벤트의 분석 저장소입니다. 엔진: `ReplacingMergeTree`, 월별 파티션, `(session_id, ts, dedup_key)` 순으로 정렬됩니다. 서버는 `CLICKHOUSE_URL`을 통해 연결합니다. 번들로 제공되는 `deploy/base/clickhouse/`에는 성능 최적화된 단일 노드 구성이 포함됩니다. **멀티테넌트 요구사항:** 번들 구성은 SQL 액세스 관리와 `users_without_row_policies_can_read_rows=false`를 활성화하여 서버가 조직마다 읽기 전용 ClickHouse 사용자와 행 정책을 생성할 수 있도록 합니다(SQL 에디터 및 AI 에이전트의 엔진 수준 격리 경계). 자체 ClickHouse 구성을 사용하는 경우 이 설정을 가져오세요(`deploy/base/clickhouse/configmap.yaml` 참조). +- **Redis 7+**: *선택적* 공유 캐시 + 속도 제한 백엔드입니다. 서버와 대시보드 모두 `REDIS_URL`을 통해 연결합니다. 없는 경우 두 서비스 모두 Postgres 전용 경로로 정상 저하됩니다. 아래 **Redis (선택적 캐시)** 섹션을 참조하세요. --- @@ -47,77 +47,76 @@ echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin docker pull ghcr.io/agenteye-enterprise/server:beta-latest ``` -> 현재 빌드는 `beta-latest`로 게시됩니다. `latest`는 안정적인 릴리스에만 할당됩니다. 프로덕션 환경에서는 특정 `:v` 태그를 고정하세요. [사용 가능한 이미지 태그](#available-image-tags)를 참조하세요. +> 현재 빌드는 `beta-latest`로 게시됩니다. `latest`는 안정 릴리스에만 할당됩니다. 프로덕션에서는 특정 `:v` 태그를 지정하세요. [사용 가능한 이미지 태그](#available-image-tags)를 참조하세요. ### 환경 변수 | 변수 | 필수 여부 | 기본값 | 설명 | |---|---|---|---| -| `DATABASE_URL` | 예 | 없음 | Postgres DSN. `postgres://` 스키마를 사용하는 표준 libpq 연결 문자열 형식. `?sslmode=require` 및 기타 libpq 파라미터를 지원합니다. 비밀번호에 `/`, `+`, `=` 문자가 포함되면 안 됩니다. URL 안전 비밀번호 생성에는 `openssl rand -hex`를 사용하세요. | -| `ADMIN_KEY` | 아니오 | 없음 | 부트스트랩 관리자 API 키. 매 시작 시 모든 권한으로 업서트됩니다. 값을 변경하고 재시작하여 순환할 수 있습니다. | +| `DATABASE_URL` | 예 | 없음 | Postgres DSN. `postgres://` 스킴을 사용하는 표준 libpq 연결 문자열 형식. `?sslmode=require` 및 기타 libpq 파라미터를 지원합니다. 비밀번호에 `/`, `+`, `=`가 포함되면 안 됩니다. URL 안전 비밀번호 생성에는 `openssl rand -hex`를 사용하세요. | +| `ADMIN_KEY` | 아니오 | 없음 | 부트스트랩 관리자 API 키. 시작 시마다 모든 권한으로 upsert됩니다. 값을 변경하고 재시작하면 교체됩니다. | | `LISTEN_ADDR` | 아니오 | `0.0.0.0:8080` | 바인딩할 TCP 주소 | | `MAX_BODY_BYTES` | 아니오 | `134217728` (128 MB) | 최대 요청 본문 크기 | -| `ADMIN_EMAIL` | 아니오 | 없음 | 부트스트랩 관리자 사용자 이메일. 매 시작 시 모든 권한으로 업서트되며 보호됨으로 표시됩니다. 대시보드/API를 통해 비활성화하거나 권한을 수정할 수 없습니다. 부트스트랩 관리자를 순환하려면 `ADMIN_EMAIL`을 변경하고 재시작하세요. 새 이메일이 보호됨으로 업서트되고, 이전 이메일은 데이터베이스에서 수동으로 초기화할 때까지 보호 상태를 유지합니다. | -| `ALLOWED_EMAILS` | 아니오 | 없음 (모두 차단됨) | 사용자 생성 및 로그인에 허용된 이메일의 쉼표로 구분된 목록. 정확한 주소(`user@example.com`)와 도메인 와일드카드(`*@example.com`)를 지원합니다. 설정하지 않으면 사용자를 생성하거나 로그인할 수 없습니다. **첫 번째 부트 시드 전용**: 첫 번째 부팅 시 기본 조직의 허용 목록을 시드합니다. 이후에는 각 조직의 [`//settings`](#operational-settings) 페이지가 진실의 원천이 되며, 이 환경 변수를 변경해도 효력이 없습니다. | -| `SMTP_HOST` | 아니오 | 없음 | OTP 이메일 발송을 위한 SMTP 서버 호스트명. 설정하지 않으면 OTP 코드가 stdout에 기록됩니다. | +| `ADMIN_EMAIL` | 아니오 | 없음 | 부트스트랩 관리자 사용자 이메일. 시작 시마다 모든 권한으로 upsert되며 보호됨으로 표시됩니다: 대시보드/API를 통해 비활성화하거나 권한을 수정할 수 없습니다. 부트스트랩 관리자를 교체하려면 `ADMIN_EMAIL`을 변경하고 재시작하세요. 새 이메일이 보호됨으로 upsert되며, 이전 이메일은 데이터베이스에서 수동으로 초기화할 때까지 보호 상태를 유지합니다. | +| `ALLOWED_EMAILS` | 아니오 | 없음 (모두 차단) | 사용자 생성 및 로그인이 허용된 이메일의 쉼표 구분 목록. 정확한 주소(`user@example.com`)와 도메인 와일드카드(`*@example.com`)를 지원합니다. 설정하지 않으면 사용자를 생성하거나 로그인할 수 없습니다. **첫 번째 부팅 시드 전용**: 첫 번째 부팅 시 기본 org의 허용 목록을 시드합니다. 이후에는 각 org의 [`//settings`](#operational-settings) 페이지가 신뢰 소스가 되며, 이 환경 변수를 변경해도 효과가 없습니다. | +| `SMTP_HOST` | 아니오 | 없음 | OTP 이메일 발송을 위한 SMTP 서버 호스트명. 설정하지 않으면 OTP 코드가 stdout에 로깅됩니다. | | `SMTP_PORT` | 아니오 | `587` | SMTP 서버 포트 | | `SMTP_USERNAME` | 아니오 | 없음 | SMTP 인증 사용자명 | | `SMTP_PASSWORD` | 아니오 | 없음 | SMTP 인증 비밀번호 | | `SMTP_FROM` | 아니오 | 없음 | OTP 이메일의 발신자 이메일 주소 | -| `SMTP_TLS` | 아니오 | STARTTLS | 명시적으로 비활성화하지 않는 한 STARTTLS가 사용됩니다. `false` 또는 `0`은 일반 텍스트(TLS 없음)로 전송하고, 설정하지 않은 경우를 포함한 다른 모든 값은 STARTTLS를 활성화합니다. | -| `DASHBOARD_URL` | 아니오 | 내장 기본값 | OTP 이메일 매직 링크 및 알림의 인시던트 매직 링크 생성에 사용되는 대시보드 원본 주소. 설정하지 않으면 내장 기본값으로 폴백하고(OTP의 경우에만 대시보드에서 파생된 요청 원본 주소로 먼저 폴백). 이메일과 Slack/인시던트 링크가 모두 대시보드를 가리키도록 도메인이 분리된 설정에서는 이 값을 설정하세요. 아래의 **이메일 매직 링크 URL** 참조. 대부분의 운영자는 설정할 필요가 없습니다. | -| `SESSION_TTL_SECS` | 아니오 | `86400` (24시간) | 대시보드 세션 지속 시간(초). **첫 번째 부트 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 조직별로 수정하세요. | -| `OTP_TTL_SECS` | 아니오 | `600` (10분) | OTP 코드 유효 기간(초). **첫 번째 부트 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 조직별로 수정하세요. | -| `REDIS_URL` | 아니오 | 없음 | 선택 사항인 공유 캐시 + 속도 제한 백엔드. 예: `redis://redis:6379/0`. 설정하면 서버는 인증된 API 키 조회, 대시보드의 `/models` 집계, 세션 목록, env 목록 패싯을 캐시합니다. 또한 OTP 요청 속도 제한을 Postgres COUNT에서 Redis INCR로 전환합니다. 설정하지 않거나 연결할 수 없으면 캐시 없이 실행됩니다(OTP 제한은 Postgres로 폴백, 나머지 캐시 호출은 진실의 원천으로 폴스루). 아래의 **Redis(선택 사항 캐시)** 참조. | -| `CLICKHOUSE_URL` | **예** | 없음 | ClickHouse 인스턴스의 기본 URL. 예: `http://clickhouse:8123`. 서버는 매 시작 시 이 데이터베이스에 이벤트 스키마를 적용하며, ClickHouse에 연결할 수 없으면 부팅을 거부합니다. 아래의 **ClickHouse(필수 분석 저장소)** 참조. | +| `SMTP_TLS` | 아니오 | STARTTLS | 명시적으로 비활성화하지 않으면 STARTTLS가 사용됩니다: `false` 또는 `0`은 평문(TLS 없음)으로 전송하며, 설정하지 않은 경우를 포함한 다른 모든 값은 STARTTLS를 활성화합니다. | +| `DASHBOARD_URL` | 아니오 | 내장 기본값 | OTP 이메일 매직 링크와 알림의 인시던트 매직 링크를 구성하는 데 사용되는 대시보드 오리진. 설정하지 않으면 내장 기본값으로 폴백하며(OTP만의 경우 대시보드에서 파생된 요청 오리진으로 먼저 폴백). 이메일과 Slack/인시던트 링크가 모두 대시보드를 가리키도록 스플릿 도메인 설정에서 사용하세요. 아래 **이메일 매직 링크 URL** 참조. 대부분의 운영자는 설정할 필요가 없습니다. | +| `SESSION_TTL_SECS` | 아니오 | `86400` (24시간) | 대시보드 세션 유지 시간(초). **첫 번째 부팅 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 org별로 편집하세요. | +| `OTP_TTL_SECS` | 아니오 | `600` (10분) | OTP 코드 유효 기간(초). **첫 번째 부팅 시드 전용**: 첫 번째 배포 후 [`//settings`](#operational-settings)에서 org별로 편집하세요. | +| `REDIS_URL` | 아니오 | 없음 | 선택적 공유 캐시 + 속도 제한 백엔드, 예: `redis://redis:6379/0`. 설정 시 서버는 인증된 API 키 조회, 대시보드의 `/models` 집계, 세션 목록, env 목록 패싯을 캐시합니다. OTP 요청 속도 제한도 Postgres COUNT 대신 Redis INCR로 이동합니다. 설정하지 않거나 연결할 수 없는 경우 서버는 캐시 없이 실행됩니다(OTP 제한은 Postgres로 폴백하고 다른 모든 캐시 호출은 신뢰 소스로 폴백). 아래 **Redis (선택적 캐시)** 참조. | +| `CLICKHOUSE_URL` | **예** | 없음 | ClickHouse 인스턴스의 기본 URL, 예: `http://clickhouse:8123`. 서버는 시작 시 이 데이터베이스에 이벤트 스키마를 적용하며, ClickHouse에 연결할 수 없으면 부팅을 거부합니다. 아래 **ClickHouse (필수 분석 저장소)** 참조. | | `CLICKHOUSE_DATABASE` | 아니오 | `agenteye` | ClickHouse 데이터베이스(스키마) 이름. 존재하지 않으면 서버가 시작 시 생성합니다. | -| `ORG_CH_SECRET` | 아니오(단일 테넌트) / **예(멀티 조직)** | 개발 기본값 | 각 조직의 테넌트별 ClickHouse 비밀번호를 파생하는 데 사용되는 HMAC 키. SQL 편집기와 AI 에이전트의 `run_query`는 조직 자체의 읽기 전용 ClickHouse 사용자로 실행되며, 해당 사용자의 행 정책이 엔진에서 테넌트 격리를 강제합니다. 단일 테넌트 배포는 내장된 개발 기본값으로 정상 부팅됩니다. **두 번째 조직을 프로비저닝하기 전에 강력하고 안정적인 값을 반드시 설정하세요.** `agenteye-orgctl org create` CLI는 내장된 개발 기본값에서 실행을 거부합니다. 값을 변경하면 다음 시작 시 부트 타임 조정이 자동으로 복구할 때까지 모든 조직의 ClickHouse 사용자가 고아 상태가 됩니다. 복제본 전체에서 비밀로 유지하고 변경하지 마세요. 조직 프로비저닝 자체는 운영자 전용입니다. 아래의 **조직(멀티테넌시)** 참조. | -| `DEFAULT_ORG_NAME` | 아니오 | `Default` | 내장된 기본 조직에 시드되는 표시 이름. **첫 번째 부트 시드 전용**이며, 조직이 아직 새로 마이그레이션된 일반 ID를 유지하는 동안에만 시작 시 적용된 후 무시됩니다. 조직 이름을 변경(`agenteye-orgctl org rename`)하면 해당 이름이 신뢰할 수 있는 값이 되고 이 환경 변수는 더 이상 효력이 없습니다. | -| `DEFAULT_ORG_SLUG` | 아니오 | `default` | 내장된 기본 조직의 URL 슬러그. 대시보드에서 조직이 위치하는 경로(`//…`). `DEFAULT_ORG_NAME`과 동일한 첫 번째 부트 전용/초기 상태 전용 시맨틱을 갖습니다. 1-40자의 소문자 영숫자로 구성되며 단일 내부 하이픈이 허용되고 [예약어](#organizations-multi-tenancy)는 사용할 수 없습니다. 잘못된 값은 무시됩니다(조직은 `default`를 유지). 단일 테넌트 설치를 배포 후 CLI 단계 없이 `/default` 대신 `/acme`와 같은 경로로 표시할 수 있습니다. | -| `RUST_LOG` | 아니오 | `info` | 로그 상세도 (`debug`, `warn`, `error`, `agenteye_server=trace`) | -| `EVALUATOR_ENDPOINT` | 아니오 | 없음 | 평가자 서비스의 기본 URL (예: `http://evaluator:9000`). 설정하지 않으면 전체 평가 파이프라인이 no-op이 됩니다. 큐 행이 기록되지 않고 워커도 실행되지 않습니다. [평가 스위트](/ko/agenteye/evaluation-suite) 참조. | -| `EVALUATOR_TOKEN` | 아니오 | 없음 | 평가자에게 `Authorization: Bearer `으로 전송됩니다. **평가자 서비스에 구성된 값과 동일해야 합니다.** 평가자가 토큰 없이 구성된 경우에만 선택 사항입니다. | +| `ORG_CH_SECRET` | 아니오(단일 테넌트) / **예(멀티 org)** | 개발 기본값 | 각 조직의 테넌트별 ClickHouse 비밀번호를 파생하는 HMAC 키. SQL 에디터 및 AI 에이전트의 `run_query`는 org의 자체 읽기 전용 ClickHouse 사용자로 실행되며, 행 정책이 엔진에서 테넌트 격리를 적용합니다. 단일 테넌트 배포는 내장 개발 기본값으로도 정상 부팅됩니다. **두 번째 org를 프로비저닝하기 전에 강력하고 안정적인 값을 반드시 설정해야 합니다.** `agenteye-orgctl org create` CLI는 내장 개발 기본값에서 실행을 거부합니다. 교체하면 다음 시작 시 부팅 시간 조정이 자동으로 복구할 때까지 모든 org의 ClickHouse 사용자가 고아 상태가 됩니다. 복제본 전체에서 비밀로 유지하고 변경하지 마세요. org 프로비저닝 자체는 운영자 전용입니다. 아래 **Organizations (멀티테넌시)** 참조. | +| `DEFAULT_ORG_NAME` | 아니오 | `Default` | 내장 기본 org에 시드되는 표시 이름. **첫 번째 부팅 시드 전용**, org가 새로 마이그레이션된 일반 ID를 유지하는 동안에만 시작 시 적용되고 이후 무시됩니다. org를 이름 변경(`agenteye-orgctl org rename`)하면 그것이 권위 있는 값이 되고 이 환경 변수는 효과가 없습니다. | +| `DEFAULT_ORG_SLUG` | 아니오 | `default` | 내장 기본 org의 URL 슬러그, 대시보드 경로(`//…`). `DEFAULT_ORG_NAME`과 동일한 첫 번째 부팅 전용/초기 상태 전용 의미론. 단일 내부 하이픈을 포함한 1-40자의 소문자 영숫자여야 하며 [예약어](#organizations-multi-tenancy)가 아니어야 합니다. 잘못된 값은 무시됩니다(org는 `default`를 유지). 사후 배포 CLI 단계 없이 단일 테넌트 설치가 `/default` 대신 `/acme`로 표시되도록 할 수 있습니다. | +| `RUST_LOG` | 아니오 | `info` | 로그 상세도(`debug`, `warn`, `error`, `agenteye_server=trace`) | +| `EVALUATOR_ENDPOINT` | 아니오 | 없음 | 평가자 서비스의 기본 URL(예: `http://evaluator:9000`). 설정하지 않으면 전체 평가 파이프라인이 no-op가 됩니다. 큐 행이 기록되지 않고 워커가 실행되지 않습니다. [평가 스위트](/ko/agenteye/evaluation-suite) 참조. | +| `EVALUATOR_TOKEN` | 아니오 | 없음 | 평가자에게 `Authorization: Bearer `으로 전송됩니다. **평가자 서비스에 구성된 것과 동일한 값이어야 합니다.** 평가자가 토큰 없이 구성된 경우에만 선택 사항입니다. | | `EVALUATOR_WORKERS` | 아니오 | `2` | 동시성: 평가를 디스패치하는 서버 인스턴스당 워커 태스크 수. 수평 확장된 여러 서버에서 안전하게 실행할 수 있습니다. | -| `EVALUATOR_CLAIM_BATCH` | 아니오 | `4` | 단일 워커가 틱당 클레임하는 최대 평가 수. 배치는 **동시에** 디스패치되므로 평가자 엔드포인트의 총 동시성은 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`입니다. | -| `EVALUATOR_POLL_IDLE_SECS` | 아니오 | `2` | 디스패치할 항목이 없을 때 워커가 디스패치 시도 사이에 대기하는 시간. | -| `EVALUATOR_POLLING_INTERVAL_SECS` | 아니오 | `10` | 평가자가 응답별 `next_poll_secs`를 반환하지 않고 `GET /config`에서 `default_poll_interval_secs`를 광고하지 않는 경우 `GET /evaluate/{id}` 폴링의 최종 폴백 주기(초). | -| `EVALUATOR_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | 평가자에 대한 HTTP 요청당 타임아웃(밀리초). | -| `EVALUATOR_MAX_ATTEMPTS` | 아니오 | `5` | 이 횟수만큼 실패하면 평가가 최종 `error`(실패가 요청 타임아웃이었던 경우 `timeout`)로 기록됩니다. | -| `EVALUATOR_CONFIG_REFRESH_SECS` | 아니오 | `300` (5분) | 서버가 평가자로부터 `GET /config`를 다시 가져오는 주기. | -| `EVALUATOR_MAX_POLL_DURATION_SECS` | 아니오 | `3600` (1시간) | AgentEye가 세션을 `timeout`으로 종료하기 전까지 폴링 큐에 남아 있을 수 있는 최대 실시간 시간. 영원히 `pending`을 반환하는 평가자로부터 보호합니다. | +| `EVALUATOR_CLAIM_BATCH` | 아니오 | `4` | 단일 워커가 틱당 요청하는 최대 평가 수. 배치는 **동시에** 디스패치되므로 평가자 엔드포인트의 총 동시성은 `EVALUATOR_WORKERS × EVALUATOR_CLAIM_BATCH`입니다. | +| `EVALUATOR_POLL_IDLE_SECS` | 아니오 | `2` | 대기 중인 항목이 없을 때 워커가 디스패치 시도 사이에 대기하는 시간. | +| `EVALUATOR_POLLING_INTERVAL_SECS` | 아니오 | `10` | 평가자가 응답별 `next_poll_secs`를 반환하지 않고 `GET /config`에서 `default_poll_interval_secs`도 알리지 않을 때 `GET /evaluate/{id}` 폴링의 최종 폴백 주기(초). | +| `EVALUATOR_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | 평가자에 대한 HTTP 요청별 타임아웃(밀리초). | +| `EVALUATOR_MAX_ATTEMPTS` | 아니오 | `5` | 이 횟수만큼 실패하면 평가가 최종 `error`(또는 실패가 요청 타임아웃이었으면 `timeout`)로 기록됩니다. | +| `EVALUATOR_CONFIG_REFRESH_SECS` | 아니오 | `300` (5분) | 서버가 평가자에서 `GET /config`를 다시 가져오는 빈도. | +| `EVALUATOR_MAX_POLL_DURATION_SECS` | 아니오 | `3600` (1시간) | 세션이 폴링 큐에 남아 있을 수 있는 최대 벽시계 시간. 이를 초과하면 AgentEye가 `timeout`으로 종료합니다. 평가자가 영구적으로 `pending`을 반환하는 경우를 방지합니다. | | `ALERT_WORKERS` | 아니오 | `1` | 동시성: 알림 규칙을 평가하는 서버 인스턴스당 워커 태스크 수. [알림](/ko/agenteye/alerts) 참조. | -| `ALERT_CLAIM_BATCH` | 아니오 | `16` | 단일 워커가 틱당 클레임하는 최대 알림 수. | +| `ALERT_CLAIM_BATCH` | 아니오 | `16` | 단일 워커가 틱당 요청하는 최대 알림 수. | | `ALERT_POLL_IDLE_SECS` | 아니오 | `5` | 큐가 비었을 때 알림 워커가 대기하는 시간. | -| `ALERT_REQUEST_TIMEOUT_MS` | 아니오 | `15000` | 트리거 평가당 타임아웃(ClickHouse 쿼리 + 아웃바운드 채널 HTTP). | -| `ALERT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 알림을 재예약하기 전 연속 일시적 실패 횟수. | +| `ALERT_REQUEST_TIMEOUT_MS` | 아니오 | `15000` | 트리거 평가별 타임아웃(ClickHouse 쿼리 + 아웃바운드 채널 HTTP). | +| `ALERT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 알림이 재예약되기 전 연속 일시적 실패 횟수. | | `AUDIT_WORKERS` | 아니오 | `1` | 동시성: 감사를 실행하는 서버 인스턴스당 워커 태스크 수. [감사](/ko/agenteye/audits) 참조. | -| `AUDIT_CLAIM_BATCH` | 아니오 | `1` | 단일 워커가 틱당 클레임하는 최대 예정된 감사 수. 에이전트 조사는 긴 루프이므로 기본값은 1입니다. | +| `AUDIT_CLAIM_BATCH` | 아니오 | `1` | 단일 워커가 틱당 요청하는 최대 감사 수. 에이전틱 조사는 하나의 긴 루프이므로 기본값은 1입니다. | | `AUDIT_POLL_IDLE_SECS` | 아니오 | `30` | 예정된 감사가 없을 때 감사 워커가 대기하는 시간. | -| `AUDIT_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | ClickHouse에 대한 정책 쿼리당 타임아웃(밀리초). | -| `AUDIT_LLM_TIMEOUT_MS` | 아니오 | `1440000` | AI 어시스턴트 서비스에 대한 에이전트 조사 호출의 타임아웃. 전체 에이전트 루프는 몇 분간 실행됩니다. 에이전트가 서버가 포기하기 전에 부분 결과를 반환할 수 있도록 에이전트 자체의 `AGENTEYE_AUDIT_TIMEOUT_MS`보다 높게 유지하세요. | -| `AUDIT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 감사를 재예약하기 전 연속 일시적 실패 횟수. | -| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | 아니오 | — | 감사의 에이전트 조사는 어시스턴트와 동일한 연결을 재사용하여 AI 어시스턴트 `agent` 서비스를 호출합니다. 따라서 이 두 값을 **서버**에도 설정하세요(번들 매니페스트/컴포즈에서 이미 설정됨). 둘 다 설정되면 감사에서 AI 조사가 실행됩니다. 하나라도 설정되지 않으면 감사는 **정책 전용**으로 실행됩니다(결정론적 SQL 정책 패스는 여전히 실행됨). 감사별 `llm_enabled` 플래그와 무관합니다. 에이전트에도 LLM이 구성되어 있어야 합니다. [assistant.md](/ko/agenteye/assistant) 참조. | +| `AUDIT_REQUEST_TIMEOUT_MS` | 아니오 | `30000` | ClickHouse에 대한 정책 쿼리별 타임아웃(밀리초). | +| `AUDIT_LLM_TIMEOUT_MS` | 아니오 | `1440000` | AI 어시스턴트 서비스에 대한 에이전틱 조사 호출 타임아웃. 전체 에이전트 루프는 수 분 동안 실행됩니다. 에이전트가 부분 결과를 반환하기 전에 서버가 포기하지 않도록 에이전트 자체의 `AGENTEYE_AUDIT_TIMEOUT_MS`보다 높게 유지하세요. | +| `AUDIT_MAX_ATTEMPTS` | 아니오 | `5` | 지수 백오프 대신 정상 주기로 감사가 재예약되기 전 연속 일시적 실패 횟수. | +| `AGENTEYE_AGENT_URL` / `AGENTEYE_AGENT_TOKEN` | 아니오 | — | 감사의 에이전틱 조사는 어시스턴트와 동일한 연결을 재사용하는 AI 어시스턴트 `agent` 서비스를 호출합니다. 따라서 이 두 값을 **서버**에도 설정해야 합니다(번들 매니페스트/컴포즈가 이를 수행). 둘 다 설정 → 감사가 AI 조사를 실행합니다. 둘 중 하나라도 설정되지 않으면 → per-audit `llm_enabled` 플래그와 관계없이 감사가 **정책 전용**(결정론적 SQL 정책 패스만 실행)으로 실행됩니다. 에이전트에도 LLM이 구성되어 있어야 합니다 — [assistant.md](/ko/agenteye/assistant) 참조. | -**AI 어시스턴트 서비스 — 감사 + 샌드박스 설정.** 에이전트 조사와 인팟 Python 샌드박스는 **에이전트 서비스**(서버가 아님)에서 `AGENTEYE_AUDIT_*` 접두사로 모두 선택 사항으로 조정됩니다: +**AI 어시스턴트 서비스 — 감사 + 샌드박스 설정.** 에이전틱 조사 및 파드 내 Python 샌드박스는 서버가 아닌 **에이전트 서비스**에서 `AGENTEYE_AUDIT_*` 접두사로 튜닝되며, 모두 선택 사항입니다: | 변수 | 기본값 | 의미 | |---|---|---| | `AGENTEYE_AUDIT_MAX_STEPS` | `200` | 조사당 최대 에이전트 턴 수. | -| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | 하나의 조사에 대한 실시간 타임아웃(20분). 서버의 `AUDIT_LLM_TIMEOUT_MS`보다 **낮게** 유지해야 합니다. | -| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | 에이전트 파드당 동시 조사 수(채팅 어시스턴트 예산과 별개). | -| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | bubblewrap 샌드박스에 대한 스크립트당 제한. | +| `AGENTEYE_AUDIT_TIMEOUT_MS` | `1200000` | 단일 조사의 벽시계 시간(20분). 서버의 `AUDIT_LLM_TIMEOUT_MS`보다 **낮게** 유지해야 합니다. | +| `AGENTEYE_AUDIT_MAX_CONCURRENCY` | `1` | 에이전트 파드당 동시 조사 수(채팅 어시스턴트 예산과 별도). | +| `AGENTEYE_AUDIT_SANDBOX_TIMEOUT_MS` / `_MEM_MB` / `_CPU_SECS` / `_OUTPUT_MAX_BYTES` / `_SCRIPT_MAX_BYTES` | `20000` / `768` / `10` / `64000` / `64000` | bubblewrap 샌드박스의 스크립트별 제한. | -**샌드박스 플랫폼 요구사항.** 감사 코드 샌드박스는 bubblewrap 감옥 내에서 모델의 Python을 실행하며, **비권한 사용자 네임스페이스**가 필요합니다. 에이전트 파드는 `clone()` 플래그를 허용해야 합니다. k8s에서는 `seccompProfile: Unconfined`를, 컴포즈에서는 `security_opt: [seccomp:unconfined]`를 에이전트에 설정하세요. 노드 커널이 비권한 사용자 네임스페이스를 비활성화한 경우(예: 일부 GKE COS 이미지), 샌드박스 **프리플라이트가 실패하고 감사자는 자동으로 SQL 전용으로 저하됩니다.** 오류 없이 에이전트의 `/health`에 `sandbox_available: false`만 표시됩니다. +**샌드박스 플랫폼 요구사항.** 감사 코드 샌드박스는 모델의 Python을 bubblewrap 감옥 내에서 실행하며, 이는 **비권한 사용자 네임스페이스**가 필요합니다. 에이전트 파드는 `clone()` 플래그를 허용해야 합니다 — 에이전트에 `seccompProfile: Unconfined`(k8s) 또는 `security_opt: [seccomp:unconfined]`(컴포즈)를 설정하세요. 노드 커널이 비권한 사용자 네임스페이스를 비활성화하는 경우(예: 일부 GKE COS 이미지), 샌드박스 **사전 점검이 실패하고 감사기는 SQL 전용으로 자동 저하**됩니다 — 오류 없이 에이전트의 `/health`에 `sandbox_available: false`만 표시됩니다. ### 실행 -환경에서 `DATABASE_URL`과 `CLICKHOUSE_URL`을 설정하고(서버는 ClickHouse 없이 부팅을 거부합니다), 컨테이너로 전달하세요: +환경에 `DATABASE_URL`을 설정한 다음 컨테이너에 전달하세요: ```bash docker run -d --restart unless-stopped \ --name agenteye-server \ -e DATABASE_URL="$DATABASE_URL" \ - -e CLICKHOUSE_URL="$CLICKHOUSE_URL" \ -e ADMIN_KEY="$ADMIN_KEY" \ -p 8080:8080 \ ghcr.io/agenteye-enterprise/server:beta-latest @@ -128,30 +127,30 @@ docker run -d --restart unless-stopped \ ### 헬스 체크 ``` -GET /health # liveness - always {"status":"ok"} once the process is up -GET /ready # readiness - 200 when Postgres + ClickHouse are reachable, else 503 +GET /health # 활성 상태 - 프로세스가 시작되면 항상 {"status":"ok"} +GET /ready # 준비 상태 - Postgres + ClickHouse에 연결 가능하면 200, 아니면 503 ``` -인증이 필요하지 않습니다. **활성(liveness)** 프로브에는 `/health`를, **준비(readiness)**/로드 밸런서 프로브에는 `/ready`를 사용하세요. `/ready`는 서버가 서비스를 제공할 수 없는 하드 의존성(Postgres + ClickHouse)을 확인합니다. 따라서 실행 중이지만 데이터베이스에 연결할 수 없는 서버는 로테이션에서 제외되고 `NotReady`로 표시됩니다. Redis는 보고되지만 준비 상태 실패를 유발하지 않습니다. 번들로 제공되는 Kubernetes 매니페스트에서 준비 프로브는 이미 `/ready`를 가리키고 활성 프로브는 `/health`를 유지합니다. Slack으로의 선택적 Kubernetes 네이티브 파드 실패 알림을 포함한 전체 내용은 [enterprise-docs/health-monitoring.md](/ko/agenteye/health-monitoring)를 참조하세요. +인증이 필요하지 않습니다. **활성 상태** 프로브에는 `/health`를, **준비 상태**/로드밸런서 프로브에는 `/ready`를 사용하세요. `/ready`는 서버가 제공할 수 없는 필수 종속성(Postgres + ClickHouse)을 확인합니다. 따라서 실행 중이지만 데이터베이스에 연결할 수 없는 서버는 순환에서 제외되고 `NotReady`로 표시됩니다. Redis는 보고되지만 준비 상태를 실패시키지 않습니다. 번들 Kubernetes 매니페스트에서 준비 상태 프로브는 이미 `/ready`를 가리키고 활성 상태는 `/health`를 유지합니다. 전체 내용(Slack에 대한 옵트인 Kubernetes 네이티브 파드 장애 알림 포함)은 [enterprise-docs/health-monitoring.md](/ko/agenteye/health-monitoring)를 참조하세요. ### 이메일 매직 링크 URL -OTP 로그인 이메일에는 **대시보드 열기** 원탭 버튼이 포함됩니다. 클릭하면 사용자가 `/login?token=&email=
`로 이동하고, 대시보드는 해당 쌍을 세션으로 교환하여 앱으로 리디렉션합니다. 코드를 수동으로 다시 입력할 필요가 없습니다. 서버는 링크 생성에 사용되는 대시보드 원본 주소를 세 단계로 결정합니다: +OTP 로그인 이메일에는 원탭 **대시보드 열기** 버튼이 포함됩니다. 클릭하면 `/login?token=&email=
`로 이동합니다. 대시보드는 해당 쌍을 세션으로 교환하고 앱으로 리디렉션하며, 수동 코드 재입력이 필요하지 않습니다. 서버는 링크를 구성하는 데 사용할 대시보드 오리진을 세 단계로 확인합니다: -1. **`X-AgentEye-Dashboard-Url` 헤더**: 대시보드의 `/api/auth/otp/request` 프록시가 자체 공개 원본 주소에서 자동으로 설정합니다. 동일 원본 배포(서버와 대시보드가 프록시 헤더를 전달하는 하나의 인그레스 뒤에 있는 경우)에서는 **구성이 필요하지 않습니다.** -2. **`DASHBOARD_URL` 환경 변수**: 대시보드가 서버의 OTP 요청 엔드포인트가 보는 원본 주소와 다른 원본 주소(`api.example.com` / `app.example.com` 분리)로 접근 가능한 경우, 또는 인그레스가 공개 호스트를 대시보드 파드로 전파하지 않는 경우(`request.nextUrl.origin`이 `0.0.0.0:3000`과 같은 와일드카드 바인드로 해석될 수 있음) 이 값을 설정하세요. 예: `DASHBOARD_URL=https://app.example.com`. -3. **기본값**: `https://app.befailproof.ai`. 위의 두 가지가 모두 없는 경우에만 사용됩니다. +1. **`X-AgentEye-Dashboard-Url` 헤더**: 대시보드의 `/api/auth/otp/request` 프록시가 자체 공개 오리진에서 자동으로 설정합니다. 동일 오리진 배포(서버와 대시보드가 프록시 헤더를 전달하는 하나의 인그레스 뒤에서 호스트를 공유)에서는 **구성이 필요하지 않습니다**. +2. **`DASHBOARD_URL` 환경 변수**: 대시보드가 서버의 OTP 요청 엔드포인트가 보는 것과 다른 오리진에서 접근 가능하거나(`api.example.com` / `app.example.com` 분리), 인그레스가 공개 호스트를 대시보드 파드에 전파하지 않는 경우(그러면 `request.nextUrl.origin`이 `0.0.0.0:3000`과 같은 와일드카드 바인드로 확인됨) 설정하세요. 예: `DASHBOARD_URL=https://app.example.com`. +3. **기본값**: 위 두 가지가 모두 없을 때만 사용되는 `https://app.befailproof.ai`. -헤더 값이 검증됩니다. `https://*` 및 루프백(`http://localhost*`, `http://127.0.0.1*`) 원본만 허용되며, `https://` 스키마가 있더라도 와일드카드 바인드 주소(`0.0.0.0`, `[::]`)는 거부됩니다. 그 외의 경우는 2단계로 폴스루됩니다. +헤더 값의 유효성이 검사됩니다: `https://*` 및 루프백(`http://localhost*`, `http://127.0.0.1*`) 오리진만 허용되며, 와일드카드 바인드 주소(`0.0.0.0`, `[::]`)는 `https://` 스킴이 있어도 거부됩니다. 그 외의 것은 2단계로 폴백됩니다. -파일이나 kustomize 재빌드 없이 원라이너로 실행 중인 클러스터에 설정하세요: +한 줄 명령으로 실행 중인 클러스터에 설정합니다. 파일이나 kustomize 재빌드가 필요하지 않습니다: ```bash kubectl set env deployment/server -n agenteye \ DASHBOARD_URL=https://app.example.com ``` -이렇게 하면 롤아웃이 트리거되고 새 파드가 첫 번째 요청 시 값을 가져옵니다. 재정의는 Deployment에만 존재합니다. 이후에 오버레이에 대해 `kustomize build | kubectl apply`를 실행하면 동일한 환경 변수를 오버레이의 `server-env.yaml` 패치에 추가하지 않는 한 이 값이 지워집니다. +이는 롤아웃을 트리거합니다. 새 파드는 첫 번째 요청 시 값을 가져옵니다. 재정의는 Deployment에만 존재한다는 점에 유의하세요. 오버레이에 대해 `kustomize build | kubectl apply`를 이후에 실행하면 오버레이의 `server-env.yaml` 패치에 동일한 환경 변수를 추가하지 않는 한 제거됩니다. --- @@ -167,14 +166,14 @@ docker pull ghcr.io/agenteye-enterprise/dashboard:beta-latest | 변수 | 필수 여부 | 기본값 | 설명 | |---|---|---|---| -| `AGENTEYE_SERVER_URL` | 예 | 없음 | 서버의 기본 URL. 예: `http://localhost:8080` | -| `AGENTEYE_API_KEY` | 예 | 없음 | 대시보드가 서버 인증에 사용하는 API 키. 모든 권한이 필요합니다(관리자 키 권장). | -| `AE_LOG_LEVEL` | 아니오 | `info` | 서버 측 로그 상세도: `debug`, `info`, `warn`, `error`. 문제 진단 시 업스트림 요청/응답 줄과 세션 검증 추적을 보려면 `debug`로 설정하세요. | -| `AE_LOG_JSON` | 아니오 | 자동 | `1`은 JSON 한 줄 출력 강제, `0`은 사람이 읽을 수 있는 출력 강제. 설정하지 않으면 `NODE_ENV=production`인 경우 JSON이 자동으로 활성화됩니다. 프로덕션에서는 `jq`나 로그 집계기로 깔끔하게 파싱할 수 있도록 JSON을 권장합니다. | -| `AE_ANALYTICS_DISABLED` | 아니오 | 없음 | `1`/`true`로 설정하면 대시보드의 익명 제품 사용 텔레메트리가 비활성화됩니다. 아래의 [텔레메트리 및 개인정보 보호](#telemetry--privacy) 참조. | -| `REDIS_URL` | 아니오 | 없음 | 선택 사항인 공유 캐시 백엔드. 예: `redis://redis:6379/0`. 설정하면 대시보드는 복제본 전체에서 `validateSession()` 결과를 캐시하고 지연 집계/env 목록 프록시 라우트에 대한 Next.js 페치 캐시를 공유합니다. 엣지 OTP 요청 및 검증 속도 제한도 Redis가 있으면 Redis를 사용합니다(Redis에 연결할 수 없으면 열린 상태로 실패하며, 서버 측 제한이 보안 백스톱). 아래의 **Redis(선택 사항 캐시)** 참조. | -| `AGENTEYE_AGENT_URL` | 아니오 | 없음 | 선택 사항인 AI 어시스턴트 `agent` 서비스의 기본 URL. 예: `http://agent:9100`. **어시스턴트를 완전히 숨기려면 설정하지 마세요.** 대시보드에 어시스턴트 버블이 나타나지 않습니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | -| `AGENTEYE_AGENT_TOKEN` | 아니오 | 없음 | 대시보드가 `agent` 서비스에 제공하는 공유 비밀. 에이전트에 구성된 `AGENTEYE_AGENT_TOKEN`과 일치해야 합니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | +| `AGENTEYE_SERVER_URL` | 예 | 없음 | 서버의 기본 URL, 예: `http://localhost:8080` | +| `AGENTEYE_API_KEY` | 예 | 없음 | 대시보드가 서버에 인증하는 데 사용하는 API 키. 모든 권한이 필요합니다(관리자 키 권장). | +| `AE_LOG_LEVEL` | 아니오 | `info` | 서버 측 로그 상세도: `debug`, `info`, `warn`, `error`. 문제 진단 시 업스트림 요청/응답 라인과 세션 유효성 검사 추적을 보려면 `debug`로 설정하세요. | +| `AE_LOG_JSON` | 아니오 | 자동 | `1`은 JSON 라인별 출력을 강제합니다. `0`은 사람이 읽을 수 있는 출력을 강제합니다. 설정하지 않으면 `NODE_ENV=production`일 때 JSON이 자동으로 활성화됩니다. 프로덕션에서는 `jq` 또는 로그 집계기로 깔끔하게 파싱할 수 있도록 JSON을 권장합니다. | +| `AE_ANALYTICS_DISABLED` | 아니오 | 없음 | `1`/`true`로 설정하면 대시보드의 익명 제품 사용 텔레메트리가 비활성화됩니다. 아래 [텔레메트리 및 개인정보](#telemetry--privacy)를 참조하세요. | +| `REDIS_URL` | 아니오 | 없음 | 선택적 공유 캐시 백엔드, 예: `redis://redis:6379/0`. 설정 시 대시보드는 복제본 간에 `validateSession()` 결과를 캐시하고 레이턴시 집계/env 목록 프록시 경로에 대한 Next.js 페치 캐시를 공유합니다. 엣지 측 OTP 요청 및 확인 속도 제한도 Redis가 있으면 사용합니다(Redis에 연결할 수 없으면 열린 상태로 폴백하며, 서버 측 제한이 보안 백스톱). 아래 **Redis (선택적 캐시)** 참조. | +| `AGENTEYE_AGENT_URL` | 아니오 | 없음 | 선택적 AI 어시스턴트 `agent` 서비스의 기본 URL, 예: `http://agent:9100`. **설정하지 않으면 어시스턴트가 완전히 숨겨집니다**: 대시보드에 어시스턴트 버블이 표시되지 않습니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | +| `AGENTEYE_AGENT_TOKEN` | 아니오 | 없음 | 대시보드가 `agent` 서비스에 제시하는 공유 시크릿. 에이전트에 구성된 `AGENTEYE_AGENT_TOKEN`과 일치해야 합니다. [enterprise-docs/assistant.md](/ko/agenteye/assistant) 참조. | ### 실행 @@ -187,91 +186,91 @@ docker run -d --restart unless-stopped \ ghcr.io/agenteye-enterprise/dashboard:beta-latest ``` -### 텔레메트리 및 개인정보 보호 +### 텔레메트리 및 개인정보 -대시보드는 **익명 제품 사용 분석**을 Exosphere의 분석 서비스(PostHog)로 전송합니다. 대시보드 페이지 조회 및 API 키 생성이나 세션 재평가 같은 일부 UI 액션이 포함됩니다. 이 사용 신호는 기능 우선순위 결정에 활용됩니다. +대시보드는 **익명 제품 사용 분석**을 Exosphere의 분석 서비스(PostHog)로 전송합니다: 어떤 대시보드 페이지가 조회되었는지, API 키 생성 또는 세션 재평가와 같은 몇 가지 UI 동작이 포함됩니다. 이 사용 신호는 어떤 기능을 우선순위에 둘지 결정하는 데 활용됩니다. -- **에이전트, 세션 또는 이벤트 데이터는 인프라 외부로 전혀 전송되지 않습니다.** 오직 대시보드 UI 사용만 보고됩니다. 페이지 URL은 전송 전에 식별자가 제거되며, 운영자는 이메일이 아닌 불투명한 내부 ID로만 식별됩니다. +- **에이전트, 세션 또는 이벤트 데이터는 절대 인프라 밖으로 나가지 않습니다.** 대시보드 UI 사용만 보고됩니다. 페이지 URL은 전송 전에 식별자가 제거되며, 운영자는 이메일이 아닌 불투명한 내부 ID로만 식별됩니다. - 텔레메트리는 **기본적으로 활성화**되어 있습니다. 완전히 끄려면 대시보드 컨테이너에 `AE_ANALYTICS_DISABLED=1`을 설정하고 재시작하세요. -- 분석은 대시보드의 `/ingest` 경로로 전송되며, 대시보드는 이를 PostHog(`https://us.i.posthog.com`)로 역방향 프록시합니다. 요청을 퍼스트 파티로 유지하면 브라우저 광고 차단기가 차단하지 않습니다. **대시보드 컨테이너**는 PostHog에 대한 아웃바운드 액세스가 필요합니다. 차단된 경우 텔레메트리는 조용히 아무것도 하지 않고 대시보드는 영향을 받지 않습니다. +- 분석은 대시보드의 `/ingest` 경로로 전송되며, 대시보드가 이를 PostHog(`https://us.i.posthog.com`)로 역방향 프록시합니다. 요청을 퍼스트파티로 유지하면 브라우저 광고 차단기가 이를 차단하지 않습니다. **대시보드 컨테이너**는 PostHog로 아웃바운드 접근이 필요합니다. 차단된 경우 텔레메트리는 조용히 동작하지 않으며 대시보드는 영향을 받지 않습니다. --- ## AI 어시스턴트 (선택 사항) -인대시보드 AI 어시스턴트를 통해 팀원들이 자연어로 에이전트 데이터에 대한 질문을 할 수 있습니다(세션 요약, `/queries` 편집기를 위한 SQL 초안 작성, 저장된 쿼리를 대시보드 타일로 변환). 대시보드를 떠날 필요가 없으며, 대시보드만 접근할 수 있는 별도의 내부 `agent` 컨테이너(Claude Agents SDK 기반)로 실행됩니다. **LLM 엔드포인트를 구성할 때까지 비활성화 상태입니다.** +대시보드 내 AI 어시스턴트를 통해 팀이 에이전트 데이터를 자연어로 질의할 수 있습니다(세션 요약, `/queries` 에디터용 SQL 초안 작성, 저장된 쿼리를 대시보드 타일로 변환). 대시보드를 벗어날 필요가 없습니다. Claude Agents SDK 기반의 별도 내부 `agent` 컨테이너로 실행되며 대시보드만 접근할 수 있고, **LLM 엔드포인트를 구성할 때까지 비활성화 상태**로 유지됩니다. -활성화하려면 `agent` 서비스에 LLM 연결(**Portkey**: `PORTKEY_API_KEY` + 모델 카탈로그 슬러그 `AGENTEYE_AGENT_MODEL=@/`, 직접 Anthropic: `ANTHROPIC_API_KEY`, 다른 게이트웨이: `ANTHROPIC_BASE_URL`, 또는 Bedrock/Vertex), **전용** 데이터 키, 그리고 대시보드와 일치하는 공유 `AGENTEYE_AGENT_TOKEN`을 설정합니다. 대시보드 사용자는 추가로 `agent:use` 권한이 필요합니다. +활성화하려면 `agent` 서비스에 LLM 연결(**Portkey** via `PORTKEY_API_KEY` + 모델 카탈로그 슬러그 `AGENTEYE_AGENT_MODEL=@/`, 직접 Anthropic via `ANTHROPIC_API_KEY`, 다른 게이트웨이 via `ANTHROPIC_BASE_URL`, 또는 Bedrock/Vertex), **전용** 데이터 키, 대시보드와 일치하는 공유 `AGENTEYE_AGENT_TOKEN`을 설정합니다. 대시보드 사용자에게는 추가로 `agent:use` 권한이 필요합니다. -어시스턴트의 데이터 키는 직접 생성하지 않아도 됩니다. 랜덤 비밀을 선택하여 `agent`에 `AGENTEYE_API_KEY`로 설정하고 `server`에 `AGENT_API_KEY`로 설정하면, 서버가 시작 시 고정된 권한 세트로 시드합니다. 데이터 접근은 읽기 전용(`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`)이며, 승인 게이트 작성 범위(`dashboards:write`, `queries:write`, `queries:run`)도 보유하여 사용자를 대신해 저장된 쿼리를 초안 작성/검증하고 대시보드 타일을 빌드할 수 있습니다. 모든 SQL은 여전히 조직의 읽기 전용 ClickHouse 역할을 통해 실행되므로, 어시스턴트가 작성할 수 있는 범위가 넓어지는 것이지 접근할 수 있는 데이터 범위가 넓어지는 것은 아닙니다. 범위는 코드에서 고정되며 구성으로 확장할 수 없습니다. 해당 키는 보호됩니다. API를 통해 비활성화하거나 재생성할 수 없으며, 값을 변경하고 재시작하여 순환할 수 있습니다. 이 용도로 관리자/대시보드 키를 재사용하지 마세요. +어시스턴트의 데이터 키는 직접 생성할 필요가 없습니다: 임의의 시크릿을 선택하여 `agent`에는 `AGENTEYE_API_KEY`로, `server`에는 `AGENT_API_KEY`로 설정하면 서버가 시작 시 고정된 권한 세트로 시드합니다. 데이터 접근은 읽기 전용(`events:read`, `evaluations:read`, `dashboards:read`, `queries:read`)이며, 승인이 필요한 저작 범위(`dashboards:write`, `queries:write`, `queries:run`)도 보유하여 사용자를 대신해 저장된 쿼리를 초안 작성, 검증하고 대시보드 타일을 구축할 수 있습니다. 모든 SQL은 여전히 org의 읽기 전용 ClickHouse 역할을 통해 실행되므로, 어시스턴트가 저작할 수 있는 내용이 넓어지는 것이지 접근 가능한 데이터가 넓어지는 것이 아닙니다. 범위는 코드에 고정되어 있으며 구성으로 넓힐 수 없습니다. 해당 키는 보호되어 있으며 API를 통해 비활성화하거나 재생성할 수 없고, 값을 변경하고 재시작하는 방식으로만 교체할 수 있습니다. 어시스턴트에 관리자/대시보드 키를 재사용하지 마세요. -전체 설정, 완전한 환경 변수 레퍼런스, 텔레메트리 옵션, 보안 모델은 **[enterprise-docs/assistant.md](/ko/agenteye/assistant)**에 있습니다. +전체 설정, 완전한 환경 변수 참조, 텔레메트리 옵션, 보안 모델은 **[enterprise-docs/assistant.md](/ko/agenteye/assistant)**에 있습니다. --- ## ClickHouse (필수 분석 저장소) -ClickHouse는 높은 이벤트 볼륨에서도 대시보드의 응답성을 유지하고, `/queries` SQL 편집기가 이벤트, 평가, 세션을 단일 저장소에서 조인할 수 있게 합니다. 수집된 모든 이벤트, 모든 최종 평가 결과, 파생된 세션별 집계에 대한 필수 정규 저장소입니다. PostgreSQL은 관계형/가변 상태 테이블(api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries)을 보유하고, 분석 표면은 ClickHouse에 있어 대시보드 롤업과 사용자 정의 SQL 쿼리가 크로스 데이터베이스 라운드트립 없이 기본적으로 스캔하고 조인할 수 있습니다. 서버는 `CLICKHOUSE_URL` 없이 부팅을 거부합니다. +ClickHouse는 높은 이벤트 볼륨에서도 대시보드를 빠르게 유지하며, `/queries` SQL 에디터가 단일 저장소에서 이벤트, 평가, 세션을 조인할 수 있게 합니다. 수집된 모든 이벤트, 모든 최종 평가 결과, 파생된 세션별 집계의 필수 표준 저장소입니다. PostgreSQL은 관계형/가변 상태 테이블(api_keys, users, otp_codes, evaluation_jobs, dashboards, saved_queries)을 보유하며, 분석 표면은 ClickHouse에 있어 대시보드 롤업과 자체 SQL 쿼리가 크로스 데이터베이스 왕복 없이 네이티브로 스캔하고 조인할 수 있습니다. 서버는 `CLICKHOUSE_URL` 없이 부팅을 거부합니다. ### 스키마 -서버 시작 시 세 개의 ClickHouse 객체가 생성됩니다. 모두 멱등적입니다(`CREATE IF NOT EXISTS`): +서버 시작 시 세 가지 ClickHouse 객체가 생성됩니다. 모두 멱등적입니다(`CREATE IF NOT EXISTS`): -- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(ts)`로 파티션됨, `(session_id, ts, dedup_key)` 순서로 정렬됨. 중복 삽입(콜렉터 재시도)은 병합 시 단일 행으로 합쳐집니다. 서버는 모든 이벤트에 대해 결정론적 SHA-256 `dedup_key`를 계산하므로 재시도가 안전합니다. -- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(finished_at)`로 파티션됨, `(session_id, finished_at, dedup_key)` 순서로 정렬됨. 평가자 파이프라인이 최종 평가 결과마다 한 번 기록합니다. `events`와 동일한 dedup 키 모델. -- **`agenteye.agent_sessions`**: 물리적 테이블이 아닌 `agenteye.events`에 대한 **뷰**. 모든 컬럼이 파생됩니다(`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()` 등). 이벤트별 업서트나 별도 백필 없이 뷰가 `events`의 내용을 자동으로 반영합니다. +- **`agenteye.events`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(ts)`로 파티션됨, `(session_id, ts, dedup_key)` 순 정렬. 중복 삽입(수집기 재시도)은 병합 시 단일 행으로 축소됩니다. 서버는 모든 이벤트에 대해 결정론적 SHA-256 `dedup_key`를 계산하므로 재시도가 안전합니다. +- **`agenteye.evaluations`**: `ReplacingMergeTree(ingested_at)`, `toYYYYMM(finished_at)`로 파티션됨, `(session_id, finished_at, dedup_key)` 순 정렬. 평가자 파이프라인이 최종 평가 결과당 한 번 씁니다. `events`와 동일한 중복 제거 키 모델. +- **`agenteye.agent_sessions`**: 물리적 테이블이 아닌 `agenteye.events`에 대한 **VIEW**. 모든 컬럼이 파생됩니다(`started_at = min(ts)`, `last_event_at = max(ts)`, `ended_at = max(if event_type='agent_end', ts, NULL)`, `event_count = count()` 등). 이벤트별 upsert와 별도 백필이 없으며, 뷰는 `events`에 있는 내용을 자동으로 반영합니다. -`analytics.evaluations` / `analytics.sessions`를 참조하는 저장된 쿼리와의 하위 호환성을 위해 서버는 `agenteye.*` 테이블 위에 뷰가 있는 `analytics` ClickHouse 데이터베이스도 생성합니다. `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions`가 모두 올바르게 해석됩니다. +`analytics.evaluations` / `analytics.sessions`를 참조하는 저장된 쿼리와의 하위 호환성을 위해 서버는 `agenteye.*` 테이블에 대한 뷰가 포함된 `analytics` ClickHouse 데이터베이스도 생성합니다. `analytics.events`, `analytics.evaluations`, `analytics.agent_sessions`, `analytics.sessions`가 모두 올바르게 확인됩니다. ### 구성 -번들로 제공되는 docker-compose와 `deploy/base/clickhouse/`는 AgentEye의 워크로드에 최적화된 ClickHouse 서비스를 포함합니다: +번들 docker-compose 및 `deploy/base/clickhouse/`는 AgentEye 워크로드에 맞게 최적화된 ClickHouse 서비스를 제공합니다: -- 번들 기본 오버레이에서 2 GiB 요청 / 4 GiB 제한 메모리(작은 POC/스테이징 노드에 맞게 조정됨). 프로덕션 고객은 오버레이를 조정해야 합니다. 권장 최솟값은 2c / 4Gi 요청, 6c / 8Gi 제한입니다. `max_server_memory_usage_to_ram_ratio=0.9` +- 제공된 기본 오버레이에서 요청 2 GiB / 제한 4 GiB 메모리(소규모 POC/스테이징 노드에 맞게 크기 조정). 프로덕션 고객은 오버레이를 업사이징해야 합니다. 권장 최소 사양은 요청 2c/4Gi, 제한 6c/8Gi입니다. `max_server_memory_usage_to_ram_ratio=0.9` - 5 GiB 마크 캐시 + 8 GiB 비압축 캐시 - `background_pool_size=16`, `background_merges_mutations_concurrency_ratio=2` - MergeTree: `parts_to_throw_insert=3000`, `parts_to_delay_insert=1500`, `non_replicated_deduplication_window=1000` - `local_io_method=auto` (지원되는 커널에서 io_uring) -- `fsync_metadata=0`: 최소 1회 이상 수집 + ReplacingMergeTree dedup으로 인해 허용됨 -- `query_log`은 30일 TTL로 활성화됨. `query_thread_log`는 제거됨(높은 QPS에서 비용이 많이 듦) +- `fsync_metadata=0`: 최소 한 번 수집 + ReplacingMergeTree 중복 제거 때문에 허용됨 +- 30일 TTL을 가진 `query_log` 활성화. 높은 QPS에서 비용이 많이 드는 `query_thread_log` 제거됨 - 사용자 측 쿼리에 대한 `max_execution_time=30` -- StatefulSet 템플릿에 100 GiB PVC(고객 오버레이는 프로덕션에서 빠른 SSD 스토리지 클래스로 재정의해야 함) +- StatefulSet 템플릿에 100 GiB PVC (고객 오버레이는 프로덕션을 위해 빠른 SSD 스토리지 클래스로 재정의해야 함) ### 백업 -전체 데이터셋은 매일 밤 단일 복원 가능한 아카이브로 캡처되므로, 클러스터 또는 스토리지 손실 시 복구할 수 있습니다. ClickHouse는 일일 `agenteye-backup` CronJob에 의해 자동으로 백업됩니다. 이 CronJob은 PostgreSQL과 ClickHouse를 한 번에 덤프합니다. ClickHouse는 HTTP API를 통해 읽힙니다. `agenteye.events`와 `agenteye.evaluations`는 ClickHouse 네이티브 형식으로 덤프되며(뷰와 행 정책은 서버 시작 시 재생성되므로 테이블 데이터가 완전한 그림), Postgres 덤프와 함께 단일 압축 아카이브로 번들되어 객체 스토리지에 업로드됩니다. +전체 데이터셋이 매일 밤 단일 복원 가능한 아카이브로 캡처되므로 클러스터 또는 스토리지 손실에서 복구할 수 있습니다. ClickHouse는 일별 `agenteye-backup` CronJob에 의해 자동으로 백업되며, 이는 PostgreSQL과 ClickHouse를 한 번에 덤프합니다. ClickHouse는 HTTP API를 통해 읽힙니다: `agenteye.events`와 `agenteye.evaluations`가 ClickHouse 네이티브 형식으로 덤프되고(뷰와 행 정책은 서버 시작 시 재생성되므로 테이블 데이터가 완전한 그림), Postgres 덤프와 함께 단일 압축 아카이브로 번들되어 객체 스토리지에 업로드됩니다. -대상 버킷과 클라우드 자격 증명은 오버레이별로 구성됩니다. 업로드 구성 및 복원 단계는 [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)의 **백업** 섹션을 참조하세요. +대상 버킷과 클라우드 자격증명은 오버레이별로 구성됩니다. 업로드 구성 및 복원 단계는 [enterprise-docs/kubernetes-deployment.md](/ko/agenteye/kubernetes-deployment)의 **백업** 섹션을 참조하세요. --- -## Redis (선택 사항 캐시) +## Redis (선택적 캐시) -Redis는 서버와 대시보드가 사용하는 **선택 사항**인 공유 캐시 + 속도 제한 백엔드입니다. Redis를 배포하고 두 서비스 모두에 `REDIS_URL`을 설정하면: +Redis는 서버와 대시보드에서 사용하는 **선택적** 공유 캐시 + 속도 제한 백엔드입니다. Redis를 배포하고 두 서비스 모두에 `REDIS_URL`을 설정하면: - **서버**는 인증된 API 키 조회, `/events/environments` + `/evaluations/environments` 목록, `/events/latency_aggregate` 롤업(대시보드가 폴링하는 가장 무거운 쿼리), `/sessions` 목록을 캐시하고, OTP 요청 속도 제한을 Postgres `COUNT(*)`에서 Redis `INCR + EXPIRE`로 전환합니다. -- **대시보드**는 `validateSession()` 결과를 캐시하여 일반적인 페이지 로드에서 발생하는 10-20개의 인증된 API 호출이 하나의 업스트림 세션 확인을 공유합니다. 또한 대시보드 엣지에서 OTP 요청 및 검증 속도를 제한합니다. +- **대시보드**는 `validateSession()` 결과를 캐시하여 일반적인 페이지 로드에서 발생하는 10-20개의 인증된 API 호출이 모두 하나의 업스트림 세션 확인을 공유합니다. 또한 대시보드 엣지에서 OTP 요청 및 확인을 속도 제한합니다. -**Redis에 연결할 수 없으면 두 서비스 모두 자연스럽게 저하됩니다.** 모든 캐시 호출은 제한된 타임아웃 내에 `Err`를 반환하고, 호출자는 진실의 원천으로 폴백합니다(서버는 Postgres, 대시보드는 업스트림 Rust 서버). OTP 속도 제한은 서버의 Postgres `COUNT(*)` 경로로 폴백합니다(보안 속성 유지). 대시보드의 엣지 OTP 제한은 열린 상태로 실패하지만 서버 측 제한은 여전히 유효합니다. Redis 다운 시 정확성이 아닌 지연 시간이 저하됩니다. +**두 서비스 모두 Redis에 연결할 수 없는 경우 정상적으로 저하됩니다.** 모든 캐시 호출은 제한된 타임아웃 내에 `Err`를 반환하고 호출자는 신뢰 소스(서버의 경우 Postgres, 대시보드의 경우 업스트림 Rust 서버)로 폴백합니다. OTP 속도 제한은 서버의 Postgres `COUNT(*)` 경로로 폴백합니다(보안 속성은 유지됨). 대시보드의 엣지 OTP 제한은 열린 상태로 실패하지만 서버 측 제한은 여전히 유지됩니다. Redis가 다운되면 정확성이 아닌 레이턴시가 저하됩니다. ### 구성 -docker-compose 번들에는 이미 Redis 서비스가 포함되어 있으며, 서버와 대시보드에 `REDIS_URL=redis://redis:6379/0`이 연결됩니다. 외부 Redis를 사용하려면 `REDIS_URL`을 엔드포인트로 설정하고 컴포즈 파일에서 `redis` 서비스를 제거하세요. +docker-compose 번들에는 이미 Redis 서비스가 포함되어 있으며 서버와 대시보드에 `REDIS_URL=redis://redis:6379/0`이 연결되어 있습니다. 외부 Redis를 사용하려면 `REDIS_URL`을 해당 엔드포인트로 설정하고 컴포즈 파일에서 `redis` 서비스를 제거하세요. ### 메모리 + 지속성 -번들 Redis 이미지는 `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`로 실행됩니다. AOF 지속성은 컨테이너 재시작 후에도 캐시가 유지됨을 의미합니다. `everysec`는 마지막 1초의 캐시 쓰기 손실이 무해하기 때문에 올바른 내구성/성능 균형입니다. LRU 제거는 메모리 증가를 제한합니다. +번들 Redis 이미지는 `--appendonly yes --appendfsync everysec --maxmemory 256mb --maxmemory-policy allkeys-lru`로 실행됩니다. AOF 지속성은 캐시가 컨테이너 재시작 후에도 살아남도록 합니다. `everysec`은 마지막 1초의 캐시 쓰기 손실이 무해하므로 올바른 내구성/성능 균형입니다. LRU 축출은 메모리 증가를 제한합니다. ### Redis를 배포하지 않아야 할 때 -- 단일 인스턴스 개발/QA 환경. 서버의 인프로세스 캐시만으로도 복제본당 이점의 대부분을 제공합니다. Redis는 단일 인스턴스 설정에서는 필요하지 않은 크로스 복제본 공유를 추가합니다. -- 서비스 하나를 더 운영하는 비용이 지연 시간 이점보다 큰 에어갭 설치 환경. +- 단일 인스턴스 개발/QA 환경. 서버의 인프로세스 캐시만으로도 복제본별 이점의 대부분을 제공합니다. Redis는 단일 인스턴스 설정에서 필요하지 않은 복제본 간 공유를 추가합니다. +- 추가 서비스 운영 비용이 레이턴시 이점보다 큰 에어갭 설치 환경. --- ## Docker Compose (권장) -`docker-compose.yml`은 `agenteye-enterprise/releases` 저장소에서 사용할 수 있습니다. 단일 명령으로 Postgres, ClickHouse, Redis, 서버, 대시보드를 시작합니다. +`docker-compose.yml`은 `agenteye-enterprise/releases` 저장소에서 사용할 수 있습니다. 단일 명령으로 Postgres, 서버, 대시보드를 시작합니다. ```bash GITHUB_TOKEN=$AGENTEYE_TOKEN gh release download \ @@ -323,42 +322,48 @@ docker compose down -v ## 운영 설정 -환경 변수로 고정되던 일부 운영 설정은 이제 대시보드의 **`//settings`** 페이지에서 조직별로 편집할 수 있습니다. 각 조직이 독립적으로 구성합니다. 변경 사항은 재시작이나 재배포 없이 수 초 내에 적용됩니다. +환경 변수로 고정되던 일부 운영 설정은 이제 대시보드의 **`//settings`** 페이지에서 조직별로 편집할 수 있습니다. 각 org가 자체적으로 구성합니다. 변경 사항은 재시작이나 재배포 없이 수 초 내에 적용됩니다. -| 설정 | 부트스트랩 환경 변수 | 제어 대상 | +| 설정 | 부트스트랩 환경 변수 | 제어 내용 | |---|---|---| | 허용된 로그인 | `ALLOWED_EMAILS` | OTP를 받고 사용자로 추가될 수 있는 이메일(또는 `*@domain.com` 와일드카드) | -| 기본 사용자 권한 | `DEFAULT_USER_PERMISSIONS` | 관리자가 **+ new user**를 열 때 미리 선택되는 쉼표로 구분된 권한 토큰. 각 토큰은 [API 키 권한](/ko/agenteye/api-keys)에 나열된 문자열 중 하나여야 합니다. 기본값은 `standard` 프리셋: 읽기 전용 접근 및 일상적인 온콜 액션(재평가 트리거, 쿼리 실행, 인시던트 확인, 어시스턴트 사용). | -| 세션 수명 | `SESSION_TTL_SECS` | 재인증 전까지 대시보드 로그인 유효 기간. 대시보드는 매 5초마다 업스트림 세션을 재확인하므로, `//users`에서의 권한 업데이트는 재로그인 없이 다음 요청에서 해당 사용자에게 적용됩니다. | -| 일회용 코드 수명 | `OTP_TTL_SECS` | OTP/매직 링크 사용 가능 기간 | -| 알림 채널 | `ALERTS_ENABLED_CHANNELS` | 알림 디스패처가 사용할 수 있는 채널 종류의 쉼표 구분 목록: `email`, `slack`, `webhook`. 알림별 구성은 여전히 `//alerts/`에서 작성되지만, 디스패처는 이 세트를 통해 모든 아웃바운드 전달을 필터링합니다. 여기서 비활성화된 채널은 `skipped_disabled` 감사 행으로 단락됩니다. `dashboard` 채널(로컬 감사 삽입)은 항상 허용됩니다. 기본값은 세 채널 모두 활성화. | +| 기본 사용자 권한 | `DEFAULT_USER_PERMISSIONS` | 관리자가 **+ 새 사용자**를 열 때 미리 선택되는 쉼표 구분 권한 토큰. 각 토큰은 [API 키 권한](/ko/agenteye/api-keys)에 나열된 문자열 중 하나여야 합니다. 기본값은 `standard` 프리셋: 읽기 전용 접근 및 일상적인 온콜 작업(재평가 트리거, 쿼리 실행, 인시던트 확인, 어시스턴트 사용). | +| 세션 유효 기간 | `SESSION_TTL_SECS` | 재인증 전 대시보드 로그인 유효 시간. 대시보드는 5초마다 업스트림 세션을 재확인하므로 `//users`에서의 권한 업데이트는 재로그인 없이 다음 요청에서 해당 사용자에게 적용됩니다. | +| 일회용 코드 유효 기간 | `OTP_TTL_SECS` | OTP/매직 링크의 사용 가능 시간 | +| 알림 채널 | `ALERTS_ENABLED_CHANNELS` | 알림 디스패처가 사용할 수 있는 채널 종류의 쉼표 구분 목록: `email`, `slack`, `webhook`. 알림별 구성은 여전히 `//alerts/`에서 작성되지만, 디스패처는 모든 아웃바운드 전달을 이 집합을 통해 필터링합니다. 여기서 비활성화된 채널은 `skipped_disabled` 감사 행으로 단락됩니다. `dashboard` 채널(로컬 감사 삽입)은 항상 허용됩니다. 기본값은 세 가지 모두 활성화입니다. | -### 부트스트랩 동작 방식 +### 부트스트랩 작동 방식 -설정은 `org_settings`에 조직별로 저장됩니다. 첫 번째 부팅 시 서버는 일치하는 환경 변수(또는 환경 변수가 설정되지 않은 경우 적절한 기본값)에서 기본 조직의 누락된 행을 시드합니다. 이후에는 **저장된 값이 진실의 원천이 되며 환경 변수는 무시됩니다.** 이후 재시작 시 환경 변수를 변경해도 라이브 조직의 값에 영향을 주지 않으며, 추가 조직은 기본값에서 시작하여 독립적으로 구성합니다. +설정은 `org_settings`에 조직별로 저장됩니다. 첫 번째 부팅 시 서버는 일치하는 환경 변수(환경 변수가 설정되지 않은 경우 적절한 기본값)에서 기본 org의 누락된 행을 시드합니다. 이후 **저장된 값이 신뢰 소스가 되고 환경 변수는 무시됩니다**. 이후 재시작 시 환경 변수를 변경해도 라이브 org의 값에 영향을 미치지 않으며, 추가 org는 기본값에서 시작하여 자체적으로 구성합니다. -이는 다음을 의미합니다: +즉: -- 새로운 배포에서는 위에 표시된 대로 환경 변수를 설정하면 기본 조직이 첫 번째 부팅 시 읽습니다. -- 나중에 값을 변경하려면 대시보드에 로그인하여 `//settings`에서 편집하세요. 변경 사항은 모든 서버 복제본에 수 초 내에 적용됩니다. 재시작이 필요하지 않습니다. -- 시작 로그 줄에 시드된 항목과 이미 존재하는 항목이 기록되어 부트스트랩이 적용되었는지 확인할 수 있습니다: +- 새 배포의 경우 위에 표시된 대로 환경 변수를 설정하면 기본 org가 첫 번째 부팅 시 읽습니다. +- 나중에 값을 변경하려면 대시보드에 로그인하고 `//settings`에서 편집하세요. 변경 사항은 수 초 내에 모든 서버 복제본에 적용됩니다. 재시작이 필요하지 않습니다. +- 시작 로그 라인에 시드된 것과 이미 존재하는 것이 기록되므로 부트스트랩이 적용되었는지 확인할 수 있습니다: ```text INFO settings bootstrap: seeded default-org row key=allowed_sign_ins env_var=ALLOWED_EMAILS seeded_from_env=true ``` -#### 조직 간 로그인 시맨틱 +#### 조직 간 로그인 의미론 -세션과 OTP는 단일 조직이 아닌 사용자 전체에 적용되므로, 로그인 시 조직별 설정을 조정하는 두 가지 규칙이 있습니다: +세션과 OTP는 단일 org가 아닌 사용자에게 전역적이므로, 로그인 시 org별 설정을 조율하는 두 가지 규칙이 있습니다: -- **세션/OTP 수명**: 사용자가 속한 조직 중 가장 엄격한(가장 짧은) 수명이 적용됩니다. -- **허용된 로그인**: 게이트는 모든 조직의 허용 목록과 조직 멤버십을 OR로 결합합니다. 어떤 조직의 허용 목록이 이메일을 허용하거나 사용자가 이미 어떤 조직의 멤버인 경우 OTP를 요청할 수 있습니다. +- **세션/OTP 유효 기간**: 사용자가 속한 org 중 가장 엄격한(가장 짧은) 유효 기간이 적용됩니다. +- **허용된 로그인**: 게이트는 모든 org의 허용 목록과 org 멤버십을 OR로 결합합니다. 이메일이 어느 org의 허용 목록에든 허용되거나 이미 어느 org의 멤버이면 OTP를 요청할 수 있습니다. ### 권한 -`//settings` 페이지 접근은 두 가지 권한으로 제어됩니다: +`//settings` 페이지 접근은 두 가지 권한으로 제한됩니다: -- `settings:read`: 페이지 및 현재 값 보기. -- `settings:write`: 변경 사항 저장. +- `settings:read`: 페이지와 현재 값을 볼 수 있습니다. +- `settings:write`: 변경 사항을 저장할 수 있습니다. -부트스트랩 관리자(`ADMIN_EMAIL`에서 시드됨)는 다른 모든 권한과 함께 두 권한을 자동으로 받습니다. 필요에 따라 `//users`에서 다른 사 \ No newline at end of file +부트스트랩 관리자 사용자(`ADMIN_EMAIL`에서 시드됨)는 다른 모든 권한과 함께 자동으로 둘 다 부여받습니다. 필요에 따라 `//users`에서 다른 사용자에게 부여하세요. + +--- + +## Organizations (멀티테넌시) + +단일 배포가 여러 격리된 **조직**(테넌트)을 제공할 수 있습니다. 모든 데이터 행은 정확히 하나의 org에 속하며 격리는 데이터베이스 엔진에서 적용됩니다. 단일 테넌트 설치에서는 아무것도 필요하지 않습니다. 모든 데이터는 내장된 `default` org에 있습니다. (첫 \ No newline at end of file diff --git a/docs/ko/agenteye/getting-started.mdx b/docs/ko/agenteye/getting-started.mdx index 94f4c602..b74167f6 100644 --- a/docs/ko/agenteye/getting-started.mdx +++ b/docs/ko/agenteye/getting-started.mdx @@ -4,32 +4,32 @@ description: "AgentEye 시작하기 문서입니다." --- -이 가이드는 AgentEye의 전체 설정 과정을 안내합니다. 서버와 대시보드 배포, 에이전트 머신에 수집기 설치, 그리고 Python 에이전트 코드 계측까지 다룹니다. +이 가이드는 AgentEye의 전체 설정 과정을 안내합니다. 서버와 대시보드 배포, 에이전트 머신에 컬렉터 설치, Python 에이전트 코드 계측까지 단계별로 살펴봅니다. --- -## AgentEye란 무엇인가요? +## AgentEye란? -AgentEye는 **AI 에이전트를 위한 자체 호스팅 관찰 가능성 및 평가 플랫폼**입니다. 에이전트가 수행하는 모든 작업 — 실행의 각 단계 — 을 기록하고, 완료된 각 실행의 품질을 자동으로 평가합니다. 덕분에 프로덕션 환경에서 에이전트의 동작을 파악하고, 사용자보다 먼저 회귀를 발견할 수 있습니다. +AgentEye는 **AI 에이전트를 위한 자체 호스팅 방식의 관측성 및 평가 플랫폼**입니다. 에이전트가 수행하는 모든 작업을 실행 단계별로 기록하고, 완료된 각 실행의 품질을 자동으로 채점합니다. 이를 통해 프로덕션 환경에서 에이전트의 동작을 파악하고, 사용자가 문제를 경험하기 전에 회귀를 미리 감지할 수 있습니다. -데이터는 단방향으로 흐릅니다. 에이전트 코드가 **Python SDK**를 통해 **이벤트**를 내보내면 → 경량 **수집기** 데몬이 이를 일괄 처리해 **서버**로 전송하고 → 이벤트와 분석 데이터는 **ClickHouse**에 저장됩니다(조직, 사용자, API 키, 대시보드, 저장된 쿼리와 같은 운영 상태는 **Postgres**에 보관됩니다) → 모든 데이터를 **대시보드**에서 탐색할 수 있습니다. +데이터는 단방향으로 흐릅니다. 에이전트 코드가 **Python SDK**를 통해 **이벤트**를 발생시키면 → 경량 **컬렉터** 데몬이 이를 배치로 묶어 **서버**로 전송하고 → 이벤트와 분석 데이터는 **ClickHouse**에 저장됩니다(조직, 사용자, API 키, 대시보드, 저장된 쿼리 등 운영 상태는 **Postgres**에 저장) → **대시보드**에서 모든 데이터를 탐색할 수 있습니다. -제공되는 기능: +제공 기능: -- **이벤트** — 모든 에이전트 실행의 단계별 원시 기록 (도구 호출, 모델 호출, 훅, 오류). -- **세션** — 실행 단위로 집계된 이벤트로, 각 실행마다 **자동 평가** 및 점수가 부여됩니다. -- **평가** — 자체 평가자 서비스가 생성하는 품질 점수로, 수동 검토 없이 품질 저하를 감지합니다. -- **쿼리 및 대시보드** — 데이터에 대한 저장된 ClickHouse SQL을 조직 범위의 공유 대시보드로 시각화합니다. -- **알림 및 인시던트** — 임계값 규칙에 따라 알림(이메일, Slack, 웹훅, 대시보드 내)을 발송하고, 인시던트 분류를 위한 워크플로를 제공합니다. -- **CLI 및 AI 어시스턴트** — 터미널 클라이언트(`agenteye`)와 대시보드 내 어시스턴트로 자연어 질의를 지원합니다. +- **이벤트** — 모든 에이전트 실행의 단계별 원시 기록(도구 호출, 모델 호출, 훅, 오류). +- **세션** — 실행당 하나의 행으로 집계된 이벤트. 각 세션은 **자동으로 평가**되고 채점됩니다. +- **평가** — 직접 구성한 평가자 서비스가 생성한 품질 점수로, 수동 검토 없이도 품질 저하를 감지합니다. +- **쿼리 & 대시보드** — 데이터에 대한 저장된 ClickHouse SQL을 공유 가능한 조직 범위의 대시보드로 시각화합니다. +- **알림 & 인시던트** — 임계값 규칙을 기반으로 알림(이메일, Slack, 웹훅, 대시보드 내)을 발송하고, 트리아지를 위한 인시던트 워크플로우를 제공합니다. +- **CLI & AI 어시스턴트** — 터미널 클라이언트(`agenteye`)와 대시보드 내 어시스턴트를 통해 자연어로 질문할 수 있습니다. -모든 구성 요소를 자체 인프라에서 실행할 수 있습니다. 단일 Docker Compose 스택(이 가이드), 프로덕션 Kubernetes 설치, 또는 단일 코로케이션 파드로 구성할 수 있습니다. 이 가이드의 나머지 부분은 Compose 스택을 처음부터 끝까지 설정합니다. +이 모든 것을 자체 인프라에서 단일 Docker Compose 스택(이 가이드 기준), 프로덕션 Kubernetes 설치, 또는 단일 코로케이션 파드로 운영할 수 있습니다. 이 가이드에서는 Compose 스택을 처음부터 끝까지 설정합니다. --- ## 1단계: 인증 -모든 AgentEye 아티팩트는 `agenteye-enterprise` GitHub 조직에서 배포됩니다. 엔터프라이즈 개발자는 자체 GitHub PAT를 생성할 수 있습니다. 정확한 단계와 필요한 권한은 [enterprise-docs/github-token.md](/ko/agenteye/github-token)를 참고하세요. +모든 AgentEye 아티팩트는 `agenteye-enterprise` GitHub 조직에서 배포됩니다. 엔터프라이즈 개발자는 GitHub PAT를 직접 생성할 수 있습니다. 정확한 단계와 필요한 권한은 [enterprise-docs/github-token.md](/ko/agenteye/github-token)를 참고하세요. ```bash export AGENTEYE_TOKEN= @@ -42,9 +42,9 @@ echo $AGENTEYE_TOKEN | docker login ghcr.io -u x --password-stdin ## 2단계: 서버 및 대시보드 배포 -서버는 수집기로부터 이벤트를 수신하여 조회할 수 있게 만들고, 대시보드는 데이터를 탐색하는 공간입니다. 수집된 이벤트와 분석 데이터는 ClickHouse(필수 분석 저장소)에 저장되며, Postgres는 조직, 사용자, API 키, 대시보드, 저장된 쿼리와 같은 운영 상태를 보관합니다. +서버는 컬렉터로부터 이벤트를 수신하고 이를 쿼리 가능하게 만들며, 대시보드는 데이터를 탐색하는 공간입니다. 수집된 이벤트와 분석 데이터는 ClickHouse(필수 분석 저장소)에 저장되고, Postgres는 조직, 사용자, API 키, 대시보드, 저장된 쿼리 등 운영 상태를 보관합니다. -**게시된 compose 파일 다운로드:** +**공개된 Compose 파일 다운로드:** ```bash mkdir -p ./agenteye @@ -57,36 +57,30 @@ cd agenteye **시크릿 설정:** -기본 `admin` 자격 증명으로 배포되지 않도록 `.env` 파일을 생성하세요. 최소한 `ADMIN_KEY`와 `POSTGRES_PASSWORD`를 설정해야 합니다: +기본 `admin` 자격증명으로 배포되지 않도록 `.env` 파일을 생성합니다. 최소한 `ADMIN_KEY`와 `POSTGRES_PASSWORD`를 설정해야 합니다: ```bash POSTGRES_PASSWORD=your-db-password ADMIN_KEY=your-admin-secret ``` -이후 단계(예: 3단계의 `curl`)에서 직접 참조할 수 있도록 현재 셸에도 `ADMIN_KEY`를 내보내세요: - -```bash -export ADMIN_KEY=your-admin-secret -``` - **스택 시작:** ```bash docker compose up -d ``` -이 명령은 필수 ClickHouse 분석 저장소, 선택적 Redis 캐시, 서버, 대시보드를 포함한 전체 스택을 시작합니다. 서버가 시작되려면 ClickHouse가 정상 상태여야 합니다. +이 명령은 필수 ClickHouse 분석 저장소와 선택적 Redis 캐시를 포함한 전체 스택을 서버 및 대시보드와 함께 실행합니다. 서버가 시작되려면 ClickHouse가 정상 상태여야 합니다. -서버는 `http://localhost:8080`에서, 대시보드는 `http://localhost:3000`에서 수신 대기 중입니다. +이제 서버는 `http://localhost:8080`에서, 대시보드는 `http://localhost:3000`에서 수신 대기 중입니다. 프로덕션 배포(커스텀 Postgres, TLS, 리버스 프록시)는 [enterprise-docs/deployment.md](/ko/agenteye/deployment)를 참고하세요. --- -## 3단계: 수집기용 API 키 생성 +## 3단계: 컬렉터용 API 키 생성 -각 수집기는 범위가 지정된 API 키로 인증합니다. 2단계에서 설정한 `ADMIN_KEY`를 사용하여 키를 생성하세요: +각 컬렉터는 범위가 지정된 API 키로 인증합니다. 2단계에서 설정한 `ADMIN_KEY`를 사용해 키를 생성합니다: ```bash curl -s -X POST http://localhost:8080/keys \ @@ -95,13 +89,13 @@ curl -s -X POST http://localhost:8080/keys \ -d '{"name":"prod-collector","key":"your-collector-secret","permissions":["events:add"]}' ``` -`key` 값은 직접 지정하며, 4단계의 수집기 설정에서 사용됩니다. 전체 키 관리 방법은 [enterprise-docs/api-keys.md](/ko/agenteye/api-keys)를 참고하세요. +`key` 값은 직접 지정합니다. 이 값은 4단계의 컬렉터 설정에 사용됩니다. 전체 키 관리 방법은 [enterprise-docs/api-keys.md](/ko/agenteye/api-keys)를 참고하세요. --- -## 4단계: 수집기 설치 +## 4단계: 컬렉터 설치 -AI 에이전트가 실행되는 모든 머신에 수집기 데몬을 설치하세요. +AI 에이전트가 실행되는 모든 머신에 컬렉터 데몬을 설치합니다. **바이너리 다운로드 (Linux x86_64):** @@ -114,7 +108,7 @@ chmod +x agenteye-collector-linux-x86_64 sudo mv agenteye-collector-linux-x86_64 /usr/local/bin/agenteye-collector ``` -> 이 명령은 **Linux x86_64** 빌드를 다운로드합니다. macOS(Apple Silicon 또는 Intel), Linux arm64, Docker / systemd / launchd 설정의 경우 [collector-installation.md](/ko/agenteye/collector-installation)를 참고하세요. 각 플랫폼별 다운로드 링크가 나열되어 있습니다 — 위 명령은 다른 환경에서는 실행되지 않는 Linux 바이너리를 설치합니다. +> 이 명령은 **Linux x86_64** 빌드를 다운로드합니다. macOS(Apple Silicon 또는 Intel), Linux arm64, Docker/systemd/launchd 설정은 [collector-installation.md](/ko/agenteye/collector-installation)를 참고하세요. 각 플랫폼별 다운로드 방법이 나와 있습니다. 위 명령은 Linux 바이너리를 설치하므로 다른 환경에서는 실행되지 않습니다. **설정:** @@ -134,7 +128,7 @@ EOF agenteye-collector start ``` -원샷 플러시로 연결을 확인하세요(대기 중인 이벤트를 모두 처리한 후 종료됩니다): +원샷 플러시로 연결 상태를 확인합니다(대기 중인 이벤트를 모두 전송한 후 종료): ```bash agenteye-collector flush @@ -146,7 +140,7 @@ Docker, systemd, launchd 설정은 [enterprise-docs/collector-installation.md](/ ## 5단계: Python SDK 설치 -에이전트 코드를 계측할 각 머신에 GitHub Releases의 wheel 파일로 SDK를 설치하세요. +에이전트 코드를 계측할 각 머신에 GitHub Releases에서 wheel 파일을 설치합니다. ```bash VERSION=0.0.1b9 @@ -160,7 +154,7 @@ pip install agenteye-${VERSION}-py3-none-any.whl ## 6단계: 에이전트 계측 -에이전트 코드에 이벤트를 추가하세요. 최소한 `agent_start`와 `agent_end`를 내보내야 합니다: +에이전트 코드에 이벤트를 추가합니다. 최소한 `agent_start`와 `agent_end`를 발생시켜야 합니다: ```python import agenteye @@ -180,7 +174,7 @@ agenteye.event.agent_end( ) ``` -이벤트는 버퍼링되어 500ms마다 `$AGENTEYE_HOME/events/`(또는 `AGENTEYE_HOME`이 설정되지 않은 경우 `~/.agenteye/events/`)에 플러시됩니다. 수집기가 자동으로 이를 수집합니다. +이벤트는 버퍼에 쌓이다가 500ms마다 `$AGENTEYE_HOME/events/`(또는 `AGENTEYE_HOME`이 설정되지 않은 경우 `~/.agenteye/events/`)로 플러시됩니다. 컬렉터가 자동으로 이를 수집합니다. 전체 이벤트 API는 [enterprise-docs/python-sdk.md](/ko/agenteye/python-sdk)를 참고하세요. @@ -188,21 +182,21 @@ agenteye.event.agent_end( ## 7단계: 대시보드에서 이벤트 확인 -`http://your-dashboard-host:3000`을 열고 로그인하세요. AgentEye는 일회용 코드(또는 원클릭 매직 링크)를 이메일로 전송하므로 비밀번호를 관리할 필요가 없습니다. +`http://your-dashboard-host:3000`을 열고 로그인합니다. AgentEye는 일회용 코드(또는 원클릭 매직 링크)를 이메일로 발송하므로 비밀번호를 관리할 필요가 없습니다. -![AgentEye 로그인 화면 - 이메일로 일회용 코드를 전송합니다](/agenteye/images/login.png) +![단일 사용 코드를 이메일로 발송하는 AgentEye 로그인 화면](/agenteye/images/login.png) -로그인 후 **Events** 페이지에서 수집된 모든 이벤트의 실시간 추적을 확인할 수 있습니다. `session_id` 또는 `agent_id`로 필터링하여 특정 실행을 자세히 살펴볼 수 있습니다. +로그인 후 **이벤트** 페이지에서 수집된 모든 이벤트의 실시간 내역을 확인할 수 있습니다. `session_id` 또는 `agent_id`로 필터링하여 특정 실행을 상세 조회할 수 있습니다. -![이벤트 유형별로 색상 구분되며 환경, 에이전트, 세션으로 필터링 가능한 실시간 이벤트 스트림](/agenteye/images/events-stream.png) +![이벤트 유형별로 색상이 구분되고 환경, 에이전트, 세션으로 필터링 가능한 실시간 이벤트 스트림](/agenteye/images/events-stream.png) -**Sessions** 페이지는 해당 이벤트를 실행별 한 행으로 집계합니다. AgentEye가 완료된 세션을 자동으로 평가하므로 모든 실행에 점수가 부여되고, 수동 검토 없이 품질 회귀를 발견할 수 있습니다. 최신 평가 점수가 각 행에 한눈에 표시됩니다: +**세션** 페이지는 해당 이벤트들을 실행당 하나의 행으로 집계합니다. AgentEye는 완료된 세션을 자동으로 평가하므로 모든 실행이 채점되고 수동 검토 없이도 품질 회귀를 감지할 수 있습니다. 최신 평가 점수는 각 행에서 한눈에 확인할 수 있습니다: -![세션 목록 - 실행별 한 행, 상태 배지와 평가 점수 뱃지](/agenteye/images/sessions-list.png) +![상태 배지와 평가 점수 배지가 표시된 실행별 세션 목록](/agenteye/images/sessions-list.png) -세션 평가 방식 설정은 [enterprise-docs/evaluation-suite.md](/ko/agenteye/evaluation-suite)를 참고하세요. +세션 채점 방식 설정은 [enterprise-docs/evaluation-suite.md](/ko/agenteye/evaluation-suite)를 참고하세요. -세션을 클릭하면 **실행 그래프**를 열 수 있습니다. git 스타일 뷰로 에이전트, 도구, 훅, 모델 호출이 시간에 따라 어떻게 전개되었는지 보여주며, 병렬 서브 에이전트는 별도 레인에 표시되고 오른쪽 패널에 실행별 세부 정보가 제공됩니다: +세션을 클릭하면 **실행 그래프**가 열립니다. 이는 에이전트, 도구, 훅, 모델 호출이 시간에 따라 어떻게 전개되었는지 git 스타일로 보여주는 뷰로, 병렬 서브 에이전트는 각자의 레인에 표시되고 오른쪽 패널에서 실행별 분석을 확인할 수 있습니다: ![이벤트 타임라인 옆에 표시된 세션의 git 스타일 실행 그래프와 도구/모델/훅 분석 패널](/agenteye/images/session-detail.png) @@ -210,21 +204,21 @@ agenteye.event.agent_end( ## 8단계: 탐색, 시각화, 알림 -이벤트가 유입되기 시작하면 **분석** 페이지에서 원시 활동 데이터를 통찰로 변환할 수 있습니다. 에이전트 동작을 측정하고, 팀과 결과를 공유하며, 문제가 발생하는 즉시 알림을 받을 수 있습니다. 대시보드 페이지는 조직 범위로 지정되므로 주소창에 표시되는 URL에는 조직 슬러그(`//…`)가 접두사로 붙습니다. +이벤트가 흐르기 시작하면 **분석** 페이지에서 원시 활동 데이터를 인사이트로 변환할 수 있습니다. 에이전트 동작을 측정하고, 팀과 결과를 공유하며, 문제가 발생하는 즉시 알림을 받을 수 있습니다. 대시보드 페이지는 조직 범위로 적용되므로 주소 표시줄의 URL은 조직 슬러그(`//…`)로 시작합니다. -- **쿼리** (`//queries`): 이벤트와 평가에 대한 저장된 재사용 가능한 쿼리 라이브러리(기본 제공 프리셋 및 사용자 정의)에서 시작하세요… +- **쿼리** (`//queries`): 이벤트와 평가 데이터에 대한 저장된 재사용 가능한 쿼리 라이브러리(기본 프리셋 및 커스텀 쿼리)에서 시작하세요… -![저장된 쿼리 라이브러리: 기본 제공 프리셋과 사용자 정의 쿼리가 그리드 형식으로 표시됩니다](/agenteye/images/queries.png) +![재사용 가능한 쿼리 그리드로 구성된 저장된 쿼리 라이브러리(기본 프리셋과 커스텀 쿼리 포함)](/agenteye/images/queries.png) - …그런 다음 SQL 작성기에서 열어 수정하고 실시간 결과와 함께 실행하세요: + …그런 다음 SQL 작성기에서 쿼리를 열어 수정하고 실시간 결과와 함께 실행합니다: -![저장된 쿼리를 실행하는 SQL 쿼리 작성기 - 스키마 사이드바와 실시간 결과 그리드](/agenteye/images/query-lab.png) +![스키마 사이드바와 실시간 결과 그리드가 있는 SQL 쿼리 작성기에서 저장된 쿼리 실행 화면](/agenteye/images/query-lab.png) -- **대시보드** (`//dashboards`): 쿼리를 선 그래프, 막대 그래프, 영역 그래프, 파이 차트 타일로 고정하여 조직 전체가 공유하는 대시보드를 만드세요. +- **대시보드** (`//dashboards`): 쿼리를 라인, 바, 에어리어, 파이 타일로 고정하여 조직 전체가 공유하는 대시보드를 구성합니다. -![저장된 쿼리로 구성된 대시보드: 시간당 이벤트 선 그래프, 오류 유형별 막대 그래프, 지연 시간 영역 차트, 모델별 토큰 수](/agenteye/images/dashboard-fleet.png) +![저장된 쿼리로 구성된 대시보드: 시간당 이벤트 라인 차트, 유형별 오류 바 차트, 지연 시간 에어리어 차트, 모델별 토큰 차트](/agenteye/images/dashboard-fleet.png) -- **알림** (`//alerts`): 임계값 조건을 이메일, Slack, 웹훅, 또는 대시보드 내 알림 규칙으로 전환하세요. [enterprise-docs/alerts.md](/ko/agenteye/alerts)를 참고하세요. +- **알림** (`//alerts`): 임계값을 이메일, Slack, 웹훅, 대시보드 내 알림으로 통보하는 규칙으로 전환합니다. [enterprise-docs/alerts.md](/ko/agenteye/alerts)를 참고하세요. --- diff --git a/docs/ko/agenteye/managed-deployment.mdx b/docs/ko/agenteye/managed-deployment.mdx index a08edbbe..bb447f4b 100644 --- a/docs/ko/agenteye/managed-deployment.mdx +++ b/docs/ko/agenteye/managed-deployment.mdx @@ -1,155 +1,156 @@ --- -title: "Kubernetes 클러스터에서의 Managed Deployment" -description: "Kubernetes 클러스터에서의 AgentEye Managed Deployment 문서입니다." +title: "Kubernetes 클러스터에서의 관리형 배포" +description: "Kubernetes 클러스터에서의 AgentEye 관리형 배포 문서입니다." --- -AgentEye는 AI 및 LLM 에이전트를 위한 셀프 호스팅 관찰 가능성(observability) 및 평가 플랫폼입니다. 에이전트 세션, 도구 호출, 모델 요청, 오류를 캡처하여 검색 가능한 분석 및 평가로 변환하고, 선택적 읽기 전용 AI 어시스턴트가 포함된 대시보드에 결과를 표시합니다. -Managed Deployment 모델에서는 전용 Kubernetes 클러스터를 제공하면 Exosphere가 그 안에서 전체 플랫폼을 운영합니다. 모든 컴포넌트의 배포, 구성, 운영, 백업, 업그레이드를 Exosphere가 대신 처리합니다. 팀은 데이터베이스, 인증서, 업그레이드를 직접 관리하지 않고도 플랫폼의 가치(에이전트 가시성, 분석, 평가, 선택적 어시스턴트)를 누릴 수 있습니다. 모든 데이터는 여러분의 클라우드 계정 내에 유지됩니다. +AgentEye는 AI 및 LLM 에이전트를 위한 자체 호스팅 형태의 관측성 및 평가 플랫폼입니다. 에이전트 세션, 도구 호출, 모델 요청, 오류를 수집하여 검색 가능한 분석 및 평가 데이터로 변환하고, 선택적 읽기 전용 AI 어시스턴트를 포함한 대시보드에 결과를 표시합니다. + +관리형 배포 모델에서는 전용 Kubernetes 클러스터를 제공하면 Exosphere가 모든 컴포넌트의 배포, 구성, 운영, 백업, 업그레이드를 대신 처리하며 플랫폼 전체를 그 안에서 운영합니다. 팀은 데이터베이스, 인증서, 업그레이드 등을 직접 관리하지 않고도 플랫폼의 핵심 가치(에이전트 가시성, 분석, 평가, 선택적 어시스턴트)를 누릴 수 있습니다. 모든 데이터는 여러분의 클라우드 계정 안에 머물러 있습니다. --- ## 사전 요구 사항 -- 컨테이너 이미지 가져오기 및 아티팩트 다운로드를 위한 **GitHub PAT** ([GitHub Token 설정](/ko/agenteye/github-token) 참조) -- **전용 Kubernetes 클러스터** (아래 요구 사항 참조) +- 컨테이너 이미지 풀 및 아티팩트 다운로드를 위한 **GitHub PAT** ([enterprise-docs/github-token.md](/ko/agenteye/github-token) 참고) +- **전용 Kubernetes 클러스터** (아래 요구 사항 참고) - 데이터베이스 백업을 위한 **스토리지 버킷** -- **네트워크 연결**: 클러스터 로드 밸런서로의 인바운드 포트 443 +- **네트워크 연결**: 클러스터 로드 밸런서로 인바운드 443 포트 개방 --- ## 1단계: 전용 Kubernetes 클러스터 프로비저닝 -AgentEye 전용 Kubernetes 클러스터를 생성합니다. 다른 워크로드와 공유하지 않아야 하며, 전체 플랫폼(애플리케이션 서비스, 데이터베이스, 분석, 캐싱)이 기존 인프라에 영향을 주지 않고 격리된 환경에서 실행됩니다. +AgentEye 전용 Kubernetes 클러스터를 생성합니다. 다른 워크로드와 공유하지 않아야 플랫폼 전체(애플리케이션 서비스, 데이터베이스, 분석, 캐싱)가 격리된 환경에서 실행되어 기존 인프라에 영향을 주지 않습니다. -| 요구 사항 | 세부 사항 | +| 요구 사항 | 세부 내용 | |---|---| -| **배포판** | EKS, GKE, AKS 또는 자체 관리형 등 표준 규격을 준수하는 Kubernetes | +| **배포판** | EKS, GKE, AKS 또는 자체 관리형 등 표준 Kubernetes | | **버전** | 1.27 이상 | -| **노드 풀** | 최소 사양: **노드 3개, 각 4 vCPU / 8 GB RAM** (표준 범용 인스턴스) | +| **노드 풀** | 최소: **노드 3개, 각 4 vCPU / 8 GB RAM** (범용 표준 인스턴스) | | **스토리지** | 블록 볼륨을 프로비저닝하는 기본 StorageClass (예: AWS의 `gp3`, GCP의 `pd-ssd`) | -| **로드 밸런서** | 클러스터가 클라우드 LoadBalancer 서비스를 프로비저닝할 수 있어야 함 (EKS, GKE, AKS 기본 지원) | +| **로드 밸런서** | 클라우드 LoadBalancer 서비스 프로비저닝 가능해야 함 (EKS, GKE, AKS 기본 지원) | -> Exosphere는 클러스터 내부의 나머지 모든 것을 설치하고 관리합니다: 인그레스 컨트롤러, TLS 인증서, 데이터베이스, 캐싱, 모니터링, 모든 애플리케이션 배포. +> Exosphere는 클러스터 내부의 모든 것을 설치하고 관리합니다: 인그레스 컨트롤러, TLS 인증서, 데이터베이스, 캐싱, 모니터링, 모든 애플리케이션 배포. --- ## 2단계: AgentEye 팀에 접근 권한 부여 -Exosphere는 네임스페이스, 커스텀 리소스 정의, 인그레스 컨트롤러, 스토리지 프로비저너를 관리하기 위해 cluster-admin 권한(또는 동등한 광범위한 RBAC)이 필요합니다. +Exosphere는 네임스페이스, 커스텀 리소스 정의, 인그레스 컨트롤러, 스토리지 프로비저너를 관리하기 위해 cluster-admin 권한(또는 이에 준하는 광범위한 RBAC)이 필요합니다. -| 요구 사항 | 세부 사항 | +| 요구 사항 | 세부 내용 | |---|---| -| **접근 방법** | IAM 역할 (EKS/GKE에 권장), kubeconfig, 또는 SSO 기반 접근 | -| **VPN / 배스천** | Kubernetes API 서버가 비공개인 경우 Exosphere 운영 팀을 위한 VPN 자격 증명 또는 배스천 접근 제공 | +| **접근 방식** | IAM 역할 (EKS/GKE에 권장), kubeconfig, 또는 SSO 기반 접근 | +| **VPN / 배스천** | Kubernetes API 서버가 프라이빗 환경이라면 Exosphere 운영팀에 VPN 자격 증명 또는 배스천 접근 정보 제공 | --- ## 3단계: 네트워크 연결 구성 -네트워크 팀에서 클러스터 로드 밸런서의 **포트 443**으로의 인바운드 트래픽을 허용해야 합니다. 배포는 두 개의 별도 로드 밸런서를 운영합니다: 하나는 이벤트 수집(mTLS 보호)용, 다른 하나는 대시보드용입니다. +네트워크 팀에서 클러스터 로드 밸런서로의 **443 포트** 인바운드 트래픽을 허용해야 합니다. 배포는 두 개의 별도 로드 밸런서를 사용합니다: 하나는 이벤트 수집용(mTLS 보호), 다른 하나는 대시보드용입니다. | 트래픽 | 출발지 | 목적지 | 보안 | |---|---|---|---| -| **이벤트 수집** | 클러스터의 Collector 파드 | Ingest LoadBalancer, 포트 443 | mTLS (클라이언트 인증서) + API 키 | -| **대시보드** | 개발자 브라우저 | Dashboard LoadBalancer, 포트 443 | 도메인의 HTTPS, 패스워드리스 이메일 OTP 로그인 | +| **이벤트 수집** | 클러스터 내 수집기 파드 | 수집 LoadBalancer, 443 포트 | mTLS(클라이언트 인증서) + API 키 | +| **대시보드** | 개발자 브라우저 | 대시보드 LoadBalancer, 443 포트 | 도메인에 HTTPS, 비밀번호 없는 이메일 OTP 로그인 | -수집 엔드포인트는 상호 TLS로 보호됩니다. Collector는 모든 요청 시 유효한 클라이언트 인증서 **및** 유효한 API 키를 함께 제시해야 합니다. 대시보드는 자체 로드 밸런서와 호스트네임에서 실행되며, 허용 목록에 등록된 이메일 주소/도메인만 로그인이 가능합니다. +수집 엔드포인트는 상호 TLS로 보호되며, 수집기는 모든 요청에 유효한 클라이언트 인증서와 유효한 API 키를 **모두** 제시해야 합니다. 대시보드는 자체 로드 밸런서와 호스트명으로 운영되며, 허용 목록에 등록된 이메일 주소/도메인으로 로그인이 제한됩니다. -**DNS 레코드 (최초 1회):** 관리하는 도메인 하위에 두 개의 CNAME 레코드를 생성합니다 — 하나는 수집 엔드포인트용, 하나는 대시보드용 (예: `agenteye.your-company.example`) — Exosphere가 제공하는 로드 밸런서 호스트네임을 가리킵니다. 이후 Exosphere가 두 호스트네임에 대해 공개적으로 신뢰받는 TLS 인증서를 자동으로 프로비저닝하며 갱신도 포함됩니다. +**DNS 레코드 (최초 1회):** 관리하는 도메인 아래에 CNAME 레코드 두 개를 생성합니다. 하나는 수집 엔드포인트용, 다른 하나는 대시보드용(예: `agenteye.your-company.example`)으로, Exosphere가 제공하는 로드 밸런서 호스트명을 가리키면 됩니다. Exosphere가 두 호스트명에 대해 갱신을 포함한 공개 신뢰 TLS 인증서를 자동으로 프로비저닝합니다. -> **포트 80 참고:** 자동 인증서 발급 및 갱신은 각 로드 밸런서의 포트 80을 통한 HTTP로 유효성을 검사합니다. 보안 정책상 대시보드 로드 밸런서를 회사 IP 범위로 제한해야 하는 경우 Exosphere에 먼저 알려주세요 — DNS 기반 인증서 검증 방식으로 전환하여 (고객 측에서 DNS 레코드 하나 추가) 제한된 환경에서도 갱신이 계속 작동하도록 합니다. +> **80 포트 참고:** 자동 인증서 발급 및 갱신은 각 로드 밸런서의 80 포트 HTTP를 통해 검증됩니다. 보안 정책상 대시보드 로드 밸런서를 사내 IP 범위로 제한해야 하는 경우 Exosphere에 먼저 알려 주세요. DNS 기반 인증서 검증 방식(여러분 측에 DNS 레코드 하나 추가)으로 전환하여 제한 환경에서도 갱신이 계속 작동하도록 합니다. -> **아웃바운드:** 클러스터 노드는 `ghcr.io`에서 컨테이너 이미지를 가져오기 위해 인터넷 접근이 필요합니다. 아웃바운드 트래픽을 제한하는 네트워크 환경이라면 `ghcr.io`를 허용 목록에 추가하거나 내부 레지스트리로 이미지를 미러링하세요. +> **아웃바운드:** 클러스터 노드는 `ghcr.io`에서 컨테이너 이미지를 받기 위해 인터넷 접근이 필요합니다. 아웃바운드 트래픽을 제한하는 네트워크 환경이라면 `ghcr.io`를 허용 목록에 추가하거나 내부 레지스트리에 이미지를 미러링하세요. --- ## 4단계: 백업 스토리지 버킷 제공 -데이터베이스 백업은 고객이 소유한 클라우드 스토리지 버킷에 저장됩니다. +데이터베이스 백업은 여러분이 소유한 클라우드 스토리지 버킷에 저장됩니다. -| 요구 사항 | 세부 사항 | +| 요구 사항 | 세부 내용 | |---|---| | **서비스** | S3 (AWS), GCS (GCP), 또는 Azure Blob Storage | -| **접근 권한** | IAM 역할(IRSA on EKS, Workload Identity on GKE)을 통해 클러스터 노드에 쓰기 권한 부여 또는 자격 증명 제공 | -| **보존 기간** | 버킷의 수명 주기 정책(보존 기간, 아카이브 규칙)은 고객이 직접 제어합니다. Exosphere는 백업을 기록하고, 보존 기간은 고객이 결정합니다 | +| **접근** | IRSA (EKS) 또는 Workload Identity (GKE)를 통한 IAM 역할로 클러스터 노드에 쓰기 권한 부여, 또는 자격 증명 직접 제공 | +| **보존 기간** | 버킷의 수명 주기 정책(보존 기간, 아카이브 규칙)은 여러분이 직접 제어합니다. Exosphere는 백업을 기록하며, 보존 기간은 여러분이 결정합니다 | -하루에 한 번 PostgreSQL(관계형 상태)과 ClickHouse(이벤트 및 평가) 모두를 하나의 압축 아카이브로 덤프하여 버킷에 업로드합니다. 업그레이드 전에도 백업이 실행됩니다. +매일 1회 백업이 실행되어 PostgreSQL(관계형 상태)과 ClickHouse(이벤트 및 평가)를 하나의 압축 아카이브로 덤프하여 버킷에 업로드합니다. 백업은 모든 업그레이드 직전에도 실행됩니다. --- ## 5단계: 담당자 지정 -클러스터 수준 문제(노드 상태, 클라우드 계정 한도, 네트워크 변경)에 대응할 담당자 1인 또는 Slack/Teams 채널을 지정해 주세요. 일상적인 운영에서는 이 담당자의 개입이 필요하지 않습니다. +클러스터 수준 문제(노드 상태, 클라우드 계정 한도, 네트워크 변경)에 대응할 담당자 1명 또는 Slack/Teams 채널을 지정해 주세요. 일상적인 운영에서는 해당 담당자가 관여할 필요가 없습니다. --- -## 배포 컴포넌트 +## 배포되는 컴포넌트 Exosphere가 클러스터 접근 권한을 확보하면 다음 컴포넌트들이 배포되고 관리됩니다. | 컴포넌트 | 역할 | |---|---| -| **AgentEye Server** | Collector로부터 이벤트를 수신하고, 분석을 실행하며, 대시보드에 데이터를 제공하는 HTTP API | -| **대시보드** | 에이전트 세션, 도구 호출, 모델 요청, 오류를 조회하는 웹 인터페이스; 선택적 읽기 전용 AI 어시스턴트 호스팅 | +| **AgentEye 서버** | 수집기로부터 이벤트를 받아 분석을 실행하고 대시보드에 데이터를 제공하는 HTTP API | +| **대시보드** | 에이전트 세션, 도구 호출, 모델 요청, 오류를 확인하는 웹 인터페이스; 선택적 읽기 전용 AI 어시스턴트 포함 | | **ClickHouse** | 수집된 이벤트, 분석, 평가를 위한 필수 정규 스토어 | | **PostgreSQL** | 조직, API 키, 사용자, 대시보드, 저장된 쿼리를 위한 관계형 스토어 | -| **Redis** | 선택적 공유 캐시 및 속도 제한 백엔드; 사용 불가 시 플랫폼이 우아하게 성능 저하됨 | -| **AI 어시스턴트 (선택)** | 내부 읽기 전용 어시스턴트 컨테이너; LLM 엔드포인트가 구성될 때까지 비활성 상태 유지 | -| **인그레스 컨트롤러** | 두 개의 로드 밸런서 (mTLS 보호 수집용 및 대시보드용): 공개적으로 신뢰받는 자동 갱신 인증서로 TLS를 종료하고 수집 엔드포인트에 mTLS 적용 | +| **Redis** | 선택적 공유 캐시 및 속도 제한 백엔드; 사용 불가 시 플랫폼이 점진적으로 성능을 낮춰 계속 동작 | +| **AI 어시스턴트 (선택)** | 내부 읽기 전용 어시스턴트 컨테이너; LLM 엔드포인트가 구성될 때까지 비활성화 상태 유지 | +| **인그레스 컨트롤러** | 두 개의 로드 밸런서(mTLS 보호 수집용, 대시보드용)로 TLS를 종료하고 공개 신뢰 자동 갱신 인증서 사용, 수집 엔드포인트에 mTLS 적용 | | **cert-manager** | TLS 인증서 프로비저닝 및 mTLS 클라이언트 인증서 발급 자동화 | -| **인증서 모니터링** | 예약 작업이 인증서 만료를 확인하고 갱신 시점이 다가오면 알림 전송 (예: Slack) | +| **인증서 모니터링** | 주기적으로 인증서 만료를 확인하고 갱신 시점이 가까워지면 알림(예: Slack) 발송 | -Managed 제공에는 에이전트 활동을 평가 기준에 따라 점수화하는 플랫폼의 평가 파이프라인 운영도 포함됩니다. 이 기능들이 제공하는 내용은 [어시스턴트](/ko/agenteye/assistant) 및 [평가 스위트](/ko/agenteye/evaluation-suite)를 참조하세요. +관리형 서비스는 평가 기준에 따라 에이전트 활동을 채점하는 플랫폼의 평가 파이프라인도 운영합니다. 해당 기능에 대한 자세한 내용은 [enterprise-docs/assistant.md](/ko/agenteye/assistant) 및 [enterprise-docs/evaluation-suite.md](/ko/agenteye/evaluation-suite)를 참고하세요. --- -## 제공 항목 +## 제공 내용 -배포 완료 후 다음 항목을 받게 됩니다. +배포가 완료되면 다음 항목이 제공됩니다. -| 항목 | 세부 사항 | +| 항목 | 세부 내용 | |---|---| -| **대시보드 URL** | 고객 도메인 하위의 호스트네임 (예: `https://agenteye.your-company.example`), 공개적으로 신뢰받는 자동 갱신 TLS 인증서로 제공. 제공된 로드 밸런서 호스트네임으로 CNAME 하나를 생성하면 되며, 로그인은 패스워드리스 이메일 OTP 방식 | -| **Collector 엔드포인트** | 수집 호스트네임의 `/events` 경로 (예: `https://ingest.your-company.example/events`), mTLS 보호 | -| **클라이언트 인증서 번들** | 클러스터별: 클라이언트 인증서, 개인 키, CA 인증서가 Kubernetes Secret 매니페스트로 전달됨. 클러스터당 한 번만 적용 | -| **GitHub PAT** | Collector 바이너리 및 Python SDK 패키지 다운로드용 | -| **Collector API 키** | `events:add` 권한을 가진 범위 한정 키, Collector 배포당 하나 | -| **설치 가이드** | Collector 및 Python SDK에 대한 단계별 문서 | +| **대시보드 URL** | 여러분의 도메인 아래 호스트명(예: `https://agenteye.your-company.example`), 공개 신뢰 자동 갱신 TLS 인증서 적용. 제공된 로드 밸런서 호스트명으로 CNAME 하나 생성; 비밀번호 없는 이메일 OTP 로그인 | +| **수집기 엔드포인트** | 수집 호스트명의 `/events` 경로(예: `https://ingest.your-company.example/events`), mTLS 보호 | +| **클라이언트 인증서 번들** | 클러스터별 제공: 클라이언트 인증서, 개인 키, CA 인증서가 Kubernetes Secret 매니페스트로 전달됨. 클러스터당 1회 적용 | +| **GitHub PAT** | 수집기 바이너리 및 Python SDK 패키지 다운로드용 | +| **수집기 API 키** | `events:add` 권한이 부여된 범위 지정 키, 수집기 배포당 1개 | +| **설치 가이드** | 수집기 및 Python SDK에 대한 단계별 문서 | --- -## 설정 이후 할 일 +## 설정 이후 수행 사항 -이후 지속적인 작업은 AgentEye 클러스터가 아닌 고객의 에이전트 머신에서만 이루어집니다. +이후의 지속적인 작업은 AgentEye 클러스터가 아닌 여러분의 에이전트 머신에서만 이루어집니다. -1. AI 에이전트를 실행하는 각 Kubernetes 클러스터에 **Collector를 설치**합니다: 클라이언트 인증서를 마운트하고 엔드포인트 URL 및 API 키를 설정합니다. [Collector 설치](/ko/agenteye/collector-installation)를 참조하세요. -2. 에이전트 코드에 **Python SDK를 통합**합니다. [Python SDK](/ko/agenteye/python-sdk)를 참조하세요. +1. AI 에이전트가 실행되는 각 Kubernetes 클러스터에 **수집기를 설치합니다**: 클라이언트 인증서를 마운트하고 엔드포인트 URL과 API 키를 구성합니다. [enterprise-docs/collector-installation.md](/ko/agenteye/collector-installation) 참고. +2. 에이전트 코드에 **Python SDK를 연동합니다**. [enterprise-docs/python-sdk.md](/ko/agenteye/python-sdk) 참고. 3. 브라우저에서 **대시보드를 열어** 에이전트 활동을 확인합니다. -클러스터 운영, 데이터베이스 관리, 인증서 갱신, 업그레이드 — 모두 필요 없습니다. +클러스터 운영, 데이터베이스 관리, 인증서 갱신, 업그레이드는 모두 필요하지 않습니다. --- ## 보안 -- **데이터는 클라우드 계정 내에 유지됩니다.** 클러스터, 스토리지, 데이터베이스 모두 고객 환경에서 실행됩니다. 데이터가 경계 밖으로 나가지 않습니다. -- **접근 권한은 고객이 제어합니다.** 클러스터는 고객 계정에 있습니다. Exosphere의 접근을 언제든지 감사, 모니터링, 철회할 수 있습니다. 모든 작업은 클라우드 감사 로그(CloudTrail, GCP Audit Logs 등)를 통해 기록됩니다. -- **이벤트 수집에 mTLS 적용.** 모든 Collector 요청은 유효한 클라이언트 인증서와 API 키를 모두 필요로 합니다. 키가 유출되어도 인증서 없이는 무용지물이며, 인증서를 탈취해도 유효한 키 없이는 사용할 수 없습니다. -- **대시보드 접근 제어.** 대시보드는 이벤트 수집과 분리된 자체 로드 밸런서에서 실행되며, 로그인은 허용 목록에 등록된 이메일 주소/도메인으로 제한된 패스워드리스 이메일 OTP 방식입니다. 로드 밸런서의 IP 소스 범위 허용 목록은 요청 시 제공됩니다. 자동 인증서 갱신이 로드 밸런서에 도달해야 하므로 Exosphere는 제한과 함께 DNS 기반 인증서 검증으로 전환하여 제한 환경에서도 갱신이 계속 작동하도록 합니다. -- **클러스터별 인증서.** 각 클러스터는 고유한 클라이언트 인증서를 받습니다. 한 클러스터가 침해되더라도 해당 인증서만 독립적으로 폐기되며 다른 클러스터에는 영향이 없습니다. +- **데이터는 여러분의 클라우드 계정에 머뭅니다.** 클러스터, 스토리지, 데이터베이스 모두 여러분의 환경에서 실행됩니다. 어떠한 데이터도 경계 밖으로 나가지 않습니다. +- **접근 제어는 여러분이 합니다.** 클러스터는 여러분의 계정에 있습니다. Exosphere의 접근 권한을 언제든지 감사, 모니터링, 취소할 수 있습니다. 모든 작업은 클라우드 감사 로그(CloudTrail, GCP Audit Logs 등)에 기록됩니다. +- **이벤트 수집에 mTLS 적용.** 모든 수집기 요청은 유효한 클라이언트 인증서와 API 키를 모두 요구합니다. 키가 유출되어도 인증서 없이는 무용지물이며, 인증서가 탈취되어도 유효한 키 없이는 사용할 수 없습니다. +- **대시보드 접근 제어.** 대시보드는 이벤트 수집과 분리된 자체 로드 밸런서에서 실행되며, 로그인은 허용 목록에 등록된 이메일 주소/도메인으로 제한된 비밀번호 없는 이메일 OTP 방식입니다. 요청 시 로드 밸런서에 IP 소스 범위 허용 목록을 적용할 수 있으며, 자동 인증서 갱신이 로드 밸런서에 도달해야 하므로 Exosphere는 제한과 함께 DNS 기반 인증서 검증을 사용하여 갱신이 계속 작동하도록 합니다. +- **클러스터별 인증서.** 각 클러스터는 고유한 클라이언트 인증서를 받습니다. 특정 클러스터가 침해당하더라도 해당 인증서만 독립적으로 취소되며 다른 클러스터에는 영향을 주지 않습니다. --- ## 배포 일정 -| 단계 | 소요 시간 | 고객 참여 | +| 단계 | 기간 | 고객 참여 사항 | |---|---|---| | **클러스터 프로비저닝** | 1~2일 | 클러스터 프로비저닝 및 Exosphere 접근 권한 부여 | | **플랫폼 설정** | 1일 | 없음; Exosphere가 모든 인프라 컴포넌트 설치 | | **애플리케이션 배포** | 1일 | 없음; Exosphere가 서버, 대시보드 배포 및 API 키 생성 | -| **Collector 롤아웃** | 1~3일 | 클러스터에 Collector 설치 (Exosphere 가이드 지원) | -| **프로덕션 번인** | 1주일 | 없음; Exosphere가 모니터링 및 튜닝 | +| **수집기 롤아웃** | 1~3일 | 클러스터에 수집기 설치 (Exosphere의 안내 포함) | +| **프로덕션 안정화** | 1주 | 없음; Exosphere가 모니터링 및 튜닝 | 킥오프부터 프로덕션 준비 완료까지 일반적으로 **약 2주** 소요됩니다. @@ -157,14 +158,14 @@ Managed 제공에는 에이전트 활동을 평가 기준에 따라 점수화하 ## 지원 -문의 사항이나 이슈가 있으면 `support@exosphere.host`로 Exosphere에 연락하세요. +문의 사항이나 문제가 있으시면 `support@exosphere.host`로 Exosphere에 연락하세요. --- ## 다음 단계 -- [시작하기](/ko/agenteye/getting-started): 엔드투엔드 안내 -- [Collector 설치](/ko/agenteye/collector-installation): Collector 설치 및 구성 +- [시작하기](/ko/agenteye/getting-started): 처음부터 끝까지 전체 안내 +- [수집기 설치](/ko/agenteye/collector-installation): 수집기 설치 및 구성 - [Python SDK](/ko/agenteye/python-sdk): 에이전트 코드 계측 -- [API 키](/ko/agenteye/api-keys): 접근 및 권한 관리 -- [트러블슈팅](/ko/agenteye/troubleshooting): 일반적인 문제 및 해결 방법 \ No newline at end of file +- [API 키](/ko/agenteye/api-keys): 접근 권한 및 퍼미션 관리 +- [문제 해결](/ko/agenteye/troubleshooting): 일반적인 문제 및 해결 방법 \ No newline at end of file From 4ecd054eb84009e6f1e83dc63d818bd98bcbb41f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 15 Jul 2026 06:53:43 +0000 Subject: [PATCH 5/8] docs: update translations for changed English sources --- docs/ar/built-in-policies.mdx | 321 ++++++++-------- docs/ar/cli/audit.mdx | 69 ++-- docs/ar/configuration.mdx | 126 ++++--- docs/ar/dashboard.mdx | 89 ++--- docs/ar/getting-started.mdx | 83 +++-- docs/ar/introduction.mdx | 30 +- docs/built-in-policies.mdx | 9 +- docs/cli/audit.mdx | 2 +- docs/configuration.mdx | 22 +- docs/dashboard.mdx | 16 +- docs/de/built-in-policies.mdx | 174 ++++----- docs/de/cli/audit.mdx | 68 ++-- docs/de/configuration.mdx | 110 +++--- docs/de/dashboard.mdx | 78 ++-- docs/de/getting-started.mdx | 46 +-- docs/de/introduction.mdx | 22 +- docs/docs.json | 4 +- docs/es/built-in-policies.mdx | 247 +++++++------ docs/es/cli/audit.mdx | 65 ++-- docs/es/configuration.mdx | 104 +++--- docs/es/dashboard.mdx | 62 ++-- docs/es/getting-started.mdx | 52 +-- docs/es/introduction.mdx | 14 +- docs/fr/built-in-policies.mdx | 224 ++++++----- docs/fr/cli/audit.mdx | 72 ++-- docs/fr/configuration.mdx | 92 ++--- docs/fr/dashboard.mdx | 66 ++-- docs/fr/getting-started.mdx | 50 +-- docs/fr/introduction.mdx | 14 +- docs/getting-started.mdx | 10 +- docs/he/built-in-policies.mdx | 315 ++++++++-------- docs/he/cli/audit.mdx | 83 ++--- docs/he/configuration.mdx | 144 ++++---- docs/he/dashboard.mdx | 114 +++--- docs/he/getting-started.mdx | 96 ++--- docs/he/introduction.mdx | 32 +- docs/hi/built-in-policies.mdx | 295 +++++++-------- docs/hi/cli/audit.mdx | 71 ++-- docs/hi/configuration.mdx | 127 ++++--- docs/hi/dashboard.mdx | 94 ++--- docs/hi/getting-started.mdx | 70 ++-- docs/hi/introduction.mdx | 21 +- docs/i18n/README.ar.md | 130 ++++--- docs/i18n/README.de.md | 126 ++++--- docs/i18n/README.es.md | 108 +++--- docs/i18n/README.fr.md | 105 ++++-- docs/i18n/README.he.md | 137 ++++--- docs/i18n/README.hi.md | 118 +++--- docs/i18n/README.it.md | 127 ++++--- docs/i18n/README.ja.md | 107 ++++-- docs/i18n/README.ko.md | 116 +++--- docs/i18n/README.pt-br.md | 109 ++++-- docs/i18n/README.ru.md | 112 +++--- docs/i18n/README.tr.md | 137 ++++--- docs/i18n/README.vi.md | 123 ++++--- docs/i18n/README.zh.md | 112 +++--- docs/introduction.mdx | 2 +- docs/it/built-in-policies.mdx | 348 +++++++++--------- docs/it/cli/audit.mdx | 72 ++-- docs/it/configuration.mdx | 134 +++---- docs/it/dashboard.mdx | 76 ++-- docs/it/getting-started.mdx | 65 ++-- docs/it/introduction.mdx | 30 +- docs/ja/built-in-policies.mdx | 213 ++++++----- docs/ja/cli/audit.mdx | 72 ++-- docs/ja/configuration.mdx | 120 +++--- docs/ja/dashboard.mdx | 84 ++--- docs/ja/getting-started.mdx | 56 +-- docs/ja/introduction.mdx | 22 +- docs/ko/built-in-policies.mdx | 305 ++++++++------- docs/ko/cli/audit.mdx | 69 ++-- docs/ko/configuration.mdx | 112 +++--- docs/ko/dashboard.mdx | 82 ++--- docs/ko/getting-started.mdx | 48 +-- docs/ko/introduction.mdx | 18 +- docs/pt-br/built-in-policies.mdx | 186 +++++----- docs/pt-br/cli/audit.mdx | 73 ++-- docs/pt-br/configuration.mdx | 90 ++--- docs/pt-br/dashboard.mdx | 58 +-- docs/pt-br/getting-started.mdx | 44 ++- docs/pt-br/introduction.mdx | 14 +- docs/ru/built-in-policies.mdx | 301 ++++++++------- docs/ru/cli/audit.mdx | 87 ++--- docs/ru/configuration.mdx | 126 ++++--- docs/ru/dashboard.mdx | 90 ++--- docs/ru/getting-started.mdx | 76 ++-- docs/ru/introduction.mdx | 24 +- .../config/vocabularies/Mintlify/accept.txt | 1 - docs/tr/built-in-policies.mdx | 275 +++++++------- docs/tr/cli/audit.mdx | 68 ++-- docs/tr/configuration.mdx | 138 +++---- docs/tr/dashboard.mdx | 92 ++--- docs/tr/getting-started.mdx | 68 ++-- docs/tr/introduction.mdx | 24 +- docs/vi/built-in-policies.mdx | 225 ++++++----- docs/vi/cli/audit.mdx | 74 ++-- docs/vi/configuration.mdx | 126 ++++--- docs/vi/dashboard.mdx | 73 ++-- docs/vi/getting-started.mdx | 80 ++-- docs/vi/introduction.mdx | 24 +- docs/zh/built-in-policies.mdx | 321 ++++++++-------- docs/zh/cli/audit.mdx | 66 ++-- docs/zh/configuration.mdx | 114 +++--- docs/zh/dashboard.mdx | 70 ++-- docs/zh/getting-started.mdx | 74 ++-- docs/zh/introduction.mdx | 24 +- 106 files changed, 5521 insertions(+), 4983 deletions(-) diff --git a/docs/ar/built-in-policies.mdx b/docs/ar/built-in-policies.mdx index 1c508863..ffea25a3 100644 --- a/docs/ar/built-in-policies.mdx +++ b/docs/ar/built-in-policies.mdx @@ -1,10 +1,10 @@ --- title: السياسات المدمجة -description: "39 سياسة مدمجة تمنع أنماط فشل الوكلاء الشائعة" +description: "جميع 39 سياسة مدمجة تلتقط أنماط فشل الوكيل الشائعة" icon: shield --- -يأتي failproofai مع 39 سياسة مدمجة تمنع أنماط فشل الوكلاء الشائعة. تعمل كل سياسة على نوع حدث hook محدد واسم أداة معين. تقبل تسع عشرة سياسة معاملات تتيح لك ضبط سلوكها دون كتابة أكواد. تفرض خمس سياسات سير عمل خط أنابيب التزام → دفع → طلب دمج → CI قبل توقف Claude. +يأتي failproofai مع 39 سياسة مدمجة تلتقط أنماط فشل الوكيل الشائعة. تُطلق كل سياسة على نوع حدث hook محدد واسم أداة معين. تقبل تسع عشرة سياسة معاملات تتيح لك ضبط سلوكها دون كتابة أكواد. خمس سياسات سير عمل تفرض خط أنابيب commit → push → PR → CI قبل أن يتوقف Claude. --- @@ -16,28 +16,26 @@ icon: shield |----------|----------|-----------| | [الأوامر الخطرة](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [أوامر البنية التحتية](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [الأسرار (معقّمات)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [الأسرار (المعالجات)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | | [البيئة](#environment) | block-env-files, protect-env-vars | PreToolUse | | [الوصول إلى الملفات](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | | [قاعدة البيانات](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | -| [تحذيرات](#warnings) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | +| [التحذيرات](#warnings) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | | [مديري الحزم](#package-managers) | prefer-package-manager | PreToolUse | | [سير العمل](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | - **`block-`** — إيقاف الوكيل عن المتابعة. -- **`warn-`** — إعطاء الوكيل سياق إضافي حتى يتمكن من تصحيح نفسه. -- **`sanitize-`** — إزالة البيانات الحساسة من مخرجات الأداة قبل أن يراها الوكيل. +- **`warn-`** — منح الوكيل سياق إضافي حتى يتمكن من تصحيح نفسه. +- **`sanitize-`** — محو البيانات الحساسة من مخرجات الأداة قبل أن يراها الوكيل. -### الأسماء الموصوفة +### مساحات الأسماء -تقع كل سياسة في فتحة `/`. تنتمي السياسات المدمجة إلى الفضاء الموصوف -**`failproofai/`** — على سبيل المثال، `failproofai/sanitize-jwt`. يمنع الفضاء الموصوف -التصادمات عند تحميل سياسات مخصصة أو من طرف ثالث -بأسماء قصيرة متشابهة. +تقع كل سياسة في فتحة `/`. تنتمي السياسات المدمجة إلى مساحة الأسماء +**`failproofai/`** — على سبيل المثال، `failproofai/sanitize-jwt`. تمنع مساحة الأسماء +التصادمات عند تحميل سياسات مخصصة أو من جهات خارجية بأسماء قصيرة مماثلة. -في ملف التكوين الخاص بك، يمكنك الإشارة إلى سياسة مدمجة باستخدام اسمها القصير أو اسمها -المؤهل؛ كلا الشكلين يحل لنفس السياسة: +في إعدادك يمكنك الإشارة إلى سياسة مدمجة باستخدام اسمها القصير أو اسمها المؤهل؛ كلا النموذجين يحلان إلى نفس السياسة: ```json { @@ -48,35 +46,34 @@ icon: shield } ``` -إذا لم يكن للاسم أي `/`، يعامل failproofai اسمه كتابعاً للفضاء الموصوف الافتراضي -`failproofai`. الأسماء التي تحتوي بالفعل على `/` (مثل `myorg/foo`، -`custom/my-hook`) تُبقى كما هي. -- **`require-`** — منع حدث Stop حتى يتم استيفاء الشروط. +إذا لم يكن لدى الاسم `/`، يعامله failproofai كتابع لمساحة الأسماء الافتراضية `failproofai`. الأسماء التي تحتوي بالفعل على `/` (على سبيل المثال `myorg/foo`، +`custom/my-hook`) يتم الاحتفاظ بها كما هي. +- **`require-`** — حجب حدث Stop حتى استيفاء الشروط. --- -تدعم كل سياسة حقل `hint` اختياري في `policyParams`. يتم إلحاق hint بعنوان الرفض أو التعليمات الذي يراه Claude، مما يوفر إرشادات قابلة للتنفيذ دون تعديل كود السياسة. يعمل مع السياسات المدمجة والمخصصة والاتفاقية. راجع [الإعدادات → hint](/ar/configuration#hint-cross-cutting) للحصول على التفاصيل. +تدعم كل سياسة حقل `hint` اختياري في `policyParams`. يتم إضافة التلميح إلى رسالة deny أو instruct التي يراها Claude، مما يوفر إرشادات قابلة للتنفيذ دون تعديل كود السياسة. يعمل مع السياسات المدمجة والمخصصة والاتفاقية. انظر [التكوين → hint](/ar/configuration#hint-cross-cutting) للمزيد من التفاصيل. --- ## الأوامر الخطرة -منع الوكلاء من تشغيل العمليات التي يصعب التراجع عنها أو التي قد تضر بنظام الكمبيوتر. +منع الوكلاء من تشغيل عمليات يصعب التراجع عنها أو قد تضر نظام المضيف. ### `block-sudo` **الحدث:** PreToolUse (Bash) **الافتراضي:** ينكر أي أمر `sudo`. -يمنع الاستدعاءات التي تتضمن كلمة `sudo`. يتم مطابقة النمط على رموز الأوامر المحللة، وليس السلسلة الأصلية، لمنع الالتفافة عبر حقن عامل الأغلاف. +يحجب الاستدعاءات التي تتضمن كلمة `sudo`. يتم المطابقة على أساس رموز الأوامر المحللة، وليس السلسلة الخام، لمنع الالتفاف عبر حقن مشغل shell. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات الأوامر الدقيقة المسموحة. يتم مطابقة كل إدخال مقابل رموز argv المحللة. | +| `allowPatterns` | `string[]` | `[]` | بادئات الأوامر الدقيقة المسموح بها. كل إدخال يطابق رموز argv المحللة. | **مثال:** @@ -90,10 +87,10 @@ icon: shield } ``` -مع هذا التكوين، يُسمح بـ `sudo systemctl status nginx`، لكن `sudo rm /etc/hosts` مرفوض. +مع هذا الإعداد، يُسمح بـ `sudo systemctl status nginx`، لكن `sudo rm /etc/hosts` يُرفض. -يتم مطابقة الأنماط مقابل الرموز المحللة، وليس السلسلة الأصلية للأمر. يمنع هذا الالتفافة عبر عوامل الأغلاف المرفقة (مثل `sudo systemctl status x; rm -rf /` لا يطابق `sudo systemctl status *`). +يتم مطابقة الأنماط مقابل الرموز المحللة، وليس سلسلة الأوامر الخام. يمنع هذا الالتفاف عبر مشغلات shell المرفقة (على سبيل المثال `sudo systemctl status x; rm -rf /` لا يطابق `sudo systemctl status *`). --- @@ -101,13 +98,13 @@ icon: shield ### `block-rm-rf` **الحدث:** PreToolUse (Bash) -**الافتراضي:** ينكر `rm -rf`، `rm -fr`، وأشكال الحذف المتكررة المماثلة. +**الافتراضي:** ينكر `rm -rf`, `rm -fr`، والأشكال الحذف التكراري المماثلة. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | المسارات التي يمكن حذفها بشكل متكرر بأمان (مثل `/tmp`). | +| `allowPaths` | `string[]` | `[]` | المسارات التي يمكن حذفها بشكل آمن بشكل تكراري (مثل `/tmp`). | **مثال:** @@ -126,26 +123,26 @@ icon: shield ### `block-curl-pipe-sh` **الحدث:** PreToolUse (Bash) -**الافتراضي:** ينكر `curl | bash`، `curl | sh`، `wget | bash`، والأنماط المماثلة. +**الافتراضي:** ينكر `curl | bash`, `curl | sh`, `wget | bash`، والأنماط المماثلة. -لا توجد معاملات. +بدون معاملات. --- ### `block-failproofai-commands` **الحدث:** PreToolUse (Bash) -**الافتراضي:** ينكر الأوامر التي ستلغي تثبيت أو تعطيل failproofai نفسه (مثل `npm uninstall failproofai`، `failproofai policies --uninstall`). +**الافتراضي:** ينكر الأوامر التي ستلغي تثبيت failproofai أو تعطله (مثل `npm uninstall failproofai`, `failproofai policies --uninstall`). -لا توجد معاملات. +بدون معاملات. --- ## أوامر البنية التحتية -منع وكلاء البرمجة من تشغيل CLI البنية التحتية أو بدء خطوط أنابيب CI/CD. جميع السياسات في هذه الفئة **اختيارية** (`defaultEnabled: false`) — الوكلاء الذين يحتاجون فعلاً إلى استدعاء `kubectl`، `terraform`، إلخ. لن يتعطلوا ما لم تفعّل السياسة. عند التفعيل، يتم رفض كل استدعاء للأداة المطابقة ما لم يطابق الأمر إدخالاً في `allowPatterns`. +منع وكلاء الترميز من تشغيل CLIs البنية التحتية أو تفعيل خطوط أنابيب CI/CD. جميع السياسات في هذه الفئة **اختيارية** (`defaultEnabled: false`) — الوكلاء الذين يحتاجون حقاً إلى استدعاء `kubectl`, `terraform`، إلخ لن يتعطلوا ما لم تفعّل السياسة. عند التفعيل، يُرفض كل استدعاء للـ CLI المطابق ما لم تطابق الأمر إدخالاً في `allowPatterns`. -نحو النمط هو نفسه [`block-sudo`](#block-sudo): يتم مطابقة الرموز مقابل argv المحللة، `*` هو حرف بدل لرمز واحد، وأي أمر يحتوي على عامل أغلاف مستقل (`&&`، `||`، `|`، `;`) أو رمز يحتوي على أحرف أغلاف مضمنة يُرفض قبل مطابقة القائمة البيضاء لمنع التفافات الحقن. +قواعد الأنماط هي نفسها [`block-sudo`](#block-sudo): يتم مطابقة الرموز مقابل argv المحلل، `*` هي بطاقة برية لرمز واحد، وأي أمر يحتوي على مشغل shell مستقل (`&&`, `||`, `|`, `;`) أو رمز يحتوي على أحرف metacharacter لـ shell يُرفض قبل مطابقة القائمة البيضاء لمنع التجاوز بالحقن. ### `block-kubectl` @@ -154,9 +151,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر kubectl المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر kubectl المسموح بها. | **مثال:** @@ -170,7 +167,7 @@ icon: shield } ``` -مع هذا التكوين، يُسمح بـ `kubectl get pods` لكن `kubectl apply -f deploy.yaml` مرفوض. +مع هذا الإعداد، `kubectl get pods` مسموح لكن `kubectl apply -f deploy.yaml` مرفوض. --- @@ -181,9 +178,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر terraform/tofu المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر terraform/tofu المسموح بها. | **مثال:** @@ -206,9 +203,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر aws CLI المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر aws CLI المسموح بها. | **مثال:** @@ -231,9 +228,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر gcloud المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر gcloud المسموح بها. | **مثال:** @@ -256,9 +253,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر az CLI المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر az CLI المسموح بها. | **مثال:** @@ -281,9 +278,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | بادئات أوامر helm المسموحة. | +| `allowPatterns` | `string[]` | `[]` | بادئات أوامر helm المسموح بها. | **مثال:** @@ -302,7 +299,7 @@ icon: shield ### `block-gh-pipeline` **الحدث:** PreToolUse (Bash) -**الافتراضي:** ينكر أوامر CLI `gh` الفرعية التالية التي تغيّر الحالة أو تبدأ خطوط أنابيب: +**الافتراضي:** ينكر أوامر `gh` CLI الفرعية التالية التي تغير الحالة أو تفعل خطوط أنابيب: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -311,13 +308,13 @@ icon: shield - `gh cache delete` - `gh secret set`, `gh secret delete` -أوامر `gh` الفرعية للقراءة فقط مثل `gh pr view`, `gh pr list`, `gh run list`, `gh release view`, و `gh api repos/.../...` **لا** يتطابقون مع هذه السياسة — يُحتاج إليهم بشكل منتظم لفحوصات سير العمل (بما في ذلك `require-ci-green-before-stop` الخاص بـ failproofai). +أوامر `gh` الفرعية للقراءة فقط مثل `gh pr view`, `gh pr list`, `gh run list`, `gh release view`، و `gh api repos/.../...` **لم** تطابقها هذه السياسة — فهي مطلوبة بشكل روتيني لفحوصات سير العمل (بما في ذلك `require-ci-green-before-stop` الخاص بـ failproofai). **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | استدعاءات برمجية محددة للسماح بها رغم أنها كانت ستُرفض. | +| `allowPatterns` | `string[]` | `[]` | استدعاءات محددة برمجية للسماح بها حتى لو كانت ستُرفض بخلاف ذلك. | **مثال:** @@ -333,29 +330,29 @@ icon: shield --- -## الأسرار (معقّمات) +## الأسرار (المعالجات) -منع الوكلاء من تسرب بيانات الاعتماد إلى سياقهم أو مخرجاتهم. تعمل سياسات المعقّم على أحداث **PostToolUse**. عندما يشغّل Claude أمر Bash، أو يقرأ ملف، أو يستدعي أي أداة، تفحص هذه السياسات المخرجات قبل إرجاعها إلى Claude. إذا تم كشف نمط سري، تعود السياسة برار الرفض الذي يمنع إرجاع المخرجات. +منع الوكلاء من تسرب بيانات اعتماد إلى سياقهم أو مخرجاتهم. تطلق سياسات المعالج على أحداث **PostToolUse**. عندما يشغل Claude أمر Bash أو يقرأ ملف أو يستدعي أي أداة، تفتش هذه السياسات المخرجات قبل إرجاعها إلى Claude. إذا تم اكتشاف نمط سري، تُرجع السياسة قرار deny يمنع المخرجات من الإرجاع. ### `sanitize-jwt` **الحدث:** PostToolUse (جميع الأدوات) -**الافتراضي:** يزيل رموز JWT (ثلاثة أجزاء base64url مفصولة بـ `.`). +**الافتراضي:** يحذف رموز JWT (ثلاث مقاطع base64url مفصولة بـ `.`). -لا توجد معاملات. +بدون معاملات. --- ### `sanitize-api-keys` **الحدث:** PostToolUse (جميع الأدوات) -**الافتراضي:** يزيل تنسيقات مفاتيح API الشائعة: Anthropic (`sk-ant-`)، OpenAI (`sk-`)، GitHub PATs (`ghp_`)، مفاتيح AWS (`AKIA`)، مفاتيح Stripe (`sk_live_`, `sk_test_`)، ومفاتيح Google API (`AIza`). +**الافتراضي:** يحذف تنسيقات مفاتيح API الشائعة: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`), و Google API keys (`AIza`). **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | أنماط regex إضافية لتعاملها كأسرار. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | أنماط regex إضافية للتعامل معها كأسرار. | **مثال:** @@ -377,42 +374,42 @@ icon: shield ### `sanitize-connection-strings` **الحدث:** PostToolUse (جميع الأدوات) -**الافتراضي:** يزيل سلاسل اتصال قاعدة البيانات التي تحتوي على بيانات اعتماد مضمنة (مثل `postgresql://user:password@host/db`). +**الافتراضي:** يحذف سلاسل اتصال قاعدة البيانات التي تحتوي على بيانات اعتماد مضمنة (مثل `postgresql://user:password@host/db`). -لا توجد معاملات. +بدون معاملات. --- ### `sanitize-private-key-content` **الحدث:** PostToolUse (جميع الأدوات) -**الافتراضي:** يزيل كتل PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`، إلخ). +**الافتراضي:** يحذف كتل PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`، إلخ). -لا توجد معاملات. +بدون معاملات. --- ### `sanitize-bearer-tokens` **الحدث:** PostToolUse (جميع الأدوات) -**الافتراضي:** يزيل رؤوس `Authorization: Bearer ` حيث يكون الرمز 20 حرفاً أو أكثر. +**الافتراضي:** يحذف رؤوس `Authorization: Bearer ` حيث يكون الرمز 20 حرفاً أو أكثر. -لا توجد معاملات. +بدون معاملات. --- ## البيئة -حماية إعدادات البيئة الحساسة من القراءة أو الكشف بواسطة الوكلاء. +حماية إعدادات البيئة الحساسة من قراءتها أو عرضها من قبل الوكلاء. ### `block-env-files` **الحدث:** PreToolUse (Bash, Read) -**الافتراضي:** ينكر قراءة ملفات `.env` عبر `cat .env`، استدعاءات أداة Read بـ `.env` كمسار ملف، إلخ. +**الافتراضي:** ينكر قراءة ملفات `.env` عبر `cat .env`, استدعاءات أداة Read بـ `.env` كمسار ملف، إلخ. -لا يمنع `.envrc` أو ملفات بيئية أخرى — فقط الملفات المسماة بالضبط `.env`. +لا يحجب `.envrc` أو ملفات بيئة أخرى — فقط الملفات المسماة بالضبط `.env`. -لا توجد معاملات. +بدون معاملات. --- @@ -421,24 +418,24 @@ icon: shield **الحدث:** PreToolUse (Bash) **الافتراضي:** ينكر الأوامر التي تطبع متغيرات البيئة: `printenv`, `env`, `echo $VAR`. -لا توجد معاملات. +بدون معاملات. --- ## الوصول إلى الملفات -إبقاء الوكلاء يعملون داخل حدود المشروع وبعيداً عن الملفات الحساسة. +احبس الوكلاء بداخل حدود المشروع وبعيداً عن الملفات الحساسة. ### `block-read-outside-cwd` **الحدث:** PreToolUse (Read, Bash) -**الافتراضي:** ينكر قراءة الملفات خارج جذر المشروع. الحد هو `CLAUDE_PROJECT_DIR` (يُعيّن مرة واحدة لكل جلسة بواسطة Claude Code)، مع تراجع إلى مجلد العمل الحالي للجلسة عندما يكون المتغير غير مُعيّن. استخدام جذر المشروع بدلاً من `cwd` المباشر يعني أن الحد يبقى ثابتاً حتى بعد أن يقوم Claude بـ `cd` إلى مجلد فرعي. +**الافتراضي:** ينكر قراءة الملفات خارج جذر المشروع. الحد هو `CLAUDE_PROJECT_DIR` (يتم تعيينه مرة واحدة لكل جلسة بواسطة Claude Code)، مع الرجوع إلى دليل العمل الحالي للجلسة عندما يكون هذا المتغير غير معرّف. يعني استخدام جذر المشروع بدلاً من `cwd` الحي أن الحد يبقى مستقراً حتى بعد أن يعدّل Claude بـ `cd` إلى مجلد فرعي. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | بادئات المسارات المطلقة المسموحة حتى لو كانت خارج جذر المشروع. | +| `allowPaths` | `string[]` | `[]` | بادئات المسار المطلقة المسموح بها حتى لو كانت خارج جذر المشروع. | **مثال:** @@ -457,13 +454,13 @@ icon: shield ### `block-secrets-write` **الحدث:** PreToolUse (Write, Edit) -**الافتراضي:** ينكر الكتابة إلى الملفات المستخدمة بشكل شائع للمفاتيح الخاصة والشهادات: `id_rsa`، `id_ed25519`، `*.key`، `*.pem`، `*.p12`، `*.pfx`. +**الافتراضي:** ينكر الكتابة إلى ملفات تستخدم عادة للمفاتيح الخاصة والشهادات: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | أنماط أسماء ملفات إضافية (نمط glob) لمنعها. | +| `additionalPatterns` | `string[]` | `[]` | أنماط اسم ملف إضافية بأسلوب glob للحجب. | **مثال:** @@ -481,7 +478,7 @@ icon: shield ## Git -منع الدفع العرضي والدفع القسري وأخطاء الفرع التي يصعب التراجع عنها. +منع عمليات Push العرضية والـ force-pushes وأخطاء الفرع التي يصعب التراجع عنها. ### `block-push-master` @@ -490,9 +487,9 @@ icon: shield **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | أسماء الفروع التي لا يمكن الدفع إليها مباشرة. | +| `protectedBranches` | `string[]` | `["main", "master"]` | أسماء الفروع التي لا يمكن الـ push إليها مباشرة. | **مثال:** @@ -507,7 +504,7 @@ icon: shield ``` -للسماح بالدفع إلى جميع الفروع (تعطيل هذه السياسة فعلياً دون إزالتها من `enabledPolicies`)، عيّن `protectedBranches: []`. +للسماح بالـ push إلى جميع الفروع (فعلياً تعطيل هذه السياسة بدون إزالتها من `enabledPolicies`)، اضبط `protectedBranches: []`. --- @@ -515,13 +512,13 @@ icon: shield ### `block-work-on-main` **الحدث:** PreToolUse (Bash) -**الافتراضي:** ينكر `git commit`، `git merge`، `git rebase`، و `git cherry-pick` بينما تكون شجرة العمل على `main` أو `master`. إنشاء الفروع والتبديل بينها (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) لا تتأثر. +**الافتراضي:** ينكر `git commit`, `git merge`, `git rebase`، و `git cherry-pick` بينما يكون شجرة العمل على `main` أو `master`. إنشاء الفروع والتبديل (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) لم تتأثر. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | أسماء الفروع التي يتم فيها رفض commit/merge/rebase/cherry-pick. | +| `protectedBranches` | `string[]` | `["main", "master"]` | أسماء الفروع التي يُرفض عليها commit/merge/rebase/cherry-pick. | --- @@ -530,13 +527,13 @@ icon: shield **الحدث:** PreToolUse (Bash) **الافتراضي:** ينكر `git push --force` و `git push -f`. -لا توجد معاملات خاصة بالسياسة. استخدم [`hint`](/ar/configuration#hint-cross-cutting) عبر جميع المشاريع لاقتراح بدائل: +بدون معاملات خاصة بالسياسة. استخدم cross-cutting [`hint`](/ar/configuration#hint-cross-cutting) لاقتراح بدائل: ```json { "policyParams": { "block-force-push": { - "hint": "أنشئ فرعاً جديداً من HEAD الحالي لديك (مثل `git checkout -b `) وادفعه بدلاً من ذلك." + "hint": "Create a new branch from your current HEAD (e.g. `git checkout -b `) and push that instead." } } } @@ -547,66 +544,66 @@ icon: shield ### `warn-git-amend` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يتابع بحذر عند تشغيل `git commit --amend`. لا يمنع الأمر. +**الافتراضي:** يُرشد Claude ليتابع بحذر عند تشغيل `git commit --amend`. لا يحجب الأمر. -لا توجد معاملات. +بدون معاملات. --- ### `warn-git-stash-drop` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل تشغيل `git stash drop`. لا يمنع الأمر. +**الافتراضي:** يُرشد Claude لتأكيد قبل تشغيل `git stash drop`. لا يحجب الأمر. -لا توجد معاملات. +بدون معاملات. --- ### `warn-all-files-staged` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يراجع ما يقوم بتحضيره عند تشغيل `git add -A` أو `git add .`. لا يمنع الأمر. +**الافتراضي:** يُرشد Claude لمراجعة ما يقوم بـ stage عند تشغيل `git add -A` أو `git add .`. لا يحجب الأمر. -لا توجد معاملات. +بدون معاملات. --- ## قاعدة البيانات -اكتشف العمليات SQL التدميرية قبل تنفيذها ضد قاعدة البيانات الخاصة بك. +التقط عمليات SQL المدمرة قبل تنفيذها على قاعدة البيانات الخاصة بك. ### `warn-destructive-sql` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل تشغيل SQL يحتوي على `DROP TABLE`, `DROP DATABASE`, أو `DELETE` بدون جملة `WHERE`. +**الافتراضي:** يُرشد Claude لتأكيد قبل تشغيل SQL يحتوي على `DROP TABLE`, `DROP DATABASE`، أو `DELETE` بدون جملة `WHERE`. -لا توجد معاملات. +بدون معاملات. --- ### `warn-schema-alteration` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل تشغيل بيانات `ALTER TABLE`. +**الافتراضي:** يُرشد Claude لتأكيد قبل تشغيل جمل `ALTER TABLE`. -لا توجد معاملات. +بدون معاملات. --- -## تحذيرات +## التحذيرات -إعطاء الوكلاء سياقاً إضافياً قبل العمليات المحتملة الخطورة لكن غير التدميرية. +أعط الوكلاء سياق إضافي قبل عمليات محتملة الخطورة لكن غير مدمرة. ### `warn-large-file-write` **الحدث:** PreToolUse (Write) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل كتابة ملفات أكبر من 1024 كيلوبايت. +**الافتراضي:** يُرشد Claude لتأكيد قبل كتابة ملفات أكبر من 1024 KB. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | عتبة حجم الملف بالكيلوبايت التي يُصدر فوقها تحذير. | +| `thresholdKb` | `number` | `1024` | حد حجم الملف بالكيلوبايت الذي يصدر عنده تحذير. | **مثال:** @@ -621,7 +618,7 @@ icon: shield ``` -معالج Hook يفرض حد أقصى 1 MB لـ stdin في حمولات الطلبات. لاختبار هذه السياسة بمحتوى صغير، عيّن `thresholdKb` إلى قيمة أقل بكثير من 1024. +يفرض معالج hook حد أقصى 1 MB على حمولات stdin. لاختبار هذه السياسة بمحتوى صغير، اضبط `thresholdKb` على قيمة أقل بكثير من 1024. --- @@ -629,49 +626,49 @@ icon: shield ### `warn-package-publish` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل تشغيل `npm publish`. +**الافتراضي:** يُرشد Claude لتأكيد قبل تشغيل `npm publish`. -لا توجد معاملات. +بدون معاملات. --- ### `warn-background-process` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يكون حذراً عند إطلاق عمليات الخلفية عبر `nohup`, `&`, `disown`, أو `screen`. +**الافتراضي:** يُرشد Claude ليكون حذراً عند تشغيل عمليات في الخلفية عبر `nohup`, `&`, `disown`، أو `screen`. -لا توجد معاملات. +بدون معاملات. --- ### `warn-global-package-install` **الحدث:** PreToolUse (Bash) -**الافتراضي:** يعلّم Claude بأن يؤكد قبل تشغيل `npm install -g`, `yarn global add`, أو `pip install` بدون بيئة افتراضية. +**الافتراضي:** يُرشد Claude لتأكيد قبل تشغيل `npm install -g`, `yarn global add`، أو `pip install` بدون بيئة افتراضية. -لا توجد معاملات. +بدون معاملات. --- ## مديري الحزم -فرض أي مديري حزم يُسمح للوكيل باستخدامهم. +فرض مديري الحزم الذي يسمح للوكيل باستخدامه. ### `prefer-package-manager` **الحدث:** PreToolUse (Bash) -**الافتراضي:** معطّل. عند التفعيل، يمنع أي أمر مدير حزم ليس في قائمة `allowed` ويخبر Claude بأن يعيد كتابة الأمر باستخدام مدير مسموح. +**الافتراضي:** معطّل. عند التفعيل، يحجب أي أمر مدير حزم ليس في قائمة `allowed` ويخبر Claude بإعادة كتابة الأمر باستخدام مدير مسموح. -الكشف عن: pip، pip3، python -m pip، npm، npx، yarn، pnpm، pnpx، bun، bunx، uv، poetry، pipenv، conda، cargo. +يكتشف: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. -| معامل | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | أسماء مديري الحزم المسموحة. أي مدير مكتشف ليس في هذه القائمة يتم منعه. عندما تكون فارغة، السياسة بلا تأثير. | -| `blocked` | string[] | `[]` | أسماء مديري حزم إضافية لمنعها بخلاف القائمة المدمجة (مثل `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | أسماء مديري الحزم المسموح بها. أي مدير مكتشف ليس في هذه القائمة يُحجب. عند الفراغ، السياسة لا-op. | +| `blocked` | string[] | `[]` | أسماء مديري إضافية للحجب تتجاوز القائمة المدمجة (مثل `['pdm', 'pipx']`). | -قائمة الحظر المدمجة تغطي: pip، pip3، npm، npx، yarn، pnpm، pnpx، bun، bunx، uv، poetry، pipenv، conda، cargo. استخدم `blocked` لإضافة مديري حزم ليسوا في هذه القائمة. +قائمة الحجب المدمجة تغطي: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. استخدم `blocked` لإضافة مديري ليسوا في هذه القائمة. -**مثال التكوين:** +**مثال إعداد:** ```json { @@ -685,74 +682,73 @@ icon: shield } ``` -مع هذا التكوين، يتم رفض كل من `pip install flask` و `pdm install flask` برسالة تخبر Claude بأن يستخدم `uv` أو `bun` بدلاً من ذلك. أوامر مثل `uv pip install flask` مسموحة لأن `uv` موجود في قائمة التسامح ويتم التحقق منه أولاً. +مع هذا الإعداد، `pip install flask` و `pdm install flask` كلاهما مرفوض برسالة تخبر Claude باستخدام `uv` أو `bun` بدلاً من ذلك. أوامر مثل `uv pip install flask` مسموحة لأن `uv` موجود في القائمة البيضاء ويتم فحصه أولاً. --- -## سلوك الذكاء الاصطناعي +## سلوك AI -اكتشف عندما يعلق الوكلاء أو يتصرفون بشكل غير متوقع. +اكتشف عندما يتعطل الوكلاء أو يتصرفون بشكل غير متوقع. ### `warn-repeated-tool-calls` **الحدث:** PreToolUse (جميع الأدوات) -**الافتراضي:** يعلّم Claude بأن يعيد النظر عندما يتم استدعاء نفس الأداة 3 مرات أو أكثر بمعاملات متطابقة — علامة شائعة لأن الوكيل عالق في حلقة. +**الافتراضي:** يُرشد Claude لإعادة التفكير عندما يتم استدعاء نفس الأداة 3+ مرات بمعاملات متطابقة - علامة شائعة على أن الوكيل محاصر في حلقة. -لا توجد معاملات. +بدون معاملات. --- ## سير العمل -فرض سير عمل منضبط في نهاية الجلسة. تعمل هذه السياسات على حدث **Stop** وترفض الوكيل من التوقف حتى يتم استيفاء كل شرط. تتبع سلسلة تبعية طبيعية: التزام → دفع → طلب دمج → CI. إذا رفضت سياسة، يتم تخطي السياسات اللاحقة في السلسلة (الرفض يقصر الدائرة). +فرض سير عمل نهاية جلسة منضبط. تطلق هذه السياسات على حدث **Stop** وترفض الوكيل من التوقف حتى يتم استيفاء كل شرط. تتبع سلسلة اعتماد طبيعية: commit → push → PR → CI. إذا رفضت سياسة، يتم تخطي السياسات اللاحقة في السلسلة (deny يقصر). -جميع سياسات سير العمل **تفشل مفتوحة**: إذا لم تكن الأداة المطلوبة متوفرة (مثل `gh` غير مثبتة، بدون جهاز تحكم git بعيد)، تسمح السياسة برسالة معلوماتية تشرح سبب تخطي الفحص. +جميع سياسات سير العمل **fail-open**: إذا لم تتوفر الأداة المطلوبة (مثل `gh` غير مثبت، لا git remote)، تسمح السياسة برسالة إعلامية تشرح سبب تخطي الفحص. ### دلالات Stop لكل CLI -يبدو إنفاذ Stop مختلفاً قليلاً عبر سبعة CLI مدعومة لأن كل واحد يعرّض عقد hook مختلفاً. النتيجة **متطابقة** — الوكيل لا يهرب من التوقف بينما تفشل بوابة سير العمل — لكن **الميكانيكا** تختلف. يلخص الجدول أدناه؛ فقط Pi لديه خصوصية واضحة للمستخدم تستحق الفهم قبل تفعيل سياسة `require-*-before-stop`. +يبدو إنفاذ Stop مختلفاً قليلاً عبر ستة CLIs المدعومة لأن كل واحد يعرض عقد hook "agent finished" مختلف. **النتيجة** هي نفسها — الوكيل لا يتمكن من التوقف بينما بوابة سير عمل فاشلة — لكن **الآليات** تختلف. يلخص الجدول أدناه؛ فقط Pi لديها دقة مرئية للمستخدم تستحق الفهم قبل تفعيل سياسة `require-*-before-stop`. -| CLI | متى تعمل البوابة | ما تراه | +| CLI | متى تطلق البوابة | ما تراه | |---|---|---| -| Claude Code | نفس حلقة الوكيل، فوراً | يستمر Claude في العمل — يصحح المشكلة، ثم يحاول الإنهاء مرة أخرى. لا توقف ظاهر لك. | +| Claude Code | نفس حلقة الوكيل، فوراً | يستمر Claude في العمل — يصلح المشكلة، ثم يحاول الانتهاء مرة أخرى. لا انقطاع مرئي لك. | | Codex | نفس حلقة الوكيل، فوراً | نفس Claude. | -| GitHub Copilot CLI | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة إعادة محاولة `{decision:"block", reason}` الخاصة بـ Copilot — تم التحقق منها تجريبياً ضد Copilot CLI 1.0.41). | -| Cursor Agent | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة `{followup_message}` الخاصة بـ Cursor — محدودة بـ `loop_limit`، افتراضي 5 إعادة محاولات). | -| Gemini CLI | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة `{decision:"block", reason}` الخاصة بـ Gemini على `AfterAgent`). | -| OpenCode | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم استدعاء SDK `client.session.prompt(...)` الخاص بـ OpenCode الموجه عبر `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **دور المستخدم التالي** | **يتوقف Pi بشكل واضح** عندما تعمل البوابة — تنهي حلقة الوكيل الخاصة به وتعودين إلى الموجه. تعمل البوابة بعد ذلك في المرة القادمة التي تقدّمين فيها موجهاً: يضيف failproofai توجيهاً `MANDATORY ACTION REQUIRED` إلى موجه نظام هذا الدور، يعلّم LLM بإكمال خطوة سير العمل (التزام، دفع، إلخ) قبل فعل ما طلبتِ. | +| GitHub Copilot CLI | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة إعادة محاولة Copilot `{decision:"block", reason}` — تم التحقق تجريبياً مقابل Copilot CLI 1.0.41). | +| Cursor Agent | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم قناة Cursor `{followup_message}` — مقطوعة بـ `loop_limit`، الافتراضي 5 إعادة محاولة). | +| OpenCode | نفس حلقة الوكيل، فوراً | نفس Claude (يستخدم استدعاء SDK `client.session.prompt(...)` في OpenCode الموجه عبر `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **دور المستخدم التالي** | **Pi يتوقف بشكل مرئي** عندما تطلق البوابة — حلقة وكيلها تخرج وتُرجع إلى الدعوة. ثم تطلق البوابة دور المستخدم التالي: يضع failproofai توجيه `MANDATORY ACTION REQUIRED` على نظام الدعوة لذلك الدور، يرشد LLM لإكمال خطوة سير العمل (commit, push, إلخ) قبل القيام بما طلبت. | -**قيد Pi.** `AgentEndEvent` الخاص بـ Pi (المعادل الأعلى لـ hook `Stop` الخاص بـ Claude) لا يملك نوع Result — بحلول الوقت الذي يعمل فيه، تكون حلقة الوكيل الخاصة بـ Pi قد خرجت بالفعل. لا يمكن إجبار Pi على إعادة محاولة نفس الحلقة بالطريقة التي يمكن بها Claude / Copilot / Cursor / Gemini / OpenCode. ينقل failproofai البوابة إلى حدث `before_agent_start` الخاص بـ Pi (الذي يعمل بعد الموجه التالي للمستخدم) لذا يبقى فحص سير العمل مفروضاً، فقط على الدور التالي بدلاً من الحالي. +**قيد Pi.** `AgentEndEvent` (المعادل upstream لحدث Claude `Stop` hook) في Pi ليس لديه نوع Result — بحلول الوقت الذي يطلق، حلقة وكيل Pi قد خرجت بالفعل. لا يمكن إجبار Pi على إعادة محاولة نفس الحلقة الطريقة التي يمكن بها Claude / Copilot / Cursor / OpenCode. يحول failproofai البوابة إلى حدث Pi `before_agent_start` (الذي يطلق بعد الدعوة التالية للمستخدم) بحيث فحص سير العمل ما يزال يُنفذ، فقط على الدور التالي بدلاً من الحالي. -**ما يعنيه هذا عملياً:** +**ما يعني هذا عملياً:** -- بعد توقف Pi، يتم التقاط رار الرفض في الذاكرة بمفتاح معرف جلسة Pi. الموجه التالي الذي تقدّمينه بالضبط في نفس عملية Pi يصرفه: يرى LLM توجيه `MANDATORY ACTION REQUIRED` في أعلى موجه النظام الخاص به، يلتزم (أو يدفع / يفتح PR / ينتظر CI)، وفقط بعد ذلك يستمر مع طلبك. رار الرفض المقبوض مرة واحدة — بمجرد صرفه، تكون البوابة واضحة. -- البوابة محدودة بعمر عملية Pi. إذا قمتِ بـ `Ctrl+C` Pi أو أغلقتِ بين الأدوار، يتم حذف الإدخال في الذاكرة مع العملية والبوابة تُفتقد. Claude و Copilot و Cursor و Gemini و OpenCode لديها نفس الحد (اقتل الوكيل والبوابة تُفتقد) — Pi فقط يجعله أكثر وضوحاً لأن الوكيل يخرج بشكل واضح قبل عمل البوابة. -- رار الرفض المعلق يتم مسحه أيضاً على `session_shutdown` لأي سبب (`new` / `resume` / `fork` / `quit`)، لذا بوابة قديمة من جلسة سابقة لا تستطيع التسرب إلى جلسة جديدة بدأت في نفس عملية Pi. +- بعد توقف Pi، يُلتقط سبب الرفض في الذاكرة مفتاح برقم جلسة Pi. الدعوة التالية للمستخدم في نفس عملية Pi بالضبط تصرفه: يرى LLM التوجيه `MANDATORY ACTION REQUIRED` في أعلى نظام الدعوة الخاص به، يcommit (أو push / يفتح PR / ينتظر CI)، فقط بعد ذلك يستمر مع طلبك. سبب الرفض الملتقط هو one-shot — بمجرد صرفه، البوابة واضحة. +- البوابة محدودة برمز عملية Pi. إذا ضغطت `Ctrl+C` Pi أو خرجت بين الأدوار، يُسقط الإدخال في الذاكرة مع العملية والبوابة تُفقد. Claude, Copilot, Cursor, و OpenCode لهما نفس الحد (اقتل الوكيل والبوابة تُفقد) — Pi فقط يجعله أكثر وضوحاً لأن الوكيل يخرج بشكل مرئي قبل البوابة. +- رفض معلق يُمسح أيضاً على `session_shutdown` لأي سبب (`new` / `resume` / `fork` / `quit`)، بحيث بوابة قديمة من جلسة سابقة لا يمكن أن تتسرب إلى جلسة جديدة بدأت في نفس عملية Pi. -إذا احتجتِ إلى إعادة محاولة نفس الحلقة بأسلوب Claude، قومي بتشغيل سياسات `Stop` الخاصة بك تحت أي من ستة CLI الأخرى المدعومة. نحن نتابع Pi في المنبع لنوع Result مستقبلي على `AgentEndEvent` الذي سيسمح لنا بإغلاق هذه الفجوة. +إذا كنت تحتاج إلى إعادة محاولة نفس حلقة على أسلوب Claude، شغّل سياسات `Stop` الخاصة بك تحت أي من الخمسة CLIs المدعومة الأخرى. نحن نتتبع Pi upstream لنوع Result مستقبلي على `AgentEndEvent` الذي سيسمح لنا بإغلاق هذه الفجوة. ### `require-commit-before-stop` **الحدث:** Stop -**الافتراضي:** ينكر التوقف عندما يكون هناك تغييرات غير مرتكبة (ملفات معدلة أو مرحلة أو غير تتبع). يعيد رسالة معلوماتية عندما يكون مجلد العمل نظيفاً. +**الافتراضي:** ينكر التوقف عند وجود تغييرات uncommitted (ملفات معدلة أو مرحلة أو لم يتم تتبعها). يُرجع رسالة إعلامية عندما يكون دليل العمل نظيف. -لا توجد معاملات. +بدون معاملات. --- ### `require-push-before-stop` **الحدث:** Stop -**الافتراضي:** ينكر التوقف عندما يكون هناك التزامات غير مدفوعة أو عندما لا يملك الفرع الحالي فرع تتبع بعيد. يقترح `git push -u` لإنشاء فرع تتبع إذا لزم الأمر. يفشل مفتوحاً إذا لم يكن هناك جهاز تحكم مكونة. +**الافتراضي:** ينكر التوقف عندما تكون هناك commits غير مدفوعة أو عندما لا يكون للفرع الحالي فرع تتبع بعيد. يقترح `git push -u` لإنشاء فرع تتبع إذا لزم الأمر. يفشل مفتوح إذا لم يكن أي remote مكون. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | اسم الجهاز البعيد الذي سيتم الدفع إليه. | +| `remote` | `string` | `"origin"` | اسم remote للـ push إليها. | **مثال:** @@ -771,14 +767,14 @@ icon: shield ### `require-pr-before-stop` **الحدث:** Stop -**الافتراضي:** ينكر التوقف عندما لا يكون هناك طلب دمج للفرع الحالي، أو عندما يكون طلب الدمج الموجود مغلقاً دون دمج. يعلّم Claude بإنشاء PR باستخدام `gh pr create`. عندما يكون PR **مدمجاً**، تسمح السياسة (تم شحن العمل) والرسالة تلمّح إلى التبديل عن الفرع (`git checkout main && git pull`). +**الافتراضي:** ينكر التوقف عندما لا يوجد pull request للفرع الحالي، أو عندما يكون PR الموجود مغلقاً بدون دمج. يُرشد Claude لإنشاء PR مع `gh pr create`. عندما يتم **دمج** PR، تسمح السياسة (العمل قد تم شحنه) والرسالة تلمح إلى التبديل من الفرع (`git checkout main && git pull`). -لا توجد معاملات. +بدون معاملات. -تتطلب هذه السياسة [GitHub CLI](https://cli.github.com/) (`gh`) مثبتاً ومصادقاً. -قم بتشغيل `gh auth login` برمز الوصول الشخصي الذي يملك نطاق `repo` للوصول القراءة إلى -طلبات السحب. إذا لم يكن `gh` مثبتاً أو مصادقاً، تفشل السياسة مفتوحة وتبلّغ عن السبب إلى Claude. +تتطلب هذه السياسة [GitHub CLI](https://cli.github.com/) (`gh`) مثبتة ومصرحة. +شغّل `gh auth login` ببطاقة وصول شخصية لها نطاق `repo` للوصول للقراءة +إلى pull requests. إذا لم يكن `gh` مثبتاً أو مصرحاً، تفشل السياسة مفتوحة وتبلغ السبب إلى Claude. --- @@ -786,23 +782,24 @@ icon: shield ### `require-no-conflicts-before-stop` **الحدث:** Stop -**الافتراضي:** ينكر التوقف عندما لا يمكن دمج الفرع الحالي بنظافة في فرع القاعدة. تؤكد السياسة أولاً أن هناك PR `OPEN` على GitHub للفرع — بدونها، لا يوجد هدف دمج للفرض، لذا تختصر السياسة بأكملها للسماح. عند تأكيد PR `OPEN`، يعمل مسحان مستقلان: +**الافتراضي:** ينكر التوقف عندما لا يمكن للفرع الحالي الدمج بنظافة مع الفرع الأساسي. تتحقق السياسة أولاً من وجود PR `OPEN` على GitHub للفرع — بدون واحد، لا يوجد هدف دمج للفرض، بحيث السياسة بأكملها تقصر للسماح. بمجرد تأكيد PR `OPEN`، يعمل اثنان من الاستكشافات المستقلة: -1. **محلي** — `git merge-tree --write-tree --name-only origin/ HEAD`. عند التضارب، تسمي رسالة الرفض الملفات المتضاربة حتى يعرف Claude بالضبط ما يجب حله. -2. **GitHub** — يعيد استخدام نتيجة `gh pr view --json mergeable,state` المجلوبة بالفعل في الفحص المسبق. يمسك التضاربات التي كانت `origin/` محلية قديمة ستفقدها (مثل الهبوط على PR متضارب على `main` منذ آخر جلب). نتيجة `CONFLICTING` ترفض. نتيجة `UNKNOWN` ترفض أيضاً وتعلّم Claude بالانتظار ~10 ثوان وإعادة الفحص قبل محاولة التوقف مرة أخرى — يمنع السلبيات الكاذبة بينما تعيد حساب GitHub. +1. **محلي** — `git merge-tree --write-tree --name-only origin/ HEAD`. عند التضارب، رسالة الرفض تسمي الملفات المتضاربة بحيث Claude يعرف بالضبط ما يحل. +2. **GitHub** — يعاد استخدام نتيجة `gh pr view --json mergeable,state` المحققة بالفعل في الفحص المسبق. يلتقط التضاربات التي `origin/` محلي قديم سيفوت (مثل شخص ما وضع PR متضارب على `main` منذ آخر fetch). نتيجة `CONFLICTING` ترفض. نتيجة `UNKNOWN` ترفض أيضاً وتُرشد Claude للانتظار ~10 ثوان وإعادة فحص قبل محاولة التوقف مرة أخرى — يمنع هذا false negatives بينما GitHub تعيد حساب. -تخطيها بالكامل (سماح) عند: `gh` غير مثبت، لا يوجد PR للفرع، حالة PR ليست `OPEN` (مثل `MERGED`, `CLOSED`)، أو `gh pr view` يرجع مخرجات غير قابلة للتحليل. يفشل أيضاً مفتوحاً عند فقدان `origin/` محلياً أو عند عدم وجود التزامات تقدماً من القاعدة — تلك أمراض مستوى الطبقة 1 تستشير قابلية دمج PR المخزنة مؤقتاً قبل السماح. +تخطي كلياً (السماح) عندما: `gh` غير مثبت، لا PR موجود للفرع، حالة PR ليست `OPEN` (مثل `MERGED`, `CLOSED`)، أو `gh pr view` ترجع مخرجات غير قابلة للتحليل. تفشل أيضاً مفتوحة عندما `origin/` مفقود محلياً أو عندما لا توجد commits بقدم الأساس — تلك Fall-throughs الطبقة 1 ما تزال تستشير mergeability المخزن مؤقتاً للـ PR قبل السماح. **المعاملات:** -| Param | النوع | الافتراضي | الوصف | +| المعامل | النوع | الافتراضي | الوصف | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | فرع القاعدة للفحص للتضاربات ضده. | +| `baseBranch` | `string` | `"main"` | فرع أساسي للفحص على التضاربات ضده. | -يُطلب GitHub CLI (`gh`) لهذه السياسة. تستخدم السياسة `gh pr view` لتأكيد -وجود PR `OPEN` قبل تشغيل أي مسح تضارب — بدون `gh`، تختصر السياسة للسماح. قم بتشغيل `gh auth login` برمز وصول شخصي يملك -نطاق `repo` للوصول القراءة إلى طلبات السحب. +GitHub CLI (`gh`) مطلوب لهذه السياسة. تستخدم السياسة `gh pr view` لتأكيد +وجود PR `OPEN` قبل تشغيل أي استكشاف تضارب — بدون `gh`، تقصر السياسة +للسماح. شغّل `gh auth login` ببطاقة وصول شخصية لها نطاق `repo` للوصول +للقراءة إلى pull requests. --- @@ -810,14 +807,14 @@ icon: shield ### `require-ci-green-before-stop` **الحدث:** Stop -**الافتراضي:** ينكر التوقف عندما تكون فحوصات CI فاشلة أو لا تزال تعمل على الفرع الحالي. يفحص كل من تشغيلات سير عمل GitHub Actions وفحوصات الروبوت من طرف ثالث (مثل CodeRabbit، SonarCloud، Codecov). يعتبر `skipped`, `cancelled`, و `neutral` الخلاصات غير فاشلة (الأخير يغطي مثل تنبيهات Socket Security على PRs المساهمين الخارجيين، حيث يبلّغ التطبيق عن neutral بدلاً من النجاح/الفشل بقصد). يعيد رسالة معلوماتية عندما تمر جميع الفحوصات. +**الافتراضي:** ينكر التوقف عندما تكون فحوصات CI فاشلة أو ما تزال تعمل على الفرع الحالي. يفحص كلاً من GitHub Actions workflow runs والفحوصات bot الخارجية (مثل CodeRabbit, SonarCloud, Codecov). يعامل `skipped`, `cancelled`، و `neutral` الخلاصات كغير فاشلة (الأخير يغطي مثل تنبيهات Socket Security على PRs المساهم الخارجي، حيث يبلغ التطبيق عن neutral عن قصد بدلاً من success/failure). يُرجع رسالة إعلامية عندما تمر جميع الفحوصات. -لا توجد معاملات. +بدون معاملات. -تتطلب هذه السياسة [GitHub CLI](https://cli.github.com/) (`gh`) مثبتاً ومصادقاً. -قم بتشغيل `gh auth login` برمز وصول شخصي يملك نطاق `repo` للوصول القراءة إلى -تشغيلات سير عمل Actions وAPI الفحوصات. إذا لم يكن `gh` مثبتاً أو مصادقاً، تفشل السياسة مفتوحة وتبلّغ عن السبب إلى Claude. +تتطلب هذه السياسة [GitHub CLI](https://cli.github.com/) (`gh`) مثبتة ومصرحة. +شغّل `gh auth login` ببطاقة وصول شخصية لها نطاق `repo` للوصول +لـ Actions workflow runs و Checks API. إذا لم يكن `gh` مثبتاً أو مصرحاً، تفشل السياسة مفتوحة وتبلغ السبب إلى Claude. --- @@ -826,7 +823,7 @@ icon: shield ## تعطيل السياسات الفردية -أزل سياسة محددة من `enabledPolicies` في ملف التكوين الخاص بك، أو قم بتبديلها في تبويب السياسات بلوحة البيانات. +أزل سياسة محددة من `enabledPolicies` في إعدادك، أو أطفئها في تبويب Policies بـ dashboard. ```json { @@ -837,4 +834,4 @@ icon: shield } ``` -السياسات غير المدرجة في `enabledPolicies` لا تعمل، حتى لو كانت هناك إدخالات `policyParams` موجودة لها. \ No newline at end of file +السياسات غير المدرجة في `enabledPolicies` لا تعمل، حتى إذا كانت إدخالات `policyParams` موجودة لها. \ No newline at end of file diff --git a/docs/ar/cli/audit.mdx b/docs/ar/cli/audit.mdx index fd1384a9..ccd76219 100644 --- a/docs/ar/cli/audit.mdx +++ b/docs/ar/cli/audit.mdx @@ -1,18 +1,19 @@ --- +--- title: تدقيق الجلسات السابقة (تجريبي) -description: "عد عدد المرات التي فعل فيها الوكيل أشياء مهدرة أو محفوفة بالمخاطر عبر النصوص السابقة" +description: "عد عدد مرات قيام الوكيل بأشياء مهدرة أو محفوفة بالمخاطر عبر النصوص السابقة" --- - **ميزة تجريبية.** يشحن التدقيق كإصدار تجريبي بينما نجمع التعليقات المبكرة. - قد يتغير كتالوج الكاشف وتنسيق التقرير قبل الإصدار المستقر التالي. يرجى فتح مشكلة إذا بدا شيء غير صحيح. + **ميزة تجريبية.** يتم شحن التدقيق كإصدار تجريبي أثناء جمع ملاحظاتنا المبكرة. + قد يتغير كتالوج المكتشف وتنسيق التقرير قبل الإصدار المستقر التالي. يرجى فتح مشكلة إذا بدا شيء ما خاطئًا. -يعيد التدقيق تشغيل نصوص عامل CLI السابقة عبر محرك السياسة الخاص بـ failproofai ويعرض تقريراً مشاركاً وبصرياً على **صفحة لوحة التحكم `/audit`** — نموذج الوكيل الأصلي، نقطة من 0–100، وبالضبط أي سياسات كان يمكن أن تلتقط ماذا. +يعيد التدقيق تشغيل نصوص failproofai الخاصة بك من CLI السابقة من خلال محرك السياسة ويعرض تقريرًا مرئيًا قابلًا للمشاركة على صفحة لوحة المعلومات **`/audit`** — نموذج الوكيل الأصلي، درجة من 0 إلى 100، وبالضبط أي السياسات كان يمكن أن تكتشف ما. ## قم بتشغيله -ثلاث طرق للدخول — جميعها تصل إلى نفس تقرير `/audit`. +ثلاث طرق للدخول — جميعها تؤدي إلى نفس تقرير `/audit`. @@ -24,7 +25,7 @@ npx -y failproofai audit failproofai audit ``` -```bash failproofai (لوحة التحكم) +```bash failproofai (لوحة المعلومات) failproofai ``` @@ -32,56 +33,56 @@ failproofai - `npx -y failproofai audit` يجلب failproofai، ويقوم بتشغيل الفحص، ويفتح لوحة التحكم لك — لا حاجة لتثبيت شيء مسبقاً. + `npx -y failproofai audit` يجلب failproofai، ويشغل الفحص، ويفتح لوحة المعلومات لك — لا حاجة لتثبيت أي شيء أولاً. - - `failproofai audit` يقوم بتشغيل الفحص في محطتك، ثم يفتح `localhost:8020/audit` تلقائياً عند انتهائه. + + `failproofai audit` يشغل الفحص في طرفيتك، ثم يفتح `localhost:8020/audit` تلقائيًا عند انتهاء العملية. - + قم بتشغيل `failproofai` وانقر على **Audit** في شريط التنقل (بين Policies و Projects)، أو افتح `/audit` مباشرة. - قم بتشغيل `failproofai audit -h` (أو `--help`) لرؤية الاستخدام. يعمل التدقيق **بالكامل بدون اتصال** — لا تحتاج إلى حساب أو شبكة — ولوحة التحكم تستمر في الخدمة حتى توقفها بـ `Ctrl+C`. + قم بتشغيل `failproofai audit -h` (أو `--help`) لمراجعة الاستخدام. يعمل التدقيق **بالكامل دون الاتصال بالإنترنت** — لا تحتاج إلى حساب أو شبكة — وتستمر لوحة المعلومات في العمل حتى تيقفها باستخدام `Ctrl+C`. -تقوم لوحة التحكم بفحص نصوص وكيل CLI السابقة على هذا الجهاز (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) وتقرر كم مرة فعل الوكيل أشياء تم بناء failproofai لإيقافها — فحوصات متغيرات البيئة، الدفعات القسرية، البادئات `cd ` الزائدة، حلقات الانتظار بالنوم، إعادة قراءة الملفات التي تم تحريرها للتو، وغير ذلك. +تمسح لوحة المعلومات نصوص CLI الخاصة بالوكيل السابقة على هذا الجهاز (Claude Code، Codex، Copilot، Cursor، OpenCode، Pi) وتقرر عدد مرات قيام الوكيل بأشياء failproofai مبنية للتوقف عنها — فحوصات متغيرات البيئة، الدفع القسري، بادئات `cd ` الزائدة، حلقات استطلاع النوم، إعادة قراءة الملفات المحررة للتو، والمزيد. -لكل نص، يتم إعادة تشغيل كل حدث استخدام أداة عبر السياسات المدمجة البالغ عددها 39 **و** عبر 8 كواشف خاصة بالتدقيق فقط التي تلتقط الأنماط التي لم تغطها السياسات الوقتية بعد. يتم تجميع الأعداد لكل سياسة / كاشف عبر جميع الجلسات. +بالنسبة لكل نص، يتم إعادة تشغيل كل حدث استخدام أداة من خلال 39 سياسة مدمجة **و** من خلال 8 كواشف تدقيق فقط تكتشف الأنماط التي لم تتم تغطيتها بعد بواسطة سياسات وقت التشغيل. يتم تجميع الأعداد حسب السياسة / الكاشف عبر جميع الجلسات. -## ما ستحصل عليه +## ما الذي تحصل عليه -صفحة `/audit` عبارة عن **ملصق** واحد على شاشة واحدة وقابل للمشاركة متبوعاً بأربعة أقسام أسفل الصفحة: +صفحة `/audit` عبارة عن **ملصق** بشاشة واحدة وقابل للمشاركة متبوعًا بأربعة أقسام أسفل الطية: -1. **الملصق** — هوية الوكيل للوهلة الأولى: **نموذجه الأصلي** (أحد 8 — `optimist`، `cowboy`، `explorer`، `goldfish`، `paranoid architect`، `precision builder`، `hammer`، `ghost`)، كلماته الأساسية في الشخصية، مدى ندرة هذا النموذج الأصلي، و **نقطة من 0–100** مع فئة (`S` وحتى `bottom tier`). تم بناؤه للمشاركة — انشر على X أو LinkedIn، أو نزّله كملف PNG. -2. **`// strengths`** — ما يفعله الوكيل جيداً بالفعل، كأرقام حقيقية من الفحص (مثل clean-tool-call %، `0` محاولات push-to-main)، موضحة فقط حيث تحتوي السياسة ذات الصلة على سجل نظيف. -3. **`// quirks`** — ما انزلق: جدول مرتب من السلوكيات التي كان يمكن لـ failproofai اكتشافها — *متى* حدثت آخر مرة، *ما انزلق* (والمدمج الذي كان سيحجبه)، *شدتها*، وكم مرة تمت رؤيتها (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — قائمة الإصلاح الموصوف: صف واحد لكل سياسة مع نسخ لصق `failproofai policy add `، بالإضافة إلى زر **install all** يفعّل كل توصية مرة واحدة ويظهر **المجموع المتوقع** الخاص بك إذا فعلت ذلك. -5. **`// come back better`** — بناء العادة: عيّن تذكير إعادة تدقيق بالبريد الإلكتروني **reminder** (`3d` / `7d` / `14d` / `30d`) أو أعد التدقيق الآن، و **ادعُ صديقاً** لتشغيل التدقيق الخاص به (مرسل من failproof.ai، مع نسخة موجهة إليك). تتطلب التذكيرات والدعوات تسجيل الدخول — انظر [`failproofai auth`](/ar/cli/auth). +1. **ملصق** — هوية الوكيل في لمحة سريعة: **نموذجه الأصلي** (واحد من 8 — `optimist`، `cowboy`، `explorer`، `goldfish`، `paranoid architect`، `precision builder`، `hammer`، `ghost`)، كلمات المفاتيح الشخصية له، مدى ندرة هذا النموذج الأصلي، و **درجة من 0 إلى 100** مع فرقة مستوى (`S` إلى `bottom tier`). مصنوع للمشاركة — انشره على X أو LinkedIn، أو قم بتنزيله كصورة PNG. +2. **`// strengths`** — ما يفعله الوكيل بالفعل بشكل جيد، كأرقام حقيقية من الفحص (مثل نسبة استدعاء أداة نظيفة، `0` محاولات push-to-main)، يظهر فقط حيث تحتفظ السياسة ذات الصلة بسجل نظيف. +3. **`// quirks`** — ما انزلق: جدول مرتب للسلوكيات التي كان failproofai سيكتشفها — *متى* حدثت آخر مرة، *ما الذي انزلق* (والمدمج الذي كان يمكن أن يمنعه)، *شدته*، وعدد مرات *رؤيته* (`new` / `recurring` / `N× seen`). +4. **`// كيفية التحسين`** — قائمة الإصلاح الموصى بها: صف واحد لكل سياسة مع نسخ ولصق `failproofai policy add `، بالإضافة إلى زر **تثبيت الكل** الذي يفعّل كل توصية دفعة واحدة ويعرض **الدرجة المتوقعة** إذا فعلت. +5. **`// عد بحالة أفضل`** — بناء العادة: قم بتعيين **تذكير** إعادة تدقيق البريد الإلكتروني (`3d` / `7d` / `14d` / `30d`) أو أعد التدقيق الآن، و**دعوة صديق** لتشغيل التدقيق الخاص به (المرسلة من failproof.ai، Cc موجه لك). تتطلب التذكيرات والدعوات تسجيل الدخول — انظر [`failproofai auth`](/ar/cli/auth). ## كواشف التدقيق فقط -هذه تكتشف أنماط السلوك الحمقاء غير المطبقة (بعد) في الوقت الفعلي. تعمل فقط أثناء التدقيق ولا تحجب أبداً استدعاء أداة مباشرة. +هذه تكتشف أنماط السلوك "الغبي" التي لم تُفرض (بعد) في الوقت الفعلي. تعمل فقط أثناء التدقيق ولا تمنع أبدًا استدعاء أداة مباشر. -| الكاشف | ما يحسبه | +| الكاشف | ما الذي يحسبه | |---|---| -| `redundant-cd-cwd` | أوامر Bash التي تبدأ بـ `cd && …` حتى وإن كانت الأوامر تعمل بالفعل في `cwd`. | +| `redundant-cd-cwd` | أوامر Bash التي تبدأ بـ `cd && …` حتى لو كانت الأوامر تعمل بالفعل في `cwd`. | | `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` على ملف مصدر واحد — استخدم أداة `Read`. | -| `prefer-edit-over-sed-awk` | تحريرات في الموضع `sed -i` / `awk … > file` — استخدم أداة `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / كتابة الملفات بـ `echo > file` متعدد الأسطر — استخدم أداة `Write`. | -| `sleep-polling-loop` | حلقات الانتظار `sleep N` الطويلة (≥ 30s) أو `while …; sleep …; done`. | -| `find-from-root` | `find /`, `find /home`, `find /usr`، إلخ. — حدد النطاق إلى `cwd` بدلاً من ذلك. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`، يتخطى الخطافات. | -| `reread-after-edit` | `Read` لملف تم `Edit`/`Write` للتو في نفس الجلسة. | +| `prefer-edit-over-sed-awk` | تحرير في المكان `sed -i` / `awk … > file` — استخدم أداة `Edit`. | +| `prefer-write-over-heredoc` | Heredoc / كتابة `echo > file` متعددة الأسطر للملفات — استخدم أداة `Write`. | +| `sleep-polling-loop` | `sleep N` طويل (≥ 30s) أو حلقات استطلاع `while …; sleep …; done`. | +| `find-from-root` | `find /`، `find /home`، `find /usr`، وغيرها — قم بتحديد نطاق `cwd`. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`، تخطي الخطافات. | +| `reread-after-edit` | `Read` لملف تم تحريره/كتابته للتو في نفس الجلسة. | ## الذاكرات المؤقتة -- **ذاكرة مؤقتة لكل نص** في `~/.failproofai/cache/audit/.json` مفهرسة حسب `(mtime, size, engineVersion, detectorVersion)` — تُلغى تلقائياً عند تغيير النص أو رمز السياسة/الكاشف. يخزن كل إدخال أيضاً طابع زمني `cachedAt` كـ **بيانات وصفية TTL** (ليست جزءاً من مفتاح الذاكرة المؤقتة)؛ الإدخالات الأقدم من **7 أيام** يتم رفضها عند القراءة حتى لا تتجاوز النتائج طويلة الأجل القصد المتطور للكاشف. -- **ذاكرة مؤقتة للنتيجة الكاملة** في `~/.failproofai/audit-dashboard.json` (mode 0600). تسمح لوحة التحكم بالعرض الفوري عند التنقل دون إعادة التشغيل. يتم رفضها أيضاً عند القراءة بعد **TTL لمدة 7 أيام** — ثم `/audit` تسقط إلى حالتها الفارغة وتطالب بتشغيل جديد. انقر على `[ re-audit now ]` بالقرب من أسفل التقرير للتحديث — تعيد التدقيق ترسل `noCache: true`، لذا فهي تتجاوز ذاكرة التخزين المؤقت لكل نص وتعيد فحص كل نص بدلاً من إرجاع النتيجة المخزنة مؤقتاً؛ التشغيل يتدفق التقدم عبر شريط لاصق في الأعلى ويبدل النتيجة في المكان عند النجاح (لا إعادة تحميل للصفحة؛ فشل إعادة التدقيق يحافظ على التقرير السابق). +- **ذاكرة مؤقتة لكل نص** في `~/.failproofai/cache/audit/.json` مفهرسة حسب `(mtime, size, engineVersion, detectorVersion)` — تلغى تلقائيًا عند تغيير النص أو كود السياسة/الكاشف. يخزن كل إدخال أيضًا طابع زمني `cachedAt` كـ **بيانات وصف TTL** (ليس جزءًا من مفتاح الذاكرة المؤقتة)؛ يتم رفض الإدخالات الأقدم من **7 أيام** عند القراءة بحيث لا تتجاوز النتائج طويلة المدى النية المتطورة للكاشف. +- **ذاكرة مؤقتة للنتيجة الكاملة** في `~/.failproofai/audit-dashboard.json` (الوضع 0600). يسمح لوحة المعلومات بالعرض فورًا عند الملاحة دون إعادة تشغيل. يتم رفضها أيضًا عند القراءة بعد **TTL مدة 7 أيام** — `/audit` ثم يسقط إلى حالته الفارغة ويدفع لتشغيل جديد. انقر فوق `[ re-audit now ]` بالقرب من أسفل التقرير للتحديث — يرسل إعادة التدقيق `noCache: true`، لذا فإنه يتجاوز ذاكرة النص المؤقتة وينسخ كل نص بدلاً من إرجاع النتيجة المخزنة مؤقتًا؛ يتدفق المدى بنقاء من شريط لزج علوي ويتبادل النتيجة في المكان عند النجاح (بدون إعادة تحميل الصفحة؛ إعادة تدقيق فاشلة تحتفظ بالتقرير السابق). ## ملاحظات -- **لا طفرة.** يعاد التدقيق في وضع القراءة فقط. يتم تخطي `warn-repeated-tool-calls` لأن الملف الجانبي لكل جلسة قد يتم تعديله بخلاف ذلك. -- **سياسات سير العمل المتخطاة.** سياسات `require-*-before-stop` تنطلق فقط عند أحداث `Stop` و `execSync` مقابل حالة git المباشرة — ليس لديها تفسير ذي مغزى من نوع "ما كان سيحدث في 2025"، لذا لا تظهر في أعداد التدقيق. -- **السياسات المخصصة المتخطاة.** الخطافات المخصصة التي يوفرها المستخدم لا يتم إعادة تشغيلها (قد تكون قد تغيرت منذ الجلسة الأصلية). \ No newline at end of file +- **بدون طفرة.** يعاد تشغيل التدقيق في وضع القراءة فقط. يتم تخطي `warn-repeated-tool-calls` لأن سياره الجانب لكل جلسة سيتم تعديله بخلاف ذلك. +- **تم تخطي سياسات سير العمل.** سياسات `require-*-before-stop` تطلق فقط على أحداث `Stop` و `execSync` ضد حالة git المباشرة — ليس لديهم تفسير ذي مغزى "ماذا كان سيحدث في 2025"، لذا لا تظهر في عدد التدقيق. +- **تم تخطي السياسات المخصصة.** لا يتم إعادة تشغيل الخطافات المخصصة المزودة من قبل المستخدم (قد تكون قد تغيرت منذ الجلسة الأصلية). \ No newline at end of file diff --git a/docs/ar/configuration.mdx b/docs/ar/configuration.mdx index 71fa9a37..af2c1eb5 100644 --- a/docs/ar/configuration.mdx +++ b/docs/ar/configuration.mdx @@ -1,62 +1,62 @@ --- --- title: التكوين -description: "تنسيق ملف الإعدادات، ونظام النطاقات الثلاثة، وقواعد الدمج" +description: "تنسيق ملف التكوين ونظام النطاقات الثلاثة وقواعد الدمج" icon: gear --- -يستخدم failproofai ملفات إعدادات JSON للتحكم في السياسات المفعلة وكيفية عملها ومن أين يتم تحميل السياسات المخصصة. صُمم التكوين ليكون سهل المشاركة مع فريقك - التزمه في مستودعك وسيحصل كل مطور على نفس شبكة الأمان للوكيل. +يستخدم failproofai ملفات تكوين JSON للتحكم في السياسات النشطة وكيفية تصرفها ومكان تحميل السياسات المخصصة. تم تصميم التكوين ليكون سهل المشاركة مع فريقك - قم بإلزامه على مستودعك وسيحصل كل مطور على نفس شبكة الأمان للوكيل. --- ## نطاقات التكوين -هناك ثلاثة نطاقات للتكوين، يتم تقييمها بترتيب الأولوية: +هناك ثلاثة نطاقات تكوين، يتم تقييمها بترتيب الأولوية: | النطاق | مسار الملف | الغرض | |-------|-----------|---------| -| **المشروع** | `.failproofai/policies-config.json` | إعدادات خاصة بكل مستودع، مرتبطة بمراقبة الإصدار | -| **محلي** | `.failproofai/policies-config.local.json` | تجاوزات شخصية لكل مستودع، مستبعدة من git | -| **عام** | `~/.failproofai/policies-config.json` | الإعدادات الافتراضية على مستوى المستخدم عبر جميع المشاريع | +| **المشروع** | `.failproofai/policies-config.json` | إعدادات لكل مستودع، مرتكبة للتحكم في الإصدار | +| **محلي** | `.failproofai/policies-config.local.json` | تجاوزات شخصية لكل مستودع، مدرجة في gitignore | +| **عام** | `~/.failproofai/policies-config.json` | إعدادات افتراضية على مستوى المستخدم عبر جميع المشاريع | عندما يتلقى failproofai حدث hook، يقوم بتحميل ودمج جميع الملفات الثلاثة الموجودة للدليل العامل الحالي. ### قواعد الدمج -**`enabledPolicies`** - اتحاد جميع النطاقات الثلاثة. السياسة المفعلة على أي مستوى تكون نشطة. +**`enabledPolicies`** - اتحاد جميع النطاقات الثلاثة. السياسة المفعلة على أي مستوى نشطة. ```text project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← اتحاد منقى من التكرارات +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← اتحاد مزال منه التكرار ``` -**`policyParams`** - أول نطاق يحدد معاملات سياسة معينة يفوز بالكامل. لا يوجد دمج عميق للقيم داخل معاملات السياسة. +**`policyParams`** - النطاق الأول الذي يحدد المعاملات لسياسة معينة يفوز بالكامل. لا يوجد دمج عميق للقيم ضمن معاملات السياسة. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← المشروع يفوز، يتم تجاهل العام +resolved: { allowPatterns: ["sudo apt-get update"] } ← المشروع يفوز، العام مُتجاهل ``` ```text -project: (لا توجد إدخالة block-sudo) -local: (لا توجد إدخالة block-sudo) +project: (no block-sudo entry) +local: (no block-sudo entry) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى العام ``` -**`customPoliciesPath`** - أول نطاق يحدده يفوز. +**`customPoliciesPath`** - النطاق الأول الذي يحدده يفوز. -**`llm`** - أول نطاق يحدده يفوز. +**`llm`** - النطاق الأول الذي يحدده يفوز. --- -## تنسيق ملف الإعدادات +## تنسيق ملف التكوين ```json { @@ -103,25 +103,25 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى ا النوع: `string[]` -قائمة أسماء السياسات المراد تفعيلها. يجب أن تطابق الأسماء بالضبط معرفات السياسات التي تظهر من خلال `failproofai policies`. انظر [السياسات المدمجة](/ar/built-in-policies) للحصول على القائمة الكاملة. +قائمة أسماء السياسات المراد تفعيلها. يجب أن تتطابق الأسماء بالضبط مع معرفات السياسات التي تظهر بواسطة `failproofai policies`. اطلع على [السياسات المدمجة](/ar/built-in-policies) للحصول على القائمة الكاملة. -السياسات غير الموجودة في `enabledPolicies` تكون غير نشطة، حتى لو كان لديها إدخالات في `policyParams`. +السياسات التي لا تظهر في `enabledPolicies` غير نشطة، حتى لو كان لديها إدخالات في `policyParams`. ### `policyParams` النوع: `Record>` -تجاوزات المعاملات لكل سياسة. المفتاح الخارجي هو اسم السياسة؛ والمفاتيح الداخلية خاصة بكل سياسة. تتوثق كل سياسة معاملاتها المتاحة في [السياسات المدمجة](/ar/built-in-policies). +تجاوزات المعاملات لكل سياسة. المفتاح الخارجي هو اسم السياسة؛ المفاتيح الداخلية خاصة بالسياسة. تتوثق كل سياسة معاملاتها المتاحة في [السياسات المدمجة](/ar/built-in-policies). -إذا كانت السياسة لها معاملات ولم تحددها، يتم استخدام الإعدادات المدمجة الافتراضية للسياسة. المستخدمون الذين لا يقومون بتكوين `policyParams` على الإطلاق يحصلون على سلوك متطابق مع الإصدارات السابقة. +إذا كان لدى السياسة معاملات لكنك لم تحددها، يتم استخدام القيم الافتراضية المدمجة للسياسة. يحصل المستخدمون الذين لا يقومون بتكوين `policyParams` على الإطلاق على سلوك مطابق للإصدارات السابقة. -المفاتيح غير المعروفة داخل كتلة معاملات السياسة يتم تجاهلها بصمت في وقت حدث الخطاف ولكن يتم الإشارة إليها كتحذيرات عند تشغيل `failproofai policies`. +المفاتيح غير المعروفة ضمن كتلة معاملات السياسة يتم تجاهلها بصمت عند حريق hook لكن يتم تعليمها كتحذيرات عند تشغيل `failproofai policies`. #### `hint` (شامل) النوع: `string` (اختياري) -رسالة يتم إلحاقها بالسبب عندما تعيد السياسة `deny` أو `instruct`. استخدمها لإعطاء Claude إرشادات قابلة للتنفيذ دون تعديل السياسة نفسها. +رسالة يتم إضافتها للسبب عند إرجاع السياسة `deny` أو `instruct`. استخدمه لإعطاء Claude توجيهات قابلة للتنفيذ دون تعديل السياسة ذاتها. يعمل مع أي نوع سياسة — مدمجة، مخصصة (`custom/`)، اتفاقية المشروع (`.failproofai-project/`)، أو اتفاقية المستخدم (`.failproofai-user/`). @@ -129,7 +129,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى ا { "policyParams": { "block-force-push": { - "hint": "حاول إنشاء فرع جديد بدلاً من ذلك." + "hint": "جرب إنشاء فرع جديد بدلاً من ذلك." }, "block-sudo": { "allowPatterns": ["sudo apt-get"], @@ -142,40 +142,40 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى ا } ``` -عندما ترفض `block-force-push`، يرى Claude: *"فرض الدفع محظور. حاول إنشاء فرع جديد بدلاً من ذلك."* +عند رفض `block-force-push`، يرى Claude: *"دفع القوة محظور. جرب إنشاء فرع جديد بدلاً من ذلك."* -القيم غير النصية والنصوص الفارغة يتم تجاهلها بصمت. إذا لم يتم تعيين `hint`، السلوك لا يتغير (متوافق مع الإصدارات السابقة). +القيم غير النصية والسلاسل الفارغة يتم تجاهلها بصمت. إذا لم يتم تعيين `hint`، يبقى السلوك دون تغيير (متوافق بشكل عكسي). ### `customPoliciesPath` النوع: `string` (مسار مطلق) -مسار ملف JavaScript يحتوي على سياسات خطاف مخصصة. يتم تعيينه تلقائياً بواسطة `failproofai policies --install --custom ` (يتم حل المسار إلى مطلق قبل التخزين). +المسار إلى ملف JavaScript يحتوي على سياسات hook مخصصة. يتم تعيينه تلقائياً بواسطة `failproofai policies --install --custom ` (يتم حل المسار إلى مطلق قبل تخزينه). -يتم تحميل الملف مجدداً في كل حدث خطاف - لا يوجد تخزين مؤقت. انظر [السياسات المخصصة](/ar/custom-policies) لتفاصيل الإنشاء. +يتم تحميل الملف بشكل جديد على كل حدث hook - لا يوجد تخزين مؤقت. اطلع على [السياسات المخصصة](/ar/custom-policies) للحصول على تفاصيل المؤلفات. -### سياسات قائمة على الاتفاقية +### السياسات المستندة إلى الاتفاقية -بالإضافة إلى `customPoliciesPath` الصريح، يقوم failproofai تلقائياً باكتشاف وتحميل ملفات السياسات من دلائل `.failproofai/policies/`: +بالإضافة إلى `customPoliciesPath` الصريح، يكتشف failproofai تلقائياً ويحمل ملفات السياسات من الأدلة `.failproofai/policies/`: | المستوى | الدليل | النطاق | -|-------|---------|-------| -| المشروع | `.failproofai/policies/` | مشاركة مع الفريق عبر مراقبة الإصدار | +|-------|-----------|-------| +| المشروع | `.failproofai/policies/` | مشاركة مع الفريق عبر التحكم في الإصدار | | المستخدم | `~/.failproofai/policies/` | شخصي، ينطبق على جميع المشاريع | -**مطابقة الملفات:** يتم تحميل الملفات فقط التي تتطابق مع `*policies.{js,mjs,ts}` (مثلاً `security-policies.mjs`, `workflow-policies.js`). تُتجاهل الملفات الأخرى في الدليل. +**مطابقة الملفات:** يتم تحميل الملفات المطابقة لـ `*policies.{js,mjs,ts}` فقط (على سبيل المثال `security-policies.mjs`، `workflow-policies.js`). يتم تجاهل الملفات الأخرى في الدليل. -**لا حاجة لإعدادات:** سياسات الاتفاقية لا تتطلب إدخالات في `policies-config.json`. فقط ضع ملفات في الدليل وسيتم التقاطها في حدث الخطاف التالي. +**لا يوجد تكوين مطلوب:** سياسات الاتفاقية لا تتطلب إدخالات في `policies-config.json`. فقط قم بإسقاط الملفات في الدليل وسيتم التقاطها على حدث hook التالي. -**تحميل الاتحاد:** يتم البحث في دلائل الاتفاقية للمشروع والمستخدم. يتم تحميل جميع الملفات المطابقة من كلا المستويين (على عكس `customPoliciesPath` الذي يستخدم أول نطاق يفوز). +**تحميل الاتحاد:** يتم مسح أدلة الاتفاقية للمشروع والمستخدم. يتم تحميل جميع ملفات المطابقة من كلا المستويين (على عكس `customPoliciesPath` الذي يستخدم أول نطاق يفوز). -انظر [السياسات المخصصة](/ar/custom-policies) لمزيد من التفاصيل والأمثلة. +اطلع على [السياسات المخصصة](/ar/custom-policies) للحصول على المزيد من التفاصيل والأمثلة. ### `llm` النوع: `object` (اختياري) -إعدادات عميل LLM للسياسات التي تقوم بعمليات استدعاء ذكية. غير مطلوبة لمعظم الإعدادات. +تكوين عميل LLM للسياسات التي تجري استدعاءات AI. غير مطلوب لمعظم الإعدادات. ```json { @@ -188,22 +188,26 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← ينتقل إلى ا --- -## إدارة الإعدادات من سطر الأوامر +## إدارة التكوين من سطر الأوامر -تقوم أوامر `policies --install` و `policies --uninstall` بالكتابة إلى ملف إعدادات خطاف عميل الوكيل (نقاط دخول الخطاف)، بينما `policies-config.json` هو الملف الذي تديره مباشرة. الاثنان منفصلان: +تكتب أوامر `policies --install` و `policies --uninstall` إلى ملف إعدادات hook لعميل agent CLI الخاص بك (نقاط دخول hook)، بينما `policies-config.json` هو الملف الذي تديره مباشرة. الاثنان منفصلان: -- **إعدادات عميل الوكيل** — يخبر الوكيل باستدعاء `failproofai --hook ` في كل استخدام أداة: - - **Claude Code**: `~/.claude/settings.json` (مستخدم), `/.claude/settings.json` (مشروع), `/.claude/settings.local.json` (محلي) - - **OpenAI Codex**: `~/.codex/hooks.json` (مستخدم), `/.codex/hooks.json` (مشروع) — Codex ليس له نطاق محلي - - **GitHub Copilot CLI _(نسخة تجريبية)_**: `~/.copilot/hooks/failproofai.json` (مستخدم), `/.github/hooks/failproofai.json` (مشروع) — Copilot ليس له نطاق محلي. إدخالات الخطاف تستخدم حقول أوامر Copilot المفتاحة بنظام التشغيل `bash`/`powershell` مع `timeoutSec`؛ يحمل الملف علامة `version: 1` على المستوى الأعلى. دعم GitHub Copilot CLI **نسخة تجريبية** بينما نتحقق من مخطط سجل `events.jsonl` (الذي لا تحدده المستندات العامة) مقابل جلسات حقيقية أكثر. - - **Cursor Agent _(نسخة تجريبية)_**: `~/.cursor/hooks.json` (مستخدم), `/.cursor/hooks.json` (مشروع) — Cursor ليس له نطاق محلي. إدخالات الخطاف تستخدم نموذج `{type, command, timeout}` على شكل Claude (لا انقسام `bash`/`powershell`)، لكن يتم تخزينها تحت مفاتيح أحداث camelCase (`preToolUse`, `beforeSubmitPrompt`, …) في مصفوفة مسطحة وفقاً [لمخطط الخطافات](https://cursor.com/docs/hooks) الخاص بـ Cursor؛ يحمل الملف علامة `version: 1` على المستوى الأعلى. يقوم المعالج بتحويل camelCase → PascalCase عبر `CURSOR_EVENT_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. دعم Cursor Agent **نسخة تجريبية** بينما نتحقق من نسخة Cursor على القرص (غير محددة في المستندات العامة) مقابل عمليات تثبيت حقيقية أكثر. - - **OpenCode _(نسخة تجريبية)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (مستخدم), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (مشروع) — OpenCode ليس له نطاق محلي. على عكس المحررات الستة الأخرى، OpenCode **ليس له نظام خطاف أوامر خارجية**: يحمل في الذاكرة مكوّنات JavaScript/TypeScript مسجلة بشكل صريح عبر مصفوفة `plugin: []` في `opencode.json` (الاكتشاف التلقائي من `.opencode/plugins/` **ليس** كيف يتم تحميل المكونات على opencode v1.14.33). التثبيت ينقط مكون شيم صغير يستدعي ثنائي failproofai عبر subprocess ويترجم استجابة JSON على شكل Claude الخاصة بالثنائي إلى دلالات المكون: `throw new Error()` لرفض حدث الأداة (يلغي استدعاء الأداة)، `client.session.prompt(...)` للتعليمات **و** لرفض `Stop` / `SubagentStop` (يرسل سبب الرفض كرسالة المستخدم التالية — القناة الوحيدة للإعادة القسرية منذ أن `session.idle` إخطار فقط والرمي منه لا يعمل)، بدون عملية للسماح. يقوم الشيم بتحويل أسماء الأدوات (lowercase → PascalCase عبر `OPENCODE_TOOL_MAP`) ومفاتيح حجج إدخال الأداة (camelCase → snake_case عبر `OPENCODE_TOOL_INPUT_MAP` لـ `Read` / `Write` / `Edit`، مثلاً `filePath` → `file_path`, `oldString` → `old_string`) قبل إعادة التوجيه إلى الثنائي، بحيث تعمل عمليات التحقق من المسارات المدمجة مثل `block-read-outside-cwd`, `block-env-files`, و `block-secrets-write` بدون تغيير على استدعاءات أداة OpenCode. الجلسات تعيش في قاعدة بيانات OpenCode SQLite في `~/.local/share/opencode/opencode.db`؛ عارض الجلسات في لوحة التحكم يقرأها عبر `opencode db --format json` و `opencode export `. دعم OpenCode **نسخة تجريبية** بينما نتحقق من السلوك عبر الإصدارات ومقابل جلسات حقيقية أكثر. انظر [مستندات مكونات OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(نسخة تجريبية)_**: `~/.pi/agent/settings.json` (مستخدم), `/.pi/settings.json` (مشروع) — Pi ليس له نطاق محلي. يحمل Pi حزم ملحقات TypeScript عند البدء؛ ملف الإعدادات مصفوفة نصية مسطحة `{"packages": ["./relative/path", …]}`. يكتب failproofai إدخالة مصفوفة حزم واحدة تشير إلى دليل `pi-extension/` المجمع الخاص به. يشترك الملحق داخلياً في أحداث Pi `tool_call` / `user_bash` / `input` / `session_start` ويقذف إلى `failproofai --hook --cli pi`؛ يقوم المعالج بتحويل underscore_lower_snake_case → PascalCase عبر `PI_EVENT_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. يتم أيضاً تحويل حجج إدخال الأداة عبر `PI_TOOL_INPUT_MAP` (تسليم Pi للقراءة / الكتابة / التحرير `path` بدلاً من `file_path`؛ تعيين المفتاح على المستوى الأعلى يسمح بتشغيل `block-env-files` و `block-secrets-write` — `block-read-outside-cwd` كان لديه بالفعل بديل `path`). دعم Pi **نسخة تجريبية** بينما تستقر ملحقات Pi API وتخطيط سجل الجلسة. - - **Gemini CLI _(نسخة تجريبية)_**: `~/.gemini/settings.json` (مستخدم), `/.gemini/settings.json` (مشروع) — Gemini ليس له نطاق محلي (يوثق نطاق `system` على `/etc/gemini-cli/settings.json` الذي لا يعرضه failproofai). إدخالات الخطاف تستخدم نموذج Claude `{type, command, timeout}` ملفوف في مخطط مطابق Gemini `{matcher, hooks: [...]}` مع `matcher: "*"` افتراضياً. الأحداث تكون PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); يقوم المعالج بالتعيين إلى أسماء Claude الأساسية عبر `GEMINI_EVENT_MAP`. أسماء الأدوات تكون snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — يقوم المعالج بتحويلها عبر `GEMINI_TOOL_MAP` بحيث تعمل السياسات المدمجة الموجودة بدون تغيير. يصدر محقق السياسة شكل Gemini المسطح `{decision: "deny", reason}` (مفضل وفقاً لـ Golden Rule للخروج-0 من Gemini)، `{hookSpecificOutput: {hookEventName, additionalContext}}` لحقن السياق على BeforeAgent / AfterTool / SessionStart، و `{decision: "block", reason}` على AfterAgent لدلالات الإعادة القسرية. دعم Gemini CLI **نسخة تجريبية** بينما نوسع التغطية الحقيقية. انظر [مستندات خطافات Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**نطاق المستخدم فقط** — Hermes ليس له إعدادات المشروع/المحلي). Hermes هو **بوابة** Slack/Telegram، لذلك تثبيت واحد يعترض استدعاءات الأدوات من كل منصة (Slack/Telegram/cli/cron) **و** الوكلاء الفرعيين الداخليين. إدخالات الخطاف هي زوج `{command, timeout}` (المهلة الزمنية **بالثواني**) تحت خريطة `hooks:` مفتاحها بأحداث snake_case من Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); يقوم المعالج بتحويل الأحداث عبر `HERMES_EVENT_MAP` وأسماء الأدوات عبر `HERMES_TOOL_MAP` بحيث تعمل السياسات المدمجة بدون تغيير. يتم تحرير الإعدادات من خلال استدارة YAML `Document` حفاظاً على التعليقات بحيث تبقى الإعدادات الأخرى للمشغل، والتثبيت يعيّن `hooks_auto_accept: true` بحيث تعمل بوابة بدون رأس (لا TTY) الخطافات بدون موجه موافقة. يصدر المقيّم عقد stdout الخاص بـ Hermes `{"decision":"block","reason"}` (يتجاهل Hermes أكواد الخروج). **القيود:** Hermes ليس له حدث نهاية الدور `Stop`، لذا فإن المدمجات `require-*-before-stop` لن تعمل أبداً لـ Hermes (غير قابلة للتطبيق، وليس كسر)؛ `instruct` تنخفض إلى السماح مع ملاحظة مسجلة (لا قناة سياق إضافية)؛ وإعادة تسمية سرية الإخراج (`sanitize-*`) لا يمكن إعادة كتابة إخراج الأداة على عقد shell-hook. Hermes هو **أيضاً** مصدر **تدقيق** غير متصل — لوحة التحكم تقرأ جلسات بوابتها مباشرة من `~/.hermes/state.db`. -- **`policies-config.json`** — يخبر failproofai بالسياسات التي يجب تقييمها وبأية معاملات (مشاركة عبر جميع عملاء الوكيل) +- **إعدادات Agent CLI** — يخبر الوكيل باستدعاء `failproofai --hook ` على كل استخدام أداة: + - **Claude Code**: `~/.claude/settings.json` (مستخدم)، `/.claude/settings.json` (مشروع)، `/.claude/settings.local.json` (محلي) + - **OpenAI Codex**: `~/.codex/hooks.json` (مستخدم)، `/.codex/hooks.json` (مشروع) — لا يوجد نطاق `محلي` في Codex + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (مستخدم)، `/.github/hooks/failproofai.json` (مشروع) — لا نطاق `محلي` في Copilot. إدخالات Hook تستخدم حقول الأوامر `bash`/`powershell` المعروفة بنظام التشغيل في Copilot مع `timeoutSec`؛ يحتمل الملف على علامة `version: 1` على المستوى الأعلى. دعم Copilot CLI هو **beta** بينما نتحقق من مخطط سجل `events.jsonl` (الذي لا تحدده الوثائق العامة) مقابل جلسات عملية أكثر. **وضع عميل VS Code Copilot Chat (معاينة)** يقرأ تكوينات hook من `.github/hooks/*.json`، `~/.copilot/hooks/*.json`، و `~/.claude/settings.json` (يحكمها الإعداد `chat.hookFilesLocations`) باستخدام نفس عقد Claude المشكل `{hookSpecificOutput:{permissionDecision:"deny",…}}` — المسارات الدقيقة التي يكتبها تكامل `copilot` وتكامل `claude` (`~/.claude/settings.json`) بالفعل، لذا `failproofai policies --install --cli copilot` (أو `--cli claude`) **بالفعل ينفذ في وضع عميل VS Code** بدون تكامل `vscode` منفصل (تم تأكيده مباشرة من سجلات اكتشاف VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (مستخدم)، `/.cursor/hooks.json` (مشروع) — لا نطاق `محلي` في Cursor. إدخالات Hook تستخدم شكل Claude `{type, command, timeout}` (بدون تقسيم `bash`/`powershell`)، لكن مخزنة تحت مفاتيح حدث camelCase (`preToolUse`، `beforeSubmitPrompt`، ...) في مصفوفة مسطحة لكل مخطط hooks في Cursor؛ يحمل الملف علامة `version: 1` على المستوى الأعلى. يقوم المعالج بتطبيع camelCase → PascalCase عبر `CURSOR_EVENT_MAP` بحيث تطلق السياسات المدمجة الموجودة دون تغيير. دعم Cursor Agent هو **beta** بينما نتحقق من نسخة Cursor على القرص (غير محددة في الوثائق العامة) مقابل عمليات تثبيت عملية أكثر. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (مستخدم)، `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (مشروع) — لا نطاق `محلي` في OpenCode. بخلاف CLIs الخمسة الأخرى، OpenCode ليس لديه **نظام hook أوامر خارجية**: يحمل مكونات إضافية JS/TS في العملية مسجلة بشكل صريح عبر مصفوفة `plugin: []` في `opencode.json` (الاكتشاف التلقائي من `.opencode/plugins/` **ليس** كيفية تحميل المكونات الإضافية على opencode v1.14.33). يسقط التثبيت شيم مكون إضافي صغير محمول يستدعي استدعاء فرعي ملف ثنائي failproofai ويرجع استجابة JSON على شكل Claude للدلالات المكون الإضافي: `throw new Error()` لإنكار حدث أداة (يلغي استدعاء الأداة)، `client.session.prompt(...)` للتعليمات **و** لإنكار `Stop` / `SubagentStop` (يقدم سبب الإنكار كرسالة المستخدم التالية — القناة الوحيدة لإعادة المحاولة القسرية حيث أن `session.idle` ملاحظة فقط والرمي منها عدم عملية)، وبدون عملية للسماح. يقوم الشيم بتطبيع أسماء الأدوات (الأحرف الصغيرة → PascalCase عبر `OPENCODE_TOOL_MAP`) ومفاتيح حجج الإدخال (camelCase → snake_case عبر `OPENCODE_TOOL_INPUT_MAP` لـ `Read` / `Write` / `Edit`، على سبيل المثال `filePath` → `file_path`، `oldString` → `old_string`) قبل الإرسال للملف الثنائي، بحيث تطلق الوحدات المدمجة التي تتحقق من المسارات مثل `block-read-outside-cwd`، `block-env-files`، و `block-secrets-write` بدون تغيير على استدعاءات أدوات OpenCode. تعيش الجلسات في قاعدة بيانات SQLite في opencode على `~/.local/share/opencode/opencode.db`؛ عارض الجلسات في لوحة التحكم يقرأها عبر `opencode db --format json` و `opencode export `. دعم OpenCode هو **beta** بينما نتحقق من السلوك عبر الإصدارات ومقابل جلسات عملية أكثر. اطلع على [وثائق مكونات OpenCode الإضافية](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (مستخدم)، `/.pi/settings.json` (مشروع) — لا نطاق `محلي` في Pi. يحمل Pi حزم تمديد TypeScript عند بدء التشغيل؛ ملف الإعدادات هو مصفوفة سلسلة مسطحة `{"packages": ["./relative/path", …]}`. يكتب failproofai إدخال مصفوفة حزم واحد يشير إلى دليله الموزع `pi-extension/`. يشترك المكون الإضافي داخلياً في أحداث `tool_call` / `user_bash` / `input` / `session_start` في Pi ويقوم بتشغيل فرعي إلى `failproofai --hook --cli pi`؛ يقوم المعالج بتطبيع underscore_lower_snake_case → PascalCase عبر `PI_EVENT_MAP` بحيث تطلق السياسات المدمجة الموجودة دون تغيير. يتم أيضاً تطبيع حجج إدخال الأداة عبر `PI_TOOL_INPUT_MAP` (يسلم Pi `path` بدلاً من `file_path`؛ تعيين المفتاح على المستوى الأعلى يتيح `block-env-files` و `block-secrets-write` - `block-read-outside-cwd` كان بالفعل لديه احتياطي `path`). دعم Pi هو **beta** بينما يستقر API التمديد في Pi وتخطيط السجل على القرص. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**نطاق المستخدم فقط** — Hermes ليس لديه تكوين مشروع/محلي). Hermes بوابة **Slack/Telegram**، لذا يعترض تثبيت واحد استدعاءات أداة من كل منصة (Slack/Telegram/cli/cron) **و** الوكلاء الفرعيين الداخليين. إدخالات Hook هي زوج `{command, timeout}` (المهلة الزمنية بـ **ثوان**) تحت خريطة `hooks:` مفتاحها بأحداث snake_case في Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`)؛ يقوم المعالج بتطبيع الأحداث عبر `HERMES_EVENT_MAP` وأسماء الأدوات عبر `HERMES_TOOL_MAP` بحيث تطلق السياسات المدمجة بدون تغيير. يتم تعديل التكوين من خلال دورة YAML `Document` التي تحتفظ بالتعليقات بحيث تبقى إعدادات المشغل الأخرى، ويعين التثبيت `hooks_auto_accept: true` بحيث تعمل البوابة بدون رأس (بدون TTY) الخطافات دون موجه موافقة. يصدر المقيّم عقد Hermes `{"decision":"block","reason"}` stdout (تتجاهل Hermes رموز الخروج). **القيود:** Hermes ليس لديها حدث `Stop` في نهاية المنعطف، لذا يتم إطلاق الوحدات المدمجة `require-*-before-stop` مطلقاً (غير قابلة للتطبيق، وليس معطلة)؛ `instruct` يتضاءل إلى السماح برسالة مسجلة (بدون قناة سياق إضافية)؛ وإعادة تحرير سر الإخراج (`sanitize-*`) لا يمكنها إعادة كتابة إخراج الأداة عبر عقد shell-hook. Hermes هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ جلسات البوابة مباشرة من `~/.hermes/state.db`. + - **OpenClaw (openClaw gateway)**: `~/.openclaw/openclaw.json` (**نطاق المستخدم فقط** — OpenClaw ليس لديه تكوين مشروع/محلي). مثل Hermes، OpenClaw هو بوابة متعددة القنوات ذاتية الاستضافة **، لذا يعترض تثبيت واحد استدعاءات أداة من كل قناة والوكلاء الفرعيين الداخليين. يتم تشغيل الإنفاذ من خلال خطافات **في العملية** في OpenClaw (خطافات الملفات الداخلية هي ملاحظة فقط ولا يمكنها الحجب)، لذا - مثل OpenCode/Pi - يشحن failproofai حزمة ثابتة `openclaw-plugin/` تشغل بشكل متزامن الملف الثنائي failproofai وترجم الحكم. يسجل التثبيت دليل البرنامج الإضافي المشحون في `openclaw.json`'s `plugins.load.paths[]` وتمكنه تحت `plugins.entries.failproofai` (مع `hooks.allowConversationAccess: true`، مطلوب لخطافات المحادثة الخام). يصدر المقيّم حكم مسطح `{permission, reason}` ويعيّن الشيم خريطته إلى شكل عودة كل خطاف: `before_tool_call → {block:true, blockReason}` (**PreToolUse**)، `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**)، و `before_agent_finalize → {action:"revise", reason}` (**Stop** — بوابة نهاية منعطف حقيقية، بحيث **تنفذ** الوحدات المدمجة `require-*-before-stop` على OpenClaw، على عكس Hermes). الأحداث وأسماء الأدوات قانونية على جانب ثنائي عبر `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`، `read→Read`، ...) بحيث تطلق السياسات المدمجة بدون تغيير؛ يفشل الشيم بشكل مفتوح على أي خطأ spawn/parse/timeout. OpenClaw هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ جلسات JSONL الخاصة به على `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (مستخدم)، `/.factory/hooks.json` (مشروع) — Factory ليس لديه نطاق `محلي`. يشحن droid نظام hook أمر خارجي بشكل Claude، لكن مع اثنين من الغرائب التي تم التحقق منها مباشرة ضد droid v0.171.0: (1) أسماء الأحداث تعيش على **المستوى الأعلى** من `hooks.json` — **لا توجد غلاف `"hooks"`** (droid يرفض واحد)؛ أحداث الأداة (`PreToolUse`/`PostToolUse`) تحمل `"matcher": "*"`، الأحداث غير الأداة تحذفها. (2) يتم التحكم في الإنكار بخروج **hook 2 + stderr**، وليس قرار JSON — فرع `factory` للمقيّم يعود الخروج 2 لأحداث الأداة/الموجه و `{decision:"block", reason}` فقط على حدث التشغيل `Stop` (القناة الوحيدة لإعادة محاولة قسرية في droid). الأحداث بالفعل PascalCase (لا خريطة أحداث) والحمولة Claude snake_case؛ فقط أسماء الأدوات قانونية عبر `FACTORY_TOOL_MAP` (`Execute→Bash`، `Create→Write`، `FetchUrl→WebFetch`، ...). Factory هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ جلسات JSONL على القرص الخاصة به على `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (مستخدم)، `/.devin/config.json` (مشروع) — Devin ليس لديه نطاق `محلي`. Devin هو **نسخة مستنسخة من Claude نقية** تم التحقق منها مباشرة ضد devin v3000.1.27: يستخدم مخطط `"hooks"`-wrapper القياسي Claude (الكتابات تحافظ على الدمج بحيث تبقى المفاتيح الأخرى في ملف التكوين — `org_id`، `theme_mode`، ...) أسماء الأحداث بالفعل PascalCase (لا خريطة أحداث، لا فرع معالج)، وحمولة stdin Python snake_case (لا تطبيع). فرع `devin` للمقيّم يرفض بـ `{"decision":"block","reason"}` JSON على stdout عند الخروج 0 لـ **كل** حدث (تم التحقق — الكتلة أعادت تعيين `--permission-mode dangerous`)؛ على حدث نهاية المنعطف `Stop` يحمل السبب صياغة الإجراء الإجباري لإعادة المحاولة بحيث **تنفذ** الوحدات المدمجة `require-*-before-stop`. يتم تطبيع فقط أسماء الأدوات عبر `DEVIN_TOOL_MAP` (`exec→Bash`؛ `tool_input.command` بالفعل قانونية). Devin هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ جلسات SQLite الخاصة به على `~/.local/share/devin/cli/sessions.db` (كل صف `sessions` يحمل `working_directory` حقيقي، لذا تجمع الجلسات حسب مشروع cwd مثل Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (مستخدم)، `/.agents/hooks.json` (مشروع) — Antigravity ليس لديه نطاق `محلي`. بخلاف Factory/Devin، Antigravity لديها **عقدها الخاص** (ليس نسخة مستنسخة من Claude)، التحقق منها مباشرة ضد agy v1.1.2. `hooks.json` يستخدم **مخطط hook بالاسم**: المفتاح على المستوى الأعلى هو اسم hook *name* (`"failproofai"`) التي قيمتها خريطة أحداث → معالجات — تغلف أحداث الأداة (`PreToolUse`/`PostToolUse`) معالجات في `{matcher:"*", hooks:[…]}`، بينما `PreInvocation`/`Stop` هي **مسطحة** مصفوفات معالج (يتم الاحتفاظ بخطافات بأسماء أخرى). حمولة stdin هي **protojson camelCase** (`toolCall:{name,args}`، `conversationId`، `workspacePaths`، `transcriptPath`) — يقوم failproofai بتطبيعها إلى snake_case قبل تشغيل السياسات، ويعيّن أسماء args PascalCase `run_command` (`CommandLine`/`Cwd`) عبر `ANTIGRAVITY_TOOL_INPUT_MAP`. فرع `antigravity` للمقيّم يستخدم أشكال استجابة **خاصة بـ Antigravity**: `{decision:"deny", reason}` يحجب أداة/موجه (خروج 0)، `{decision:"continue", reason}` على حدث `Stop` في نهاية المنعطف يعيد دخول الحلقة (بحيث **تنفذ** الوحدات المدمجة `require-*-before-stop`)، و `{injectSteps:[{ephemeralMessage}]}` حقن تعليمات على `PreInvocation` (→ `UserPromptSubmit`). تقانون أسماء الأدوات عبر `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`، `view_file→Read`، ...). Antigravity هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ نصوصها JSONL العادية على `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (فهرس المحادثة في `conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (مستخدم)، `/.agents/plugins/failproofai/hooks/hooks.json` (مشروع) — Goose ليس لديه نطاق `محلي`. يستخدم الإنفاذ نظام **خطافات** Goose، المواصفات **Open Plugins** بين الوكلاء: يقوم المثبت بإسقاط دليل `failproofai` البرنامج الإضافي فقط و Goose اكتشاف ذاتي عند بدء التشغيل (تسجيل ذاتي في `~/.config/goose/config.yaml`). يستخدم `hooks.json` مخطط **Open Plugins** مع غلاف `"hooks"` على المستوى الأعلى، والمطابق **محذوف** على كل حدث — `"*"` مجردة تنظيم معاد غير صالح يطابق لا شيء (تم التحقق منها مباشرة ضد goose v1.43.0). أسماء الأحداث بالفعل PascalCase (لا خريطة أحداث)؛ حمولة stdin تستخدم `event`/`working_dir`، التي يقوم المعالج بتطبيعها إلى `hook_event_name`/`cwd`. فرع `goose` للمقيّم يرفض بـ `{"decision":"block","reason"}` JSON على stdout عند الخروج 0، محترم على حدث **`PreToolUse`** فقط (يشحن في goose ≥ v1.37.0) — الذي يطلق لأداة shell **و داخل وكلاء فرعيين مفوضين**، لذا إنه نقطة رفض كافية واحدة؛ أي خطأ خطاف آخر يفشل **مفتوح**. Goose ليس لديها حدث **`Stop`**، بحيث لا تنطبق الوحدات المدمجة `require-*-before-stop` (كما هو الحال مع Hermes). تقانون أسماء الأدوات عبر `GOOSE_TOOL_MAP` (`shell→Bash`، `write→Write`، `todo__todo_write→TodoWrite`، ...) ومفاتيح المسار عبر `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose هو **أيضاً** مصدر **تدقيق** بدون اتصال — لوحة التحكم تقرأ جلسات SQLite الخاصة به على `~/.local/share/goose/sessions/sessions.db` (كل صف `sessions` يحمل `working_dir` حقيقي، بحيث تجمع الجلسات حسب مشروع cwd مثل Devin؛ الجريان `--no-session` يتم تصفيتها). +- **`policies-config.json`** — يخبر failproofai أي السياسات المراد تقييمها وبأي معاملات (مشاركة عبر جميع CLIs الوكيل) -مرر `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` لاستهداف وكيل محدد (مفصول بمسافات أو متكرر لأي مجموعة فرعية): +مرر `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` للاستهداف وكيل معين (مفصول بالمسافة أو مكرر لأي مجموعة فرعية): ```bash failproofai policies --install --cli codex --scope project @@ -211,25 +215,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -عندما يتم حذف `--cli`، يكتشف failproofai عملاء الوكيل المثبتة (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +عندما يتم حذف `--cli`، يكتشف failproofai أي CLI وكيل يتم تثبيتها (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **تم اكتشاف عميل واحد** — يختار ذلك العميل تلقائياً بدون فور. -- **عملاء متعددة مكتشفة** في محطة طرفية تفاعلية — يعرض موجه اختيار مفرد بمفاتيح الأسهم مجمع في قسم `Detected (N)` (مع صف إجمالي للتثبيت لكل عميل مكتشفة N + كل عميل مكتشفة بشكل فردي) وقسم `Not installed (M) · install hooks ahead of time` يسرد كل عميل مكتشفة مدعومة كخيار تثبيت آجل (↑↓ للتحريك، أدخل للاختيار، ^C للخروج). يعرض تدفق الإلغاء قسم Detected فقط. -- **عملاء متعددة مكتشفة** في تشغيل غير تفاعلي (CI، لا TTY) — يثبت لجميع العملاء المكتشفة بدون فور. -- **لم يتم اكتشاف أي** — ينخفض إلى `claude`، مع تحذير بأنه لم يتم العثور على ثنائي وكيل في PATH؛ أمر الخطاف لا يزال مكتوباً بحيث ينشط بمجرد تثبيت واحد. +- **اكتشف CLI واحد** — يختار ذلك CLI تلقائياً دون موجه. +- **عدة CLIs مكتشفة** في محطة تفاعلية — يظهر موجه تحديد مفتاح أسهم مجمع في قسم `Detected (N)` (مع صف دمج `Install for all N detected` + كل CLI مكتشف بشكل فردي) وقسم `Not installed (M) · install hooks ahead of time` يسرد كل CLI مدعوم غير مكتشف كخيار تثبيت إلى الأمام (↑↓ للانتقال، Enter لتحديد، ^C للخروج). تظهر منطقة إلغاء التثبيت قسم الاكتشاف فقط. +- **عدة CLIs مكتشفة** في تشغيل غير تفاعلي (CI، بدون TTY) — يثبت لجميع CLIs المكتشفة دون موجه. +- **لم يتم الكشف عن أي** — يعود إلى `claude`، مع تحذير من أن لا تم العثور على ثنائي وكيل في PATH؛ أمر hook لا يزال مكتوب بحيث يتنشط بمجرد تثبيت واحد. -يمكنك تحرير `policies-config.json` مباشرة في أي وقت؛ التغييرات تصبح نافذة فوراً في حدث الخطاف التالي بدون حاجة إلى إعادة تشغيل. +يمكنك تحرير `policies-config.json` مباشرة في أي وقت؛ تحدث التغييرات تأثير فوراً على حدث hook التالي بدون الحاجة إلى إعادة تشغيل. --- -## مثال: إعدادات على مستوى المشروع مع إعدادات افتراضية للفريق +## مثال: تكوين على مستوى المشروع مع إعدادات الفريق -التزم `.failproofai/policies-config.json` بمستودعك: +التزم `.failproofai/policies-config.json` إلى مستودعك: ```json { @@ -248,4 +256,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -يمكن لكل مطور بعد ذلك إنشاء `.failproofai/policies-config.local.json` (مستبعد من git) لتجاوزات شخصية بدون التأثير على زملائك. \ No newline at end of file +يمكن لكل مطور بعد ذلك إنشاء `.failproofai/policies-config.local.json` (مدرج في gitignore) لتجاوزات شخصية دون التأثير على زملائك. \ No newline at end of file diff --git a/docs/ar/dashboard.mdx b/docs/ar/dashboard.mdx index fc2633a9..a7848a1b 100644 --- a/docs/ar/dashboard.mdx +++ b/docs/ar/dashboard.mdx @@ -1,10 +1,11 @@ --- +--- title: لوحة التحكم -description: "راقب جلسات الوكيل، واستعرض استدعاءات الأدوات، وأدر السياسات" +description: "مراقبة جلسات الوكيل، ومراجعة استدعاءات الأدوات، وإدارة السياسات" icon: chart-line --- -لوحة التحكم failproofai عبارة عن تطبيق ويب محلي لمراقبة جلسات وكيل الذكاء الاصطناعي الخاص بك وإدارة السياسات. اطّلع على ما فعله وكلاؤك أثناء غيابك. +لوحة تحكم failproofai هي تطبيق ويب محلي لمراقبة جلسات وكيل الذكاء الاصطناعي الخاص بك وإدارة السياسات. انظر ما فعله وكلاؤك أثناء غيابك. --- @@ -14,9 +15,9 @@ icon: chart-line failproofai ``` -يتم فتحها في `http://localhost:8020`. +يفتح في `http://localhost:8020`. -تقرأ لوحة التحكم مباشرة من نظام الملفات - مجلدات مشاريع Claude Code وملفات إعدادات failproofai. لا يتم كتابة أي شيء إلى خدمة بعيدة. +تقرأ لوحة التحكم مباشرة من نظام الملفات - مجلدات مشاريع Claude Code وملفات تكوين failproofai. لا يتم كتابة أي شيء إلى خدمة بعيدة. --- @@ -24,81 +25,81 @@ failproofai ### المشاريع -يسرد جميع مشاريع Claude Code و OpenAI Codex و GitHub Copilot CLI _(إصدار تجريبي)_ و Cursor Agent _(إصدار تجريبي)_ و OpenCode _(إصدار تجريبي)_ و Pi _(إصدار تجريبي)_ و Gemini CLI _(إصدار تجريبي)_ و Hermes الموجودة على جهازك. يتم اكتشاف مشاريع Claude من `~/.claude/projects/` (أو المسار المحدد بواسطة `CLAUDE_PROJECTS_PATH`); يتم اكتشاف مشاريع Codex بمسح كل نص تحت `~/.codex/sessions///
/*.jsonl` وتجميعها حسب `cwd` المسجل في السجل الأول من كل جلسة; يتم اكتشاف مشاريع Copilot CLI بمسح كل `~/.copilot/session-state//workspace.yaml` (قابل للتكوين عبر `COPILOT_HOME`) وتجميعها حسب حقل `cwd` الخاص به; يتم اكتشاف مشاريع Cursor Agent بمسح البيانات الفوقية لكل جلسة تحت `~/.cursor/agent-sessions//` (قابل للتكوين عبر `CURSOR_HOME`، مع اختبار `conversations/` و `sessions/` كبدائل) للبحث عن `cwd` في `meta.json` / `session.json` / `workspace.yaml`; يتم اكتشاف مشاريع OpenCode بالاستعلام عن قاعدة بيانات SQLite الخاصة به في `~/.local/share/opencode/opencode.db` عبر `opencode db --format json` (نحن نقرأ الجداول `session` و `project` ونجمعها حسب `project_id`); يتم اكتشاف مشاريع Pi بمسح نصوص JSONL لكل جلسة تحت `~/.pi/agent/sessions//_.jsonl` (قابل للتكوين عبر `PI_SESSIONS_DIR`) واستخراج `cwd` من السجل الأول من كل جلسة; يتم اكتشاف مشاريع Gemini CLI بمسح `~/.gemini/tmp//chats/session--.jsonl` (قابل للتكوين عبر `GEMINI_SESSIONS_DIR`) واسترجاع cwd القانوني من علامة النص المجاورة `.project_root`; تتم قراءة جلسات بوابة Hermes مباشرة من متجرها SQLite في `~/.hermes/state.db` (قابل للتكوين عبر `HERMES_DB_PATH`) وتجميعها في مشاريع `hermes-` حسب `source` (Slack/Telegram/cli/cron — جلسات البوابة لا تحتوي على cwd). يتم عرض المشروع الذي تم استخدامه بواسطة عدة CLIs كصف واحد مع جميع الشارات المطابقة. استخدم القائمة المنسدلة **CLI** فوق الجدول للتصفية حسب CLI وكيل معين; يحافظ عنوان URL على اختيارك كـ `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +يسرد جميع مشاريع Claude Code و OpenAI Codex و GitHub Copilot CLI _(beta)_ و Cursor Agent _(beta)_ و OpenCode _(beta)_ و Pi _(beta)_ و Hermes و OpenClaw و Factory Droid و Devin و Antigravity و Goose الموجودة على جهازك. يتم اكتشاف مشاريع Claude من `~/.claude/projects/` (أو المسار المحدد بواسطة `CLAUDE_PROJECTS_PATH`); يتم اكتشاف مشاريع Codex من خلال مسح كل نسخة من `~/.codex/sessions///
/*.jsonl` وتجميعها حسب `cwd` المسجل في السجل الأول لكل جلسة; يتم اكتشاف مشاريع Copilot CLI من خلال مسح كل `~/.copilot/session-state//workspace.yaml` (قابلة للتكوين عبر `COPILOT_HOME`) وتجميعها حسب حقل `cwd`; يتم اكتشاف مشاريع Cursor Agent من خلال مسح بيانات التعريف لكل جلسة تحت `~/.cursor/agent-sessions//` (قابلة للتكوين عبر `CURSOR_HOME`، مع `conversations/` و `sessions/` كخيارات احتياطية) بحثاً عن `cwd` سلمي في `meta.json` / `session.json` / `workspace.yaml`; يتم اكتشاف مشاريع OpenCode من خلال الاستعلام عن قاعدة بيانات SQLite الخاصة به في `~/.local/share/opencode/opencode.db` عبر `opencode db --format json` (نقرأ جداول `session` و `project` ونجمعها حسب `project_id`); يتم اكتشاف مشاريع Pi من خلال مسح نسخ JSONL لكل جلسة تحت `~/.pi/agent/sessions//_.jsonl` (قابلة للتكوين عبر `PI_SESSIONS_DIR`) واستخراج `cwd` من السجل الأول لكل جلسة; يتم قراءة جلسات بوابة Hermes مباشرة من متجرها SQLite في `~/.hermes/state.db` (قابلة للتكوين عبر `HERMES_DB_PATH`) وتجميعها إلى مشاريع `hermes-` حسب `source` (Slack/Telegram/cli/cron — لا توجد jلسات البوابة cwd); يتم قراءة جلسات بوابة OpenClaw من `~/.openclaw/agents//sessions/*.jsonl` وتجميعها إلى مشاريع `openclaw-` (أيضاً بدون cwd); يتم اكتشاف مشاريع Factory Droid من نسخ JSONL في `~/.factory/sessions//*.jsonl` وتجميعها حسب cwd; مشاريع Devin من قاعدة بيانات SQLite الخاصة به في `~/.local/share/devin/cli/sessions.db` (مجمعة حسب `working_directory` لكل جلسة); مشاريع Antigravity من نسخ JSONL في `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` ومجمعة حسب cwd; ومشاريع Goose من قاعدة بيانات SQLite الخاصة به في `~/.local/share/goose/sessions/sessions.db` (مجمعة حسب `working_dir` لكل جلسة). يتم عرض المشروع الذي تم استخدامه بواسطة عدة CLIs كصف واحد مع جميع الشارات المطابقة. استخدم القائمة المنسدلة **CLI** فوق الجدول للتصفية حسب CLI وكيل محدد; يحتفظ URL بقائمتك كـ `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. يعرض كل مشروع: - اسم المشروع (مشتق من مسار المجلد) -- شارة CLI — `Claude Code` (برتقالي)، `OpenAI Codex` (بنفسجي)، `GitHub Copilot` (أزرق)، `Cursor Agent` (زمردي)، `OpenCode` (كهرماني)، `Pi` (وردي)، `Gemini CLI` (سماوي)، و/أو `Hermes` (نيلي) -- تاريخ آخر نشاط جلسة +- شارة CLI — `Claude Code` (برتقالي)، `OpenAI Codex` (بنفسجي)، `GitHub Copilot` (أزرق)، `Cursor Agent` (زمردي)، `OpenCode` (كهرماني)، `Pi` (وردي)، و/أو `Hermes` (靛) +- تاريخ أحدث نشاط للجلسة -انقر على مشروع لمشاهدة جلساته. +انقر على مشروع لرؤية جلساته. ### الجلسات -يسرد جميع الجلسات ضمن مشروع. تعرض كل جلسة: -- معرف الجلسة -- طوابع زمنية البدء والنهاية +يسرد جميع الجلسات داخل مشروع. تعرض كل جلسة: +- معرّف الجلسة +- الطوابع الزمنية للبداية والنهاية - عدد استدعاءات الأدوات -- عدد نشاط الخطاف (السياسات التي تم تشغيلها) +- عدد أنشطة الخطاف (السياسات التي تم تشغيلها) -استخدم مرشح نطاق التاريخ وبحث معرف الجلسة لتضييق القائمة. يتم تقسيم الجلسات على صفحات. +استخدم عامل تصفية نطاق التاريخ وبحث معرّف الجلسة لتضييق القائمة. تتم ترقيم الجلسات. انقر على جلسة لفتح عارض الجلسة. ### عارض الجلسة -يجيب عارض الجلسة على السؤال الأساسي للوكلاء المستقلين: ماذا فعل الوكيل، وهل بقي على المسار الصحيح؟ تشير شارة CLI بجانب الرأس إلى ما إذا كانت الجلسة نسخة Claude Code أو OpenAI Codex أو GitHub Copilot CLI أو Cursor Agent أو OpenCode أو Pi أو Gemini CLI أو Hermes. يعرض جدول زمني لكل ما حدث في جلسة: +يجيب عارض الجلسة على السؤال الرئيسي للوكلاء المستقلين: ماذا فعل الوكيل، وهل ظل على المسار الصحيح؟ تشير شارة CLI بجوار الرأس إلى ما إذا كانت الجلسة نسخة Claude Code أو OpenAI Codex أو GitHub Copilot CLI أو Cursor Agent أو OpenCode أو Pi أو Hermes أو OpenClaw أو Factory Droid أو Devin أو Antigravity أو Goose. يعرض خط زمني لكل ما حدث في جلسة: -- **الرسائل** - استجابات نصية من Claude ومحفزات المستخدم -- **استدعاءات الأدوات** - كل أداة استدعاها Claude، مع إدخالها وإخراجها +- **الرسائل** - استجابات Claude النصية وطلبات المستخدم +- **استدعاءات الأدوات** - كل أداة استدعاها Claude، مع المدخلات والمخرجات - **نشاط السياسة** - لكل استدعاء أداة، السياسات التي تم تشغيلها والقرار الذي أرجعته -تعرض شريط الإحصائيات في الأعلى مدة الجلسة وإجمالي استدعاءات الأدوات وملخص قرارات الخطاف (عدد السماح/الرفض/التعليمات). +شريط الإحصائيات في الأعلى يعرض مدة الجلسة والعدد الإجمالي لاستدعاءات الأدوات وملخص قرارات الخطاف (عدد السماح / الرفض / إرشاد). -انقر على زر **تحميل السجلات** لتصدير الجلسة. بالنسبة لجلسات Claude Code و Codex و Copilot و Cursor و Pi و Gemini، تحصل على نص JSONL الأصلي على القرص بالكامل; بالنسبة لـ OpenCode (التي تعيش جلساتها في SQLite وليس على القرص) تحصل على وثيقة JSON تعكس جداول `session` / `messages` / `parts` الأساسية. +انقر على زر **تحميل السجلات** لتصدير الجلسة. بالنسبة لجلسات Claude Code و Codex و Copilot و Cursor و Pi تحصل على نسخة JSONL الأصلية على القرص بالكامل; بالنسبة لـ OpenCode (التي تعيش جلساتها في SQLite، وليس على القرص) تحصل على مستند JSON يعكس جداول `session` / `messages` / `parts` الأساسية. ### التدقيق -تقرير مدفوع بالشخصية حول كيفية تصرف وكيلك بالفعل عبر الجلسات السابقة. يشغل نفس المسح مثل CLI `failproofai audit` لكن يعرضه كملصق على شاشة واحدة قابل للمشاركة + أربعة أقسام تحت الطي: +تقرير مدفوع بالشخصية لكيفية تصرف وكيلك بالفعل عبر الجلسات السابقة. يقوم بتشغيل نفس المسح مثل CLI `failproofai audit` ولكن يعرضه كملصق واحد قابل للمشاركة على شاشة واحدة + أربعة أقسام أسفل الطية: -1. **الملصق** — يملأ أول عرض. منطقة PNG محكمة الإغلاق تحتوي على علامة failproof_ai + تسمية التدقيق · فهرس الأنماط (`№ NN من 08`) + تاريخ التدقيق · النقاط الرقمية (0–100) + حبة تصنيف النسبة المئوية (`أفضل 15%`) · اسم النمط (واحد من `المتفائل` أو `رجل الفوضى` أو `المستكشف` أو `سمك الذاكرة القصيرة` أو `معماري بجنون الارتياب` أو `بناء الدقة` أو `المطرقة` أو `الشبح`) + شريط 3 كلمات · `// فقط N% من الوكلاء لديهم هذا النمط` خط الندرة · بلاط sigil بحجم 8×8 بكسل · تذييل `قم بتدقيق ملكك → failproof.ai`. ثلاث أزرار مشاركة تجلس خارج صندوق الالتقاط: `شارك نمطك` (نية X)، `شارك على linkedin`، `تحميل الملصق`. يتم الالتقاط من خلال `html-to-image` لذا فإن PNG يطابق الرسم على الشاشة بكل بكسل (الحدود المقسومة، قناع شعار SVG، التدرجات، مقاييس الخط — كل شيء محفوظ). -2. **نقاط القوة** — قائمة صفوف هادئة من السلوكيات التي يفعلها وكيلك بالفعل بشكل صحيح، مشتقة من بيانات التدقيق المباشرة (معدل استدعاء أداة نظيف، لا دفع مباشر إلى main، صفر تسريب بيانات اعتماد، صفر عواصف إعادة محاولة) — يتم طرح كل واحد فقط عندما تحتوي السياسة ذات الصلة على سجل نظيف عبر نافذة التدقيق. -3. **الفضول** — جدول ما تسلل، مصنف حسب الشدة: `عندما · ما تسلل + السياسة التي كانت ستقبضه · حبة الشدة · مرئي`، حيث تقرأ التكرار `جديد` (مرة واحدة)، `مرئي N×` (2–9 مرات)، أو `متكرر` (10+). -4. **كيفية التحسن** — قائمة صفوف هادئة، واحدة لكل سياسة موصى بها: اسم السياسة بالأبيض، وصف سطر واحد، أمر التثبيت + زر النسخ على الجانب الأيمن. يقرأ رأس القسم `تفعيل الكل N → النتيجة المتوقعة · ` (النتيجة التي ستصل إليها مع تطبيق كل إصلاح)، وزر `[تثبيت الكل]` الخاص به ينسخ أمر `failproofai policy add a b c …` المدمج لكل سياسة موصى بها. -5. **عودة أفضل** — بطاقتان جنباً إلى جنب. اليسار: اضبط تذكيراً (منتقي إيقاع `3d` / `7d` / `14d` / `30d`; يستمر عبر `/api/auth/reminder` بمجرد المصادقة). اليمين: افتح مزايا failproof — `دعوة صديق` يفتح نافذة منفثقة تأخذ قائمة بريد إلكتروني للأصدقاء مفصولة بفاصلة/مسافة/سطر جديد (بحد أقصى 10 لكل إرسال)، POSTs إلى `/api/audit/invite`، التي تعيد إلى `POST /v0/invite` من خادم api. يرسل خادم api رسالة بريد إلكترونية واحدة لكل مستلم من `invite@failproof.ai` مع مرسل Cc وتعيين `Reply-To`، لذا يرى المستلم من دعاك والمرسل يحصل على نسخة في صندوق الوارد الخاص به. يتم توجيه المستخدمين المجهولين عبر `AuthDialog` أولاً بحيث يكون بريد المرسل معروفاً قبل إرسال الدعوات. تحقيق الحقوق/المزايا متابعة. +1. **الملصق** — يملأ منفذ العرض الأول. منطقة PNG ذاتية الاحتواء مع شعار failproof_ai + تسمية التدقيق · فهرس النموذج الأولي (`№ NN من 08`) + تاريخ التدقيق · درجة رقمية (0–100) + حبة ترتيب النسبة المئوية (`أعلى 15%`) · اسم النموذج الأولي (أحدها `the optimist`، `the cowboy`، `the explorer`، `the goldfish`، `the paranoid architect`، `the precision builder`، `the hammer`، `the ghost`) + شريط 3 كلمات رئيسية · خط ندرة `// فقط N% من الوكلاء لديهم هذا النموذج الأولي` · بلاط شعار 8×8 بكسل · `audit yours → failproof.ai` التذييل. تجلس ثلاثة أزرار مشاركة خارج صندوق الالتقاط: `post your archetype` (X intent)، `share on linkedin`، `download poster`. يتم تشغيل الالتقاط عبر `html-to-image` لذا تتطابق PNG مع عرض الشاشة بكسل مقابل بكسل (الحدود المتقطعة، قناع شعار SVG، التدرجات، مقاييس الخط — كل شيء محفوظ). +2. **نقاط القوة** — قائمة صف هادئة ✓ للسلوكيات التي يقوم بها وكيلك بالفعل بشكل صحيح، مشتقة من بيانات التدقيق المباشرة (معدل استدعاء أداة نظيف، بدون دفعات مباشرة إلى main، بدون تسريب بيانات اعتماد، بدون عواصف إعادة محاولة) — يتم سطح كل منها فقط عندما تكون السياسة ذات الصلة لديها سجل نظيف عبر نافذة التدقيق. +3. **الغرائب** — جدول ما انزلق من خلاله، مرتب حسب الشدة: `when · ما تسرب + السياسة التي كانت ستمسكه · حبة الشدة · seen`، حيث يقرأ التكرار `new` (مرة واحدة)، `N× seen` (2–9 مرات)، أو `recurring` (10+). +4. **كيفية التحسن** — قائمة صف هادئة، واحدة لكل سياسة موصى بها: اسم السياسة باللون الأبيض، وصف بسطر واحد، أمر التثبيت + زر نسخ على الجانب الأيمن. يقرأ رأس القسم `enable all N → projected · ` (الدرجة التي ستصل إليها مع تطبيق كل إصلاح)، وزره `[install all]` ينسخ أمر `failproofai policy add a b c …` المدمج لكل سياسة موصى بها. +5. **عد بشكل أفضل** — بطاقتان جنباً إلى جنب. اليسار: اضبط تذكيراً (منتقي `3d` / `7d` / `14d` / `30d`; يبقى من خلال `/api/auth/reminder` بعد المصادقة). اليمين: فتح مميزات failproof — `invite a friend` يفتح نمطاً يأخذ قائمة بريد إلكتروني للأصدقاء مفصولة بفواصل/مسافات/أسطر جديدة (15 كحد أقصى في كل إرسال)، POSTs لهم إلى `/api/audit/invite`، الذي ينتقل إلى `POST /v0/invite` الخاص بخادم api. يرسل خادم api بريداً إلكترونياً واحداً لكل متلقي من `invite@failproof.ai` مع نسخة مرسل وتعيين `Reply-To`، لذا يرى المتلقي من دعاهم والمرسل يحصل على نسخة في صندوق البريد الخاص به. يتم توجيه المستخدمين المجهولين من خلال `AuthDialog` أولاً بحيث يكون البريد الإلكتروني للمرسل معروفاً قبل إرسال الدعوات. استحقاق / وفاء المميزات هو متابعة. -مدفوعة بواسطة وقت تشغيل `failproofai audit` — انظر [Audit CLI](/ar/cli/audit) لمحرك المسح الأساسي والأعلام المدعومة وثوابت ذاكرة التخزين المؤقت لكل نص. تخزن لوحة التحكم أحدث نتيجة في `~/.failproofai/audit-dashboard.json` (الوضع `0600`، فتحة واحدة، يؤدي التشغيل الجديد إلى الكتابة فوق) بحيث تكون الزيارات الثانية فورية; **يتم رفض كل من ذاكرة التخزين المؤقت لكل نص والنتيجة الكاملة عند القراءة بمجرد تجاوزها 7 أيام** لذا لا تقدم لوحة التحكم أبداً نتيجة قديمة بصمت — بعد انتهاء TTL `/audit` يسقط إلى حالة فارغة ويطالب بتشغيل جديد. ينقر `[ إعادة تدقيق الآن ]` بالقرب من أسفل التقرير على POST `/api/audit/run` مع `noCache: true` — إعادة التدقيق تتجاوز ذاكرة التخزين المؤقت لكل نص وتعيد مسح كل نص من البداية بدلاً من إرجاع النتيجة المخزنة مؤقتاً بصمت — وتستقصي لوحة التحكم `/api/audit/status` بمعدل 1Hz حتى ينتهي التشغيل; شريط تقدم وردي لاصق يثبت في أعلى viewport أثناء التشغيل مع مؤقت الوقت المنقضي، والنتيجة الجديدة تحل محل مكانها عند النجاح (لا إعادة تحميل للصفحة الكاملة; إعادة تدقيق فاشلة تترك التقرير السابق سليماً). في حالة الفشل، يتحول الشريط إلى اللون الأحمر مع نسخة مفصولة عن `RerunError.kind` (`timeout` / `network` / `post_failed`). الحالة الفارغة (لا ذاكرة تخزين مؤقت أو منتهية الصلاحية) وحالة الصفر الجلسات (توجد ذاكرة التخزين المؤقت ولكن المسح لم يجد نصوصاً) يتم عرضهما بشكل منفصل. +مدفوع بـ `failproofai audit` runtime — انظر [Audit CLI](/ar/cli/audit) لمحرك المسح الأساسي، الأعلام المدعومة، وثوابت cache لكل نسخة. تخزن لوحة التحكم أحدث نتيجة في `~/.failproofai/audit-dashboard.json` (الوضع `0600`، فتحة واحدة، تستبدل عمليات التشغيل الجديدة) لذا تكون إعادة الزيارات فورية; **يتم رفض ذاكرة التخزين المؤقت لكل نسخة والنتيجة الكاملة عند القراءة بمجرد أن تصبح أقدم من 7 أيام** لذا لا تخدم لوحة التحكم أبداً نتيجة عمرها أسبوع بصمت — بعد انتهاء الصلاحية `/audit` يسقط إلى حالته الفارغة ويطالب بتشغيل جديد. النقر على `[ re-audit now ]` بالقرب من أسفل التقرير POSTs `/api/audit/run` مع `noCache: true` — إعادة التدقيق تتجاوز ذاكرة التخزين المؤقت لكل نسخة وإعادة مسح كل نسخة من الصفر بدلاً من إرجاع النتيجة المخزنة بصمت — ولوحة التحكم تستقصي `/api/audit/status` في 1Hz حتى انتهاء التشغيل; شريط تقدم وردي لزج يثبت أعلى منفذ العرض أثناء التشغيل مع مؤقت انقضى، والنتيجة الطازجة تتبادل في مكانها عند النجاح (بدون إعادة تحميل الصفحة الكاملة؛ فشل إعادة التدقيق يترك التقرير السابق سليماً). عند الفشل يتحول الشريط إلى اللون الأحمر مع نسخ مفتوحة من `RerunError.kind` (`timeout` / `network` / `post_failed`). يتم سطح الحالة الفارغة (بدون cache أو انتهت الصلاحية) والحالة صفر الجلسات (cache موجود لكن المسح لم يعثر على نسخ) بشكل منفصل. ### السياسات -صفحة بتبويبين لإدارة السياسات ومراجعة النشاط. +صفحة ذات تبويب واحد لإدارة السياسات ومراجعة النشاط. - - حدد بطاقة متعددة الاختيار CLI الذي يحمي failproofai من لوحة واحدة — Claude Code و OpenAI Codex و GitHub Copilot و Cursor Agent و OpenCode و Pi و Gemini CLI و Hermes لها جميعاً صف مع حالة التثبيت (`نشط` / `مكتشف` / `غير نشط`)، مسار إعدادات نطاق المستخدم، وتمييز ملون العلامة التجارية. قم بتحديد أو إلغاء تحديد CLIs التي تريد وانقر `تطبيق التغييرات` لتثبيت/إلغاء تثبيت الفرق في خطوة واحدة. CLIs التي تم اكتشاف ملفها الثنائي على PATH يتم تحديدها مسبقاً. - - بدّل السياسات الفردية على أو بيقاف مع نقرة واحدة (يكتب إلى `~/.failproofai/policies-config.json` — مشترك عبر كل CLI مثبت) + - المحدد متعدد الخيارات الذي CLIs من failproofai يحمي من لوحة واحدة — Claude Code و OpenAI Codex و GitHub Copilot و Cursor Agent و OpenCode و Pi و Hermes جميعاً لها صف يحتوي على حالة التثبيت (`Active` / `Detected` / `Inactive`)، مسار إعدادات نطاق المستخدم، وعلامة مشروطة بالعلامة التجارية. تحقق أو قم بإلغاء تحديد CLIs التي تريدها وانقر على `Apply changes` لتثبيت/إلغاء تثبيت الفرق في خطوة واحدة. يتم فحص CLIs الذي يتم الكشف عن الملفات الثنائية له على PATH مسبقاً. + - تبديل السياسات الفردية على أو إيقاف تشغيلها بنقرة واحدة (يكتب إلى `~/.failproofai/policies-config.json` — مشترك عبر كل CLI مثبت) - قم بتوسيع سياسة لتكوين معاملات (للسياسات التي تدعم `policyParams`) - - عيّن مسار ملف سياسات مخصص + - اضبط مسار ملف السياسات المخصص - - السجل الكامل المقسم على صفحات لكل حدث خطاف تم تشغيله عبر جميع الجلسات - - التصفية حسب القرار ونوع الحدث و CLI (Claude Code / OpenAI Codex / GitHub Copilot _(إصدار تجريبي)_ / Cursor Agent _(إصدار تجريبي)_ / OpenCode _(إصدار تجريبي)_ / Pi _(إصدار تجريبي)_ / Gemini CLI _(إصدار تجريبي)_ / Hermes) واسم السياسة أو معرف الجلسة - - يعرض كل صف: الطابع الزمني واسم السياسة والقرار وشارة CLI (برتقالي = Claude Code، بنفسجي = OpenAI Codex، أزرق = GitHub Copilot، زمردي = Cursor Agent، كهرماني = OpenCode، وردي = Pi، سماوي = Gemini CLI، نيلي = Hermes) واسم الأداة ومعرف الجلسة وسبب قرارات الرفض/التعليمات - - انقر على معرف جلسة لفتح النص الخاص به — الكاشف التلقائي للعارض CLI الذي أطلق الخطاف (Claude `~/.claude/projects/…`، Codex `~/.codex/sessions/…`، Copilot CLI `~/.copilot/session-state//events.jsonl`، Cursor Agent `~/.cursor/agent-sessions//events.jsonl`، OpenCode `~/.local/share/opencode/opencode.db`، Pi `~/.pi/agent/sessions//.jsonl`، Gemini CLI `~/.gemini/tmp//chats/.jsonl`، Hermes `~/.hermes/state.db`) ويعرض شارة CLI المطابقة في الرأس + - السجل الكامل المرقم لكل حدث خطاف تم تشغيله عبر جميع الجلسات + - التصفية حسب القرار أو نوع الحدث أو CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose) أو اسم السياسة أو معرّف الجلسة + - يعرض كل صف: الطابع الزمني، اسم السياسة، القرار، شارة CLI (برتقالي = Claude Code، بنفسجي = OpenAI Codex، أزرق = GitHub Copilot، زمردي = Cursor Agent، كهرماني = OpenCode، وردي = Pi،靛 = Hermes، سماوي = OpenClaw، وردي = Factory Droid، بنفسجي = Devin، سماوي = Antigravity، ليمي = Goose)، اسم الأداة، معرّف الجلسة، والسبب وراء قرارات الرفض/الإرشاد + - انقر على معرّف جلسة لفتح نسخة — يكتشف العارض تلقائياً CLI الذي أطلق الخطاف (Claude `~/.claude/projects/…`، Codex `~/.codex/sessions/…`، Copilot CLI `~/.copilot/session-state//events.jsonl`، Cursor Agent `~/.cursor/agent-sessions//events.jsonl`، OpenCode `~/.local/share/opencode/opencode.db`، Pi `~/.pi/agent/sessions//.jsonl`، Hermes `~/.hermes/state.db`، OpenClaw `~/.openclaw/agents//sessions/*.jsonl`، Factory Droid `~/.factory/sessions//.jsonl`، Devin `~/.local/share/devin/cli/sessions.db`، Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`، Goose `~/.local/share/goose/sessions/sessions.db`) ويعرض شارة CLI المطابقة في الرأس --- -## التحديث التلقائي +## الانتعاش التلقائي -تحتوي لوحة التحكم على مفتاح التحديث التلقائي في التنقل العلوي. عند التفعيل، يتم تحديث الصفحة الحالية بشكل دوري لإظهار جلسات جديدة ونشاط سياسة جديد وهو يظهر. ضروري لمراقبة جلسات الوكيل المستقل طويلة الأجل. +تحتوي لوحة التحكم على مفتاح انتعاش تلقائي في الملاح العلوي. عند التفعيل، تنعش الصفحة الحالية بشكل دوري لعرض جلسات جديدة ونشاط سياسة جديدة كما تظهر. أساسي لمراقبة جلسات الوكيل المستقل طويلة الأجل. --- ## تعطيل الصفحات -إذا كنت تحتاج فقط إلى بعض أجزاء لوحة التحكم، فاضبط `FAILPROOFAI_DISABLE_PAGES` على قائمة مفصولة بفواصل من أسماء الصفحات: +إذا كنت بحاجة إلى بعض أجزاء لوحة التحكم فقط، اضبط `FAILPROOFAI_DISABLE_PAGES` على قائمة أسماء صفحات مفصولة بفواصل: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +111,7 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai ## تكوين مسار المشاريع -بشكل افتراضي، تقرأ لوحة التحكم من دليل مشاريع Claude Code القياسي. تجاوزه للإعدادات المخصصة: +افتراضياً، تقرأ لوحة التحكم من دليل مشاريع Claude Code القياسي. قم بتجاوزها للإعدادات المخصصة: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,32 +119,32 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## الوصول من مضيف غير محلي +## الوصول من مضيف غير localhost -عند تشغيل لوحة التحكم في **وضع التطوير** (`npm run dev`) والوصول إليها من hostname بخلاف `localhost` - على سبيل المثال، نطاق مخصص أو IP بعيد أو عنوان URL يتم نفقه - قد تراى تحذيراً مثل: +عند تشغيل لوحة التحكم في **وضع التطوير** (`npm run dev`) والوصول إليها من اسم مضيف بخلاف `localhost` - على سبيل المثال، نطاق مخصص أو IP بعيد أو عنوان URL متنفق - قد ترى تحذيراً مثل: ```text -⚠ طلب cross-origin محظور لمورد Next.js dev /_next/webpack-hmr من dashboard.example.com. +⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -هذا هو Next.js الذي يحظر الوصول cross-origin إلى HMR (hot module reload) websocket، وهي ميزة dev فقط. للسماح بمضيفك، استخدم علم `--allowed-origins`: +هذا Next.js يحظر الوصول عبر الأصول إلى websocket HMR الخاص به (إعادة تحميل الوحدة الساخنة)، وهي ميزة خاصة بوضع التطوير. للسماح بمضيفك، استخدم العلم `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -لعدة مضيفين أو IPs، مرر قائمة مفصولة بفواصل: +بالنسبة للعديد من المضيفين أو IPs، مرر قائمة مفصولة بفواصل: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -يمكنك أيضاً تعيين متغير البيئة `FAILPROOFAI_ALLOWED_DEV_ORIGINS` بدلاً من ذلك: +يمكنك أيضاً تعيين متغير البيئة `FAILPROOFAI_ALLOWED_DEV_ORIGINS`: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -هذا ينطبق فقط على وضع التطوير. عند تشغيل `failproofai` (وضع الإنتاج)، لا يوجد HMR websocket ولا مشكلة مورد dev cross-origin. +هذا ينطبق فقط على وضع التطوير. عند تشغيل `failproofai` (وضع الإنتاج)، لا يوجد websocket HMR ولا مشكلة مورد تطوير عبر الأصول. \ No newline at end of file diff --git a/docs/ar/getting-started.mdx b/docs/ar/getting-started.mdx index 350cf141..97296293 100644 --- a/docs/ar/getting-started.mdx +++ b/docs/ar/getting-started.mdx @@ -1,6 +1,5 @@ --- ---- -title: البدء السريع +title: ابدأ الآن description: "ثبّت failproofai، فعّل السياسات، واترك وكلاءك يعملون بموثوقية" icon: rocket --- @@ -31,16 +30,16 @@ bun add -g failproofai ## البدء السريع - - السياسات هي قواعد تعمل قبل وبعد كل استدعاء أداة لدى الوكيل. تلتقط الأوامر الضارة، تسرب الأسرار، وأوضاع الفشل الأخرى قبل أن تسبب ضررًا. + + السياسات هي قواعد تعمل قبل وبعد كل استدعاء أداة من الوكيل. تقبض على الأوامر المدمرة وتسريب الأسرار وأوضاع الفشل الأخرى قبل أن تسبب ضررًا. ```bash failproofai policies --install ``` - يكتب هذا إدخالات hook في أدوات الوكيل المثبتة لديك (ملف Claude Code `~/.claude/settings.json`، ملف OpenAI Codex `~/.codex/hooks.json`، ملف GitHub Copilot CLI `~/.copilot/hooks/failproofai.json`، ملف Cursor Agent `~/.cursor/hooks.json`، مكون OpenCode المولد في `~/.config/opencode/plugins/failproofai.mjs` بالإضافة إلى إدخال التسجيل في مصفوفة `plugin` في `~/.config/opencode/opencode.json`، ملف Pi `~/.pi/agent/settings.json`، ملف Gemini CLI `~/.gemini/settings.json`، أو ملف Hermes `~/.hermes/config.yaml`). عند وجود أكثر من واحد ستُطلب منك المتابعة؛ مرر `--cli claude codex copilot cursor opencode pi gemini hermes` (أي مجموعة فرعية) لتخطي الطلب. + يكتب هذا مدخلات الخطاف في واجهات سطر الأوامر المثبتة للوكيل (ملف `~/.claude/settings.json` الخاص بـ Claude Code، `~/.codex/hooks.json` الخاص بـ OpenAI Codex، `~/.copilot/hooks/failproofai.json` الخاص بـ GitHub Copilot CLI، `~/.cursor/hooks.json` الخاص بـ Cursor Agent، مكون إضافة shim مُنتج في `~/.config/opencode/plugins/failproofai.mjs` الخاص بـ OpenCode بالإضافة إلى مدخل تسجيل في مصفوفة `plugin` في `~/.config/opencode/opencode.json`، `~/.pi/agent/settings.json` الخاص بـ Pi، `~/.hermes/config.yaml` الخاص بـ Hermes، `~/.openclaw/openclaw.json` الخاص بـ OpenClaw، `~/.factory/hooks.json` الخاص بـ Factory Droid، `~/.config/devin/config.json` الخاص بـ Devin CLI، `~/.gemini/config/hooks.json` الخاص بـ Antigravity CLI، أو دليل المكون الإضافي الذي يتم اكتشافه تلقائيًا في `~/.agents/plugins/failproofai/hooks/hooks.json` الخاص بـ Goose). عندما يكون أكثر من واحد موجودًا ستُطالب؛ مرّر `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (أي مجموعة جزئية) لتخطي المطالبة. - دعم GitHub Copilot CLI و Cursor Agent و OpenCode و Pi و Gemini CLI موجود في مرحلة **تجريبية** — ثبّت باستخدام `--cli copilot` أو `--cli cursor` أو `--cli opencode` أو `--cli pi` أو `--cli gemini`. يثبّت Hermes (hermes-agent، بوابة Slack/Telegram) بنطاق المستخدم باستخدام `--cli hermes` وهو أيضًا **مصدر تدقيق** دون اتصال. + دعم GitHub Copilot CLI و Cursor Agent و OpenCode و Pi هو **تجريبي** — ثبّت باستخدام `--cli copilot` أو `--cli cursor` أو `--cli opencode` أو `--cli pi`. يثبت Hermes (hermes-agent، بوابة Slack/Telegram) بنطاق المستخدم باستخدام `--cli hermes` وهو **أيضًا** مصدر تدقيق غير متصل. يثبت OpenClaw (بوابة openclaw، مساعد متعدد القنوات ذاتي الاستضافة) بنطاق المستخدم باستخدام `--cli openclaw` — يعمل الإنفاذ عبر خطاف البرنامج المدمج (`before_agent_finalize` هو بوابة نهاية دور حقيقية، لذا يفرض البرنامج المدمج `require-*-before-stop`) — وهو **أيضًا** مصدر تدقيق غير متصل. يثبت Factory Droid (`droid`) باستخدام `--cli factory` (نطاق المستخدم والمشروع) وهو **أيضًا** مصدر تدقيق غير متصل. يثبت Devin CLI (`devin`، Cognition) باستخدام `--cli devin` (نطاق المستخدم والمشروع) وهو **أيضًا** مصدر تدقيق غير متصل. يثبت Antigravity CLI (`agy`) باستخدام `--cli antigravity` (نطاق المستخدم والمشروع) وهو **أيضًا** مصدر تدقيق غير متصل. يثبت Goose (اسم الكود goose، Block) باستخدام `--cli goose` (نطاق المستخدم والمشروع) — يقطع المثبت للتو دليل مكون إضافي في `~/.agents/plugins/failproofai/` الذي يكتشفه Goose تلقائيًا، وهو **أيضًا** مصدر تدقيق غير متصل. ```bash failproofai policies --install --scope project @@ -49,66 +48,70 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` - + ```bash failproofai policies ``` - يعرض كل سياسة، وما إذا كانت مفعّلة، وأي معاملات مُعدّة. + يعرض كل سياسة، وما إذا كانت مُفعّلة، وأي معاملات مكونة. - + ```bash failproofai ``` - يفتح لوحة معلومات محلية على `http://localhost:8020` حيث يمكنك استعراض الجلسات، فحص استدعاءات الأدوات، وإدارة السياسات. + يفتح لوحة معلومات محلية في `http://localhost:8020` حيث يمكنك استعراض الجلسات والتفتيش على استدعاءات الأدوات وإدارة السياسات. - - شغّل Claude Code كالمعتاد. إذا حاول الوكيل فعل شيء محفوف بالمخاطر، سيعترضه failproofai تلقائيًا. اتركه يعمل دون إشراف واستعرض ما حدث في لوحة المعلومات. + + شغّل Claude Code كالمعتاد. إذا حاول الوكيل فعل شيء محفوف بالمخاطر، سيعترضه failproofai تلقائيًا. اتركه يعمل دون حضور واستعرض ما حدث في لوحة المعلومات. --- -## كيف تعمل السياسات +## كيفية عمل السياسات -في كل مرة يشغّل الوكيل أداة، يستدعي Claude Code failproofai كعملية فرعية: +في كل مرة يشغل الوكيل أداة، يستدعي Claude Code failproofai كعملية فرعية: ```text -Claude Code → failproofai --hook PreToolUse → reads stdin JSON - evaluates policies - writes decision to stdout +Claude Code → failproofai --hook PreToolUse → يقرأ JSON من stdin + يقيّم السياسات + يكتب القرار إلى stdout ``` -كل سياسة تعيد أحد ثلاث قرارات: +تُرجع كل سياسة أحد ثلاثة قرارات: -- **allow** - يمضي الوكيل بشكل طبيعي -- **deny** - يتم حظر الإجراء، يُخبر الوكيل السبب -- **instruct** - يتم إضافة سياق إضافي إلى فوري الوكيل +- **allow** - يستمر الوكيل بشكل طبيعي +- **deny** - يتم حظر الإجراء، ويُخبر الوكيل السبب +- **instruct** - يضاف سياق إضافي إلى موجه الوكيل -تعمل السياسات في عمليتك المحلية. لا شيء يُرسل إلى خدمة بعيدة. +تعمل السياسات في عمليتك المحلية. لا يتم إرسال أي شيء إلى خدمة بعيدة. --- -## إعداد سياسات الفريق باستخدام السياسات المستندة إلى الاتفاقية +## اضبط سياسات الفريق باستخدام السياسات المبنية على الاتفاقية -أسرع طريقة لإنشاء معايير الجودة عبر فريقك هي اتفاقية `.failproofai/policies/`. ضع ملفات السياسة في هذا الدليل وسيتم تحميلها تلقائيًا — لا أعلام، لا تغييرات إعدادات، لا أوامر تثبيت. +الطريقة الأسرع لإنشاء معايير جودة في جميع أنحاء فريقك هي اتفاقية `.failproofai/policies/`. ضع ملفات السياسة في هذا الدليل وسيتم تحميلها تلقائيًا — لا أعلام، لا تغييرات في الإعدادات، لا أوامر تثبيت. - + ```bash mkdir -p .failproofai/policies ``` - - انسخ أمثلة المبتدئين أو اكتب خاصتك: + + انسخ أمثلة البدء أو اكتب خاصتك: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -133,43 +136,43 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON }); ``` - + ```bash git add .failproofai/policies/ git commit -m "Add team quality policies" ``` - كل فرد من فريقك الذي لديه failproofai مثبت سيستقبل هذه السياسات تلقائيًا. لا يلزم إعداد لكل مطور. + كل عضو في الفريق لديه failproofai مثبتًا يختار هذه السياسات تلقائيًا. لا حاجة لإعداد لكل مطور. -التزم بـ `.failproofai/policies/` في مستودعك حتى يتشارك الفريق بأكمله نفس المعايير. كلما اكتشف فريقك أوضاع فشل جديدة، أضف سياسات وادفع — الجميع يحصلون على التحديث في `git pull` التالي. بمرور الوقت تصبح هذه السياسات معيار جودة حي يستمر في التحسن. +التزم بـ `.failproofai/policies/` في مستودعك حتى يشارك الفريق بأكمله نفس المعايير. مع اكتشاف فريقك لأوضاع فشل جديدة، أضف سياسات وادفع — يحصل الجميع على التحديث في عملية `git pull` التالية. بمرور الوقت، تصبح هذه السياسات معيار جودة حي يستمر في التحسن. --- ## تخزين البيانات -جميع الإعدادات والسجلات تبقى على جهازك: +تبقى جميع الإعدادات والسجلات على جهازك: | المسار | ما يخزنه | -|------|-------------| +|------|----------------| | `~/.failproofai/policies-config.json` | إعدادات السياسة العامة | -| `~/.failproofai/hook-activity.jsonl` | سجل تنفيذ Hook | -| `~/.failproofai/hook.log` | سجل تصحيح أخطاء Hook المخصص | -| `.failproofai/policies-config.json` | إعدادات لكل مشروع (مُلتزم به) | -| `.failproofai/policies-config.local.json` | تجاوزات شخصية (مُستثناة من git) | +| `~/.failproofai/hook-activity.jsonl` | سجل تنفيذ الخطاف | +| `~/.failproofai/hook.log` | سجل تصحيح لأخطاء الخطاف المخصصة | +| `.failproofai/policies-config.json` | إعدادات لكل مشروع (ملتزم بها) | +| `.failproofai/policies-config.local.json` | التجاوزات الشخصية (مُدرجة في gitignore) | --- -## إلغاء التثبيت +## الإزالة ```bash failproofai policies --uninstall ``` -يزيل إدخالات hook من `~/.claude/settings.json`. ملفات الإعدادات في `~/.failproofai/` يتم الاحتفاظ بها. +يزيل مدخلات الخطاف من `~/.claude/settings.json`. يتم الاحتفاظ بملفات الإعدادات في `~/.failproofai/`. --- @@ -190,7 +193,7 @@ failproofai policies --uninstall - مراقبة الجلسات واستعرض نشاط السياسة + راقب الجلسات واستعرض نشاط السياسة \ No newline at end of file diff --git a/docs/ar/introduction.mdx b/docs/ar/introduction.mdx index 2475e146..27dfb886 100644 --- a/docs/ar/introduction.mdx +++ b/docs/ar/introduction.mdx @@ -1,41 +1,41 @@ --- title: "Failproof AI" -description: "FailproofAI يوفر للوكلاء الذكيين 39 سياسة فشل مدمجة تكتشف الحلقات وتسرب الأسرار واستدعاءات الأدوات المدمرة والمزيد في تثبيت واحد." +description: "FailproofAI يمنح وكلاء الذكاء الاصطناعي 39 سياسة فشل مدمجة تكتشف الحلقات والتسريبات السرية واستدعاءات الأدوات المدمرة والمزيد في تثبيت واحد." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -الخطافات والسياسات لـ **معالجة أعطال الذكاء الاصطناعي** و **استرجاع الأخطاء** و **موثوقية نماذج اللغة الكبيرة**. حافظ على موثوقية وكلائك الذكيين والعمل بشكل مستقل عبر **Claude Code** و **OpenAI Codex** و **GitHub Copilot** و **Cursor Agent** و **OpenCode** و **Pi** و **Gemini CLI** و **Hermes** و **Agents SDK**. +خطافات وسياسات لـ **معالجة فشل الذكاء الاصطناعي**، **استرجاع الأخطاء**، و**موثوقية نموذج اللغة الكبير**. حافظ على وكلاء الذكاء الاصطناعي الخاص بك موثوقين وتشغيلهم بشكل مستقل عبر **Claude Code**، **OpenAI Codex**، **GitHub Copilot**، **Cursor Agent**، **OpenCode**، **Pi**، **Hermes**، **OpenClaw**، **Factory Droid**، **Devin CLI**، **Antigravity CLI**، و**Agents SDK**. -الوكلاء الذكيون يفشلون بطرق يمكن التنبؤ بها. يقومون بتنفيذ أوامر مدمرة، تسرب الأسرار، الانجراف عن المهمة الأساسية، الوقوع في حلقات، أو الدفع مباشرة إلى الفرع الرئيسي. إذا تركت دون مراقبة، فإن الأعطال الصغيرة قد تؤدي إلى انقطاعات، تسرب بيانات الاعتماد، وفقدان العمل. +وكلاء الذكاء الاصطناعي يفشلون بطرق يمكن التنبؤ بها. يقومون بتشغيل أوامر مدمرة، وتسريب الأسرار، والانجراف عن المهمة، والعلوق في حلقات، أو الدفع مباشرة إلى الفرع الرئيسي. في حالة تركهم بدون مراقبة، قد تتسبب الأخطاء الصغيرة في انهيارات وتسريب بيانات المصادقة وفقدان العمل. -FailproofAI يحل هذه المشكلة عبر **السياسات**. هذه القواعد تتصل بكل استدعاء أداة من الوكيل لـ **الكشف عن الأعطال** و **تخفيفها** (حظر، توجيه، تعقيم) و **تنبيهك** عند الحاجة للاهتمام. لوحة معلومات محلية تسمح لك باستعراض كل استدعاء أداة وفشل وكيل وإجراء استرجاع بعد ذلك. +يحل FailproofAI هذه المشكلة باستخدام **السياسات**. هذه القواعد تتعلق بكل استدعاء أداة من وكيل لـ **اكتشاف الأخطاء**، **التخفيف من آثارها** (حظر، إرشاد، تعقيم)، و**إنبيهك** عند الحاجة إلى الانتباه. لوحة تحكم محلية تسمح لك بمراجعة كل استدعاء أداة، فشل الوكيل، وإجراء الاسترجاع لاحقاً. -لا تغادر أي بيانات جهازك. +لا تترك أي بيانات جهازك. -## ابدأ الآن +## البدء - حظر الأوامر المدمرة، منع تسرب الأسرار، إبقاء الوكلاء داخل حدود المشروع، والمزيد. كل ذلك جاهز من البداية. + احظر الأوامر المدمرة، ومنع تسريب الأسرار، وحافظ على الوكلاء داخل حدود المشروع، والمزيد. كل شيء جاهز من الصندوق. - - اكتب قواعدك الخاصة في JavaScript باستخدام واجهة برمجية بسيطة allow / deny / instruct. + + اكتب قواعدك الخاصة في JavaScript باستخدام واجهة برمجة تطبيقات allow / deny / instruct بسيطة. - انظر إلى ما فعله وكلائك أثناء غيابك. استعرض الجلسات، افحص استدعاءات الأدوات، راجع المكان الذي تم تطبيق السياسات فيه. + شاهد ما فعله وكلاؤك أثناء غيابك. تصفح الجلسات، وافحص استدعاءات الأدوات، وراجع حيث تم تفعيل السياسات. - ضبط أي سياسة دون كود. عيّن قوائم السماح أو الفروع المحمية أو العتبات لكل مشروع أو عالميًا. + اضبط أي سياسة بدون كود. عيّن قوائم السماح أو الفروع المحمية أو العتبات لكل مشروع أو عام. -## ابدأ بسرعة +## البدء السريع @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # تفعيل السياسات (أو تخطي — سيقدم failproofai تعيينها عند التشغيل الأول) -failproofai # إطلاق لوحة المعلومات +failproofai policies --install # enable policies (or skip — `failproofai` will offer to set them up on first run) +failproofai # launch the dashboard ``` -راجع دليل [البدء](/ar/getting-started) للحصول على الشرح الكامل. \ No newline at end of file +اطلع على دليل [البدء](/ar/getting-started) للحصول على الشرح الكامل. \ No newline at end of file diff --git a/docs/built-in-policies.mdx b/docs/built-in-policies.mdx index 55093ffe..95fe24f5 100644 --- a/docs/built-in-policies.mdx +++ b/docs/built-in-policies.mdx @@ -710,7 +710,7 @@ All workflow policies are **fail-open**: if the required tool is not available ( ### Per-CLI Stop semantics -Stop enforcement looks slightly different across the seven supported CLIs because each one exposes a different "agent finished" hook contract. The **outcome** is the same — the agent doesn't get away with stopping while a workflow gate is failing — but the **mechanics** differ. The table below summarizes; only Pi has a user-visible quirk worth understanding before you enable a `require-*-before-stop` policy. +Stop enforcement looks slightly different across the six supported CLIs because each one exposes a different "agent finished" hook contract. The **outcome** is the same — the agent doesn't get away with stopping while a workflow gate is failing — but the **mechanics** differ. The table below summarizes; only Pi has a user-visible quirk worth understanding before you enable a `require-*-before-stop` policy. | CLI | When the gate fires | What you see | |---|---|---| @@ -718,20 +718,19 @@ Stop enforcement looks slightly different across the seven supported CLIs becaus | Codex | Same agent loop, immediately | Same as Claude. | | GitHub Copilot CLI | Same agent loop, immediately | Same as Claude (uses Copilot's `{decision:"block", reason}` retry channel — verified empirically against Copilot CLI 1.0.41). | | Cursor Agent | Same agent loop, immediately | Same as Claude (uses Cursor's `{followup_message}` channel — capped at `loop_limit`, default 5 retries). | -| Gemini CLI | Same agent loop, immediately | Same as Claude (uses Gemini's `{decision:"block", reason}` channel on `AfterAgent`). | | OpenCode | Same agent loop, immediately | Same as Claude (uses OpenCode's `client.session.prompt(...)` SDK call routed through `hookSpecificOutput.additionalContext`). | | **Pi (pi-coding-agent)** | **Next user turn** | **Pi visibly stops** when the gate fires — its agent loop exits and you're returned to the prompt. The gate then fires the next time you submit a prompt: failproofai prepends a `MANDATORY ACTION REQUIRED` directive to that turn's system prompt, instructing the LLM to complete the workflow step (commit, push, etc.) before doing whatever you asked. | -**Pi limitation.** Pi's `AgentEndEvent` (the upstream equivalent of Claude's `Stop` hook) has no Result type — by the time it fires, Pi's agent loop has already exited. Pi cannot be forced to retry the same loop the way Claude / Copilot / Cursor / Gemini / OpenCode can. failproofai shifts the gate to Pi's `before_agent_start` event (which fires after the next user prompt) so the workflow check still enforces, just on the next turn rather than the current one. +**Pi limitation.** Pi's `AgentEndEvent` (the upstream equivalent of Claude's `Stop` hook) has no Result type — by the time it fires, Pi's agent loop has already exited. Pi cannot be forced to retry the same loop the way Claude / Copilot / Cursor / OpenCode can. failproofai shifts the gate to Pi's `before_agent_start` event (which fires after the next user prompt) so the workflow check still enforces, just on the next turn rather than the current one. **What this means in practice:** - After Pi stops, the deny reason is captured in-memory keyed by Pi session id. The very next prompt you submit in the same Pi process drains it: the LLM sees the `MANDATORY ACTION REQUIRED` directive at the top of its system prompt, commits (or pushes / opens the PR / waits for CI), and only then continues with your request. The captured deny reason is one-shot — once drained, the gate is clear. -- The gate is bounded by Pi's process lifetime. If you `Ctrl+C` Pi or quit between turns, the in-memory entry is dropped along with the process and the gate is missed. Claude, Copilot, Cursor, Gemini, and OpenCode have the same bound (kill the agent and the gate is missed) — Pi just makes it more visible because the agent visibly exits before the gate fires. +- The gate is bounded by Pi's process lifetime. If you `Ctrl+C` Pi or quit between turns, the in-memory entry is dropped along with the process and the gate is missed. Claude, Copilot, Cursor, and OpenCode have the same bound (kill the agent and the gate is missed) — Pi just makes it more visible because the agent visibly exits before the gate fires. - A pending deny is also cleared on `session_shutdown` for any reason (`new` / `resume` / `fork` / `quit`), so a stale gate from a prior session cannot leak into a fresh session started in the same Pi process. -If you need Claude-style same-loop retry, run your `Stop` policies under any of the other six supported CLIs. We are tracking Pi upstream for a future Result type on `AgentEndEvent` that would let us close this gap. +If you need Claude-style same-loop retry, run your `Stop` policies under any of the other five supported CLIs. We are tracking Pi upstream for a future Result type on `AgentEndEvent` that would let us close this gap. ### `require-commit-before-stop` diff --git a/docs/cli/audit.mdx b/docs/cli/audit.mdx index 6972cbcc..cc059e45 100644 --- a/docs/cli/audit.mdx +++ b/docs/cli/audit.mdx @@ -55,7 +55,7 @@ failproofai until you stop it with `Ctrl+C`. -The dashboard scans past agent CLI transcripts on this machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) and reports how often the agent did things failproofai is built to stop — env-var checks, force pushes, redundant `cd ` prefixes, sleep-polling loops, re-reading files just edited, and more. +The dashboard scans past agent CLI transcripts on this machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) and reports how often the agent did things failproofai is built to stop — env-var checks, force pushes, redundant `cd ` prefixes, sleep-polling loops, re-reading files just edited, and more. For each transcript, every tool-use event is replayed through the 39 builtin policies **and** through 8 audit-only detectors that catch patterns not yet covered by runtime policies. Counts are aggregated per policy / detector across all sessions. diff --git a/docs/configuration.mdx b/docs/configuration.mdx index b1568711..795dc884 100644 --- a/docs/configuration.mdx +++ b/docs/configuration.mdx @@ -194,15 +194,19 @@ The `policies --install` and `policies --uninstall` commands write to your agent - **Agent CLI settings** — tells the agent to call `failproofai --hook ` on each tool use: - **Claude Code**: `~/.claude/settings.json` (user), `/.claude/settings.json` (project), `/.claude/settings.local.json` (local) - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex doesn't have a `local` scope - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot has no `local` scope. Hook entries use Copilot's OS-keyed `bash`/`powershell` command fields with `timeoutSec`; the file carries a top-level `version: 1` marker. Copilot CLI support is **beta** while we verify the `events.jsonl` record schema (which the public docs do not specify) against more real-world sessions. + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot has no `local` scope. Hook entries use Copilot's OS-keyed `bash`/`powershell` command fields with `timeoutSec`; the file carries a top-level `version: 1` marker. Copilot CLI support is **beta** while we verify the `events.jsonl` record schema (which the public docs do not specify) against more real-world sessions. **VS Code Copilot Chat agent mode (Preview)** reads hook configs from `.github/hooks/*.json`, `~/.copilot/hooks/*.json`, and `~/.claude/settings.json` (governed by the `chat.hookFilesLocations` setting) using the same Claude-shaped `{hookSpecificOutput:{permissionDecision:"deny",…}}` contract — the exact paths this `copilot` integration and the `claude` integration (`~/.claude/settings.json`) already write, so `failproofai policies --install --cli copilot` (or `--cli claude`) **already enforces in VS Code agent mode** with no separate `vscode` integration needed (confirmed live from VS Code's discovery logs). - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor has no `local` scope. Hook entries use the Claude-shaped `{type, command, timeout}` form (no `bash`/`powershell` split), but stored under camelCase event keys (`preToolUse`, `beforeSubmitPrompt`, …) in a flat array per Cursor's [hooks schema](https://cursor.com/docs/hooks); the file carries a top-level `version: 1` marker. The handler canonicalizes camelCase → PascalCase via `CURSOR_EVENT_MAP` so existing built-in policies fire unchanged. Cursor Agent support is **beta** while we verify Cursor's transcript on-disk format (not specified in the public docs) against more real-world installs. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode has no `local` scope. Unlike the other six CLIs, OpenCode has **no external-command hook system**: it loads in-process JS/TS plugins explicitly registered via the `plugin: []` array in `opencode.json` (auto-discovery from `.opencode/plugins/` is **not** how plugins load on opencode v1.14.33). Install drops a small generated plugin shim that subprocess-calls the failproofai binary and translates the binary's Claude-shape JSON response back into plugin semantics: `throw new Error()` for tool-event deny (cancels the tool call), `client.session.prompt(...)` for instruct AND for `Stop` / `SubagentStop` deny (submits the deny reason as the next user message — the only force-retry channel since `session.idle` is notification-only and throwing from it is a no-op), and no-op for allow. The shim canonicalizes both tool names (lowercase → PascalCase via `OPENCODE_TOOL_MAP`) and tool-input arg keys (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` for `Read` / `Write` / `Edit`, e.g. `filePath` → `file_path`, `oldString` → `old_string`) before forwarding to the binary, so path-checking builtins like `block-read-outside-cwd`, `block-env-files`, and `block-secrets-write` fire unchanged on OpenCode tool calls. Sessions live in opencode's SQLite DB at `~/.local/share/opencode/opencode.db`; the dashboard's session viewer reads them via `opencode db --format json` and `opencode export `. OpenCode support is **beta** while we verify behavior across versions and against more real-world sessions. See the [OpenCode plugins docs](https://opencode.ai/docs/plugins/). + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode has no `local` scope. Unlike the other five CLIs, OpenCode has **no external-command hook system**: it loads in-process JS/TS plugins explicitly registered via the `plugin: []` array in `opencode.json` (auto-discovery from `.opencode/plugins/` is **not** how plugins load on opencode v1.14.33). Install drops a small generated plugin shim that subprocess-calls the failproofai binary and translates the binary's Claude-shape JSON response back into plugin semantics: `throw new Error()` for tool-event deny (cancels the tool call), `client.session.prompt(...)` for instruct AND for `Stop` / `SubagentStop` deny (submits the deny reason as the next user message — the only force-retry channel since `session.idle` is notification-only and throwing from it is a no-op), and no-op for allow. The shim canonicalizes both tool names (lowercase → PascalCase via `OPENCODE_TOOL_MAP`) and tool-input arg keys (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` for `Read` / `Write` / `Edit`, e.g. `filePath` → `file_path`, `oldString` → `old_string`) before forwarding to the binary, so path-checking builtins like `block-read-outside-cwd`, `block-env-files`, and `block-secrets-write` fire unchanged on OpenCode tool calls. Sessions live in opencode's SQLite DB at `~/.local/share/opencode/opencode.db`; the dashboard's session viewer reads them via `opencode db --format json` and `opencode export `. OpenCode support is **beta** while we verify behavior across versions and against more real-world sessions. See the [OpenCode plugins docs](https://opencode.ai/docs/plugins/). - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi has no `local` scope. Pi loads TypeScript extension packages at startup; the settings file is a flat string array `{"packages": ["./relative/path", …]}`. failproofai writes a single packages-array entry pointing at its bundled `pi-extension/` directory. The extension internally subscribes to Pi's `tool_call` / `user_bash` / `input` / `session_start` events and shells out to `failproofai --hook --cli pi`; the handler canonicalizes underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` so existing built-in policies fire unchanged. Tool input args are also canonicalized via `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit deliver `path` rather than `file_path`; mapping the top-level key lets `block-env-files` and `block-secrets-write` fire — `block-read-outside-cwd` already had a `path` fallback). Pi support is **beta** while Pi's extension API and session-log layout stabilize. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini has no `local` scope (it documents a `system` scope at `/etc/gemini-cli/settings.json` which failproofai does not expose). Hook entries use Claude's `{type, command, timeout}` form wrapped in Gemini's `{matcher, hooks: [...]}` matcher schema with `matcher: "*"` by default. Events are PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); the handler maps to Claude canonical names via `GEMINI_EVENT_MAP`. Tool names are snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — the handler canonicalizes via `GEMINI_TOOL_MAP` so existing built-in policies fire unchanged. The policy evaluator emits Gemini's flat `{decision: "deny", reason}` shape (preferred per Gemini's "Golden Rule" exit-0 contract), `{hookSpecificOutput: {hookEventName, additionalContext}}` for context injection on BeforeAgent / AfterTool / SessionStart, and `{decision: "block", reason}` on AfterAgent for force-retry semantics. Gemini CLI support is **beta** while we widen real-world coverage. See the [Gemini CLI hooks docs](https://geminicli.com/docs/hooks/). - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**user scope only** — Hermes has no project/local config). Hermes is a Slack/Telegram **gateway**, so one install intercepts tool calls from every platform (Slack/Telegram/cli/cron) **and** internal subagents. Hook entries are a `{command, timeout}` pair (timeout in **seconds**) under a `hooks:` map keyed by Hermes's snake_case events (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); the handler canonicalizes events via `HERMES_EVENT_MAP` and tool names via `HERMES_TOOL_MAP` so built-in policies fire unchanged. The config is edited through a comment-preserving YAML `Document` round-trip so the operator's other settings survive, and install sets `hooks_auto_accept: true` so the headless gateway (no TTY) runs the hooks without a consent prompt. The evaluator emits Hermes's `{"decision":"block","reason"}` stdout contract (Hermes ignores exit codes). **Limitations:** Hermes has no turn-end `Stop` event, so the `require-*-before-stop` builtins never fire for it (inapplicable, not broken); `instruct` degrades to allow-with-logged-note (no additional-context channel); and output-secret redaction (`sanitize-*`) can't rewrite tool output over the shell-hook contract. Hermes is **also** an offline **audit** source — the dashboard reads its gateway sessions directly from `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**user scope only** — OpenClaw has no project/local config). Like Hermes, OpenClaw is a self-hosted multi-channel **gateway**, so one install intercepts tool calls from every channel and its internal subagents. Enforcement runs through OpenClaw's **in-process plugin hooks** (its file-based internal hooks are observation-only and cannot block), so — like OpenCode/Pi — failproofai ships a static `openclaw-plugin/` package that async-spawns the failproofai binary and translates the verdict. Install registers the shipped plugin dir in `openclaw.json`'s `plugins.load.paths[]` and enables it under `plugins.entries.failproofai` (with `hooks.allowConversationAccess: true`, required for the raw-conversation hooks). The evaluator emits a flat `{permission, reason}` verdict and the shim maps it to each hook's native return shape: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), and `before_agent_finalize → {action:"revise", reason}` (**Stop** — a real turn-end gate, so the `require-*-before-stop` builtins **enforce** on OpenClaw, unlike Hermes). Events and tool names canonicalize binary-side via `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) so built-in policies fire unchanged; the shim fails open on any spawn/parse/timeout error. OpenClaw is **also** an offline **audit** source — the dashboard reads its JSONL sessions at `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (user), `/.factory/hooks.json` (project) — Factory has no `local` scope. droid ships a Claude-style external-command hook system, but with two quirks verified live against droid v0.171.0: (1) event names live at the **top level** of `hooks.json` — there is **no `"hooks"` wrapper** (droid rejects one); tool events (`PreToolUse`/`PostToolUse`) carry `"matcher": "*"`, non-tool events omit it. (2) Deny is driven by hook **exit code 2 + stderr**, not a JSON decision — the evaluator's `factory` branch returns exit 2 for tool/prompt events and `{decision:"block", reason}` only on the turn-end `Stop` event (droid's sole force-retry channel). Events are already PascalCase (no event map) and the payload is Claude snake_case; only tool names are canonicalized via `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory is **also** an offline **audit** source — the dashboard reads its on-disk JSONL sessions at `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (user), `/.devin/config.json` (project) — Devin has no `local` scope. Devin is a **pure Claude-clone** verified live against devin v3000.1.27: it uses the standard Claude `"hooks"`-wrapper schema (writes are merge-preserving so the config file's other keys — `org_id`, `theme_mode`, … — survive), already-PascalCase event names (no event map, no handler branch), and a Claude snake_case stdin payload (no normalization). The evaluator's `devin` branch denies with `{"decision":"block","reason"}` JSON on stdout at exit 0 for **every** event (verified — the block overrode `--permission-mode dangerous`); on the turn-end `Stop` event the reason carries the MANDATORY-ACTION force-retry wording so the `require-*-before-stop` builtins enforce. Only tool names are canonicalized via `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` is already canonical). Devin is **also** an offline **audit** source — the dashboard reads its SQLite sessions at `~/.local/share/devin/cli/sessions.db` (each `sessions` row carries a real `working_directory`, so sessions group by project cwd like Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (user), `/.agents/hooks.json` (project) — Antigravity has no `local` scope. Unlike Factory/Devin, Antigravity has its **own** contract (not a Claude-clone), verified live against agy v1.1.2. `hooks.json` uses a **named-hook** schema: the top-level key is a hook *name* (`"failproofai"`) whose value is an event→handlers map — tool events (`PreToolUse`/`PostToolUse`) wrap handlers in `{matcher:"*", hooks:[…]}`, while `PreInvocation`/`Stop` are **flat** handler arrays (other named hooks are preserved). The stdin payload is **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai normalizes it to snake_case before policies run, and maps `run_command`'s PascalCase args (`CommandLine`/`Cwd`) via `ANTIGRAVITY_TOOL_INPUT_MAP`. The evaluator's `antigravity` branch uses Antigravity's **own** response shapes: `{decision:"deny", reason}` blocks a tool/prompt (exit 0), `{decision:"continue", reason}` on the turn-end `Stop` re-enters the loop (so the `require-*-before-stop` builtins enforce), and `{injectSteps:[{ephemeralMessage}]}` injects an instruction on `PreInvocation` (→ `UserPromptSubmit`). Tool names canonicalize via `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity is **also** an offline **audit** source — the dashboard reads its plain-JSONL transcripts at `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (conversation index in `conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (user), `/.agents/plugins/failproofai/hooks/hooks.json` (project) — Goose has no `local` scope. Enforcement uses Goose's **hooks** system, the cross-agent **Open Plugins** spec: the installer just drops the `failproofai` plugin dir and Goose auto-discovers it at startup (self-registering it into `~/.config/goose/config.yaml`). The `hooks.json` uses an Open Plugins schema **with** a top-level `"hooks"` wrapper, and the matcher is **omitted** on every event — a bare `"*"` is an invalid regex that matches nothing (verified live against goose v1.43.0). Event names are already PascalCase (no event map); the stdin payload uses `event`/`working_dir`, which the handler normalizes to `hook_event_name`/`cwd`. The evaluator's `goose` branch denies with `{"decision":"block","reason"}` JSON on stdout at exit 0, honored on the **`PreToolUse`** event only (shipped in goose ≥ v1.37.0) — which fires for the shell tool **and inside delegated subagents**, so it is the single sufficient deny point; any other hook error fails **open**. Goose has **no `Stop` event**, so the `require-*-before-stop` builtins don't apply (as with Hermes). Tool names canonicalize via `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) and path keys via `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose is **also** an offline **audit** source — the dashboard reads its SQLite sessions at `~/.local/share/goose/sessions/sessions.db` (each `sessions` row carries a real `working_dir`, so sessions group by project cwd like Devin; `--no-session` scratch runs are filtered). - **`policies-config.json`** — tells failproofai which policies to evaluate and with what params (shared across all agent CLIs) -Pass `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` to target a specific agent (space-separated or repeated for any subset): +Pass `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` to target a specific agent (space-separated or repeated for any subset): ```bash failproofai policies --install --cli codex --scope project @@ -210,12 +214,16 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -When `--cli` is omitted, `failproofai` detects which agent CLIs are installed (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +When `--cli` is omitted, `failproofai` detects which agent CLIs are installed (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): - **One CLI detected** — auto-selects that CLI without prompting. - **Multiple CLIs detected** in an interactive terminal — shows an arrow-key single-select prompt grouped into a `Detected (N)` section (with an `Install for all N detected` aggregate row + each detected CLI individually) and a `Not installed (M) · install hooks ahead of time` section listing every undetected supported CLI as a forward-install option (↑↓ to move, Enter to select, ^C to quit). The uninstall flow shows only the Detected section. diff --git a/docs/dashboard.mdx b/docs/dashboard.mdx index a528fb40..bfdee30d 100644 --- a/docs/dashboard.mdx +++ b/docs/dashboard.mdx @@ -24,11 +24,11 @@ The dashboard reads directly from the filesystem - your Claude Code project fold ### Projects -Lists all Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, and Hermes projects found on your machine. Claude projects are discovered from `~/.claude/projects/` (or the path set by `CLAUDE_PROJECTS_PATH`); Codex projects are discovered by scanning every transcript under `~/.codex/sessions///
/*.jsonl` and grouping by the `cwd` recorded in each session's first record; Copilot CLI projects are discovered by scanning each `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) and grouping by its `cwd` field; Cursor Agent projects are discovered by scanning per-session metadata under `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, with `conversations/` and `sessions/` probed as fallbacks) for a `cwd` scalar in `meta.json` / `session.json` / `workspace.yaml`; OpenCode projects are discovered by querying its SQLite DB at `~/.local/share/opencode/opencode.db` via `opencode db --format json` (we read the `session` and `project` tables and group by `project_id`); Pi projects are discovered by scanning per-session JSONL transcripts under `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) and pulling the `cwd` from each session's first record; Gemini CLI projects are discovered by scanning `~/.gemini/tmp//chats/session--.jsonl` (configurable via `GEMINI_SESSIONS_DIR`) and recovering the canonical cwd from the sibling `.project_root` text marker; Hermes gateway sessions are read directly from its SQLite store at `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) and grouped into `hermes-` projects by `source` (Slack/Telegram/cli/cron — gateway sessions have no cwd). A project that has been used by multiple CLIs renders as a single row with all matching badges. Use the **CLI** dropdown above the table to filter by a specific agent CLI; the URL preserves your selection as `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lists all Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, and Goose projects found on your machine. Claude projects are discovered from `~/.claude/projects/` (or the path set by `CLAUDE_PROJECTS_PATH`); Codex projects are discovered by scanning every transcript under `~/.codex/sessions///
/*.jsonl` and grouping by the `cwd` recorded in each session's first record; Copilot CLI projects are discovered by scanning each `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) and grouping by its `cwd` field; Cursor Agent projects are discovered by scanning per-session metadata under `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, with `conversations/` and `sessions/` probed as fallbacks) for a `cwd` scalar in `meta.json` / `session.json` / `workspace.yaml`; OpenCode projects are discovered by querying its SQLite DB at `~/.local/share/opencode/opencode.db` via `opencode db --format json` (we read the `session` and `project` tables and group by `project_id`); Pi projects are discovered by scanning per-session JSONL transcripts under `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) and pulling the `cwd` from each session's first record; Hermes gateway sessions are read directly from its SQLite store at `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) and grouped into `hermes-` projects by `source` (Slack/Telegram/cli/cron — gateway sessions have no cwd); OpenClaw gateway sessions are read from `~/.openclaw/agents//sessions/*.jsonl` and grouped into `openclaw-` projects (also cwd-less); Factory Droid projects are discovered from the JSONL transcripts at `~/.factory/sessions//*.jsonl` and grouped by cwd; Devin projects from its SQLite DB at `~/.local/share/devin/cli/sessions.db` (grouped by each session's `working_directory`); Antigravity projects from the JSONL transcripts at `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` and grouped by cwd; and Goose projects from its SQLite DB at `~/.local/share/goose/sessions/sessions.db` (grouped by each session's `working_dir`). A project that has been used by multiple CLIs renders as a single row with all matching badges. Use the **CLI** dropdown above the table to filter by a specific agent CLI; the URL preserves your selection as `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Each project shows: - Project name (derived from the folder path) -- A CLI badge — `Claude Code` (orange), `OpenAI Codex` (purple), `GitHub Copilot` (blue), `Cursor Agent` (emerald), `OpenCode` (amber), `Pi` (pink), `Gemini CLI` (sky), and/or `Hermes` (indigo) +- A CLI badge — `Claude Code` (orange), `OpenAI Codex` (purple), `GitHub Copilot` (blue), `Cursor Agent` (emerald), `OpenCode` (amber), `Pi` (pink), and/or `Hermes` (indigo) - Date of most recent session activity Click a project to see its sessions. @@ -47,7 +47,7 @@ Click a session to open the session viewer. ### Session viewer -The session viewer answers the key question for autonomous agents: what did the agent do, and did it stay on track? A CLI badge beside the header indicates whether the session is a Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, or Hermes transcript. It shows a timeline of everything that happened in a session: +The session viewer answers the key question for autonomous agents: what did the agent do, and did it stay on track? A CLI badge beside the header indicates whether the session is a Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, or Goose transcript. It shows a timeline of everything that happened in a session: - **Messages** - Claude's text responses and user prompts - **Tool calls** - Every tool Claude invoked, with its input and output @@ -55,7 +55,7 @@ The session viewer answers the key question for autonomous agents: what did the The stats bar at the top shows session duration, total tool calls, and a summary of hook decisions (allow / deny / instruct counts). -Click the **Download Logs** button to export the session. For Claude Code, Codex, Copilot, Cursor, Pi, and Gemini sessions you get the original on-disk JSONL transcript byte-for-byte; for OpenCode (whose sessions live in SQLite, not on disk) you get a JSON document mirroring the underlying `session` / `messages` / `parts` tables. +Click the **Download Logs** button to export the session. For Claude Code, Codex, Copilot, Cursor, and Pi sessions you get the original on-disk JSONL transcript byte-for-byte; for OpenCode (whose sessions live in SQLite, not on disk) you get a JSON document mirroring the underlying `session` / `messages` / `parts` tables. ### Audit @@ -75,16 +75,16 @@ A two-tab page for managing policies and reviewing activity. - - Multi-select which agent CLIs failproofai protects from a single panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, and Hermes all have a row with install status (`Active` / `Detected` / `Inactive`), the user-scope settings path, and a brand-colored accent. Check or uncheck the CLIs you want and click `Apply changes` to install/uninstall the diff in one step. CLIs whose binary is detected on PATH are pre-checked. + - Multi-select which agent CLIs failproofai protects from a single panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, and Hermes all have a row with install status (`Active` / `Detected` / `Inactive`), the user-scope settings path, and a brand-colored accent. Check or uncheck the CLIs you want and click `Apply changes` to install/uninstall the diff in one step. CLIs whose binary is detected on PATH are pre-checked. - Toggle individual policies on or off with a single click (writes to `~/.failproofai/policies-config.json` — shared across every installed CLI) - Expand a policy to configure its parameters (for policies that support `policyParams`) - Set a custom policies file path - Full paginated history of every hook event that has fired across all sessions - - Filter by decision, event type, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), policy name, or session ID - - Each row shows: timestamp, policy name, decision, CLI badge (orange = Claude Code, purple = OpenAI Codex, blue = GitHub Copilot, emerald = Cursor Agent, amber = OpenCode, pink = Pi, sky = Gemini CLI, indigo = Hermes), tool name, session ID, and the reason for deny/instruct decisions - - Click a session ID to open its transcript — the viewer auto-detects which CLI fired the hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) and renders the matching CLI badge in the header + - Filter by decision, event type, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), policy name, or session ID + - Each row shows: timestamp, policy name, decision, CLI badge (orange = Claude Code, purple = OpenAI Codex, blue = GitHub Copilot, emerald = Cursor Agent, amber = OpenCode, pink = Pi, indigo = Hermes, teal = OpenClaw, rose = Factory Droid, violet = Devin, cyan = Antigravity, lime = Goose), tool name, session ID, and the reason for deny/instruct decisions + - Click a session ID to open its transcript — the viewer auto-detects which CLI fired the hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) and renders the matching CLI badge in the header diff --git a/docs/de/built-in-policies.mdx b/docs/de/built-in-policies.mdx index c7bbeca4..b53208c9 100644 --- a/docs/de/built-in-policies.mdx +++ b/docs/de/built-in-policies.mdx @@ -4,7 +4,7 @@ description: "Alle 39 integrierten Richtlinien, die häufige Fehlerszenarien von icon: shield --- -failproofai enthält 39 integrierte Richtlinien, die häufige Fehlerszenarien von Agenten abfangen. Jede Richtlinie wird für einen bestimmten Hook-Ereignistyp und Toolnamen ausgelöst. Neunzehn Richtlinien akzeptieren Parameter, mit denen Sie ihr Verhalten anpassen können, ohne Code zu schreiben. Fünf Workflow-Richtlinien erzwingen eine Commit → Push → PR → CI-Pipeline, bevor Claude anhält. +failproofai wird mit 39 integrierten Richtlinien ausgeliefert, die häufige Fehlerszenarien von Agenten abfangen. Jede Richtlinie reagiert auf einen bestimmten Hook-Ereignistyp und Tool-Namen. Neunzehn Richtlinien akzeptieren Parameter, mit denen Sie ihr Verhalten anpassen können, ohne Code schreiben zu müssen. Fünf Workflow-Richtlinien erzwingen eine Commit → Push → PR → CI-Pipeline, bevor Claude anhält. --- @@ -15,8 +15,8 @@ Richtlinien sind in Kategorien gruppiert: | Kategorie | Richtlinien | Hook-Typ | |----------|----------|-----------| | [Gefährliche Befehle](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | -| [Infra-Befehle](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [Secrets (Sanitizer)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [Infrastrukturbefehle](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | +| [Secrets (Bereiniger)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | | [Umgebung](#environment) | block-env-files, protect-env-vars | PreToolUse | | [Dateizugriff](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | @@ -27,13 +27,17 @@ Richtlinien sind in Kategorien gruppiert: - **`block-`** — verhindert, dass der Agent fortfährt. - **`warn-`** — gibt dem Agenten zusätzlichen Kontext, damit er sich selbst korrigieren kann. -- **`sanitize-`** — entfernt vertrauliche Daten aus der Tool-Ausgabe, bevor der Agent sie sieht. +- **`sanitize-`** — bereinigt sensible Daten aus der Tool-Ausgabe, bevor der Agent sie sieht. ### Namespaces -Jede Richtlinie befindet sich in einem `/`-Slot. Integrierte Richtlinien gehören zum **`failproofai/`**-Namespace — zum Beispiel `failproofai/sanitize-jwt`. Der Namespace verhindert Konflikte, wenn Sie auch benutzerdefinierte oder Drittanbieter-Richtlinien mit ähnlichen Kurznamen laden. +Jede Richtlinie befindet sich in einem `/`-Slot. Integrierte Richtlinien gehören zum +**`failproofai/`**-Namespace — zum Beispiel `failproofai/sanitize-jwt`. Der +Namespace verhindert Konflikte, wenn Sie auch benutzerdefinierte oder Drittanbieter-Richtlinien +mit ähnlichen Kurznamen laden. -In Ihrer Konfiguration können Sie eine integrierte Richtlinie entweder über ihren Kurznamen oder ihren qualifizierten Namen referenzieren; beide Formen lösen sich zur gleichen Richtlinie auf: +In Ihrer Konfiguration können Sie auf eine integrierte Richtlinie entweder über ihren Kurznamen oder ihren +qualifizierten Namen verweisen; beide Formen werden zur selben Richtlinie aufgelöst: ```json { @@ -44,20 +48,22 @@ In Ihrer Konfiguration können Sie eine integrierte Richtlinie entweder über ih } ``` -Wenn ein Name kein `/` enthält, behandelt failproofai ihn als zum Standard-Namespace `failproofai` gehörend. Namen, die bereits ein `/` enthalten (z.B. `myorg/foo`, `custom/my-hook`), werden unverändert übernommen. +Wenn ein Name kein `/` enthält, behandelt failproofai ihn als zum Standard-Namespace +`failproofai` gehörend. Namen, die bereits ein `/` enthalten (z. B. `myorg/foo`, +`custom/my-hook`), werden unverändert beibehalten. - **`require-`** — blockiert das Stop-Ereignis, bis die Bedingungen erfüllt sind. --- -Jede Richtlinie unterstützt ein optionales `hint`-Feld in `policyParams`. Der Hinweis wird an die deny- oder instruct-Nachricht angehängt, die Claude sieht, und gibt umsetzbare Anweisungen, ohne den Richtliniencode zu ändern. Funktioniert mit integrierten, benutzerdefinierten und konventionsbasierten Richtlinien. Weitere Informationen finden Sie unter [Konfiguration → hint](/de/configuration#hint-cross-cutting). +Jede Richtlinie unterstützt ein optionales `hint`-Feld in `policyParams`. Der Hinweis wird an die deny- oder instruct-Nachricht angehängt, die Claude sieht, und gibt umsetzbare Anleitungen, ohne den Richtliniencode zu verändern. Funktioniert mit integrierten, benutzerdefinierten und konventionellen Richtlinien. Weitere Informationen finden Sie unter [Konfiguration → hint](/de/configuration#hint-cross-cutting). --- ## Gefährliche Befehle -Verhindert, dass Agenten Operationen ausführen, die schwer rückgängig zu machen sind oder das Hostsystem beschädigen könnten. +Verhindert, dass Agenten Operationen ausführen, die schwer rückgängig zu machen sind oder das Host-System beschädigen könnten. ### `block-sudo` @@ -70,7 +76,7 @@ Blockiert Aufrufe, die das Schlüsselwort `sudo` enthalten. Der Musterabgleich e | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Exakte Befehlspräfixe, die erlaubt sind. Jeder Eintrag wird gegen die geparsten argv-Tokens abgeglichen. | +| `allowPatterns` | `string[]` | `[]` | Exakte Befehlspräfixe, die erlaubt sind. Jeder Eintrag wird gegen die geparsten argv-Tokens geprüft. | **Beispiel:** @@ -87,7 +93,7 @@ Blockiert Aufrufe, die das Schlüsselwort `sudo` enthalten. Der Musterabgleich e Mit dieser Konfiguration ist `sudo systemctl status nginx` erlaubt, aber `sudo rm /etc/hosts` wird verweigert. -Muster werden gegen geparste Tokens abgeglichen, nicht gegen den rohen Befehlsstring. Dies verhindert Umgehungsversuche über angehängte Shell-Operatoren (z.B. führt `sudo systemctl status x; rm -rf /` nicht zu einer Übereinstimmung mit `sudo systemctl status *`). +Muster werden gegen geparste Tokens geprüft, nicht gegen den rohen Befehlsstring. Dies verhindert Umgehungsversuche über angehängte Shell-Operatoren (z. B. entspricht `sudo systemctl status x; rm -rf /` nicht `sudo systemctl status *`). --- @@ -101,7 +107,7 @@ Muster werden gegen geparste Tokens abgeglichen, nicht gegen den rohen Befehlsst | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Pfade, die sicher rekursiv gelöscht werden dürfen (z.B. `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Pfade, die sicher rekursiv gelöscht werden dürfen (z. B. `/tmp`). | **Beispiel:** @@ -129,17 +135,17 @@ Keine Parameter. ### `block-failproofai-commands` **Ereignis:** PreToolUse (Bash) -**Standard:** Verweigert Befehle, die failproofai selbst deinstallieren oder deaktivieren würden (z.B. `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Standard:** Verweigert Befehle, die failproofai selbst deinstallieren oder deaktivieren würden (z. B. `npm uninstall failproofai`, `failproofai policies --uninstall`). Keine Parameter. --- -## Infra-Befehle +## Infrastrukturbefehle -Verhindert, dass Coding-Agenten Infrastruktur-CLIs ausführen oder CI/CD-Pipelines auslösen. Alle Richtlinien in dieser Kategorie sind **opt-in** (`defaultEnabled: false`) — Agenten, die legitimerweise `kubectl`, `terraform` usw. aufrufen müssen, werden nicht beeinträchtigt, es sei denn, Sie aktivieren die Richtlinie. Wenn aktiviert, wird jeder Aufruf der entsprechenden CLI verweigert, sofern der Befehl nicht einem Eintrag in `allowPatterns` entspricht. +Verhindert, dass Coding-Agenten Infrastruktur-CLIs ausführen oder CI/CD-Pipelines auslösen. Alle Richtlinien in dieser Kategorie sind **opt-in** (`defaultEnabled: false`) — Agenten, die legitim `kubectl`, `terraform` usw. aufrufen müssen, werden nicht beeinträchtigt, sofern Sie die Richtlinie nicht aktivieren. Wenn aktiviert, wird jeder Aufruf der entsprechenden CLI verweigert, sofern der Befehl keinem Eintrag in `allowPatterns` entspricht. -Die Muster-Grammatik ist dieselbe wie bei [`block-sudo`](#block-sudo): Tokens werden gegen geparste argv abgeglichen, `*` ist ein Platzhalter für ein Token, und jeder Befehl, der einen eigenständigen Shell-Operator (`&&`, `||`, `|`, `;`) oder ein Token mit eingebetteten Shell-Metazeichen enthält, wird vor dem Allowlist-Abgleich abgelehnt, um Injektionsumgehungen zu verhindern. +Die Mustergrammatik ist dieselbe wie bei [`block-sudo`](#block-sudo): Tokens werden gegen geparste argv geprüft, `*` ist ein Platzhalter für ein Token, und jeder Befehl, der einen eigenständigen Shell-Operator (`&&`, `||`, `|`, `;`) oder ein Token mit eingebetteten Shell-Metazeichen enthält, wird vor dem Allowlist-Abgleich abgelehnt, um Injektionsumgehungen zu verhindern. ### `block-kubectl` @@ -171,7 +177,7 @@ Mit dieser Konfiguration ist `kubectl get pods` erlaubt, aber `kubectl apply -f ### `block-terraform` **Ereignis:** PreToolUse (Bash) -**Standard:** Verweigert jeden `terraform`- oder `tofu`-(OpenTofu-)Aufruf. +**Standard:** Verweigert jeden `terraform`- oder `tofu`- (OpenTofu) Aufruf. **Parameter:** @@ -221,7 +227,7 @@ Mit dieser Konfiguration ist `kubectl get pods` erlaubt, aber `kubectl apply -f ### `block-gcloud` **Ereignis:** PreToolUse (Bash) -**Standard:** Verweigert jeden `gcloud`-(Google Cloud-)CLI-Aufruf. +**Standard:** Verweigert jeden `gcloud`- (Google Cloud) CLI-Aufruf. **Parameter:** @@ -246,7 +252,7 @@ Mit dieser Konfiguration ist `kubectl get pods` erlaubt, aber `kubectl apply -f ### `block-az-cli` **Ereignis:** PreToolUse (Bash) -**Standard:** Verweigert jeden `az`-(Azure-)CLI-Aufruf. +**Standard:** Verweigert jeden `az`- (Azure) CLI-Aufruf. **Parameter:** @@ -305,13 +311,13 @@ Mit dieser Konfiguration ist `kubectl get pods` erlaubt, aber `kubectl apply -f - `gh cache delete` - `gh secret set`, `gh secret delete` -Schreibgeschützte `gh`-Unterbefehle wie `gh pr view`, `gh pr list`, `gh run list`, `gh release view` und `gh api repos/.../...` werden von dieser Richtlinie **nicht** erfasst — sie werden routinemäßig für Workflow-Prüfungen benötigt (einschließlich failproofai's eigenem `require-ci-green-before-stop`). +Schreibgeschützte `gh`-Unterbefehle wie `gh pr view`, `gh pr list`, `gh run list`, `gh release view` und `gh api repos/.../...` werden von dieser Richtlinie **nicht** erfasst — sie werden routinemäßig für Workflow-Prüfungen benötigt (einschließlich des eigenen `require-ci-green-before-stop` von failproofai). **Parameter:** | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Bestimmte skriptgesteuerte Aufrufe, die erlaubt werden sollen, obwohl sie sonst verweigert würden. | +| `allowPatterns` | `string[]` | `[]` | Bestimmte skriptgesteuerte Aufrufe, die erlaubt sind, obwohl sie sonst verweigert würden. | **Beispiel:** @@ -327,14 +333,14 @@ Schreibgeschützte `gh`-Unterbefehle wie `gh pr view`, `gh pr list`, `gh run lis --- -## Secrets (Sanitizer) +## Secrets (Bereiniger) -Verhindert, dass Agenten Zugangsdaten in ihren Kontext oder ihre Ausgabe einschleusen. Sanitizer-Richtlinien werden bei **PostToolUse**-Ereignissen ausgelöst. Wenn Claude einen Bash-Befehl ausführt, eine Datei liest oder ein Tool aufruft, prüfen diese Richtlinien die Ausgabe, bevor sie an Claude zurückgegeben wird. Wenn ein Secret-Muster erkannt wird, gibt die Richtlinie eine Verweigerungsentscheidung zurück, die verhindert, dass die Ausgabe weitergeleitet wird. +Verhindert, dass Agenten Anmeldeinformationen in ihren Kontext oder ihre Ausgabe einschleusen. Bereiniger-Richtlinien reagieren auf **PostToolUse**-Ereignisse. Wenn Claude einen Bash-Befehl ausführt, eine Datei liest oder ein beliebiges Tool aufruft, prüfen diese Richtlinien die Ausgabe, bevor sie an Claude zurückgegeben wird. Wird ein Secret-Muster erkannt, gibt die Richtlinie eine Verweigerungsentscheidung zurück, die verhindert, dass die Ausgabe weitergeleitet wird. ### `sanitize-jwt` **Ereignis:** PostToolUse (alle Tools) -**Standard:** Schwärzt JWT-Tokens (drei base64url-Segmente, getrennt durch `.`). +**Standard:** Schwärzt JWT-Token (drei base64url-Segmente, getrennt durch `.`). Keine Parameter. @@ -343,7 +349,7 @@ Keine Parameter. ### `sanitize-api-keys` **Ereignis:** PostToolUse (alle Tools) -**Standard:** Schwärzt gängige API-Key-Formate: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS-Zugriffsschlüssel (`AKIA`), Stripe-Schlüssel (`sk_live_`, `sk_test_`) und Google API-Schlüssel (`AIza`). +**Standard:** Schwärzt gängige API-Key-Formate: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS-Zugriffsschlüssel (`AKIA`), Stripe-Schlüssel (`sk_live_`, `sk_test_`) und Google API Keys (`AIza`). **Parameter:** @@ -371,7 +377,7 @@ Keine Parameter. ### `sanitize-connection-strings` **Ereignis:** PostToolUse (alle Tools) -**Standard:** Schwärzt Datenbankverbindungszeichenfolgen, die eingebettete Zugangsdaten enthalten (z.B. `postgresql://user:password@host/db`). +**Standard:** Schwärzt Datenbankverbindungsstrings mit eingebetteten Anmeldeinformationen (z. B. `postgresql://user:password@host/db`). Keine Parameter. @@ -389,7 +395,7 @@ Keine Parameter. ### `sanitize-bearer-tokens` **Ereignis:** PostToolUse (alle Tools) -**Standard:** Schwärzt `Authorization: Bearer `-Header, bei denen das Token 20 oder mehr Zeichen lang ist. +**Standard:** Schwärzt `Authorization: Bearer `-Header, bei denen der Token 20 oder mehr Zeichen lang ist. Keine Parameter. @@ -397,14 +403,14 @@ Keine Parameter. ## Umgebung -Schützt vertrauliche Umgebungskonfigurationen davor, von Agenten gelesen oder offengelegt zu werden. +Schützt sensible Umgebungskonfigurationen davor, von Agenten gelesen oder offengelegt zu werden. ### `block-env-files` **Ereignis:** PreToolUse (Bash, Read) **Standard:** Verweigert das Lesen von `.env`-Dateien über `cat .env`, `Read`-Tool-Aufrufe mit `.env` als Dateipfad usw. -Blockiert nicht `.envrc` oder andere umgebungsnahe Dateien — nur Dateien, die exakt `.env` heißen. +Blockiert keine `.envrc`- oder anderen umgebungsnahen Dateien — nur Dateien mit dem exakten Namen `.env`. Keine Parameter. @@ -421,18 +427,18 @@ Keine Parameter. ## Dateizugriff -Hält Agenten innerhalb der Projektgrenzen und fernab von vertraulichen Dateien. +Hält Agenten innerhalb der Projektgrenzen und fernab sensibler Dateien. ### `block-read-outside-cwd` **Ereignis:** PreToolUse (Read, Bash) -**Standard:** Verweigert das Lesen von Dateien außerhalb des Projektstamms. Die Grenze ist `CLAUDE_PROJECT_DIR` (einmalig pro Sitzung von Claude Code gesetzt), mit einem Fallback auf das aktuelle Arbeitsverzeichnis der Sitzung, wenn diese Variable nicht gesetzt ist. Die Verwendung des Projektstamms anstelle des Live-`cwd` bedeutet, dass die Grenze stabil bleibt, auch nachdem Claude in ein Unterverzeichnis gewechselt hat. +**Standard:** Verweigert das Lesen von Dateien außerhalb des Projektstammverzeichnisses. Die Grenze ist `CLAUDE_PROJECT_DIR` (einmalig pro Sitzung von Claude Code gesetzt), mit einem Fallback auf das aktuelle Arbeitsverzeichnis der Sitzung, wenn diese Variable nicht gesetzt ist. Durch die Verwendung des Projektstammverzeichnisses anstelle des aktuellen `cwd` bleibt die Grenze stabil, auch wenn Claude in ein Unterverzeichnis wechselt. **Parameter:** | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Absolute Pfadpräfixe, die auch außerhalb des Projektstamms erlaubt sind. | +| `allowPaths` | `string[]` | `[]` | Absolute Pfadpräfixe, die auch außerhalb des Projektstammverzeichnisses erlaubt sind. | **Beispiel:** @@ -451,7 +457,7 @@ Hält Agenten innerhalb der Projektgrenzen und fernab von vertraulichen Dateien. ### `block-secrets-write` **Ereignis:** PreToolUse (Write, Edit) -**Standard:** Verweigert Schreibvorgänge in Dateien, die üblicherweise für private Schlüssel und Zertifikate verwendet werden: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Standard:** Verweigert Schreibvorgänge in Dateien, die häufig für private Schlüssel und Zertifikate verwendet werden: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Parameter:** @@ -501,7 +507,7 @@ Verhindert versehentliche Pushes, Force-Pushes und Branch-Fehler, die schwer rü ``` -Um das Pushen auf alle Branches zu erlauben (wodurch diese Richtlinie effektiv deaktiviert wird, ohne sie aus `enabledPolicies` zu entfernen), setzen Sie `protectedBranches: []`. +Um das Pushen auf alle Branches zu erlauben (was diese Richtlinie effektiv deaktiviert, ohne sie aus `enabledPolicies` zu entfernen), setzen Sie `protectedBranches: []`. --- @@ -509,7 +515,7 @@ Um das Pushen auf alle Branches zu erlauben (wodurch diese Richtlinie effektiv d ### `block-work-on-main` **Ereignis:** PreToolUse (Bash) -**Standard:** Verweigert `git commit`, `git merge`, `git rebase` und `git cherry-pick`, wenn sich der Working Tree auf `main` oder `master` befindet. Branch-Erstellung und -Wechsel (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) sind nicht betroffen. +**Standard:** Verweigert `git commit`, `git merge`, `git rebase` und `git cherry-pick`, solange sich der Arbeitsbaum auf `main` oder `master` befindet. Branch-Erstellung und -Wechsel (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) sind nicht betroffen. **Parameter:** @@ -524,7 +530,7 @@ Um das Pushen auf alle Branches zu erlauben (wodurch diese Richtlinie effektiv d **Ereignis:** PreToolUse (Bash) **Standard:** Verweigert `git push --force` und `git push -f`. -Keine richtlinienspezifischen Parameter. Verwenden Sie den übergreifenden [`hint`](/de/configuration#hint-cross-cutting), um Alternativen vorzuschlagen: +Keine richtlinienspezifischen Parameter. Verwenden Sie das übergreifende [`hint`](/de/configuration#hint-cross-cutting), um Alternativen vorzuschlagen: ```json { @@ -541,7 +547,7 @@ Keine richtlinienspezifischen Parameter. Verwenden Sie den übergreifenden [`hin ### `warn-git-amend` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vorsichtig vorzugehen, wenn `git commit --amend` ausgeführt wird. Blockiert den Befehl nicht. +**Standard:** Weist Claude an, beim Ausführen von `git commit --amend` vorsichtig vorzugehen. Blockiert den Befehl nicht. Keine Parameter. @@ -550,7 +556,7 @@ Keine Parameter. ### `warn-git-stash-drop` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vor der Ausführung von `git stash drop` zu bestätigen. Blockiert den Befehl nicht. +**Standard:** Weist Claude an, vor dem Ausführen von `git stash drop` zu bestätigen. Blockiert den Befehl nicht. Keine Parameter. @@ -572,7 +578,7 @@ Fängt destruktive SQL-Operationen ab, bevor sie gegen Ihre Datenbank ausgeführ ### `warn-destructive-sql` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vor der Ausführung von SQL mit `DROP TABLE`, `DROP DATABASE` oder `DELETE` ohne `WHERE`-Klausel zu bestätigen. +**Standard:** Weist Claude an, vor dem Ausführen von SQL mit `DROP TABLE`, `DROP DATABASE` oder `DELETE` ohne `WHERE`-Klausel zu bestätigen. Keine Parameter. @@ -581,7 +587,7 @@ Keine Parameter. ### `warn-schema-alteration` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vor der Ausführung von `ALTER TABLE`-Anweisungen zu bestätigen. +**Standard:** Weist Claude an, vor dem Ausführen von `ALTER TABLE`-Anweisungen zu bestätigen. Keine Parameter. @@ -600,7 +606,7 @@ Gibt Agenten zusätzlichen Kontext vor potenziell riskanten, aber nicht destrukt | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | Dateigröße in Kilobyte, ab der eine Warnung ausgegeben wird. | +| `thresholdKb` | `number` | `1024` | Dateigrößenschwelle in Kilobyte, ab der eine Warnung ausgegeben wird. | **Beispiel:** @@ -615,7 +621,7 @@ Gibt Agenten zusätzlichen Kontext vor potenziell riskanten, aber nicht destrukt ``` -Der Hook-Handler erzwingt ein stdin-Limit von 1 MB für Payloads. Um diese Richtlinie mit kleinen Inhalten zu testen, setzen Sie `thresholdKb` auf einen Wert deutlich unter 1024. +Der Hook-Handler erzwingt ein 1-MB-stdin-Limit für Payloads. Um diese Richtlinie mit kleinen Inhalten zu testen, setzen Sie `thresholdKb` auf einen Wert deutlich unter 1024. --- @@ -623,7 +629,7 @@ Der Hook-Handler erzwingt ein stdin-Limit von 1 MB für Payloads. Um diese Richt ### `warn-package-publish` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vor der Ausführung von `npm publish` zu bestätigen. +**Standard:** Weist Claude an, vor dem Ausführen von `npm publish` zu bestätigen. Keine Parameter. @@ -641,7 +647,7 @@ Keine Parameter. ### `warn-global-package-install` **Ereignis:** PreToolUse (Bash) -**Standard:** Weist Claude an, vor der Ausführung von `npm install -g`, `yarn global add` oder `pip install` ohne virtuelle Umgebung zu bestätigen. +**Standard:** Weist Claude an, vor dem Ausführen von `npm install -g`, `yarn global add` oder `pip install` ohne virtuelle Umgebung zu bestätigen. Keine Parameter. @@ -654,16 +660,16 @@ Legt fest, welche Paketmanager der Agent verwenden darf. ### `prefer-package-manager` **Ereignis:** PreToolUse (Bash) -**Standard:** Deaktiviert. Wenn aktiviert, blockiert alle Paketmanager-Befehle, die nicht in der `allowed`-Liste stehen, und teilt Claude mit, den Befehl mit einem erlaubten Manager umzuschreiben. +**Standard:** Deaktiviert. Wenn aktiviert, blockiert jeden Paketmanager-Befehl, der nicht in der `allowed`-Liste steht, und fordert Claude auf, den Befehl mit einem erlaubten Manager umzuschreiben. Erkennt: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | Parameter | Typ | Standard | Beschreibung | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Erlaubte Paketmanager-Namen. Jeder erkannte Manager, der nicht in dieser Liste steht, wird blockiert. Wenn leer, ist die Richtlinie wirkungslos. | -| `blocked` | string[] | `[]` | Zusätzliche Manager-Namen, die über die integrierte Liste hinaus blockiert werden sollen (z.B. `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Erlaubte Paketmanager-Namen. Jeder erkannte Manager, der nicht in dieser Liste steht, wird blockiert. Bei leerer Liste ist die Richtlinie wirkungslos. | +| `blocked` | string[] | `[]` | Zusätzliche Manager-Namen, die über die integrierte Liste hinaus blockiert werden sollen (z. B. `['pdm', 'pipx']`). | -Die integrierte Blockliste umfasst: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Verwenden Sie `blocked`, um Manager hinzuzufügen, die nicht in dieser Liste sind. +Die integrierte Blockliste umfasst: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Verwenden Sie `blocked`, um Manager hinzuzufügen, die nicht in dieser Liste enthalten sind. **Beispielkonfiguration:** @@ -679,18 +685,18 @@ Die integrierte Blockliste umfasst: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, } ``` -Mit dieser Konfiguration werden `pip install flask` und `pdm install flask` beide verweigert, mit einer Nachricht, die Claude auffordert, stattdessen `uv` oder `bun` zu verwenden. Befehle wie `uv pip install flask` sind erlaubt, da `uv` in der Allowlist steht und zuerst geprüft wird. +Mit dieser Konfiguration werden `pip install flask` und `pdm install flask` beide mit einer Meldung verweigert, die Claude auffordert, stattdessen `uv` oder `bun` zu verwenden. Befehle wie `uv pip install flask` sind erlaubt, da `uv` in der Allowlist steht und zuerst geprüft wird. --- ## KI-Verhalten -Erkennt, wenn Agenten stecken bleiben oder sich unerwartet verhalten. +Erkennt, wenn Agenten feststecken oder sich unerwartet verhalten. ### `warn-repeated-tool-calls` **Ereignis:** PreToolUse (alle Tools) -**Standard:** Weist Claude an, seine Vorgehensweise zu überdenken, wenn dasselbe Tool drei oder mehr Mal mit identischen Parametern aufgerufen wird — ein häufiges Zeichen dafür, dass der Agent in einer Schleife steckt. +**Standard:** Weist Claude an, seinen Ansatz zu überdenken, wenn dasselbe Tool 3 oder mehr Mal mit identischen Parametern aufgerufen wird — ein häufiges Zeichen dafür, dass der Agent in einer Schleife feststeckt. Keine Parameter. @@ -698,40 +704,39 @@ Keine Parameter. ## Workflow -Erzwingt einen disziplinierten Workflow am Sitzungsende. Diese Richtlinien werden beim **Stop**-Ereignis ausgelöst und verhindern, dass der Agent anhält, bis jede Bedingung erfüllt ist. Sie folgen einer natürlichen Abhängigkeitskette: Commit → Push → PR → CI. Wenn eine Richtlinie verweigert, werden spätere Richtlinien in der Kette übersprungen (Deny bricht ab). +Erzwingt einen disziplinierten Workflow am Ende einer Sitzung. Diese Richtlinien reagieren auf das **Stop**-Ereignis und verhindern, dass der Agent anhält, bis jede Bedingung erfüllt ist. Sie folgen einer natürlichen Abhängigkeitskette: Commit → Push → PR → CI. Wenn eine Richtlinie verweigert, werden spätere Richtlinien in der Kette übersprungen (deny schließt kurz). -Alle Workflow-Richtlinien sind **fail-open**: Wenn das erforderliche Tool nicht verfügbar ist (z.B. `gh` nicht installiert, kein git-Remote), erlaubt die Richtlinie mit einer informativen Nachricht, die erklärt, warum die Prüfung übersprungen wurde. +Alle Workflow-Richtlinien sind **fail-open**: Wenn das erforderliche Tool nicht verfügbar ist (z. B. `gh` nicht installiert, kein Git-Remote), erlaubt die Richtlinie mit einer informativen Meldung, die erklärt, warum die Prüfung übersprungen wurde. ### Stop-Semantik je CLI -Die Stop-Durchsetzung sieht bei den sieben unterstützten CLIs etwas unterschiedlich aus, da jede eine andere Vertragsgestaltung für den Hook „Agent fertig" bietet. Das **Ergebnis** ist dasselbe — der Agent kommt nicht damit durch, anzuhalten, während ein Workflow-Gate fehlschlägt — aber die **Mechanik** unterscheidet sich. Die folgende Tabelle fasst dies zusammen; nur Pi hat eine für Benutzer sichtbare Besonderheit, die Sie verstehen sollten, bevor Sie eine `require-*-before-stop`-Richtlinie aktivieren. +Die Stop-Durchsetzung unterscheidet sich je nach den sechs unterstützten CLIs leicht, da jede einen anderen Hook-Vertrag für das Ereignis implementiert. Das **Ergebnis** ist dasselbe — der Agent kann nicht anhalten, solange ein Workflow-Gate fehlschlägt — aber die **Mechanik** unterscheidet sich. Die folgende Tabelle fasst dies zusammen; nur Pi hat eine für den Benutzer sichtbare Besonderheit, die Sie kennen sollten, bevor Sie eine `require-*-before-stop`-Richtlinie aktivieren. -| CLI | Wann das Gate auslöst | Was Sie sehen | +| CLI | Wann das Gate ausgelöst wird | Was Sie sehen | |---|---|---| -| Claude Code | Gleiche Agentenschleife, sofort | Claude arbeitet weiter — behebt das Problem, versucht dann erneut zu beenden. Für Sie keine sichtbare Unterbrechung. | -| Codex | Gleiche Agentenschleife, sofort | Wie Claude. | -| GitHub Copilot CLI | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Copilots `{decision:"block", reason}`-Wiederholungskanal — empirisch verifiziert gegen Copilot CLI 1.0.41). | -| Cursor Agent | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Cursors `{followup_message}`-Kanal — begrenzt auf `loop_limit`, standardmäßig 5 Wiederholungen). | -| Gemini CLI | Gleiche Agentenschleife, sofort | Wie Claude (verwendet Geminis `{decision:"block", reason}`-Kanal auf `AfterAgent`). | -| OpenCode | Gleiche Agentenschleife, sofort | Wie Claude (verwendet OpenCodes `client.session.prompt(...)`-SDK-Aufruf, der über `hookSpecificOutput.additionalContext` geleitet wird). | -| **Pi (pi-coding-agent)** | **Nächster Benutzerturn** | **Pi hält sichtbar an**, wenn das Gate auslöst — seine Agentenschleife beendet sich und Sie gelangen zurück zur Eingabeaufforderung. Das Gate löst dann beim nächsten Absenden einer Eingabe aus: failproofai stellt eine `MANDATORY ACTION REQUIRED`-Direktive an den Systempromt dieses Turns voran und weist das LLM an, den Workflow-Schritt (Commit, Push usw.) abzuschließen, bevor es das Gewünschte tut. | +| Claude Code | Dieselbe Agenten-Schleife, sofort | Claude arbeitet weiter — behebt das Problem und versucht dann erneut zu beenden. Für Sie keine sichtbare Unterbrechung. | +| Codex | Dieselbe Agenten-Schleife, sofort | Wie bei Claude. | +| GitHub Copilot CLI | Dieselbe Agenten-Schleife, sofort | Wie bei Claude (verwendet Copilots `{decision:"block", reason}`-Wiederholungskanal — empirisch gegen Copilot CLI 1.0.41 verifiziert). | +| Cursor Agent | Dieselbe Agenten-Schleife, sofort | Wie bei Claude (verwendet Cursors `{followup_message}`-Kanal — begrenzt durch `loop_limit`, standardmäßig 5 Wiederholungen). | +| OpenCode | Dieselbe Agenten-Schleife, sofort | Wie bei Claude (verwendet OpenCodes `client.session.prompt(...)`-SDK-Aufruf, der über `hookSpecificOutput.additionalContext` geleitet wird). | +| **Pi (pi-coding-agent)** | **Nächster Benutzerturn** | **Pi hält sichtbar an**, wenn das Gate ausgelöst wird — seine Agenten-Schleife endet und Sie kehren zur Eingabeaufforderung zurück. Das Gate wird beim nächsten Einreichen einer Eingabe ausgelöst: failproofai stellt dem System-Prompt dieses Turns eine `MANDATORY ACTION REQUIRED`-Direktive voran, die das LLM anweist, den Workflow-Schritt (Commit, Push usw.) abzuschließen, bevor es Ihre Anfrage bearbeitet. | -**Pi-Einschränkung.** Pis `AgentEndEvent` (das Upstream-Äquivalent zu Claudes `Stop`-Hook) hat keinen Result-Typ — wenn er auslöst, hat Pis Agentenschleife bereits beendet. Pi kann nicht dazu gezwungen werden, dieselbe Schleife zu wiederholen, wie es Claude / Copilot / Cursor / Gemini / OpenCode können. failproofai verlagert das Gate auf Pis `before_agent_start`-Ereignis (das nach der nächsten Benutzereingabe auslöst), sodass die Workflow-Prüfung trotzdem greift, nur beim nächsten Turn statt beim aktuellen. +**Pi-Einschränkung.** Pis `AgentEndEvent` (das Upstream-Äquivalent von Claudes `Stop`-Hook) hat keinen Result-Typ — bis er ausgelöst wird, hat Pis Agenten-Schleife bereits geendet. Pi kann nicht zur Wiederholung derselben Schleife gezwungen werden, wie es bei Claude / Copilot / Cursor / OpenCode möglich ist. failproofai verschiebt das Gate auf Pis `before_agent_start`-Ereignis (das nach dem nächsten Benutzer-Prompt ausgelöst wird), sodass die Workflow-Prüfung noch durchgesetzt wird — allerdings im nächsten Turn statt im aktuellen. **Was das in der Praxis bedeutet:** -- Nachdem Pi anhält, wird der Ablehnungsgrund im Speicher gespeichert, indexiert nach Pi-Sitzungs-ID. Die nächste Eingabe, die Sie im selben Pi-Prozess absenden, entleert ihn: Das LLM sieht die `MANDATORY ACTION REQUIRED`-Direktive am Anfang seines Systemprompts, führt einen Commit durch (oder Push / öffnet den PR / wartet auf CI) und fährt erst dann mit Ihrer Anfrage fort. Der gespeicherte Ablehnungsgrund ist einmalig — sobald entleert, ist das Gate frei. -- Das Gate ist durch die Prozesslebensdauer von Pi begrenzt. Wenn Sie Pi zwischen den Turns mit `Ctrl+C` beenden oder schließen, wird der In-Memory-Eintrag zusammen mit dem Prozess gelöscht und das Gate wird verfehlt. Claude, Copilot, Cursor, Gemini und OpenCode haben dieselbe Einschränkung (Agent beenden und das Gate wird verfehlt) — bei Pi ist es nur sichtbarer, weil der Agent sichtbar beendet wird, bevor das Gate auslöst. -- Ein ausstehender Deny wird auch bei `session_shutdown` aus beliebigem Grund (`new` / `resume` / `fork` / `quit`) gelöscht, sodass ein veraltetes Gate einer vorherigen Sitzung nicht in eine neue Sitzung überlaufen kann, die im selben Pi-Prozess gestartet wurde. +- Nachdem Pi anhält, wird der Verweigerungsgrund im Speicher gespeichert, indexiert nach der Pi-Sitzungs-ID. Der allernächste Prompt, den Sie im selben Pi-Prozess einreichen, leert ihn: Das LLM sieht die `MANDATORY ACTION REQUIRED`-Direktive am Anfang seines System-Prompts, führt den Commit (oder Push / öffnet den PR / wartet auf CI) durch und fährt dann erst mit Ihrer Anfrage fort. Der gespeicherte Verweigerungsgrund ist einmalig — nach dem Leeren ist das Gate frei. +- Das Gate ist an die Prozesslebensdauer von Pi gebunden. Wenn Sie Pi zwischen den Turns mit `Ctrl+C` beenden oder schließen, wird der In-Memory-Eintrag zusammen mit dem Prozess gelöscht und das Gate wird verpasst. Claude, Copilot, Cursor und OpenCode haben dieselbe Einschränkung (den Agenten beenden, und das Gate wird verpasst) — bei Pi ist es nur sichtbarer, weil der Agent vor dem Auslösen des Gates sichtbar beendet wird. +- Ein ausstehender Verweigerungsgrund wird auch bei `session_shutdown` aus beliebigem Grund (`new` / `resume` / `fork` / `quit`) gelöscht, sodass ein veraltetes Gate einer früheren Sitzung nicht in eine neue Sitzung im selben Pi-Prozess durchsickern kann. -Wenn Sie das Claude-ähnliche Wiederholen in derselben Schleife benötigen, führen Sie Ihre `Stop`-Richtlinien unter einer der anderen sechs unterstützten CLIs aus. Wir verfolgen Pi upstream auf einen zukünftigen Result-Typ bei `AgentEndEvent`, der es uns ermöglichen würde, diese Lücke zu schließen. +Wenn Sie Claude-ähnliche Wiederholungen in derselben Schleife benötigen, führen Sie Ihre `Stop`-Richtlinien unter einer der anderen fünf unterstützten CLIs aus. Wir verfolgen Pi Upstream auf einen zukünftigen Result-Typ für `AgentEndEvent`, der es uns ermöglichen würde, diese Lücke zu schließen. ### `require-commit-before-stop` **Ereignis:** Stop -**Standard:** Verweigert das Anhalten, wenn nicht committete Änderungen vorhanden sind (geänderte, gestagete oder nicht verfolgte Dateien). Gibt eine informative Nachricht zurück, wenn das Arbeitsverzeichnis sauber ist. +**Standard:** Verweigert das Anhalten, wenn nicht committete Änderungen vorhanden sind (geänderte, gestagede oder nicht getrackte Dateien). Gibt eine informative Meldung zurück, wenn das Arbeitsverzeichnis sauber ist. Keine Parameter. @@ -740,13 +745,13 @@ Keine Parameter. ### `require-push-before-stop` **Ereignis:** Stop -**Standard:** Verweigert das Anhalten, wenn nicht gepushte Commits vorhanden sind oder wenn der aktuelle Branch keinen Remote-Tracking-Branch hat. Schlägt bei Bedarf `git push -u` vor, um einen Tracking-Branch zu erstellen. Fail-open, wenn kein Remote konfiguriert ist. +**Standard:** Verweigert das Anhalten, wenn nicht gepushte Commits vorhanden sind oder wenn der aktuelle Branch keinen Remote-Tracking-Branch hat. Schlägt `git push -u` vor, um bei Bedarf einen Tracking-Branch zu erstellen. Schlägt fehl-offen, wenn kein Remote konfiguriert ist. **Parameter:** | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | Remote-Name, zu dem gepusht wird. | +| `remote` | `string` | `"origin"` | Name des Remotes, auf das gepusht werden soll. | **Beispiel:** @@ -765,14 +770,14 @@ Keine Parameter. ### `require-pr-before-stop` **Ereignis:** Stop -**Standard:** Verweigert das Anhalten, wenn kein Pull Request für den aktuellen Branch existiert oder wenn der vorhandene PR ohne Merge geschlossen wurde. Weist Claude an, einen PR mit `gh pr create` zu erstellen. Wenn der PR **gemergt** wurde, erlaubt die Richtlinie (die Arbeit ist ausgeliefert) und die Nachricht gibt den Hinweis, den Branch zu wechseln (`git checkout main && git pull`). +**Standard:** Verweigert das Anhalten, wenn kein Pull Request für den aktuellen Branch existiert oder wenn der vorhandene PR ohne Merge geschlossen wurde. Weist Claude an, einen PR mit `gh pr create` zu erstellen. Wenn der PR **gemergt** wurde, erlaubt die Richtlinie (die Arbeit wurde ausgeliefert) und die Meldung gibt einen Hinweis, den Branch zu wechseln (`git checkout main && git pull`). Keine Parameter. -Diese Richtlinie erfordert die Installation und Authentifizierung von [GitHub CLI](https://cli.github.com/) (`gh`). +Diese Richtlinie erfordert die Installation und Authentifizierung der [GitHub CLI](https://cli.github.com/) (`gh`). Führen Sie `gh auth login` mit einem persönlichen Zugriffstoken aus, das den `repo`-Scope für Lesezugriff auf -Pull Requests hat. Wenn `gh` nicht installiert oder nicht authentifiziert ist, ist die Richtlinie fail-open und meldet den Grund an Claude. +Pull Requests hat. Wenn `gh` nicht installiert oder nicht authentifiziert ist, schlägt die Richtlinie fehl-offen und meldet Claude den Grund. --- @@ -780,23 +785,24 @@ Pull Requests hat. Wenn `gh` nicht installiert oder nicht authentifiziert ist, i ### `require-no-conflicts-before-stop` **Ereignis:** Stop -**Standard:** Verweigert das Anhalten, wenn der aktuelle Branch nicht konfliktfrei in den Basis-Branch gemergt werden kann. Die Richtlinie bestätigt zunächst, dass für den Branch ein `OPEN`-PR auf GitHub vorhanden ist — ohne einen solchen gibt es kein Merge-Ziel zum Erzwingen, sodass die gesamte Richtlinie allow zurückgibt. Sobald ein `OPEN`-PR bestätigt wurde, laufen zwei unabhängige Prüfungen: +**Standard:** Verweigert das Anhalten, wenn der aktuelle Branch nicht sauber in den Basis-Branch gemergt werden kann. Die Richtlinie bestätigt zunächst, dass es einen `OPEN`-PR auf GitHub für den Branch gibt — ohne einen solchen gibt es kein Merge-Ziel zum Durchsetzen, sodass die gesamte Richtlinie kurzschließt und erlaubt. Sobald ein `OPEN`-PR bestätigt ist, werden zwei unabhängige Prüfungen durchgeführt: -1. **Lokal** — `git merge-tree --write-tree --name-only origin/ HEAD`. Bei einem Konflikt nennt die Deny-Nachricht die konfliktbehafteten Dateien, damit Claude genau weiß, was zu lösen ist. -2. **GitHub** — verwendet das bereits beim Vorcheck abgerufene `gh pr view --json mergeable,state`-Ergebnis erneut. Fängt Konflikte ab, die ein veraltetes lokales `origin/` übersehen würde (z.B. wenn jemand einen konfliktbehafteten PR auf `main` seit dem letzten Fetch gemergt hat). Ein `CONFLICTING`-Ergebnis verweigert. Ein `UNKNOWN`-Ergebnis verweigert ebenfalls und weist Claude an, etwa 10 Sekunden zu warten und erneut zu prüfen, bevor ein erneuter Stoppversuch unternommen wird — dies verhindert falsche Negative, während GitHub neu berechnet. +1. **Lokal** — `git merge-tree --write-tree --name-only origin/ HEAD`. Bei einem Konflikt nennt die Verweigerungsmeldung die konfliktbehafteten Dateien, damit Claude genau weiß, was zu beheben ist. +2. **GitHub** — verwendet das bereits beim Vorcheck abgerufene `gh pr view --json mergeable,state`-Ergebnis. Erfasst Konflikte, die ein veraltetes lokales `origin/` verpassen würde (z. B. wenn jemand seit dem letzten Fetch einen konfliktbehafteten PR auf `main` gemergt hat). Ein `CONFLICTING`-Ergebnis verweigert. Ein `UNKNOWN`-Ergebnis verweigert ebenfalls und weist Claude an, ~10 Sekunden zu warten und erneut zu prüfen, bevor es erneut versucht zu stoppen — dies verhindert falsche Negative, während GitHub neu berechnet. -Überspringt vollständig (erlaubt), wenn: `gh` nicht installiert ist, kein PR für den Branch vorhanden ist, der PR-Status nicht `OPEN` ist (z.B. `MERGED`, `CLOSED`), oder `gh pr view` nicht parsbare Ausgabe liefert. Fail-open auch wenn `origin/` lokal fehlt oder wenn keine Commits vor dem Basis-Branch vorhanden sind — diese Layer-1-Durchfälle konsultieren trotzdem die zwischengespeicherte PR-Zusammenführbarkeit, bevor sie erlauben. +Überspringt vollständig (erlaubt), wenn: `gh` nicht installiert ist, kein PR für den Branch existiert, der PR-Status nicht `OPEN` ist (z. B. `MERGED`, `CLOSED`), oder `gh pr view` nicht parsbare Ausgabe zurückgibt. Schlägt auch fehl-offen, wenn `origin/` lokal fehlt oder keine Commits vor dem Basis-Branch vorhanden sind — diese Layer-1-Durchfälle konsultieren immer noch die gecachte PR-Mergierbarkeit, bevor sie erlauben. **Parameter:** | Parameter | Typ | Standard | Beschreibung | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Basis-Branch, gegen den auf Konflikte geprüft wird. | +| `baseBranch` | `string` | `"main"` | Basis-Branch, gegen den auf Konflikte geprüft werden soll. | GitHub CLI (`gh`) ist für diese Richtlinie erforderlich. Die Richtlinie verwendet `gh pr view`, um zu bestätigen, -dass ein `OPEN`-PR vorhanden ist, bevor eine Konfliktprüfung durchgeführt wird — ohne `gh` gibt die Richtlinie -allow zurück. Führen Sie `gh auth login` mit einem persönlichen Zugriffstoken aus, das den `repo`-Scope für Lesezugriff auf Pull Requests hat. +dass ein `OPEN`-PR existiert, bevor eine Konfliktprüfung durchgeführt wird — ohne `gh` schließt die Richtlinie +kurzschluss und erlaubt. Führen Sie `gh auth login` mit einem persönlichen Zugriffstoken aus, das den `repo`-Scope +für Lesezugriff auf Pull Requests hat. --- @@ -804,14 +810,14 @@ allow zurück. Führen Sie `gh auth login` mit einem persönlichen Zugriffstoken ### `require-ci-green-before-stop` **Ereignis:** Stop -**Standard:** Verweigert das Anhalten, wenn CI-Prüfungen fehlschlagen oder auf dem aktuellen Branch noch ausgeführt werden. Prüft sowohl GitHub Actions-Workflow-Runs als auch Drittanbieter-Bot-Prüfungen (z.B. CodeRabbit, SonarCloud, Codecov). Behandelt `skipped`-, `cancelled`- und `neutral`-Abschlüsse als nicht fehlerhaft (letzteres deckt z.B. Socket Security-Meldungen bei PRs externer Mitwirkender ab, bei denen die App absichtlich neutral statt success/failure meldet). Gibt eine informative Nachricht zurück, wenn alle Prüfungen bestanden sind. +**Standard:** Verweigert das Anhalten, wenn CI-Prüfungen auf dem aktuellen Branch fehlschlagen oder noch laufen. Prüft sowohl GitHub Actions-Workflow-Runs als auch Drittanbieter-Bot-Prüfungen (z. B. CodeRabbit, SonarCloud, Codecov). Behandelt `skipped`, `cancelled` und `neutral`-Ergebnisse als nicht fehlgeschlagen (letzteres deckt z. B. Socket Security-Warnungen bei PRs externer Mitwirkender ab, bei denen die App absichtlich neutral statt Erfolg/Fehler meldet). Gibt eine informative Meldung zurück, wenn alle Prüfungen bestehen. Keine Parameter. -Diese Richtlinie erfordert die Installation und Authentifizierung von [GitHub CLI](https://cli.github.com/) (`gh`). +Diese Richtlinie erfordert die Installation und Authentifizierung der [GitHub CLI](https://cli.github.com/) (`gh`). Führen Sie `gh auth login` mit einem persönlichen Zugriffstoken aus, das den `repo`-Scope für Lesezugriff auf -Actions-Workflow-Runs und die Checks API hat. Wenn `gh` nicht installiert oder nicht authentifiziert ist, ist die Richtlinie fail-open und meldet den Grund an Claude. +Actions-Workflow-Runs und die Checks-API hat. Wenn `gh` nicht installiert oder nicht authentifiziert ist, schlägt die Richtlinie fehl-offen und meldet Claude den Grund. --- @@ -820,7 +826,7 @@ Actions-Workflow-Runs und die Checks API hat. Wenn `gh` nicht installiert oder n ## Einzelne Richtlinien deaktivieren -Entfernen Sie eine bestimmte Richtlinie aus `enabledPolicies` in Ihrer Konfiguration, oder deaktivieren Sie sie im Dashboard-Tab „Policies". +Entfernen Sie eine bestimmte Richtlinie aus `enabledPolicies` in Ihrer Konfiguration, oder deaktivieren Sie sie im Dashboard-Tab Policies. ```json { diff --git a/docs/de/cli/audit.mdx b/docs/de/cli/audit.mdx index 833e1a9d..a1ea2759 100644 --- a/docs/de/cli/audit.mdx +++ b/docs/de/cli/audit.mdx @@ -1,21 +1,21 @@ --- title: Vergangene Sitzungen prüfen (Beta) -description: "Zähle, wie oft der Agent bei vergangenen Transkripten verschwenderische oder riskante Aktionen durchgeführt hat" +description: "Zähle, wie oft der Agent in vergangenen Transkripten verschwenderische oder riskante Aktionen ausgeführt hat" --- - **Beta-Funktion.** Das Audit wird als Beta ausgeliefert, während wir frühes Feedback sammeln. - Der Detektor-Katalog und das Berichtsformat können sich vor dem nächsten stabilen + **Beta-Funktion.** Das Audit-Feature wird als Beta veröffentlicht, während wir frühe Rückmeldungen sammeln. + Der Detector-Katalog und das Berichtsformat können sich vor dem nächsten stabilen Release ändern. Bitte öffne ein Issue, wenn etwas nicht stimmt. -Das Audit spielt vergangene Agent-CLI-Transkripte durch die Richtlinien-Engine von failproofai -ab und erstellt einen teilbaren, visuellen Bericht auf der **`/audit`-Dashboard-Seite** – -den Archetyp deines Agenten, einen Score von 0–100 und genau welche Richtlinien was abgefangen hätten. +Das Audit spielt vergangene Agent-CLI-Transkripte durch failproofais Policy-Engine +ab und erstellt einen teilbaren, visuellen Bericht auf der **`/audit`-Dashboard-Seite** — +das Archetyp deines Agenten, ein Score von 0–100 und genau, welche Policies was abgefangen hätten. ## Ausführen -Drei Einstiegsmöglichkeiten – alle landen im selben `/audit`-Bericht. +Drei Möglichkeiten — alle führen zum selben `/audit`-Bericht. @@ -34,62 +34,62 @@ failproofai - + `npx -y failproofai audit` lädt failproofai herunter, führt den Scan durch und öffnet das - Dashboard für dich – nichts muss vorab installiert werden. + Dashboard — nichts muss zuvor installiert werden. `failproofai audit` führt den Scan im Terminal aus und öffnet anschließend automatisch `localhost:8020/audit`. - Führe `failproofai` aus und klicke in der Navigationsleiste auf **Audit** (zwischen Policies und + Starte `failproofai` und klicke in der Navigationsleiste auf **Audit** (zwischen Policies und Projects), oder öffne `/audit` direkt. Führe `failproofai audit -h` (oder `--help`) aus, um die Verwendung anzuzeigen. Das Audit läuft **vollständig - offline** – kein Account oder Netzwerk erforderlich – und das Dashboard bleibt aktiv, + offline** — kein Konto oder Netzwerk erforderlich — und das Dashboard bleibt aktiv, bis du es mit `Ctrl+C` beendest. -Das Dashboard scannt vergangene Agent-CLI-Transkripte auf diesem Rechner (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) und meldet, wie oft der Agent Dinge getan hat, die failproofai unterbinden soll – Env-Var-Prüfungen, Force-Pushes, redundante `cd `-Präfixe, Sleep-Polling-Schleifen, erneutes Einlesen gerade bearbeiteter Dateien und mehr. +Das Dashboard scannt vergangene Agent-CLI-Transkripte auf diesem Rechner (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) und zeigt, wie oft der Agent Dinge getan hat, die failproofai verhindern soll — Env-Var-Prüfungen, Force Pushes, redundante `cd `-Präfixe, Sleep-Polling-Schleifen, erneutes Lesen gerade bearbeiteter Dateien und mehr. -Für jedes Transkript wird jedes Tool-Use-Ereignis durch die 39 eingebauten Richtlinien **und** durch 8 Audit-exklusive Detektoren abgespielt, die Muster erkennen, die noch nicht von Laufzeit-Richtlinien abgedeckt werden. Die Zählungen werden pro Richtlinie bzw. Detektor über alle Sitzungen hinweg aggregiert. +Für jedes Transkript wird jedes Tool-Use-Ereignis durch die 39 eingebauten Policies **sowie** durch 8 Audit-exklusive Detektoren abgespielt, die Muster erkennen, die noch nicht von Laufzeit-Policies abgedeckt werden. Die Zählungen werden pro Policy / Detektor über alle Sitzungen aggregiert. ## Was du erhältst -Die `/audit`-Seite ist ein einseitiges, teilbares **Poster**, gefolgt von vier Abschnitten darunter: +Die `/audit`-Seite ist ein einzeiliger, teilbarer **Poster** gefolgt von vier Abschnitten unterhalb des sichtbaren Bereichs: -1. **Poster** – die Identität deines Agenten auf einen Blick: sein **Archetyp** (einer von 8 – `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), seine Persona-Schlüsselwörter, wie selten dieser Archetyp ist, und ein **0–100-Score** mit Bandebene (`S` bis `bottom tier`). Zum Teilen gemacht – poste es auf X oder LinkedIn oder lade es als PNG herunter. -2. **`// strengths`** – was dein Agent bereits gut macht, als echte Zahlen aus dem Scan (z. B. Clean-Tool-Call-%, `0` Push-to-Main-Versuche), wird nur angezeigt, wenn die entsprechende Richtlinie eine saubere Bilanz hat. -3. **`// quirks`** – was durchgerutscht ist: eine nach Rang geordnete Tabelle von Verhaltensweisen, die failproofai abgefangen hätte – *wann* es zuletzt passiert ist, *was durchgerutscht ist* (und die eingebaute Richtlinie, die es blockiert hätte), der *Schweregrad* und wie oft es *gesehen* wurde (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** – die vorgeschlagene Korrekturreihenfolge: eine Zeile pro Richtlinie mit einem kopierbaren `failproofai policy add `, plus einem **Alle installieren**-Button, der jede Empfehlung auf einmal aktiviert und deinen **projizierten Score** anzeigt, wenn du das tätest. -5. **`// come back better`** – bau dir die Gewohnheit auf: setze eine E-Mail-**Erinnerung** für eine erneute Prüfung (`3d` / `7d` / `14d` / `30d`) oder prüfe jetzt erneut, und **lade einen Freund ein**, sein eigenes Audit durchzuführen (gesendet von failproof.ai, mit dir in Cc). Erinnerungen und Einladungen erfordern eine Anmeldung – siehe [`failproofai auth`](/de/cli/auth). +1. **Poster** — die Identität deines Agenten auf einen Blick: sein **Archetyp** (einer von 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), seine Persona-Schlüsselwörter, wie selten dieser Archetyp ist, und ein **Score von 0–100** mit einem Tier-Band (`S` bis `bottom tier`). Zum Teilen gemacht — poste ihn auf X oder LinkedIn oder lade ihn als PNG herunter. +2. **`// strengths`** — was dein Agent bereits gut macht, als echte Zahlen aus dem Scan (z. B. Clean-Tool-Call-%, `0` Push-to-Main-Versuche), nur angezeigt, wenn die betreffende Policy eine einwandfreie Bilanz hat. +3. **`// quirks`** — was durchgerutscht ist: eine sortierte Tabelle von Verhaltensweisen, die failproofai abgefangen hätte — *wann* es zuletzt passierte, *was durchrutschte* (und die eingebaute Policy, die es blockiert hätte), dessen *Schweregrad* und wie oft es *gesehen* wurde (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — die empfohlene Korrektourliste: eine Zeile pro Policy mit einem kopierbaren `failproofai policy add `, plus einem **Alle installieren**-Button, der jede Empfehlung auf einmal aktiviert und deinen **voraussichtlichen Score** anzeigt. +5. **`// come back better`** — baue die Gewohnheit auf: stelle eine E-Mail-**Erinnerung** für ein erneutes Audit ein (`3d` / `7d` / `14d` / `30d`) oder führe jetzt ein Audit durch, und **lade einen Freund** ein, ihr eigenes Audit durchzuführen (gesendet von failproof.ai, mit Kopie an dich). Erinnerungen und Einladungen erfordern eine Anmeldung — siehe [`failproofai auth`](/de/cli/auth). ## Audit-exklusive Detektoren -Diese erkennen Muster für unkluge Verhaltensweisen, die (noch) nicht in Echtzeit erzwungen werden. Sie laufen nur während des Audits und blockieren niemals einen Live-Tool-Aufruf. +Diese erkennen Muster für unkluge Verhaltensweisen, die (noch) nicht in Echtzeit durchgesetzt werden. Sie laufen nur während des Audits und blockieren niemals einen Live-Tool-Aufruf. -| Detektor | Was er zählt | +| Detektor | Was gezählt wird | |---|---| -| `redundant-cd-cwd` | Bash-Befehle, die mit `cd && …` beginnen, obwohl Befehle bereits in `cwd` laufen. | -| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` auf einer einzelnen Quelldatei – verwende stattdessen das `Read`-Tool. | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` In-place-Bearbeitungen – verwende stattdessen das `Edit`-Tool. | -| `prefer-write-over-heredoc` | Heredoc / mehrzeiliges `echo > file` zum Schreiben von Dateien – verwende stattdessen das `Write`-Tool. | -| `sleep-polling-loop` | Langes `sleep N` (≥ 30s) oder `while …; sleep …; done` Polling-Schleifen. | -| `find-from-root` | `find /`, `find /home`, `find /usr` usw. – auf `cwd` beschränken. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, wodurch Hooks übersprungen werden. | -| `reread-after-edit` | `Read` einer Datei, die in derselben Sitzung gerade per `Edit`/`Write` bearbeitet wurde. | +| `redundant-cd-cwd` | Bash-Befehle, die mit `cd && …` beginnen, obwohl Befehle bereits im `cwd` ausgeführt werden. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` auf einer einzelnen Quelldatei — verwende stattdessen das `Read`-Tool. | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` In-Place-Bearbeitungen — verwende das `Edit`-Tool. | +| `prefer-write-over-heredoc` | Heredoc / mehrzeilige `echo > file`-Dateioperationen — verwende das `Write`-Tool. | +| `sleep-polling-loop` | Lange `sleep N` (≥ 30s) oder `while …; sleep …; done` Polling-Schleifen. | +| `find-from-root` | `find /`, `find /home`, `find /usr` usw. — stattdessen auf `cwd` beschränken. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, um Hooks zu überspringen. | +| `reread-after-edit` | `Read` einer Datei, die gerade erst mit `Edit`/`Write` in derselben Sitzung bearbeitet wurde. | ## Caches -- **Pro-Transkript-Cache** unter `~/.failproofai/cache/audit/.json`, per `(mtime, size, engineVersion, detectorVersion)` indiziert – wird automatisch invalidiert, wenn sich das Transkript oder der Richtlinien-/Detektorcode ändert. Jeder Eintrag speichert auch einen `cachedAt`-Zeitstempel als **TTL-Metadaten** (kein Teil des Cache-Schlüssels); Einträge, die älter als **7 Tage** sind, werden beim Lesen abgelehnt, damit langlebige Ergebnisse nicht die Weiterentwicklung der Detektoren überdauern. -- **Gesamtergebnis-Cache** unter `~/.failproofai/audit-dashboard.json` (Modus 0600). Ermöglicht ein sofortiges Rendern des Dashboards beim Navigieren, ohne einen erneuten Scan durchzuführen. Wird beim Lesen ebenfalls nach dem **7-Tage-TTL** abgelehnt – `/audit` fällt dann in seinen leeren Zustand zurück und fordert einen neuen Scan an. Klicke auf `[ re-audit now ]` unten im Bericht, um zu aktualisieren – ein erneutes Audit sendet `noCache: true`, umgeht also den Pro-Transkript-Cache und scannt alle Transkripte erneut, anstatt das zwischengespeicherte Ergebnis zurückzugeben; der Lauf streamt den Fortschritt über einen fixierten oberen Streifen und tauscht das Ergebnis bei Erfolg an Ort und Stelle aus (kein Seitenneuladen; ein fehlgeschlagenes erneutes Audit behält den vorherigen Bericht). +- **Pro-Transkript-Cache** unter `~/.failproofai/cache/audit/.json`, indiziert nach `(mtime, size, engineVersion, detectorVersion)` — wird automatisch invalidiert, wenn sich das Transkript oder der Policy-/Detektor-Code ändert. Jeder Eintrag speichert auch einen `cachedAt`-Zeitstempel als **TTL-Metadaten** (kein Teil des Cache-Schlüssels); Einträge, die älter als **7 Tage** sind, werden beim Lesen abgelehnt, damit langlebige Ergebnisse nicht die sich weiterentwickelnde Detektor-Logik überdauern. +- **Gesamtergebnis-Cache** unter `~/.failproofai/audit-dashboard.json` (Modus 0600). Ermöglicht dem Dashboard, beim Navigieren sofort zu rendern, ohne erneut ausgeführt zu werden. Wird beim Lesen nach der **7-Tage-TTL** ebenfalls abgelehnt — `/audit` fällt dann in seinen leeren Zustand und fordert eine neue Ausführung an. Klicke auf `[ re-audit now ]` am unteren Ende des Berichts zum Aktualisieren — ein erneutes Audit sendet `noCache: true`, wodurch der Pro-Transkript-Cache umgangen und jedes Transkript neu gescannt wird, anstatt das gecachte Ergebnis zurückzugeben. Die Ausführung überträgt den Fortschritt über einen fixierten oberen Balken und tauscht das Ergebnis bei Erfolg nahtlos aus (kein Seiten-Reload; bei einem fehlgeschlagenen erneuten Audit bleibt der vorherige Bericht erhalten). ## Hinweise -- **Keine Mutation.** Das Audit wird im Read-only-Modus wiedergegeben. `warn-repeated-tool-calls` wird übersprungen, da sein sitzungsbegleitender Sidecar sonst modifiziert würde. -- **Workflow-Richtlinien übersprungen.** `require-*-before-stop`-Richtlinien werden nur bei `Stop`-Ereignissen ausgelöst und führen `execSync` gegen den Live-Git-Status aus – sie haben keine sinnvolle Interpretation im Sinne von "was wäre 2025 passiert", daher erscheinen sie nicht in den Audit-Zählungen. -- **Benutzerdefinierte Richtlinien übersprungen.** Vom Benutzer bereitgestellte benutzerdefinierte Hooks werden nicht wiedergegeben (sie können sich seit der ursprünglichen Sitzung geändert haben). \ No newline at end of file +- **Keine Änderungen.** Das Audit wird im schreibgeschützten Modus abgespielt. `warn-repeated-tool-calls` wird übersprungen, da sein Pro-Sitzungs-Sidecar andernfalls geändert würde. +- **Workflow-Policies übersprungen.** `require-*-before-stop`-Policies werden nur bei `Stop`-Ereignissen ausgelöst und führen `execSync` gegen den Live-Git-Zustand aus — sie haben keine sinnvolle Interpretation für vergangene Sitzungen und erscheinen daher nicht in den Audit-Zählungen. +- **Benutzerdefinierte Policies übersprungen.** Benutzerdefinierte Custom Hooks werden nicht abgespielt (sie können sich seit der ursprünglichen Sitzung geändert haben). \ No newline at end of file diff --git a/docs/de/configuration.mdx b/docs/de/configuration.mdx index a0b1ad6a..b0310993 100644 --- a/docs/de/configuration.mdx +++ b/docs/de/configuration.mdx @@ -1,28 +1,28 @@ --- title: Konfiguration -description: "Konfigurationsdateiformat, Drei-Scope-System und Zusammenführungsregeln" +description: "Konfigurationsdateiformat, Drei-Ebenen-System und Zusammenführungsregeln" icon: gear --- -failproofai verwendet JSON-Konfigurationsdateien, um zu steuern, welche Richtlinien aktiv sind, wie sie sich verhalten und woher benutzerdefinierte Richtlinien geladen werden. Die Konfiguration ist darauf ausgelegt, einfach mit Ihrem Team geteilt zu werden – committen Sie sie in Ihr Repository und jeder Entwickler erhält dasselbe Sicherheitsnetz für den Agenten. +failproofai verwendet JSON-Konfigurationsdateien, um festzulegen, welche Richtlinien aktiv sind, wie sie sich verhalten und von wo benutzerdefinierte Richtlinien geladen werden. Die Konfiguration ist so gestaltet, dass sie einfach mit dem Team geteilt werden kann – committen Sie sie in Ihr Repository, und jeder Entwickler erhält dasselbe Sicherheitsnetz für Agenten. --- -## Konfigurationsscopes +## Konfigurationsebenen -Es gibt drei Konfigurationsscopes, die in Prioritätsreihenfolge ausgewertet werden: +Es gibt drei Konfigurationsebenen, die in der folgenden Prioritätsreihenfolge ausgewertet werden: -| Scope | Dateipfad | Zweck | +| Ebene | Dateipfad | Zweck | |-------|-----------|-------| -| **project** | `.failproofai/policies-config.json` | Repository-spezifische Einstellungen, per Versionsverwaltung committet | -| **local** | `.failproofai/policies-config.local.json` | Persönliche Overrides pro Repository, per .gitignore ausgeschlossen | -| **global** | `~/.failproofai/policies-config.json` | Benutzerweite Standardeinstellungen für alle Projekte | +| **project** | `.failproofai/policies-config.json` | Repository-spezifische Einstellungen, in die Versionskontrolle eingecheckt | +| **local** | `.failproofai/policies-config.local.json` | Persönliche Repository-Überschreibungen, via gitignore ausgeschlossen | +| **global** | `~/.failproofai/policies-config.json` | Benutzerweite Standardwerte für alle Projekte | -Wenn failproofai ein Hook-Ereignis empfängt, lädt und führt es alle drei Dateien zusammen, die für das aktuelle Arbeitsverzeichnis existieren. +Wenn failproofai ein Hook-Ereignis empfängt, lädt und kombiniert es alle drei Dateien, die für das aktuelle Arbeitsverzeichnis vorhanden sind. ### Zusammenführungsregeln -**`enabledPolicies`** – die Vereinigung aller drei Scopes. Eine Richtlinie, die auf irgendeiner Ebene aktiviert ist, ist aktiv. +**`enabledPolicies`** – die Vereinigungsmenge aller drei Ebenen. Eine Richtlinie, die auf irgendeiner Ebene aktiviert ist, ist aktiv. ```text project: ["block-sudo"] @@ -32,7 +32,7 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← deduplizierte Vereinigung ``` -**`policyParams`** – der erste Scope, der Parameter für eine bestimmte Richtlinie definiert, gewinnt vollständig. Es gibt kein tiefes Zusammenführen von Werten innerhalb der Parameter einer Richtlinie. +**`policyParams`** – die erste Ebene, die Parameter für eine bestimmte Richtlinie definiert, gewinnt vollständig. Es findet kein tiefes Zusammenführen von Werten innerhalb der Parameter einer Richtlinie statt. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } @@ -42,16 +42,16 @@ resolved: { allowPatterns: ["sudo apt-get update"] } ← project gewinnt, glob ``` ```text -project: (kein block-sudo Eintrag) -local: (kein block-sudo Eintrag) +project: (kein block-sudo-Eintrag) +local: (kein block-sudo-Eintrag) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← fällt auf global zurück +resolved: { allowPatterns: ["sudo systemctl status"] } ← Durchreichen bis global ``` -**`customPoliciesPath`** – der erste Scope, der diesen definiert, gewinnt. +**`customPoliciesPath`** – die erste Ebene, die diesen Wert definiert, gewinnt. -**`llm`** – der erste Scope, der diesen definiert, gewinnt. +**`llm`** – die erste Ebene, die diesen Wert definiert, gewinnt. --- @@ -102,9 +102,9 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← fällt auf global zu Typ: `string[]` -Liste der zu aktivierenden Richtliniennamen. Die Namen müssen exakt mit den Richtlinienbezeichnern übereinstimmen, die `failproofai policies` anzeigt. Eine vollständige Liste finden Sie unter [Integrierte Richtlinien](/de/built-in-policies). +Liste der zu aktivierenden Richtliniennamen. Die Namen müssen exakt mit den Richtlinienbezeichnern übereinstimmen, die von `failproofai policies` angezeigt werden. Die vollständige Liste finden Sie unter [Integrierte Richtlinien](/de/built-in-policies). -Richtlinien, die nicht in `enabledPolicies` enthalten sind, sind inaktiv, auch wenn sie Einträge in `policyParams` haben. +Richtlinien, die nicht in `enabledPolicies` aufgeführt sind, sind inaktiv – selbst wenn sie Einträge in `policyParams` haben. ### `policyParams` @@ -112,15 +112,15 @@ Typ: `Record>` Richtlinienspezifische Parameterüberschreibungen. Der äußere Schlüssel ist der Richtlinienname; die inneren Schlüssel sind richtlinienspezifisch. Jede Richtlinie dokumentiert ihre verfügbaren Parameter unter [Integrierte Richtlinien](/de/built-in-policies). -Wenn eine Richtlinie Parameter hat, Sie diese aber nicht angeben, werden die integrierten Standardwerte der Richtlinie verwendet. Benutzer, die `policyParams` überhaupt nicht konfigurieren, erhalten dasselbe Verhalten wie in früheren Versionen. +Wenn eine Richtlinie Parameter hat, Sie diese aber nicht angeben, werden die integrierten Standardwerte der Richtlinie verwendet. Benutzer, die `policyParams` überhaupt nicht konfigurieren, erhalten ein identisches Verhalten wie in früheren Versionen. -Unbekannte Schlüssel im Parameterblock einer Richtlinie werden zum Zeitpunkt des Hook-Aufrufs stillschweigend ignoriert, aber bei der Ausführung von `failproofai policies` als Warnungen markiert. +Unbekannte Schlüssel innerhalb des Parameter-Blocks einer Richtlinie werden zum Zeitpunkt des Hook-Aufrufs stillschweigend ignoriert, aber als Warnungen angezeigt, wenn Sie `failproofai policies` ausführen. -#### `hint` (übergreifend) +#### `hint` (richtlinienübergreifend) Typ: `string` (optional) -Eine Nachricht, die an den Grund angehängt wird, wenn eine Richtlinie `deny` oder `instruct` zurückgibt. Damit können Sie Claude handlungsrelevante Hinweise geben, ohne die Richtlinie selbst zu ändern. +Eine Nachricht, die dem Grund hinzugefügt wird, wenn eine Richtlinie `deny` oder `instruct` zurückgibt. Verwenden Sie dieses Feld, um Claude handlungsrelevante Hinweise zu geben, ohne die Richtlinie selbst zu ändern. Funktioniert mit jedem Richtlinientyp – integriert, benutzerdefiniert (`custom/`), Projektkonvention (`.failproofai-project/`) oder Benutzerkonvention (`.failproofai-user/`). @@ -141,32 +141,32 @@ Funktioniert mit jedem Richtlinientyp – integriert, benutzerdefiniert (`custom } ``` -Wenn `block-force-push` ablehnt, sieht Claude: *„Force-Pushing ist blockiert. Try creating a fresh branch instead."* +Wenn `block-force-push` ablehnt, sieht Claude: *„Force-pushing is blocked. Try creating a fresh branch instead."* -Nicht-String-Werte und leere Strings werden stillschweigend ignoriert. Wenn `hint` nicht gesetzt ist, bleibt das Verhalten unverändert (abwärtskompatibel). +Nicht-String-Werte und leere Zeichenketten werden stillschweigend ignoriert. Wenn `hint` nicht gesetzt ist, bleibt das Verhalten unverändert (rückwärtskompatibel). ### `customPoliciesPath` Typ: `string` (absoluter Pfad) -Pfad zu einer JavaScript-Datei mit benutzerdefinierten Hook-Richtlinien. Dieser wird automatisch von `failproofai policies --install --custom ` gesetzt (der Pfad wird vor der Speicherung in einen absoluten Pfad aufgelöst). +Pfad zu einer JavaScript-Datei mit benutzerdefinierten Hook-Richtlinien. Dieser Wert wird automatisch durch `failproofai policies --install --custom ` gesetzt (der Pfad wird vor dem Speichern in einen absoluten Pfad aufgelöst). -Die Datei wird bei jedem Hook-Ereignis neu geladen – es gibt kein Caching. Weitere Details zur Erstellung finden Sie unter [Benutzerdefinierte Richtlinien](/de/custom-policies). +Die Datei wird bei jedem Hook-Ereignis neu geladen – es gibt kein Caching. Weitere Informationen zur Erstellung finden Sie unter [Benutzerdefinierte Richtlinien](/de/custom-policies). ### Konventionsbasierte Richtlinien Zusätzlich zum expliziten `customPoliciesPath` erkennt und lädt failproofai automatisch Richtliniendateien aus `.failproofai/policies/`-Verzeichnissen: -| Ebene | Verzeichnis | Scope | -|-------|-------------|-------| -| Projekt | `.failproofai/policies/` | Per Versionsverwaltung mit dem Team geteilt | +| Ebene | Verzeichnis | Geltungsbereich | +|-------|-------------|-----------------| +| Projekt | `.failproofai/policies/` | Mit dem Team über Versionskontrolle geteilt | | Benutzer | `~/.failproofai/policies/` | Persönlich, gilt für alle Projekte | **Dateiabgleich:** Es werden nur Dateien geladen, die dem Muster `*policies.{js,mjs,ts}` entsprechen (z. B. `security-policies.mjs`, `workflow-policies.js`). Andere Dateien im Verzeichnis werden ignoriert. -**Keine Konfiguration erforderlich:** Konventionsrichtlinien benötigen keine Einträge in `policies-config.json`. Legen Sie einfach Dateien in das Verzeichnis und sie werden beim nächsten Hook-Ereignis erkannt. +**Keine Konfiguration erforderlich:** Konventionsrichtlinien benötigen keine Einträge in `policies-config.json`. Legen Sie die Dateien einfach in das Verzeichnis – sie werden beim nächsten Hook-Ereignis aufgenommen. -**Vereinigtes Laden:** Sowohl das Projekt- als auch das Benutzerkonventionsverzeichnis werden durchsucht. Alle passenden Dateien aus beiden Ebenen werden geladen (im Gegensatz zu `customPoliciesPath`, das das Prinzip „erster Scope gewinnt" verwendet). +**Vereinigtes Laden:** Sowohl das Projekt- als auch das Benutzerkonventionsverzeichnis werden durchsucht. Alle passenden Dateien beider Ebenen werden geladen (im Gegensatz zu `customPoliciesPath`, das nach dem Prinzip „erste Ebene gewinnt" arbeitet). Weitere Details und Beispiele finden Sie unter [Benutzerdefinierte Richtlinien](/de/custom-policies). @@ -189,20 +189,24 @@ LLM-Client-Konfiguration für Richtlinien, die KI-Aufrufe durchführen. Für die ## Konfiguration über die CLI verwalten -Die Befehle `policies --install` und `policies --uninstall` schreiben in die Hook-Einstellungsdatei Ihrer Agenten-CLI (die Hook-Einstiegspunkte), während `policies-config.json` die Datei ist, die Sie direkt verwalten. Die beiden sind voneinander getrennt: +Die Befehle `policies --install` und `policies --uninstall` schreiben in die Hook-Einstellungsdatei Ihrer Agenten-CLI (die Hook-Einstiegspunkte), während `policies-config.json` die Datei ist, die Sie direkt verwalten. Beide sind getrennt: - **Agenten-CLI-Einstellungen** – weist den Agenten an, bei jeder Toolnutzung `failproofai --hook ` aufzurufen: - **Claude Code**: `~/.claude/settings.json` (Benutzer), `/.claude/settings.json` (Projekt), `/.claude/settings.local.json` (lokal) - - **OpenAI Codex**: `~/.codex/hooks.json` (Benutzer), `/.codex/hooks.json` (Projekt) – Codex hat keinen `local`-Scope - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (Benutzer), `/.github/hooks/failproofai.json` (Projekt) – Copilot hat keinen `local`-Scope. Hook-Einträge verwenden Copilots betriebssystemspezifische `bash`/`powershell`-Befehlsfelder mit `timeoutSec`; die Datei enthält einen `version: 1`-Marker auf oberster Ebene. Die Unterstützung von Copilot CLI ist **beta**, während wir das `events.jsonl`-Aufzeichnungsschema (das in der öffentlichen Dokumentation nicht spezifiziert ist) anhand weiterer realer Sitzungen überprüfen. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (Benutzer), `/.cursor/hooks.json` (Projekt) – Cursor hat keinen `local`-Scope. Hook-Einträge verwenden die Claude-ähnliche `{type, command, timeout}`-Form (ohne `bash`/`powershell`-Aufteilung), werden aber unter camelCase-Ereignisschlüsseln (`preToolUse`, `beforeSubmitPrompt`, …) in einem flachen Array gemäß Cursors [Hooks-Schema](https://cursor.com/docs/hooks) gespeichert; die Datei enthält einen `version: 1`-Marker auf oberster Ebene. Der Handler kanonisiert camelCase → PascalCase über `CURSOR_EVENT_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Die Unterstützung von Cursor Agent ist **beta**, während wir Cursors On-Disk-Transkriptformat (in der öffentlichen Dokumentation nicht spezifiziert) anhand weiterer realer Installationen überprüfen. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (Benutzer), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (Projekt) – OpenCode hat keinen `local`-Scope. Im Gegensatz zu den anderen sechs CLIs verfügt OpenCode über **kein externes Befehls-Hook-System**: Es lädt In-Process-JS/TS-Plugins, die explizit über das `plugin: []`-Array in `opencode.json` registriert werden (automatische Erkennung aus `.opencode/plugins/` ist **nicht** die Art, wie Plugins in opencode v1.14.33 geladen werden). Die Installation legt ein kleines generiertes Plugin-Shim ab, das den failproofai-Binary als Subprozess aufruft und die JSON-Antwort im Claude-Format des Binaries zurück in Plugin-Semantik übersetzt: `throw new Error()` für tool-event deny (bricht den Tool-Aufruf ab), `client.session.prompt(...)` für instruct UND für `Stop` / `SubagentStop` deny (reicht den Ablehnungsgrund als nächste Benutzernachricht ein – der einzige Force-Retry-Kanal, da `session.idle` nur eine Benachrichtigung ist und das Werfen einer Exception dort ein No-op ist), und No-op für allow. Das Shim kanonisiert sowohl Tool-Namen (Kleinbuchstaben → PascalCase über `OPENCODE_TOOL_MAP`) als auch Tool-Input-Argumentschlüssel (camelCase → snake_case über `OPENCODE_TOOL_INPUT_MAP` für `Read` / `Write` / `Edit`, z. B. `filePath` → `file_path`, `oldString` → `old_string`), bevor es an das Binary weiterleitet, sodass pfadprüfende Builtins wie `block-read-outside-cwd`, `block-env-files` und `block-secrets-write` bei OpenCode-Tool-Aufrufen unverändert ausgelöst werden. Sitzungen werden in OpenCodes SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` gespeichert; der Session-Viewer des Dashboards liest sie über `opencode db --format json` und `opencode export `. Die OpenCode-Unterstützung ist **beta**, während wir das Verhalten versionsübergreifend und anhand weiterer realer Sitzungen überprüfen. Siehe die [OpenCode-Plugin-Dokumentation](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (Benutzer), `/.pi/settings.json` (Projekt) – Pi hat keinen `local`-Scope. Pi lädt TypeScript-Erweiterungspakete beim Start; die Einstellungsdatei ist ein flaches String-Array `{"packages": ["./relative/path", …]}`. failproofai schreibt einen einzelnen packages-Array-Eintrag, der auf sein gebündeltes `pi-extension/`-Verzeichnis zeigt. Die Erweiterung abonniert intern Pis `tool_call` / `user_bash` / `input` / `session_start`-Ereignisse und ruft `failproofai --hook --cli pi` als Shell-Befehl auf; der Handler kanonisiert Ereignisse über `PI_EVENT_MAP` von underscore_lower_snake_case → PascalCase, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Tool-Input-Argumente werden ebenfalls über `PI_TOOL_INPUT_MAP` kanonisiert (Pis Read / Write / Edit liefern `path` statt `file_path`; die Zuordnung des obersten Schlüssels lässt `block-env-files` und `block-secrets-write` auslösen – `block-read-outside-cwd` hatte bereits einen `path`-Fallback). Die Pi-Unterstützung ist **beta**, während sich Pis Erweiterungs-API und das Sitzungslog-Layout stabilisieren. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (Benutzer), `/.gemini/settings.json` (Projekt) – Gemini hat keinen `local`-Scope (es dokumentiert einen `system`-Scope unter `/etc/gemini-cli/settings.json`, den failproofai nicht verfügbar macht). Hook-Einträge verwenden Claudes `{type, command, timeout}`-Form, eingebettet in Geminis `{matcher, hooks: [...]}`-Matcher-Schema mit standardmäßig `matcher: "*"`. Ereignisse sind PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); der Handler ordnet sie über `GEMINI_EVENT_MAP` kanonischen Claude-Namen zu. Tool-Namen sind snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) – der Handler kanonisiert über `GEMINI_TOOL_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Der Richtlinienauswerter gibt Geminis flache `{decision: "deny", reason}`-Form aus (bevorzugt gemäß Geminis „Goldener Regel" exit-0-Vertrag), `{hookSpecificOutput: {hookEventName, additionalContext}}` für Kontext-Injection bei BeforeAgent / AfterTool / SessionStart, und `{decision: "block", reason}` bei AfterAgent für Force-Retry-Semantik. Die Gemini CLI-Unterstützung ist **beta**, während wir die reale Abdeckung ausweiten. Siehe die [Gemini CLI Hooks-Dokumentation](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**nur Benutzer-Scope** – Hermes hat keine Projekt-/lokale Konfiguration). Hermes ist ein Slack/Telegram-**Gateway**, daher fängt eine Installation Tool-Aufrufe von jeder Plattform (Slack/Telegram/cli/cron) **und** internen Subagenten ab. Hook-Einträge sind ein `{command, timeout}`-Paar (Timeout in **Sekunden**) unter einem `hooks:`-Map, der nach Hermes' snake_case-Ereignissen (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) geordnet ist; der Handler kanonisiert Ereignisse über `HERMES_EVENT_MAP` und Tool-Namen über `HERMES_TOOL_MAP`, sodass integrierte Richtlinien unverändert ausgelöst werden. Die Konfiguration wird durch einen kommentarerhaltenden YAML-`Document`-Round-trip bearbeitet, sodass die anderen Einstellungen des Betreibers erhalten bleiben, und die Installation setzt `hooks_auto_accept: true`, sodass das kopflose Gateway (kein TTY) die Hooks ohne Zustimmungsaufforderung ausführt. Der Auswerter gibt Hermes' stdout-Vertrag `{"decision":"block","reason"}` aus (Hermes ignoriert Exit-Codes). **Einschränkungen:** Hermes hat kein turn-end-`Stop`-Ereignis, daher werden die `require-*-before-stop`-Builtins für Hermes nie ausgelöst (nicht anwendbar, nicht defekt); `instruct` wird zu allow-with-logged-note herabgestuft (kein additional-context-Kanal); und Output-Secret-Redaktion (`sanitize-*`) kann Tool-Output über den Shell-Hook-Vertrag nicht umschreiben. Hermes ist **auch** eine Offline-**Audit**-Quelle – das Dashboard liest seine Gateway-Sitzungen direkt aus `~/.hermes/state.db`. -- **`policies-config.json`** – teilt failproofai mit, welche Richtlinien ausgewertet werden sollen und mit welchen Parametern (geteilt über alle Agenten-CLIs) - -Übergeben Sie `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes`, um einen bestimmten Agenten anzusprechen (durch Leerzeichen getrennt oder wiederholt für eine beliebige Teilmenge): + - **OpenAI Codex**: `~/.codex/hooks.json` (Benutzer), `/.codex/hooks.json` (Projekt) — Codex hat keinen `local`-Bereich + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (Benutzer), `/.github/hooks/failproofai.json` (Projekt) — Copilot hat keinen `local`-Bereich. Hook-Einträge verwenden die OS-schlüsselbasierten `bash`/`powershell`-Befehlsfelder von Copilot mit `timeoutSec`; die Datei enthält einen obersten `version: 1`-Marker. Die Unterstützung für Copilot CLI ist **Beta**, während wir das `events.jsonl`-Aufzeichnungsschema (das in der öffentlichen Dokumentation nicht spezifiziert ist) gegen weitere reale Sessions verifizieren. **VS Code Copilot Chat Agent-Modus (Vorschau)** liest Hook-Konfigurationen aus `.github/hooks/*.json`, `~/.copilot/hooks/*.json` und `~/.claude/settings.json` (gesteuert durch die `chat.hookFilesLocations`-Einstellung) mit demselben Claude-förmigen `{hookSpecificOutput:{permissionDecision:"deny",…}}`-Vertrag — genau die Pfade, in die diese `copilot`-Integration und die `claude`-Integration (`~/.claude/settings.json`) bereits schreiben, sodass `failproofai policies --install --cli copilot` (oder `--cli claude`) **bereits im VS Code-Agentenmodus erzwingt** ohne separate `vscode`-Integration (aus VS Codes Discovery-Logs bestätigt). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (Benutzer), `/.cursor/hooks.json` (Projekt) — Cursor hat keinen `local`-Bereich. Hook-Einträge verwenden die Claude-förmige `{type, command, timeout}`-Form (keine `bash`/`powershell`-Aufteilung), werden aber unter camelCase-Ereignisschlüsseln (`preToolUse`, `beforeSubmitPrompt`, …) in einem flachen Array gemäß Cursors [Hooks-Schema](https://cursor.com/docs/hooks) gespeichert; die Datei enthält einen obersten `version: 1`-Marker. Der Handler kanonisiert camelCase → PascalCase über `CURSOR_EVENT_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Die Unterstützung für Cursor Agent ist **Beta**, während wir Cursors Transkript-On-Disk-Format (in der öffentlichen Dokumentation nicht spezifiziert) gegen weitere reale Installationen verifizieren. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (Benutzer), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (Projekt) — OpenCode hat keinen `local`-Bereich. Im Gegensatz zu den anderen fünf CLIs hat OpenCode **kein externes Befehlshook-System**: Es lädt In-Process-JS/TS-Plugins, die explizit über das `plugin: []`-Array in `opencode.json` registriert werden (Auto-Discovery aus `.opencode/plugins/` ist **nicht** die Art, wie Plugins unter opencode v1.14.33 geladen werden). Die Installation legt einen kleinen generierten Plugin-Shim ab, der das failproofai-Binary als Subprozess aufruft und die Claude-förmige JSON-Antwort des Binaries zurück in Plugin-Semantik übersetzt: `throw new Error()` für Tool-Event-Deny (bricht den Tool-Aufruf ab), `client.session.prompt(...)` für instruct UND für `Stop`/`SubagentStop`-Deny (sendet den Ablehnungsgrund als nächste Benutzernachricht — der einzige Force-Retry-Kanal, da `session.idle` nur zur Benachrichtigung dient und das Werfen daraus ein No-Op ist), und No-Op für allow. Der Shim kanonisiert sowohl Tool-Namen (Kleinbuchstaben → PascalCase über `OPENCODE_TOOL_MAP`) als auch Tool-Input-Argumentschlüssel (camelCase → snake_case über `OPENCODE_TOOL_INPUT_MAP` für `Read`/`Write`/`Edit`, z. B. `filePath` → `file_path`, `oldString` → `old_string`) vor der Weiterleitung an das Binary, sodass pfadprüfende Built-ins wie `block-read-outside-cwd`, `block-env-files` und `block-secrets-write` bei OpenCode-Tool-Aufrufen unverändert ausgelöst werden. Sessions befinden sich in OpenCodes SQLite-DB unter `~/.local/share/opencode/opencode.db`; der Session-Viewer des Dashboards liest sie über `opencode db --format json` und `opencode export `. Die Unterstützung für OpenCode ist **Beta**, während wir das Verhalten über Versionen hinweg und gegen weitere reale Sessions verifizieren. Siehe die [OpenCode-Plugins-Dokumentation](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (Benutzer), `/.pi/settings.json` (Projekt) — Pi hat keinen `local`-Bereich. Pi lädt TypeScript-Erweiterungspakete beim Start; die Einstellungsdatei ist ein flaches String-Array `{"packages": ["./relative/path", …]}`. failproofai schreibt einen einzelnen packages-Array-Eintrag, der auf sein gebündeltes `pi-extension/`-Verzeichnis zeigt. Die Erweiterung abonniert intern Pis `tool_call`/`user_bash`/`input`/`session_start`-Ereignisse und ruft `failproofai --hook --cli pi` als Shell-Befehl auf; der Handler kanonisiert underscore_lower_snake_case → PascalCase über `PI_EVENT_MAP`, sodass bestehende integrierte Richtlinien unverändert ausgelöst werden. Tool-Input-Args werden ebenfalls über `PI_TOOL_INPUT_MAP` kanonisiert (Pis Read/Write/Edit liefern `path` statt `file_path`; das Mapping des obersten Schlüssels ermöglicht das Auslösen von `block-env-files` und `block-secrets-write` — `block-read-outside-cwd` hatte bereits einen `path`-Fallback). Die Unterstützung für Pi ist **Beta**, während sich Pis Extension-API und Session-Log-Layout noch stabilisieren. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**nur Benutzerbereich** — Hermes hat keine Projekt-/lokale Konfiguration). Hermes ist ein Slack/Telegram-**Gateway**, sodass eine Installation Tool-Aufrufe von jeder Plattform (Slack/Telegram/cli/cron) **und** internen Subagenten abfängt. Hook-Einträge sind ein `{command, timeout}`-Paar (Timeout in **Sekunden**) unter einer `hooks:`-Map, die durch Hermes' snake_case-Ereignisse (`pre_tool_call`/`post_tool_call`/`on_session_start`/`on_session_end`/`subagent_stop`) gekennzeichnet ist; der Handler kanonisiert Ereignisse über `HERMES_EVENT_MAP` und Tool-Namen über `HERMES_TOOL_MAP`, sodass integrierte Richtlinien unverändert ausgelöst werden. Die Konfiguration wird durch ein kommentarerhaltenes YAML-`Document`-Roundtrip bearbeitet, sodass die anderen Einstellungen des Betreibers erhalten bleiben, und die Installation setzt `hooks_auto_accept: true`, damit das kopflose Gateway (kein TTY) die Hooks ohne Zustimmungsaufforderung ausführt. Der Evaluator gibt Hermes' `{"decision":"block","reason"}`-stdout-Vertrag aus (Hermes ignoriert Exit-Codes). **Einschränkungen:** Hermes hat kein Turn-End-`Stop`-Ereignis, sodass die `require-*-before-stop`-Built-ins für es nie ausgelöst werden (nicht anwendbar, nicht defekt); `instruct` degradiert zu allow-with-logged-note (kein Zusatzkontext-Kanal); und Output-Secret-Redaktion (`sanitize-*`) kann die Tool-Ausgabe nicht über den Shell-Hook-Vertrag umschreiben. Hermes ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine Gateway-Sessions direkt aus `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**nur Benutzerbereich** — OpenClaw hat keine Projekt-/lokale Konfiguration). Wie Hermes ist OpenClaw ein selbst gehostetes Multi-Channel-**Gateway**, sodass eine Installation Tool-Aufrufe von jedem Kanal und seinen internen Subagenten abfängt. Die Durchsetzung läuft über OpenClaws **In-Process-Plugin-Hooks** (seine dateibasierten internen Hooks dienen nur zur Beobachtung und können nicht blockieren), daher — wie OpenCode/Pi — liefert failproofai ein statisches `openclaw-plugin/`-Paket, das das failproofai-Binary asynchron als Subprozess startet und das Urteil übersetzt. Die Installation registriert das gelieferte Plugin-Verzeichnis in `openclaw.json`'s `plugins.load.paths[]` und aktiviert es unter `plugins.entries.failproofai` (mit `hooks.allowConversationAccess: true`, erforderlich für die Raw-Conversation-Hooks). Der Evaluator gibt ein flaches `{permission, reason}`-Urteil aus, und der Shim ordnet es der nativen Rückgabeform jedes Hooks zu: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**) und `before_agent_finalize → {action:"revise", reason}` (**Stop** — ein echtes Turn-End-Gate, sodass die `require-*-before-stop`-Built-ins auf OpenClaw **durchgesetzt werden**, anders als bei Hermes). Ereignisse und Tool-Namen werden binärseitig über `OPENCLAW_EVENT_MAP`/`OPENCLAW_TOOL_MAP` kanonisiert (`exec→Bash`, `read→Read`, …), sodass integrierte Richtlinien unverändert ausgelöst werden; der Shim schlägt bei Spawn-/Parse-/Timeout-Fehlern offen fehl. OpenClaw ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine JSONL-Sessions unter `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (Benutzer), `/.factory/hooks.json` (Projekt) — Factory hat keinen `local`-Bereich. droid liefert ein Claude-artiges externes Befehlshook-System, hat aber zwei Besonderheiten, die live gegen droid v0.171.0 verifiziert wurden: (1) Ereignisnamen befinden sich auf der **obersten Ebene** von `hooks.json` — es gibt **keinen `"hooks"`-Wrapper** (droid lehnt einen ab); Tool-Ereignisse (`PreToolUse`/`PostToolUse`) tragen `"matcher": "*"`, Nicht-Tool-Ereignisse lassen ihn weg. (2) Deny wird durch Hook-**Exit-Code 2 + stderr** gesteuert, nicht durch eine JSON-Entscheidung — der Evaluator-`factory`-Zweig gibt Exit 2 für Tool-/Prompt-Ereignisse zurück und `{decision:"block", reason}` nur beim Turn-End-`Stop`-Ereignis (dem einzigen Force-Retry-Kanal von droid). Ereignisse sind bereits PascalCase (keine Ereignis-Map), und die Nutzlast ist Claude snake_case; nur Tool-Namen werden über `FACTORY_TOOL_MAP` kanonisiert (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine On-Disk-JSONL-Sessions unter `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (Benutzer), `/.devin/config.json` (Projekt) — Devin hat keinen `local`-Bereich. Devin ist ein **reiner Claude-Klon**, verifiziert live gegen devin v3000.1.27: Es verwendet das Standard-Claude-`"hooks"`-Wrapper-Schema (Schreibvorgänge sind merge-erhaltend, sodass die anderen Schlüssel der Konfigurationsdatei — `org_id`, `theme_mode`, … — erhalten bleiben), bereits PascalCase-Ereignisnamen (keine Ereignis-Map, kein Handler-Zweig) und eine Claude snake_case stdin-Nutzlast (keine Normalisierung). Der Evaluator-`devin`-Zweig lehnt mit `{"decision":"block","reason"}` JSON auf stdout bei Exit 0 für **jedes** Ereignis ab (verifiziert — die Blockierung überschrieb `--permission-mode dangerous`); beim Turn-End-`Stop`-Ereignis enthält der Grund die MANDATORY-ACTION-Force-Retry-Formulierung, sodass die `require-*-before-stop`-Built-ins durchgesetzt werden. Nur Tool-Namen werden über `DEVIN_TOOL_MAP` kanonisiert (`exec→Bash`; `tool_input.command` ist bereits kanonisch). Devin ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine SQLite-Sessions unter `~/.local/share/devin/cli/sessions.db` (jede `sessions`-Zeile trägt ein echtes `working_directory`, sodass Sessions nach Projekt-cwd gruppiert werden wie bei Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (Benutzer), `/.agents/hooks.json` (Projekt) — Antigravity hat keinen `local`-Bereich. Anders als Factory/Devin hat Antigravity seinen **eigenen** Vertrag (kein Claude-Klon), verifiziert live gegen agy v1.1.2. `hooks.json` verwendet ein **benanntes Hook**-Schema: Der oberste Schlüssel ist ein Hook-*Name* (`"failproofai"`), dessen Wert eine Ereignis→Handler-Map ist — Tool-Ereignisse (`PreToolUse`/`PostToolUse`) umhüllen Handler in `{matcher:"*", hooks:[…]}`, während `PreInvocation`/`Stop` **flache** Handler-Arrays sind (andere benannte Hooks werden beibehalten). Die stdin-Nutzlast ist **camelCase-Protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai normalisiert es vor dem Ausführen der Richtlinien zu snake_case und ordnet die PascalCase-Args von `run_command` (`CommandLine`/`Cwd`) über `ANTIGRAVITY_TOOL_INPUT_MAP` zu. Der Evaluator-`antigravity`-Zweig verwendet Antigravitys **eigene** Antwortformen: `{decision:"deny", reason}` blockiert ein Tool/Prompt (Exit 0), `{decision:"continue", reason}` beim Turn-End-`Stop` tritt erneut in die Schleife ein (sodass die `require-*-before-stop`-Built-ins durchgesetzt werden), und `{injectSteps:[{ephemeralMessage}]}` injiziert eine Anweisung bei `PreInvocation` (→ `UserPromptSubmit`). Tool-Namen werden über `ANTIGRAVITY_TOOL_MAP` kanonisiert (`run_command→Bash`, `view_file→Read`, …). Antigravity ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine Plain-JSONL-Transkripte unter `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (Konversationsindex in `conversation_summaries.db`). + - **Goose (Codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (Benutzer), `/.agents/plugins/failproofai/hooks/hooks.json` (Projekt) — Goose hat keinen `local`-Bereich. Die Durchsetzung verwendet Gooses **Hooks**-System, die Cross-Agent-**Open-Plugins**-Spezifikation: Der Installer legt einfach das `failproofai`-Plugin-Verzeichnis ab, und Goose entdeckt es beim Start automatisch (und registriert es selbst in `~/.config/goose/config.yaml`). Die `hooks.json` verwendet ein Open-Plugins-Schema **mit** einem obersten `"hooks"`-Wrapper, und der Matcher wird bei jedem Ereignis **weggelassen** — ein bloßes `"*"` ist ein ungültiger Regex, der nichts findet (live verifiziert gegen goose v1.43.0). Ereignisnamen sind bereits PascalCase (keine Ereignis-Map); die stdin-Nutzlast verwendet `event`/`working_dir`, was der Handler zu `hook_event_name`/`cwd` normalisiert. Der Evaluator-`goose`-Zweig lehnt mit `{"decision":"block","reason"}` JSON auf stdout bei Exit 0 ab, was **nur** beim `PreToolUse`-Ereignis berücksichtigt wird (ab goose ≥ v1.37.0 geliefert) — das für das Shell-Tool **und innerhalb delegierter Subagenten** ausgelöst wird, sodass es der einzige ausreichende Deny-Punkt ist; jeder andere Hook-Fehler schlägt **offen** fehl. Goose hat **kein `Stop`-Ereignis**, sodass die `require-*-before-stop`-Built-ins nicht gelten (wie bei Hermes). Tool-Namen werden über `GOOSE_TOOL_MAP` kanonisiert (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) und Pfadschlüssel über `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose ist **außerdem** eine Offline-**Audit**-Quelle — das Dashboard liest seine SQLite-Sessions unter `~/.local/share/goose/sessions/sessions.db` (jede `sessions`-Zeile trägt ein echtes `working_dir`, sodass Sessions nach Projekt-cwd gruppiert werden wie bei Devin; `--no-session`-Scratch-Runs werden gefiltert). +- **`policies-config.json`** — teilt failproofai mit, welche Richtlinien ausgewertet werden sollen und mit welchen Parametern (gilt für alle Agenten-CLIs) + +Übergeben Sie `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`, um einen bestimmten Agenten anzusprechen (durch Leerzeichen getrennt oder wiederholt für eine beliebige Teilmenge): ```bash failproofai policies --install --cli codex --scope project @@ -210,19 +214,23 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Wenn `--cli` weggelassen wird, erkennt `failproofai` automatisch, welche Agenten-CLIs installiert sind (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Wenn `--cli` weggelassen wird, erkennt `failproofai`, welche Agenten-CLIs installiert sind (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Eine CLI erkannt** – wählt diese CLI automatisch ohne Rückfrage aus. -- **Mehrere CLIs erkannt** in einem interaktiven Terminal – zeigt eine Einzelauswahl-Eingabeaufforderung mit Pfeiltasten an, die in einen Abschnitt `Erkannt (N)` (mit einer `Für alle N erkannten installieren`-Sammelzeile + jeder erkannten CLI einzeln) und einen Abschnitt `Nicht installiert (M) · Hooks vorab installieren` unterteilt ist, der alle nicht erkannten unterstützten CLIs als Vorwärts-Installationsoption auflistet (↑↓ zum Bewegen, Enter zum Auswählen, ^C zum Beenden). Der Deinstallationsablauf zeigt nur den Abschnitt „Erkannt" an. -- **Mehrere CLIs erkannt** in einem nicht-interaktiven Lauf (CI, kein TTY) – installiert für alle erkannten CLIs ohne Rückfrage. -- **Keine erkannt** – fällt auf `claude` zurück, mit einer Warnung, dass kein Agenten-Binary im PATH gefunden wurde; der Hook-Befehl wird trotzdem geschrieben, sodass er aktiviert wird, sobald Sie einen installieren. +- **Eine CLI erkannt** — wählt diese CLI automatisch ohne Nachfrage aus. +- **Mehrere CLIs erkannt** in einem interaktiven Terminal — zeigt eine Pfeilnavigations-Einzelauswahl-Aufforderung an, gruppiert in einen Abschnitt `Erkannt (N)` (mit einer aggregierten Zeile `Für alle N erkannten installieren` + jede erkannte CLI einzeln) und einen Abschnitt `Nicht installiert (M) · Hooks vorab installieren`, der alle nicht erkannten unterstützten CLIs als Vorausinstallationsoption auflistet (↑↓ zum Bewegen, Enter zum Auswählen, ^C zum Beenden). Der Deinstallationsablauf zeigt nur den Erkannt-Abschnitt an. +- **Mehrere CLIs erkannt** in einem nicht-interaktiven Lauf (CI, kein TTY) — installiert für alle erkannten CLIs ohne Nachfrage. +- **Keine erkannt** — fällt auf `claude` zurück, mit einer Warnung, dass kein Agenten-Binary im PATH gefunden wurde; der Hook-Befehl wird trotzdem geschrieben, sodass er aktiviert wird, sobald Sie eine CLI installieren. -Sie können `policies-config.json` jederzeit direkt bearbeiten; Änderungen treten sofort beim nächsten Hook-Ereignis in Kraft, ohne dass ein Neustart erforderlich ist. +Sie können `policies-config.json` jederzeit direkt bearbeiten; Änderungen treten sofort beim nächsten Hook-Ereignis in Kraft, kein Neustart erforderlich. --- @@ -247,4 +255,4 @@ Committen Sie `.failproofai/policies-config.json` in Ihr Repository: } ``` -Jeder Entwickler kann dann `.failproofai/policies-config.local.json` (per .gitignore ausgeschlossen) für persönliche Overrides erstellen, ohne Teammitglieder zu beeinflussen. \ No newline at end of file +Jeder Entwickler kann dann `.failproofai/policies-config.local.json` (via gitignore ausgeschlossen) für persönliche Überschreibungen erstellen, ohne die Teammitglieder zu beeinflussen. \ No newline at end of file diff --git a/docs/de/dashboard.mdx b/docs/de/dashboard.mdx index 610aaa73..68667441 100644 --- a/docs/de/dashboard.mdx +++ b/docs/de/dashboard.mdx @@ -1,10 +1,10 @@ --- title: Dashboard -description: "Agentensitzungen überwachen, Tool-Aufrufe prüfen und Richtlinien verwalten" +description: "Agent-Sitzungen überwachen, Tool-Aufrufe überprüfen und Richtlinien verwalten" icon: chart-line --- -Das failproofai Dashboard ist eine lokale Webanwendung zur Überwachung Ihrer KI-Agentensitzungen und Verwaltung von Richtlinien. Sehen Sie, was Ihre Agenten in Ihrer Abwesenheit getan haben. +Das failproofai-Dashboard ist eine lokale Webanwendung zur Überwachung deiner KI-Agent-Sitzungen und zur Verwaltung von Richtlinien. Sieh nach, was deine Agents in deiner Abwesenheit getan haben. --- @@ -16,7 +16,7 @@ failproofai Öffnet sich unter `http://localhost:8020`. -Das Dashboard liest direkt vom Dateisystem – aus Ihren Claude Code-Projektordnern und den failproofai-Konfigurationsdateien. Es werden keine Daten an einen externen Dienst übertragen. +Das Dashboard liest direkt aus dem Dateisystem – aus deinen Claude Code-Projektordnern und den failproofai-Konfigurationsdateien. Es werden keine Daten an einen externen Dienst übertragen. --- @@ -24,67 +24,67 @@ Das Dashboard liest direkt vom Dateisystem – aus Ihren Claude Code-Projektordn ### Projekte -Listet alle Claude Code-, OpenAI Codex-, GitHub Copilot CLI- _(Beta)_, Cursor Agent- _(Beta)_, OpenCode- _(Beta)_, Pi- _(Beta)_, Gemini CLI- _(Beta)_ und Hermes-Projekte auf, die auf Ihrem Rechner gefunden wurden. Claude-Projekte werden aus `~/.claude/projects/` erkannt (oder dem über `CLAUDE_PROJECTS_PATH` festgelegten Pfad); Codex-Projekte werden durch Scannen aller Transkripte unter `~/.codex/sessions///
/*.jsonl` ermittelt und nach dem `cwd` des ersten Eintrags jeder Sitzung gruppiert; Copilot CLI-Projekte werden durch Scannen von `~/.copilot/session-state//workspace.yaml` (konfigurierbar über `COPILOT_HOME`) und Gruppierung nach dem dortigen `cwd`-Feld erkannt; Cursor Agent-Projekte werden durch Scannen der sitzungsspezifischen Metadaten unter `~/.cursor/agent-sessions//` (konfigurierbar über `CURSOR_HOME`, mit `conversations/` und `sessions/` als Fallbacks) nach einem `cwd`-Skalar in `meta.json` / `session.json` / `workspace.yaml` erkannt; OpenCode-Projekte werden durch Abfrage der SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` via `opencode db --format json` ermittelt (dabei werden die Tabellen `session` und `project` gelesen und nach `project_id` gruppiert); Pi-Projekte werden durch Scannen von sitzungsspezifischen JSONL-Transkripten unter `~/.pi/agent/sessions//_.jsonl` (konfigurierbar über `PI_SESSIONS_DIR`) und Auslesen des `cwd` aus dem ersten Eintrag jeder Sitzung erkannt; Gemini CLI-Projekte werden durch Scannen von `~/.gemini/tmp//chats/session--.jsonl` (konfigurierbar über `GEMINI_SESSIONS_DIR`) und Rückgewinnung des kanonischen cwd aus dem benachbarten `.project_root`-Textmarker erkannt; Hermes-Gateway-Sitzungen werden direkt aus dem SQLite-Store unter `~/.hermes/state.db` (konfigurierbar über `HERMES_DB_PATH`) gelesen und nach `source` (Slack/Telegram/cli/cron — Gateway-Sitzungen haben kein cwd) in `hermes-`-Projekte gruppiert. Ein Projekt, das von mehreren CLIs genutzt wurde, wird als einzelne Zeile mit allen zugehörigen Badges angezeigt. Verwenden Sie das **CLI**-Dropdown über der Tabelle, um nach einer bestimmten Agenten-CLI zu filtern; die URL speichert Ihre Auswahl als `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Listet alle Claude Code-, OpenAI Codex-, GitHub Copilot CLI- _(beta)_, Cursor Agent- _(beta)_, OpenCode- _(beta)_, Pi- _(beta)_, Hermes-, OpenClaw-, Factory Droid-, Devin-, Antigravity- und Goose-Projekte auf, die auf deinem Rechner gefunden wurden. Claude-Projekte werden aus `~/.claude/projects/` (oder dem über `CLAUDE_PROJECTS_PATH` festgelegten Pfad) ermittelt; Codex-Projekte werden durch das Scannen aller Transkripte unter `~/.codex/sessions///
/*.jsonl` und Gruppierung nach dem im ersten Datensatz jeder Sitzung gespeicherten `cwd` entdeckt; Copilot-CLI-Projekte werden durch das Scannen jeder `~/.copilot/session-state//workspace.yaml` (konfigurierbar über `COPILOT_HOME`) und Gruppierung nach deren `cwd`-Feld entdeckt; Cursor-Agent-Projekte werden durch das Scannen sitzungsspezifischer Metadaten unter `~/.cursor/agent-sessions//` (konfigurierbar über `CURSOR_HOME`, mit `conversations/` und `sessions/` als Fallbacks) nach einem `cwd`-Skalar in `meta.json` / `session.json` / `workspace.yaml` entdeckt; OpenCode-Projekte werden durch Abfrage seiner SQLite-Datenbank unter `~/.local/share/opencode/opencode.db` via `opencode db --format json` ermittelt (es werden die Tabellen `session` und `project` gelesen und nach `project_id` gruppiert); Pi-Projekte werden durch das Scannen sitzungsspezifischer JSONL-Transkripte unter `~/.pi/agent/sessions//_.jsonl` (konfigurierbar über `PI_SESSIONS_DIR`) und Auslesen des `cwd` aus dem ersten Datensatz jeder Sitzung entdeckt; Hermes-Gateway-Sitzungen werden direkt aus dem SQLite-Speicher unter `~/.hermes/state.db` (konfigurierbar über `HERMES_DB_PATH`) gelesen und nach `source` in `hermes-`-Projekte gruppiert (Slack/Telegram/cli/cron – Gateway-Sitzungen haben kein cwd); OpenClaw-Gateway-Sitzungen werden aus `~/.openclaw/agents//sessions/*.jsonl` gelesen und in `openclaw-`-Projekte gruppiert (ebenfalls ohne cwd); Factory-Droid-Projekte werden aus den JSONL-Transkripten unter `~/.factory/sessions//*.jsonl` ermittelt und nach cwd gruppiert; Devin-Projekte aus seiner SQLite-Datenbank unter `~/.local/share/devin/cli/sessions.db` (gruppiert nach dem `working_directory` jeder Sitzung); Antigravity-Projekte aus den JSONL-Transkripten unter `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` und nach cwd gruppiert; sowie Goose-Projekte aus seiner SQLite-Datenbank unter `~/.local/share/goose/sessions/sessions.db` (gruppiert nach dem `working_dir` jeder Sitzung). Ein Projekt, das von mehreren CLIs verwendet wurde, erscheint als einzelne Zeile mit allen passenden Badges. Verwende das **CLI**-Dropdown oberhalb der Tabelle, um nach einer bestimmten Agent-CLI zu filtern; die URL speichert deine Auswahl als `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Jedes Projekt zeigt: - Projektname (abgeleitet vom Ordnerpfad) -- Ein CLI-Badge — `Claude Code` (orange), `OpenAI Codex` (lila), `GitHub Copilot` (blau), `Cursor Agent` (smaragd), `OpenCode` (bernstein), `Pi` (pink), `Gemini CLI` (himmelblau) und/oder `Hermes` (indigo) +- Ein CLI-Badge — `Claude Code` (orange), `OpenAI Codex` (lila), `GitHub Copilot` (blau), `Cursor Agent` (smaragd), `OpenCode` (bernstein), `Pi` (rosa) und/oder `Hermes` (indigo) - Datum der letzten Sitzungsaktivität -Klicken Sie auf ein Projekt, um dessen Sitzungen anzuzeigen. +Klicke auf ein Projekt, um seine Sitzungen anzuzeigen. ### Sitzungen Listet alle Sitzungen innerhalb eines Projekts auf. Jede Sitzung zeigt: - Sitzungs-ID -- Start- und Endzeitstempel +- Start- und Endzeitpunkt - Anzahl der Tool-Aufrufe -- Anzahl der Hook-Aktivitäten (ausgelöste Richtlinien) +- Hook-Aktivitätsanzahl (ausgelöste Richtlinien) -Verwenden Sie den Datumsbereichsfilter und die Sitzungs-ID-Suche, um die Liste einzugrenzen. Sitzungen werden paginiert angezeigt. +Verwende den Datumsbereichsfilter und die Sitzungs-ID-Suche zum Eingrenzen der Liste. Sitzungen werden seitenweise angezeigt. -Klicken Sie auf eine Sitzung, um den Sitzungsviewer zu öffnen. +Klicke auf eine Sitzung, um den Sitzungsviewer zu öffnen. ### Sitzungsviewer -Der Sitzungsviewer beantwortet die zentrale Frage bei autonomen Agenten: Was hat der Agent getan, und ist er auf Kurs geblieben? Ein CLI-Badge neben der Überschrift zeigt an, ob es sich um ein Claude Code-, OpenAI Codex-, GitHub Copilot CLI-, Cursor Agent-, OpenCode-, Pi-, Gemini CLI- oder Hermes-Transkript handelt. Er zeigt eine Zeitleiste aller Ereignisse einer Sitzung: +Der Sitzungsviewer beantwortet die zentrale Frage bei autonomen Agents: Was hat der Agent getan, und ist er auf Kurs geblieben? Ein CLI-Badge neben der Überschrift gibt an, ob es sich um ein Transkript von Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity oder Goose handelt. Er zeigt eine Zeitleiste aller Ereignisse einer Sitzung: - **Nachrichten** – Claudes Textantworten und Benutzeranfragen -- **Tool-Aufrufe** – Jedes von Claude aufgerufene Tool mit Ein- und Ausgabe -- **Richtlinienaktivität** – Für jeden Tool-Aufruf: welche Richtlinien ausgelöst wurden und welche Entscheidung sie getroffen haben +- **Tool-Aufrufe** – Jedes Tool, das Claude aufgerufen hat, mit Ein- und Ausgabe +- **Richtlinienaktivität** – Für jeden Tool-Aufruf: welche Richtlinien ausgelöst wurden und welche Entscheidung sie zurückgegeben haben -Die Statistikleiste oben zeigt Sitzungsdauer, Gesamtzahl der Tool-Aufrufe und eine Zusammenfassung der Hook-Entscheidungen (allow / deny / instruct-Anzahl). +Die Statistikleiste oben zeigt Sitzungsdauer, Gesamtanzahl der Tool-Aufrufe und eine Zusammenfassung der Hook-Entscheidungen (allow-/deny-/instruct-Zählungen). -Klicken Sie auf **Logs herunterladen**, um die Sitzung zu exportieren. Für Claude Code-, Codex-, Copilot-, Cursor-, Pi- und Gemini-Sitzungen erhalten Sie das originale JSONL-Transkript vom Datenträger byte-genau; für OpenCode (dessen Sitzungen in SQLite und nicht auf dem Datenträger gespeichert sind) erhalten Sie ein JSON-Dokument, das die zugrundeliegenden Tabellen `session` / `messages` / `parts` widerspiegelt. +Klicke auf die Schaltfläche **Logs herunterladen**, um die Sitzung zu exportieren. Bei Claude Code-, Codex-, Copilot-, Cursor- und Pi-Sitzungen erhältst du das ursprüngliche JSONL-Transkript byte-für-byte vom Datenträger; bei OpenCode (dessen Sitzungen in SQLite statt auf dem Datenträger gespeichert sind) erhältst du ein JSON-Dokument, das die zugrunde liegenden Tabellen `session` / `messages` / `parts` widerspiegelt. ### Audit -Ein persönlichkeitsgesteuerter Bericht darüber, wie sich Ihr Agent tatsächlich über vergangene Sitzungen hinweg verhalten hat. Führt denselben Scan wie der `failproofai audit`-CLI durch, stellt ihn jedoch als einzeiligen teilbaren Poster + vier darunter liegende Abschnitte dar: +Ein charaktergeprägter Bericht darüber, wie sich dein Agent tatsächlich über vergangene Sitzungen hinweg verhalten hat. Führt den gleichen Scan wie die `failproofai audit`-CLI durch, stellt ihn aber als einseitiges, teilbares Poster und vier darunter liegende Abschnitte dar: -1. **Poster** — füllt den ersten Viewport. Eigenständiger PNG-Erfassungsbereich mit dem failproof_ai-Schriftzug + Audit-Label · Archetyp-Index (`№ NN of 08`) + Audit-Datum · numerischer Score (0–100) + Perzentil-Rangpille (`top 15%`) · der Archetyp-Name (einer von `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + 3-Schlagwort-Streifen · `// only N% of agents are this archetype`-Seltenheitszeile · 8×8-Pixel-Sigil-Kachel · `audit yours → failproof.ai`-Fußzeile. Drei Share-Buttons befinden sich knapp außerhalb des Erfassungsbereichs: `post your archetype` (X-Intent), `share on linkedin`, `download poster`. Die Erfassung erfolgt über `html-to-image`, sodass das PNG pixelgenau der Bildschirmdarstellung entspricht (gestrichelte Rahmen, SVG-Logo-Maske, Farbverläufe, Schriftmetriken – alles erhalten). -2. **Stärken** — ruhige ✓-Zeilenliste mit Verhaltensweisen, die Ihr Agent bereits richtig macht, abgeleitet aus den Live-Audit-Daten (saubere Tool-Aufruf-Rate, keine direkten Pushes auf main, null Zugangsdaten-Lecks, null Wiederholungs-Stürme) — jede wird nur angezeigt, wenn die zugehörige Richtlinie im Audit-Zeitraum eine einwandfreie Bilanz hat. -3. **Eigenheiten** — Tabelle mit dem, was durchgerutscht ist, nach Schwere sortiert: `wann · was durchgerutscht ist + die Richtlinie, die es hätte abfangen können · Schwere-Pille · gesehen`, wobei die Häufigkeit `new` (einmal), `N× seen` (2–9 Mal) oder `recurring` (10+) anzeigt. -4. **So verbessern Sie sich** — ruhige Zeilenliste, eine pro empfohlener Richtlinie: Richtlinienname in Weiß, einzeilige Beschreibung, Installationsbefehl + Kopier-Button auf der rechten Seite. Die Abschnittsüberschrift lautet `enable all N → projected · ` (der Score, den Sie mit allen Korrekturen erreichen würden), und der `[install all]`-Button kopiert den kombinierten `failproofai policy add a b c …`-Befehl für alle empfohlenen Richtlinien. -5. **Kommen Sie besser zurück** — zwei nebeneinander liegende Karten. Links: Erinnerung setzen (`3d` / `7d` / `14d` / `30d`-Kadenz-Auswahl; wird über `/api/auth/reminder` nach Authentifizierung gespeichert). Rechts: failproof-Vorteile freischalten — `invite a friend` öffnet ein Modal, das eine komma-/leerzeichen-/zeilenumbruch-getrennte Liste von Freundes-E-Mails akzeptiert (max. 10 pro Sendung), sendet diese per POST an `/api/audit/invite`, der sie an den `POST /v0/invite`-Endpunkt des API-Servers weiterleitet. Der API-Server sendet eine E-Mail pro Empfänger von `invite@failproof.ai` mit dem Absender in Cc und `Reply-To` gesetzt, sodass der Empfänger sieht, wer ihn eingeladen hat, und der Absender eine Kopie in seinem Posteingang erhält. Anonyme Benutzer werden zunächst durch den `AuthDialog` geleitet, damit die Absender-E-Mail vor dem Versand der Einladungen bekannt ist. Berechtigungen/Vorteile-Erfüllung ist ein Folgeschritt. +1. **Poster** — füllt den ersten Viewport. Eigenständiger PNG-Aufnahmebereich mit dem failproof_ai-Wortzeichen + Audit-Label · Archetyp-Index (`№ NN of 08`) + Auditdatum · numerischer Wert (0–100) + Perzentil-Rang-Pille (`top 15%`) · der Archetyp-Name (einer von `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + 3-Stichwort-Streifen · `// only N% of agents are this archetype`-Seltenheitszeile · 8×8-Pixel-Sigil-Kachel · `audit yours → failproof.ai`-Fußzeile. Drei Share-Buttons befinden sich knapp außerhalb des Aufnahmebereichs: `post your archetype` (X intent), `share on linkedin`, `download poster`. Die Aufnahme erfolgt über `html-to-image`, sodass das PNG pixelgenau mit der Bildschirmdarstellung übereinstimmt (gestrichelte Rahmen, SVG-Logo-Maske, Verläufe, Schriftmetriken – alles erhalten). +2. **Stärken** — ruhige ✓-Zeilenliste von Verhaltensweisen, die dein Agent bereits richtig macht, abgeleitet aus den Live-Audit-Daten (saubere Tool-Aufruf-Rate, keine direkten Pushes nach main, null Credential-Lecks, null Wiederholungsstürme) — jede nur angezeigt, wenn die entsprechende Richtlinie im Audit-Zeitraum eine makellose Bilanz aufweist. +3. **Eigenheiten** — Tabelle der Dinge, die durchgeschlüpft sind, nach Schweregrad geordnet: `when · what slipped + the policy that would've caught it · severity pill · seen`, wobei das Wiederauftreten als `new` (einmal), `N× seen` (2–9 Mal) oder `recurring` (10+) angegeben wird. +4. **So geht es besser** — ruhige Zeilenliste, eine pro empfohlener Richtlinie: Richtlinienname in Weiß, einzeilige Beschreibung, Installationsbefehl + Kopierschaltfläche auf der rechten Seite. Die Abschnittsüberschrift lautet `enable all N → projected · ` (der Wert, den du mit allen angewandten Korrekturen erreichen würdest), und die Schaltfläche `[install all]` kopiert den kombinierten `failproofai policy add a b c …`-Befehl für jede empfohlene Richtlinie. +5. **Komm besser wieder** — zwei nebeneinander angeordnete Karten. Links: eine Erinnerung setzen (`3d` / `7d` / `14d` / `30d`-Intervallauswahl; wird über `/api/auth/reminder` gespeichert, sobald authentifiziert). Rechts: failproof-Vorteile freischalten — `invite a friend` öffnet ein Modal, das eine komma-/leerzeichen-/zeilenumbruch-getrennte Liste von Freundes-E-Mails entgegennimmt (max. 10 pro Sendung), sendet diese per POST an `/api/audit/invite`, das an den api-server's `POST /v0/invite` weitergeleitet wird. Der api-server sendet eine E-Mail pro Empfänger von `invite@failproof.ai` mit dem Absender in Cc und gesetztem `Reply-To`, sodass der Empfänger sieht, wer ihn eingeladen hat, und der Absender eine Kopie in seinem Posteingang erhält. Anonyme Benutzer werden zunächst über `AuthDialog` geleitet, damit die E-Mail des Absenders bekannt ist, bevor Einladungen verschickt werden. Berechtigungen/Vorteilserfüllung folgt. -Betrieben vom `failproofai audit`-Runtime — siehe [Audit CLI](/de/cli/audit) für die zugrundeliegende Scan-Engine, unterstützte Flags und Transkript-spezifische Cache-Invarianten. Das Dashboard speichert das neueste Ergebnis unter `~/.failproofai/audit-dashboard.json` (Modus `0600`, einzelner Slot, neue Läufe überschreiben), sodass Revisits sofort erfolgen; **sowohl der Transkript-spezifische als auch der Gesamt-Ergebnis-Cache werden beim Lesen abgelehnt, sobald sie älter als 7 Tage sind**, sodass das Dashboard niemals still ein wochealtes Ergebnis ausliefert — nach Ablauf der TTL fällt `/audit` in seinen leeren Zustand zurück und fordert einen neuen Lauf an. Ein Klick auf `[ re-audit now ]` am unteren Ende des Berichts sendet einen POST an `/api/audit/run` mit `noCache: true` — der Re-Audit umgeht den Transkript-Cache und scannt jedes Transkript von Grund auf neu, anstatt das gecachte Ergebnis still zurückzugeben — und das Dashboard fragt `/api/audit/status` mit 1 Hz ab, bis der Lauf abgeschlossen ist; ein anheftender pinker Fortschrittsstreifen fixiert sich während des Laufs oben im Viewport mit einem Laufzeit-Timer, und das neue Ergebnis tauscht sich bei Erfolg an Ort und Stelle aus (kein vollständiges Neuladen der Seite; ein fehlgeschlagener Re-Audit lässt den vorherigen Bericht unberührt). Bei einem Fehler wird der Streifen rot mit Text, der auf `RerunError.kind` abgestimmt ist (`timeout` / `network` / `post_failed`). Leerzustand (kein Cache oder abgelaufen) und Null-Sitzungszustand (Cache existiert, aber der Scan fand keine Transkripte) werden separat angezeigt. +Wird durch die `failproofai audit`-Laufzeitumgebung gesteuert — siehe [Audit CLI](/de/cli/audit) für die zugrunde liegende Scan-Engine, unterstützte Flags und sitzungsspezifische Cache-Invarianten. Das Dashboard speichert das neueste Ergebnis unter `~/.failproofai/audit-dashboard.json` (Modus `0600`, einzelner Slot, neue Durchläufe überschreiben), sodass Wiederbesuche sofort sind; **sowohl der sitzungsspezifische als auch der Gesamtergebnis-Cache werden beim Lesen abgelehnt, sobald sie älter als 7 Tage sind**, damit das Dashboard nie stillschweigend ein wochealtes Ergebnis liefert — nach dem TTL fällt `/audit` auf seinen leeren Zustand zurück und fordert einen neuen Durchlauf an. Ein Klick auf `[ re-audit now ]` nahe dem Ende des Berichts sendet einen POST an `/api/audit/run` mit `noCache: true` — ein erneuter Audit umgeht den sitzungsspezifischen Cache und scannt jedes Transkript von Grund auf neu, anstatt stillschweigend das gecachte Ergebnis zurückzugeben — und das Dashboard fragt `/api/audit/status` im Sekundentakt ab, bis der Durchlauf abgeschlossen ist; während des Durchlaufs erscheint ein pinker Fortschrittsstreifen oben im Viewport mit einem laufenden Timer, und das neue Ergebnis wird bei Erfolg an Ort und Stelle eingefügt (kein vollständiges Neuladen der Seite; ein fehlgeschlagener erneuter Audit lässt den vorherigen Bericht unberührt). Bei einem Fehler wird der Streifen rot mit einer Meldung, die auf dem `RerunError.kind` basiert (`timeout` / `network` / `post_failed`). Leerzustand (kein Cache oder abgelaufen) und Null-Sitzungen-Zustand (Cache vorhanden, aber der Scan hat keine Transkripte gefunden) werden separat angezeigt. ### Richtlinien -Eine zweiseitige Seite zur Verwaltung von Richtlinien und Überprüfung der Aktivität. +Eine zweiseitige Seite zur Verwaltung von Richtlinien und zur Überprüfung von Aktivitäten. - - Wählen Sie in einem einzelnen Panel aus, welche Agenten-CLIs failproofai schützt — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI und Hermes haben jeweils eine Zeile mit Installationsstatus (`Active` / `Detected` / `Inactive`), dem benutzerbereichs-spezifischen Einstellungspfad und einem markenfarbigen Akzent. Aktivieren oder deaktivieren Sie die gewünschten CLIs und klicken Sie auf `Apply changes`, um die Änderungen in einem Schritt zu installieren/deinstallieren. CLIs, deren Binärdatei im PATH erkannt wird, sind vorab aktiviert. - - Aktivieren oder deaktivieren Sie einzelne Richtlinien mit einem einzigen Klick (schreibt in `~/.failproofai/policies-config.json` — gemeinsam genutzt von allen installierten CLIs) - - Erweitern Sie eine Richtlinie, um ihre Parameter zu konfigurieren (für Richtlinien, die `policyParams` unterstützen) - - Legen Sie einen benutzerdefinierten Richtliniendateipfad fest + - Wähle über ein einziges Panel aus, welche Agent-CLIs failproofai schützt — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi und Hermes haben jeweils eine Zeile mit Installationsstatus (`Active` / `Detected` / `Inactive`), dem benutzerspezifischen Einstellungspfad und einem markenspezifischen Akzent. Hake die gewünschten CLIs an oder ab und klicke auf `Apply changes`, um die Änderungen in einem Schritt zu installieren/deinstallieren. CLIs, deren Binary auf dem PATH erkannt wurde, sind vorausgewählt. + - Einzelne Richtlinien per Klick aktivieren oder deaktivieren (schreibt in `~/.failproofai/policies-config.json` — gilt für jede installierte CLI) + - Eine Richtlinie erweitern, um ihre Parameter zu konfigurieren (für Richtlinien, die `policyParams` unterstützen) + - Einen benutzerdefinierten Richtliniendateipfad festlegen - - Vollständige paginierte Historie aller Hook-Ereignisse, die in allen Sitzungen ausgelöst wurden - - Filtern nach Entscheidung, Ereignistyp, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(Beta)_ / Cursor Agent _(Beta)_ / OpenCode _(Beta)_ / Pi _(Beta)_ / Gemini CLI _(Beta)_ / Hermes), Richtlinienname oder Sitzungs-ID - - Jede Zeile zeigt: Zeitstempel, Richtlinienname, Entscheidung, CLI-Badge (orange = Claude Code, lila = OpenAI Codex, blau = GitHub Copilot, smaragd = Cursor Agent, bernstein = OpenCode, pink = Pi, himmelblau = Gemini CLI, indigo = Hermes), Tool-Name, Sitzungs-ID und den Grund für deny/instruct-Entscheidungen - - Klicken Sie auf eine Sitzungs-ID, um das zugehörige Transkript zu öffnen — der Viewer erkennt automatisch, welche CLI den Hook ausgelöst hat (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) und zeigt das passende CLI-Badge in der Überschrift an + - Vollständige, seitenweise Chronik aller Hook-Ereignisse, die sitzungsübergreifend ausgelöst wurden + - Nach Entscheidung, Ereignistyp, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), Richtlinienname oder Sitzungs-ID filtern + - Jede Zeile zeigt: Zeitstempel, Richtlinienname, Entscheidung, CLI-Badge (orange = Claude Code, lila = OpenAI Codex, blau = GitHub Copilot, smaragd = Cursor Agent, bernstein = OpenCode, rosa = Pi, indigo = Hermes, blaugrün = OpenClaw, rose = Factory Droid, violett = Devin, cyan = Antigravity, limette = Goose), Tool-Name, Sitzungs-ID und den Grund für deny/instruct-Entscheidungen + - Klicke auf eine Sitzungs-ID, um ihr Transkript zu öffnen — der Viewer erkennt automatisch, welche CLI den Hook ausgelöst hat (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) und zeigt das passende CLI-Badge in der Kopfzeile an @@ -92,13 +92,13 @@ Eine zweiseitige Seite zur Verwaltung von Richtlinien und Überprüfung der Akti ## Automatische Aktualisierung -Das Dashboard verfügt über eine Auto-Refresh-Umschalttaste in der oberen Navigation. Wenn aktiviert, wird die aktuelle Seite regelmäßig aktualisiert, um neue Sitzungen und Richtlinienaktivitäten anzuzeigen, sobald sie auftreten. Unverzichtbar für die Überwachung langläufiger autonomer Agentensitzungen. +Das Dashboard verfügt über einen Auto-Aktualisierungs-Schalter in der oberen Navigation. Wenn aktiviert, wird die aktuelle Seite regelmäßig aktualisiert, um neue Sitzungen und Richtlinienaktivitäten anzuzeigen, sobald sie auftreten. Unverzichtbar für die Überwachung langwieriger autonomer Agent-Sitzungen. --- ## Seiten deaktivieren -Wenn Sie nur bestimmte Teile des Dashboards benötigen, setzen Sie `FAILPROOFAI_DISABLE_PAGES` auf eine kommagetrennte Liste von Seitennamen: +Wenn du nur bestimmte Teile des Dashboards benötigst, setze `FAILPROOFAI_DISABLE_PAGES` auf eine kommagetrennte Liste von Seitennamen: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +110,7 @@ Gültige Werte: `policies`, `projects`, `audit`. ## Projektpfad konfigurieren -Standardmäßig liest das Dashboard aus dem standardmäßigen Claude Code-Projektverzeichnis. Überschreiben Sie dies für benutzerdefinierte Setups: +Standardmäßig liest das Dashboard aus dem Standard-Claude Code-Projektverzeichnis. Für benutzerdefinierte Setups überschreibe diesen Pfad: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -120,30 +120,30 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ## Zugriff von einem Nicht-localhost-Host -Wenn Sie das Dashboard im **Dev-Modus** (`npm run dev`) ausführen und von einem anderen Hostnamen als localhost darauf zugreifen — zum Beispiel einer benutzerdefinierten Domain, einer Remote-IP oder einer getunnelten URL — kann folgende Warnung auftreten: +Wenn du das Dashboard im **Dev-Modus** (`npm run dev`) betreibst und von einem anderen Hostnamen als `localhost` darauf zugreifst – zum Beispiel einer benutzerdefinierten Domain, einer Remote-IP oder einer getunnelten URL – siehst du möglicherweise eine Warnung wie: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Dies ist Next.js, das den cross-origin-Zugriff auf seinen HMR-WebSocket (Hot Module Reload) blockiert, eine reine Entwicklungsfunktion. Um Ihren Host zuzulassen, verwenden Sie das Flag `--allowed-origins`: +Next.js blockiert dabei den Cross-Origin-Zugriff auf seinen HMR-WebSocket (Hot Module Reload), der ausschließlich im Dev-Modus vorhanden ist. Um deinen Host zuzulassen, verwende das Flag `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -Für mehrere Hosts oder IPs übergeben Sie eine kommagetrennte Liste: +Für mehrere Hosts oder IPs übergib eine kommagetrennte Liste: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -Sie können stattdessen auch die Umgebungsvariable `FAILPROOFAI_ALLOWED_DEV_ORIGINS` setzen: +Du kannst auch stattdessen die Umgebungsvariable `FAILPROOFAI_ALLOWED_DEV_ORIGINS` setzen: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Dies gilt nur für den Dev-Modus. Beim Ausführen von `failproofai` (Produktionsmodus) gibt es keinen HMR-WebSocket und kein cross-origin-Entwicklungsressourcenproblem. +Dies gilt nur für den Dev-Modus. Beim Ausführen von `failproofai` (Produktionsmodus) gibt es keinen HMR-WebSocket und kein Cross-Origin-Dev-Ressourcen-Problem. \ No newline at end of file diff --git a/docs/de/getting-started.mdx b/docs/de/getting-started.mdx index 4499b6f3..80d4bdf8 100644 --- a/docs/de/getting-started.mdx +++ b/docs/de/getting-started.mdx @@ -1,13 +1,13 @@ --- title: Erste Schritte -description: "Installiere failproofai, aktiviere Richtlinien und lass deine Agenten zuverlässig arbeiten" +description: "failproofai installieren, Richtlinien aktivieren und Agenten zuverlässig ausführen" icon: rocket --- ## Voraussetzungen - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (optional – nur zum Kompilieren aus dem Quellcode erforderlich) +- **Bun** >= 1.3.0 (optional – nur beim Bauen aus dem Quellcode erforderlich) --- @@ -31,15 +31,15 @@ bun add -g failproofai - Richtlinien sind Regeln, die vor und nach jedem Agenten-Tool-Aufruf ausgeführt werden. Sie erkennen destruktive Befehle, den Abfluss von Geheimnissen und andere Fehlerquellen, bevor sie Schaden anrichten können. + Richtlinien sind Regeln, die vor und nach jedem Werkzeugaufruf eines Agenten ausgeführt werden. Sie erkennen destruktive Befehle, den Abfluss von Geheimnissen und andere Fehlerquellen, bevor diese Schaden anrichten können. ```bash failproofai policies --install ``` - Damit werden Hook-Einträge in die installierten Agenten-CLIs geschrieben (Claude Codes `~/.claude/settings.json`, OpenAI Codex' `~/.codex/hooks.json`, GitHub Copilot CLIs `~/.copilot/hooks/failproofai.json`, Cursor Agents `~/.cursor/hooks.json`, OpenCodes generiertem Plugin-Shim unter `~/.config/opencode/plugins/failproofai.mjs` sowie einem Registrierungseintrag im `plugin`-Array von `~/.config/opencode/opencode.json`, Pis `~/.pi/agent/settings.json`, Gemini CLIs `~/.gemini/settings.json` oder Hermes' `~/.hermes/config.yaml`). Sind mehrere installiert, wirst du zur Auswahl aufgefordert; übergib `--cli claude codex copilot cursor opencode pi gemini hermes` (beliebige Teilmenge), um die Abfrage zu überspringen. + Damit werden Hook-Einträge in die installierten Agent-CLIs geschrieben (Claude Codes `~/.claude/settings.json`, OpenAI Codex' `~/.codex/hooks.json`, GitHub Copilot CLIs `~/.copilot/hooks/failproofai.json`, Cursor Agents `~/.cursor/hooks.json`, OpenCodes generierter Plugin-Shim unter `~/.config/opencode/plugins/failproofai.mjs` sowie ein Registrierungseintrag im `plugin`-Array von `~/.config/opencode/opencode.json`, Pis `~/.pi/agent/settings.json`, Hermes' `~/.hermes/config.yaml`, OpenClaws `~/.openclaw/openclaw.json`, Factory Droids `~/.factory/hooks.json`, Devin CLIs `~/.config/devin/config.json`, Antigravity CLIs `~/.gemini/config/hooks.json` oder Gooses automatisch erkanntem Plugin-Verzeichnis unter `~/.agents/plugins/failproofai/hooks/hooks.json`). Wenn mehr als eine CLI vorhanden ist, wird eine Auswahl angezeigt; übergib `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (beliebige Teilmenge), um die Abfrage zu überspringen. - Unterstützung für GitHub Copilot CLI, Cursor Agent, OpenCode, Pi und Gemini CLI ist **Beta** – Installation mit `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` oder `--cli gemini`. Hermes (hermes-agent, ein Slack/Telegram-Gateway) wird im Benutzerbereich mit `--cli hermes` installiert und ist **ebenfalls** eine Offline-Auditquelle. + GitHub Copilot CLI, Cursor Agent, OpenCode und Pi werden als **Beta** unterstützt – Installation mit `--cli copilot`, `--cli cursor`, `--cli opencode` bzw. `--cli pi`. Hermes (hermes-agent, ein Slack/Telegram-Gateway) wird mit User-Scope über `--cli hermes` installiert und ist **zudem** eine Offline-Audit-Quelle. OpenClaw (openclaw gateway, ein selbst gehosteter Multi-Channel-Assistent) wird mit User-Scope über `--cli openclaw` installiert – die Durchsetzung erfolgt über In-Process-Plugin-Hooks (`before_agent_finalize` ist ein echter Turn-End-Gate, sodass die `require-*-before-stop`-Builtins greifen) – und ist **zudem** eine Offline-Audit-Quelle. Factory Droid (`droid`) wird mit `--cli factory` (User + Project Scope) installiert und ist **ebenfalls** eine Offline-Audit-Quelle. Devin CLI (`devin`, Cognition) wird mit `--cli devin` (User + Project Scope) installiert und ist **ebenfalls** eine Offline-Audit-Quelle. Antigravity CLI (`agy`) wird mit `--cli antigravity` (User + Project Scope) installiert und ist **ebenfalls** eine Offline-Audit-Quelle. Goose (Codename goose, Block) wird mit `--cli goose` (User + Project Scope) installiert – das Installationsprogramm legt lediglich ein Plugin-Verzeichnis unter `~/.agents/plugins/failproofai/` an, das Goose automatisch erkennt, und ist **ebenfalls** eine Offline-Audit-Quelle. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,14 +62,14 @@ bun add -g failproofai failproofai policies ``` - Zeigt alle Richtlinien, ihren Aktivierungsstatus und konfigurierte Parameter an. + Zeigt alle Richtlinien an, ob sie aktiviert sind und welche Parameter konfiguriert wurden. - + ```bash failproofai ``` - Öffnet ein lokales Dashboard unter `http://localhost:8020`, in dem du Sitzungen durchsuchen, Tool-Aufrufe einsehen und Richtlinien verwalten kannst. + Öffnet ein lokales Dashboard unter `http://localhost:8020`, in dem du Sitzungen durchsuchen, Werkzeugaufrufe inspizieren und Richtlinien verwalten kannst. Starte Claude Code wie gewohnt. Versucht der Agent etwas Riskantes, greift failproofai automatisch ein. Lass ihn unbeaufsichtigt laufen und prüfe anschließend im Dashboard, was passiert ist. @@ -74,9 +78,9 @@ bun add -g failproofai --- -## So funktionieren Richtlinien +## Wie Richtlinien funktionieren -Jedes Mal, wenn ein Agent ein Tool ausführt, ruft Claude Code failproofai als Subprozess auf: +Jedes Mal, wenn ein Agent ein Werkzeug aufruft, ruft Claude Code failproofai als Unterprozess auf: ```text Claude Code → failproofai --hook PreToolUse → reads stdin JSON @@ -98,7 +102,7 @@ Richtlinien laufen in deinem lokalen Prozess. Es werden keine Daten an einen ext ## Team-Richtlinien mit konventionsbasierten Richtlinien einrichten -Der schnellste Weg, einheitliche Qualitätsstandards im Team einzuführen, ist die `.failproofai/policies/`-Konvention. Lege Richtliniendateien in dieses Verzeichnis und sie werden automatisch geladen – keine Flags, keine Konfigurationsänderungen, keine Installationsbefehle. +Der schnellste Weg, einheitliche Qualitätsstandards im Team zu etablieren, ist die `.failproofai/policies/`-Konvention. Lege Richtliniendateien in dieses Verzeichnis – sie werden automatisch geladen, ohne Flags, Konfigurationsänderungen oder Installationsbefehle. @@ -107,7 +111,7 @@ Der schnellste Weg, einheitliche Qualitätsstandards im Team einzuführen, ist d ``` - Kopiere die Beispieldateien oder schreibe eigene: + Kopiere die Starterbeispiele oder schreibe eigene: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -132,18 +136,18 @@ Der schnellste Weg, einheitliche Qualitätsstandards im Team einzuführen, ist d }); ``` - + ```bash git add .failproofai/policies/ git commit -m "Add team quality policies" ``` - Alle Teammitglieder, die failproofai installiert haben, erhalten diese Richtlinien automatisch. Kein individuelles Setup erforderlich. + Alle Teammitglieder, die failproofai installiert haben, übernehmen diese Richtlinien automatisch. Kein individuelles Setup erforderlich. -Checke `.failproofai/policies/` in dein Repository ein, damit das gesamte Team dieselben Standards verwendet. Wenn neue Fehlerquellen entdeckt werden, füge Richtlinien hinzu und pushe sie – alle erhalten das Update beim nächsten `git pull`. Im Laufe der Zeit werden diese Richtlinien zu einem lebendigen Qualitätsstandard, der sich kontinuierlich verbessert. +Committe `.failproofai/policies/` in dein Repository, damit das gesamte Team dieselben Standards teilt. Wenn das Team neue Fehlerquellen entdeckt, füge Richtlinien hinzu und pushe sie – alle erhalten das Update beim nächsten `git pull`. Mit der Zeit werden diese Richtlinien zu einem lebendigen Qualitätsstandard, der sich kontinuierlich verbessert. --- @@ -155,10 +159,10 @@ Alle Konfigurationen und Protokolle verbleiben auf deinem Rechner: | Pfad | Inhalt | |------|--------| | `~/.failproofai/policies-config.json` | Globale Richtlinienkonfiguration | -| `~/.failproofai/hook-activity.jsonl` | Hook-Ausführungsverlauf | +| `~/.failproofai/hook-activity.jsonl` | Ausführungshistorie der Hooks | | `~/.failproofai/hook.log` | Debug-Protokoll für benutzerdefinierte Hook-Fehler | | `.failproofai/policies-config.json` | Projektbezogene Konfiguration (eingecheckt) | -| `.failproofai/policies-config.local.json` | Persönliche Überschreibungen (per gitignore ausgeschlossen) | +| `.failproofai/policies-config.local.json` | Persönliche Überschreibungen (via gitignore ausgeschlossen) | --- @@ -177,7 +181,7 @@ Entfernt Hook-Einträge aus `~/.claude/settings.json`. Konfigurationsdateien in - Geltungsbereiche und Konfigurationsdateiformat + Scopes und Konfigurationsdateiformat @@ -185,11 +189,11 @@ Entfernt Hook-Einträge aus `~/.claude/settings.json`. Konfigurationsdateien in - Schreibe eigene Richtlinien in JavaScript + Eigene Richtlinien in JavaScript schreiben - Sitzungen überwachen und Richtlinienaktivitäten einsehen + Sitzungen überwachen und Richtlinienaktivität prüfen \ No newline at end of file diff --git a/docs/de/introduction.mdx b/docs/de/introduction.mdx index c0c06daa..6a54dd67 100644 --- a/docs/de/introduction.mdx +++ b/docs/de/introduction.mdx @@ -1,32 +1,32 @@ --- title: "Failproof AI" -description: "FailproofAI gibt KI-Agenten 39 integrierte Fehlerrichtlinien, die Schleifen, Secret-Leaks, destruktive Tool-Aufrufe und mehr mit einer einzigen Installation abfangen." +description: "FailproofAI stattet KI-Agenten mit 39 integrierten Fehlerrichtlinien aus, die Schleifen, Secret-Leaks, destruktive Tool-Aufrufe und mehr mit einer einzigen Installation abfangen." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks und Richtlinien für **KI-Fehlerbehandlung**, **Fehlerbehebung** und **LLM-Zuverlässigkeit**. Halten Sie Ihre KI-Agenten zuverlässig und autonom am Laufen – für **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** und das **Agents SDK**. +Hooks und Richtlinien für **KI-Fehlerbehandlung**, **Fehlerbehebung** und **LLM-Zuverlässigkeit**. Halte deine KI-Agenten zuverlässig und autonom am Laufen – für **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** und das **Agents SDK**. -KI-Agenten scheitern auf vorhersehbare Weisen. Sie führen destruktive Befehle aus, geben Secrets preis, weichen von ihrer Aufgabe ab, stecken in Schleifen fest oder pushen direkt in den main-Branch. Werden diese Fehler nicht behoben, können kleine Probleme zu Ausfällen, geleakten Zugangsdaten und verlorenem Code führen. +KI-Agenten scheitern auf vorhersehbare Weisen. Sie führen destruktive Befehle aus, leaken Secrets, verlieren den Fokus, stecken in Schleifen fest oder pushen direkt in den Main-Branch. Unbeaufsichtigt können kleine Fehler zu Ausfällen, geleakten Zugangsdaten und verlorenem Arbeitsfortschritt eskalieren. -FailproofAI löst dieses Problem mit **Richtlinien**. Diese Regeln haken sich in jeden Agent-Tool-Aufruf ein, um **Fehler zu erkennen**, **zu beheben** (blockieren, anweisen, bereinigen) und **Sie zu benachrichtigen**, wenn etwas Aufmerksamkeit erfordert. Ein lokales Dashboard ermöglicht es Ihnen, jeden Tool-Aufruf, jeden Agentenfehler und jede Wiederherstellungsmaßnahme im Nachhinein zu überprüfen. +FailproofAI löst dieses Problem mit **Richtlinien**. Diese Regeln klinken sich in jeden Tool-Aufruf eines Agenten ein, um **Fehler zu erkennen**, **sie zu beheben** (blockieren, anweisen, bereinigen) und **dich zu benachrichtigen**, wenn etwas Aufmerksamkeit erfordert. Ein lokales Dashboard ermöglicht es dir, jeden Tool-Aufruf, jeden Agentenfehler und jede Wiederherstellungsaktion im Nachhinein zu überprüfen. -Keine Daten verlassen Ihren Computer. +Es verlassen keine Daten deinen Rechner. -## Erste Schritte +## Loslegen - Destruktive Befehle blockieren, Secret-Leaks verhindern, Agenten innerhalb der Projektgrenzen halten und mehr. Alles direkt einsatzbereit. + Destruktive Befehle blockieren, Secret-Leaks verhindern, Agenten innerhalb der Projektgrenzen halten und mehr – alles sofort einsatzbereit. - - Schreiben Sie eigene Regeln in JavaScript mit einer einfachen allow / deny / instruct API. + + Schreibe deine eigenen Regeln in JavaScript mit einem einfachen allow / deny / instruct API. - Sehen Sie, was Ihre Agenten in Ihrer Abwesenheit getan haben. Sitzungen durchsuchen, Tool-Aufrufe untersuchen und überprüfen, wo Richtlinien ausgelöst wurden. + Sieh, was deine Agenten in deiner Abwesenheit getan haben. Sitzungen durchsuchen, Tool-Aufrufe inspizieren und überprüfen, wo Richtlinien ausgelöst wurden. @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -Eine vollständige Anleitung finden Sie im [Erste-Schritte-Leitfaden](/de/getting-started). \ No newline at end of file +Den vollständigen Einstieg findest du im [Erste Schritte](/de/getting-started)-Leitfaden. \ No newline at end of file diff --git a/docs/docs.json b/docs/docs.json index 07ba70d0..56e2c9da 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -344,7 +344,7 @@ ] }, { - "language": "pt-BR", + "language": "pt-br", "tabs": [ { "tab": "Documentação", @@ -1275,7 +1275,7 @@ ] }, { - "language": "pt-BR", + "language": "pt-br", "tabs": [ { "tab": "Documentação", diff --git a/docs/es/built-in-policies.mdx b/docs/es/built-in-policies.mdx index 5644f1c6..8fae9faa 100644 --- a/docs/es/built-in-policies.mdx +++ b/docs/es/built-in-policies.mdx @@ -4,13 +4,13 @@ description: "Las 39 políticas integradas que detectan los fallos más comunes icon: shield --- -failproofai incluye 39 políticas integradas que detectan los fallos más comunes de los agentes. Cada política se activa en un tipo de evento de hook específico y en un nombre de herramienta determinado. Diecinueve políticas aceptan parámetros que permiten ajustar su comportamiento sin necesidad de escribir código. Cinco políticas de flujo de trabajo imponen una cadena commit → push → PR → CI antes de que Claude se detenga. +failproofai incluye 39 políticas integradas que detectan los modos de fallo más comunes de los agentes. Cada política se activa en un tipo específico de evento de hook y nombre de herramienta. Diecinueve políticas aceptan parámetros que permiten ajustar su comportamiento sin escribir código. Cinco políticas de flujo de trabajo exigen una secuencia de commit → push → PR → CI antes de que Claude se detenga. --- ## Descripción general -Las políticas están agrupadas en categorías: +Las políticas se agrupan en las siguientes categorías: | Categoría | Políticas | Tipo de hook | |----------|----------|-----------| @@ -26,18 +26,18 @@ Las políticas están agrupadas en categorías: | [Flujo de trabajo](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | - **`block-`** — impide que el agente continúe. -- **`warn-`** — proporciona al agente contexto adicional para que pueda corregirse. +- **`warn-`** — proporciona contexto adicional al agente para que pueda corregirse. - **`sanitize-`** — elimina datos sensibles del resultado de la herramienta antes de que el agente lo vea. ### Espacios de nombres -Cada política reside en un espacio `/`. Las políticas integradas pertenecen al +Cada política ocupa un slot `/`. Las políticas integradas pertenecen al espacio de nombres **`failproofai/`** — por ejemplo, `failproofai/sanitize-jwt`. El espacio de nombres evita colisiones cuando también se cargan políticas personalizadas o de terceros con nombres cortos similares. En la configuración puedes referirte a una política integrada por su nombre corto o su -nombre calificado; ambas formas apuntan a la misma política: +nombre calificado; ambas formas resuelven a la misma política: ```json { @@ -48,35 +48,35 @@ nombre calificado; ambas formas apuntan a la misma política: } ``` -Si un nombre no contiene `/`, failproofai lo trata como perteneciente al espacio de nombres -predeterminado `failproofai`. Los nombres que ya contienen `/` (p. ej. `myorg/foo`, +Si un nombre no contiene `/`, failproofai lo considera parte del espacio de nombres predeterminado +`failproofai`. Los nombres que ya contienen `/` (p. ej. `myorg/foo`, `custom/my-hook`) se mantienen tal cual. - **`require-`** — bloquea el evento Stop hasta que se cumplan las condiciones. --- -Todas las políticas admiten un campo opcional `hint` en `policyParams`. El hint se añade al mensaje de deny o instruct que ve Claude, proporcionando orientación accionable sin modificar el código de la política. Funciona con políticas integradas, personalizadas y de convención. Consulta [Configuración → hint](/es/configuration#hint-cross-cutting) para más detalles. +Todas las políticas admiten un campo opcional `hint` en `policyParams`. El hint se añade al mensaje deny o instruct que ve Claude, proporcionando orientación accionable sin modificar el código de la política. Funciona con políticas integradas, personalizadas y de convención. Consulta [Configuración → hint](/es/configuration#hint-cross-cutting) para más detalles. --- ## Comandos peligrosos -Evita que los agentes ejecuten operaciones difíciles de deshacer o que puedan dañar el sistema anfitrión. +Evita que los agentes ejecuten operaciones difíciles de deshacer o que podrían dañar el sistema anfitrión. ### `block-sudo` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier comando `sudo`. +**Por defecto:** Deniega cualquier comando `sudo`. -Bloquea invocaciones que incluyen la palabra clave `sudo`. La coincidencia de patrones se realiza sobre los tokens del comando analizado, no sobre la cadena en bruto, para evitar bypass mediante inyección de operadores de shell. +Bloquea invocaciones que incluyen la palabra clave `sudo`. La coincidencia de patrones se realiza sobre los tokens del comando parseado, no sobre la cadena sin procesar, para evitar bypass mediante inyección de operadores shell. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos exactos que están permitidos. Cada entrada se compara contra los tokens argv analizados. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos exactos que están permitidos. Cada entrada se compara contra los tokens argv parseados. | **Ejemplo:** @@ -93,7 +93,7 @@ Bloquea invocaciones que incluyen la palabra clave `sudo`. La coincidencia de pa Con esta configuración, `sudo systemctl status nginx` está permitido, pero `sudo rm /etc/hosts` se deniega. -Los patrones se comparan contra tokens analizados, no contra la cadena de comando en bruto. Esto evita bypass mediante operadores de shell añadidos (p. ej. `sudo systemctl status x; rm -rf /` no coincide con `sudo systemctl status *`). +Los patrones se comparan contra tokens parseados, no contra la cadena de comando sin procesar. Esto evita bypass mediante operadores shell añadidos (p. ej. `sudo systemctl status x; rm -rf /` no coincide con `sudo systemctl status *`). --- @@ -101,13 +101,13 @@ Los patrones se comparan contra tokens analizados, no contra la cadena de comand ### `block-rm-rf` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega `rm -rf`, `rm -fr` y formas similares de eliminación recursiva. +**Por defecto:** Deniega `rm -rf`, `rm -fr` y formas similares de eliminación recursiva. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Rutas que pueden eliminarse de forma recursiva de manera segura (p. ej. `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Rutas que es seguro eliminar de forma recursiva (p. ej. `/tmp`). | **Ejemplo:** @@ -126,7 +126,7 @@ Los patrones se comparan contra tokens analizados, no contra la cadena de comand ### `block-curl-pipe-sh` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega `curl | bash`, `curl | sh`, `wget | bash` y patrones similares. +**Por defecto:** Deniega `curl | bash`, `curl | sh`, `wget | bash` y patrones similares. Sin parámetros. @@ -135,7 +135,7 @@ Sin parámetros. ### `block-failproofai-commands` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega comandos que desinstalarían o deshabilitarían failproofai (p. ej. `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Por defecto:** Deniega comandos que desinstalarían o desactivarían el propio failproofai (p. ej. `npm uninstall failproofai`, `failproofai policies --uninstall`). Sin parámetros. @@ -143,20 +143,20 @@ Sin parámetros. ## Comandos de infraestructura -Impide que los agentes de código ejecuten CLIs de infraestructura o activen pipelines de CI/CD. Todas las políticas de esta categoría están **desactivadas por defecto** (`defaultEnabled: false`) — los agentes que legítimamente necesiten llamar a `kubectl`, `terraform`, etc. no se verán afectados a menos que habilites la política. Cuando está habilitada, cualquier invocación del CLI correspondiente se deniega a menos que el comando coincida con una entrada en `allowPatterns`. +Impide que los agentes de código ejecuten CLIs de infraestructura o activen pipelines de CI/CD. Todas las políticas de esta categoría son **opt-in** (`defaultEnabled: false`) — los agentes que legítimamente necesiten llamar a `kubectl`, `terraform`, etc. no se verán interrumpidos a menos que habilites la política. Cuando se habilita, se deniega cualquier invocación del CLI correspondiente a menos que el comando coincida con alguna entrada en `allowPatterns`. -La gramática de patrones es la misma que en [`block-sudo`](#block-sudo): los tokens se comparan contra argv analizado, `*` es un comodín para un token, y cualquier comando que contenga un operador de shell independiente (`&&`, `||`, `|`, `;`) o un token con metacaracteres de shell incrustados se rechaza antes de la comprobación de la lista de permitidos para evitar bypass por inyección. +La gramática de patrones es la misma que en [`block-sudo`](#block-sudo): los tokens se comparan contra los argv parseados, `*` es un comodín para un token, y cualquier comando que contenga un operador shell independiente (`&&`, `||`, `|`, `;`) o un token con metacaracteres shell embebidos se rechaza antes de la comprobación de la lista de permitidos para evitar bypasses por inyección. ### `block-kubectl` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación de `kubectl`. +**Por defecto:** Deniega cualquier invocación de `kubectl`. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos kubectl permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos kubectl que están permitidos. | **Ejemplo:** @@ -177,13 +177,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-terraform` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación de `terraform` o `tofu` (OpenTofu). +**Por defecto:** Deniega cualquier invocación de `terraform` o `tofu` (OpenTofu). **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos terraform/tofu permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos terraform/tofu que están permitidos. | **Ejemplo:** @@ -202,13 +202,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-aws-cli` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación del CLI `aws`. +**Por defecto:** Deniega cualquier invocación del CLI de `aws`. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos del CLI aws permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos del CLI de aws que están permitidos. | **Ejemplo:** @@ -227,13 +227,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-gcloud` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación del CLI `gcloud` (Google Cloud). +**Por defecto:** Deniega cualquier invocación del CLI de `gcloud` (Google Cloud). **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos gcloud permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos gcloud que están permitidos. | **Ejemplo:** @@ -252,13 +252,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-az-cli` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación del CLI `az` (Azure). +**Por defecto:** Deniega cualquier invocación del CLI de `az` (Azure). **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos del CLI az permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos del CLI de az que están permitidos. | **Ejemplo:** @@ -277,13 +277,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-helm` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega cualquier invocación de `helm`. +**Por defecto:** Deniega cualquier invocación de `helm`. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos helm permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefijos de comandos helm que están permitidos. | **Ejemplo:** @@ -302,7 +302,7 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply ### `block-gh-pipeline` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega los siguientes subcomandos del CLI `gh` que modifican estado o activan pipelines: +**Por defecto:** Deniega los siguientes subcomandos del CLI de `gh` que mutan estado o activan pipelines: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -311,13 +311,13 @@ Con esta configuración, `kubectl get pods` está permitido pero `kubectl apply - `gh cache delete` - `gh secret set`, `gh secret delete` -Los subcomandos de solo lectura de `gh` como `gh pr view`, `gh pr list`, `gh run list`, `gh release view` y `gh api repos/.../...` **no** son interceptados por esta política — son habitualmente necesarios para verificaciones de flujo de trabajo (incluido el propio `require-ci-green-before-stop` de failproofai). +Los subcomandos de `gh` de solo lectura como `gh pr view`, `gh pr list`, `gh run list`, `gh release view` y `gh api repos/.../...` **no** son interceptados por esta política — son necesarios habitualmente para comprobaciones de flujo de trabajo (incluida la propia `require-ci-green-before-stop` de failproofai). **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Invocaciones específicas permitidas aunque normalmente serían denegadas. | +| `allowPatterns` | `string[]` | `[]` | Invocaciones específicas que se permiten aunque normalmente serían denegadas. | **Ejemplo:** @@ -335,12 +335,12 @@ Los subcomandos de solo lectura de `gh` como `gh pr view`, `gh pr list`, `gh run ## Secretos (sanitizadores) -Evita que los agentes filtren credenciales en su contexto o salida. Las políticas sanitizadoras se activan en eventos **PostToolUse**. Cuando Claude ejecuta un comando Bash, lee un archivo o llama a cualquier herramienta, estas políticas inspeccionan la salida antes de devolvérsela a Claude. Si se detecta un patrón de secreto, la política devuelve una decisión de deny que impide que la salida sea retornada. +Evita que los agentes filtren credenciales en su contexto o salida. Las políticas sanitizadoras se activan en eventos **PostToolUse**. Cuando Claude ejecuta un comando Bash, lee un archivo o llama a cualquier herramienta, estas políticas inspeccionan la salida antes de devolverla a Claude. Si se detecta un patrón de secreto, la política devuelve una decisión de denegación que impide que la salida sea retransmitida. ### `sanitize-jwt` **Evento:** PostToolUse (todas las herramientas) -**Comportamiento por defecto:** Redacta tokens JWT (tres segmentos base64url separados por `.`). +**Por defecto:** Redacta tokens JWT (tres segmentos base64url separados por `.`). Sin parámetros. @@ -349,13 +349,13 @@ Sin parámetros. ### `sanitize-api-keys` **Evento:** PostToolUse (todas las herramientas) -**Comportamiento por defecto:** Redacta formatos comunes de claves de API: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), claves de acceso AWS (`AKIA`), claves Stripe (`sk_live_`, `sk_test_`) y claves de Google API (`AIza`). +**Por defecto:** Redacta formatos comunes de API keys: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), claves de acceso AWS (`AKIA`), claves Stripe (`sk_live_`, `sk_test_`) y claves de Google API (`AIza`). **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Patrones regex adicionales que deben tratarse como secretos. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Patrones regex adicionales a tratar como secretos. | **Ejemplo:** @@ -377,7 +377,7 @@ Sin parámetros. ### `sanitize-connection-strings` **Evento:** PostToolUse (todas las herramientas) -**Comportamiento por defecto:** Redacta cadenas de conexión a bases de datos que contienen credenciales incrustadas (p. ej. `postgresql://user:password@host/db`). +**Por defecto:** Redacta cadenas de conexión a bases de datos que contienen credenciales embebidas (p. ej. `postgresql://user:password@host/db`). Sin parámetros. @@ -386,7 +386,7 @@ Sin parámetros. ### `sanitize-private-key-content` **Evento:** PostToolUse (todas las herramientas) -**Comportamiento por defecto:** Redacta bloques PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, etc.). +**Por defecto:** Redacta bloques PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, etc.). Sin parámetros. @@ -395,7 +395,7 @@ Sin parámetros. ### `sanitize-bearer-tokens` **Evento:** PostToolUse (todas las herramientas) -**Comportamiento por defecto:** Redacta cabeceras `Authorization: Bearer ` donde el token tiene 20 o más caracteres. +**Por defecto:** Redacta cabeceras `Authorization: Bearer ` donde el token tiene 20 o más caracteres. Sin parámetros. @@ -408,9 +408,9 @@ Protege la configuración sensible del entorno para que los agentes no puedan le ### `block-env-files` **Evento:** PreToolUse (Bash, Read) -**Comportamiento por defecto:** Deniega la lectura de archivos `.env` mediante `cat .env`, llamadas a la herramienta `Read` con `.env` como ruta de archivo, etc. +**Por defecto:** Deniega la lectura de archivos `.env` mediante `cat .env`, llamadas a la herramienta `Read` con `.env` como ruta de archivo, etc. -No bloquea `.envrc` ni otros archivos relacionados con el entorno — solo archivos cuyo nombre exacto sea `.env`. +No bloquea `.envrc` ni otros archivos relacionados con el entorno; solo archivos llamados exactamente `.env`. Sin parámetros. @@ -419,7 +419,7 @@ Sin parámetros. ### `protect-env-vars` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega comandos que imprimen variables de entorno: `printenv`, `env`, `echo $VAR`. +**Por defecto:** Deniega comandos que imprimen variables de entorno: `printenv`, `env`, `echo $VAR`. Sin parámetros. @@ -432,13 +432,13 @@ Mantiene a los agentes dentro de los límites del proyecto y alejados de archivo ### `block-read-outside-cwd` **Evento:** PreToolUse (Read, Bash) -**Comportamiento por defecto:** Deniega la lectura de archivos fuera de la raíz del proyecto. El límite es `CLAUDE_PROJECT_DIR` (establecido una vez por sesión por Claude Code), con un fallback al directorio de trabajo actual de la sesión cuando esa variable no está definida. Usar la raíz del proyecto en lugar del `cwd` activo significa que el límite se mantiene estable incluso después de que Claude haga `cd` a un subdirectorio. +**Por defecto:** Deniega la lectura de archivos fuera de la raíz del proyecto. El límite es `CLAUDE_PROJECT_DIR` (establecido una vez por sesión por Claude Code), con respaldo al directorio de trabajo actual de la sesión cuando esa variable no está definida. Usar la raíz del proyecto en lugar del `cwd` activo garantiza que el límite permanezca estable incluso después de que Claude haga `cd` a un subdirectorio. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Prefijos de rutas absolutas permitidos aunque estén fuera de la raíz del proyecto. | +| `allowPaths` | `string[]` | `[]` | Prefijos de rutas absolutas que están permitidos aunque estén fuera de la raíz del proyecto. | **Ejemplo:** @@ -457,11 +457,11 @@ Mantiene a los agentes dentro de los límites del proyecto y alejados de archivo ### `block-secrets-write` **Evento:** PreToolUse (Write, Edit) -**Comportamiento por defecto:** Deniega escrituras en archivos comúnmente utilizados para claves privadas y certificados: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Por defecto:** Deniega escrituras en archivos comúnmente usados para claves privadas y certificados: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| | `additionalPatterns` | `string[]` | `[]` | Patrones de nombre de archivo adicionales (estilo glob) a bloquear. | @@ -481,16 +481,16 @@ Mantiene a los agentes dentro de los límites del proyecto y alejados de archivo ## Git -Previene pushes accidentales, force-pushes y errores de rama que son difíciles de deshacer. +Previene pushes accidentales, force-pushes y errores de rama difíciles de deshacer. ### `block-push-master` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega `git push origin main` y `git push origin master`. +**Por defecto:** Deniega `git push origin main` y `git push origin master`. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | Nombres de ramas a las que no se puede hacer push directamente. | @@ -507,7 +507,7 @@ Previene pushes accidentales, force-pushes y errores de rama que son difíciles ``` -Para permitir push a todas las ramas (deshabilitando efectivamente esta política sin eliminarla de `enabledPolicies`), establece `protectedBranches: []`. +Para permitir push a todas las ramas (desactivando efectivamente esta política sin eliminarla de `enabledPolicies`), establece `protectedBranches: []`. --- @@ -515,11 +515,11 @@ Para permitir push a todas las ramas (deshabilitando efectivamente esta polític ### `block-work-on-main` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega `git commit`, `git merge`, `git rebase` y `git cherry-pick` mientras el árbol de trabajo esté en `main` o `master`. La creación y el cambio de ramas (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) no se ven afectados. +**Por defecto:** Deniega `git commit`, `git merge`, `git rebase` y `git cherry-pick` mientras el árbol de trabajo está en `main` o `master`. La creación y cambio de ramas (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) no se ven afectados. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | Nombres de ramas en las que se deniega commit/merge/rebase/cherry-pick. | @@ -528,9 +528,9 @@ Para permitir push a todas las ramas (deshabilitando efectivamente esta polític ### `block-force-push` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Deniega `git push --force` y `git push -f`. +**Por defecto:** Deniega `git push --force` y `git push -f`. -Sin parámetros específicos de política. Usa el campo transversal [`hint`](/es/configuration#hint-cross-cutting) para sugerir alternativas: +Sin parámetros específicos de la política. Usa el [`hint`](/es/configuration#hint-cross-cutting) transversal para sugerir alternativas: ```json { @@ -547,7 +547,7 @@ Sin parámetros específicos de política. Usa el campo transversal [`hint`](/es ### `warn-git-amend` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a proceder con cautela al ejecutar `git commit --amend`. No bloquea el comando. +**Por defecto:** Instruye a Claude a proceder con cuidado al ejecutar `git commit --amend`. No bloquea el comando. Sin parámetros. @@ -556,7 +556,7 @@ Sin parámetros. ### `warn-git-stash-drop` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de ejecutar `git stash drop`. No bloquea el comando. +**Por defecto:** Instruye a Claude a confirmar antes de ejecutar `git stash drop`. No bloquea el comando. Sin parámetros. @@ -565,7 +565,7 @@ Sin parámetros. ### `warn-all-files-staged` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a revisar qué está añadiendo al área de stage cuando ejecuta `git add -A` o `git add .`. No bloquea el comando. +**Por defecto:** Instruye a Claude a revisar lo que está añadiendo al stage cuando ejecuta `git add -A` o `git add .`. No bloquea el comando. Sin parámetros. @@ -573,12 +573,12 @@ Sin parámetros. ## Base de datos -Intercepta operaciones SQL destructivas antes de que se ejecuten en tu base de datos. +Detecta operaciones SQL destructivas antes de que se ejecuten contra la base de datos. ### `warn-destructive-sql` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de ejecutar SQL que contenga `DROP TABLE`, `DROP DATABASE` o `DELETE` sin cláusula `WHERE`. +**Por defecto:** Instruye a Claude a confirmar antes de ejecutar SQL que contenga `DROP TABLE`, `DROP DATABASE` o `DELETE` sin cláusula `WHERE`. Sin parámetros. @@ -587,7 +587,7 @@ Sin parámetros. ### `warn-schema-alteration` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de ejecutar sentencias `ALTER TABLE`. +**Por defecto:** Instruye a Claude a confirmar antes de ejecutar sentencias `ALTER TABLE`. Sin parámetros. @@ -595,16 +595,16 @@ Sin parámetros. ## Advertencias -Proporciona a los agentes contexto adicional antes de operaciones potencialmente arriesgadas pero no destructivas. +Proporciona contexto adicional a los agentes antes de operaciones potencialmente arriesgadas pero no destructivas. ### `warn-large-file-write` **Evento:** PreToolUse (Write) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de escribir archivos de más de 1024 KB. +**Por defecto:** Instruye a Claude a confirmar antes de escribir archivos mayores de 1024 KB. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| | `thresholdKb` | `number` | `1024` | Umbral de tamaño de archivo en kilobytes a partir del cual se emite una advertencia. | @@ -629,7 +629,7 @@ El manejador de hooks impone un límite de 1 MB en stdin para los payloads. Para ### `warn-package-publish` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de ejecutar `npm publish`. +**Por defecto:** Instruye a Claude a confirmar antes de ejecutar `npm publish`. Sin parámetros. @@ -638,7 +638,7 @@ Sin parámetros. ### `warn-background-process` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a tener cuidado al lanzar procesos en segundo plano mediante `nohup`, `&`, `disown` o `screen`. +**Por defecto:** Instruye a Claude a ser cuidadoso al lanzar procesos en segundo plano mediante `nohup`, `&`, `disown` o `screen`. Sin parámetros. @@ -647,7 +647,7 @@ Sin parámetros. ### `warn-global-package-install` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Instruye a Claude a confirmar antes de ejecutar `npm install -g`, `yarn global add` o `pip install` sin un entorno virtual. +**Por defecto:** Instruye a Claude a confirmar antes de ejecutar `npm install -g`, `yarn global add` o `pip install` sin un entorno virtual. Sin parámetros. @@ -655,21 +655,21 @@ Sin parámetros. ## Gestores de paquetes -Impone qué gestores de paquetes puede utilizar el agente. +Controla qué gestores de paquetes puede usar el agente. ### `prefer-package-manager` **Evento:** PreToolUse (Bash) -**Comportamiento por defecto:** Desactivado. Cuando está habilitado, bloquea cualquier comando de gestor de paquetes que no esté en la lista `allowed` e indica a Claude que reescriba el comando usando un gestor permitido. +**Por defecto:** Deshabilitado. Cuando se habilita, bloquea cualquier comando de gestor de paquetes que no esté en la lista `allowed` e indica a Claude que reescriba el comando usando un gestor permitido. Detecta: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Nombres de gestores de paquetes permitidos. Cualquier gestor detectado que no esté en esta lista será bloqueado. Cuando está vacía, la política no tiene efecto. | +| `allowed` | string[] | `[]` | Nombres de gestores de paquetes permitidos. Cualquier gestor detectado que no esté en esta lista será bloqueado. Cuando está vacío, la política no hace nada. | | `blocked` | string[] | `[]` | Nombres de gestores adicionales a bloquear más allá de la lista integrada (p. ej. `['pdm', 'pipx']`). | -La lista de bloqueo integrada incluye: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Usa `blocked` para añadir gestores que no están en esta lista. +La lista de bloqueo integrada incluye: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Usa `blocked` para añadir gestores que no estén en esta lista. **Ejemplo de configuración:** @@ -689,14 +689,14 @@ Con esta configuración, tanto `pip install flask` como `pdm install flask` se d --- -## Comportamiento de la IA +## Comportamiento de IA -Detecta cuándo los agentes se quedan atascados o se comportan de forma inesperada. +Detecta cuándo los agentes se quedan bloqueados o se comportan de forma inesperada. ### `warn-repeated-tool-calls` **Evento:** PreToolUse (todas las herramientas) -**Comportamiento por defecto:** Instruye a Claude a reconsiderar cuando la misma herramienta se llama 3 o más veces con parámetros idénticos — señal habitual de que el agente está atrapado en un bucle. +**Por defecto:** Instruye a Claude a reconsiderar cuando la misma herramienta se llama 3 o más veces con parámetros idénticos, señal habitual de que el agente está atrapado en un bucle. Sin parámetros. @@ -704,40 +704,39 @@ Sin parámetros. ## Flujo de trabajo -Impone un flujo de trabajo disciplinado al final de la sesión. Estas políticas se activan en el evento **Stop** y deniegan al agente detenerse hasta que se cumpla cada condición. Siguen una cadena de dependencias natural: commit → push → PR → CI. Si una política deniega, las políticas posteriores en la cadena se omiten (la denegación cortocircuita la cadena). +Impone un flujo de trabajo disciplinado al final de la sesión. Estas políticas se activan en el evento **Stop** y bloquean al agente para que no se detenga hasta que se cumplan todas las condiciones. Siguen una cadena de dependencias natural: commit → push → PR → CI. Si una política deniega, las políticas posteriores de la cadena se omiten (la denegación provoca un cortocircuito). -Todas las políticas de flujo de trabajo son **fail-open**: si la herramienta requerida no está disponible (p. ej. `gh` no está instalado, no hay remote de git), la política permite con un mensaje informativo explicando por qué se omitió la comprobación. +Todas las políticas de flujo de trabajo son **fail-open**: si la herramienta requerida no está disponible (p. ej. `gh` no instalado, sin remote de git), la política permite con un mensaje informativo que explica por qué se omitió la comprobación. ### Semántica de Stop por CLI -La aplicación del Stop se ve ligeramente diferente entre los siete CLIs compatibles porque cada uno expone un contrato de hook distinto para "el agente ha terminado". El **resultado** es el mismo — el agente no puede detenerse mientras una condición de flujo de trabajo esté fallando — pero los **mecanismos** difieren. La tabla a continuación resume esto; solo Pi tiene un comportamiento visible para el usuario que vale la pena entender antes de habilitar una política `require-*-before-stop`. +La aplicación de Stop funciona de forma ligeramente diferente en cada uno de los seis CLIs compatibles, porque cada uno expone un contrato de hook distinto para "el agente ha terminado". El **resultado** es el mismo — el agente no puede detenerse mientras un control de flujo de trabajo falla — pero la **mecánica** difiere. La tabla siguiente lo resume; solo Pi tiene una particularidad visible para el usuario que conviene entender antes de habilitar una política `require-*-before-stop`. -| CLI | Cuándo se activa la condición | Lo que ves | +| CLI | Cuándo se activa el control | Qué verás | |---|---|---| -| Claude Code | En el mismo bucle del agente, inmediatamente | Claude continúa trabajando — soluciona el problema y luego intenta terminar de nuevo. No hay interrupción visible para ti. | -| Codex | En el mismo bucle del agente, inmediatamente | Igual que Claude. | -| GitHub Copilot CLI | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal de reintento `{decision:"block", reason}` de Copilot — verificado empíricamente contra Copilot CLI 1.0.41). | -| Cursor Agent | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal `{followup_message}` de Cursor — limitado a `loop_limit`, por defecto 5 reintentos). | -| Gemini CLI | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa el canal `{decision:"block", reason}` de Gemini en `AfterAgent`). | -| OpenCode | En el mismo bucle del agente, inmediatamente | Igual que Claude (usa la llamada SDK `client.session.prompt(...)` de OpenCode enrutada a través de `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **En el siguiente turno del usuario** | **Pi se detiene visiblemente** cuando se activa la condición — su bucle de agente termina y se te devuelve el prompt. La condición se activa la próxima vez que envíes un prompt: failproofai antepone una directiva `MANDATORY ACTION REQUIRED` al system prompt de ese turno, instruyendo al LLM a completar el paso del flujo de trabajo (commit, push, etc.) antes de hacer lo que pediste. | +| Claude Code | En el mismo bucle del agente, de inmediato | Claude sigue trabajando — resuelve el problema y luego intenta terminar de nuevo. Sin interrupciones visibles. | +| Codex | En el mismo bucle del agente, de inmediato | Igual que Claude. | +| GitHub Copilot CLI | En el mismo bucle del agente, de inmediato | Igual que Claude (usa el canal de reintento `{decision:"block", reason}` de Copilot — verificado empíricamente contra Copilot CLI 1.0.41). | +| Cursor Agent | En el mismo bucle del agente, de inmediato | Igual que Claude (usa el canal `{followup_message}` de Cursor — limitado a `loop_limit`, 5 reintentos por defecto). | +| OpenCode | En el mismo bucle del agente, de inmediato | Igual que Claude (usa la llamada SDK `client.session.prompt(...)` de OpenCode enrutada a través de `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **En el siguiente turno del usuario** | **Pi se detiene visiblemente** cuando el control se activa — su bucle de agente termina y vuelves al prompt. El control se activa la próxima vez que envíes un prompt: failproofai antepone una directiva `MANDATORY ACTION REQUIRED` al system prompt de ese turno, instruyendo al LLM a completar el paso de flujo de trabajo (commit, push, etc.) antes de hacer lo que pediste. | -**Limitación de Pi.** El `AgentEndEvent` de Pi (el equivalente upstream del hook `Stop` de Claude) no tiene tipo Result — para cuando se activa, el bucle del agente de Pi ya ha terminado. Pi no puede ser forzado a reintentar el mismo bucle como Claude / Copilot / Cursor / Gemini / OpenCode. failproofai traslada la condición al evento `before_agent_start` de Pi (que se activa después del siguiente prompt del usuario) para que la comprobación del flujo de trabajo siga siendo efectiva, solo en el siguiente turno en lugar del actual. +**Limitación de Pi.** El `AgentEndEvent` de Pi (equivalente al hook `Stop` de Claude) no tiene tipo Result — en el momento en que se activa, el bucle de agente de Pi ya ha terminado. Pi no puede ser forzado a reintentar el mismo bucle como Claude / Copilot / Cursor / OpenCode. failproofai desplaza el control al evento `before_agent_start` de Pi (que se activa tras el siguiente prompt del usuario) para que la comprobación de flujo de trabajo siga aplicándose, solo en el siguiente turno en lugar del actual. -**Lo que esto significa en la práctica:** +**Qué significa esto en la práctica:** -- Después de que Pi se detenga, el motivo de la denegación se captura en memoria indexado por el id de sesión de Pi. El siguiente prompt que envíes en el mismo proceso de Pi lo drena: el LLM ve la directiva `MANDATORY ACTION REQUIRED` al inicio de su system prompt, hace el commit (o push / abre el PR / espera a CI), y solo entonces continúa con tu solicitud. El motivo de denegación capturado es de un solo uso — una vez drenado, la condición queda libre. -- La condición está limitada por el tiempo de vida del proceso de Pi. Si haces `Ctrl+C` en Pi o sales entre turnos, la entrada en memoria se descarta junto con el proceso y la condición se pierde. Claude, Copilot, Cursor, Gemini y OpenCode tienen el mismo límite (matar el agente hace que se pierda la condición) — Pi simplemente lo hace más visible porque el agente termina visiblemente antes de que se active la condición. -- Una denegación pendiente también se limpia en `session_shutdown` por cualquier motivo (`new` / `resume` / `fork` / `quit`), de modo que una condición obsoleta de una sesión anterior no puede filtrarse a una sesión nueva iniciada en el mismo proceso de Pi. +- Cuando Pi se detiene, la razón de denegación se captura en memoria indexada por el id de sesión de Pi. El siguiente prompt que envíes en el mismo proceso de Pi lo consume: el LLM ve la directiva `MANDATORY ACTION REQUIRED` al inicio de su system prompt, hace el commit (o el push / abre el PR / espera al CI) y solo entonces continúa con tu solicitud. La razón de denegación capturada es de un solo uso — una vez consumida, el control queda libre. +- El control está acotado al tiempo de vida del proceso de Pi. Si haces `Ctrl+C` a Pi o sales entre turnos, la entrada en memoria se descarta junto con el proceso y el control se pierde. Claude, Copilot, Cursor y OpenCode tienen el mismo límite (matar el agente implica perder el control) — Pi simplemente lo hace más visible porque el agente termina de forma visible antes de que el control se active. +- Una denegación pendiente también se limpia en `session_shutdown` por cualquier motivo (`new` / `resume` / `fork` / `quit`), por lo que un control obsoleto de una sesión anterior no puede filtrarse a una sesión nueva iniciada en el mismo proceso de Pi. -Si necesitas el reintento en el mismo bucle al estilo Claude, ejecuta tus políticas de `Stop` bajo cualquiera de los otros seis CLIs compatibles. Estamos siguiendo Pi upstream para un futuro tipo Result en `AgentEndEvent` que nos permitiría cerrar esta brecha. +Si necesitas el reintento en el mismo bucle al estilo de Claude, ejecuta tus políticas `Stop` con cualquiera de los otros cinco CLIs compatibles. Estamos siguiendo el desarrollo de Pi para un futuro tipo Result en `AgentEndEvent` que permitiría cerrar esta brecha. ### `require-commit-before-stop` **Evento:** Stop -**Comportamiento por defecto:** Deniega la detención cuando hay cambios sin confirmar (archivos modificados, en stage o sin seguimiento). Devuelve un mensaje informativo cuando el directorio de trabajo está limpio. +**Por defecto:** Deniega la detención cuando hay cambios sin commit (archivos modificados, en stage o sin seguimiento). Devuelve un mensaje informativo cuando el directorio de trabajo está limpio. Sin parámetros. @@ -746,11 +745,11 @@ Sin parámetros. ### `require-push-before-stop` **Evento:** Stop -**Comportamiento por defecto:** Deniega la detención cuando hay commits sin subir o cuando la rama actual no tiene una rama de seguimiento remota. Sugiere `git push -u` para crear una rama de seguimiento si es necesario. Falla de forma abierta si no hay remote configurado. +**Por defecto:** Deniega la detención cuando hay commits sin push o cuando la rama actual no tiene rama de seguimiento remota. Sugiere `git push -u` para crear una rama de seguimiento si es necesario. Falla de forma abierta si no hay remote configurado. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| | `remote` | `string` | `"origin"` | Nombre del remote al que hacer push. | @@ -771,12 +770,12 @@ Sin parámetros. ### `require-pr-before-stop` **Evento:** Stop -**Comportamiento por defecto:** Deniega la detención cuando no existe un pull request para la rama actual, o cuando el PR existente está cerrado sin haberse fusionado. Instruye a Claude a crear un PR con `gh pr create`. Cuando el PR está **fusionado**, la política lo permite (el trabajo está publicado) y el mensaje sugiere cambiar de la rama (`git checkout main && git pull`). +**Por defecto:** Deniega la detención cuando no existe ningún pull request para la rama actual, o cuando el PR existente está cerrado sin fusionar. Indica a Claude que cree un PR con `gh pr create`. Cuando el PR está **fusionado**, la política permite (el trabajo se ha publicado) y el mensaje sugiere salir de la rama (`git checkout main && git pull`). Sin parámetros. -Esta política requiere que el [CLI de GitHub](https://cli.github.com/) (`gh`) esté instalado y autenticado. +Esta política requiere tener instalado y autenticado el [GitHub CLI](https://cli.github.com/) (`gh`). Ejecuta `gh auth login` con un token de acceso personal que tenga el scope `repo` para acceso de lectura a pull requests. Si `gh` no está instalado o no está autenticado, la política falla de forma abierta e informa del motivo a Claude. @@ -786,24 +785,24 @@ pull requests. Si `gh` no está instalado o no está autenticado, la política f ### `require-no-conflicts-before-stop` **Evento:** Stop -**Comportamiento por defecto:** Deniega la detención cuando la rama actual no puede fusionarse limpiamente con la rama base. La política primero confirma que existe un PR `OPEN` en GitHub para la rama — sin uno, no hay un destino de fusión que aplicar, por lo que toda la política cortocircuita a allow. Una vez confirmado un PR `OPEN`, se ejecutan dos comprobaciones independientes: +**Por defecto:** Deniega la detención cuando la rama actual no puede fusionarse limpiamente en la rama base. La política primero confirma que existe un PR `OPEN` en GitHub para la rama — sin uno, no hay destino de fusión que aplicar, por lo que toda la política cortocircuita a allow. Una vez confirmado el PR `OPEN`, se ejecutan dos comprobaciones independientes: -1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. En caso de conflicto, el mensaje de denegación nombra los archivos conflictivos para que Claude sepa exactamente qué resolver. -2. **GitHub** — reutiliza el resultado de `gh pr view --json mergeable,state` ya obtenido en la precomprobación. Detecta conflictos que un `origin/` local obsoleto podría pasar por alto (p. ej. alguien fusionó un PR conflictivo en `main` desde el último fetch). Un resultado `CONFLICTING` deniega. Un resultado `UNKNOWN` también deniega e instruye a Claude a esperar ~10 segundos y volver a comprobar antes de intentar detenerse de nuevo — esto previene falsos negativos mientras GitHub recalcula. +1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. En caso de conflicto, el mensaje de denegación nombra los archivos en conflicto para que Claude sepa exactamente qué resolver. +2. **GitHub** — reutiliza el resultado de `gh pr view --json mergeable,state` ya obtenido en la comprobación previa. Detecta conflictos que un `origin/` local desactualizado podría omitir (p. ej. si alguien publicó un PR conflictivo en `main` desde el último fetch). Un resultado `CONFLICTING` deniega. Un resultado `UNKNOWN` también deniega e instruye a Claude a esperar ~10 segundos y volver a comprobar antes de intentar detenerse — esto evita falsos negativos mientras GitHub recalcula. -Se omite completamente (permite) cuando: `gh` no está instalado, no existe PR para la rama, el estado del PR no es `OPEN` (p. ej. `MERGED`, `CLOSED`), o `gh pr view` devuelve una salida no parseable. También falla de forma abierta cuando `origin/` falta localmente o cuando no hay commits por delante de la base — esos fallbacks de Capa 1 aún consultan la fusionabilidad del PR en caché antes de permitir. +Se omite por completo (permite) cuando: `gh` no está instalado, no existe PR para la rama, el estado del PR no es `OPEN` (p. ej. `MERGED`, `CLOSED`), o `gh pr view` devuelve una salida no parseable. También falla de forma abierta cuando `origin/` no existe localmente o cuando no hay commits por delante de la base — esos casos de fallthrough de Capa 1 aún consultan la fusionabilidad del PR en caché antes de permitir. **Parámetros:** -| Parámetro | Tipo | Valor por defecto | Descripción | +| Parámetro | Tipo | Por defecto | Descripción | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Rama base contra la que comprobar los conflictos. | +| `baseBranch` | `string` | `"main"` | Rama base contra la que comprobar conflictos. | -El CLI de GitHub (`gh`) es necesario para esta política. La política usa `gh pr view` para confirmar +Esta política requiere el GitHub CLI (`gh`). La política usa `gh pr view` para confirmar que existe un PR `OPEN` antes de ejecutar cualquier comprobación de conflictos — sin `gh`, la política -cortocircuita a allow. Ejecuta `gh auth login` con un token de acceso personal que tenga el scope `repo` -para acceso de lectura a pull requests. +cortocircuita a allow. Ejecuta `gh auth login` con un token de acceso personal que tenga +el scope `repo` para acceso de lectura a pull requests. --- @@ -811,23 +810,23 @@ para acceso de lectura a pull requests. ### `require-ci-green-before-stop` **Evento:** Stop -**Comportamiento por defecto:** Deniega la detención cuando las comprobaciones de CI están fallando o aún en ejecución en la rama actual. Comprueba tanto los workflow runs de GitHub Actions como las comprobaciones de bots de terceros (p. ej. CodeRabbit, SonarCloud, Codecov). Trata las conclusiones `skipped`, `cancelled` y `neutral` como no fallidas (esta última cubre, por ejemplo, alertas de Socket Security en PRs de colaboradores externos, donde la aplicación intencionalmente reporta neutral en lugar de success/failure). Devuelve un mensaje informativo cuando todas las comprobaciones pasan. +**Por defecto:** Deniega la detención cuando las comprobaciones de CI están fallando o aún en ejecución en la rama actual. Comprueba tanto las ejecuciones de flujo de trabajo de GitHub Actions como las comprobaciones de bots de terceros (p. ej. CodeRabbit, SonarCloud, Codecov). Trata las conclusiones `skipped`, `cancelled` y `neutral` como no fallidas (esto último cubre p. ej. alertas de Socket Security en PRs de colaboradores externos, donde la aplicación reporta neutral intencionadamente en lugar de éxito/fallo). Devuelve un mensaje informativo cuando todas las comprobaciones pasan. Sin parámetros. -Esta política requiere que el [CLI de GitHub](https://cli.github.com/) (`gh`) esté instalado y autenticado. +Esta política requiere tener instalado y autenticado el [GitHub CLI](https://cli.github.com/) (`gh`). Ejecuta `gh auth login` con un token de acceso personal que tenga el scope `repo` para acceso de lectura a -workflow runs de Actions y la API de Checks. Si `gh` no está instalado o no está autenticado, la política falla de forma abierta e informa del motivo a Claude. +las ejecuciones de flujo de trabajo de Actions y la API de Checks. Si `gh` no está instalado o no está autenticado, la política falla de forma abierta e informa del motivo a Claude. --- --- -## Desactivar políticas individuales +## Deshabilitar políticas individuales -Elimina una política específica de `enabledPolicies` en tu configuración, o desactívala desde la pestaña Policies del dashboard. +Elimina una política específica de `enabledPolicies` en tu configuración, o desactívala en la pestaña Políticas del panel de control. ```json { @@ -838,4 +837,4 @@ Elimina una política específica de `enabledPolicies` en tu configuración, o d } ``` -Las políticas que no aparecen en `enabledPolicies` no se ejecutan, aunque existan entradas para ellas en `policyParams`. \ No newline at end of file +Las políticas que no aparecen en `enabledPolicies` no se ejecutan, aunque existan entradas en `policyParams` para ellas. \ No newline at end of file diff --git a/docs/es/cli/audit.mdx b/docs/es/cli/audit.mdx index 0694d437..a17e06eb 100644 --- a/docs/es/cli/audit.mdx +++ b/docs/es/cli/audit.mdx @@ -1,20 +1,22 @@ --- title: Auditar sesiones pasadas (beta) -description: "Cuenta con qué frecuencia el agente hizo cosas innecesarias o arriesgadas en transcripciones anteriores" +description: "Cuenta con qué frecuencia el agente realizó acciones innecesarias o arriesgadas en transcripciones anteriores" --- - **Función beta.** La auditoría se lanza en versión beta mientras recopilamos comentarios iniciales. - El catálogo de detectores y el formato del informe pueden cambiar antes del próximo corte estable. - Por favor, abre un issue si algo parece incorrecto. + **Función beta.** El auditor se lanza en beta mientras recopilamos comentarios iniciales. + El catálogo de detectores y el formato de los informes pueden cambiar antes del próximo lanzamiento estable. + Por favor, abre un issue si algo no parece correcto. -La auditoría reproduce tus transcripciones pasadas del agente CLI a través del motor de políticas de failproofai -y genera un informe visual y compartible en la **página del panel `/audit`** — el arquetipo de tu agente, una puntuación del 0 al 100, y exactamente qué políticas habrían detectado qué. +El auditor reproduce tus transcripciones anteriores del agente CLI a través del motor de políticas de failproofai +y genera un informe visual y compartible en la **página del panel `/audit`** — +el arquetipo de tu agente, una puntuación del 0 al 100, y exactamente qué políticas +habrían detectado qué comportamientos. -## Ejecutarla +## Ejecútalo -Tres formas de iniciarla — todas llevan al mismo informe `/audit`. +Tres formas de iniciarlo — todas llevan al mismo informe `/audit`. @@ -48,46 +50,47 @@ failproofai - Ejecuta `failproofai audit -h` (o `--help`) para ver el uso. La auditoría funciona **completamente - sin conexión** — no requiere cuenta ni red — y el panel sigue activo hasta que lo detengas con `Ctrl+C`. + Ejecuta `failproofai audit -h` (o `--help`) para ver el uso. El auditor funciona **completamente + sin conexión** — no se necesita cuenta ni red — y el panel sigue activo + hasta que lo detengas con `Ctrl+C`. -El panel analiza las transcripciones pasadas del agente CLI en esta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e informa con qué frecuencia el agente hizo cosas que failproofai está diseñado para detener — comprobaciones de variables de entorno, push forzados, prefijos `cd ` redundantes, bucles de sleep-polling, releer archivos recién editados y más. +El panel analiza las transcripciones pasadas del agente CLI en esta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e informa con qué frecuencia el agente hizo cosas que failproofai está diseñado para prevenir — comprobaciones de variables de entorno, force pushes, prefijos redundantes `cd `, bucles de polling con sleep, relectura de archivos recién editados, y más. -Por cada transcripción, cada evento de uso de herramienta se reproduce a través de las 39 políticas integradas **y** a través de 8 detectores exclusivos de auditoría que capturan patrones que aún no están cubiertos por las políticas en tiempo real. Los recuentos se agregan por política / detector en todas las sesiones. +Por cada transcripción, cada evento de uso de herramienta se reproduce a través de las 39 políticas integradas **y** a través de 8 detectores exclusivos del auditor que identifican patrones que aún no están cubiertos por las políticas en tiempo real. Los conteos se agregan por política/detector en todas las sesiones. ## Qué obtienes -La página `/audit` es un **póster** de pantalla única y compartible seguido de cuatro secciones debajo del pliegue: +La página `/audit` es un **póster** en pantalla completa y compartible, seguido de cuatro secciones debajo del pliegue: -1. **Póster** — la identidad de tu agente de un vistazo: su **arquetipo** (uno de 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), sus palabras clave de persona, cuán raro es ese arquetipo y una **puntuación del 0 al 100** con una banda de nivel (`S` hasta `bottom tier`). Diseñado para compartir — publícalo en X o LinkedIn, o descárgalo como PNG. -2. **`// strengths`** — lo que tu agente ya hace bien, con números reales del análisis (p. ej., % de llamadas a herramientas limpias, `0` intentos de push a main), mostrado solo donde la política relevante tiene un historial limpio. -3. **`// quirks`** — lo que se escapó: una tabla ordenada de comportamientos que failproofai habría detectado — *cuándo* ocurrió por última vez, *qué se escapó* (y el integrado que lo habría bloqueado), su *severidad* y con qué frecuencia fue *visto* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — la lista de correcciones recomendadas: una fila por política con un `failproofai policy add ` listo para copiar y pegar, más un botón **install all** que habilita todas las recomendaciones a la vez y muestra tu **puntuación proyectada** si lo hicieras. -5. **`// come back better`** — construye el hábito: configura un **recordatorio** por correo electrónico para volver a auditar (`3d` / `7d` / `14d` / `30d`) o vuelve a auditar ahora, e **invita a un amigo** a ejecutar su propia auditoría (enviado desde failproof.ai, con copia a ti). Los recordatorios e invitaciones requieren inicio de sesión — consulta [`failproofai auth`](/es/cli/auth). +1. **Póster** — la identidad de tu agente de un vistazo: su **arquetipo** (uno de 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), sus palabras clave de personalidad, qué tan raro es ese arquetipo, y una **puntuación del 0 al 100** con un nivel de banda (`S` hasta `bottom tier`). Diseñado para compartir — publícalo en X o LinkedIn, o descárgalo como PNG. +2. **`// strengths`** — lo que tu agente ya hace bien, con números reales del análisis (ej. % de llamadas a herramientas limpias, `0` intentos de push a main), mostrado solo donde la política relevante tiene un historial limpio. +3. **`// quirks`** — lo que se escapó: una tabla ordenada de comportamientos que failproofai habría detectado — *cuándo* ocurrió por última vez, *qué se escapó* (y el integrado que lo habría bloqueado), su *severidad*, y con qué frecuencia fue *visto* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — la lista de correcciones recomendadas: una fila por política con un `failproofai policy add ` listo para copiar y pegar, más un botón de **instalar todo** que activa cada recomendación de una vez y muestra tu **puntuación proyectada** si lo hicieras. +5. **`// come back better`** — crea el hábito: configura un **recordatorio** de re-auditoría por correo electrónico (`3d` / `7d` / `14d` / `30d`) o vuelve a auditar ahora, e **invita a un amigo** a ejecutar su propia auditoría (enviado desde failproof.ai, con copia a ti). Los recordatorios e invitaciones requieren iniciar sesión — consulta [`failproofai auth`](/es/cli/auth). -## Detectores exclusivos de auditoría +## Detectores exclusivos del auditor -Estos detectan patrones de "comportamiento ineficiente" que aún no se aplican en tiempo real. Solo se ejecutan durante la auditoría y nunca bloquean una llamada a herramienta en vivo. +Estos detectan patrones de comportamiento ineficiente que (todavía) no se aplican en tiempo real. Solo se ejecutan durante la auditoría y nunca bloquean una llamada de herramienta en vivo. | Detector | Qué cuenta | |---|---| -| `redundant-cd-cwd` | Comandos Bash que comienzan con `cd && …` aunque los comandos ya se ejecutan en `cwd`. | -| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` en un único archivo fuente — usa la herramienta `Read`. | -| `prefer-edit-over-sed-awk` | Ediciones en sitio con `sed -i` / `awk … > file` — usa la herramienta `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / `echo > file` multilínea para escribir archivos — usa la herramienta `Write`. | +| `redundant-cd-cwd` | Comandos Bash que empiezan con `cd && …` aunque los comandos ya se ejecutan en `cwd`. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` sobre un único archivo fuente — usar la herramienta `Read`. | +| `prefer-edit-over-sed-awk` | Ediciones en línea con `sed -i` / `awk … > file` — usar la herramienta `Edit`. | +| `prefer-write-over-heredoc` | Escritura de archivos con heredoc / `echo > file` multilínea — usar la herramienta `Write`. | | `sleep-polling-loop` | `sleep N` largo (≥ 30s) o bucles de polling `while …; sleep …; done`. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — delimita el alcance a `cwd`. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, omitiendo los hooks. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — limitar el ámbito a `cwd`. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, saltándose los hooks. | | `reread-after-edit` | `Read` de un archivo que acaba de ser modificado con `Edit`/`Write` en la misma sesión. | ## Cachés -- **Caché por transcripción** en `~/.failproofai/cache/audit/.json` indexada por `(mtime, size, engineVersion, detectorVersion)` — se invalida automáticamente cuando cambia la transcripción o el código de políticas/detectores. Cada entrada también almacena una marca de tiempo `cachedAt` como **metadatos TTL** (no forma parte de la clave de caché); las entradas con más de **7 días** se rechazan en la lectura para que los resultados de larga duración no sobrevivan a la evolución de los detectores. -- **Caché del resultado completo** en `~/.failproofai/audit-dashboard.json` (modo 0600). Permite que el panel se renderice instantáneamente al navegar sin volver a ejecutar el análisis. También se rechaza al leer pasado el **TTL de 7 días** — `/audit` cae entonces a su estado vacío y solicita una nueva ejecución. Haz clic en `[ re-audit now ]` cerca de la parte inferior del informe para actualizar — la re-auditoría envía `noCache: true`, por lo que omite la caché por transcripción y vuelve a analizar cada transcripción en lugar de devolver el resultado en caché; la ejecución transmite el progreso mediante una barra superior fija y reemplaza el resultado al terminar con éxito (sin recarga de página; una re-auditoría fallida conserva el informe anterior). +- **Caché por transcripción** en `~/.failproofai/cache/audit/.json` indexada por `(mtime, size, engineVersion, detectorVersion)` — se invalida automáticamente cuando cambia la transcripción o el código de política/detector. Cada entrada también almacena una marca de tiempo `cachedAt` como **metadatos de TTL** (no forma parte de la clave de caché); las entradas de más de **7 días** se rechazan en la lectura para que los resultados de larga duración no sobrevivan a la evolución de los detectores. +- **Caché de resultado completo** en `~/.failproofai/audit-dashboard.json` (modo 0600). Permite que el panel se muestre instantáneamente al navegar sin volver a ejecutar el análisis. También se rechaza en la lectura pasado el **TTL de 7 días** — `/audit` entonces cae a su estado vacío y solicita una nueva ejecución. Haz clic en `[ re-audit now ]` cerca de la parte inferior del informe para actualizar — el re-auditor envía `noCache: true`, por lo que omite la caché por transcripción y vuelve a analizar cada transcripción en lugar de devolver el resultado en caché; la ejecución transmite el progreso mediante una franja fija en la parte superior e intercambia el resultado en el lugar al terminar correctamente (sin recarga de página; un re-auditor fallido conserva el informe anterior). ## Notas -- **Sin mutaciones.** La auditoría se reproduce en modo de solo lectura. `warn-repeated-tool-calls` se omite porque de lo contrario se modificaría su sidecar por sesión. -- **Políticas de flujo de trabajo omitidas.** Las políticas `require-*-before-stop` solo se activan en eventos `Stop` y ejecutan `execSync` contra el estado git en vivo — no tienen una interpretación significativa de tipo "qué habría pasado en 2025", por lo que no aparecen en los recuentos de auditoría. -- **Políticas personalizadas omitidas.** Los hooks personalizados proporcionados por el usuario no se reproducen (pueden haber cambiado desde la sesión original). \ No newline at end of file +- **Sin mutaciones.** El auditor se reproduce en modo de solo lectura. `warn-repeated-tool-calls` se omite porque de lo contrario su sidecar por sesión sería modificado. +- **Políticas de flujo de trabajo omitidas.** Las políticas `require-*-before-stop` solo se activan en eventos `Stop` y `execSync` contra el estado git activo — no tienen una interpretación significativa de "qué habría pasado en 2025", por lo que no aparecen en los conteos del auditor. +- **Políticas personalizadas omitidas.** Los hooks personalizados del usuario no se reproducen (pueden haber cambiado desde la sesión original). \ No newline at end of file diff --git a/docs/es/configuration.mdx b/docs/es/configuration.mdx index 591ada62..d55306a8 100644 --- a/docs/es/configuration.mdx +++ b/docs/es/configuration.mdx @@ -1,10 +1,10 @@ --- title: Configuración -description: "Formato de archivo de configuración, sistema de tres ámbitos y reglas de combinación" +description: "Formato del archivo de configuración, sistema de tres ámbitos y reglas de fusión" icon: gear --- -failproofai utiliza archivos de configuración JSON para controlar qué políticas están activas, cómo se comportan y desde dónde se cargan las políticas personalizadas. La configuración está diseñada para compartirse fácilmente con tu equipo: confírmala en tu repositorio y todos los desarrolladores tendrán la misma red de seguridad para el agente. +failproofai utiliza archivos de configuración JSON para controlar qué políticas están activas, cómo se comportan y desde dónde se cargan las políticas personalizadas. La configuración está diseñada para compartirse fácilmente con tu equipo: confírmala en tu repositorio y cada desarrollador tendrá la misma red de seguridad para agentes. --- @@ -15,12 +15,12 @@ Existen tres ámbitos de configuración, evaluados en orden de prioridad: | Ámbito | Ruta del archivo | Propósito | |--------|-----------------|-----------| | **project** | `.failproofai/policies-config.json` | Configuración por repositorio, confirmada en control de versiones | -| **local** | `.failproofai/policies-config.local.json` | Sobreescrituras personales por repositorio, ignoradas por git | -| **global** | `~/.failproofai/policies-config.json` | Valores predeterminados de usuario para todos los proyectos | +| **local** | `.failproofai/policies-config.local.json` | Sobrescrituras personales por repositorio, ignoradas por git | +| **global** | `~/.failproofai/policies-config.json` | Valores predeterminados a nivel de usuario para todos los proyectos | -Cuando failproofai recibe un evento de hook, carga y combina los tres archivos que existen para el directorio de trabajo actual. +Cuando failproofai recibe un evento de hook, carga y fusiona los tres archivos que existan para el directorio de trabajo actual. -### Reglas de combinación +### Reglas de fusión **`enabledPolicies`** — la unión de los tres ámbitos. Una política habilitada en cualquier nivel está activa. @@ -32,26 +32,26 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← unión sin duplicados ``` -**`policyParams`** — el primer ámbito que define parámetros para una política determinada gana por completo. No hay combinación profunda de valores dentro de los parámetros de una política. +**`policyParams`** — el primer ámbito que defina parámetros para una política determinada prevalece completamente. No se realiza una fusión profunda de valores dentro de los parámetros de una política. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project gana, global se ignora +resolved: { allowPatterns: ["sudo apt-get update"] } ← project prevalece, global se ignora ``` ```text -project: (sin entrada para block-sudo) -local: (sin entrada para block-sudo) +project: (sin entrada block-sudo) +local: (sin entrada block-sudo) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← se aplica global como respaldo +resolved: { allowPatterns: ["sudo systemctl status"] } ← cae hasta global ``` -**`customPoliciesPath`** — el primer ámbito que lo defina gana. +**`customPoliciesPath`** — el primer ámbito que lo defina prevalece. -**`llm`** — el primer ámbito que lo defina gana. +**`llm`** — el primer ámbito que lo defina prevalece. --- @@ -104,23 +104,23 @@ Tipo: `string[]` Lista de nombres de políticas a habilitar. Los nombres deben coincidir exactamente con los identificadores de política que muestra `failproofai policies`. Consulta [Políticas integradas](/es/built-in-policies) para ver la lista completa. -Las políticas que no están en `enabledPolicies` están inactivas, aunque tengan entradas en `policyParams`. +Las políticas que no estén en `enabledPolicies` están inactivas, aunque tengan entradas en `policyParams`. ### `policyParams` Tipo: `Record>` -Sobreescrituras de parámetros por política. La clave exterior es el nombre de la política; las claves internas son específicas de cada política. Cada política documenta sus parámetros disponibles en [Políticas integradas](/es/built-in-policies). +Sobrescrituras de parámetros por política. La clave externa es el nombre de la política; las claves internas son específicas de cada política. Cada política documenta sus parámetros disponibles en [Políticas integradas](/es/built-in-policies). -Si una política tiene parámetros pero no los especificas, se utilizan los valores predeterminados integrados de la política. Los usuarios que no configuran `policyParams` en absoluto obtienen un comportamiento idéntico al de versiones anteriores. +Si una política tiene parámetros pero no los especificas, se utilizan los valores predeterminados integrados de la política. Los usuarios que no configuren `policyParams` en absoluto obtendrán un comportamiento idéntico al de versiones anteriores. -Las claves desconocidas dentro del bloque de parámetros de una política se ignoran silenciosamente en el momento de la ejecución del hook, pero se marcan como advertencias cuando ejecutas `failproofai policies`. +Las claves desconocidas dentro del bloque de parámetros de una política se ignoran silenciosamente en el momento de ejecución del hook, pero se marcan como advertencias cuando ejecutas `failproofai policies`. #### `hint` (transversal) Tipo: `string` (opcional) -Un mensaje que se añade al motivo cuando una política devuelve `deny` o `instruct`. Úsalo para darle a Claude orientación accionable sin modificar la política en sí. +Un mensaje que se agrega al motivo cuando una política devuelve `deny` o `instruct`. Úsalo para dar a Claude orientación accionable sin modificar la política en sí. Funciona con cualquier tipo de política: integrada, personalizada (`custom/`), convención de proyecto (`.failproofai-project/`) o convención de usuario (`.failproofai-user/`). @@ -141,32 +141,32 @@ Funciona con cualquier tipo de política: integrada, personalizada (`custom/`), } ``` -Cuando `block-force-push` deniega, Claude ve: *"Se ha bloqueado el force-push. Try creating a fresh branch instead."* +Cuando `block-force-push` deniega, Claude ve: *"Force-pushing is blocked. Try creating a fresh branch instead."* -Los valores que no son cadenas de texto y las cadenas vacías se ignoran silenciosamente. Si no se define `hint`, el comportamiento no cambia (compatible con versiones anteriores). +Los valores que no sean cadenas de texto y las cadenas vacías se ignoran silenciosamente. Si `hint` no está definido, el comportamiento no cambia (compatible con versiones anteriores). ### `customPoliciesPath` Tipo: `string` (ruta absoluta) -Ruta a un archivo JavaScript que contiene políticas de hook personalizadas. Este valor lo establece automáticamente `failproofai policies --install --custom ` (la ruta se resuelve a absoluta antes de almacenarse). +Ruta a un archivo JavaScript que contiene políticas de hook personalizadas. Se establece automáticamente mediante `failproofai policies --install --custom ` (la ruta se resuelve a absoluta antes de almacenarse). -El archivo se carga de nuevo en cada evento de hook; no hay caché. Consulta [Políticas personalizadas](/es/custom-policies) para ver los detalles de creación. +El archivo se carga de nuevo en cada evento de hook, sin caché. Consulta [Políticas personalizadas](/es/custom-policies) para obtener detalles sobre cómo crearlas. -### Políticas basadas en convenciones +### Políticas basadas en convención Además del `customPoliciesPath` explícito, failproofai descubre y carga automáticamente archivos de políticas desde directorios `.failproofai/policies/`: | Nivel | Directorio | Ámbito | |-------|-----------|--------| | Proyecto | `.failproofai/policies/` | Compartido con el equipo mediante control de versiones | -| Usuario | `~/.failproofai/policies/` | Personal, se aplica a todos los proyectos | +| Usuario | `~/.failproofai/policies/` | Personal, aplica a todos los proyectos | -**Coincidencia de archivos:** Solo se cargan los archivos que coincidan con `*policies.{js,mjs,ts}` (p. ej., `security-policies.mjs`, `workflow-policies.js`). Los demás archivos del directorio se ignoran. +**Coincidencia de archivos:** Solo se cargan los archivos que coincidan con `*policies.{js,mjs,ts}` (por ejemplo, `security-policies.mjs`, `workflow-policies.js`). Los demás archivos del directorio se ignoran. -**Sin configuración necesaria:** Las políticas de convención no requieren entradas en `policies-config.json`. Simplemente coloca los archivos en el directorio y se detectarán en el próximo evento de hook. +**Sin configuración necesaria:** Las políticas por convención no requieren entradas en `policies-config.json`. Solo coloca los archivos en el directorio y se detectarán en el próximo evento de hook. -**Carga por unión:** Se analizan tanto el directorio de convenciones del proyecto como el del usuario. Se cargan todos los archivos coincidentes de ambos niveles (a diferencia de `customPoliciesPath`, que usa el primero que gana por ámbito). +**Carga por unión:** Se analizan tanto el directorio de convención del proyecto como el del usuario. Todos los archivos coincidentes de ambos niveles se cargan (a diferencia de `customPoliciesPath`, que usa el primer ámbito ganador). Consulta [Políticas personalizadas](/es/custom-policies) para más detalles y ejemplos. @@ -174,7 +174,7 @@ Consulta [Políticas personalizadas](/es/custom-policies) para más detalles y e Tipo: `object` (opcional) -Configuración del cliente LLM para políticas que realizan llamadas a IA. No es necesario en la mayoría de los casos. +Configuración del cliente LLM para políticas que realizan llamadas a IA. No es necesario en la mayoría de las configuraciones. ```json { @@ -189,20 +189,24 @@ Configuración del cliente LLM para políticas que realizan llamadas a IA. No es ## Gestión de la configuración desde la CLI -Los comandos `policies --install` y `policies --uninstall` escriben en el archivo de configuración de hooks de tu CLI de agente (los puntos de entrada del hook), mientras que `policies-config.json` es el archivo que gestionas directamente. Son dos cosas separadas: +Los comandos `policies --install` y `policies --uninstall` escriben en el archivo de configuración de hooks de tu agente CLI (los puntos de entrada del hook), mientras que `policies-config.json` es el archivo que gestionas directamente. Ambos son independientes: -- **Configuración de la CLI del agente** — indica al agente que llame a `failproofai --hook ` en cada uso de herramienta: +- **Configuración del agente CLI** — indica al agente que llame a `failproofai --hook ` en cada uso de herramienta: - **Claude Code**: `~/.claude/settings.json` (usuario), `/.claude/settings.json` (proyecto), `/.claude/settings.local.json` (local) - **OpenAI Codex**: `~/.codex/hooks.json` (usuario), `/.codex/hooks.json` (proyecto) — Codex no tiene ámbito `local` - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuario), `/.github/hooks/failproofai.json` (proyecto) — Copilot no tiene ámbito `local`. Las entradas de hook usan los campos de comando `bash`/`powershell` de Copilot según el sistema operativo con `timeoutSec`; el archivo lleva un marcador `version: 1` de nivel superior. El soporte de Copilot CLI está en **beta** mientras verificamos el esquema de registros `events.jsonl` (que la documentación pública no especifica) con más sesiones reales. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuario), `/.cursor/hooks.json` (proyecto) — Cursor no tiene ámbito `local`. Las entradas de hook usan la forma de Claude `{type, command, timeout}` (sin división `bash`/`powershell`), pero almacenadas bajo claves de evento en camelCase (`preToolUse`, `beforeSubmitPrompt`, …) en un array plano según el [esquema de hooks de Cursor](https://cursor.com/docs/hooks); el archivo lleva un marcador `version: 1` de nivel superior. El manejador canonicaliza camelCase → PascalCase mediante `CURSOR_EVENT_MAP`, de modo que las políticas integradas existentes se activan sin cambios. El soporte de Cursor Agent está en **beta** mientras verificamos el formato en disco de la transcripción de Cursor (no especificado en la documentación pública) con más instalaciones reales. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuario), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proyecto) — OpenCode no tiene ámbito `local`. A diferencia de las otras seis CLIs, OpenCode **no tiene un sistema de hooks de comandos externos**: carga plugins JS/TS en proceso registrados explícitamente mediante el array `plugin: []` en `opencode.json` (el autodescubrimiento desde `.opencode/plugins/` **no** es cómo se cargan los plugins en opencode v1.14.33). La instalación coloca un pequeño shim de plugin generado que llama al binario failproofai como subproceso y traduce la respuesta JSON de forma Claude del binario de vuelta a la semántica del plugin: `throw new Error()` para denegar eventos de herramienta (cancela la llamada a la herramienta), `client.session.prompt(...)` para instruct Y para `Stop` / `SubagentStop` deny (envía el motivo de denegación como el siguiente mensaje del usuario — el único canal de reintento forzado, ya que `session.idle` es solo notificación y lanzar desde él es un no-op), y no-op para allow. El shim canonicaliza tanto los nombres de herramientas (minúsculas → PascalCase mediante `OPENCODE_TOOL_MAP`) como las claves de argumentos de entrada de herramientas (camelCase → snake_case mediante `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, p. ej. `filePath` → `file_path`, `oldString` → `old_string`) antes de reenviar al binario, de modo que las políticas integradas de verificación de rutas como `block-read-outside-cwd`, `block-env-files` y `block-secrets-write` se activan sin cambios en las llamadas a herramientas de OpenCode. Las sesiones viven en la base de datos SQLite de opencode en `~/.local/share/opencode/opencode.db`; el visor de sesiones del panel las lee mediante `opencode db --format json` y `opencode export `. El soporte de OpenCode está en **beta** mientras verificamos el comportamiento en distintas versiones y con más sesiones reales. Consulta la [documentación de plugins de OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuario), `/.pi/settings.json` (proyecto) — Pi no tiene ámbito `local`. Pi carga paquetes de extensiones TypeScript al inicio; el archivo de configuración es un array de cadenas plano `{"packages": ["./relative/path", …]}`. failproofai escribe una única entrada en el array de packages apuntando a su directorio `pi-extension/` integrado. La extensión se suscribe internamente a los eventos `tool_call` / `user_bash` / `input` / `session_start` de Pi y ejecuta `failproofai --hook --cli pi` como proceso hijo; el manejador canonicaliza eventos de snake_case en minúsculas → PascalCase mediante `PI_EVENT_MAP` para que las políticas integradas existentes se activen sin cambios. Los argumentos de entrada de herramientas también se canonizan mediante `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit entregan `path` en lugar de `file_path`; mapear la clave de nivel superior permite que `block-env-files` y `block-secrets-write` se activen — `block-read-outside-cwd` ya tenía un respaldo con `path`). El soporte de Pi está en **beta** mientras la API de extensiones de Pi y el diseño del registro de sesiones se estabilizan. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (usuario), `/.gemini/settings.json` (proyecto) — Gemini no tiene ámbito `local` (documenta un ámbito `system` en `/etc/gemini-cli/settings.json` que failproofai no expone). Las entradas de hook usan la forma de Claude `{type, command, timeout}` envuelta en el esquema de matcher de Gemini `{matcher, hooks: [...]}` con `matcher: "*"` por defecto. Los eventos están en PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); el manejador los mapea a nombres canónicos de Claude mediante `GEMINI_EVENT_MAP`. Los nombres de herramientas están en snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — el manejador los canonicaliza mediante `GEMINI_TOOL_MAP` para que las políticas integradas existentes se activen sin cambios. El evaluador de políticas emite la forma plana de Gemini `{decision: "deny", reason}` (preferida según el contrato exit-0 de la "Regla de Oro" de Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` para inyección de contexto en BeforeAgent / AfterTool / SessionStart, y `{decision: "block", reason}` en AfterAgent para semántica de reintento forzado. El soporte de Gemini CLI está en **beta** mientras ampliamos la cobertura en el mundo real. Consulta la [documentación de hooks de Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**solo ámbito de usuario** — Hermes no tiene configuración de proyecto/local). Hermes es una **pasarela** de Slack/Telegram, por lo que una instalación intercepta las llamadas a herramientas de todas las plataformas (Slack/Telegram/cli/cron) **y** de los subagentes internos. Las entradas de hook son un par `{command, timeout}` (tiempo de espera en **segundos**) bajo un mapa `hooks:` indexado por los eventos snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); el manejador canonicaliza los eventos mediante `HERMES_EVENT_MAP` y los nombres de herramientas mediante `HERMES_TOOL_MAP` para que las políticas integradas se activen sin cambios. La configuración se edita mediante un round-trip YAML `Document` que preserva los comentarios, de modo que los demás ajustes del operador sobreviven, y la instalación establece `hooks_auto_accept: true` para que la pasarela sin cabeza (sin TTY) ejecute los hooks sin solicitud de consentimiento. El evaluador emite el contrato stdout `{"decision":"block","reason"}` de Hermes (Hermes ignora los códigos de salida). **Limitaciones:** Hermes no tiene un evento `Stop` de fin de turno, por lo que las políticas integradas `require-*-before-stop` nunca se activan para él (no aplicable, no roto); `instruct` degrada a allow con nota registrada (sin canal de contexto adicional); y la redacción de secretos en la salida (`sanitize-*`) no puede reescribir la salida de herramientas a través del contrato de hook de shell. Hermes es también una fuente de **auditoría** sin conexión — el panel lee sus sesiones de pasarela directamente desde `~/.hermes/state.db`. -- **`policies-config.json`** — indica a failproofai qué políticas evaluar y con qué parámetros (compartido entre todas las CLIs de agentes) - -Pasa `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` para apuntar a un agente específico (separados por espacios o repetidos para cualquier subconjunto): + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuario), `/.github/hooks/failproofai.json` (proyecto) — Copilot no tiene ámbito `local`. Las entradas de hook usan los campos de comando `bash`/`powershell` con clave de SO de Copilot con `timeoutSec`; el archivo incluye un marcador de nivel superior `version: 1`. El soporte de Copilot CLI está en **beta** mientras verificamos el esquema de registros `events.jsonl` (que la documentación pública no especifica) contra más sesiones del mundo real. **VS Code Copilot Chat en modo agente (Preview)** lee configuraciones de hook desde `.github/hooks/*.json`, `~/.copilot/hooks/*.json` y `~/.claude/settings.json` (gobernado por la configuración `chat.hookFilesLocations`) usando el mismo contrato de forma Claude `{hookSpecificOutput:{permissionDecision:"deny",…}}` — exactamente las rutas que esta integración `copilot` y la integración `claude` (`~/.claude/settings.json`) ya escriben, por lo que `failproofai policies --install --cli copilot` (o `--cli claude`) **ya aplica en el modo agente de VS Code** sin necesidad de una integración `vscode` separada (confirmado en vivo desde los registros de descubrimiento de VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuario), `/.cursor/hooks.json` (proyecto) — Cursor no tiene ámbito `local`. Las entradas de hook usan la forma Claude `{type, command, timeout}` (sin división `bash`/`powershell`), pero almacenadas bajo claves de evento en camelCase (`preToolUse`, `beforeSubmitPrompt`, …) en un array plano según el [esquema de hooks](https://cursor.com/docs/hooks) de Cursor; el archivo incluye un marcador de nivel superior `version: 1`. El handler canonicaliza camelCase → PascalCase mediante `CURSOR_EVENT_MAP`, por lo que las políticas integradas existentes se ejecutan sin cambios. El soporte de Cursor Agent está en **beta** mientras verificamos el formato de transcripción en disco de Cursor (no especificado en la documentación pública) contra más instalaciones del mundo real. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuario), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proyecto) — OpenCode no tiene ámbito `local`. A diferencia de los otros cinco CLI, OpenCode **no tiene un sistema de hooks de comandos externos**: carga plugins JS/TS en proceso registrados explícitamente a través del array `plugin: []` en `opencode.json` (el autodescubrimiento desde `.opencode/plugins/` **no** es cómo se cargan los plugins en opencode v1.14.33). La instalación deposita un pequeño shim de plugin generado que llama al binario failproofai como subproceso y traduce la respuesta JSON de forma Claude del binario de vuelta a semántica de plugin: `throw new Error()` para denegar eventos de herramienta (cancela la llamada a la herramienta), `client.session.prompt(...)` para instruct Y para `Stop` / `SubagentStop` deny (envía el motivo de denegación como el siguiente mensaje de usuario — el único canal de reintento forzado ya que `session.idle` es solo de notificación y lanzar desde él es una no operación), y no-op para allow. El shim canonicaliza tanto los nombres de herramientas (minúsculas → PascalCase mediante `OPENCODE_TOOL_MAP`) como las claves de argumentos de entrada de herramientas (camelCase → snake_case mediante `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, p. ej. `filePath` → `file_path`, `oldString` → `old_string`) antes de reenviar al binario, por lo que las políticas integradas de verificación de rutas como `block-read-outside-cwd`, `block-env-files` y `block-secrets-write` se ejecutan sin cambios en las llamadas a herramientas de OpenCode. Las sesiones viven en la base de datos SQLite de opencode en `~/.local/share/opencode/opencode.db`; el visor de sesiones del panel las lee mediante `opencode db --format json` y `opencode export `. El soporte de OpenCode está en **beta** mientras verificamos el comportamiento en distintas versiones y contra más sesiones del mundo real. Consulta la [documentación de plugins de OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuario), `/.pi/settings.json` (proyecto) — Pi no tiene ámbito `local`. Pi carga paquetes de extensión TypeScript al inicio; el archivo de configuración es un array plano de cadenas `{"packages": ["./relative/path", …]}`. failproofai escribe una sola entrada en el array de paquetes apuntando a su directorio `pi-extension/` incluido. La extensión se suscribe internamente a los eventos `tool_call` / `user_bash` / `input` / `session_start` de Pi y llama al subproceso `failproofai --hook --cli pi`; el handler canonicaliza underscore_lower_snake_case → PascalCase mediante `PI_EVENT_MAP`, por lo que las políticas integradas existentes se ejecutan sin cambios. Los argumentos de entrada de herramientas también se canonizan mediante `PI_TOOL_INPUT_MAP` (Read / Write / Edit de Pi entregan `path` en lugar de `file_path`; mapear la clave de nivel superior permite que `block-env-files` y `block-secrets-write` se ejecuten — `block-read-outside-cwd` ya tenía un fallback de `path`). El soporte de Pi está en **beta** mientras la API de extensiones de Pi y el diseño de los registros de sesión se estabilizan. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**solo ámbito de usuario** — Hermes no tiene configuración de proyecto/local). Hermes es una **pasarela** de Slack/Telegram, por lo que una sola instalación intercepta las llamadas a herramientas de cada plataforma (Slack/Telegram/cli/cron) **y** los subagentes internos. Las entradas de hook son un par `{command, timeout}` (timeout en **segundos**) bajo un mapa `hooks:` con clave por los eventos snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); el handler canonicaliza los eventos mediante `HERMES_EVENT_MAP` y los nombres de herramientas mediante `HERMES_TOOL_MAP`, por lo que las políticas integradas se ejecutan sin cambios. La configuración se edita mediante un round-trip YAML `Document` que preserva comentarios para que la configuración del operador sobreviva, y la instalación establece `hooks_auto_accept: true` para que la pasarela sin cabeza (sin TTY) ejecute los hooks sin un aviso de consentimiento. El evaluador emite el contrato stdout `{"decision":"block","reason"}` de Hermes (Hermes ignora los códigos de salida). **Limitaciones:** Hermes no tiene un evento `Stop` de fin de turno, por lo que las políticas integradas `require-*-before-stop` nunca se ejecutan para él (no aplicable, no roto); `instruct` se degrada a allow con nota registrada (sin canal de contexto adicional); y la redacción de secretos en salida (`sanitize-*`) no puede reescribir la salida de herramientas sobre el contrato shell-hook. Hermes es **también** una fuente de **auditoría** sin conexión — el panel lee sus sesiones de pasarela directamente desde `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**solo ámbito de usuario** — OpenClaw no tiene configuración de proyecto/local). Al igual que Hermes, OpenClaw es una **pasarela** multicanal autoalojada, por lo que una sola instalación intercepta las llamadas a herramientas de cada canal y sus subagentes internos. La aplicación se ejecuta a través de los **hooks de plugin en proceso** de OpenClaw (sus hooks internos basados en archivos son solo de observación y no pueden bloquear), por lo que — como OpenCode/Pi — failproofai incluye un paquete estático `openclaw-plugin/` que lanza de forma asíncrona el binario failproofai y traduce el veredicto. La instalación registra el directorio de plugin incluido en `plugins.load.paths[]` de `openclaw.json` y lo habilita bajo `plugins.entries.failproofai` (con `hooks.allowConversationAccess: true`, requerido para los hooks de conversación sin procesar). El evaluador emite un veredicto plano `{permission, reason}` y el shim lo mapea a la forma de retorno nativa de cada hook: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), y `before_agent_finalize → {action:"revise", reason}` (**Stop** — una compuerta real de fin de turno, por lo que las políticas integradas `require-*-before-stop` **se aplican** en OpenClaw, a diferencia de Hermes). Los eventos y nombres de herramientas se canonizan en el lado del binario mediante `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …), por lo que las políticas integradas se ejecutan sin cambios; el shim falla de forma abierta ante cualquier error de lanzamiento/análisis/tiempo de espera. OpenClaw es **también** una fuente de **auditoría** sin conexión — el panel lee sus sesiones JSONL en `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (usuario), `/.factory/hooks.json` (proyecto) — Factory no tiene ámbito `local`. droid incluye un sistema de hooks de comandos externos de estilo Claude, pero con dos peculiaridades verificadas en vivo contra droid v0.171.0: (1) los nombres de eventos residen en el **nivel superior** de `hooks.json` — **no hay un envoltorio `"hooks"`** (droid lo rechaza); los eventos de herramienta (`PreToolUse`/`PostToolUse`) llevan `"matcher": "*"`, los eventos no relacionados con herramientas lo omiten. (2) La denegación se controla por el **código de salida 2 + stderr** del hook, no por una decisión JSON — la rama `factory` del evaluador devuelve la salida 2 para eventos de herramienta/prompt y `{decision:"block", reason}` solo en el evento `Stop` de fin de turno (el único canal de reintento forzado de droid). Los eventos ya están en PascalCase (sin mapa de eventos) y el payload es Claude snake_case; solo los nombres de herramientas se canonizan mediante `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory es **también** una fuente de **auditoría** sin conexión — el panel lee sus sesiones JSONL en disco en `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (usuario), `/.devin/config.json` (proyecto) — Devin no tiene ámbito `local`. Devin es un **clon puro de Claude** verificado en vivo contra devin v3000.1.27: usa el esquema estándar de envoltorio `"hooks"` de Claude (las escrituras preservan la fusión para que las otras claves del archivo de configuración — `org_id`, `theme_mode`, … — sobrevivan), nombres de eventos ya en PascalCase (sin mapa de eventos, sin rama de handler) y un payload stdin en snake_case de Claude (sin normalización). La rama `devin` del evaluador deniega con JSON `{"decision":"block","reason"}` en stdout con salida 0 para **cada** evento (verificado — el bloqueo anuló `--permission-mode dangerous`); en el evento `Stop` de fin de turno, el motivo lleva el texto de reintento forzado MANDATORY-ACTION para que las políticas integradas `require-*-before-stop` se apliquen. Solo los nombres de herramientas se canonizan mediante `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` ya es canónico). Devin es **también** una fuente de **auditoría** sin conexión — el panel lee sus sesiones SQLite en `~/.local/share/devin/cli/sessions.db` (cada fila de `sessions` lleva un `working_directory` real, por lo que las sesiones se agrupan por cwd del proyecto como Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (usuario), `/.agents/hooks.json` (proyecto) — Antigravity no tiene ámbito `local`. A diferencia de Factory/Devin, Antigravity tiene su **propio** contrato (no es un clon de Claude), verificado en vivo contra agy v1.1.2. `hooks.json` usa un esquema de **hook con nombre**: la clave de nivel superior es un *nombre* de hook (`"failproofai"`) cuyo valor es un mapa de evento→handlers — los eventos de herramienta (`PreToolUse`/`PostToolUse`) envuelven los handlers en `{matcher:"*", hooks:[…]}`, mientras que `PreInvocation`/`Stop` son arrays de handlers **planos** (se preservan otros hooks con nombre). El payload stdin es **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai lo normaliza a snake_case antes de ejecutar las políticas, y mapea los args en PascalCase de `run_command` (`CommandLine`/`Cwd`) mediante `ANTIGRAVITY_TOOL_INPUT_MAP`. La rama `antigravity` del evaluador usa las **propias** formas de respuesta de Antigravity: `{decision:"deny", reason}` bloquea una herramienta/prompt (salida 0), `{decision:"continue", reason}` en el `Stop` de fin de turno vuelve a entrar al bucle (por lo que las políticas integradas `require-*-before-stop` se aplican), y `{injectSteps:[{ephemeralMessage}]}` inyecta una instrucción en `PreInvocation` (→ `UserPromptSubmit`). Los nombres de herramientas se canonizan mediante `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity es **también** una fuente de **auditoría** sin conexión — el panel lee sus transcripciones JSONL planas en `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (índice de conversaciones en `conversation_summaries.db`). + - **Goose (nombre en clave goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (usuario), `/.agents/plugins/failproofai/hooks/hooks.json` (proyecto) — Goose no tiene ámbito `local`. La aplicación usa el sistema de **hooks** de Goose, la especificación **Open Plugins** para agentes cruzados: el instalador simplemente deposita el directorio del plugin `failproofai` y Goose lo autodescubre al inicio (registrándolo en `~/.config/goose/config.yaml`). El `hooks.json` usa un esquema Open Plugins **con** un envoltorio de nivel superior `"hooks"`, y el matcher se **omite** en cada evento — un `"*"` desnudo es una regex inválida que no coincide con nada (verificado en vivo contra goose v1.43.0). Los nombres de eventos ya están en PascalCase (sin mapa de eventos); el payload stdin usa `event`/`working_dir`, que el handler normaliza a `hook_event_name`/`cwd`. La rama `goose` del evaluador deniega con JSON `{"decision":"block","reason"}` en stdout con salida 0, respetado en el evento **`PreToolUse`** únicamente (incluido en goose ≥ v1.37.0) — que se activa tanto para la herramienta shell **como dentro de subagentes delegados**, por lo que es el único punto de denegación suficiente; cualquier otro error de hook falla de forma **abierta**. Goose **no tiene evento `Stop`**, por lo que las políticas integradas `require-*-before-stop` no aplican (como con Hermes). Los nombres de herramientas se canonizan mediante `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) y las claves de ruta mediante `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose es **también** una fuente de **auditoría** sin conexión — el panel lee sus sesiones SQLite en `~/.local/share/goose/sessions/sessions.db` (cada fila de `sessions` lleva un `working_dir` real, por lo que las sesiones se agrupan por cwd del proyecto como Devin; las ejecuciones de prueba con `--no-session` se filtran). +- **`policies-config.json`** — indica a failproofai qué políticas evaluar y con qué parámetros (compartido entre todos los agentes CLI) + +Pasa `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` para seleccionar un agente específico (separados por espacios o repetidos para cualquier subconjunto): ```bash failproofai policies --install --cli codex --scope project @@ -210,19 +214,23 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Cuando se omite `--cli`, `failproofai` detecta qué CLIs de agentes están instaladas (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Cuando se omite `--cli`, `failproofai` detecta qué agentes CLI están instalados (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Una CLI detectada** — la selecciona automáticamente sin solicitar confirmación. -- **Múltiples CLIs detectadas** en un terminal interactivo — muestra un prompt de selección única con teclas de flecha, agrupado en una sección `Detected (N)` (con una fila agregada `Install for all N detected` + cada CLI detectada individualmente) y una sección `Not installed (M) · install hooks ahead of time` que lista cada CLI compatible no detectada como opción de instalación anticipada (↑↓ para moverse, Enter para seleccionar, ^C para salir). El flujo de desinstalación muestra solo la sección Detected. -- **Múltiples CLIs detectadas** en una ejecución no interactiva (CI, sin TTY) — instala para todas las CLIs detectadas sin solicitar confirmación. -- **Ninguna detectada** — recurre a `claude`, con una advertencia de que no se encontró ningún binario de agente en el PATH; el comando de hook se escribe de todas formas para que se active en cuanto instales uno. +- **Un CLI detectado** — lo selecciona automáticamente sin preguntar. +- **Múltiples CLI detectados** en una terminal interactiva — muestra un aviso de selección única con teclas de flecha, agrupado en una sección `Detected (N)` (con una fila agregada `Install for all N detected` + cada CLI detectado individualmente) y una sección `Not installed (M) · install hooks ahead of time` que lista todos los CLI soportados no detectados como opción de instalación anticipada (↑↓ para moverse, Enter para seleccionar, ^C para salir). El flujo de desinstalación muestra solo la sección Detected. +- **Múltiples CLI detectados** en una ejecución no interactiva (CI, sin TTY) — instala para todos los CLI detectados sin preguntar. +- **Ninguno detectado** — vuelve a `claude`, con una advertencia de que no se encontró ningún binario de agente en PATH; el comando de hook se escribe igualmente para que se active en cuanto instales uno. -Puedes editar `policies-config.json` directamente en cualquier momento; los cambios surten efecto inmediatamente en el próximo evento de hook sin necesidad de reiniciar. +Puedes editar `policies-config.json` directamente en cualquier momento; los cambios surten efecto inmediatamente en el siguiente evento de hook sin necesidad de reinicio. --- @@ -247,4 +255,4 @@ Confirma `.failproofai/policies-config.json` en tu repositorio: } ``` -Cada desarrollador puede entonces crear `.failproofai/policies-config.local.json` (ignorado por git) para sobreescrituras personales sin afectar a sus compañeros de equipo. \ No newline at end of file +Cada desarrollador puede entonces crear `.failproofai/policies-config.local.json` (ignorado por git) para sus propias sobrescrituras personales sin afectar a sus compañeros de equipo. \ No newline at end of file diff --git a/docs/es/dashboard.mdx b/docs/es/dashboard.mdx index b08f724b..220c99fa 100644 --- a/docs/es/dashboard.mdx +++ b/docs/es/dashboard.mdx @@ -4,7 +4,7 @@ description: "Monitorea sesiones de agentes, revisa llamadas a herramientas y ge icon: chart-line --- -El dashboard de failproofai es una aplicación web local para monitorear tus sesiones de agentes de IA y gestionar políticas. Consulta lo que hicieron tus agentes mientras no estabas. +El dashboard de failproofai es una aplicación web local para monitorear tus sesiones de agentes de IA y gestionar políticas. Descubre qué hicieron tus agentes mientras no estabas. --- @@ -24,11 +24,11 @@ El dashboard lee directamente desde el sistema de archivos: las carpetas de proy ### Proyectos -Lista todos los proyectos de Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ y Hermes encontrados en tu máquina. Los proyectos de Claude se descubren desde `~/.claude/projects/` (o la ruta definida por `CLAUDE_PROJECTS_PATH`); los proyectos de Codex se descubren escaneando todas las transcripciones en `~/.codex/sessions///
/*.jsonl` y agrupándolas por el `cwd` registrado en el primer registro de cada sesión; los proyectos de Copilot CLI se descubren escaneando cada `~/.copilot/session-state//workspace.yaml` (configurable mediante `COPILOT_HOME`) y agrupándolos por su campo `cwd`; los proyectos de Cursor Agent se descubren escaneando metadatos por sesión en `~/.cursor/agent-sessions//` (configurable mediante `CURSOR_HOME`, con `conversations/` y `sessions/` como alternativas de búsqueda) para un escalar `cwd` en `meta.json` / `session.json` / `workspace.yaml`; los proyectos de OpenCode se descubren consultando su base de datos SQLite en `~/.local/share/opencode/opencode.db` mediante `opencode db --format json` (leemos las tablas `session` y `project` y agrupamos por `project_id`); los proyectos de Pi se descubren escaneando transcripciones JSONL por sesión en `~/.pi/agent/sessions//_.jsonl` (configurable mediante `PI_SESSIONS_DIR`) y extrayendo el `cwd` del primer registro de cada sesión; los proyectos de Gemini CLI se descubren escaneando `~/.gemini/tmp//chats/session--.jsonl` (configurable mediante `GEMINI_SESSIONS_DIR`) y recuperando el cwd canónico desde el marcador de texto `.project_root` adyacente; las sesiones del gateway de Hermes se leen directamente desde su almacén SQLite en `~/.hermes/state.db` (configurable mediante `HERMES_DB_PATH`) y se agrupan en proyectos `hermes-` por `source` (Slack/Telegram/cli/cron — las sesiones del gateway no tienen cwd). Un proyecto que haya sido utilizado por múltiples CLIs se muestra como una sola fila con todas las insignias correspondientes. Usa el menú desplegable **CLI** sobre la tabla para filtrar por un agente CLI específico; la URL conserva tu selección como `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lista todos los proyectos de Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity y Goose encontrados en tu máquina. Los proyectos de Claude se descubren en `~/.claude/projects/` (o la ruta definida por `CLAUDE_PROJECTS_PATH`); los proyectos de Codex se descubren escaneando cada transcripción en `~/.codex/sessions///
/*.jsonl` y agrupándolos por el `cwd` registrado en el primer registro de cada sesión; los proyectos de Copilot CLI se descubren escaneando cada `~/.copilot/session-state//workspace.yaml` (configurable mediante `COPILOT_HOME`) y agrupándolos por su campo `cwd`; los proyectos de Cursor Agent se descubren escaneando los metadatos por sesión en `~/.cursor/agent-sessions//` (configurable mediante `CURSOR_HOME`, con `conversations/` y `sessions/` como alternativas) buscando un escalar `cwd` en `meta.json` / `session.json` / `workspace.yaml`; los proyectos de OpenCode se descubren consultando su base de datos SQLite en `~/.local/share/opencode/opencode.db` mediante `opencode db --format json` (se leen las tablas `session` y `project` y se agrupan por `project_id`); los proyectos de Pi se descubren escaneando las transcripciones JSONL por sesión en `~/.pi/agent/sessions//_.jsonl` (configurable mediante `PI_SESSIONS_DIR`) y extrayendo el `cwd` del primer registro de cada sesión; las sesiones del gateway de Hermes se leen directamente desde su almacén SQLite en `~/.hermes/state.db` (configurable mediante `HERMES_DB_PATH`) y se agrupan en proyectos `hermes-` por `source` (Slack/Telegram/cli/cron — las sesiones del gateway no tienen cwd); las sesiones del gateway de OpenClaw se leen desde `~/.openclaw/agents//sessions/*.jsonl` y se agrupan en proyectos `openclaw-` (también sin cwd); los proyectos de Factory Droid se descubren a partir de las transcripciones JSONL en `~/.factory/sessions//*.jsonl` y se agrupan por cwd; los proyectos de Devin desde su base de datos SQLite en `~/.local/share/devin/cli/sessions.db` (agrupados por el `working_directory` de cada sesión); los proyectos de Antigravity desde las transcripciones JSONL en `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` agrupados por cwd; y los proyectos de Goose desde su base de datos SQLite en `~/.local/share/goose/sessions/sessions.db` (agrupados por el `working_dir` de cada sesión). Un proyecto utilizado por varios CLIs se muestra como una sola fila con todas las insignias correspondientes. Usa el desplegable **CLI** sobre la tabla para filtrar por un agente CLI específico; la URL conserva tu selección como `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Cada proyecto muestra: - Nombre del proyecto (derivado de la ruta de la carpeta) -- Una insignia de CLI — `Claude Code` (naranja), `OpenAI Codex` (morado), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (ámbar), `Pi` (rosa), `Gemini CLI` (celeste) y/o `Hermes` (índigo) +- Una insignia de CLI — `Claude Code` (naranja), `OpenAI Codex` (morado), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (ámbar), `Pi` (rosa) y/o `Hermes` (índigo) - Fecha de la actividad de sesión más reciente Haz clic en un proyecto para ver sus sesiones. @@ -47,44 +47,44 @@ Haz clic en una sesión para abrir el visor de sesión. ### Visor de sesión -El visor de sesión responde la pregunta clave para los agentes autónomos: ¿qué hizo el agente y se mantuvo en curso? Una insignia de CLI junto al encabezado indica si la sesión es una transcripción de Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI o Hermes. Muestra una línea de tiempo de todo lo que ocurrió en una sesión: +El visor de sesión responde la pregunta clave sobre los agentes autónomos: ¿qué hizo el agente y se mantuvo dentro de lo esperado? Una insignia de CLI junto al encabezado indica si la sesión es una transcripción de Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity o Goose. Muestra una línea de tiempo de todo lo que ocurrió en una sesión: -- **Mensajes** - Respuestas de texto de Claude y prompts del usuario +- **Mensajes** - Las respuestas de texto de Claude y los prompts del usuario - **Llamadas a herramientas** - Cada herramienta que Claude invocó, con su entrada y salida - **Actividad de políticas** - Para cada llamada a herramienta, qué políticas se activaron y qué decisión devolvieron -La barra de estadísticas en la parte superior muestra la duración de la sesión, el total de llamadas a herramientas y un resumen de las decisiones de los hooks (recuentos de allow / deny / instruct). +La barra de estadísticas en la parte superior muestra la duración de la sesión, el total de llamadas a herramientas y un resumen de las decisiones de hooks (recuentos de allow / deny / instruct). -Haz clic en el botón **Descargar Logs** para exportar la sesión. Para sesiones de Claude Code, Codex, Copilot, Cursor, Pi y Gemini obtienes la transcripción JSONL original en disco byte a byte; para OpenCode (cuyas sesiones residen en SQLite, no en disco) obtienes un documento JSON que refleja las tablas subyacentes `session` / `messages` / `parts`. +Haz clic en el botón **Descargar Logs** para exportar la sesión. Para sesiones de Claude Code, Codex, Copilot, Cursor y Pi obtienes la transcripción JSONL original en disco byte a byte; para OpenCode (cuyas sesiones residen en SQLite, no en disco) obtienes un documento JSON que refleja las tablas subyacentes `session` / `messages` / `parts`. ### Auditoría -Un informe con personalidad sobre cómo se ha comportado realmente tu agente a lo largo de sesiones pasadas. Ejecuta el mismo escaneo que el CLI `failproofai audit` pero lo renderiza como un póster compartible de pantalla completa + cuatro secciones debajo del pliegue: +Un informe con personalidad propia sobre cómo se ha comportado realmente tu agente en sesiones pasadas. Ejecuta el mismo análisis que el CLI `failproofai audit` pero lo renderiza como un póster de una sola pantalla compartible + cuatro secciones debajo del pliegue: -1. **Póster** — ocupa el primer viewport. Región de captura PNG autocontenida con el logotipo de failproof_ai + etiqueta de auditoría · índice de arquetipo (`№ NN de 08`) + fecha de auditoría · puntuación numérica (0–100) + píldora de percentil (`top 15%`) · el nombre del arquetipo (uno de `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + tira de 3 palabras clave · línea de rareza `// only N% of agents are this archetype` · ficha de símbolo de 8×8 píxeles · pie de página `audit yours → failproof.ai`. Tres botones de compartir se ubican justo fuera del recuadro de captura: `post your archetype` (intención en X), `share on linkedin`, `download poster`. La captura se realiza mediante `html-to-image` para que el PNG coincida píxel a píxel con el renderizado en pantalla (bordes punteados, máscara de logo SVG, degradados, métricas de fuente — todo preservado). -2. **Fortalezas** — lista de comportamientos que tu agente ya hace bien, con una marca de verificación tranquila, derivada de los datos de auditoría en tiempo real (tasa de llamadas a herramientas limpia, sin pushes directos a main, cero filtraciones de credenciales, cero tormentas de reintentos) — cada una se muestra solo cuando la política relevante tiene un historial limpio durante la ventana de auditoría. -3. **Peculiaridades** — tabla de lo que se escapó, ordenado por severidad: `cuándo · qué se escapó + la política que lo habría detectado · píldora de severidad · visto`, donde la recurrencia se lee como `new` (una vez), `N× seen` (2–9 veces) o `recurring` (10+). -4. **Cómo mejorar** — lista tranquila de filas, una por política prescrita: nombre de la política en blanco, descripción de una línea, comando de instalación + botón de copiar a la derecha. El encabezado de la sección dice `enable all N → projected · ` (la puntuación que alcanzarías con todas las correcciones aplicadas), y su botón `[install all]` copia el comando combinado `failproofai policy add a b c …` para cada política prescrita. -5. **Vuelve mejor** — dos tarjetas lado a lado. Izquierda: establecer un recordatorio (selector de cadencia `3d` / `7d` / `14d` / `30d`; persiste mediante `/api/auth/reminder` una vez autenticado). Derecha: desbloquear ventajas de failproof — `invite a friend` abre un modal que acepta una lista de correos de amigos separados por coma, espacio o salto de línea (máximo 10 por envío), los publica en `/api/audit/invite`, que los reenvía al `POST /v0/invite` del servidor de API. El servidor de API envía un correo por destinatario desde `invite@failproof.ai` con el remitente en Cc y `Reply-To` configurado, de modo que el destinatario vea quién lo invitó y el remitente reciba una copia en su bandeja. Los usuarios anónimos pasan primero por el `AuthDialog` para que el correo del remitente sea conocido antes de enviar las invitaciones. El cumplimiento de derechos y ventajas es un seguimiento pendiente. +1. **Póster** — ocupa el primer viewport. Región de captura PNG autónoma con el logo de failproof_ai + etiqueta de auditoría · índice de arquetipo (`№ NN de 08`) + fecha de auditoría · puntuación numérica (0–100) + píldora de rango percentil (`top 15%`) · el nombre del arquetipo (uno de `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + banda de 3 palabras clave · línea de rareza `// only N% of agents are this archetype` · tesela de símbolo de 8×8 píxeles · pie de página `audit yours → failproof.ai`. Tres botones de compartir se ubican justo fuera del recuadro de captura: `post your archetype` (intención en X), `share on linkedin`, `download poster`. La captura se realiza mediante `html-to-image`, por lo que el PNG coincide con el renderizado en pantalla píxel a píxel (bordes punteados, máscara de logo SVG, degradados, métricas de fuente — todo preservado). +2. **Fortalezas** — lista de filas con ✓ de los comportamientos que tu agente ya hace bien, derivados de los datos de auditoría en vivo (tasa de llamadas a herramientas limpia, sin empujes directos a main, cero filtraciones de credenciales, cero tormentas de reintentos) — cada uno se muestra solo cuando la política relevante tiene un historial limpio en la ventana de auditoría. +3. **Peculiaridades** — tabla de lo que se escapó, ordenado por gravedad: `cuándo · qué se escapó + la política que lo habría detectado · píldora de gravedad · visto`, donde la recurrencia se lee como `new` (una vez), `N× seen` (2–9 veces) o `recurring` (10+). +4. **Cómo mejorar** — lista de filas tranquila, una por política prescrita: nombre de política en blanco, descripción de una línea, comando de instalación + botón de copiar a la derecha. El encabezado de la sección dice `enable all N → projected · ` (la puntuación que alcanzarías con todas las correcciones aplicadas), y su botón `[install all]` copia el comando combinado `failproofai policy add a b c …` para cada política prescrita. +5. **Vuelve mejor** — dos tarjetas en paralelo. Izquierda: establecer un recordatorio (selector de cadencia `3d` / `7d` / `14d` / `30d`; persiste mediante `/api/auth/reminder` una vez autenticado). Derecha: desbloquear ventajas de failproof — `invite a friend` abre un modal que acepta una lista separada por comas/espacios/saltos de línea de correos de amigos (máximo 10 por envío), los publica en `/api/audit/invite`, que los reenvía al servidor de API en `POST /v0/invite`. El servidor de API envía un correo por destinatario desde `invite@failproof.ai` con el remitente en Cc y `Reply-To` configurado, de modo que el destinatario ve quién lo invitó y el remitente recibe una copia en su bandeja de entrada. Los usuarios anónimos pasan primero por el `AuthDialog` para que el correo del remitente sea conocido antes de que salgan las invitaciones. El cumplimiento de derechos/ventajas es un trabajo pendiente. -Impulsado por el runtime de `failproofai audit` — consulta [Audit CLI](/es/cli/audit) para el motor de escaneo subyacente, flags compatibles e invariantes de caché por transcripción. El dashboard almacena en caché el último resultado en `~/.failproofai/audit-dashboard.json` (modo `0600`, ranura única, las nuevas ejecuciones sobrescriben) para que las revisitas sean instantáneas; **tanto las cachés por transcripción como las de resultado completo se rechazan al leer una vez que tienen más de 7 días** para que el dashboard nunca sirva silenciosamente un resultado de hace una semana — pasado el TTL, `/audit` cae a su estado vacío y solicita una ejecución nueva. Al hacer clic en `[ re-audit now ]` cerca de la parte inferior del informe se hace un POST a `/api/audit/run` con `noCache: true` — la re-auditoría omite la caché por transcripción y re-escanea cada transcripción desde cero en lugar de devolver silenciosamente el resultado en caché — y el dashboard consulta `/api/audit/status` a 1 Hz hasta que termina la ejecución; una tira de progreso rosa fija se ancla en la parte superior del viewport durante la ejecución con un temporizador transcurrido, y el resultado nuevo se intercambia en su lugar al tener éxito (sin recarga de página completa; una re-auditoría fallida deja intacto el informe anterior). En caso de fallo, la tira se vuelve roja con texto basado en el `RerunError.kind` (`timeout` / `network` / `post_failed`). El estado vacío (sin caché o caducado) y el estado de cero sesiones (caché existe pero el escaneo no encontró transcripciones) se muestran por separado. +Impulsado por el runtime `failproofai audit` — consulta [Audit CLI](/es/cli/audit) para conocer el motor de análisis subyacente, los flags admitidos y los invariantes de caché por transcripción. El dashboard almacena en caché el último resultado en `~/.failproofai/audit-dashboard.json` (modo `0600`, una sola ranura, las nuevas ejecuciones sobreescriben) para que las visitas posteriores sean instantáneas; **tanto la caché por transcripción como la caché del resultado completo se rechazan al leer cuando tienen más de 7 días de antigüedad**, por lo que el dashboard nunca sirve silenciosamente un resultado de una semana: pasado el TTL, `/audit` cae a su estado vacío y solicita una nueva ejecución. Hacer clic en `[ re-audit now ]` cerca de la parte inferior del informe hace un POST a `/api/audit/run` con `noCache: true` — la reauditoría omite la caché por transcripción y reanaliza cada transcripción desde cero en lugar de devolver silenciosamente el resultado en caché — y el dashboard sondea `/api/audit/status` a 1Hz hasta que la ejecución termina; una franja rosa adhesiva se ancla en la parte superior del viewport durante la ejecución con un temporizador transcurrido, y el resultado fresco se intercambia en su lugar al completarse correctamente (sin recarga de página completa; una reauditoría fallida deja intacto el informe anterior). En caso de fallo, la franja se vuelve roja con texto según el `RerunError.kind` (`timeout` / `network` / `post_failed`). El estado vacío (sin caché o caducada) y el estado de cero sesiones (caché existente pero el análisis no encontró transcripciones) se presentan por separado. ### Políticas -Una página de dos pestañas para gestionar políticas y revisar actividad. +Una página de dos pestañas para gestionar políticas y revisar la actividad. - - - Selección múltiple de los CLIs de agentes que failproofai protege desde un único panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI y Hermes tienen una fila con el estado de instalación (`Active` / `Detected` / `Inactive`), la ruta de configuración de alcance de usuario y un acento de color de marca. Marca o desmarca los CLIs que desees y haz clic en `Apply changes` para instalar/desinstalar la diferencia en un solo paso. Los CLIs cuyo binario se detecta en PATH se marcan previamente. - - Activa o desactiva políticas individuales con un solo clic (escribe en `~/.failproofai/policies-config.json` — compartido entre cada CLI instalado) + + - Selección múltiple de qué CLIs de agentes failproofai protege desde un único panel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi y Hermes tienen cada uno una fila con el estado de instalación (`Active` / `Detected` / `Inactive`), la ruta de configuración de ámbito de usuario y un acento de color de marca. Marca o desmarca los CLIs que deseas y haz clic en `Apply changes` para instalar/desinstalar la diferencia en un solo paso. Los CLIs cuyo binario se detecta en PATH vienen marcados previamente. + - Activa o desactiva políticas individuales con un solo clic (escribe en `~/.failproofai/policies-config.json` — compartido entre todos los CLIs instalados) - Expande una política para configurar sus parámetros (para políticas que admiten `policyParams`) - - Establece una ruta de archivo de políticas personalizadas + - Establece una ruta de archivo de políticas personalizada - - - Historial completo paginado de cada evento de hook que se ha activado en todas las sesiones - - Filtra por decisión, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nombre de política o ID de sesión - - Cada fila muestra: marca de tiempo, nombre de política, decisión, insignia de CLI (naranja = Claude Code, morado = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, ámbar = OpenCode, rosa = Pi, celeste = Gemini CLI, índigo = Hermes), nombre de herramienta, ID de sesión y el motivo de las decisiones deny/instruct - - Haz clic en un ID de sesión para abrir su transcripción — el visor detecta automáticamente qué CLI activó el hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) y renderiza la insignia de CLI correspondiente en el encabezado + + - Historial paginado completo de cada evento de hook que se ha disparado en todas las sesiones + - Filtra por decisión, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), nombre de política o ID de sesión + - Cada fila muestra: marca de tiempo, nombre de política, decisión, insignia de CLI (naranja = Claude Code, morado = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, ámbar = OpenCode, rosa = Pi, índigo = Hermes, verde azulado = OpenClaw, rosa intenso = Factory Droid, violeta = Devin, cian = Antigravity, lima = Goose), nombre de herramienta, ID de sesión y el motivo de las decisiones deny/instruct + - Haz clic en un ID de sesión para abrir su transcripción — el visor detecta automáticamente qué CLI disparó el hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) y renderiza la insignia de CLI correspondiente en el encabezado @@ -92,13 +92,13 @@ Una página de dos pestañas para gestionar políticas y revisar actividad. ## Actualización automática -El dashboard tiene un botón de actualización automática en la navegación superior. Cuando está habilitado, la página actual se actualiza periódicamente para mostrar nuevas sesiones y actividad de políticas a medida que aparecen. Es esencial para monitorear sesiones de agentes autónomos de larga duración. +El dashboard tiene un interruptor de actualización automática en la navegación superior. Cuando está activado, la página actual se refresca periódicamente para mostrar nuevas sesiones y actividad de políticas a medida que aparecen. Esencial para monitorear sesiones de agentes autónomos de larga duración. --- ## Deshabilitar páginas -Si solo necesitas algunas partes del dashboard, establece `FAILPROOFAI_DISABLE_PAGES` en una lista separada por comas de nombres de páginas: +Si solo necesitas algunas partes del dashboard, establece `FAILPROOFAI_DISABLE_PAGES` con una lista separada por comas de nombres de páginas: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +110,7 @@ Valores válidos: `policies`, `projects`, `audit`. ## Configurar la ruta de proyectos -Por defecto, el dashboard lee desde el directorio de proyectos estándar de Claude Code. Puedes sobreescribirlo para configuraciones personalizadas: +Por defecto, el dashboard lee desde el directorio estándar de proyectos de Claude Code. Puedes sobreescribirlo para configuraciones personalizadas: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,15 +118,15 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## Acceder desde un host que no sea localhost +## Acceder desde un host que no es localhost -Cuando ejecutas el dashboard en **modo dev** (`npm run dev`) y accedes a él desde un hostname distinto a `localhost` — por ejemplo, un dominio personalizado, una IP remota o una URL tunelizada — es posible que veas una advertencia como: +Cuando ejecutas el dashboard en **modo dev** (`npm run dev`) y accedes a él desde un nombre de host distinto a `localhost` — por ejemplo, un dominio personalizado, una IP remota o una URL tunelizada — es posible que veas una advertencia como: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Esto es Next.js bloqueando el acceso cross-origin a su websocket de HMR (recarga de módulos en caliente), que es una característica exclusiva del modo dev. Para permitir tu host, usa el flag `--allowed-origins`: +Esto es Next.js bloqueando el acceso de origen cruzado a su websocket HMR (recarga en caliente de módulos), que es una función exclusiva del modo dev. Para permitir tu host, usa el flag `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com @@ -145,5 +145,5 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Esto solo aplica al modo dev. Al ejecutar `failproofai` (modo producción), no hay websocket de HMR ni problema de recursos dev cross-origin. +Esto solo aplica al modo dev. Al ejecutar `failproofai` (modo producción), no hay websocket HMR ni problemas de recursos dev de origen cruzado. \ No newline at end of file diff --git a/docs/es/getting-started.mdx b/docs/es/getting-started.mdx index 51f88320..e1e9837e 100644 --- a/docs/es/getting-started.mdx +++ b/docs/es/getting-started.mdx @@ -1,13 +1,13 @@ --- title: Primeros pasos -description: "Instala failproofai, activa las políticas y deja que tus agentes funcionen de forma confiable" +description: "Instala failproofai, habilita políticas y deja que tus agentes funcionen de forma fiable" icon: rocket --- ## Requisitos - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (opcional — solo necesario para compilar desde el código fuente) +- **Bun** >= 1.3.0 (opcional - solo necesario para compilar desde el código fuente) --- @@ -30,16 +30,16 @@ bun add -g failproofai ## Inicio rápido - - Las políticas son reglas que se ejecutan antes y después de cada llamada a una herramienta del agente. Detectan comandos destructivos, filtraciones de secretos y otros modos de fallo antes de que causen daño. + + Las políticas son reglas que se ejecutan antes y después de cada llamada a una herramienta del agente. Detectan comandos destructivos, filtraciones de secretos y otros modos de fallo antes de que causen daños. ```bash failproofai policies --install ``` - Esto escribe entradas de hooks en los CLIs de agentes instalados (el `~/.claude/settings.json` de Claude Code, el `~/.codex/hooks.json` de OpenAI Codex, el `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, el `~/.cursor/hooks.json` de Cursor Agent, el shim de plugin generado de OpenCode en `~/.config/opencode/plugins/failproofai.mjs` junto con una entrada de registro en el array `plugin` de `~/.config/opencode/opencode.json`, el `~/.pi/agent/settings.json` de Pi, el `~/.gemini/settings.json` de Gemini CLI, o el `~/.hermes/config.yaml` de Hermes). Si hay más de uno presente, se te pedirá que elijas; pasa `--cli claude codex copilot cursor opencode pi gemini hermes` (cualquier subconjunto) para omitir la pregunta. + Esto escribe entradas de hooks en los CLIs de agentes instalados (el `~/.claude/settings.json` de Claude Code, el `~/.codex/hooks.json` de OpenAI Codex, el `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, el `~/.cursor/hooks.json` de Cursor Agent, el shim de plugin generado por OpenCode en `~/.config/opencode/plugins/failproofai.mjs` junto con una entrada de registro en el array `plugin` de `~/.config/opencode/opencode.json`, el `~/.pi/agent/settings.json` de Pi, el `~/.hermes/config.yaml` de Hermes, el `~/.openclaw/openclaw.json` de OpenClaw, el `~/.factory/hooks.json` de Factory Droid, el `~/.config/devin/config.json` de Devin CLI, el `~/.gemini/config/hooks.json` de Antigravity CLI, o el directorio de plugins autodescubierto por Goose en `~/.agents/plugins/failproofai/hooks/hooks.json`). Si hay más de uno instalado, se te pedirá que elijas; pasa `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (cualquier subconjunto) para omitir la solicitud. - El soporte para GitHub Copilot CLI, Cursor Agent, OpenCode, Pi y Gemini CLI es **beta** — instala con `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` o `--cli gemini`. Hermes (hermes-agent, una puerta de enlace para Slack/Telegram) se instala con alcance de usuario mediante `--cli hermes` y es **también** una fuente de auditoría sin conexión. + El soporte para GitHub Copilot CLI, Cursor Agent, OpenCode y Pi está en **beta** — instala con `--cli copilot`, `--cli cursor`, `--cli opencode` o `--cli pi`. Hermes (hermes-agent, una pasarela Slack/Telegram) se instala con alcance de usuario con `--cli hermes` y es **también** una fuente de auditoría sin conexión. OpenClaw (pasarela openclaw, un asistente multicanal autohospedado) se instala con alcance de usuario con `--cli openclaw` — la aplicación de políticas se ejecuta a través de sus hooks de plugin en proceso (`before_agent_finalize` es una puerta real al final del turno, por lo que los incorporados `require-*-before-stop` se aplican efectivamente) — y es **también** una fuente de auditoría sin conexión. Factory Droid (`droid`) se instala con `--cli factory` (alcance de usuario y de proyecto) y es **también** una fuente de auditoría sin conexión. Devin CLI (`devin`, Cognition) se instala con `--cli devin` (alcance de usuario y de proyecto) y es **también** una fuente de auditoría sin conexión. Antigravity CLI (`agy`) se instala con `--cli antigravity` (alcance de usuario y de proyecto) y es **también** una fuente de auditoría sin conexión. Goose (nombre en clave goose, Block) se instala con `--cli goose` (alcance de usuario y de proyecto) — el instalador simplemente crea un directorio de plugin en `~/.agents/plugins/failproofai/` que Goose autodescubre, y es **también** una fuente de auditoría sin conexión. ```bash failproofai policies --install --scope project @@ -48,27 +48,31 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` - + ```bash failproofai policies ``` Muestra todas las políticas, si están habilitadas y los parámetros configurados. - + ```bash failproofai ``` Abre un panel de control local en `http://localhost:8020` donde puedes explorar sesiones, inspeccionar llamadas a herramientas y gestionar políticas. - - Inicia Claude Code como de costumbre. Si el agente intenta algo arriesgado, failproofai lo intercepta automáticamente. Déjalo correr desatendido y revisa lo que ocurrió en el panel de control. + + Inicia Claude Code como de costumbre. Si el agente intenta algo arriesgado, failproofai lo intercepta automáticamente. Déjalo en ejecución sin supervisión y revisa lo que ocurrió en el panel de control. @@ -86,9 +90,9 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON Cada política devuelve una de tres decisiones: -- **allow** — el agente continúa con normalidad -- **deny** — la acción es bloqueada y se le indica al agente el motivo -- **instruct** — se añade contexto adicional al prompt del agente +- **allow** - el agente continúa con normalidad +- **deny** - la acción es bloqueada y se le indica al agente el motivo +- **instruct** - se añade contexto adicional al prompt del agente Las políticas se ejecutan en tu proceso local. No se envía nada a un servicio remoto. @@ -98,16 +102,16 @@ Las políticas se ejecutan en tu proceso local. No se envía nada a un servicio ## Configura políticas de equipo con políticas basadas en convenciones -La forma más rápida de establecer estándares de calidad en tu equipo es la convención `.failproofai/policies/`. Coloca archivos de políticas en este directorio y se cargan automáticamente — sin flags, sin cambios de configuración, sin comandos de instalación. +La forma más rápida de establecer estándares de calidad en tu equipo es la convención de directorio `.failproofai/policies/`. Coloca archivos de políticas en este directorio y se cargan automáticamente — sin flags, sin cambios de configuración, sin comandos de instalación. - + ```bash mkdir -p .failproofai/policies ``` - - Copia los ejemplos de inicio o escribe los tuyos propios: + + Copia los ejemplos de inicio o escribe los tuyos: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -132,7 +136,7 @@ La forma más rápida de establecer estándares de calidad en tu equipo es la co }); ``` - + ```bash git add .failproofai/policies/ git commit -m "Add team quality policies" @@ -143,7 +147,7 @@ La forma más rápida de establecer estándares de calidad en tu equipo es la co -Confirma `.failproofai/policies/` en tu repositorio para que todo el equipo comparta los mismos estándares. A medida que tu equipo descubra nuevos modos de fallo, añade políticas y haz push — todos recibirán la actualización en su próximo `git pull`. Con el tiempo, estas políticas se convierten en un estándar de calidad vivo que no deja de mejorar. +Confirma `.failproofai/policies/` en tu repositorio para que todo el equipo comparta los mismos estándares. A medida que el equipo descubra nuevos modos de fallo, agrega políticas y envíalas — todos recibirán la actualización en su próximo `git pull`. Con el tiempo, estas políticas se convierten en un estándar de calidad vivo que no deja de mejorar. --- @@ -157,12 +161,12 @@ Toda la configuración y los registros permanecen en tu máquina: | `~/.failproofai/policies-config.json` | Configuración global de políticas | | `~/.failproofai/hook-activity.jsonl` | Historial de ejecución de hooks | | `~/.failproofai/hook.log` | Registro de depuración para errores de hooks personalizados | -| `.failproofai/policies-config.json` | Configuración por proyecto (confirmada en git) | -| `.failproofai/policies-config.local.json` | Sobreescrituras personales (en gitignore) | +| `.failproofai/policies-config.json` | Configuración por proyecto (confirmada en el repositorio) | +| `.failproofai/policies-config.local.json` | Anulaciones personales (en gitignore) | --- -## Desinstalación +## Desinstalar ```bash failproofai policies --uninstall @@ -177,7 +181,7 @@ Elimina las entradas de hooks de `~/.claude/settings.json`. Los archivos de conf - Alcances y formato del archivo de configuración + Alcances y formato de los archivos de configuración diff --git a/docs/es/introduction.mdx b/docs/es/introduction.mdx index b3eabeed..e8479159 100644 --- a/docs/es/introduction.mdx +++ b/docs/es/introduction.mdx @@ -1,15 +1,15 @@ --- title: "Failproof AI" -description: "FailproofAI ofrece a los agentes de IA 39 políticas de fallo integradas que detectan bucles, filtraciones de secretos, llamadas destructivas a herramientas y más, con una sola instalación." +description: "FailproofAI proporciona a los agentes de IA 39 políticas de fallo integradas que detectan bucles, filtraciones de secretos, llamadas destructivas a herramientas y más en una sola instalación." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks y políticas para **manejo de fallos de IA**, **recuperación de errores** y **fiabilidad de LLM**. Mantén tus agentes de IA fiables y funcionando de forma autónoma en **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** y el **Agents SDK**. +Hooks y políticas para el **manejo de fallos de IA**, **recuperación de errores** y **fiabilidad de LLM**. Mantén tus agentes de IA confiables y en funcionamiento autónomo en **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** y el **Agents SDK**. -Los agentes de IA fallan de maneras predecibles. Ejecutan comandos destructivos, filtran secretos, se desvían de sus tareas, quedan atrapados en bucles o hacen push directamente a main. Sin supervisión, los pequeños fallos se convierten en interrupciones del servicio, credenciales expuestas y trabajo perdido. +Los agentes de IA fallan de maneras predecibles. Ejecutan comandos destructivos, filtran secretos, se desvían de sus tareas, quedan atrapados en bucles o hacen push directamente a main. Sin supervisión, los fallos pequeños se convierten en interrupciones del servicio, credenciales expuestas y trabajo perdido. -FailproofAI resuelve esto mediante **políticas**. Estas reglas se enganchan en cada llamada a herramientas del agente para **detectar fallos**, **mitigarlos** (bloquear, instruir, sanitizar) y **alertarte** cuando algo requiere tu atención. Un panel de control local te permite revisar después cada llamada a herramientas, cada fallo del agente y cada acción de recuperación. +FailproofAI resuelve esto con **políticas**. Estas reglas se enganchan en cada llamada a herramientas del agente para **detectar fallos**, **mitigarlos** (block, instruct, sanitize) y **alertarte** cuando algo requiere atención. Un panel de control local te permite revisar cada llamada a herramientas, fallo del agente y acción de recuperación después de que ocurran. Ningún dato sale de tu máquina. @@ -18,11 +18,11 @@ Ningún dato sale de tu máquina. - Bloquea comandos destructivos, evita filtraciones de secretos, mantén a los agentes dentro de los límites del proyecto y mucho más. Todo listo para usar desde el primer momento. + Bloquea comandos destructivos, evita la filtración de secretos, mantén a los agentes dentro de los límites del proyecto y más. Todo disponible desde el primer momento. - Escribe tus propias reglas en JavaScript con una sencilla API de allow / deny / instruct. + Escribe tus propias reglas en JavaScript con una API sencilla de allow / deny / instruct. @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -Consulta la guía de [Primeros pasos](/es/getting-started) para ver el recorrido completo. \ No newline at end of file +Consulta la guía de [Primeros pasos](/es/getting-started) para ver el proceso completo. \ No newline at end of file diff --git a/docs/fr/built-in-policies.mdx b/docs/fr/built-in-policies.mdx index edefb9c4..82147302 100644 --- a/docs/fr/built-in-policies.mdx +++ b/docs/fr/built-in-policies.mdx @@ -1,16 +1,16 @@ --- title: Politiques intégrées -description: "Les 39 politiques intégrées qui interceptent les modes d'échec courants des agents" +description: "Les 39 politiques intégrées qui interceptent les modes de défaillance courants des agents" icon: shield --- -failproofai est livré avec 39 politiques intégrées qui interceptent les modes d'échec courants des agents. Chaque politique se déclenche sur un type d'événement hook et un nom d'outil spécifiques. Dix-neuf politiques acceptent des paramètres permettant d'affiner leur comportement sans écrire de code. Cinq politiques de workflow imposent un pipeline commit → push → PR → CI avant que Claude ne s'arrête. +failproofai est livré avec 39 politiques intégrées qui interceptent les modes de défaillance courants des agents. Chaque politique se déclenche sur un type d'événement de hook et un nom d'outil spécifiques. Dix-neuf politiques acceptent des paramètres permettant d'ajuster leur comportement sans écrire de code. Cinq politiques de workflow imposent un pipeline commit → push → PR → CI avant que Claude ne s'arrête. --- ## Vue d'ensemble -Les politiques sont regroupées par catégories : +Les politiques sont regroupées par catégorie : | Catégorie | Politiques | Type de hook | |----------|----------|-----------| @@ -25,15 +25,15 @@ Les politiques sont regroupées par catégories : | [Gestionnaires de paquets](#package-managers) | prefer-package-manager | PreToolUse | | [Workflow](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — empêche l'agent de poursuivre. +- **`block-`** — empêche l'agent de continuer. - **`warn-`** — fournit à l'agent du contexte supplémentaire pour qu'il puisse se corriger. -- **`sanitize-`** — nettoie les données sensibles de la sortie d'un outil avant que l'agent ne les voie. +- **`sanitize-`** — expurge les données sensibles de la sortie d'un outil avant que l'agent ne les consulte. ### Espaces de noms -Chaque politique occupe un emplacement `/`. Les politiques intégrées appartiennent à l'espace de noms **`failproofai/`** — par exemple, `failproofai/sanitize-jwt`. L'espace de noms évite les collisions lorsque vous chargez également des politiques personnalisées ou tierces portant des noms courts similaires. +Chaque politique occupe un emplacement `/`. Les politiques intégrées appartiennent à l'espace de noms **`failproofai/`** — par exemple, `failproofai/sanitize-jwt`. L'espace de noms évite les collisions lorsque vous chargez également des politiques personnalisées ou tierces avec des noms courts similaires. -Dans votre configuration, vous pouvez désigner une politique intégrée par son nom court ou son nom qualifié ; les deux formes pointent vers la même politique : +Dans votre configuration, vous pouvez faire référence à une politique intégrée par son nom court ou son nom qualifié ; les deux formes résolvent vers la même politique : ```json { @@ -44,13 +44,13 @@ Dans votre configuration, vous pouvez désigner une politique intégrée par son } ``` -Si un nom ne contient pas de `/`, failproofai considère qu'il appartient à l'espace de noms par défaut `failproofai`. Les noms contenant déjà un `/` (par ex. `myorg/foo`, `custom/my-hook`) sont conservés tels quels. +Si un nom ne contient pas de `/`, failproofai le considère comme appartenant à l'espace de noms par défaut `failproofai`. Les noms qui contiennent déjà un `/` (ex. `myorg/foo`, `custom/my-hook`) sont conservés tels quels. - **`require-`** — bloque l'événement Stop jusqu'à ce que les conditions soient remplies. --- -Toute politique supporte un champ `hint` optionnel dans `policyParams`. Le hint est ajouté au message deny ou instruct que Claude reçoit, offrant des conseils pratiques sans modifier le code de la politique. Fonctionne avec les politiques intégrées, personnalisées et de convention. Voir [Configuration → hint](/fr/configuration#hint-cross-cutting) pour les détails. +Toutes les politiques prennent en charge un champ `hint` optionnel dans `policyParams`. Le hint est ajouté au message de refus ou d'instruction que Claude reçoit, fournissant des conseils actionnables sans modifier le code de la politique. Fonctionne avec les politiques intégrées, personnalisées et de convention. Consultez [Configuration → hint](/fr/configuration#hint-cross-cutting) pour plus de détails. --- @@ -62,13 +62,13 @@ Empêche les agents d'exécuter des opérations difficiles à annuler ou suscept ### `block-sudo` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute commande `sudo`. +**Par défaut :** Refuse toute commande `sudo`. -Bloque les invocations contenant le mot-clé `sudo`. La correspondance de motif s'effectue sur les tokens de commande analysés, et non sur la chaîne brute, afin d'empêcher les contournements par injection d'opérateurs shell. +Bloque les invocations contenant le mot-clé `sudo`. La correspondance de motif est effectuée sur les tokens de commande analysés, et non sur la chaîne brute, pour éviter les contournements via injection d'opérateurs shell. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Préfixes de commandes exacts autorisés. Chaque entrée est comparée aux tokens argv analysés. | @@ -84,10 +84,10 @@ Bloque les invocations contenant le mot-clé `sudo`. La correspondance de motif } ``` -Avec cette configuration, `sudo systemctl status nginx` est autorisé, mais `sudo rm /etc/hosts` est bloqué. +Avec cette configuration, `sudo systemctl status nginx` est autorisé, mais `sudo rm /etc/hosts` est refusé. -Les motifs sont comparés aux tokens analysés, et non à la chaîne de commande brute. Cela empêche les contournements par opérateurs shell ajoutés (par ex. `sudo systemctl status x; rm -rf /` ne correspond pas à `sudo systemctl status *`). +Les motifs sont comparés aux tokens analysés, non à la chaîne de commande brute. Cela empêche les contournements via des opérateurs shell ajoutés en suffixe (ex. `sudo systemctl status x; rm -rf /` ne correspond pas à `sudo systemctl status *`). --- @@ -95,13 +95,13 @@ Les motifs sont comparés aux tokens analysés, et non à la chaîne de commande ### `block-rm-rf` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque `rm -rf`, `rm -fr` et les formes similaires de suppression récursive. +**Par défaut :** Refuse `rm -rf`, `rm -fr` et les formes similaires de suppression récursive. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Chemins dont la suppression récursive est autorisée (par ex. `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Chemins dont la suppression récursive est autorisée (ex. `/tmp`). | **Exemple :** @@ -120,7 +120,7 @@ Les motifs sont comparés aux tokens analysés, et non à la chaîne de commande ### `block-curl-pipe-sh` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque `curl | bash`, `curl | sh`, `wget | bash` et les motifs similaires. +**Par défaut :** Refuse `curl | bash`, `curl | sh`, `wget | bash` et les motifs similaires. Aucun paramètre. @@ -129,7 +129,7 @@ Aucun paramètre. ### `block-failproofai-commands` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque les commandes qui désinstalleraient ou désactiveraient failproofai lui-même (par ex. `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Par défaut :** Refuse les commandes qui désinstalleraient ou désactiveraient failproofai lui-même (ex. `npm uninstall failproofai`, `failproofai policies --uninstall`). Aucun paramètre. @@ -137,18 +137,18 @@ Aucun paramètre. ## Commandes infra -Empêche les agents de code d'exécuter des CLI d'infrastructure ou de déclencher des pipelines CI/CD. Toutes les politiques de cette catégorie sont **opt-in** (`defaultEnabled: false`) — les agents qui ont légitimement besoin d'appeler `kubectl`, `terraform`, etc. ne seront pas perturbés, sauf si vous activez explicitement la politique. Une fois activée, toute invocation du CLI correspondant est bloquée, à moins que la commande ne corresponde à une entrée de `allowPatterns`. +Empêche les agents de code d'exécuter des CLI d'infrastructure ou de déclencher des pipelines CI/CD. Toutes les politiques de cette catégorie sont **opt-in** (`defaultEnabled: false`) — les agents qui ont légitimement besoin d'appeler `kubectl`, `terraform`, etc. ne seront pas perturbés sauf si vous activez la politique. Une fois activée, chaque invocation du CLI correspondant est refusée sauf si la commande correspond à une entrée dans `allowPatterns`. -La grammaire des motifs est identique à celle de [`block-sudo`](#block-sudo) : les tokens sont comparés aux argv analysés, `*` est un joker pour un token, et toute commande contenant un opérateur shell autonome (`&&`, `||`, `|`, `;`) ou un token avec des métacaractères shell intégrés est rejetée avant la vérification de la liste d'autorisation, afin d'éviter les contournements par injection. +La grammaire des motifs est identique à celle de [`block-sudo`](#block-sudo) : les tokens sont comparés à l'argv analysé, `*` est un joker pour un token, et toute commande contenant un opérateur shell autonome (`&&`, `||`, `|`, `;`) ou un token avec des métacaractères shell intégrés est rejetée avant la vérification de la liste d'autorisation pour éviter les injections. ### `block-kubectl` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation de `kubectl`. +**Par défaut :** Refuse toute invocation `kubectl`. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Préfixes de commandes kubectl autorisés. | @@ -164,18 +164,18 @@ La grammaire des motifs est identique à celle de [`block-sudo`](#block-sudo) : } ``` -Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply -f deploy.yaml` est bloqué. +Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply -f deploy.yaml` est refusé. --- ### `block-terraform` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation de `terraform` ou `tofu` (OpenTofu). +**Par défaut :** Refuse toute invocation `terraform` ou `tofu` (OpenTofu). **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Préfixes de commandes terraform/tofu autorisés. | @@ -196,13 +196,13 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - ### `block-aws-cli` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation du CLI `aws`. +**Par défaut :** Refuse toute invocation du CLI `aws`. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Préfixes de commandes aws CLI autorisés. | +| `allowPatterns` | `string[]` | `[]` | Préfixes de commandes CLI aws autorisés. | **Exemple :** @@ -221,11 +221,11 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - ### `block-gcloud` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation du CLI `gcloud` (Google Cloud). +**Par défaut :** Refuse toute invocation du CLI `gcloud` (Google Cloud). **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Préfixes de commandes gcloud autorisés. | @@ -246,13 +246,13 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - ### `block-az-cli` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation du CLI `az` (Azure). +**Par défaut :** Refuse toute invocation du CLI `az` (Azure). **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Préfixes de commandes az CLI autorisés. | +| `allowPatterns` | `string[]` | `[]` | Préfixes de commandes CLI az autorisés. | **Exemple :** @@ -271,11 +271,11 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - ### `block-helm` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque toute invocation de `helm`. +**Par défaut :** Refuse toute invocation `helm`. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Préfixes de commandes helm autorisés. | @@ -296,7 +296,7 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - ### `block-gh-pipeline` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque les sous-commandes `gh` CLI suivantes qui modifient l'état ou déclenchent des pipelines : +**Par défaut :** Refuse les sous-commandes `gh` CLI suivantes qui modifient l'état ou déclenchent des pipelines : - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -305,13 +305,13 @@ Avec cette configuration, `kubectl get pods` est autorisé mais `kubectl apply - - `gh cache delete` - `gh secret set`, `gh secret delete` -Les sous-commandes `gh` en lecture seule telles que `gh pr view`, `gh pr list`, `gh run list`, `gh release view` et `gh api repos/.../...` ne sont **pas** visées par cette politique — elles sont couramment nécessaires pour les vérifications de workflow (y compris `require-ci-green-before-stop` de failproofai). +Les sous-commandes `gh` en lecture seule telles que `gh pr view`, `gh pr list`, `gh run list`, `gh release view` et `gh api repos/.../...` **ne sont pas** concernées par cette politique — elles sont régulièrement nécessaires pour les vérifications de workflow (y compris la politique `require-ci-green-before-stop` de failproofai). **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Invocations scriptées spécifiques à autoriser même si elles seraient normalement bloquées. | +| `allowPatterns` | `string[]` | `[]` | Invocations scriptées spécifiques à autoriser même si elles seraient normalement refusées. | **Exemple :** @@ -329,12 +329,12 @@ Les sous-commandes `gh` en lecture seule telles que `gh pr view`, `gh pr list`, ## Secrets (sanitizers) -Empêche les agents de faire fuiter des identifiants dans leur contexte ou leur sortie. Les politiques sanitizer se déclenchent sur les événements **PostToolUse**. Lorsque Claude exécute une commande Bash, lit un fichier ou appelle un outil quelconque, ces politiques inspectent la sortie avant qu'elle ne soit renvoyée à Claude. Si un motif secret est détecté, la politique retourne une décision deny qui empêche la transmission de la sortie. +Empêche les agents de faire fuiter des identifiants dans leur contexte ou leur sortie. Les politiques de sanitisation se déclenchent sur les événements **PostToolUse**. Lorsque Claude exécute une commande Bash, lit un fichier ou appelle un outil, ces politiques inspectent la sortie avant qu'elle ne soit retournée à Claude. Si un motif secret est détecté, la politique retourne une décision de refus qui empêche la sortie d'être transmise. ### `sanitize-jwt` **Événement :** PostToolUse (tous les outils) -**Par défaut :** Masque les tokens JWT (trois segments base64url séparés par `.`). +**Par défaut :** Expurge les tokens JWT (trois segments base64url séparés par `.`). Aucun paramètre. @@ -343,11 +343,11 @@ Aucun paramètre. ### `sanitize-api-keys` **Événement :** PostToolUse (tous les outils) -**Par défaut :** Masque les formats de clés API courants : Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), clés d'accès AWS (`AKIA`), clés Stripe (`sk_live_`, `sk_test_`), et clés API Google (`AIza`). +**Par défaut :** Expurge les formats courants de clés API : Anthropic (`sk-ant-`), OpenAI (`sk-`), PATs GitHub (`ghp_`), clés d'accès AWS (`AKIA`), clés Stripe (`sk_live_`, `sk_test_`), et clés API Google (`AIza`). **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Motifs regex supplémentaires à traiter comme des secrets. | @@ -371,7 +371,7 @@ Aucun paramètre. ### `sanitize-connection-strings` **Événement :** PostToolUse (tous les outils) -**Par défaut :** Masque les chaînes de connexion aux bases de données contenant des identifiants intégrés (par ex. `postgresql://user:password@host/db`). +**Par défaut :** Expurge les chaînes de connexion aux bases de données contenant des identifiants intégrés (ex. `postgresql://user:password@host/db`). Aucun paramètre. @@ -380,7 +380,7 @@ Aucun paramètre. ### `sanitize-private-key-content` **Événement :** PostToolUse (tous les outils) -**Par défaut :** Masque les blocs PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, etc.). +**Par défaut :** Expurge les blocs PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, etc.). Aucun paramètre. @@ -389,7 +389,7 @@ Aucun paramètre. ### `sanitize-bearer-tokens` **Événement :** PostToolUse (tous les outils) -**Par défaut :** Masque les en-têtes `Authorization: Bearer ` dont le token comporte 20 caractères ou plus. +**Par défaut :** Expurge les en-têtes `Authorization: Bearer ` dont le token fait 20 caractères ou plus. Aucun paramètre. @@ -402,9 +402,9 @@ Protège la configuration d'environnement sensible contre la lecture ou l'exposi ### `block-env-files` **Événement :** PreToolUse (Bash, Read) -**Par défaut :** Bloque la lecture des fichiers `.env` via `cat .env`, les appels à l'outil `Read` avec `.env` comme chemin de fichier, etc. +**Par défaut :** Refuse la lecture des fichiers `.env` via `cat .env`, les appels à l'outil `Read` avec `.env` comme chemin de fichier, etc. -Ne bloque pas `.envrc` ni les autres fichiers liés à l'environnement — uniquement les fichiers nommés exactement `.env`. +Ne bloque pas `.envrc` ni d'autres fichiers adjacents à l'environnement — uniquement les fichiers nommés exactement `.env`. Aucun paramètre. @@ -413,7 +413,7 @@ Aucun paramètre. ### `protect-env-vars` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque les commandes qui affichent les variables d'environnement : `printenv`, `env`, `echo $VAR`. +**Par défaut :** Refuse les commandes qui affichent les variables d'environnement : `printenv`, `env`, `echo $VAR`. Aucun paramètre. @@ -421,18 +421,18 @@ Aucun paramètre. ## Accès aux fichiers -Maintient les agents dans les limites du projet et à l'écart des fichiers sensibles. +Maintient les agents à l'intérieur des limites du projet et à l'écart des fichiers sensibles. ### `block-read-outside-cwd` **Événement :** PreToolUse (Read, Bash) -**Par défaut :** Bloque la lecture de fichiers situés en dehors de la racine du projet. La limite est définie par `CLAUDE_PROJECT_DIR` (défini une fois par session par Claude Code), avec repli sur le répertoire de travail courant de la session si cette variable n'est pas définie. L'utilisation de la racine du projet plutôt que du `cwd` en temps réel garantit une limite stable, même après que Claude se soit déplacé dans un sous-répertoire avec `cd`. +**Par défaut :** Refuse la lecture de fichiers en dehors de la racine du projet. La limite est `CLAUDE_PROJECT_DIR` (définie une fois par session par Claude Code), avec repli sur le répertoire de travail courant de la session si cette variable n'est pas définie. Utiliser la racine du projet plutôt que le `cwd` courant garantit que la limite reste stable même après que Claude ait effectué un `cd` dans un sous-répertoire. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Préfixes de chemins absolus autorisés même s'ils se trouvent en dehors de la racine du projet. | +| `allowPaths` | `string[]` | `[]` | Préfixes de chemins absolus autorisés même s'ils sont en dehors de la racine du projet. | **Exemple :** @@ -451,11 +451,11 @@ Maintient les agents dans les limites du projet et à l'écart des fichiers sens ### `block-secrets-write` **Événement :** PreToolUse (Write, Edit) -**Par défaut :** Bloque les écritures dans les fichiers couramment utilisés pour les clés privées et les certificats : `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Par défaut :** Refuse les écritures dans les fichiers couramment utilisés pour les clés privées et les certificats : `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `additionalPatterns` | `string[]` | `[]` | Motifs de noms de fichiers supplémentaires (style glob) à bloquer. | @@ -475,18 +475,18 @@ Maintient les agents dans les limites du projet et à l'écart des fichiers sens ## Git -Prévient les pushs accidentels, les force-pushs et les erreurs de branche difficiles à annuler. +Évite les pushs accidentels, les force-pushs et les erreurs de branche difficiles à annuler. ### `block-push-master` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque `git push origin main` et `git push origin master`. +**Par défaut :** Refuse `git push origin main` et `git push origin master`. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Noms de branches sur lesquelles le push direct est interdit. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Noms de branches sur lesquelles les pushs directs sont interdits. | **Exemple :** @@ -501,7 +501,7 @@ Prévient les pushs accidentels, les force-pushs et les erreurs de branche diffi ``` -Pour autoriser le push sur toutes les branches (ce qui revient à désactiver cette politique sans la retirer de `enabledPolicies`), définissez `protectedBranches: []`. +Pour autoriser les pushs sur toutes les branches (ce qui désactive effectivement cette politique sans la retirer de `enabledPolicies`), définissez `protectedBranches: []`. --- @@ -509,22 +509,22 @@ Pour autoriser le push sur toutes les branches (ce qui revient à désactiver ce ### `block-work-on-main` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque `git commit`, `git merge`, `git rebase` et `git cherry-pick` lorsque l'arbre de travail est sur `main` ou `master`. La création et le changement de branche (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) ne sont pas affectés. +**Par défaut :** Refuse `git commit`, `git merge`, `git rebase` et `git cherry-pick` lorsque l'arbre de travail est sur `main` ou `master`. La création et le changement de branche (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) ne sont pas affectés. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Noms de branches sur lesquelles commit/merge/rebase/cherry-pick est bloqué. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Noms de branches sur lesquelles commit/merge/rebase/cherry-pick sont refusés. | --- ### `block-force-push` **Événement :** PreToolUse (Bash) -**Par défaut :** Bloque `git push --force` et `git push -f`. +**Par défaut :** Refuse `git push --force` et `git push -f`. -Aucun paramètre spécifique à la politique. Utilisez le [`hint`](/fr/configuration#hint-cross-cutting) transversal pour suggérer des alternatives : +Aucun paramètre spécifique à la politique. Utilisez le champ [`hint`](/fr/configuration#hint-cross-cutting) transversal pour suggérer des alternatives : ```json { @@ -559,7 +559,7 @@ Aucun paramètre. ### `warn-all-files-staged` **Événement :** PreToolUse (Bash) -**Par défaut :** Demande à Claude de vérifier ce qu'il indexe lors de l'exécution de `git add -A` ou `git add .`. Ne bloque pas la commande. +**Par défaut :** Demande à Claude de vérifier ce qu'il indexe lorsqu'il exécute `git add -A` ou `git add .`. Ne bloque pas la commande. Aucun paramètre. @@ -567,12 +567,12 @@ Aucun paramètre. ## Base de données -Intercepte les opérations SQL destructives avant qu'elles ne s'exécutent sur votre base de données. +Intercepte les opérations SQL destructives avant leur exécution contre votre base de données. ### `warn-destructive-sql` **Événement :** PreToolUse (Bash) -**Par défaut :** Demande à Claude de confirmer avant d'exécuter un SQL contenant `DROP TABLE`, `DROP DATABASE` ou `DELETE` sans clause `WHERE`. +**Par défaut :** Demande à Claude de confirmer avant d'exécuter du SQL contenant `DROP TABLE`, `DROP DATABASE`, ou `DELETE` sans clause `WHERE`. Aucun paramètre. @@ -598,7 +598,7 @@ Fournit aux agents du contexte supplémentaire avant des opérations potentielle **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `thresholdKb` | `number` | `1024` | Seuil de taille de fichier en kilo-octets au-delà duquel un avertissement est émis. | @@ -641,7 +641,7 @@ Aucun paramètre. ### `warn-global-package-install` **Événement :** PreToolUse (Bash) -**Par défaut :** Demande à Claude de confirmer avant d'exécuter `npm install -g`, `yarn global add` ou `pip install` sans environnement virtuel. +**Par défaut :** Demande à Claude de confirmer avant d'exécuter `npm install -g`, `yarn global add`, ou `pip install` sans environnement virtuel. Aucun paramètre. @@ -654,14 +654,14 @@ Impose les gestionnaires de paquets que l'agent est autorisé à utiliser. ### `prefer-package-manager` **Événement :** PreToolUse (Bash) -**Par défaut :** Désactivé. Lorsqu'il est activé, bloque toute commande d'un gestionnaire de paquets absent de la liste `allowed` et indique à Claude de réécrire la commande en utilisant un gestionnaire autorisé. +**Par défaut :** Désactivé. Une fois activé, bloque toute commande de gestionnaire de paquets absente de la liste `allowed` et demande à Claude de réécrire la commande en utilisant un gestionnaire autorisé. Détecte : pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Noms de gestionnaires de paquets autorisés. Tout gestionnaire détecté absent de cette liste est bloqué. Si vide, la politique n'a aucun effet. | -| `blocked` | string[] | `[]` | Noms de gestionnaires supplémentaires à bloquer au-delà de la liste intégrée (par ex. `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Noms des gestionnaires de paquets autorisés. Tout gestionnaire détecté absent de cette liste est bloqué. Quand la liste est vide, la politique est sans effet. | +| `blocked` | string[] | `[]` | Noms de gestionnaires supplémentaires à bloquer au-delà de la liste intégrée (ex. `['pdm', 'pipx']`). | La liste de blocage intégrée couvre : pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Utilisez `blocked` pour ajouter des gestionnaires absents de cette liste. @@ -679,7 +679,7 @@ La liste de blocage intégrée couvre : pip, pip3, npm, npx, yarn, pnpm, pnpx, b } ``` -Avec cette configuration, `pip install flask` et `pdm install flask` sont tous deux bloqués avec un message indiquant à Claude d'utiliser `uv` ou `bun` à la place. Les commandes comme `uv pip install flask` sont autorisées car `uv` figure dans la liste d'autorisation et est vérifié en premier. +Avec cette configuration, `pip install flask` et `pdm install flask` sont tous deux refusés avec un message demandant à Claude d'utiliser `uv` ou `bun` à la place. Les commandes comme `uv pip install flask` sont autorisées car `uv` figure dans la liste d'autorisation et est vérifié en premier. --- @@ -690,7 +690,7 @@ Détecte quand les agents sont bloqués ou se comportent de manière inattendue. ### `warn-repeated-tool-calls` **Événement :** PreToolUse (tous les outils) -**Par défaut :** Demande à Claude de reconsidérer lorsque le même outil est appelé 3 fois ou plus avec des paramètres identiques — signe courant que l'agent est coincé dans une boucle. +**Par défaut :** Demande à Claude de reconsidérer son action lorsque le même outil est appelé 3 fois ou plus avec des paramètres identiques — signe courant que l'agent est bloqué dans une boucle. Aucun paramètre. @@ -698,40 +698,39 @@ Aucun paramètre. ## Workflow -Impose un workflow de fin de session discipliné. Ces politiques se déclenchent sur l'événement **Stop** et empêchent l'agent de s'arrêter tant que chaque condition n'est pas remplie. Elles suivent une chaîne de dépendance naturelle : commit → push → PR → CI. Si une politique refuse, les politiques suivantes dans la chaîne sont ignorées (court-circuit sur deny). +Impose un workflow discipliné en fin de session. Ces politiques se déclenchent sur l'événement **Stop** et empêchent l'agent de s'arrêter jusqu'à ce que chaque condition soit remplie. Elles suivent une chaîne de dépendances naturelle : commit → push → PR → CI. Si une politique refuse, les politiques suivantes dans la chaîne sont ignorées (court-circuit en cas de refus). -Toutes les politiques de workflow sont **fail-open** : si l'outil requis n'est pas disponible (par ex. `gh` non installé, pas de remote git), la politique autorise avec un message informatif expliquant pourquoi la vérification a été ignorée. +Toutes les politiques de workflow sont **fail-open** : si l'outil requis n'est pas disponible (ex. `gh` non installé, pas de remote git), la politique autorise avec un message informatif expliquant pourquoi la vérification a été ignorée. ### Sémantique Stop par CLI -L'application du Stop se présente légèrement différemment selon les sept CLI supportés, car chacun expose un contrat de hook "agent terminé" différent. Le **résultat** est le même — l'agent ne peut pas s'arrêter tant qu'une porte de workflow est en échec — mais les **mécanismes** diffèrent. Le tableau ci-dessous résume la situation ; seul Pi présente une particularité visible par l'utilisateur qu'il convient de comprendre avant d'activer une politique `require-*-before-stop`. +L'application de Stop se présente légèrement différemment selon les six CLI pris en charge, car chacun expose un contrat de hook différent pour signaler la fin de l'agent. Le **résultat** est identique — l'agent ne peut pas s'arrêter tant qu'une condition de workflow n'est pas satisfaite — mais les **mécanismes** diffèrent. Le tableau ci-dessous résume la situation ; seul Pi présente une particularité visible par l'utilisateur qu'il convient de comprendre avant d'activer une politique `require-*-before-stop`. -| CLI | Quand la porte se déclenche | Ce que vous voyez | +| CLI | Quand la condition se déclenche | Ce que vous observez | |---|---|---| -| Claude Code | Dans la même boucle agent, immédiatement | Claude continue de travailler — résout le problème, puis tente de terminer à nouveau. Aucune interruption visible pour vous. | -| Codex | Dans la même boucle agent, immédiatement | Identique à Claude. | -| GitHub Copilot CLI | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal de relance `{decision:"block", reason}` de Copilot — vérifié empiriquement contre Copilot CLI 1.0.41). | -| Cursor Agent | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal `{followup_message}` de Cursor — limité à `loop_limit`, 5 relances par défaut). | -| Gemini CLI | Dans la même boucle agent, immédiatement | Identique à Claude (utilise le canal `{decision:"block", reason}` de Gemini sur `AfterAgent`). | -| OpenCode | Dans la même boucle agent, immédiatement | Identique à Claude (utilise l'appel SDK `client.session.prompt(...)` d'OpenCode acheminé via `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **Au prochain tour utilisateur** | **Pi s'arrête visiblement** lorsque la porte se déclenche — sa boucle agent se termine et vous êtes renvoyé au prompt. La porte se déclenche ensuite la prochaine fois que vous soumettez un prompt : failproofai ajoute en tête du system prompt de ce tour une directive `MANDATORY ACTION REQUIRED`, demandant au LLM de compléter l'étape de workflow (commit, push, etc.) avant de faire ce que vous avez demandé. | +| Claude Code | Même boucle d'agent, immédiatement | Claude continue de travailler — résout le problème, puis tente de terminer à nouveau. Aucune interruption visible de votre côté. | +| Codex | Même boucle d'agent, immédiatement | Identique à Claude. | +| GitHub Copilot CLI | Même boucle d'agent, immédiatement | Identique à Claude (utilise le canal de réessai `{decision:"block", reason}` de Copilot — vérifié empiriquement contre Copilot CLI 1.0.41). | +| Cursor Agent | Même boucle d'agent, immédiatement | Identique à Claude (utilise le canal `{followup_message}` de Cursor — limité à `loop_limit`, 5 réessais par défaut). | +| OpenCode | Même boucle d'agent, immédiatement | Identique à Claude (utilise l'appel SDK `client.session.prompt(...)` d'OpenCode acheminé via `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **Prochain tour utilisateur** | **Pi s'arrête visiblement** quand la condition se déclenche — sa boucle d'agent se termine et vous revenez au prompt. La condition se déclenche alors la prochaine fois que vous soumettez un prompt : failproofai ajoute en préfixe une directive `MANDATORY ACTION REQUIRED` au prompt système de ce tour, demandant au LLM de compléter l'étape de workflow (commit, push, etc.) avant de faire ce que vous avez demandé. | -**Limitation de Pi.** L'`AgentEndEvent` de Pi (l'équivalent upstream du hook `Stop` de Claude) n'a pas de type Result — au moment où il se déclenche, la boucle agent de Pi a déjà terminé. Pi ne peut pas être forcé à relancer la même boucle comme Claude / Copilot / Cursor / Gemini / OpenCode le peuvent. failproofai déplace la porte vers l'événement `before_agent_start` de Pi (qui se déclenche après le prochain prompt utilisateur) afin que la vérification de workflow s'applique quand même, simplement au tour suivant plutôt qu'au tour courant. +**Limitation de Pi.** L'événement `AgentEndEvent` de Pi (l'équivalent amont du hook `Stop` de Claude) n'a pas de type Result — au moment où il se déclenche, la boucle d'agent de Pi a déjà quitté. Pi ne peut pas être forcé de réessayer la même boucle comme Claude / Copilot / Cursor / OpenCode peuvent le faire. failproofai déplace la condition vers l'événement `before_agent_start` de Pi (qui se déclenche après le prochain prompt utilisateur) afin que la vérification du workflow soit toujours appliquée, mais au tour suivant plutôt qu'au tour courant. **Ce que cela signifie en pratique :** -- Après l'arrêt de Pi, la raison du deny est capturée en mémoire, indexée par l'identifiant de session Pi. Le tout prochain prompt soumis dans le même processus Pi la draine : le LLM voit la directive `MANDATORY ACTION REQUIRED` en tête de son system prompt, effectue le commit (ou le push / ouvre la PR / attend le CI), puis continue avec votre demande. La raison du deny capturée est à usage unique — une fois drainée, la porte est levée. -- La porte est bornée par la durée de vie du processus Pi. Si vous faites `Ctrl+C` sur Pi ou quittez entre deux tours, l'entrée en mémoire est perdue avec le processus et la porte est manquée. Claude, Copilot, Cursor, Gemini et OpenCode ont la même contrainte (tuer l'agent fait manquer la porte) — Pi la rend simplement plus visible car l'agent se termine visiblement avant que la porte ne se déclenche. -- Un deny en attente est également effacé à `session_shutdown` pour toute raison (`new` / `resume` / `fork` / `quit`), afin qu'une porte périmée d'une session précédente ne puisse pas fuiter dans une nouvelle session démarrée dans le même processus Pi. +- Après l'arrêt de Pi, le motif de refus est capturé en mémoire, indexé par l'identifiant de session Pi. Le tout prochain prompt que vous soumettez dans le même processus Pi le consomme : le LLM voit la directive `MANDATORY ACTION REQUIRED` en tête de son prompt système, effectue le commit (ou le push / ouvre la PR / attend le CI), et continue ensuite avec votre demande. Le motif de refus capturé est à usage unique — une fois consommé, la condition est levée. +- La condition est bornée par la durée de vie du processus Pi. Si vous faites `Ctrl+C` sur Pi ou quittez entre deux tours, l'entrée en mémoire est supprimée avec le processus et la condition est manquée. Claude, Copilot, Cursor et OpenCode ont la même contrainte (tuer l'agent fait manquer la condition) — Pi le rend simplement plus visible car l'agent se termine visiblement avant que la condition ne se déclenche. +- Un refus en attente est également effacé lors d'un `session_shutdown` pour n'importe quelle raison (`new` / `resume` / `fork` / `quit`), de sorte qu'une condition obsolète d'une session précédente ne peut pas se propager dans une nouvelle session démarrée dans le même processus Pi. -Si vous avez besoin d'une relance dans la même boucle à la manière de Claude, exécutez vos politiques `Stop` sous l'un des six autres CLI supportés. Nous suivons l'évolution de Pi en amont pour un futur type Result sur `AgentEndEvent` qui nous permettrait de combler cet écart. +Si vous avez besoin d'un réessai dans la même boucle à la façon de Claude, exécutez vos politiques `Stop` sous l'un des cinq autres CLI pris en charge. Nous suivons Pi en amont pour un futur type Result sur `AgentEndEvent` qui nous permettrait de combler cet écart. ### `require-commit-before-stop` **Événement :** Stop -**Par défaut :** Bloque l'arrêt lorsqu'il y a des modifications non commitées (fichiers modifiés, indexés ou non suivis). Retourne un message informatif lorsque le répertoire de travail est propre. +**Par défaut :** Refuse l'arrêt lorsqu'il y a des modifications non commitées (fichiers modifiés, indexés ou non suivis). Retourne un message informatif quand le répertoire de travail est propre. Aucun paramètre. @@ -740,11 +739,11 @@ Aucun paramètre. ### `require-push-before-stop` **Événement :** Stop -**Par défaut :** Bloque l'arrêt lorsqu'il y a des commits non pushés ou lorsque la branche courante n'a pas de branche de suivi distante. Suggère `git push -u` pour créer une branche de suivi si nécessaire. Fail-open si aucun remote n'est configuré. +**Par défaut :** Refuse l'arrêt lorsqu'il y a des commits non poussés ou que la branche courante n'a pas de branche de suivi distante. Suggère `git push -u` pour créer une branche de suivi si nécessaire. Échoue en mode ouvert si aucun remote n'est configuré. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| | `remote` | `string` | `"origin"` | Nom du remote vers lequel pousser. | @@ -765,14 +764,13 @@ Aucun paramètre. ### `require-pr-before-stop` **Événement :** Stop -**Par défaut :** Bloque l'arrêt lorsqu'aucune pull request n'existe pour la branche courante, ou lorsque la PR existante est fermée sans avoir été mergée. Demande à Claude de créer une PR avec `gh pr create`. Lorsque la PR est **mergée**, la politique autorise (le travail est livré) et le message suggère de quitter la branche (`git checkout main && git pull`). +**Par défaut :** Refuse l'arrêt lorsqu'aucune pull request n'existe pour la branche courante, ou lorsque la PR existante est fermée sans avoir été fusionnée. Demande à Claude de créer une PR avec `gh pr create`. Lorsque la PR est **fusionnée**, la politique autorise (le travail a été livré) et le message suggère de changer de branche (`git checkout main && git pull`). Aucun paramètre. -Cette politique nécessite que [GitHub CLI](https://cli.github.com/) (`gh`) soit installé et authentifié. -Exécutez `gh auth login` avec un personal access token ayant le scope `repo` pour accéder en lecture aux -pull requests. Si `gh` n'est pas installé ou non authentifié, la politique fail-open et signale la raison à Claude. +Cette politique requiert que [GitHub CLI](https://cli.github.com/) (`gh`) soit installé et authentifié. +Exécutez `gh auth login` avec un jeton d'accès personnel disposant du scope `repo` pour l'accès en lecture aux pull requests. Si `gh` n'est pas installé ou non authentifié, la politique échoue en mode ouvert et en informe Claude. --- @@ -780,24 +778,21 @@ pull requests. Si `gh` n'est pas installé ou non authentifié, la politique fai ### `require-no-conflicts-before-stop` **Événement :** Stop -**Par défaut :** Bloque l'arrêt lorsque la branche courante ne peut pas être mergée proprement dans la branche de base. La politique vérifie d'abord l'existence d'une PR `OPEN` sur GitHub pour la branche — sans PR, il n'y a pas de cible de merge à appliquer, donc toute la politique court-circuite vers allow. Une fois une PR `OPEN` confirmée, deux sondes indépendantes s'exécutent : +**Par défaut :** Refuse l'arrêt lorsque la branche courante ne peut pas être fusionnée proprement dans la branche de base. La politique vérifie d'abord qu'il existe une PR `OPEN` sur GitHub pour la branche — sans celle-ci, il n'y a pas de cible de fusion à appliquer, donc toute la politique court-circuite vers allow. Une fois une PR `OPEN` confirmée, deux sondes indépendantes s'exécutent : -1. **Locale** — `git merge-tree --write-tree --name-only origin/ HEAD`. En cas de conflit, le message deny liste les fichiers en conflit afin que Claude sache exactement quoi résoudre. -2. **GitHub** — réutilise le résultat `gh pr view --json mergeable,state` déjà récupéré lors de la prévérification. Détecte les conflits qu'un `origin/` local obsolète manquerait (par ex. si quelqu'un a mergé une PR conflictuelle sur `main` depuis le dernier fetch). Un résultat `CONFLICTING` bloque. Un résultat `UNKNOWN` bloque également et demande à Claude d'attendre ~10 secondes et de revérifier avant de tenter un nouvel arrêt — cela évite les faux négatifs pendant que GitHub recalcule. +1. **Locale** — `git merge-tree --write-tree --name-only origin/ HEAD`. En cas de conflit, le message de refus indique les fichiers en conflit afin que Claude sache exactement quoi résoudre. +2. **GitHub** — réutilise le résultat `gh pr view --json mergeable,state` déjà récupéré lors de la pré-vérification. Intercepte les conflits qu'un `origin/` local obsolète manquerait (ex. si quelqu'un a mergé une PR conflictuelle sur `main` depuis le dernier fetch). Un résultat `CONFLICTING` entraîne un refus. Un résultat `UNKNOWN` entraîne également un refus et demande à Claude d'attendre environ 10 secondes et de re-vérifier avant de tenter de s'arrêter à nouveau — cela évite les faux négatifs pendant que GitHub recalcule. -Court-circuite entièrement vers allow lorsque : `gh` n'est pas installé, aucune PR n'existe pour la branche, l'état de la PR n'est pas `OPEN` (par ex. `MERGED`, `CLOSED`), ou `gh pr view` retourne une sortie non analysable. Fail-open également lorsque `origin/` est absent localement ou lorsqu'aucun commit n'est en avance sur la base — ces court-circuits de couche 1 consultent quand même la mergeabilité en cache de la PR avant d'autoriser. +Passe entièrement (autorise) lorsque : `gh` n'est pas installé, aucune PR n'existe pour la branche, l'état de la PR n'est pas `OPEN` (ex. `MERGED`, `CLOSED`), ou `gh pr view` retourne une sortie non parsable. Échoue également en mode ouvert lorsque `origin/` est absent localement ou qu'aucun commit n'est en avance sur la base — ces cas de repli de couche 1 consultent tout de même la fusionnabilité PR mise en cache avant d'autoriser. **Paramètres :** -| Paramètre | Type | Défaut | Description | +| Paramètre | Type | Par défaut | Description | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Branche de base par rapport à laquelle vérifier les conflits. | +| `baseBranch` | `string` | `"main"` | Branche de base contre laquelle vérifier les conflits. | -GitHub CLI (`gh`) est requis pour cette politique. Elle utilise `gh pr view` pour confirmer -l'existence d'une PR `OPEN` avant d'exécuter toute sonde de conflit — sans `gh`, la politique -court-circuite vers allow. Exécutez `gh auth login` avec un personal access token ayant le scope -`repo` pour accéder en lecture aux pull requests. +GitHub CLI (`gh`) est requis pour cette politique. La politique utilise `gh pr view` pour confirmer l'existence d'une PR `OPEN` avant d'exécuter toute sonde de conflit — sans `gh`, la politique court-circuite vers allow. Exécutez `gh auth login` avec un jeton d'accès personnel disposant du scope `repo` pour l'accès en lecture aux pull requests. --- @@ -805,14 +800,13 @@ court-circuite vers allow. Exécutez `gh auth login` avec un personal access tok ### `require-ci-green-before-stop` **Événement :** Stop -**Par défaut :** Bloque l'arrêt lorsque les vérifications CI échouent ou sont encore en cours sur la branche courante. Vérifie à la fois les exécutions de workflows GitHub Actions et les vérifications de bots tiers (par ex. CodeRabbit, SonarCloud, Codecov). Traite les conclusions `skipped`, `cancelled` et `neutral` comme non-échouantes (cette dernière couvre par ex. les alertes Socket Security sur les PRs de contributeurs externes, où l'application signale intentionnellement neutral plutôt que success/failure). Retourne un message informatif lorsque toutes les vérifications réussissent. +**Par défaut :** Refuse l'arrêt lorsque les vérifications CI échouent ou sont toujours en cours sur la branche courante. Vérifie à la fois les exécutions de workflow GitHub Actions et les vérifications de bots tiers (ex. CodeRabbit, SonarCloud, Codecov). Traite les conclusions `skipped`, `cancelled` et `neutral` comme non-échouées (cette dernière couvre par exemple les alertes Socket Security sur les PRs de contributeurs externes, où l'application signale intentionnellement neutral plutôt que success/failure). Retourne un message informatif quand toutes les vérifications passent. Aucun paramètre. -Cette politique nécessite que [GitHub CLI](https://cli.github.com/) (`gh`) soit installé et authentifié. -Exécutez `gh auth login` avec un personal access token ayant le scope `repo` pour accéder en lecture aux -exécutions de workflows Actions et à l'API Checks. Si `gh` n'est pas installé ou non authentifié, la politique fail-open et signale la raison à Claude. +Cette politique requiert que [GitHub CLI](https://cli.github.com/) (`gh`) soit installé et authentifié. +Exécutez `gh auth login` avec un jeton d'accès personnel disposant du scope `repo` pour l'accès en lecture aux exécutions de workflow Actions et à l'API Checks. Si `gh` n'est pas installé ou non authentifié, la politique échoue en mode ouvert et en informe Claude. --- @@ -821,7 +815,7 @@ exécutions de workflows Actions et à l'API Checks. Si `gh` n'est pas installé ## Désactiver des politiques individuelles -Retirez une politique spécifique de `enabledPolicies` dans votre configuration, ou désactivez-la dans l'onglet Politiques du tableau de bord. +Retirez une politique spécifique de `enabledPolicies` dans votre configuration, ou désactivez-la depuis l'onglet Politiques du tableau de bord. ```json { diff --git a/docs/fr/cli/audit.mdx b/docs/fr/cli/audit.mdx index 50e38288..3199db1c 100644 --- a/docs/fr/cli/audit.mdx +++ b/docs/fr/cli/audit.mdx @@ -1,23 +1,22 @@ --- title: Auditer les sessions passées (bêta) -description: "Comptez la fréquence à laquelle l'agent a effectué des actions inutiles ou risquées dans les transcriptions passées" +description: "Comptabiliser la fréquence des actions inutiles ou risquées de l'agent dans les transcriptions passées" --- - **Fonctionnalité bêta.** L'audit est publié en version bêta le temps que nous - recueillions les premiers retours. Le catalogue de détecteurs et le format du - rapport sont susceptibles de changer avant la prochaine version stable. + **Fonctionnalité bêta.** L'audit est fourni en version bêta le temps de recueillir les premiers retours. + Le catalogue de détecteurs et le format des rapports peuvent évoluer avant la prochaine version stable. N'hésitez pas à ouvrir une issue si quelque chose vous semble incorrect. -L'audit rejoue vos transcriptions passées de l'agent CLI à travers le moteur de -politiques de failproofai et génère un rapport visuel partageable sur la **page -du tableau de bord `/audit`** — l'archétype de votre agent, un score de 0 à -100, et précisément quelles politiques auraient détecté quoi. +L'audit rejoue vos transcriptions passées de l'agent CLI dans le moteur de politiques de failproofai +et génère un rapport visuel partageable sur la **page `/audit` du tableau de bord** +— l'archétype de votre agent, un score de 0 à 100, et précisément quelles politiques +auraient détecté quoi. ## Lancer l'audit -Trois façons de démarrer — toutes aboutissent au même rapport `/audit`. +Trois façons de le démarrer — toutes mènent au même rapport `/audit`. @@ -37,62 +36,61 @@ failproofai - `npx -y failproofai audit` télécharge failproofai, lance l'analyse et ouvre - le tableau de bord pour vous — aucune installation préalable requise. + `npx -y failproofai audit` récupère failproofai, lance le scan et ouvre le + tableau de bord automatiquement — rien à installer au préalable. - - `failproofai audit` lance l'analyse dans votre terminal, puis ouvre + + `failproofai audit` exécute le scan dans votre terminal, puis ouvre `localhost:8020/audit` automatiquement une fois terminé. - Lancez `failproofai` et cliquez sur **Audit** dans la barre de navigation - (entre Policies et Projects), ou ouvrez `/audit` directement. + Lancez `failproofai` et cliquez sur **Audit** dans la barre de navigation (entre Policies et + Projects), ou ouvrez `/audit` directement. - Lancez `failproofai audit -h` (ou `--help`) pour afficher l'aide. L'audit - s'exécute **entièrement hors ligne** — aucun compte ni connexion réseau requis - — et le tableau de bord reste actif jusqu'à ce que vous l'arrêtiez avec - `Ctrl+C`. + Exécutez `failproofai audit -h` (ou `--help`) pour afficher l'aide. L'audit fonctionne **entièrement + hors ligne** — aucun compte ni connexion réseau requis — et le tableau de bord reste actif + jusqu'à ce que vous l'arrêtiez avec `Ctrl+C`. -Le tableau de bord analyse les transcriptions passées de l'agent CLI sur cette machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) et indique à quelle fréquence l'agent a effectué des actions que failproofai est conçu pour bloquer — vérifications de variables d'environnement, push forcés, préfixes `cd ` redondants, boucles de polling avec sleep, relecture de fichiers venant d'être édités, et bien d'autres. +Le tableau de bord analyse les transcriptions passées de l'agent CLI sur cette machine (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) et indique la fréquence à laquelle l'agent a effectué des actions que failproofai est conçu pour bloquer — vérifications de variables d'environnement, push forcés, préfixes `cd ` redondants, boucles de polling avec sleep, relecture de fichiers récemment modifiés, et bien plus encore. -Pour chaque transcription, chaque événement d'utilisation d'outil est rejoué à travers les 39 politiques intégrées **et** à travers 8 détecteurs exclusifs à l'audit qui repèrent des motifs non encore couverts par les politiques en temps réel. Les comptages sont agrégés par politique / détecteur sur l'ensemble des sessions. +Pour chaque transcription, chaque événement d'appel d'outil est rejoué à travers les 39 politiques intégrées **et** à travers 8 détecteurs exclusifs à l'audit qui repèrent des schémas non encore couverts par les politiques d'exécution en temps réel. Les occurrences sont agrégées par politique / détecteur sur l'ensemble des sessions. ## Ce que vous obtenez -La page `/audit` est une **affiche** plein écran partageable, suivie de quatre sections situées sous le pli : +La page `/audit` est une **affiche** plein écran et partageable, suivie de quatre sections situées en dessous : -1. **Affiche** — l'identité de votre agent en un coup d'œil : son **archétype** (l'un des 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), ses mots-clés de persona, la rareté de cet archétype, et un **score de 0 à 100** avec un niveau (`S` jusqu'à `bottom tier`). Conçue pour être partagée — publiez-la sur X ou LinkedIn, ou téléchargez-la en PNG. -2. **`// strengths`** — ce que votre agent fait déjà bien, exprimé en chiffres réels issus de l'analyse (ex. : taux d'appels d'outils propres, `0` tentative de push sur main), affiché uniquement lorsque la politique concernée affiche un bilan sans faille. -3. **`// quirks`** — ce qui a échappé : un tableau classé des comportements que failproofai aurait détectés — *quand* c'est arrivé la dernière fois, *ce qui a échappé* (et la politique intégrée qui l'aurait bloqué), sa *sévérité*, et la fréquence à laquelle c'a été *observé* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — la liste des correctifs recommandés : une ligne par politique avec un `failproofai policy add ` à copier-coller, ainsi qu'un bouton **install all** qui active toutes les recommandations en une fois et affiche votre **score projeté** si vous le faisiez. -5. **`// come back better`** — ancrez la bonne habitude : définissez un **rappel** par e-mail pour un nouvel audit (`3d` / `7d` / `14d` / `30d`) ou relancez l'audit maintenant, et **invitez un ami** à effectuer son propre audit (envoyé depuis failproof.ai, en Cc à vous). Les rappels et invitations nécessitent une connexion — voir [`failproofai auth`](/fr/cli/auth). +1. **Affiche** — l'identité de votre agent en un coup d'œil : son **archétype** (l'un des 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), ses mots-clés de persona, la rareté de cet archétype, et un **score de 0 à 100** avec un niveau associé (de `S` jusqu'à `bottom tier`). Conçue pour être partagée — publiez-la sur X ou LinkedIn, ou téléchargez-la en PNG. +2. **`// strengths`** — ce que votre agent fait déjà bien, illustré par des chiffres concrets issus du scan (ex. : taux d'appels d'outils propres, `0` tentative de push sur main), affiché uniquement lorsque la politique concernée présente un bilan irréprochable. +3. **`// quirks`** — ce qui est passé à travers les mailles : un tableau classé des comportements que failproofai aurait interceptés — *quand* c'est arrivé pour la dernière fois, *ce qui a glissé* (et la politique intégrée qui l'aurait bloqué), sa *sévérité*, et sa fréquence (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — la liste des correctifs recommandés : une ligne par politique avec une commande `failproofai policy add ` prête à copier-coller, plus un bouton **install all** qui active toutes les recommandations en une seule action et affiche votre **score projeté** si vous le faites. +5. **`// come back better`** — ancrez la bonne habitude : programmez un **rappel** par e-mail pour un nouvel audit (`3d` / `7d` / `14d` / `30d`) ou relancez l'audit immédiatement, et **invitez un ami** à effectuer le sien (envoyé depuis failproof.ai, avec copie à vous). Les rappels et invitations nécessitent une connexion — voir [`failproofai auth`](/fr/cli/auth). ## Détecteurs exclusifs à l'audit -Ces détecteurs repèrent des motifs de comportement inefficaces qui ne sont pas (encore) appliqués en temps réel. Ils ne s'exécutent que pendant l'audit et ne bloquent jamais un appel d'outil en direct. +Ces détecteurs repèrent des schémas de comportements problématiques non encore appliqués en temps réel. Ils s'exécutent uniquement pendant l'audit et ne bloquent jamais un appel d'outil en direct. -| Détecteur | Ce qu'il compte | +| Détecteur | Ce qu'il comptabilise | |---|---| | `redundant-cd-cwd` | Commandes Bash commençant par `cd && …` alors que les commandes s'exécutent déjà dans `cwd`. | | `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` sur un seul fichier source — utilisez plutôt l'outil `Read`. | | `prefer-edit-over-sed-awk` | Modifications en place avec `sed -i` / `awk … > file` — utilisez plutôt l'outil `Edit`. | -| `prefer-write-over-heredoc` | Écriture de fichiers via heredoc / `echo > file` multi-ligne — utilisez plutôt l'outil `Write`. | -| `sleep-polling-loop` | Longues pauses `sleep N` (≥ 30s) ou boucles de polling `while …; sleep …; done`. | +| `prefer-write-over-heredoc` | Écriture de fichiers via heredoc / `echo > file` multiligne — utilisez plutôt l'outil `Write`. | +| `sleep-polling-loop` | Longs `sleep N` (≥ 30s) ou boucles de polling `while …; sleep …; done`. | | `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — limitez la portée à `cwd`. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, contournant les hooks. | -| `reread-after-edit` | Lecture (`Read`) d'un fichier qui vient d'être modifié via `Edit`/`Write` dans la même session. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, en ignorant les hooks. | +| `reread-after-edit` | Lecture (`Read`) d'un fichier qui vient d'être modifié (`Edit`/`Write`) dans la même session. | ## Caches -- **Cache par transcription** dans `~/.failproofai/cache/audit/.json`, indexé par `(mtime, size, engineVersion, detectorVersion)` — invalidé automatiquement lorsque la transcription ou le code des politiques/détecteurs change. Chaque entrée stocke également un horodatage `cachedAt` comme **métadonnée TTL** (ne faisant pas partie de la clé de cache) ; les entrées de plus de **7 jours** sont rejetées à la lecture afin que des résultats anciens ne survivent pas à l'évolution des détecteurs. -- **Cache du résultat global** dans `~/.failproofai/audit-dashboard.json` (mode 0600). Permet au tableau de bord de s'afficher instantanément lors de la navigation sans relancer l'analyse. Également rejeté à la lecture au-delà du **TTL de 7 jours** — `/audit` bascule alors vers son état vide et invite à relancer une analyse. Cliquez sur `[ re-audit now ]` en bas du rapport pour actualiser — le re-audit envoie `noCache: true`, ce qui contourne le cache par transcription et ré-analyse chaque transcription au lieu de retourner le résultat mis en cache ; l'exécution diffuse sa progression via une bannière épinglée en haut et remplace le résultat en place en cas de succès (sans rechargement de page ; un re-audit échoué conserve le rapport précédent). +- **Cache par transcription** dans `~/.failproofai/cache/audit/.json`, indexé par `(mtime, size, engineVersion, detectorVersion)` — invalidé automatiquement lorsque la transcription ou le code de politique/détecteur change. Chaque entrée stocke également un horodatage `cachedAt` en tant que **métadonnée TTL** (non incluse dans la clé de cache) ; les entrées de plus de **7 jours** sont rejetées à la lecture afin que des résultats anciens ne survivent pas à l'évolution des détecteurs. +- **Cache du résultat global** dans `~/.failproofai/audit-dashboard.json` (mode 0600). Permet au tableau de bord de s'afficher instantanément lors de la navigation sans relancer l'analyse. Également rejeté à la lecture passé le **TTL de 7 jours** — `/audit` bascule alors sur son état vide et invite à relancer un scan. Cliquez sur `[ re-audit now ]` en bas du rapport pour actualiser — le ré-audit envoie `noCache: true`, ce qui contourne le cache par transcription et re-scanne toutes les transcriptions au lieu de retourner le résultat mis en cache ; l'exécution diffuse sa progression via une bannière collante en haut de page et remplace le résultat en place dès que c'est terminé (sans rechargement de page ; un ré-audit échoué conserve le rapport précédent). ## Remarques -- **Aucune mutation.** L'audit rejoue en mode lecture seule. `warn-repeated-tool-calls` est ignoré car son fichier sidecar par session serait autrement modifié. -- **Politiques de workflow ignorées.** Les politiques `require-*-before-stop` ne se déclenchent que sur les événements `Stop` et utilisent `execSync` sur l'état git actif — elles n'ont pas d'interprétation significative dans un contexte rétroactif type « qu'aurait-il se passé en 2025 », et n'apparaissent donc pas dans les comptages de l'audit. +- **Aucune modification.** L'audit s'exécute en mode lecture seule. `warn-repeated-tool-calls` est ignoré car son fichier sidecar par session serait autrement modifié. +- **Politiques de workflow ignorées.** Les politiques `require-*-before-stop` se déclenchent uniquement sur les événements `Stop` et s'exécutent de manière synchrone contre l'état git en direct — elles n'ont pas d'interprétation significative du type « qu'aurait-il s'est passé en 2025 », et n'apparaissent donc pas dans les comptages de l'audit. - **Politiques personnalisées ignorées.** Les hooks personnalisés fournis par l'utilisateur ne sont pas rejoués (ils peuvent avoir changé depuis la session d'origine). \ No newline at end of file diff --git a/docs/fr/configuration.mdx b/docs/fr/configuration.mdx index 81c44d79..c9a73e5b 100644 --- a/docs/fr/configuration.mdx +++ b/docs/fr/configuration.mdx @@ -1,10 +1,10 @@ --- title: Configuration -description: "Format du fichier de configuration, système à trois niveaux et règles de fusion" +description: "Format des fichiers de configuration, système à trois niveaux et règles de fusion" icon: gear --- -failproofai utilise des fichiers de configuration JSON pour contrôler quelles politiques sont actives, comment elles se comportent et où charger les politiques personnalisées. La configuration est conçue pour être facilement partageable avec votre équipe — commitez-la dans votre dépôt et chaque développeur bénéficie du même filet de sécurité pour l'agent. +failproofai utilise des fichiers de configuration JSON pour contrôler quelles politiques sont actives, comment elles se comportent et où les politiques personnalisées sont chargées. La configuration est conçue pour être facilement partagée avec votre équipe — commitez-la dans votre dépôt et chaque développeur bénéficie du même filet de sécurité pour les agents. --- @@ -14,11 +14,11 @@ Il existe trois niveaux de configuration, évalués par ordre de priorité : | Niveau | Chemin du fichier | Rôle | |--------|-------------------|------| -| **project** | `.failproofai/policies-config.json` | Paramètres par dépôt, committés dans le contrôle de version | -| **local** | `.failproofai/policies-config.local.json` | Substitutions personnelles par dépôt, ignorées par git | -| **global** | `~/.failproofai/policies-config.json` | Valeurs par défaut au niveau utilisateur pour tous les projets | +| **project** | `.failproofai/policies-config.json` | Paramètres par dépôt, commités dans le contrôle de version | +| **local** | `.failproofai/policies-config.local.json` | Surcharges personnelles par dépôt, ignorées par git | +| **global** | `~/.failproofai/policies-config.json` | Valeurs par défaut au niveau utilisateur, pour tous les projets | -Lorsque failproofai reçoit un événement de hook, il charge et fusionne les trois fichiers qui existent pour le répertoire de travail courant. +Lorsque failproofai reçoit un événement hook, il charge et fusionne les trois fichiers qui existent pour le répertoire de travail courant. ### Règles de fusion @@ -42,11 +42,11 @@ resolved: { allowPatterns: ["sudo apt-get update"] } ← project l'emporte, gl ``` ```text -project: (pas d'entrée block-sudo) -local: (pas d'entrée block-sudo) +project: (aucune entrée block-sudo) +local: (aucune entrée block-sudo) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← redescend jusqu'au global +resolved: { allowPatterns: ["sudo systemctl status"] } ← remonte jusqu'au global ``` **`customPoliciesPath`** — le premier niveau qui le définit l'emporte. @@ -102,7 +102,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← redescend jusqu'au g Type : `string[]` -Liste des noms de politiques à activer. Les noms doivent correspondre exactement aux identifiants de politique affichés par `failproofai policies`. Consultez [Built-in Policies](/fr/built-in-policies) pour la liste complète. +Liste des noms de politiques à activer. Les noms doivent correspondre exactement aux identifiants de politiques affichés par `failproofai policies`. Consultez [Politiques intégrées](/fr/built-in-policies) pour la liste complète. Les politiques absentes de `enabledPolicies` sont inactives, même si elles ont des entrées dans `policyParams`. @@ -110,7 +110,7 @@ Les politiques absentes de `enabledPolicies` sont inactives, même si elles ont Type : `Record>` -Substitutions de paramètres par politique. La clé externe est le nom de la politique ; les clés internes sont spécifiques à chaque politique. Chaque politique documente ses paramètres disponibles dans [Built-in Policies](/fr/built-in-policies). +Surcharges de paramètres par politique. La clé externe est le nom de la politique ; les clés internes sont spécifiques à chaque politique. Chaque politique documente ses paramètres disponibles dans [Politiques intégrées](/fr/built-in-policies). Si une politique possède des paramètres mais que vous ne les spécifiez pas, les valeurs par défaut intégrées de la politique sont utilisées. Les utilisateurs qui ne configurent pas `policyParams` du tout obtiennent un comportement identique aux versions précédentes. @@ -120,9 +120,9 @@ Les clés inconnues dans le bloc de paramètres d'une politique sont silencieuse Type : `string` (optionnel) -Un message ajouté à la raison lorsqu'une politique renvoie `deny` ou `instruct`. Utilisez-le pour donner à Claude des indications exploitables sans modifier la politique elle-même. +Un message ajouté à la raison lorsqu'une politique retourne `deny` ou `instruct`. Utilisez-le pour donner à Claude des instructions exploitables sans modifier la politique elle-même. -Fonctionne avec n'importe quel type de politique — intégrée, personnalisée (`custom/`), convention de projet (`.failproofai-project/`) ou convention utilisateur (`.failproofai-user/`). +Fonctionne avec tout type de politique — intégrée, personnalisée (`custom/`), convention de projet (`.failproofai-project/`) ou convention utilisateur (`.failproofai-user/`). ```json { @@ -141,9 +141,9 @@ Fonctionne avec n'importe quel type de politique — intégrée, personnalisée } ``` -Lorsque `block-force-push` refuse, Claude voit : *« Force-pushing is blocked. Try creating a fresh branch instead. »* +Lorsque `block-force-push` refuse, Claude voit : *"Force-pushing is blocked. Try creating a fresh branch instead."* -Les valeurs non-chaînes et les chaînes vides sont silencieusement ignorées. Si `hint` n'est pas défini, le comportement reste inchangé (rétrocompatible). +Les valeurs non-textuelles et les chaînes vides sont silencieusement ignorées. Si `hint` n'est pas défini, le comportement est inchangé (rétrocompatible). ### `customPoliciesPath` @@ -151,24 +151,24 @@ Type : `string` (chemin absolu) Chemin vers un fichier JavaScript contenant des politiques de hook personnalisées. Ce champ est défini automatiquement par `failproofai policies --install --custom ` (le chemin est résolu en absolu avant d'être stocké). -Le fichier est chargé à nouveau à chaque événement de hook — il n'y a pas de mise en cache. Consultez [Custom Policies](/fr/custom-policies) pour les détails de création. +Le fichier est rechargé à chaque événement hook — il n'y a pas de mise en cache. Consultez [Politiques personnalisées](/fr/custom-policies) pour les détails de création. -### Politiques basées sur les conventions +### Politiques basées sur des conventions -En plus du `customPoliciesPath` explicite, failproofai découvre et charge automatiquement les fichiers de politiques depuis les répertoires `.failproofai/policies/` : +En plus de l'explicite `customPoliciesPath`, failproofai découvre et charge automatiquement les fichiers de politiques depuis les répertoires `.failproofai/policies/` : | Niveau | Répertoire | Portée | -|--------|------------|--------| +|--------|-----------|--------| | Projet | `.failproofai/policies/` | Partagé avec l'équipe via le contrôle de version | | Utilisateur | `~/.failproofai/policies/` | Personnel, s'applique à tous les projets | -**Correspondance de fichiers :** Seuls les fichiers correspondant à `*policies.{js,mjs,ts}` sont chargés (par exemple `security-policies.mjs`, `workflow-policies.js`). Les autres fichiers du répertoire sont ignorés. +**Correspondance de fichiers :** Seuls les fichiers correspondant à `*policies.{js,mjs,ts}` sont chargés (ex. : `security-policies.mjs`, `workflow-policies.js`). Les autres fichiers du répertoire sont ignorés. -**Aucune configuration requise :** Les politiques de convention ne nécessitent aucune entrée dans `policies-config.json`. Déposez simplement des fichiers dans le répertoire et ils seront pris en compte au prochain événement de hook. +**Aucune configuration requise :** Les politiques de convention ne nécessitent aucune entrée dans `policies-config.json`. Déposez simplement les fichiers dans le répertoire et ils seront pris en compte au prochain événement hook. -**Chargement par union :** Les répertoires de convention du projet et de l'utilisateur sont tous deux analysés. Tous les fichiers correspondants des deux niveaux sont chargés (contrairement à `customPoliciesPath` qui utilise la règle premier-niveau-gagnant). +**Chargement cumulatif :** Les répertoires de convention du projet et de l'utilisateur sont tous les deux analysés. Tous les fichiers correspondants des deux niveaux sont chargés (contrairement à `customPoliciesPath` qui utilise le premier niveau gagnant). -Consultez [Custom Policies](/fr/custom-policies) pour plus de détails et d'exemples. +Consultez [Politiques personnalisées](/fr/custom-policies) pour plus de détails et d'exemples. ### `llm` @@ -189,20 +189,24 @@ Configuration du client LLM pour les politiques qui effectuent des appels IA. No ## Gestion de la configuration depuis la CLI -Les commandes `policies --install` et `policies --uninstall` écrivent dans le fichier de paramètres des hooks de votre CLI agent (les points d'entrée des hooks), tandis que `policies-config.json` est le fichier que vous gérez directement. Les deux sont distincts : +Les commandes `policies --install` et `policies --uninstall` écrivent dans le fichier de paramètres de hook de votre CLI agent (les points d'entrée du hook), tandis que `policies-config.json` est le fichier que vous gérez directement. Les deux sont distincts : - **Paramètres de la CLI agent** — indique à l'agent d'appeler `failproofai --hook ` à chaque utilisation d'outil : - **Claude Code** : `~/.claude/settings.json` (utilisateur), `/.claude/settings.json` (projet), `/.claude/settings.local.json` (local) - **OpenAI Codex** : `~/.codex/hooks.json` (utilisateur), `/.codex/hooks.json` (projet) — Codex n'a pas de niveau `local` - - **GitHub Copilot CLI _(bêta)_** : `~/.copilot/hooks/failproofai.json` (utilisateur), `/.github/hooks/failproofai.json` (projet) — Copilot n'a pas de niveau `local`. Les entrées de hook utilisent les champs de commande `bash`/`powershell` à clé OS de Copilot avec `timeoutSec` ; le fichier porte un marqueur `version: 1` au niveau racine. La prise en charge de Copilot CLI est en **bêta** pendant que nous vérifions le schéma d'enregistrement `events.jsonl` (que la documentation publique ne spécifie pas) contre davantage de sessions réelles. - - **Cursor Agent _(bêta)_** : `~/.cursor/hooks.json` (utilisateur), `/.cursor/hooks.json` (projet) — Cursor n'a pas de niveau `local`. Les entrées de hook utilisent la forme `{type, command, timeout}` inspirée de Claude (sans séparation `bash`/`powershell`), mais stockées sous des clés d'événement en camelCase (`preToolUse`, `beforeSubmitPrompt`, …) dans un tableau plat selon le [schéma de hooks](https://cursor.com/docs/hooks) de Cursor ; le fichier porte un marqueur `version: 1` au niveau racine. Le gestionnaire canonicalise camelCase → PascalCase via `CURSOR_EVENT_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. La prise en charge de Cursor Agent est en **bêta** pendant que nous vérifions le format de transcription sur disque de Cursor (non spécifié dans la documentation publique) contre davantage d'installations réelles. - - **OpenCode _(bêta)_** : `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (utilisateur), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projet) — OpenCode n'a pas de niveau `local`. Contrairement aux six autres CLI, OpenCode **n'a pas de système de hook par commande externe** : il charge des plugins JS/TS en cours de processus explicitement enregistrés via le tableau `plugin: []` dans `opencode.json` (la découverte automatique depuis `.opencode/plugins/` **n'est pas** le mode de chargement des plugins sur opencode v1.14.33). L'installation dépose un petit shim de plugin généré qui appelle le binaire failproofai en sous-processus et traduit la réponse JSON en forme Claude du binaire vers la sémantique du plugin : `throw new Error()` pour le refus d'événement outil (annule l'appel d'outil), `client.session.prompt(...)` pour instruct ET pour le refus `Stop` / `SubagentStop` (soumet le motif de refus comme prochain message utilisateur — le seul canal de nouvelle tentative forcée puisque `session.idle` est uniquement pour les notifications et qu'une exception levée depuis celui-ci est un no-op), et no-op pour allow. Le shim canonicalise les noms d'outils (minuscules → PascalCase via `OPENCODE_TOOL_MAP`) et les clés d'arguments d'entrée d'outil (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` pour `Read` / `Write` / `Edit`, par exemple `filePath` → `file_path`, `oldString` → `old_string`) avant de transmettre au binaire, de sorte que les politiques intégrées de vérification de chemin comme `block-read-outside-cwd`, `block-env-files` et `block-secrets-write` se déclenchent sans modification sur les appels d'outils OpenCode. Les sessions vivent dans la base de données SQLite d'opencode à `~/.local/share/opencode/opencode.db` ; la visionneuse de sessions du tableau de bord les lit via `opencode db --format json` et `opencode export `. La prise en charge d'OpenCode est en **bêta** pendant que nous vérifions le comportement entre les versions et contre davantage de sessions réelles. Consultez la [documentation des plugins OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(bêta)_** : `~/.pi/agent/settings.json` (utilisateur), `/.pi/settings.json` (projet) — Pi n'a pas de niveau `local`. Pi charge des packages d'extension TypeScript au démarrage ; le fichier de paramètres est un tableau de chaînes plat `{"packages": ["./relative/path", …]}`. failproofai écrit une seule entrée dans le tableau packages pointant vers son répertoire `pi-extension/` intégré. L'extension s'abonne en interne aux événements `tool_call` / `user_bash` / `input` / `session_start` de Pi et exécute `failproofai --hook --cli pi` en shell ; le gestionnaire canonicalise les événements underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. Les arguments d'entrée d'outil sont également canonicalisés via `PI_TOOL_INPUT_MAP` (les commandes Read / Write / Edit de Pi livrent `path` plutôt que `file_path` ; mapper la clé de niveau supérieur permet à `block-env-files` et `block-secrets-write` de se déclencher — `block-read-outside-cwd` avait déjà un fallback `path`). La prise en charge de Pi est en **bêta** pendant que l'API d'extension de Pi et la disposition du journal de session se stabilisent. - - **Gemini CLI _(bêta)_** : `~/.gemini/settings.json` (utilisateur), `/.gemini/settings.json` (projet) — Gemini n'a pas de niveau `local` (il documente un niveau `system` à `/etc/gemini-cli/settings.json` que failproofai n'expose pas). Les entrées de hook utilisent la forme `{type, command, timeout}` de Claude enveloppée dans le schéma de correspondance `{matcher, hooks: [...]}` de Gemini avec `matcher: "*"` par défaut. Les événements sont en PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`) ; le gestionnaire mappe vers les noms canoniques Claude via `GEMINI_EVENT_MAP`. Les noms d'outils sont en snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — le gestionnaire canonicalise via `GEMINI_TOOL_MAP` afin que les politiques intégrées existantes se déclenchent sans modification. L'évaluateur de politiques émet la forme plate `{decision: "deny", reason}` de Gemini (recommandée selon la règle d'or exit-0 de Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` pour l'injection de contexte sur BeforeAgent / AfterTool / SessionStart, et `{decision: "block", reason}` sur AfterAgent pour la sémantique de nouvelle tentative forcée. La prise en charge de Gemini CLI est en **bêta** pendant que nous élargissons la couverture réelle. Consultez la [documentation des hooks Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)** : `~/.hermes/config.yaml` (**niveau utilisateur uniquement** — Hermes n'a pas de configuration projet/local). Hermes est une **passerelle** Slack/Telegram, donc une seule installation intercepte les appels d'outils de toutes les plateformes (Slack/Telegram/cli/cron) **et** des sous-agents internes. Les entrées de hook sont une paire `{command, timeout}` (timeout en **secondes**) sous une map `hooks:` indexée par les événements snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) ; le gestionnaire canonicalise les événements via `HERMES_EVENT_MAP` et les noms d'outils via `HERMES_TOOL_MAP` afin que les politiques intégrées se déclenchent sans modification. La configuration est modifiée via un aller-retour `Document` YAML préservant les commentaires, de sorte que les autres paramètres de l'opérateur survivent, et l'installation définit `hooks_auto_accept: true` pour que la passerelle sans tête (sans TTY) exécute les hooks sans invite de consentement. L'évaluateur émet le contrat stdout `{"decision":"block","reason"}` de Hermes (Hermes ignore les codes de sortie). **Limitations :** Hermes n'a pas d'événement `Stop` de fin de tour, donc les politiques intégrées `require-*-before-stop` ne se déclenchent jamais pour lui (non applicable, pas cassé) ; `instruct` se dégrade en allow-avec-note-journalisée (pas de canal de contexte supplémentaire) ; et la redaction des secrets en sortie (`sanitize-*`) ne peut pas réécrire la sortie d'outil via le contrat de hook shell. Hermes est **également** une source d'**audit** hors ligne — le tableau de bord lit ses sessions de passerelle directement depuis `~/.hermes/state.db`. + - **GitHub Copilot CLI _(bêta)_** : `~/.copilot/hooks/failproofai.json` (utilisateur), `/.github/hooks/failproofai.json` (projet) — Copilot n'a pas de niveau `local`. Les entrées de hook utilisent les champs de commande `bash`/`powershell` keyed par OS de Copilot avec `timeoutSec` ; le fichier porte un marqueur de niveau supérieur `version: 1`. La prise en charge de Copilot CLI est en **bêta** pendant que nous vérifions le schéma d'enregistrement `events.jsonl` (que la documentation publique ne spécifie pas) contre davantage de sessions réelles. **Le mode agent VS Code Copilot Chat (Preview)** lit les configurations de hook depuis `.github/hooks/*.json`, `~/.copilot/hooks/*.json` et `~/.claude/settings.json` (gouverné par le paramètre `chat.hookFilesLocations`) en utilisant le même contrat Claude `{hookSpecificOutput:{permissionDecision:"deny",…}}` — ce sont exactement les chemins que cette intégration `copilot` et l'intégration `claude` (`~/.claude/settings.json`) écrivent déjà, donc `failproofai policies --install --cli copilot` (ou `--cli claude`) **applique déjà les règles en mode agent VS Code** sans nécessiter d'intégration `vscode` séparée (confirmé en direct depuis les journaux de découverte de VS Code). + - **Cursor Agent _(bêta)_** : `~/.cursor/hooks.json` (utilisateur), `/.cursor/hooks.json` (projet) — Cursor n'a pas de niveau `local`. Les entrées de hook utilisent le format Claude `{type, command, timeout}` (sans séparation `bash`/`powershell`), mais stockées sous des clés d'événements camelCase (`preToolUse`, `beforeSubmitPrompt`, …) dans un tableau plat selon le [schéma de hooks de Cursor](https://cursor.com/docs/hooks) ; le fichier porte un marqueur de niveau supérieur `version: 1`. Le gestionnaire canonicalise camelCase → PascalCase via `CURSOR_EVENT_MAP` pour que les politiques intégrées existantes se déclenchent sans modification. La prise en charge de Cursor Agent est en **bêta** pendant que nous vérifions le format de transcription sur disque de Cursor (non spécifié dans la documentation publique) contre davantage d'installations réelles. + - **OpenCode _(bêta)_** : `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (utilisateur), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projet) — OpenCode n'a pas de niveau `local`. Contrairement aux cinq autres CLI, OpenCode **n'a pas de système de hook par commande externe** : il charge des plugins JS/TS en cours de processus, explicitement enregistrés via le tableau `plugin: []` dans `opencode.json` (la découverte automatique depuis `.opencode/plugins/` n'est **pas** la façon dont les plugins se chargent sur opencode v1.14.33). L'installation dépose un petit shim de plugin généré qui appelle le binaire failproofai en sous-processus et traduit la réponse JSON au format Claude du binaire en sémantique de plugin : `throw new Error()` pour le refus d'événement outil (annule l'appel outil), `client.session.prompt(...)` pour instruct ET pour le refus `Stop` / `SubagentStop` (soumet la raison du refus comme prochain message utilisateur — le seul canal de force-retry puisque `session.idle` est uniquement pour les notifications et que lancer une exception depuis celui-ci est sans effet), et sans opération pour allow. Le shim canonicalise les noms d'outils (minuscules → PascalCase via `OPENCODE_TOOL_MAP`) et les clés d'arguments d'entrée d'outil (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` pour `Read` / `Write` / `Edit`, ex. `filePath` → `file_path`, `oldString` → `old_string`) avant transmission au binaire, de sorte que les politiques intégrées de vérification de chemin comme `block-read-outside-cwd`, `block-env-files` et `block-secrets-write` se déclenchent sans modification sur les appels outils OpenCode. Les sessions vivent dans la base de données SQLite d'opencode à `~/.local/share/opencode/opencode.db` ; le visualiseur de sessions du tableau de bord les lit via `opencode db --format json` et `opencode export `. La prise en charge d'OpenCode est en **bêta** pendant que nous vérifions le comportement sur différentes versions et contre davantage de sessions réelles. Consultez la [documentation des plugins OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(bêta)_** : `~/.pi/agent/settings.json` (utilisateur), `/.pi/settings.json` (projet) — Pi n'a pas de niveau `local`. Pi charge des packages d'extension TypeScript au démarrage ; le fichier de paramètres est un tableau de chaînes plat `{"packages": ["./relative/path", …]}`. failproofai écrit une seule entrée dans le tableau packages pointant vers son répertoire `pi-extension/` intégré. L'extension souscrit en interne aux événements `tool_call` / `user_bash` / `input` / `session_start` de Pi et exécute `failproofai --hook --cli pi` en shell ; le gestionnaire canonicalise underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` pour que les politiques intégrées existantes se déclenchent sans modification. Les arguments d'entrée d'outil sont également canonicalisés via `PI_TOOL_INPUT_MAP` (Read / Write / Edit de Pi livrent `path` plutôt que `file_path` ; le mappage de la clé de niveau supérieur permet à `block-env-files` et `block-secrets-write` de se déclencher — `block-read-outside-cwd` avait déjà un fallback `path`). La prise en charge de Pi est en **bêta** pendant que l'API d'extension de Pi et la disposition des journaux de session se stabilisent. + - **Hermes (hermes-agent)** : `~/.hermes/config.yaml` (**niveau utilisateur uniquement** — Hermes n'a pas de configuration projet/local). Hermes est une **passerelle** Slack/Telegram, donc une installation intercepte les appels outils de chaque plateforme (Slack/Telegram/cli/cron) **et** des sous-agents internes. Les entrées de hook sont une paire `{command, timeout}` (timeout en **secondes**) sous un mapping `hooks:` keyed par les événements snake_case de Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) ; le gestionnaire canonicalise les événements via `HERMES_EVENT_MAP` et les noms d'outils via `HERMES_TOOL_MAP` pour que les politiques intégrées se déclenchent sans modification. La configuration est modifiée via un aller-retour YAML `Document` préservant les commentaires pour que les autres paramètres de l'opérateur survivent, et l'installation définit `hooks_auto_accept: true` pour que la passerelle sans tête (sans TTY) exécute les hooks sans invite de consentement. L'évaluateur émet le contrat stdout `{"decision":"block","reason"}` de Hermes (Hermes ignore les codes de sortie). **Limitations :** Hermes n'a pas d'événement `Stop` de fin de tour, donc les politiques intégrées `require-*-before-stop` ne se déclenchent jamais (non applicable, pas cassé) ; `instruct` se dégrade en allow avec note journalisée (pas de canal de contexte supplémentaire) ; et la rédaction des secrets en sortie (`sanitize-*`) ne peut pas réécrire la sortie outil via le contrat hook shell. Hermes est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses sessions de passerelle directement depuis `~/.hermes/state.db`. + - **OpenClaw (passerelle openclaw)** : `~/.openclaw/openclaw.json` (**niveau utilisateur uniquement** — OpenClaw n'a pas de configuration projet/local). Comme Hermes, OpenClaw est une **passerelle** multi-canal auto-hébergée, donc une installation intercepte les appels outils de chaque canal et de ses sous-agents internes. L'application des règles passe par les **hooks de plugin en cours de processus** d'OpenClaw (ses hooks internes basés sur des fichiers sont en observation uniquement et ne peuvent pas bloquer), donc — comme OpenCode/Pi — failproofai embarque un package statique `openclaw-plugin/` qui spawn de manière asynchrone le binaire failproofai et traduit le verdict. L'installation enregistre le répertoire de plugin embarqué dans `plugins.load.paths[]` de `openclaw.json` et l'active sous `plugins.entries.failproofai` (avec `hooks.allowConversationAccess: true`, requis pour les hooks de conversation brute). L'évaluateur émet un verdict plat `{permission, reason}` et le shim le mappe à la forme de retour native de chaque hook : `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), et `before_agent_finalize → {action:"revise", reason}` (**Stop** — une vraie porte de fin de tour, donc les politiques intégrées `require-*-before-stop` **s'appliquent** sur OpenClaw, contrairement à Hermes). Les événements et noms d'outils se canonicalisent côté binaire via `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) pour que les politiques intégrées se déclenchent sans modification ; le shim échoue en mode ouvert en cas d'erreur de spawn/parse/timeout. OpenClaw est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses sessions JSONL à `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)** : `~/.factory/hooks.json` (utilisateur), `/.factory/hooks.json` (projet) — Factory n'a pas de niveau `local`. droid embarque un système de hook par commande externe de style Claude, mais avec deux particularités vérifiées en direct contre droid v0.171.0 : (1) les noms d'événements se trouvent au **niveau supérieur** de `hooks.json` — il n'y a **pas d'enveloppe `"hooks"`** (droid en rejette une) ; les événements outil (`PreToolUse`/`PostToolUse`) portent `"matcher": "*"`, les événements non-outil l'omettent. (2) Le refus est piloté par le **code de sortie 2 + stderr** du hook, pas par une décision JSON — la branche `factory` de l'évaluateur retourne la sortie 2 pour les événements outil/prompt et `{decision:"block", reason}` uniquement sur l'événement de fin de tour `Stop` (seul canal de force-retry de droid). Les événements sont déjà en PascalCase (pas de mapping d'événements) et le payload est en snake_case Claude ; seuls les noms d'outils sont canonicalisés via `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses sessions JSONL sur disque à `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)** : `~/.config/devin/config.json` (utilisateur), `/.devin/config.json` (projet) — Devin n'a pas de niveau `local`. Devin est un **clone pur de Claude** vérifié en direct contre devin v3000.1.27 : il utilise le schéma standard Claude avec enveloppe `"hooks"` (les écritures préservent la fusion pour que les autres clés du fichier de config — `org_id`, `theme_mode`, … — survivent), des noms d'événements déjà en PascalCase (pas de mapping d'événements, pas de branche de gestionnaire), et un payload stdin en snake_case Claude (pas de normalisation). La branche `devin` de l'évaluateur refuse avec `{"decision":"block","reason"}` JSON sur stdout à la sortie 0 pour **chaque** événement (vérifié — le blocage a surchargé `--permission-mode dangerous`) ; sur l'événement de fin de tour `Stop`, la raison porte le libellé de force-retry MANDATORY-ACTION pour que les politiques intégrées `require-*-before-stop` s'appliquent. Seuls les noms d'outils sont canonicalisés via `DEVIN_TOOL_MAP` (`exec→Bash` ; `tool_input.command` est déjà canonique). Devin est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses sessions SQLite à `~/.local/share/devin/cli/sessions.db` (chaque ligne `sessions` porte un vrai `working_directory`, donc les sessions se regroupent par projet cwd comme Claude). + - **Antigravity CLI (`agy`)** : `~/.gemini/config/hooks.json` (utilisateur), `/.agents/hooks.json` (projet) — Antigravity n'a pas de niveau `local`. Contrairement à Factory/Devin, Antigravity a son **propre** contrat (pas un clone de Claude), vérifié en direct contre agy v1.1.2. `hooks.json` utilise un schéma de **hook nommé** : la clé de niveau supérieur est un *nom* de hook (`"failproofai"`) dont la valeur est un mapping événement→gestionnaires — les événements outil (`PreToolUse`/`PostToolUse`) enveloppent les gestionnaires dans `{matcher:"*", hooks:[…]}`, tandis que `PreInvocation`/`Stop` sont des **tableaux de gestionnaires plats** (les autres hooks nommés sont préservés). Le payload stdin est du **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai le normalise en snake_case avant l'exécution des politiques, et mappe les args PascalCase de `run_command` (`CommandLine`/`Cwd`) via `ANTIGRAVITY_TOOL_INPUT_MAP`. La branche `antigravity` de l'évaluateur utilise les **propres** formes de réponse d'Antigravity : `{decision:"deny", reason}` bloque un outil/prompt (sortie 0), `{decision:"continue", reason}` sur l'événement de fin de tour `Stop` re-rentre dans la boucle (donc les politiques intégrées `require-*-before-stop` s'appliquent), et `{injectSteps:[{ephemeralMessage}]}` injecte une instruction sur `PreInvocation` (→ `UserPromptSubmit`). Les noms d'outils se canonicalisent via `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses transcriptions JSONL brutes à `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (index des conversations dans `conversation_summaries.db`). + - **Goose (nom de code goose, Block)** : `~/.agents/plugins/failproofai/hooks/hooks.json` (utilisateur), `/.agents/plugins/failproofai/hooks/hooks.json` (projet) — Goose n'a pas de niveau `local`. L'application des règles utilise le système de **hooks** de Goose, la spec **Open Plugins** inter-agents : l'installateur dépose simplement le répertoire du plugin `failproofai` et Goose le découvre automatiquement au démarrage (en s'auto-enregistrant dans `~/.config/goose/config.yaml`). Le `hooks.json` utilise un schéma Open Plugins **avec** une enveloppe `"hooks"` de niveau supérieur, et le matcher est **omis** sur chaque événement — un `"*"` nu est une regex invalide qui ne correspond à rien (vérifié en direct contre goose v1.43.0). Les noms d'événements sont déjà en PascalCase (pas de mapping d'événements) ; le payload stdin utilise `event`/`working_dir`, que le gestionnaire normalise en `hook_event_name`/`cwd`. La branche `goose` de l'évaluateur refuse avec `{"decision":"block","reason"}` JSON sur stdout à la sortie 0, honoré sur l'événement **`PreToolUse`** uniquement (embarqué dans goose ≥ v1.37.0) — qui se déclenche pour l'outil shell **et à l'intérieur des sous-agents délégués**, ce qui en fait le seul point de refus suffisant ; toute autre erreur de hook échoue en mode **ouvert**. Goose **n'a pas d'événement `Stop`**, donc les politiques intégrées `require-*-before-stop` ne s'appliquent pas (comme avec Hermes). Les noms d'outils se canonicalisent via `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) et les clés de chemin via `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose est **aussi** une source d'**audit** hors ligne — le tableau de bord lit ses sessions SQLite à `~/.local/share/goose/sessions/sessions.db` (chaque ligne `sessions` porte un vrai `working_dir`, donc les sessions se regroupent par projet cwd comme Devin ; les exécutions ponctuelles `--no-session` sont filtrées). - **`policies-config.json`** — indique à failproofai quelles politiques évaluer et avec quels paramètres (partagé entre toutes les CLI agent) -Passez `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` pour cibler un agent spécifique (séparé par des espaces ou répété pour tout sous-ensemble) : +Passez `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` pour cibler un agent spécifique (séparés par des espaces ou répétés pour un sous-ensemble quelconque) : ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Lorsque `--cli` est omis, `failproofai` détecte quelles CLI agent sont installées (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`) : +Lorsque `--cli` est omis, `failproofai` détecte quelles CLI agent sont installées (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`) : -- **Une CLI détectée** — sélectionne automatiquement cette CLI sans demander de confirmation. -- **Plusieurs CLI détectées** dans un terminal interactif — affiche une invite de sélection unique par touches fléchées regroupée en une section `Detected (N)` (avec une ligne agrégée `Install for all N detected` + chaque CLI détectée individuellement) et une section `Not installed (M) · install hooks ahead of time` listant chaque CLI prise en charge non détectée comme option d'installation anticipée (↑↓ pour déplacer, Entrée pour sélectionner, ^C pour quitter). Le flux de désinstallation n'affiche que la section Detected. -- **Plusieurs CLI détectées** lors d'une exécution non interactive (CI, sans TTY) — installe pour toutes les CLI détectées sans demander de confirmation. -- **Aucune détectée** — revient à `claude`, avec un avertissement qu'aucun binaire agent n'a été trouvé dans PATH ; la commande de hook est tout de même écrite afin qu'elle s'active dès que vous en installez un. +- **Une seule CLI détectée** — sélectionne automatiquement cette CLI sans demande de confirmation. +- **Plusieurs CLI détectées** dans un terminal interactif — affiche une invite de sélection unique à touches fléchées regroupant une section `Detected (N)` (avec une ligne agrégée `Install for all N detected` + chaque CLI détectée individuellement) et une section `Not installed (M) · install hooks ahead of time` listant toutes les CLI supportées non détectées comme option d'installation anticipée (↑↓ pour naviguer, Entrée pour sélectionner, ^C pour quitter). Le flux de désinstallation n'affiche que la section Detected. +- **Plusieurs CLI détectées** dans une exécution non interactive (CI, sans TTY) — installe pour toutes les CLI détectées sans demande de confirmation. +- **Aucune CLI détectée** — repli sur `claude`, avec un avertissement indiquant qu'aucun binaire agent n'a été trouvé dans PATH ; la commande hook est tout de même écrite pour s'activer dès que vous en installez un. -Vous pouvez modifier `policies-config.json` directement à tout moment ; les modifications prennent effet immédiatement au prochain événement de hook, sans redémarrage nécessaire. +Vous pouvez modifier `policies-config.json` directement à tout moment ; les modifications prennent effet immédiatement au prochain événement hook, sans redémarrage nécessaire. --- -## Exemple : configuration au niveau projet avec les valeurs par défaut de l'équipe +## Exemple : configuration au niveau projet avec des valeurs par défaut d'équipe -Committez `.failproofai/policies-config.json` dans votre dépôt : +Commitez `.failproofai/policies-config.json` dans votre dépôt : ```json { @@ -247,4 +255,4 @@ Committez `.failproofai/policies-config.json` dans votre dépôt : } ``` -Chaque développeur peut ensuite créer `.failproofai/policies-config.local.json` (ignoré par git) pour des substitutions personnelles sans affecter ses coéquipiers. \ No newline at end of file +Chaque développeur peut ensuite créer `.failproofai/policies-config.local.json` (ignoré par git) pour ses surcharges personnelles sans affecter ses coéquipiers. \ No newline at end of file diff --git a/docs/fr/dashboard.mdx b/docs/fr/dashboard.mdx index 1e76570b..f9dcc072 100644 --- a/docs/fr/dashboard.mdx +++ b/docs/fr/dashboard.mdx @@ -1,14 +1,14 @@ --- -title: Tableau de bord -description: "Surveillez les sessions d'agents, examinez les appels d'outils et gérez les politiques" +title: Dashboard +description: "Surveiller les sessions d'agents, examiner les appels d'outils et gérer les politiques" icon: chart-line --- -Le tableau de bord failproofai est une application web locale permettant de surveiller vos sessions d'agents IA et de gérer vos politiques. Découvrez ce que vos agents ont fait pendant votre absence. +Le dashboard failproofai est une application web locale permettant de surveiller vos sessions d'agents IA et de gérer les politiques. Voyez ce que vos agents ont fait pendant votre absence. --- -## Démarrer le tableau de bord +## Démarrer le dashboard ```bash failproofai @@ -16,7 +16,7 @@ failproofai S'ouvre à l'adresse `http://localhost:8020`. -Le tableau de bord lit directement depuis le système de fichiers — vos dossiers de projets Claude Code et les fichiers de configuration failproofai. Rien n'est écrit vers un service distant. +Le dashboard lit directement depuis le système de fichiers — vos dossiers de projets Claude Code et les fichiers de configuration failproofai. Rien n'est écrit vers un service distant. --- @@ -24,14 +24,14 @@ Le tableau de bord lit directement depuis le système de fichiers — vos dossie ### Projets -Liste tous les projets Claude Code, OpenAI Codex, GitHub Copilot CLI _(bêta)_, Cursor Agent _(bêta)_, OpenCode _(bêta)_, Pi _(bêta)_, Gemini CLI _(bêta)_ et Hermes trouvés sur votre machine. Les projets Claude sont découverts depuis `~/.claude/projects/` (ou le chemin défini par `CLAUDE_PROJECTS_PATH`) ; les projets Codex sont découverts en analysant chaque transcription sous `~/.codex/sessions///
/*.jsonl` et en les regroupant par le `cwd` enregistré dans le premier enregistrement de chaque session ; les projets Copilot CLI sont découverts en analysant chaque `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) et en les regroupant par leur champ `cwd` ; les projets Cursor Agent sont découverts en analysant les métadonnées par session sous `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, avec `conversations/` et `sessions/` comme solutions de repli) pour un scalaire `cwd` dans `meta.json` / `session.json` / `workspace.yaml` ; les projets OpenCode sont découverts en interrogeant sa base de données SQLite à `~/.local/share/opencode/opencode.db` via `opencode db --format json` (nous lisons les tables `session` et `project` et les regroupons par `project_id`) ; les projets Pi sont découverts en analysant les transcriptions JSONL par session sous `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) et en extrayant le `cwd` du premier enregistrement de chaque session ; les projets Gemini CLI sont découverts en analysant `~/.gemini/tmp//chats/session--.jsonl` (configurable via `GEMINI_SESSIONS_DIR`) et en récupérant le répertoire de travail canonique depuis le marqueur texte `.project_root` associé ; les sessions de la passerelle Hermes sont lues directement depuis son stockage SQLite à `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) et regroupées en projets `hermes-` par `source` (Slack/Telegram/cli/cron — les sessions de passerelle n'ont pas de cwd). Un projet utilisé par plusieurs interfaces CLI s'affiche sur une seule ligne avec tous les badges correspondants. Utilisez le menu déroulant **CLI** au-dessus du tableau pour filtrer par interface CLI spécifique ; l'URL conserve votre sélection sous la forme `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Liste tous les projets Claude Code, OpenAI Codex, GitHub Copilot CLI _(bêta)_, Cursor Agent _(bêta)_, OpenCode _(bêta)_, Pi _(bêta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity et Goose trouvés sur votre machine. Les projets Claude sont découverts depuis `~/.claude/projects/` (ou le chemin défini par `CLAUDE_PROJECTS_PATH`) ; les projets Codex sont découverts en analysant chaque transcript sous `~/.codex/sessions///
/*.jsonl` et en les regroupant par le `cwd` enregistré dans le premier enregistrement de chaque session ; les projets Copilot CLI sont découverts en analysant chaque `~/.copilot/session-state//workspace.yaml` (configurable via `COPILOT_HOME`) et en les regroupant par leur champ `cwd` ; les projets Cursor Agent sont découverts en analysant les métadonnées par session sous `~/.cursor/agent-sessions//` (configurable via `CURSOR_HOME`, avec `conversations/` et `sessions/` testés en repli) pour un scalaire `cwd` dans `meta.json` / `session.json` / `workspace.yaml` ; les projets OpenCode sont découverts en interrogeant sa base SQLite à `~/.local/share/opencode/opencode.db` via `opencode db --format json` (les tables `session` et `project` sont lues et regroupées par `project_id`) ; les projets Pi sont découverts en analysant les transcripts JSONL par session sous `~/.pi/agent/sessions//_.jsonl` (configurable via `PI_SESSIONS_DIR`) et en extrayant le `cwd` du premier enregistrement de chaque session ; les sessions de passerelle Hermes sont lues directement depuis son magasin SQLite à `~/.hermes/state.db` (configurable via `HERMES_DB_PATH`) et regroupées en projets `hermes-` par `source` (Slack/Telegram/cli/cron — les sessions de passerelle n'ont pas de cwd) ; les sessions de passerelle OpenClaw sont lues depuis `~/.openclaw/agents//sessions/*.jsonl` et regroupées en projets `openclaw-` (également sans cwd) ; les projets Factory Droid sont découverts depuis les transcripts JSONL à `~/.factory/sessions//*.jsonl` et regroupés par cwd ; les projets Devin depuis sa base SQLite à `~/.local/share/devin/cli/sessions.db` (regroupés par le `working_directory` de chaque session) ; les projets Antigravity depuis les transcripts JSONL à `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` et regroupés par cwd ; et les projets Goose depuis sa base SQLite à `~/.local/share/goose/sessions/sessions.db` (regroupés par le `working_dir` de chaque session). Un projet utilisé par plusieurs CLI apparaît sur une seule ligne avec tous les badges correspondants. Utilisez le menu déroulant **CLI** au-dessus du tableau pour filtrer par un agent CLI spécifique ; l'URL conserve votre sélection sous la forme `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Chaque projet affiche : - Le nom du projet (dérivé du chemin du dossier) -- Un badge CLI — `Claude Code` (orange), `OpenAI Codex` (violet), `GitHub Copilot` (bleu), `Cursor Agent` (émeraude), `OpenCode` (ambre), `Pi` (rose), `Gemini CLI` (bleu ciel) et/ou `Hermes` (indigo) +- Un badge CLI — `Claude Code` (orange), `OpenAI Codex` (violet), `GitHub Copilot` (bleu), `Cursor Agent` (émeraude), `OpenCode` (ambre), `Pi` (rose) et/ou `Hermes` (indigo) - La date de la dernière activité de session -Cliquez sur un projet pour afficher ses sessions. +Cliquez sur un projet pour voir ses sessions. ### Sessions @@ -39,7 +39,7 @@ Liste toutes les sessions d'un projet. Chaque session affiche : - L'identifiant de session - Les horodatages de début et de fin - Le nombre d'appels d'outils -- Le nombre d'activités de hooks (politiques déclenchées) +- Le nombre d'activités de hook (politiques déclenchées) Utilisez le filtre de plage de dates et la recherche par identifiant de session pour affiner la liste. Les sessions sont paginées. @@ -47,27 +47,27 @@ Cliquez sur une session pour ouvrir le visualiseur de session. ### Visualiseur de session -Le visualiseur de session répond à la question essentielle pour les agents autonomes : qu'a fait l'agent, et est-il resté dans les limites prévues ? Un badge CLI à côté de l'en-tête indique si la session est une transcription Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI ou Hermes. Il affiche une chronologie de tout ce qui s'est passé lors d'une session : +Le visualiseur de session répond à la question clé pour les agents autonomes : qu'a fait l'agent, et est-il resté sur la bonne voie ? Un badge CLI à côté de l'en-tête indique si la session est un transcript Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity ou Goose. Il affiche une chronologie de tout ce qui s'est passé lors d'une session : - **Messages** - Les réponses textuelles de Claude et les invites utilisateur - **Appels d'outils** - Chaque outil invoqué par Claude, avec ses entrées et sorties -- **Activité des politiques** - Pour chaque appel d'outil, quelles politiques ont été déclenchées et quelle décision elles ont retournée +- **Activité des politiques** - Pour chaque appel d'outil, quelles politiques ont été déclenchées et quelle décision elles ont rendu -La barre de statistiques en haut affiche la durée de la session, le nombre total d'appels d'outils et un résumé des décisions de hook (nombre de allow / deny / instruct). +La barre de statistiques en haut affiche la durée de la session, le nombre total d'appels d'outils et un résumé des décisions de hook (comptages allow / deny / instruct). -Cliquez sur le bouton **Télécharger les journaux** pour exporter la session. Pour les sessions Claude Code, Codex, Copilot, Cursor, Pi et Gemini, vous obtenez la transcription JSONL originale sur disque octet par octet ; pour OpenCode (dont les sessions résident dans SQLite et non sur disque), vous obtenez un document JSON reproduisant les tables sous-jacentes `session` / `messages` / `parts`. +Cliquez sur le bouton **Télécharger les logs** pour exporter la session. Pour les sessions Claude Code, Codex, Copilot, Cursor et Pi, vous obtenez le transcript JSONL d'origine sur disque octet pour octet ; pour OpenCode (dont les sessions résident dans SQLite, pas sur disque) vous obtenez un document JSON reproduisant les tables sous-jacentes `session` / `messages` / `parts`. ### Audit -Un rapport personnalisé sur la manière dont votre agent s'est réellement comporté au fil des sessions passées. Effectue le même scan que la commande `failproofai audit`, mais le restitue sous forme d'une affiche partageable sur écran unique + quatre sections sous le pli : +Un rapport sur la personnalité décrivant comment votre agent s'est réellement comporté au fil des sessions passées. Exécute la même analyse que la CLI `failproofai audit` mais l'affiche sous forme d'une affiche partageable plein écran + quatre sections en dessous de la ligne de flottaison : -1. **Affiche** — occupe la première fenêtre d'affichage. Zone de capture PNG autonome avec le logo failproof_ai + libellé d'audit · index d'archétype (`№ NN of 08`) + date d'audit · score numérique (0–100) + pastille de rang percentile (`top 15%`) · le nom de l'archétype (parmi `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + bande de 3 mots-clés · ligne de rareté `// only N% of agents are this archetype` · tuile de signe graphique 8×8 pixels · pied de page `audit yours → failproof.ai`. Trois boutons de partage se trouvent juste en dehors de la zone de capture : `post your archetype` (intention X), `share on linkedin`, `download poster`. La capture s'effectue via `html-to-image` de sorte que le PNG correspond pixel pour pixel au rendu à l'écran (bordures en pointillés, masque de logo SVG, dégradés, métriques de polices — tout est conservé). -2. **Points forts** — liste de comportements que votre agent fait déjà correctement, sous forme de lignes avec une coche, dérivés des données d'audit en direct (taux d'appels d'outils propres, aucun push direct sur main, zéro fuite de credentials, zéro boucle de nouvelles tentatives) — chacun n'est affiché que lorsque la politique concernée a un bilan propre sur la fenêtre d'audit. -3. **Particularités** — tableau de ce qui a échappé au contrôle, classé par gravité : `quand · ce qui a échappé + la politique qui l'aurait intercepté · pastille de gravité · observé`, où la récurrence indique `new` (une fois), `N× seen` (2–9 fois) ou `recurring` (10+). -4. **Comment s'améliorer** — liste de lignes calmes, une par politique recommandée : nom de la politique en blanc, description en une ligne, commande d'installation + bouton de copie à droite. L'en-tête de la section indique `enable all N → projected · ` (le score que vous atteindriez en appliquant tous les correctifs), et son bouton `[install all]` copie la commande combinée `failproofai policy add a b c …` pour chaque politique recommandée. -5. **Revenez amélioré** — deux cartes côte à côte. À gauche : définir un rappel (sélecteur de cadence `3d` / `7d` / `14d` / `30d` ; persiste via `/api/auth/reminder` une fois authentifié). À droite : débloquer des avantages failproof — `invite a friend` ouvre une boîte de dialogue acceptant une liste d'adresses e-mail d'amis séparées par des virgules/espaces/sauts de ligne (max 10 par envoi), les envoie en POST à `/api/audit/invite`, qui les transmet au serveur API via `POST /v0/invite`. Le serveur API envoie un e-mail par destinataire depuis `invite@failproof.ai` avec l'expéditeur en Cc et `Reply-To` configuré, de sorte que le destinataire voit qui l'a invité et l'expéditeur reçoit une copie dans sa boîte de réception. Les utilisateurs anonymes sont d'abord redirigés vers `AuthDialog` afin que l'adresse e-mail de l'expéditeur soit connue avant l'envoi des invitations. La gestion des droits et avantages sera traitée ultérieurement. +1. **Affiche** — remplit le premier viewport. Zone de capture PNG autonome avec la marque failproof_ai + libellé d'audit · index d'archétype (`№ NN sur 08`) + date d'audit · score numérique (0–100) + pastille de rang percentile (`top 15%`) · le nom de l'archétype (l'un de `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + bande de 3 mots-clés · ligne de rareté `// only N% of agents are this archetype` · tuile de symbole pixels 8×8 · pied de page `audit yours → failproof.ai`. Trois boutons de partage se trouvent juste en dehors de la zone de capture : `post your archetype` (intention X), `share on linkedin`, `download poster`. La capture s'effectue via `html-to-image` afin que le PNG corresponde exactement au rendu à l'écran (bordures en pointillés, masque de logo SVG, dégradés, métriques de police — tous préservés). +2. **Points forts** — liste de lignes ✓ calmes des comportements que votre agent fait déjà correctement, dérivés des données d'audit en direct (taux d'appels d'outils propre, pas de push direct vers main, zéro fuite d'identifiants, zéro tempête de nouvelles tentatives) — chacun n'apparaît que lorsque la politique concernée a un bilan propre sur la fenêtre d'audit. +3. **Particularités** — tableau de ce qui a échappé au contrôle, classé par gravité : `quand · ce qui a glissé + la politique qui l'aurait détecté · pastille de gravité · vu`, où la récurrence affiche `new` (une fois), `N× seen` (2–9 fois) ou `recurring` (10+). +4. **Comment s'améliorer** — liste de lignes calmes, une par politique prescrite : nom de la politique en blanc, description en une ligne, commande d'installation + bouton copier sur le côté droit. L'en-tête de section indique `enable all N → projected · ` (le score que vous atteindriez en appliquant tous les correctifs), et son bouton `[install all]` copie la commande combinée `failproofai policy add a b c …` pour chaque politique prescrite. +5. **Revenez mieux** — deux cartes côte à côte. À gauche : définir un rappel (sélecteur de cadence `3d` / `7d` / `14d` / `30d` ; persiste via `/api/auth/reminder` une fois authentifié). À droite : débloquer les avantages failproof — `invite a friend` ouvre une fenêtre modale qui accepte une liste d'adresses e-mail d'amis séparées par des virgules/espaces/sauts de ligne (max 10 par envoi), les envoie en POST à `/api/audit/invite`, qui les transmet au serveur API via `POST /v0/invite`. Le serveur API envoie un e-mail par destinataire depuis `invite@failproof.ai` avec l'expéditeur en Cc et `Reply-To` défini, de sorte que le destinataire voit qui l'a invité et l'expéditeur reçoit une copie dans sa boîte de réception. Les utilisateurs anonymes sont d'abord redirigés via `AuthDialog` afin que l'adresse e-mail de l'expéditeur soit connue avant l'envoi des invitations. Les droits et avantages seront traités ultérieurement. -Alimenté par le runtime `failproofai audit` — consultez [Audit CLI](/fr/cli/audit) pour le moteur de scan sous-jacent, les options prises en charge et les invariants de cache par transcription. Le tableau de bord met en cache le dernier résultat dans `~/.failproofai/audit-dashboard.json` (mode `0600`, emplacement unique, les nouvelles exécutions écrasent l'ancien) afin que les revisites soient instantanées ; **les caches par transcription et par résultat global sont tous deux rejetés à la lecture s'ils ont plus de 7 jours**, de sorte que le tableau de bord ne sert jamais silencieusement un résultat vieux d'une semaine — passé le TTL, `/audit` revient à son état vide et invite à une nouvelle exécution. Cliquer sur `[ re-audit now ]` en bas du rapport envoie un POST à `/api/audit/run` avec `noCache: true` — la ré-analyse contourne le cache par transcription et réanalyse chaque transcription depuis le début plutôt que de retourner silencieusement le résultat mis en cache — et le tableau de bord interroge `/api/audit/status` à 1 Hz jusqu'à la fin de l'exécution ; une bande de progression rose épinglée en haut de la fenêtre d'affichage s'affiche pendant l'exécution avec un minuteur écoulé, et le nouveau résultat remplace l'ancien en place en cas de succès (sans rechargement complet de la page ; en cas d'échec de la ré-analyse, le rapport précédent reste intact). En cas d'échec, la bande devient rouge avec un message adapté au `RerunError.kind` (`timeout` / `network` / `post_failed`). L'état vide (aucun cache ou expiré) et l'état sans sessions (cache existant mais le scan n'a trouvé aucune transcription) sont présentés séparément. +Alimenté par le runtime `failproofai audit` — consultez [Audit CLI](/fr/cli/audit) pour le moteur d'analyse sous-jacent, les flags pris en charge et les invariants de cache par transcript. Le dashboard met en cache le dernier résultat à `~/.failproofai/audit-dashboard.json` (mode `0600`, emplacement unique, les nouvelles exécutions écrasent le précédent) afin que les revisites soient instantanées ; **les deux caches — par transcript et résultat global — sont rejetés à la lecture s'ils ont plus de 7 jours**, de sorte que le dashboard ne renvoie jamais silencieusement un résultat vieux d'une semaine — passé ce délai, `/audit` tombe dans son état vide et invite à une nouvelle exécution. Cliquer sur `[ re-audit now ]` près du bas du rapport envoie un POST à `/api/audit/run` avec `noCache: true` — la ré-analyse contourne le cache par transcript et analyse chaque transcript depuis zéro plutôt que de renvoyer silencieusement le résultat mis en cache — et le dashboard interroge `/api/audit/status` à 1 Hz jusqu'à la fin de l'exécution ; une bande de progression rose persistante s'épingle en haut du viewport pendant l'exécution avec un minuteur écoulé, et le nouveau résultat remplace l'ancien en place en cas de succès (sans rechargement complet de la page ; une ré-analyse échouée laisse le rapport précédent intact). En cas d'échec, la bande devient rouge avec un message lié au `RerunError.kind` (`timeout` / `network` / `post_failed`). L'état vide (pas de cache ou expiré) et l'état zéro session (cache existant mais l'analyse n'a trouvé aucun transcript) sont présentés séparément. ### Politiques @@ -75,16 +75,16 @@ Une page à deux onglets pour gérer les politiques et examiner l'activité. - - Sélectionnez plusieurs interfaces CLI d'agents que failproofai protège depuis un seul panneau — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI et Hermes disposent chacun d'une ligne avec le statut d'installation (`Active` / `Detected` / `Inactive`), le chemin des paramètres de portée utilisateur et un accent coloré à la marque. Cochez ou décochez les CLI souhaités et cliquez sur `Apply changes` pour installer/désinstaller les différences en une seule étape. Les CLI dont le binaire est détecté dans le PATH sont pré-cochés. + - Sélectionnez plusieurs CLI d'agents que failproofai protège depuis un seul panneau — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi et Hermes ont chacun une ligne avec le statut d'installation (`Active` / `Detected` / `Inactive`), le chemin des paramètres de portée utilisateur et un accent coloré à la marque. Cochez ou décochez les CLI souhaités et cliquez sur `Apply changes` pour installer/désinstaller la différence en une seule étape. Les CLI dont le binaire est détecté dans le PATH sont pré-cochés. - Activez ou désactivez des politiques individuelles d'un simple clic (écrit dans `~/.failproofai/policies-config.json` — partagé entre tous les CLI installés) - - Développez une politique pour configurer ses paramètres (pour les politiques prenant en charge `policyParams`) - - Définissez un chemin de fichier de politiques personnalisé + - Développez une politique pour configurer ses paramètres (pour les politiques qui prennent en charge `policyParams`) + - Définissez un chemin de fichier de politiques personnalisées - Historique paginé complet de chaque événement de hook déclenché dans toutes les sessions - - Filtrer par décision, type d'événement, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(bêta)_ / Cursor Agent _(bêta)_ / OpenCode _(bêta)_ / Pi _(bêta)_ / Gemini CLI _(bêta)_ / Hermes), nom de politique ou identifiant de session - - Chaque ligne affiche : horodatage, nom de la politique, décision, badge CLI (orange = Claude Code, violet = OpenAI Codex, bleu = GitHub Copilot, émeraude = Cursor Agent, ambre = OpenCode, rose = Pi, bleu ciel = Gemini CLI, indigo = Hermes), nom de l'outil, identifiant de session et la raison des décisions deny/instruct - - Cliquez sur un identifiant de session pour ouvrir sa transcription — le visualiseur détecte automatiquement quel CLI a déclenché le hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) et affiche le badge CLI correspondant dans l'en-tête + - Filtrez par décision, type d'événement, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(bêta)_ / Cursor Agent _(bêta)_ / OpenCode _(bêta)_ / Pi _(bêta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), nom de politique ou identifiant de session + - Chaque ligne affiche : horodatage, nom de la politique, décision, badge CLI (orange = Claude Code, violet = OpenAI Codex, bleu = GitHub Copilot, émeraude = Cursor Agent, ambre = OpenCode, rose = Pi, indigo = Hermes, sarcelle = OpenClaw, rose foncé = Factory Droid, violet foncé = Devin, cyan = Antigravity, citron vert = Goose), nom de l'outil, identifiant de session et la raison des décisions deny/instruct + - Cliquez sur un identifiant de session pour ouvrir son transcript — le visualiseur détecte automatiquement quel CLI a déclenché le hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) et affiche le badge CLI correspondant dans l'en-tête @@ -92,13 +92,13 @@ Une page à deux onglets pour gérer les politiques et examiner l'activité. ## Actualisation automatique -Le tableau de bord dispose d'un bouton de basculement d'actualisation automatique dans la navigation supérieure. Lorsqu'il est activé, la page actuelle s'actualise périodiquement pour afficher les nouvelles sessions et l'activité des politiques au fur et à mesure qu'elles apparaissent. Indispensable pour surveiller les sessions d'agents autonomes de longue durée. +Le dashboard dispose d'un bouton de basculement d'actualisation automatique dans la navigation supérieure. Lorsqu'il est activé, la page actuelle se rafraîchit périodiquement pour afficher les nouvelles sessions et l'activité des politiques au fur et à mesure. Indispensable pour surveiller les sessions d'agents autonomes de longue durée. --- ## Désactiver des pages -Si vous n'avez besoin que de certaines parties du tableau de bord, définissez `FAILPROOFAI_DISABLE_PAGES` avec une liste de noms de pages séparés par des virgules : +Si vous n'avez besoin que de certaines parties du dashboard, définissez `FAILPROOFAI_DISABLE_PAGES` avec une liste de noms de pages séparés par des virgules : ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +110,7 @@ Valeurs valides : `policies`, `projects`, `audit`. ## Configurer le chemin des projets -Par défaut, le tableau de bord lit depuis le répertoire de projets Claude Code standard. Remplacez-le pour des configurations personnalisées : +Par défaut, le dashboard lit depuis le répertoire standard des projets Claude Code. Remplacez-le pour des configurations personnalisées : ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,15 +118,15 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## Accès depuis un hôte autre que localhost +## Accès depuis un hôte non-localhost -Lorsque vous exécutez le tableau de bord en **mode développement** (`npm run dev`) et que vous y accédez depuis un nom d'hôte autre que `localhost` — par exemple, un domaine personnalisé, une IP distante ou une URL tunnelisée — vous pouvez voir un avertissement comme : +Lorsque vous exécutez le dashboard en **mode développement** (`npm run dev`) et y accédez depuis un nom d'hôte autre que `localhost` — par exemple, un domaine personnalisé, une IP distante ou une URL tunnelisée — vous pouvez voir un avertissement comme : ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Next.js bloque l'accès cross-origin à son websocket HMR (rechargement à chaud des modules), qui est une fonctionnalité réservée au développement. Pour autoriser votre hôte, utilisez l'option `--allowed-origins` : +Il s'agit de Next.js bloquant l'accès cross-origin à son websocket HMR (rechargement à chaud des modules), qui est une fonctionnalité réservée au développement. Pour autoriser votre hôte, utilisez le flag `--allowed-origins` : ```bash npm run dev -- --allowed-origins dashboard.example.com @@ -145,5 +145,5 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Ceci s'applique uniquement au mode développement. Lorsque vous exécutez `failproofai` (mode production), il n'y a pas de websocket HMR ni de problème de ressource de développement cross-origin. +Ceci s'applique uniquement au mode développement. Lors de l'exécution de `failproofai` (mode production), il n'y a pas de websocket HMR ni de problème de ressource de développement cross-origin. \ No newline at end of file diff --git a/docs/fr/getting-started.mdx b/docs/fr/getting-started.mdx index 38af4f5f..d1722a11 100644 --- a/docs/fr/getting-started.mdx +++ b/docs/fr/getting-started.mdx @@ -1,13 +1,13 @@ --- -title: Démarrage -description: "Installez failproofai, activez les politiques et laissez vos agents s'exécuter de manière fiable" +title: Démarrage rapide +description: "Installez failproofai, activez les politiques et laissez vos agents fonctionner de manière fiable" icon: rocket --- ## Prérequis - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (optionnel - nécessaire uniquement pour la compilation depuis les sources) +- **Bun** >= 1.3.0 (optionnel — uniquement nécessaire pour compiler depuis les sources) --- @@ -31,15 +31,15 @@ bun add -g failproofai - Les politiques sont des règles qui s'exécutent avant et après chaque appel d'outil d'agent. Elles interceptent les commandes destructrices, les fuites de secrets et d'autres modes d'échec avant qu'ils ne causent des dommages. + Les politiques sont des règles qui s'exécutent avant et après chaque appel d'outil d'agent. Elles interceptent les commandes destructrices, les fuites de secrets et autres modes de défaillance avant qu'ils ne causent des dommages. ```bash failproofai policies --install ``` - Cette commande inscrit des entrées de hook dans vos CLIs d'agent installés (le `~/.claude/settings.json` de Claude Code, le `~/.codex/hooks.json` d'OpenAI Codex, le `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, le `~/.cursor/hooks.json` de Cursor Agent, le shim de plugin généré par OpenCode à `~/.config/opencode/plugins/failproofai.mjs` ainsi qu'une entrée d'enregistrement dans le tableau `plugin` de `~/.config/opencode/opencode.json`, le `~/.pi/agent/settings.json` de Pi, le `~/.gemini/settings.json` de Gemini CLI, ou le `~/.hermes/config.yaml` de Hermes). Si plusieurs sont présents, une invite s'affichera ; passez `--cli claude codex copilot cursor opencode pi gemini hermes` (tout sous-ensemble) pour ignorer l'invite. + Cette commande écrit des entrées de hook dans vos CLIs d'agents installés (le `~/.claude/settings.json` de Claude Code, le `~/.codex/hooks.json` d'OpenAI Codex, le `~/.copilot/hooks/failproofai.json` de GitHub Copilot CLI, le `~/.cursor/hooks.json` de Cursor Agent, le shim de plugin généré par OpenCode à `~/.config/opencode/plugins/failproofai.mjs` ainsi qu'une entrée d'enregistrement dans le tableau `plugin` de `~/.config/opencode/opencode.json`, le `~/.pi/agent/settings.json` de Pi, le `~/.hermes/config.yaml` de Hermes, le `~/.openclaw/openclaw.json` d'OpenClaw, le `~/.factory/hooks.json` de Factory Droid, le `~/.config/devin/config.json` de Devin CLI, le `~/.gemini/config/hooks.json` d'Antigravity CLI, ou le répertoire de plugins auto-découvert de Goose à `~/.agents/plugins/failproofai/hooks/hooks.json`). Si plusieurs sont présents, une invite vous demandera de choisir ; utilisez `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (tout sous-ensemble) pour ignorer cette invite. - La prise en charge de GitHub Copilot CLI, Cursor Agent, OpenCode, Pi et Gemini CLI est en **bêta** — installez avec `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` ou `--cli gemini`. Hermes (hermes-agent, une passerelle Slack/Telegram) s'installe en portée utilisateur avec `--cli hermes` et constitue **également** une source d'audit hors ligne. + La prise en charge de GitHub Copilot CLI, Cursor Agent, OpenCode et Pi est en **bêta** — installez avec `--cli copilot`, `--cli cursor`, `--cli opencode` ou `--cli pi`. Hermes (hermes-agent, une passerelle Slack/Telegram) s'installe avec la portée utilisateur via `--cli hermes` et est **également** une source d'audit hors ligne. OpenClaw (passerelle openclaw, un assistant multi-canaux auto-hébergé) s'installe avec la portée utilisateur via `--cli openclaw` — l'application passe par ses hooks de plugin en cours de processus (`before_agent_finalize` est une véritable porte de fin de tour, donc les builtins `require-*-before-stop` s'appliquent) — et est **également** une source d'audit hors ligne. Factory Droid (`droid`) s'installe avec `--cli factory` (portée utilisateur + projet) et est **également** une source d'audit hors ligne. Devin CLI (`devin`, Cognition) s'installe avec `--cli devin` (portée utilisateur + projet) et est **également** une source d'audit hors ligne. Antigravity CLI (`agy`) s'installe avec `--cli antigravity` (portée utilisateur + projet) et est **également** une source d'audit hors ligne. Goose (nom de code goose, Block) s'installe avec `--cli goose` (portée utilisateur + projet) — l'installateur dépose simplement un répertoire de plugins à `~/.agents/plugins/failproofai/` que Goose découvre automatiquement, et il est **également** une source d'audit hors ligne. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,16 +62,16 @@ bun add -g failproofai failproofai policies ``` - Affiche toutes les politiques, leur état d'activation et les paramètres configurés. + Affiche toutes les politiques, leur statut d'activation et les paramètres configurés. ```bash failproofai ``` - Ouvre un tableau de bord local à l'adresse `http://localhost:8020` où vous pouvez parcourir les sessions, inspecter les appels d'outils et gérer les politiques. + Ouvre un tableau de bord local à `http://localhost:8020` où vous pouvez parcourir les sessions, inspecter les appels d'outils et gérer les politiques. - + Démarrez Claude Code comme d'habitude. Si l'agent tente quelque chose de risqué, failproofai l'intercepte automatiquement. Laissez-le tourner sans surveillance et consultez ce qui s'est passé dans le tableau de bord. @@ -86,9 +90,9 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON Chaque politique retourne l'une des trois décisions suivantes : -- **allow** - l'agent continue normalement -- **deny** - l'action est bloquée et l'agent est informé de la raison -- **instruct** - du contexte supplémentaire est ajouté à l'invite de l'agent +- **allow** — l'agent continue normalement +- **deny** — l'action est bloquée, l'agent est informé de la raison +- **instruct** — du contexte supplémentaire est ajouté à l'invite de l'agent Les politiques s'exécutent dans votre processus local. Rien n'est envoyé à un service distant. @@ -96,9 +100,9 @@ Les politiques s'exécutent dans votre processus local. Rien n'est envoyé à un --- -## Configurer les politiques d'équipe avec les politiques basées sur les conventions +## Configurer des politiques d'équipe avec des politiques basées sur les conventions -La manière la plus rapide d'établir des standards de qualité au sein de votre équipe est la convention `.failproofai/policies/`. Déposez des fichiers de politique dans ce répertoire et ils sont chargés automatiquement — sans indicateurs, sans modifications de configuration, sans commandes d'installation. +La façon la plus rapide d'établir des standards de qualité au sein de votre équipe est la convention `.failproofai/policies/`. Déposez des fichiers de politique dans ce répertoire et ils sont chargés automatiquement — sans options, sans changements de configuration, sans commandes d'installation. @@ -107,7 +111,7 @@ La manière la plus rapide d'établir des standards de qualité au sein de votre ``` - Copiez les exemples de démarrage ou rédigez les vôtres : + Copiez les exemples de démarrage ou écrivez les vôtres : ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -138,12 +142,12 @@ La manière la plus rapide d'établir des standards de qualité au sein de votre git commit -m "Add team quality policies" ``` - Chaque membre de l'équipe ayant failproofai installé récupère ces politiques automatiquement. Aucune configuration par développeur n'est nécessaire. + Chaque membre de l'équipe ayant failproofai installé récupère ces politiques automatiquement. Aucune configuration individuelle n'est nécessaire. -Validez `.failproofai/policies/` dans votre dépôt afin que toute l'équipe partage les mêmes standards. Au fur et à mesure que votre équipe découvre de nouveaux modes d'échec, ajoutez des politiques et poussez — tout le monde reçoit la mise à jour au prochain `git pull`. Au fil du temps, ces politiques deviennent un standard de qualité vivant qui ne cesse de s'améliorer. +Validez `.failproofai/policies/` dans votre dépôt afin que toute l'équipe partage les mêmes standards. Au fur et à mesure que votre équipe découvre de nouveaux modes de défaillance, ajoutez des politiques et poussez-les — tout le monde reçoit la mise à jour au prochain `git pull`. Avec le temps, ces politiques deviennent un standard de qualité vivant qui ne cesse de s'améliorer. --- @@ -155,10 +159,10 @@ Toute la configuration et les journaux restent sur votre machine : | Chemin | Contenu | |--------|---------| | `~/.failproofai/policies-config.json` | Configuration globale des politiques | -| `~/.failproofai/hook-activity.jsonl` | Historique d'exécution des hooks | +| `~/.failproofai/hook-activity.jsonl` | Historique des exécutions de hooks | | `~/.failproofai/hook.log` | Journal de débogage pour les erreurs de hooks personnalisés | -| `.failproofai/policies-config.json` | Configuration par projet (validée dans git) | -| `.failproofai/policies-config.local.json` | Substitutions personnelles (ignorées par git) | +| `.failproofai/policies-config.json` | Configuration par projet (versionnée) | +| `.failproofai/policies-config.local.json` | Remplacements personnels (ignorés par git) | --- @@ -172,7 +176,7 @@ Supprime les entrées de hook de `~/.claude/settings.json`. Les fichiers de conf --- -## Étapes suivantes +## Prochaines étapes @@ -188,7 +192,7 @@ Supprime les entrées de hook de `~/.claude/settings.json`. Les fichiers de conf Écrivez vos propres politiques en JavaScript - + Surveillez les sessions et examinez l'activité des politiques diff --git a/docs/fr/introduction.mdx b/docs/fr/introduction.mdx index 7bafb798..be99360d 100644 --- a/docs/fr/introduction.mdx +++ b/docs/fr/introduction.mdx @@ -1,15 +1,15 @@ --- title: "Failproof AI" -description: "FailproofAI offre aux agents IA 39 politiques de sécurité intégrées qui détectent les boucles, les fuites de secrets, les appels d'outils destructeurs, et bien plus encore, en une seule installation." +description: "FailproofAI offre aux agents IA 39 politiques de défaillance intégrées qui détectent les boucles, les fuites de secrets, les appels d'outils destructeurs, et bien plus encore, en une seule installation." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks et politiques pour la **gestion des défaillances IA**, la **récupération après erreur** et la **fiabilité des LLM**. Gardez vos agents IA fiables et autonomes sur **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** et l'**Agents SDK**. +Hooks et politiques pour la **gestion des défaillances IA**, la **récupération d'erreurs** et la **fiabilité des LLM**. Gardez vos agents IA fiables et autonomes avec **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** et le **Agents SDK**. -Les agents IA échouent de manière prévisible. Ils exécutent des commandes destructrices, exposent des secrets, dérivent hors de leur tâche, se retrouvent bloqués dans des boucles ou poussent directement sur la branche principale. Laissées sans surveillance, de petites défaillances se transforment en pannes, en identifiants compromis et en travail perdu. +Les agents IA échouent de manière prévisible. Ils exécutent des commandes destructrices, laissent fuiter des secrets, dérivent hors de leur tâche, se retrouvent coincés dans des boucles ou poussent directement sur main. Sans surveillance, de petits incidents s'enchaînent et mènent à des pannes, des identifiants compromis et du travail perdu. -FailproofAI résout ce problème grâce aux **politiques**. Ces règles s'accrochent à chaque appel d'outil de l'agent pour **détecter les défaillances**, **les atténuer** (bloquer, instruire, assainir) et **vous alerter** lorsqu'une intervention est nécessaire. Un tableau de bord local vous permet de consulter chaque appel d'outil, chaque défaillance d'agent et chaque action de récupération après coup. +FailproofAI résout ce problème grâce aux **politiques**. Ces règles s'accrochent à chaque appel d'outil de l'agent pour **détecter les défaillances**, **les atténuer** (bloquer, instruire, assainir) et **vous alerter** lorsqu'une intervention est nécessaire. Un tableau de bord local vous permet de consulter a posteriori chaque appel d'outil, chaque défaillance d'agent et chaque action de récupération. Aucune donnée ne quitte votre machine. @@ -18,7 +18,7 @@ Aucune donnée ne quitte votre machine. - Bloquez les commandes destructrices, empêchez les fuites de secrets, maintenez les agents dans les limites du projet, et bien plus encore. Tout prêt à l'emploi. + Bloquez les commandes destructrices, prévenez les fuites de secrets, maintenez les agents dans les limites du projet, et bien plus encore. Tout cela prêt à l'emploi. @@ -26,11 +26,11 @@ Aucune donnée ne quitte votre machine. - Voyez ce que vos agents ont fait pendant votre absence. Parcourez les sessions, inspectez les appels d'outils, consultez où les politiques ont été déclenchées. + Voyez ce que vos agents ont fait pendant votre absence. Parcourez les sessions, inspectez les appels d'outils, consultez où les politiques se sont déclenchées. - Ajustez n'importe quelle politique sans code. Définissez des listes d'autorisation, des branches protégées ou des seuils par projet ou globalement. + Ajustez n'importe quelle politique sans écrire de code. Définissez des listes d'autorisation, des branches protégées ou des seuils par projet ou de façon globale. diff --git a/docs/getting-started.mdx b/docs/getting-started.mdx index ae2179be..4dd58bc8 100644 --- a/docs/getting-started.mdx +++ b/docs/getting-started.mdx @@ -37,9 +37,9 @@ bun add -g failproofai failproofai policies --install ``` - This writes hook entries into your installed agent CLIs (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, or Hermes's `~/.hermes/config.yaml`). When more than one is present you'll be prompted; pass `--cli claude codex copilot cursor opencode pi gemini hermes` (any subset) to skip the prompt. + This writes hook entries into your installed agent CLIs (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Hermes's `~/.hermes/config.yaml`, OpenClaw's `~/.openclaw/openclaw.json`, Factory Droid's `~/.factory/hooks.json`, Devin CLI's `~/.config/devin/config.json`, Antigravity CLI's `~/.gemini/config/hooks.json`, or Goose's auto-discovered plugin dir at `~/.agents/plugins/failproofai/hooks/hooks.json`). When more than one is present you'll be prompted; pass `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (any subset) to skip the prompt. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, and Gemini CLI support are **beta** — install with `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, or `--cli gemini`. Hermes (hermes-agent, a Slack/Telegram gateway) installs user-scope with `--cli hermes` and is **also** an offline audit source. + GitHub Copilot CLI, Cursor Agent, OpenCode, and Pi support are **beta** — install with `--cli copilot`, `--cli cursor`, `--cli opencode`, or `--cli pi`. Hermes (hermes-agent, a Slack/Telegram gateway) installs user-scope with `--cli hermes` and is **also** an offline audit source. OpenClaw (openclaw gateway, a self-hosted multi-channel assistant) installs user-scope with `--cli openclaw` — enforcement runs through its in-process plugin hooks (`before_agent_finalize` is a real turn-end gate, so the `require-*-before-stop` builtins enforce) — and is **also** an offline audit source. Factory Droid (`droid`) installs with `--cli factory` (user + project scope) and is **also** an offline audit source. Devin CLI (`devin`, Cognition) installs with `--cli devin` (user + project scope) and is **also** an offline audit source. Antigravity CLI (`agy`) installs with `--cli antigravity` (user + project scope) and is **also** an offline audit source. Goose (codename goose, Block) installs with `--cli goose` (user + project scope) — the installer just drops a plugin dir at `~/.agents/plugins/failproofai/` that Goose auto-discovers, and it is **also** an offline audit source. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` diff --git a/docs/he/built-in-policies.mdx b/docs/he/built-in-policies.mdx index 38dfc8bc..552e9c76 100644 --- a/docs/he/built-in-policies.mdx +++ b/docs/he/built-in-policies.mdx @@ -1,43 +1,43 @@ --- -title: מדיניויות מובנות -description: "כל 39 המדיניויות המובנות שתופסות מצבי כשל נפוצים של סוכנים" +title: מדיניות מובנית +description: "כל 39 מדיניות המובנית שתופסות כשלים נפוצים של סוכנים" icon: shield --- -failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצבי כשל נפוצים של סוכנים. כל מדיניות מופעלת על סוג אירוע hook ושם כלי ספציפיים. תשע עשרה מדיניויות מקבלות פרמטרים המאפשרים לכם לכוונן את התנהגותן ללא כתיבת קוד. חמש מדיניויות זרימת עבודה אוכפות צינור commit → push → PR → CI לפני שClaude עוצר. +failproofai מגיע עם 39 מדיניות מובנית שתופסות כשלים נפוצים של סוכנים. כל מדיניות פועלת על סוג אירוע hook ושם כלי מסוים. תשע עשרה מדיניות מקבלות פרמטרים המאפשרים לך לכוונן את ההתנהגות שלהן ללא כתיבת קוד. חמש מדיניות זרימת עבודה אוכפות צינור commit → push → PR → CI לפני שClaude עוצר. --- ## סקירה כללית -המדיניויות מסודרות לקטגוריות: +מדיניות מקובצות לקטגוריות: -| קטגוריה | מדיניויות | סוג Hook | +| קטגוריה | מדיניות | סוג Hook | |----------|----------|-----------| | [פקודות מסוכנות](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [פקודות תשתית](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [סודות (מנקים)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [סודות (מנקיים)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | | [סביבה](#environment) | block-env-files, protect-env-vars | PreToolUse | | [גישת קבצים](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | -| [בסיס נתונים](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | +| [מסד נתונים](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | | [אזהרות](#warnings) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | | [מנהלי חבילות](#package-managers) | prefer-package-manager | PreToolUse | | [זרימת עבודה](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | - **`block-`** — עצור את הסוכן מהמשך. -- **`warn-`** — תן לסוכן הקשר נוסף כדי שיוכל לתקן את עצמו. -- **`sanitize-`** — גרד נתונים רגישים מפלט הכלי לפני שהסוכן רואה אותו. +- **`warn-`** — תן לסוכן הקשר נוסף כדי שיוכל להתקן עצמו. +- **`sanitize-`** — מחק נתונים רגישים מפלט הכלי לפני שהסוכן רואה אותו. ### מרחבי שמות -כל מדיניות חיה בחריץ `/`. מדיניויות מובנות שייכות למרחב השמות -**`failproofai/`** — לדוגמה, `failproofai/sanitize-jwt`. מרחב השמות מונע -התנגשויות כאשר אתה גם טוען מדיניויות מותאמות או של צד שלישי -בעלות שמות קצרים דומים. +כל מדיניות נמצאת בחריץ `/`. מדיניות מובנית שייכות +למרחב השמות **`failproofai/`** — לדוגמה, `failproofai/sanitize-jwt`. מרחב השמות +מונע התנגשויות כאשר אתה טוען גם מדיניות מותאמות או של צד שלישי +עם שמות קצרים דומים. -בתצורה שלך אתה יכול להתייחס למדיניות מובנית גם בשם קצר וגם בשם -מוסמך; שני הטפוסים מתפזרים לאותה מדיניות: +בתצורה שלך אתה יכול להתייחס למדיניות מובנית בכל שם קצר או שמה +המלא; שתי הצורות מתפתחות לאותה מדיניות: ```json { @@ -48,35 +48,35 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ } ``` -אם לשם אין `/`, failproofai מתייחס אליו כשייך למרחב השמות -ברירת המחדל `failproofai`. שמות שכבר מכילים `/` (למשל `myorg/foo`, -`custom/my-hook`) נשמרים כמו שהם. -- **`require-`** — חסום את אירוע ה-Stop עד שתנאים מתקיימים. +אם לשם אין `/`, failproofai מתייחס אליו כשייך לברירת המחדל +של מרחב השמות `failproofai`. שמות שכבר מכילים `/` (לדוגמה `myorg/foo`, +`custom/my-hook`) מתקבלים כמו שהם. +- **`require-`** — חסום את אירוע Stop עד שתנאים מתמלאים. --- -כל מדיניות תומכת בשדה `hint` אופציונלי ב-`policyParams`. ה-hint מוסף להודעת ה-deny או ה-instruct שClaude רואה, ונותן הנחיות פעולה ללא שינוי קוד המדיניות. עובד עם מדיניויות מובנות, מותאמות וקונוונציה. ראה [Configuration → hint](/he/configuration#hint-cross-cutting) לפרטים. +כל מדיניות תומכת בשדה `hint` אופציונלי ב-`policyParams`. ה-hint מתוסף להודעת deny או instruct שClaude רואה, ומספק הנחיה יישומית ללא שינוי קוד מדיניות. פועל עם מדיניות מובנית, מותאמת ותיקונית. ראה [תצורה → hint](/he/configuration#hint-cross-cutting) לפרטים. --- ## פקודות מסוכנות -מנע סוכנים מהפעלת פעולות שקשה לבטל או שעלולות לפגוע במערכת המארחת. +מנע מסוכנים מהרצת פעולות שקשה לבטל או שעלולות להזיק למערכת המארחת. ### `block-sudo` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל פקודת `sudo`. +**ברירת מחדל:** דוחה כל פקודה `sudo`. -חוסם הופעות שמכילות את מילת המפתח `sudo`. התאמת דפוס נעשית על אסימוני פקודה מנותחים, לא על המחרוזת הגולמית, כדי למנוע עקיפה דרך הזרקת אופרטור shell. +חוסם הודעות שמכילות את המילה-קליד `sudo`. התאמת דפוס נעשית על טוקנים פורסמים, לא על המחרוזת הגולמית, כדי למנוע עקיפה דרך זריקת אופרטור shell. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה מדויקות המורשות. כל ערך מותאם לאסימוני argv המנותחים. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה מדויקות המותרות. כל ערך מתואם מול טוקנים argv מפורסמים. | **דוגמה:** @@ -90,10 +90,10 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ } ``` -עם תצורה זו, `sudo systemctl status nginx` מורשה, אך `sudo rm /etc/hosts` שלול. +בתצורה זו, `sudo systemctl status nginx` מותר, אבל `sudo rm /etc/hosts` דחוי. -דפוסים מותאמים לאסימוני מנותחים, לא למחרוזת הפקודה הגולמית. זה מונע עקיפה דרך אופרטורים shell מצורפים (למשל `sudo systemctl status x; rm -rf /` לא תואם ל-`sudo systemctl status *`). +דפוסים מתואמים מול טוקנים מפורסמים, לא מול מחרוזת הפקודה הגולמית. זה מונע עקיפה דרך אופרטורים shell שנוספו (לדוגמה `sudo systemctl status x; rm -rf /` לא תואם `sudo systemctl status *`). --- @@ -101,13 +101,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-rm-rf` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת `rm -rf`, `rm -fr` וצורות מחיקה רקורסיביות דומות. +**ברירת מחדל:** דוחה `rm -rf`, `rm -fr`, וצורות מחיקה רקורסיביות דומות. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | נתיבים שבטוח למחוק בצורה רקורסיבית (למשל `/tmp`). | +| `allowPaths` | `string[]` | `[]` | נתיבים שבטוח למחוק רקורסיבית (לדוגמה `/tmp`). | **דוגמה:** @@ -126,37 +126,37 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-curl-pipe-sh` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת `curl | bash`, `curl | sh`, `wget | bash` וטפוסים דומים. +**ברירת מחדל:** דוחה `curl | bash`, `curl | sh`, `wget | bash`, ודפוסים דומים. -אין פרמטרים. +ללא פרמטרים. --- ### `block-failproofai-commands` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת פקודות שיסירו או יכבו את failproofai עצמו (למשל `npm uninstall failproofai`, `failproofai policies --uninstall`). +**ברירת מחדל:** דוחה פקודות שיהיה להן uninstall או disable failproofai עצמו (לדוגמה `npm uninstall failproofai`, `failproofai policies --uninstall`). -אין פרמטרים. +ללא פרמטרים. --- ## פקודות תשתית -עצור סוכנים קוד מהפעלת CLI תשתית או הטלת קנות CI/CD. כל המדיניויות בקטגוריה זו הן **opt-in** (`defaultEnabled: false`) — סוכנים שכל להם צורך לגיטימי להתקשר ל-`kubectl`, `terraform` וכו' לא יופרעו אלא אם אתה מפעיל את המדיניות. כשמופעלת, כל הופעה של ה-CLI המתאימה שלול אלא אם הפקודה תואמת ערך ב-`allowPatterns`. +עצור סוכנים קידוד מהרצת CLIs של תשתית או הפעלת צינורות CI/CD. כל המדיניות בקטגוריה זו הן **opt-in** (`defaultEnabled: false`) — סוכנים שבאמת צריכים להתקשר עם `kubectl`, `terraform`, וכו', לא יוסבו למעצורים אלא אם תפעיל את המדיניות. כאשר מופעלת, כל הודעה של ה-CLI המתואם מדוחה אלא אם הפקודה תואמת ערך ב-`allowPatterns`. -דקדוק הדפוס זהה ל-[`block-sudo`](#block-sudo): אסימוני argv מנותחים מותאמים, `*` הוא כרט עדבר עבור אסימון אחד, וכל פקודה המכילה אופרטור shell עצמאי (`&&`, `||`, `|`, `;`) או אסימון עם תווי shell מובנים שלול לפני התאמת מאימה כדי למנוע עקיפות הזרקה. +דקדוק הדפוס זהה ל-[`block-sudo`](#block-sudo): טוקנים מתואמים מול argv מפורסם, `*` הוא wildcard לטוקן אחד, וכל פקודה המכילה אופרטור shell עצמאי (`&&`, `||`, `|`, `;`) או טוקן עם תווי מטא-shell משובצים דחוי לפני התאמת allowlist כדי למנוע עקיפות זריקה. ### `block-kubectl` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של `kubectl`. +**ברירת מחדל:** דוחה כל הודעת `kubectl`. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה kubectl המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה kubectl המותרות. | **דוגמה:** @@ -170,20 +170,20 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ } ``` -עם תצורה זו, `kubectl get pods` מורשה אך `kubectl apply -f deploy.yaml` שלול. +בתצורה זו, `kubectl get pods` מותר אבל `kubectl apply -f deploy.yaml` דחוי. --- ### `block-terraform` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של `terraform` או `tofu` (OpenTofu). +**ברירת מחדל:** דוחה כל הודעת `terraform` או `tofu` (OpenTofu). **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה terraform/tofu המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה terraform/tofu המותרות. | **דוגמה:** @@ -202,13 +202,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-aws-cli` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של CLI `aws`. +**ברירת מחדל:** דוחה כל הודעת `aws` CLI. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה aws CLI המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה aws CLI המותרות. | **דוגמה:** @@ -227,13 +227,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-gcloud` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של CLI `gcloud` (Google Cloud). +**ברירת מחדל:** דוחה כל הודעת `gcloud` (Google Cloud) CLI. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה gcloud המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה gcloud המותרות. | **דוגמה:** @@ -252,13 +252,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-az-cli` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של CLI `az` (Azure). +**ברירת מחדל:** דוחה כל הודעת `az` (Azure) CLI. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה az CLI המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה az CLI המותרות. | **דוגמה:** @@ -277,13 +277,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-helm` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת כל הופעה של `helm`. +**ברירת מחדל:** דוחה כל הודעת `helm`. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | קידומות פקודה helm המורשות. | +| `allowPatterns` | `string[]` | `[]` | קידומות פקודה helm המותרות. | **דוגמה:** @@ -302,7 +302,7 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-gh-pipeline` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת תת-פקודות `gh` CLI הבאות המשנות מצב או מפעילות קנות: +**ברירת מחדל:** דוחה את תת-הפקודות `gh` CLI הבאות ששינוי מצב או הפעלת צינורות: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -311,13 +311,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ - `gh cache delete` - `gh secret set`, `gh secret delete` -תת-פקודות `gh` לקריאה בלבד כגון `gh pr view`, `gh pr list`, `gh run list`, `gh release view` ו-`gh api repos/.../...` **לא** מותאמות למדיניות זו — הן נדרשות בדרך כלל לבדיקות זרימת עבודה (כולל `require-ci-green-before-stop` של failproofai). +תת-פקודות `gh` של קריאה בלבד כמו `gh pr view`, `gh pr list`, `gh run list`, `gh release view`, ו-`gh api repos/.../...` **אינן** תואמות על ידי מדיניות זו — הן נחוצות באופן שגרתי לבדיקות זרימת עבודה (כולל ה-`require-ci-green-before-stop` שלnow failproofai). **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | הופעות סקריפט ספציפיות להתיר אפילו אם אחרת יהיו שלול. | +| `allowPatterns` | `string[]` | `[]` | הודעות בתסריט ספציפיות להרשות גם כשהיו אחרת דחויות. | **דוגמה:** @@ -333,29 +333,29 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ --- -## סודות (מנקים) +## סודות (מנקיים) -עצור סוכנים מדלף credentials להקשרם או לפלט שלהם. מדיניויות מנקה מופעלות על אירועי **PostToolUse**. כאשר Claude מפעיל פקודת Bash, קורא קובץ, או קורא לכל כלי, מדיניויות אלה בוחנות את הפלט לפני שהוא מוחזר ל-Claude. אם דפוס סוד מתגלה, המדיניות מחזירה החלטת deny המונעת את הפלט מהעברה בחזרה. +עצור סוכנים מדלוף אישורים להקשר או פלט שלהם. מדיניות Sanitizer פעל על אירועי **PostToolUse**. כאשר Claude מריץ פקודת Bash, קורא קובץ, או קורא לכל כלי, מדיניות אלה בוחנות את הפלט לפני שהוא מוחזר ל-Claude. אם דפוס סוד מגלה, המדיניות מחזירה החלטת deny שמונעת את הפלט מהעברה בחזרה. ### `sanitize-jwt` **אירוע:** PostToolUse (כל הכלים) -**ברירת מחדל:** מחווה אסימוני JWT (שלוש קטעי base64url המופרדים ב-`.`). +**ברירת מחדל:** מחל JWT tokens (שלוש סגמנטים base64url מופרדים ב-`.`). -אין פרמטרים. +ללא פרמטרים. --- ### `sanitize-api-keys` **אירוע:** PostToolUse (כל הכלים) -**ברירת מחדל:** מחווה פורמטי מפתח API נפוצים: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), מפתחות גישה AWS (`AKIA`), מפתחות Stripe (`sk_live_`, `sk_test_`), ומפתחות Google API (`AIza`). +**ברירת מחדל:** מחל פורמטי מפתח API נפוצים: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`), ו-Google API keys (`AIza`). **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | דפוסי regex נוסף לטיפול כסודות. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | דפוסי regex נוספים לטיפול כסודות. | **דוגמה:** @@ -364,8 +364,8 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ "policyParams": { "sanitize-api-keys": { "additionalPatterns": [ - { "regex": "myco_[A-Za-z0-9]{32}", "label": "מפתח API פנימי של MyCo" }, - { "regex": "pat_[0-9a-f]{40}", "label": "PAT פנימי" } + { "regex": "myco_[A-Za-z0-9]{32}", "label": "MyCo internal API key" }, + { "regex": "pat_[0-9a-f]{40}", "label": "Internal PAT" } ] } } @@ -377,68 +377,68 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `sanitize-connection-strings` **אירוע:** PostToolUse (כל הכלים) -**ברירת מחדל:** מחווה מחרוזות חיבור בסיס נתונים המכילות credentials מובנים (למשל `postgresql://user:password@host/db`). +**ברירת מחדל:** מחל מחרוזות חיבור מסד נתונים המכילות אישורים משובצים (לדוגמה `postgresql://user:password@host/db`). -אין פרמטרים. +ללא פרמטרים. --- ### `sanitize-private-key-content` **אירוע:** PostToolUse (כל הכלים) -**ברירת מחדל:** מחווה בלוקי PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` וכו'). +**ברירת מחדל:** מחל בלוקים PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, וכו'). -אין פרמטרים. +ללא פרמטרים. --- ### `sanitize-bearer-tokens` **אירוע:** PostToolUse (כל הכלים) -**ברירת מחדל:** מחווה כותרות `Authorization: Bearer ` כאשר האסימון הוא 20 תווים או יותר. +**ברירת מחדל:** מחל כותרות `Authorization: Bearer ` שבהן הטוקן הוא 20 או יותר תווים. -אין פרמטרים. +ללא פרמטרים. --- ## סביבה -הגן על תצורת סביבה רגישה מהקריאה או החשיפה על ידי סוכנים. +הגן על תצורת סביבה רגישה מקריאה או החשפה על ידי סוכנים. ### `block-env-files` **אירוע:** PreToolUse (Bash, Read) -**ברירת מחדל:** שוללת קריאת קבצי `.env` דרך `cat .env`, קריאות כלי `Read` עם `.env` כנתיב הקובץ, וכו'. +**ברירת מחדל:** דוחה קריאה של קבצי `.env` דרך `cat .env`, קריאות כלי Read עם `.env` כנתיב הקובץ, וכו'. -לא חוסם `.envrc` או קבצים סביבתיים אחרים - רק קבצים בשם בדיוק `.env`. +אינו חוסם `.envrc` או קבצים אחרים הסמוכים לסביבה — רק קבצים בשם בדיוק `.env`. -אין פרמטרים. +ללא פרמטרים. --- ### `protect-env-vars` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת פקודות המדפיסות משתנות סביבה: `printenv`, `env`, `echo $VAR`. +**ברירת מחדל:** דוחה פקודות המדפיסות משתני סביבה: `printenv`, `env`, `echo $VAR`. -אין פרמטרים. +ללא פרמטרים. --- ## גישת קבצים -שמור סוכנים בתוך גבולות פרויקט והרחק מקבצים רגישים. +שמור על סוכנים העובדים בתוך גבולות הפרוייקט וחוסם מקבצים רגישים. ### `block-read-outside-cwd` **אירוע:** PreToolUse (Read, Bash) -**ברירת מחדל:** שוללת קריאת קבצים מחוץ לשורש הפרויקט. הגבול הוא `CLAUDE_PROJECT_DIR` (מוגדר פעם אחת ליחידה על ידי Claude Code), עם חזרה לספריה העבודה הנוכחית של הפרקו כאשר משתנה זה לא מוגדר. שימוש בשורש הפרויקט במקום `cwd` החי משמעו שהגבול נשאר יציב אפילו אחרי שClaude `cd`s לתיקייה משנית. +**ברירת מחדל:** דוחה קריאה של קבצים מחוץ לשורש הפרוייקט. הגבול הוא `CLAUDE_PROJECT_DIR` (מוגדר פעם לכל session על ידי Claude Code), עם fallback ל-cwd הנוכחי של session כאשר המשתנה לא מוגדר. השימוש בשורש הפרוייקט במקום ב-`cwd` החי פירושו שהגבול נשאר יציב גם אחרי Claude `cd` לתיקייה משנית. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | קידומות נתיב מוחלט שמורשות אפילו מחוץ לשורש הפרויקט. | +| `allowPaths` | `string[]` | `[]` | קידומות נתיב מוחלט המותרות גם אם מחוץ לשורש הפרוייקט. | **דוגמה:** @@ -457,13 +457,13 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-secrets-write` **אירוע:** PreToolUse (Write, Edit) -**ברירת מחדל:** שוללת כתיבות לקבצים שנמצאים בשימוש נפוץ עבור מפתחות פרטיים וסרטיפיקטים: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**ברירת מחדל:** דוחה כתיבה לקבצים המשמשים בדרך כלל למפתחות פרטיים ותעודות: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | דפוסי שם קובץ נוסף (glob-style) לחסום. | +| `additionalPatterns` | `string[]` | `[]` | דפוסי שם קובץ נוספים (סגנון glob) לחסום. | **דוגמה:** @@ -481,18 +481,18 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ## Git -מנע דחיפות אקראיות, דחיפות כפויות וטעויות ענף שקשה לבטל. +מנע push טעויות, force-push, וטעויות ענף שקשה לבטל. ### `block-push-master` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת `git push origin main` ו-`git push origin master`. +**ברירת מחדל:** דוחה `git push origin main` ו-`git push origin master`. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | שמות ענפים שלא ניתן לדחוף אליהם ישירות. | +| `protectedBranches` | `string[]` | `["main", "master"]` | שמות ענפים שלא ניתן לpush ישירות. | **דוגמה:** @@ -507,7 +507,7 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ``` -כדי לאפשר דחיפה לכל הענפים (למעשה השבתה של מדיניות זו ללא הסרתה מ-`enabledPolicies`), הגדר `protectedBranches: []`. +כדי להרשות push לכל הענפים (למעשה השבתת מדיניות זו ללא הסרתה מ-`enabledPolicies`), הגדר `protectedBranches: []`. --- @@ -515,28 +515,28 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `block-work-on-main` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת `git commit`, `git merge`, `git rebase` ו-`git cherry-pick` בעוד עץ העבודה נמצא על `main` או `master`. יצירה והחלפת ענפים (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) לא מושפעות. +**ברירת מחדל:** דוחה `git commit`, `git merge`, `git rebase`, ו-`git cherry-pick` בעוד עץ העבודה נמצא ב-`main` או `master`. יצירת ענף והחלפה (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) לא מושפעות. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | שמות ענפים שעליהם commit/merge/rebase/cherry-pick שלול. | +| `protectedBranches` | `string[]` | `["main", "master"]` | שמות ענפים שעליהם commit/merge/rebase/cherry-pick דחוי. | --- ### `block-force-push` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** שוללת `git push --force` ו-`git push -f`. +**ברירת מחדל:** דוחה `git push --force` ו-`git push -f`. -אין פרמטרים ספציפיים למדיניות. השתמש ב-[`hint`](/he/configuration#hint-cross-cutting) חוצה הקטעים כדי להציע חלופות: +אין פרמטרים ספציפיים למדיניות. השתמש ב-[`hint`](/he/configuration#hint-cross-cutting) החוצה-חיתוך כדי להצביע על חלופות: ```json { "policyParams": { "block-force-push": { - "hint": "צור ענף חדש מה-HEAD הנוכחי שלך (למשל `git checkout -b `) ודחוף את זה במקום." + "hint": "Create a new branch from your current HEAD (e.g. `git checkout -b `) and push that instead." } } } @@ -547,66 +547,66 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `warn-git-amend` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude להתקדם בזהירות בעת הפעלת `git commit --amend`. לא חוסם את הפקודה. +**ברירת מחדל:** מדריך Claude להמשיך בזהירות בעת הרצת `git commit --amend`. לא חוסם את הפקודה. -אין פרמטרים. +ללא פרמטרים. --- ### `warn-git-stash-drop` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לאשר לפני הפעלת `git stash drop`. לא חוסם את הפקודה. +**ברירת מחדל:** מדריך Claude לאשר לפני הרצת `git stash drop`. לא חוסם את הפקודה. -אין פרמטרים. +ללא פרמטרים. --- ### `warn-all-files-staged` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לבדוק מה הוא מעלה בזמן הפעלת `git add -A` או `git add .`. לא חוסם את הפקודה. +**ברירת מחדל:** מדריך Claude לבדוק מה הוא staging בעת הרצת `git add -A` או `git add .`. לא חוסם את הפקודה. -אין פרמטרים. +ללא פרמטרים. --- -## בסיס נתונים +## מסד נתונים -תפוס פעולות SQL הרסניות לפני שהן מתבצעות כנגד מסד הנתונים שלך. +תפוס פעולות SQL הרסניות לפני הם מבצעים נגד מסד הנתונים שלך. ### `warn-destructive-sql` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לאשר לפני הפעלת SQL המכיל `DROP TABLE`, `DROP DATABASE` או `DELETE` ללא סעיף `WHERE`. +**ברירת מחדל:** מדריך Claude לאשר לפני הרצת SQL המכיל `DROP TABLE`, `DROP DATABASE`, או `DELETE` ללא `WHERE` סעיף. -אין פרמטרים. +ללא פרמטרים. --- ### `warn-schema-alteration` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לאשר לפני הפעלת הצהרות `ALTER TABLE`. +**ברירת מחדל:** מדריך Claude לאשר לפני הרצת הצהרות `ALTER TABLE`. -אין פרמטרים. +ללא פרמטרים. --- ## אזהרות -תן סוכנים הקשר נוסף לפני פעולות פוטנציאליות מסוכנות אך לא הרסניות. +תן לסוכנים הקשר נוסף לפני פעולות פוטנציאלית מסוכנות אך לא הרסניות. ### `warn-large-file-write` **אירוע:** PreToolUse (Write) -**ברירת מחדל:** נוקט Claude לאשר לפני כתיבת קבצים גדולים מ-1024 KB. +**ברירת מחדל:** מדריך Claude לאשר לפני כתיבת קבצים גדולים מ-1024 KB. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | סף גודל קובץ בקילו-בייטים שמעליו ניתנת אזהרה. | +| `thresholdKb` | `number` | `1024` | סף גודל קובץ בקילובייטים מעליו הודעה מוצגת. | **דוגמה:** @@ -621,7 +621,7 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ``` -מטפל ה-hook אוכף מגבלת stdin של 1 MB על מטענים. כדי לבדוק מדיניות זו עם תוכן קטן, הגדר `thresholdKb` לערך הרבה מתחת ל-1024. +מטפל ה-hook אוכף הגבלת stdin של 1 MB על עומסים. כדי לבדוק מדיניות זו עם תוכן קטן, הגדר `thresholdKb` לערך הרבה יותר נמוך מ-1024. --- @@ -629,49 +629,49 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `warn-package-publish` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לאשר לפני הפעלת `npm publish`. +**ברירת מחדל:** מדריך Claude לאשר לפני הרצת `npm publish`. -אין פרמטרים. +ללא פרמטרים. --- ### `warn-background-process` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude להיות זהיר בהשקת תהליכים בתמונה דרך `nohup`, `&`, `disown` או `screen`. +**ברירת מחדל:** מדריך Claude להיות זהיר בעת הפעלת תהליכים ברקע דרך `nohup`, `&`, `disown`, או `screen`. -אין פרמטרים. +ללא פרמטרים. --- ### `warn-global-package-install` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** נוקט Claude לאשר לפני הפעלת `npm install -g`, `yarn global add` או `pip install` ללא סביבה וירטואלית. +**ברירת מחדל:** מדריך Claude לאשר לפני הרצת `npm install -g`, `yarn global add`, או `pip install` ללא סביבה וירטואלית. -אין פרמטרים. +ללא פרמטרים. --- ## מנהלי חבילות -אכוף אילו מנהלי חבילות הסוכן רשאי להשתמש בהם. +אכוף איזה מנהלי חבילות הסוכן מורשה להשתמש. ### `prefer-package-manager` **אירוע:** PreToolUse (Bash) -**ברירת מחדל:** בוטל. כשמופעל, חוסם כל פקודת מנהל חבילות שלא ברשימת `allowed` ואומר ל-Claude לשכתב את הפקודה באמצעות מנהל מורשה. +**ברירת מחדל:** מנוטרל. כשמופעל, חוסם כל פקודת מנהל חבילות לא ברשימת `allowed` ואומר ל-Claude לשכתב את הפקודה בעזרת מנהל מורשה. -מזהה: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. +זוהה: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | פרמטר | סוג | ברירת מחדל | תיאור | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | שמות מנהלי חבילות מורשים. כל מנהל מזוהה שלא ברשימה זו מחוסם. כשריק, המדיניות היא no-op. | -| `blocked` | string[] | `[]` | שמות מנהלים נוספים לחסום מעבר לרשימה המובנית (למשל `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | שמות מנהלי חבילות מורשים. כל מנהל גלוי לא ברשימה זו חסום. כשריק, המדיניות היא no-op. | +| `blocked` | string[] | `[]` | שמות מנהלים נוספים לחסום מעבר לרשימה המובנית (לדוגמה `['pdm', 'pipx']`). | -רשימת הבלוק המובנית מכסה: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. השתמש ב-`blocked` להוסיף מנהלים שלא ברשימה זו. +רשימת החסימה המובנית מכסה: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. השתמש ב-`blocked` כדי לצרף מנהלים לא ברשימה זו. -**דוגמה תצורה:** +**תצורה דוגמה:** ```json { @@ -685,74 +685,73 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ } ``` -עם תצורה זו, `pip install flask` ו-`pdm install flask` שניהם שלול עם הודעה אומרת ל-Claude להשתמש ב-`uv` או `bun` במקום. פקודות כגון `uv pip install flask` מורשות כי `uv` נמצא ברשימה ובודק קודם. +בתצורה זו, `pip install flask` ו-`pdm install flask` שניהם דחויים עם הודעה שאומרת ל-Claude להשתמש ב-`uv` או `bun` במקום. פקודות כמו `uv pip install flask` מותרות כי `uv` ברשימת ההרשאה ובודק תחילה. --- ## התנהגות AI -גלה כשסוכנים תקועים או מתנהגים בצורה בלתי צפויה. +זהה כאשר סוכנים תקועים או מתנהגים בצורה בלתי צפויה. ### `warn-repeated-tool-calls` **אירוע:** PreToolUse (כל הכלים) -**ברירת מחדל:** נוקט Claude להתחשב מחדש כאשר אותו כלי נקרא 3+ פעמים עם פרמטרים זהים - סימן נפוץ שהסוכן תקוע בלולאה. +**ברירת מחדל:** מדריך Claude לשקול מחדש כאשר אותו כלי נקרא 3 פעמים או יותר עם פרמטרים זהים — סימן נפוץ שהסוכן תקוע בלולאה. -אין פרמטרים. +ללא פרמטרים. --- ## זרימת עבודה -אכוף זרימת עבודה משמעתית של סיום פרקו. מדיניויות אלה מופעלות על אירוע **Stop** ושוללות את הסוכן מהעצירה עד שכל תנאי מתקיים. הם עוקבים אחר שרשרת תלות טבעית: commit → push → PR → CI. אם מדיניות שוללת, מדיניויות מאוחרות בשרשרת מדולגות (deny מקצר מעגל). +אכוף זרימת עבודה משורעת בסיום session. מדיניות אלה פעלות על אירוע **Stop** ודוחות את הסוכן מהעצירה עד שכל תנאי מתקיים. הם עוקבים אחרי שרשרת התלות טבעית: commit → push → PR → CI. אם מדיניות דוחה, מדיניות מאוחרות יותר בשרשרת דלוגות (deny short-circuits). -כל מדיניויות זרימת עבודה הן **fail-open**: אם הכלי הנדרש לא זמין (למשל `gh` לא מותקן, אין ריווח git), המדיניות מורשה עם הודעה אינפורמטיבית המסבירה מדוע הבדיקה דולגה. +כל מדיניות זרימת עבודה הן **fail-open**: אם הכלי הנדרש לא זמין (לדוגמה `gh` לא מותקן, אין git remote), המדיניות מאפשרת עם הודעה אינפורמטיבית שמסבירה מדוע הבדיקה דלוגה. -### סמנטיקה Stop של לפי-CLI +### סמנטיקה Stop לכל CLI -אכיפת Stop נראית שונה במעט על פני שבעת ה-CLI הנתמכים כי לכל אחד יש חוזה hook של סיום סוכן שונה. ה-**outcome** זהה — הסוכן לא יוצא עם עצירה בזמן שער זרימת עבודה נכשל — אך ה-**mechanics** שונים. הטבלה להלן מסכמת; רק Pi יש פרמיה המשתמש בעיר שכדאי להבין לפני שתאפשר מדיניות `require-*-before-stop`. +אכיפה Stop נראית מעט שונה על פני שישה ה-CLIs התומכים כי לכל אחד יש חוזה Hook "agent finished" שונה. ה**תוצאה** היא זהה — הסוכן לא יוכל לעזוב תוך זרימת עבודה failing — אבל ה**מכניקה** שונה. הטבלה למטה מסכמת; רק Pi יש quirk נראה למשתמש שכדאי להבין לפני שתפעיל מדיניות `require-*-before-stop`. -| CLI | כשעוצר השער | מה שאתה רואה | +| CLI | מתי השער פעל | מה אתה רואה | |---|---|---| -| Claude Code | אותו לולאת סוכן, מיד | Claude ממשיך לעבוד — תקן את הבעיה, ואז מנסה לסיים שוב. אין הפסקה נראית לך. | -| Codex | אותו לולאת סוכן, מיד | זהה ל-Claude. | -| GitHub Copilot CLI | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ ממשכה `{decision:"block", reason}` של Copilot — מאומת אמפיריות נגד Copilot CLI 1.0.41). | -| Cursor Agent | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ `{followup_message}` של Cursor — מתוקבל ב-`loop_limit`, ברירת מחדל 5 ניסיונות חוזרים). | -| Gemini CLI | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בערוץ `{decision:"block", reason}` של Gemini על `AfterAgent`). | -| OpenCode | אותו לולאת סוכן, מיד | זהה ל-Claude (משתמש בקריאת SDK `client.session.prompt(...)` של OpenCode מנוטרלת דרך `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **תור משתמש הבא** | **Pi עוצר בצורה נראית** כשהשער עוצר — לולאת הסוכן שלו יוצאת ואתה חוזר ללתזמון. השער אז עוצר בפעם הבאה שאתה שולח תזמון: failproofai מקדים הנחיה `MANDATORY ACTION REQUIRED` לתזמון הסיסטם של הסיבוב הזה, נוקט את ה-LLM להשלים את שלב זרימת העבודה (commit, push, וכו') לפני עשיית מה שביקשת. | +| Claude Code | אותו loop agent, מיד | Claude ממשיך לעבוד — מתקן את הבעיה, ואז מנסה לסיים שוב. אין הפסקה נראית לך. | +| Codex | אותו loop agent, מיד | זהה ל-Claude. | +| GitHub Copilot CLI | אותו loop agent, מיד | זהה ל-Claude (משתמש בערוץ ה-retry של Copilot `{decision:"block", reason}` — אומת אמפירית מול Copilot CLI 1.0.41). | +| Cursor Agent | אותו loop agent, מיד | זהה ל-Claude (משתמש בערוץ `{followup_message}` של Cursor — מוגבל ל-`loop_limit`, ברירת מחדל 5 retry). | +| OpenCode | אותו loop agent, מיד | זהה ל-Claude (משתמש בקריאת SDK של OpenCode `client.session.prompt(...)` מנותב דרך `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **הפניה משתמש הבאה** | **Pi נראה עוצר** כאשר השער פעל — loop agent שלו יוצא והוא חוזר לבקשה. השער ואז פעל בפעם הבאה שאתה מוגיש בקשה: failproofai מתחיל `MANDATORY ACTION REQUIRED` directive לsystem prompt של התור, מדריך את ה-LLM להשלים את שלב זרימת העבודה (commit, push, וכו') לפני ביצוע מה שביקשת. | -**מגבלה של Pi.** `AgentEndEvent` של Pi (המקבילה הזרם של אירוע `Stop` של Claude) אין סוג תוצאה — ברגע שהוא עוצר, לולאת הסוכן של Pi כבר יצאה. Pi לא יכול להילחם להחזור לאותה לולאה בדרך שClaude / Copilot / Cursor / Gemini / OpenCode יכולים. failproofai מעביר את השער לאירוע `before_agent_start` של Pi (שעוצר אחרי התזמון הבא של המשתמש) כדי שבדיקת זרימת העבודה עדיין אוכפת, רק בסיבוב הבא במקום הנוכחי. +**מגבלת Pi.** ה-`AgentEndEvent` של Pi (ה-equivalent upstream של Hook `Stop` של Claude) אין סוג Result — בתוך הזמן שזה פעל, loop agent של Pi כבר יצא. Pi לא יכול להיכפה retry לאותו loop בצורה ש-Claude / Copilot / Cursor / OpenCode יכולים. failproofai מעביר את השער לאירוע `before_agent_start` של Pi (שפעל אחרי ההנחיה הבאה של משתמש) כדי בדיקת זרימת העבודה עדיין אוכפת, רק בתור הבא במקום הנוכחי. -**מה זה אומר בפרקטיקה:** +**המשמעות בפרקטיקה:** -- אחרי שPi עוצר, סיבת ה-deny נתפסה בזיכרון מפתח אחרי מזהה סשן Pi. התזמון הבא בדיוק שאתה שולח באותו תהליך Pi סוך את זה: ה-LLM רואה את ההנחיה `MANDATORY ACTION REQUIRED` בחלק העליון של תזמון הסיסטם שלו, commits (או דוחף / פותח את ה-PR / מחכה ל-CI), רק אחרי כן ממשיך עם בקשתך. סיבת ה-deny שתפסה היא one-shot — ברגע שסוך, השער ברור. -- השער מותחם על ידי חיי תהליך של Pi. אם `Ctrl+C` Pi או יוצא בין סיבובים, הערך בזיכרון בזיכרון מושלך יחד עם התהליך ואת השער מיסה. Claude, Copilot, Cursor, Gemini ו-OpenCode יש את אותו כולמן (הרוג את הסוכן ואת השער מיסה) — Pi פשוט עושה את זה יותר נראית כי הסוכן יוצא בצורה נראית לפני ש-פיר עוצר. -- deny ממתין הוא גם ברור על `session_shutdown` לכל סיבה (`new` / `resume` / `fork` / `quit`), כך שערט שנגרד מסשן קודם לא יכול לדלוף לסשן טרי שהחל באותו תהליך Pi. +- אחרי שPi עוצר, סיבת deny נתפסת בזיכרון שנעילה על ידי Pi session id. ההנחיה הבאה בדיוק שאתה מוגיש באותו Pi process מנקה אותה: ה-LLM רואה את ה-`MANDATORY ACTION REQUIRED` directive בראש system prompt שלו, מבצע commit (או push / opens PR / מחכה ל-CI), ורק אז ממשיך עם בקשתך. ה-deny reason שנתפסה היא one-shot — פעם שנמחק, השער ברור. +- השער מוגבל על ידי lifetime של processes Pi. אם `Ctrl+C` Pi או יוצא בין תורות, ערך in-memory מושמט יחד עם process והשער נפספא. Claude, Copilot, Cursor, ו-OpenCode יש אותה קשר (הרוג את agent והשער נפסף) — Pi רק עושה את זה יותר נראה כי agent יוצא בגלוי לפני השער פועל. +- pending deny גם ברור ב-`session_shutdown` לכל סיבה (`new` / `resume` / `fork` / `quit`), כדי deny stale מתור שלפני לא יכול להזדלג לתוך fresh session התחלה באותו Pi process. -אם אתה צריך retry זהה לClaude של אותו לולאה, הרץ את המדיניויות `Stop` שלך תחת כל אחד משש ה-CLI הנתמכים האחרים. אנחנו עוקבים אחרי Pi קודם לעתיד סוג תוצאה על `AgentEndEvent` שיתן לנו לסגור את הפער הזה. +אם אתה צריך Claude-style same-loop retry, הרץ את `Stop` policies שלך תחת כל אחד מחמישת ה-CLIs התומכים האחרים. אנחנו עוקבים אחרי Pi upstream עבור Result type עתידי ב-`AgentEndEvent` שיידע לנו לסגור gap זה. ### `require-commit-before-stop` **אירוע:** Stop -**ברירת מחדל:** שוללת עצירה כשיש שינויים ללא commit (שונה, מעודכן או קבצים שלא במעקב). מחזירה הודעה אינפורמטיבית כשספרית העבודה נקייה. +**ברירת מחדל:** דוחה עצירה כאשר יש שינויים לא committed (modified, staged, או untracked files). מחזיר הודעה אינפורמטיבית כאשר ספריית העבודה נקייה. -אין פרמטרים. +ללא פרמטרים. --- ### `require-push-before-stop` **אירוע:** Stop -**ברירת מחדל:** שוללת עצירה כשיש commits שלא דוחפו או כשלענף הנוכחי אין ענף עקיבה מרחוק. מציע `git push -u` ליצירת ענף עקיבה אם נדרש. נכשל פתוח אם אין ריווח מחוקי. +**ברירת מחדל:** דוחה עצירה כאשר יש unpushed commits או כאשר לענף הנוכחי אין remote tracking branch. מציע `git push -u` ליצור tracking branch אם צריך. Fails open אם אין remote מוגדר. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | שם ריווח לדחוף אליו. | +| `remote` | `string` | `"origin"` | שם remote לpush אליו. | **דוגמה:** @@ -771,13 +770,14 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `require-pr-before-stop` **אירוע:** Stop -**ברירת מחדל:** שוללת עצירה כשאין בקשת משיכה לענף הנוכחי, או כשה-PR הקיים סגור ללא merger. נוקט Claude ליצור PR עם `gh pr create`. כאשר ה-PR **מוזג**, המדיניות מורשה (העבודה נשלחה) והודעה רמזה לעבור את הענף (`git checkout main && git pull`). +**ברירת מחדל:** דוחה עצירה כאשר אין pull request לענף הנוכחי, או כאשר ה-PR הקיים סגור ללא merge. מדריך Claude ליצור PR עם `gh pr create`. כאשר ה-PR **merged**, המדיניות מאפשרת (העבודה משלחה) והודעה מרמז להחליף מהענף (`git checkout main && git pull`). -אין פרמטרים. +ללא פרמטרים. מדיניות זו דורשת [GitHub CLI](https://cli.github.com/) (`gh`) להיות מותקן ומאומת. -הרץ `gh auth login` עם אסימון גישה אישי בעל `repo` scope לגישה קריאה לבקשות משיכה. אם `gh` לא מותקן או לא מאומת, המדיניות כושלת פתוחה ומדווחת את הסיבה ל-Claude. +הרץ `gh auth login` עם personal access token שיש לו `repo` scope לגישת קריאה ל- +pull requests. אם `gh` לא מותקן או לא מאומת, המדיניות fails open ודיווח הסיבה ל-Claude. --- @@ -785,24 +785,24 @@ failproofai מגיע עם 39 מדיניויות מובנות שתופסות מצ ### `require-no-conflicts-before-stop` **אירוע:** Stop -**ברירת מחדל:** שוללת עצירה כשהענף הנוכחי לא יכול להתמזג בנקיון לענף הבסיס. המדיניות קודם כל מאשרת שיש `OPEN` PR על GitHub לענף — ללא אחד, אין מטרת merger לאכוף, כל מדיניות קצרה מעגל להתיר. ברגע שה-OPEN` PR מאושר, שני חקירות עצמאיות מופעלות: +**ברירת מחדל:** דוחה עצירה כאשר הענף הנוכחי לא יכול cleanly merge לענף base. המדיניות תחילה מאשרת יש `OPEN` PR ב-GitHub לענף — ללא אחד, אין merge target לאכיפה, כדי המדיניות כלל short-circuits להרשאה. פעם `OPEN` PR מאומת, שני probes עצמאיים הרץ: -1. **מקומי** — `git merge-tree --write-tree --name-only origin/ HEAD`. בסכסוך, הודעת ה-deny שמות קבצי הסכסוך כך Claude יודע בדיוק מה לפתור. -2. **GitHub** — משתמשות שוב בתוצאה `gh pr view --json mergeable,state` שכבר נמשכה בבדיקה מקדימה. תופסת סכסוכים שקובץ `origin/` ישן בתוך היה מיסה (למשל מישהו נחת PR סכסוך על `main` מאז הנתיבה האחרונה). תוצאה `CONFLICTING` שוללת. תוצאה `UNKNOWN` גם שוללת ונוקטת Claude להמתין ~10 שניות ובדוק שוב לפני ניסיון להפסיק שוב — זה מונע false negatives בזמן GitHub recomputes. +1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. על conflict, ה-deny message שמות conflicted files כדי Claude יודע בדיוק מה לפתור. +2. **GitHub** — reuses `gh pr view --json mergeable,state` result כבר fetched בתוך precheck. Catches conflicts שstale local `origin/` היה פחות (לדוגמה מישהו נחת conflicting PR על `main` מאז ה-fetch האחרון). `CONFLICTING` result דוחה. `UNKNOWN` result גם דוחה ומדריך Claude להמתין ~10 שניות ו-re-check לפני נסיון לעצור שוב — זה מונע false negatives בעוד GitHub recomputes. -דוג לחלוטין (מורשה) כאשר: `gh` לא מותקן, אין PR לענף, מצב ה-PR לא `OPEN` (למשל `MERGED`, `CLOSED`), או `gh pr view` מחזירה פלט לא parseable. גם כושל פתוח כאשר `origin/` חסר מקומית או כאשר אין commits לפני בסיס — הנופלים של Layer 1 האלה עדיין בודקים את ה-PR mergeability בחוסן לפני התיר. +דלוג כלל (מאפשר) כאשר: `gh` לא מותקן, אין PR לענף, מצב ה-PR לא `OPEN` (לדוגמה `MERGED`, `CLOSED`), או `gh pr view` חוזר unparseable output. גם fails open כאשר `origin/` חסר locally או כאשר אין commits ahead של base — those Layer 1 fall-throughs עדיין באו cached PR mergeability לפני הרשאה. **פרמטרים:** | פרמטר | סוג | ברירת מחדל | תיאור | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | ענף בסיס לבדוק סכסוכים נגד. | +| `baseBranch` | `string` | `"main"` | ענף base לבדוק conflicts נגדו. | GitHub CLI (`gh`) נדרש למדיניות זו. המדיניות משתמשת ב-`gh pr view` לאשר -שה-OPEN` PR קיים לפני הפעלת כל חקירה סכסוך — ללא `gh`, המדיניות -קצר מעגל להתיר. הרץ `gh auth login` עם אסימון גישה אישי בעל `repo` scope -לגישה קריאה לבקשות משיכה. +`OPEN` PR קיים לפני הרצת כל probe conflict — ללא `gh`, המדיניות +short-circuits להרשאה. הרץ `gh auth login` עם personal access token שיש לו +`repo` scope לגישת קריאה ל-pull requests. --- @@ -810,24 +810,23 @@ GitHub CLI (`gh`) נדרש למדיניות זו. המדיניות משתמשת ### `require-ci-green-before-stop` **אירוע:** Stop -**ברירת מחדל:** שוללת עצירה כשקציני CI נכשלים או עדיין מופעלים בענף הנוכחי. בודקת הן GitHub Actions זרימת עבודה מופעלה וקציני בוט צד שלישי (למשל CodeRabbit, SonarCloud, Codecov). מטפלת `skipped`, `cancelled` ו-`neutral` מסקנות כלא כושל (האחרון מכסה למשל Socket Security alerts על PR של תורמים חיצוניים, היכן האפליקציה בכוונת דיווחים ניטרליים במקום הצלחה/כישלון). מחזירה הודעה אינפורמטיבית כשכל קציני עברו. +**ברירת מחדל:** דוחה עצירה כאשר בדיקות CI נכשלות או עדיין פועלות על הענף הנוכחי. בודק GitHub Actions workflow runs וגם third-party bot checks (לדוגמה CodeRabbit, SonarCloud, Codecov). מטפל `skipped`, `cancelled`, ו-`neutral` conclusions כ-non-failing (האחרון מכסה לדוגמה Socket Security alerts על outside contributor PRs, שבו app באופן עירוני דיווח neutral במקום success/failure). מחזיר הודעה אינפורמטיבית כאשר כל בדיקות עובר. -אין פרמטרים. +ללא פרמטרים. מדיניות זו דורשת [GitHub CLI](https://cli.github.com/) (`gh`) להיות מותקן ומאומת. -הרץ `gh auth login` עם אסימון גישה אישי בעל `repo` scope לגישה קריאה לריצת -זרימות עבודה של Actions והבדיקות API. אם `gh` לא מותקן או לא מאומת, המדיניות -כושלת פתוחה ומדווחת את הסיבה ל-Claude. +הרץ `gh auth login` עם personal access token שיש לו `repo` scope לגישת קריאה ל- +Actions workflow runs וגם Checks API. אם `gh` לא מותקן או לא מאומת, המדיניות fails open ודיווח הסיבה ל-Claude. --- --- -## השבתה של מדיניויות בודדות +## השבתת מדיניות יחידות -הסר מדיניות ספציפית מ-`enabledPolicies` בתצורה שלך, או כבה אותה בלשונית Policies של ממשק הבקרה. +הסר מדיניות ספציפית מ-`enabledPolicies` בתצורה שלך, או toggle אותה ב-טאב Policies של ה-dashboard. ```json { @@ -838,4 +837,4 @@ GitHub CLI (`gh`) נדרש למדיניות זו. המדיניות משתמשת } ``` -מדיניויות שלא רשומות ב-`enabledPolicies` לא מופעלות, אפילו אם ערכי `policyParams` קיימים עבורן. \ No newline at end of file +מדיניות לא רשומות ב-`enabledPolicies` לא פעלות, גם אם ערכי `policyParams` קיימים עבורם. \ No newline at end of file diff --git a/docs/he/cli/audit.mdx b/docs/he/cli/audit.mdx index b77abfba..4459010f 100644 --- a/docs/he/cli/audit.mdx +++ b/docs/he/cli/audit.mdx @@ -1,23 +1,23 @@ --- -title: ביקורת על הפעלות קודמות (beta) -description: "ספור כמה פעמים הסוכן עשה דברים מבוזבזים או מסוכנים על פני תמלילים קודמים" +title: ביקורת של הפעלות קודמות (beta) +description: "ספירה של כמה פעמים הסוכן ביצע דברים מבוזבזים או מסוכנים בטרנסקריפטים עברים" --- - **תכונת Beta.** הביקורת משתלחת כ-beta בעוד אנחנו אוספים משוב מוקדם. - הקטלוג של הגלאים וקבוצת הדוח עלולים להשתנות לפני החתך היציב הבא. - אנא פתח כתבה אם משהו נראה לא בסדר. + **תכונת Beta.** הביקורת משתלחת כ-beta בזמן שאנחנו אוספים משוב מוקדם. + קטלוג הגלאים וקבוצת הדוחות עלולים להשתנות לפני הגרסה היציבה הבאה. + אנא פתח issue אם משהו נראה לא בסדר. -הביקורת משמרת מחדש את תמלילי agent-CLI שלך דרך מנוע המדיניות של failproofai וממציאה דוח חזותי שניתן לשיתוף בעמוד לוח המחוונים **`/audit`** — אתחול הסוכן שלך, ניקוד 0–100, ובדיוק אילו מדיניויות היו תופסות מה. +הביקורת משחזרת מחדש את טרנסקריפטים ה-CLI של הסוכן שלך בעבר דרך מנוע המדיניות של failproofai וייצור דוח חזותי שיתן לשיתוף בעמוד הלוח `/audit` — הארכיטיפ של הסוכן שלך, ציון 0–100, וכן בדיוק אילו מדיניויות היו תופסות מה. -## הפעל אותו +## הריצה שלה -שלוש דרכים פנימה — כולן נוחתות באותו דוח `/audit`. +שלוש דרכים פנימה — כולן מגיעות לאותה דוח `/audit`. -```bash npx (ללא התקנה) +```bash npx (no install) npx -y failproofai audit ``` @@ -25,7 +25,7 @@ npx -y failproofai audit failproofai audit ``` -```bash failproofai (לוח מחוונים) +```bash failproofai (dashboard) failproofai ``` @@ -33,61 +33,56 @@ failproofai - `npx -y failproofai audit` מביא את failproofai, מריץ את הסריקה, ופותח את - לוח המחוונים עבורך — אין צורך בהתקנה מראש. + `npx -y failproofai audit` משיג את failproofai, מפעיל את הסריקה, ופותח את הלוח בשבילך — אין צורך בהתקנה ראשונה. - - `failproofai audit` מריץ את הסריקה בטרמינל שלך, ואז פותח באופן אוטומטי - את `localhost:8020/audit` כאשר זה מסתיים. + + `failproofai audit` מפעיל את הסריקה בטרמינל שלך, ואז פותח את `localhost:8020/audit` באופן אוטומטי כשזה מסיים. - - הרץ את `failproofai` ולחץ על **Audit** בסרט הניווט (בין Policies - ו-Projects), או פתח את `/audit` ישירות. + + הפעל את `failproofai` וקלק על **Audit** בסרגל הניווט (בין Policies ו-Projects), או פתח את `/audit` ישירות. - הרץ את `failproofai audit -h` (או `--help`) כדי לראות שימוש. הביקורת פועלת **לחלוטין - במצב לא מקוון** — אין צורך בחשבון או ברשת — ולוח המחוונים ממשיך לשרת - עד שתעצור אותו עם `Ctrl+C`. + הפעל את `failproofai audit -h` (או `--help`) כדי לראות שימוש. הביקורת מתבצעת **באופן מלא ללא חיבור לאינטרנט** — אין צורך בחשבון או ברשת — והלוח ממשיך לשרת עד שאתה עוצר אותו עם `Ctrl+C`. -לוח המחוונים סורק תמלילי agent CLI קודמים במכונה זו (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) ודיווח כמה פעמים הסוכן עשה דברים שמבנה failproofai כדי לעצור — בדיקות משתנות סביבה, כפיות דחיפה, קידומות `cd ` מיותרות, לולאות sleep-polling, קריאה חוזרת של קבצים שנערכו זה עתה, ועוד. +הלוח סורק טרנסקריפטים קודמים של CLI סוכן על מכונה זו (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) ודיווח כמה פעמים הסוכן עשה דברים שה-failproofai בנוי לעצור — בדיקות env-var, force pushes, `cd ` prefixes מיותרות, sleep-polling loops, קריאה חוזרת של קבצים שנערכו זה עתה, ועוד. -לכל תמליל, כל אירוע tool-use משמר מחדש דרך 39 המדיניויות המובנות **וגם** דרך 8 גלאים audit-only שתופסים דפוסים שעדיין לא מכוסים על ידי מדיניויות זמן ריצה. הספירות מצטברות לכל מדיניות / גלאי על פני כל הפעלות. +לכל טרנסקריפט, כל אירוע tool-use משוחזר מחדש דרך 39 המדיניויות המובנות **וגם** דרך 8 גלאים המיוחדים לביקורת שתופסים דפוסים שעדיין לא מכוסים על ידי מדיניויות זמן אמת. הספירות מצטברות לכל מדיניות / גלאי בכל ההפעלות. ## מה אתה מקבל -עמוד `/audit` הוא כרזה של מסך יחיד שניתן לשיתוף ואחריו ארבע חלקים מתחת לקפל: +דף `/audit` הוא **פוסטר** בעמוד יחיד וניתן לשיתוף ואחריו ארבע קטעים מתחת לקיפול: -1. **כרזה** — זהות הסוכן שלך במבט חטוף: שלו **archetype** (אחד מ-8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), מילות המפתח של הפרסונה שלו, כמה נדיר האתחול הזה, וניקוד **0–100** עם רצועת שכבה (`S` עד `bottom tier`). בנוי לשיתוף — פוסט ל-X או LinkedIn, או הורד אותו כ-PNG. -2. **`// strengths`** — מה הסוכן שלך כבר עושה טוב, כמספרים אמיתיים מהסריקה (למשל clean-tool-call %, `0` push-to-main attempts), מוצג רק כאשר למדיניות הרלוונטית יש רשומה נקייה. -3. **`// quirks`** — מה התפזר: טבלה דורגת של התנהגויות shes failproofai היה תופס — *מתי* זה קרה לאחרונה, *מה התפזר* (וה-builtin שהיה חוסם אותו), שלו *severity*, וכמה פעמים זה היה *seen* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — רשימת התיקון הקבוע: שורה אחת לכל מדיניות עם `failproofai policy add ` העתקה-הדבק, ובנוסף כפתור **install all** שמאפשר כל המלצה בבת אחת ומציג את **projected score** שלך אם עשית. -5. **`// come back better`** — בנה את ההרגל: הגדר דוא"ל לביקורת חוזרת **reminder** (`3d` / `7d` / `14d` / `30d`) או biקורת כעת, והזמן **invite a friend** להפעיל ביקורת משלהם (נשלח מ-failproof.ai, Cc'd אליך). תזכורות והזמנות דורשות כניסה — ראה [`failproofai auth`](/he/cli/auth). +1. **פוסטר** — הזהות של הסוכן שלך בהשקפה: **ארכיטיפ** שלו (אחד מ-8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), מילות המפתח של הגיבור שלו, כמה נדיר אותו ארכיטיפ, וציון **0–100** עם פס רמה (`S` ועד `bottom tier`). בנוי לשיתוף — פרסם ל-X או LinkedIn, או הורד אותו כ-PNG. +2. **`// strengths`** — מה הסוכן שלך כבר עושה טוב, כמספרים אמיתיים מהסריקה (למשל clean-tool-call %, `0` push-to-main attempts), מוצג רק כאשר למדיניות הרלוונטית יש רקורד נקי. +3. **`// quirks`** — מה חמק: טבלה מדורגת של התנהגויות שה-failproofai היה תופס — *מתי* זה קרה לאחרונה, *מה חמק* (וה-builtin שהיה חוסם אותו), **חומרתו**, וכמה פעמים זה היה **נראה** (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — רשימת התיקון המוקצה: שורה אחת לכל מדיניות עם `failproofai policy add ` copy-paste, בתוספת **install all** button שמאפשר כל המלצה בבת אחת ומציג את **ציוןך החזוי** אם הייתה עושה את זה. +5. **`// come back better`** — בנה את ההרגל: הגדר **reminder** בדוא"ל לביקורת חוזרת (`3d` / `7d` / `14d` / `30d`) או בצע ביקורת חוזרת עכשיו, ו**הזמן חבר** להפעיל את הביקורת שלהם (שנשלח מ-failproof.ai, Cc אליך). Reminders והזמנות דורשים כניסה — ראה [`failproofai auth`](/he/cli/auth). -## גלאים audit-only בלבד +## גלאים המיוחדים לביקורת -אלה תופסים דפוסי התנהגות "stupid behavior" שאינם (עדיין) מאולצים בזמן אמת. הם פועלים רק במהלך הביקורת ולעולם לא חוסמים קריאת כלי חי. +אלה מגלים דפוסי התנהגות "טופשית" שאינם (עדיין) מאומצים בזמן אמת. הם מתבצעים רק במהלך הביקורת ואף פעם לא חוסמים קריאת כלי כלי חי. | גלאי | מה זה סופר | |---|---| -| `redundant-cd-cwd` | פקודות Bash המתחילות ב-`cd && …` למרות שפקודות כבר פועלות ב-`cwd`. | +| `redundant-cd-cwd` | פקודות Bash שמתחילות עם `cd && …` גם כשהפקודות כבר פועלות ב-`cwd`. | | `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` בקובץ מקור יחיד — השתמש בכלי `Read`. | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` עריכות במקום — השתמש בכלי `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / `echo > file` רב-שורות כתיבת קבצים — השתמש בכלי `Write`. | -| `sleep-polling-loop` | `sleep N` ארוך (≥ 30s) או לולאות polling `while …; sleep …; done`. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, וכו' — שדה ל-`cwd` במקום. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, דילוג על ווקפים. | -| `reread-after-edit` | `Read` של קובץ שנערך זה עתה `Edit`/`Write` באותה הפעלה. | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` עריכות בעדכון — השתמש בכלי `Edit`. | +| `prefer-write-over-heredoc` | Heredoc / `echo > file` ריבוי שורות בכתיבת קבצים — השתמש בכלי `Write`. | +| `sleep-polling-loop` | `sleep N` ארוך (≥ 30s) או `while …; sleep …; done` polling loops. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, וכו' — scope ל-`cwd` במקום זאת. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, דלג על hooks. | +| `reread-after-edit` | `Read` של קובץ שזה עתה `Edit`/`Write` באותה הפעלה. | -## קשיים +## מטמונים -- **Per-transcript cache** ב-`~/.failproofai/cache/audit/.json` מפותח על ידי `(mtime, size, engineVersion, detectorVersion)` — מבטל באופן אוטומטי כאשר התמליל או קוד המדיניות/הגלאי משתנה. כל ערך גם אחסן חותמת זמן `cachedAt` כ**metadata TTL** (לא חלק ממפתח המטמון); ערכים ישנים יותר מ**7 ימים** נדחים בקריאה כך שתוצאות חיות ארוכות לא חיות מעבר לכוונון הגלאים. -- **Whole-result cache** ב-`~/.failproofai/audit-dashboard.json` (mode 0600). מאפשר ללוח המחוונים להעניק דוח מיידי בניווט מבלי להפעיל מחדש. גם נדחה בקריאה בעבר ה-**7-day TTL** — `/audit` ואז נופל דרך מצב הריק שלו ומזמין ריצה טרייה. לחץ על `[ re-audit now ]` בקרבת התחתון של הדוח כדי לרענן — re-audit שולח `noCache: true`, כך שהוא עוקף את המטמון per-transcript וסורק מחדש כל תמליל במקום להחזיר את התוצאה המטומנה; הריצה זורמת התקדמות דרך רצועה דבקה עליונה ומחליפה את התוצאה במקום בהצלחה (אין טעינת דף מחדש; re-audit כושל שומר על הדוח הקודם). +- **Per-transcript cache** ב-`~/.failproofai/cache/audit/.json` מקודד לפי `(mtime, size, engineVersion, detectorVersion)` — מתבטל באופן אוטומטי כאשר הטרנסקריפט או קוד המדיניות/הגלאי משתנה. כל ערך גם אחסן timestamp של `cachedAt` כ**מטא-נתונים TTL** (לא חלק מהמפתח המטמון); ערכים ישנים מ**7 ימים** נדחים בקריאה כדי שתוצאות ארוכות אדומות לא יחיו יותר מ-intent גלאי מתפתחת. +- **Whole-result cache** ב-`~/.failproofai/audit-dashboard.json` (מצב 0600). מאפשר ללוח להירעיל באופן מלא בניווט ללא הפעלה מחדש. גם נדחה בקריאה עבור ה**7-day TTL** — `/audit` אז נופל דרך מצבו הריק ודחוף ריצה טרייה. לחץ על `[ re-audit now ]` בקרוב לתחתית הדוח כדי לרענן — re-audit שולח `noCache: true`, כך שהוא עוקף את ה-per-transcript cache וסורק מחדש כל טרנסקריפט במקום להחזיר את התוצאה במטמון; ההפעלה זורמת התקדמות דרך רצועה דבוקה בחלק העליון ומחליפה את התוצאה במקום בהצלחה (אין טעינת עמוד; re-audit כושל שומר על הדוח הקודם). ## הערות -- **ללא תמורה.** הביקורת משמרת במצב קריאה בלבד. `warn-repeated-tool-calls` מדולל מכיוון שה-sidecar לפי הפעלה שלו אחרת היה משתנה. -- **מדיניויות זרימת עבודה דלוגות.** `require-*-before-stop` מדיניויות יורים רק על אירועי `Stop` ו-`execSync` כנגד מצב git חי — להם אין פרשנות משמעותית של "מה היה קורה ב-2025", כך שהם לא מופיעים בספירות הביקורת. -- **מדיניויות מותאמות אישית דלוגות.** וו קסטום המסופק על ידי המשתמש אינו משמר מחדש (הם עלולים להשתנות מאז הפעלה מקורית). \ No newline at end of file +- **אין מוטציה.** הביקורת משחזרת מחדש במצב קריאה בלבד. `warn-repeated-tool-calls` מדולג מכיוון שה-per-session sidecar שלו היה שונה אחרת. +- **מדיניויות זרימת עבודה דלוגות.** `require-*-before-stop` מדיניויות ירי רק על אירועי `Stop` ו-`execSync` נגד מצב git חי — אין להם פירוש משמעותי "מה היה קורה ב-2025", כך שהם לא מופיעים בספירות ביקורת. +- **מדיניויות מותאם אישית דלוגות.** ה-hooks שסופקו משתמש לא משוחזרים מחדש (הם אולי השתנו מאז ההפעלה המקורית). \ No newline at end of file diff --git a/docs/he/configuration.mdx b/docs/he/configuration.mdx index 24e3cda4..0369fabd 100644 --- a/docs/he/configuration.mdx +++ b/docs/he/configuration.mdx @@ -1,61 +1,61 @@ --- -title: הגדרות -description: "פורמט קובץ הגדרות, מערכת תלת-היקף, וכללי מיזוג" +title: תצורה +description: "פורמט קובץ תצורה, מערכת שלוש-ההיקפים, וכללי מיזוג" icon: gear --- -failproofai משתמש בקובצי הגדרות JSON כדי לשלוט באילו מדיניות פעילה, כיצד הן מתנהגות, ומאיפה מדיניות מותאמת אישית נטענת. ההגדרות מעוצבות להיות קלות לשיתוף עם הצוות שלך - בצע commit אליהם למאגר שלך וכל מפתח יקבל את אותה רשת הבטיחות עבור agent. +failproofai משתמש בקובצי תצורה JSON כדי לשלוט אילו מדיניות פעילה, איך הן מתנהגות, והיכן מדיניות מותאמת אישית נטענת מ. התצורה מעוצבת להיות קלה לשיתוף עם הצוות שלך - עדכון אותה לאחסן שלך וכל מפתח מקבל את אותה רשת בטיחות ל-agent. --- -## היקפי הגדרות +## היקפי תצורה -יש שלושה היקפי הגדרות, המוערכים לפי סדר עדיפויות: +יש שלושה היקפי תצורה, מוערכים בסדר עדיפות: | היקף | נתיב קובץ | מטרה | |-------|-----------|---------| -| **project** | `.failproofai/policies-config.json` | הגדרות לכל מאגר, בcomit לשליטה בגרסאות | -| **local** | `.failproofai/policies-config.local.json` | עקיפה אישית לכל מאגר, מתוך gitignore | -| **global** | `~/.failproofai/policies-config.json` | ברירות מחדל ברמת משתמש לכל הפרויקטים | +| **project** | `.failproofai/policies-config.json` | הגדרות לכל-ריפוזיטורי, מוטלות על בקרת גרסה | +| **local** | `.failproofai/policies-config.local.json` | עקיפות אישיות לכל-ריפוזיטורי, מתוך gitignore | +| **global** | `~/.failproofai/policies-config.json` | ברירות מחדל ברמת משתמש בכל הפרויקטים | -כאשר failproofai מקבל אירוע hook, הוא טוען ומוזג את כל שלושת הקובצים שקיימים בספריית העבודה הנוכחית. +כאשר failproofai מקבל אירוע hook, היא טוענת וממזגת את כל שלושת הקבצים שקיימים עבור ספריית העבודה הנוכחית. ### כללי מיזוג -**`enabledPolicies`** - האיחוד של כל שלושת ההיקפים. מדיניות שמופעלת בכל רמה פעילה. +**`enabledPolicies`** - האיחוד של כל שלושת ההיקפים. מדיניות שמורשת ברמה כלשהי היא פעילה. ```text project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← deduplicated union +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← איחוד מנוקה ``` -**`policyParams`** - ההיקף הראשון שמגדיר פרמטרים לmדיניות מסוימת מנצח לחלוטין. אין מיזוג עמוק של ערכים בתוך הפרמטרים של המדיניות. +**`policyParams`** - ההיקף הראשון המגדיר params עבור מדיניות מסוימת מנצח לגמרי. אין מיזוג עמוק של ערכים בתוך params של מדיניות. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project מנצח, global מתוספר +resolved: { allowPatterns: ["sudo apt-get update"] } ← project מנצח, global מתעלם ``` ```text -project: (no block-sudo entry) -local: (no block-sudo entry) +project: (אין ערך block-sudo) +local: (אין ערך block-sudo) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← יורד לכלל הglobal +resolved: { allowPatterns: ["sudo systemctl status"] } ← נופל דרך ל-global ``` -**`customPoliciesPath`** - ההיקף הראשון שמגדיר אותו מנצח. +**`customPoliciesPath`** - ההיקף הראשון המגדיר אותו מנצח. -**`llm`** - ההיקף הראשון שמגדיר אותו מנצח. +**`llm`** - ההיקף הראשון המגדיר אותו מנצח. --- -## פורמט קובץ הגדרות +## פורמט קובץ תצורה ```json { @@ -96,85 +96,85 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← יורד לכלל ה --- -## התייחסות לשדות +## הפניה שדות ### `enabledPolicies` סוג: `string[]` -רשימת שמות המדיניות שיש להפעיל. השמות חייבים להתאים בדיוק לזהויות המדיניות המוצגות על ידי `failproofai policies`. ראה [Built-in Policies](/he/built-in-policies) לקבלת הרשימה המלאה. +רשימת שמות מדיניות להפעלה. שמות חייבים להתאים בדיוק למזהי המדיניות המוצגים על ידי `failproofai policies`. ראה [Built-in Policies](/he/built-in-policies) לרשימה המלאה. -מדיניות שלא ב`enabledPolicies` אינן פעילות, גם אם יש להן רשומות ב`policyParams`. +מדיניות שלא ב-`enabledPolicies` אינה פעילה, גם אם יש להן ערכים ב-`policyParams`. ### `policyParams` סוג: `Record>` -עקיפות פרמטרים לכל מדיניות. המפתח החיצוני הוא שם המדיניות; המפתחות הפנימיים ספציפיים למדיניות. כל מדיניות מתעדת את הפרמטרים הזמינים שלה ב[Built-in Policies](/he/built-in-policies). +עקיפות פרמטרים לכל-מדיניות. המפתח החיצוני הוא שם המדיניות; המפתחות הפנימיים הם ספציפיים למדיניות. כל מדיניות מתעדת את הפרמטרים הזמינים שלה ב-[Built-in Policies](/he/built-in-policies). -אם למדיניות יש פרמטרים אך אתה לא מציין אותם, משמשים ברירות המחדל המובנות של המדיניות. משתמשים שאינם מגדירים את `policyParams` כלל מקבלים התנהגות זהה לגרסאות קודמות. +אם למדיניות יש פרמטרים אך אתה לא מציין אותם, ברירות המחדל המובנות של המדיניות משמשות. משתמשים שלא מעצבים את `policyParams` כלל מקבלים התנהגות זהה לגרסאות קודמות. -מפתחות לא ידועים בתוך בלוק הפרמטרים של מדיניות מתעלמים בשקט בזמן הפעלת hook אך מסומנים כאזהרות כאשר אתה מריץ `failproofai policies`. +מפתחות לא ידועים בתוך בלוק params של מדיניות מתעלמים בשקט בזמן fire של hook אך מסומנים כאזהרות כאשר אתה מריץ את `failproofai policies`. -#### `hint` (חוצה פעולות) +#### `hint` (חוצה-קטעים) -סוג: `string` (בחירה) +סוג: `string` (אופציונלי) -הודעה שצורפה לסיבה כאשר מדיניות מחזירה `deny` או `instruct`. השתמש בה כדי לתן לClaude הדרכה פעולה ישירה ללא שינוי המדיניות עצמה. +הודעה המצורפת לסיבה כאשר מדיניות מחזירה `deny` או `instruct`. השתמש בה כדי לתת ל-Claude הנחיה יעילה ללא שינוי המדיניות עצמה. -עובד עם כל סוג מדיניות — מובנה, מותאם אישית (`custom/`), מוסכמת פרויקט (`.failproofai-project/`), או מוסכמת משתמש (`.failproofai-user/`). +עובד עם כל סוג מדיניות — מובנה, מותאמת אישית (`custom/`), מוסכמה של פרויקט (`.failproofai-project/`), או מוסכמה של משתמש (`.failproofai-user/`). ```json { "policyParams": { "block-force-push": { - "hint": "Try creating a fresh branch instead." + "hint": "נסה ליצור ענף טרי במקום." }, "block-sudo": { "allowPatterns": ["sudo apt-get"], - "hint": "Use apt-get directly without sudo." + "hint": "השתמש ב-apt-get ישירות ללא sudo." }, "custom/my-policy": { - "hint": "Ask the user for approval first." + "hint": "בקש אישור מהמשתמש תחילה." } } } ``` -כאשר `block-force-push` מסרב, Claude רואה: *"Force-pushing is blocked. Try creating a fresh branch instead."* +כאשר `block-force-push` מעכבת, Claude רואה: *Force-pushing is blocked. Try creating a fresh branch instead.* -ערכים שאינם מחרוזות ומחרוזות ריקות מתעלמים בשקט. אם `hint` לא מוגדר, ההתנהגות לא משתנה (תאימות לאחור). +ערכים שאינם מחרוזות ומחרוזות ריקות מתעלמים בשקט. אם `hint` לא מוגדר, התנהגות לא משתנה (תאימות לאחור). ### `customPoliciesPath` סוג: `string` (נתיב מוחלט) -נתיב לקובץ JavaScript המכיל מדיניות hook מותאמת אישית. זה מוגדר באופן אוטומטי על ידי `failproofai policies --install --custom ` (הנתיב מוחזר לערך מוחלט לפני שנשמר). +נתיב לקובץ JavaScript המכיל מדיניות hook מותאמות אישית. זה מוגדר באופן אוטומטי על ידי `failproofai policies --install --custom ` (הנתיב מחוקק למוחלט לפני שמור). -הקובץ נטען מחדש בכל אירוע hook - אין caching. ראה [Custom Policies](/he/custom-policies) לפרטי כתיבה. +הקובץ נטען מחדש בכל אירוע hook - אין זיכרון מטמון. ראה [Custom Policies](/he/custom-policies) לפרטי כתיבה. ### מדיניות מבוססת מוסכמה -בנוסף לעקיפה ההפנייה `customPoliciesPath`, failproofai גילוי ויוטען באופן אוטומטי קובצי מדיניות מתיקיות `.failproofai/policies/`: +בנוסף ל-`customPoliciesPath` המפורש, failproofai גילויה אוטומטי וטוענת קובצי מדיניות מ-`.failproofai/policies/` ספריות: | רמה | ספרייה | היקף | |-------|-----------|-------| -| Project | `.failproofai/policies/` | משותף עם צוות דרך שליטה בגרסאות | +| Project | `.failproofai/policies/` | משותף לצוות דרך בקרת גרסה | | User | `~/.failproofai/policies/` | אישי, חל על כל הפרויקטים | -**התאמת קובץ:** רק קובצים התואמים ל`*policies.{js,mjs,ts}` נטענים (לדוגמה `security-policies.mjs`, `workflow-policies.js`). קובצים אחרים בספרייה מתעלמים. +**התאמת קבצים:** רק קבצים התואמים `*policies.{js,mjs,ts}` נטענים (למשל `security-policies.mjs`, `workflow-policies.js`). קבצים אחרים בספרייה מתעלמים. -**אין צורך בהגדרה:** מדיניות מוסכמה אינה דורשת רשומות ב`policies-config.json`. פשוט שים קובצים בספרייה והם אוסף בהתקדמות hook הבא. +**אין צורך בתצורה:** מדיניות מוסכמה לא דורשת ערכים ב-`policies-config.json`. פשוט זרוק קבצים לספרייה והם נבחרים באירוע hook הבא. -**טעינה איחוד:** גם ספריות מוסכמה של פרויקט וגם משתמש סרוקות. כל קובצים תואמים משתי הרמות נטענים (שלא כמו `customPoliciesPath` אשר משתמש בראשון-היקף-מנצח). +**טעינת איחוד:** שתי ספריות הוסכמה של פרויקט ומשתמש סרוקות. כל הקבצים התואמים משתי הרמות נטענים (בניגוד ל-`customPoliciesPath` המשתמש בניצחון הראשון-היקף). -ראה [Custom Policies](/he/custom-policies) לפרטים נוספים וודוגמאות. +ראה [Custom Policies](/he/custom-policies) לפרטים וודוגמאות נוספות. ### `llm` -סוג: `object` (בחירה) +סוג: `object` (אופציונלי) -הגדרות לקוח LLM למדיניות שמבצעות קריאות AI. לא נדרש לרוב ההגדרות. +תצורת לקוח LLM עבור מדיניות שעורכות קריאות AI. לא נדרש ברוב ההתקנות. ```json { @@ -187,22 +187,26 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← יורד לכלל ה --- -## ניהול הגדרות מ-CLI +## ניהול תצורה מ-CLI -הפקודות `policies --install` ו`policies --uninstall` כותבות לקובץ הגדרות hook של ה-CLI של ה-agent (נקודות הכניסה של hook), בעוד ש`policies-config.json` הוא הקובץ שאתה מנהל ישירות. שניהם נפרדים: +פקודות `policies --install` ו-`policies --uninstall` כותבות לקובץ הגדרות hook של agent CLI שלך (נקודות הכניסה של hook), בעודothat `policies-config.json` הוא הקובץ שאתה מנהל ישירות. השניים נפרדים: -- **הגדרות Agent CLI** — אומרות ל-agent להתקשר ל`failproofai --hook ` בכל שימוש בכלי: +- **הגדרות Agent CLI** — אומר ל-agent להתקשר עם `failproofai --hook ` בכל שימוש בכלי: - **Claude Code**: `~/.claude/settings.json` (משתמש), `/.claude/settings.json` (פרויקט), `/.claude/settings.local.json` (מקומי) - - **OpenAI Codex**: `~/.codex/hooks.json` (משתמש), `/.codex/hooks.json` (פרויקט) — Codex אין לו היקף `local` - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (משתמש), `/.github/hooks/failproofai.json` (פרויקט) — Copilot אין לו היקף `local`. רשומות Hook משתמשות בשדות פקודה `bash`/`powershell` של Copilot עם מפתח OS עם `timeoutSec`; הקובץ נושא סימן `version: 1` ברמה העליונה. תמיכת Copilot CLI היא **beta** בעודנו מאמתים את סכימת רשומת `events.jsonl` (שהדוקים הציבוריים אינם מציינים) מול יותר ישיבות בעולם האמיתי. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (משתמש), `/.cursor/hooks.json` (פרויקט) — Cursor אין לו היקף `local`. רשומות Hook משתמשות בצורה בעיצוב Claude `{type, command, timeout}` (לא פיצול `bash`/`powershell`), אך מאוחסנות תחת מפתחות אירוע camelCase (`preToolUse`, `beforeSubmitPrompt`, …) במערך שטוח לכל [סכימת hooks של Cursor](https://cursor.com/docs/hooks); הקובץ נושא סימן `version: 1` ברמה העליונה. המטפל מנרמל camelCase → PascalCase דרך `CURSOR_EVENT_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. תמיכת Cursor Agent היא **beta** בעודנו מאמתים את קובץ הטרנסקריפט של Cursor (לא מצוין בדוקים הציבוריים) מול יותר התקנות בעולם האמיתי. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (משתמש), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (פרויקט) — OpenCode אין לו היקף `local`. בשונה משש ה-CLI האחרים, OpenCode **אין לו מערכת hook פקודה חיצונית**: הוא טוען בתוך התהליך תוספי JS/TS שנרשמו במפורש דרך מערך `plugin: []` ב`opencode.json` (גילוי אוטומטי מ`.opencode/plugins/` **אינו** כיצד תוספים נטענים ב-opencode v1.14.33). ההתקנה מושכת שים של תוספון שנוצר בזריעה שקוראות ב-subprocess את הבינארי failproofai ומתרגמת את התגובה JSON בעיצוב Claude של הבינארי חזרה לסמנטיקה של תוספון: `throw new Error()` עבור deny של אירוע כלי (מבטל את קריאת הכלי), `client.session.prompt(...)` עבור instruct וגם עבור deny של `Stop` / `SubagentStop` (משדרת את סיבת הreject כהודעת המשתמש הבאה — הערוץ היחיד כלומל-retry מכיוון ש`session.idle` הוא התראה בלבד ו-throwing ממנו הוא no-op), ו-no-op עבור allow. השם מנרמל גם שמות כלים (אותיות קטנות → PascalCase דרך `OPENCODE_TOOL_MAP`) וגם מפתחות טיעון קלט כלי (camelCase → snake_case דרך `OPENCODE_TOOL_INPUT_MAP` עבור `Read` / `Write` / `Edit`, לדוגמה `filePath` → `file_path`, `oldString` → `old_string`) לפני שליחה קדימה לבינארי, כך שבדיקות נתיב מובנות כמו `block-read-outside-cwd`, `block-env-files`, ו`block-secrets-write` נשרפות ללא שינוי בקריאות כלים OpenCode. ישיבות חיות בבסיס נתונים SQLite של opencode ב`~/.local/share/opencode/opencode.db`; צופה הישיבה של הדשבורד קורא להם דרך `opencode db --format json` ו`opencode export `. תמיכת OpenCode היא **beta** בעודנו מאמתים התנהגות על פני גרסאות ומול יותר ישיבות בעולם האמיתי. ראה את [דוקים של תוספי OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (משתמש), `/.pi/settings.json` (פרויקט) — Pi אין לו היקף `local`. Pi טוען חבילות הרחבה TypeScript בעת ההתחלה; קובץ ההגדרות הוא מערך מחרוזות שטוח `{"packages": ["./relative/path", …]}`. failproofai כותב רשומת מערך פקיות אחת המצביעה על תיקיית `pi-extension/` המכוסה שלה. ההרחבה מחתום פנימית על אירועי `tool_call` / `user_bash` / `input` / `session_start` של Pi ופורקת `failproofai --hook --cli pi`; המטפל מנרמל underscore_lower_snake_case → PascalCase דרך `PI_EVENT_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. טיעון קלט כלי מנורמל גם דרך `PI_TOOL_INPUT_MAP` (Read / Write / Edit של Pi משדרות `path` ולא `file_path`; מיפוי המפתח ברמה העליונה מאפשר ל`block-env-files` ו`block-secrets-write` נשרפות — `block-read-outside-cwd` כבר היה פנייה חוזרת של `path`). תמיכת Pi היא **beta** בזמן שה-API הרחבה של Pi וסכימת יומן הישיבה מתייצבות. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (משתמש), `/.gemini/settings.json` (פרויקט) — Gemini אין לו היקף `local` (הוא מתעד היקף `system` ב`/etc/gemini-cli/settings.json` שfalieproofai אינו חושף). רשומות Hook משתמשות בצורה `{type, command, timeout}` של Claude מגולפת בסכימת matcher של Gemini `{matcher, hooks: [...]}` עם `matcher: "*"` כברירת מחדל. אירועים הם PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); המטפל ממפה לשמות הקנוניים של Claude דרך `GEMINI_EVENT_MAP`. שמות כלים הם snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — המטפל מנרמל דרך `GEMINI_TOOL_MAP` כך שמדיניות מובנות קיימות נשרפות ללא שינוי. מעריך המדיניות משדרת צורה שטוחה של Gemini `{decision: "deny", reason}` (מעדיפה לפי הכלל הזהב של Gemini exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` להזרקת הקשר על BeforeAgent / AfterTool / SessionStart, ו`{decision: "block", reason}` על AfterAgent עבור סמנטיקת כפיית retry. תמיכת Gemini CLI היא **beta** בעודנו מרחיבים כיסוי בעולם אמיתי. ראה את [דוקים של hooks של Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**היקף משתמש בלבד** — Hermes אין לו תצורת פרויקט/מקומית). Hermes הוא **שער** Slack/Telegram, כך שהתקנה אחת מיירטת קריאות כלים מכל פלטפורמה (Slack/Telegram/cli/cron) **וגם** תוך-אג'נטים. רשומות Hook הן זוג `{command, timeout}` (timeout בשניות) תחת מפת `hooks:` שבאופן events snake_case של Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); המטפל מנרמל אירועים דרך `HERMES_EVENT_MAP` וגם שמות כלים דרך `HERMES_TOOL_MAP` כך שמדיניות מובנות נשרפות ללא שינוי. התצורה נערכת דרך תעודת YAML דורכת-שומרת-הערות `Document` כך שהגדרות אחרות של המנהל שורדות, והתקנה מוגדרת `hooks_auto_accept: true` כך השער חסר-TTY מריץ את ה-hooks ללא בקשת הסכמה. המעריך משדרת חוזה `{"decision":"block","reason"}` stdout של Hermes (Hermes מתעלם מקודי יציאה). **מגבלות:** Hermes אין להשקע stop `Stop` של turn-end, כך שה`require-*-before-stop` מובנה לעולם לא נשרפים עבורו (בלא הגבלה, לא שבור); `instruct` מדרדר ל-allow-עם-logged-note (אין ערוץ הקשר נוסף); ו-redaction-secret של פלט (`sanitize-*`) לא יכול לשכתב פלט כלים דרך חוזה shell-hook. Hermes הוא **גם** מקור ביקורת **offline** — הדשבורד קורא ישיבות שער שלו ישירות מ`~/.hermes/state.db`. -- **`policies-config.json`** — אומר ל-failproofai איזו מדיניות להעריך ועם אילו פרמטרים (משותף על פני כל ה-CLI של ה-agent) - -עבור `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` למטרה סוכן ספציפי (space-separated או חוזר לכל תת-קבוצה): + - **OpenAI Codex**: `~/.codex/hooks.json` (משתמש), `/.codex/hooks.json` (פרויקט) — ל-Codex אין היקף `local` + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (משתמש), `/.github/hooks/failproofai.json` (פרויקט) — ל-Copilot אין היקף `local`. ערכי Hook משתמשים בשדות הפקודה `bash`/`powershell` שנקבעו ב-OS של Copilot עם `timeoutSec`; הקובץ נושא סימן `version: 1` ברמה-עליונה. תמיכת Copilot CLI היא **beta** בזמן שאנחנו מאמתים את סכמת רשומת `events.jsonl` (שהדוקומנטציה הציבורית לא מציינת) מול יותר ממליצות בעולם-אמיתי. **מצב ה-agent של VS Code Copilot Chat (Preview)** קורא קונפיגים של hook מ-`.github/hooks/*.json`, `~/.copilot/hooks/*.json`, ו-`~/.claude/settings.json` (מנוהל על ידי ההגדרה `chat.hookFilesLocations`) באמצעות אותו חוזה בצורת Claude של `{hookSpecificOutput:{permissionDecision:"deny",…}}` — הנתיבים המדויקים שכזה `copilot` אינטגרציה וה-`claude` אינטגרציה (`~/.claude/settings.json`) כבר כותבות, כך `failproofai policies --install --cli copilot` (או `--cli claude`) **כבר אוכפת במצב ה-agent של VS Code** ללא אינטגרציה נפרדת של `vscode` (מאומת חי מיומני גילוי של VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (משתמש), `/.cursor/hooks.json` (פרויקט) — ל-Cursor אין היקף `local`. ערכי Hook משתמשים בצורת בצורת Claude של `{type, command, timeout}` (אין חלוקת `bash`/`powershell`), אך מאוחסנים תחת מפתחות ביוםamelCase (`preToolUse`, `beforeSubmitPrompt`, …) במערך שטוח לכל סכמת hooks של Cursor בעמוד [hooks schema](https://cursor.com/docs/hooks); הקובץ נושא סימן `version: 1` ברמה-עליונה. המטפל מנרמל camelCase → PascalCase דרך `CURSOR_EVENT_MAP` כך מדיניות מובנות קיימות ללא שינוי. תמיכת Cursor Agent היא **beta** בזמן שאנחנו מאמתים את תמליל של Cursor על-דיסק (לא מצוין בדוקומנטציה הציבורית) מול יותר התקנות בעולם-אמיתי. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (משתמש), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (פרויקט) — ל-OpenCode אין היקף `local`. בניגוד לחמשת CLI האחרים, ל-OpenCode יש **אין מערכת hook של פקודה חיצונית**: היא טוענת בתוך-תהליך JS/TS plugins שנרשמו בבירור דרך המערך `plugin: []` ב-`opencode.json` (גילוי-אוטומטי מ-`.opencode/plugins/` הוא **לא** איך plugins טוענים ב-opencode v1.14.33). התקנה מטילה shim plugin קטן שנוצר שקורא subprocess-calls לבינרי failproofai ותרגום התשובה JSON בצורת Claude של הבינרי חזרה לסמנטיקה של plugin: `throw new Error()` עבור tool-event deny (מבטל את קריאת הכלי), `client.session.prompt(...)` עבור instruct וגם `Stop` / `SubagentStop` deny (מגיש את הסיבה deny כהודעת המשתמש הבאה — הערוץ היחיד של force-retry מאז `session.idle` הוא notification-only וזריקה ממנו היא no-op), ו-no-op עבור allow. ה-shim מנרמל שם כלים (אותיות קטנות → PascalCase דרך `OPENCODE_TOOL_MAP`) ו-tool-input arg keys (camelCase → snake_case דרך `OPENCODE_TOOL_INPUT_MAP` עבור `Read` / `Write` / `Edit`, למשל `filePath` → `file_path`, `oldString` → `old_string`) לפני הפניה לבינרי, כך בדקות דרך בדיקה מובנות כמו `block-read-outside-cwd`, `block-env-files`, ו-`block-secrets-write` קיימות ללא שינוי בקריאות כלי OpenCode. הפעלות חיות ב-SQLite DB של opencode ב-`~/.local/share/opencode/opencode.db`; צפיית הפעלה של הדוד קורא אותן דרך `opencode db --format json` ו-`opencode export `. תמיכת OpenCode היא **beta** בזמן שאנחנו מאמתים התנהגות בין גרסאות ומול יותר הפעלות בעולם-אמיתי. ראה [OpenCode plugins docs](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (משתמש), `/.pi/settings.json` (פרויקט) — ל-Pi אין היקף `local`. Pi טוענת חבילות הרחבה TypeScript בעת ההתחלה; קובץ ההגדרות הוא מערך string שטוח `{"packages": ["./relative/path", …]}`. failproofai כותבת ערך חד-מערך packages המצביע על ספריית ה-`pi-extension/` המצטברת שלה. ההרחבה בפנים מנויה לאירועי `tool_call` / `user_bash` / `input` / `session_start` של Pi ודורכת shell ל-`failproofai --hook --cli pi`; המטפל מנרמל underscore_lower_snake_case → PascalCase דרך `PI_EVENT_MAP` כך מדיניות מובנות קיימות ללא שינוי. tool input args מנורמלים גם דרך `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit מסירים `path` במקום `file_path`; mapping של המפתח ברמה-עליונה מאפשר ל-`block-env-files` ו-`block-secrets-write` להתקיים — `block-read-outside-cwd` כבר היה fallback של `path`). תמיכת Pi היא **beta** בזמן ש-API הרחבה של Pi ותמיד על-דיסק מייצבת. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**היקף משתמש בלבד** — ל-Hermes אין תצורה של פרויקט/מקומי). Hermes הוא **שער** Slack/Telegram, כך התקנה אחת מיירטת קריאות כלים מכל פלטפורמה (Slack/Telegram/cli/cron) **וגם** sub-agents פנימיים. ערכי Hook הם זוג `{command, timeout}` (timeout בשניות) תחת מפה `hooks:` שמקודדת לפי snake_case אירועים של Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); המטפל מנרמל אירועים דרך `HERMES_EVENT_MAP` ושמות כלים דרך `HERMES_TOOL_MAP` כך מדיניות מובנות קיימות ללא שינוי. התצורה מעודכנת דרך YAML `Document` משמר-הערה סבב כך הגדרות אחרות של המפעיל שורדות, והתקנה קובעת `hooks_auto_accept: true` כך השער headless (אין TTY) מריץ את ה-hooks ללא בקשה הסכמה. המעריך משדר חוזה stdout של Hermes של `{"decision":"block","reason"}` (Hermes מתעלמת מקודי יציאה). **מגבלות:** ל-Hermes אין אירוע `Stop` של turn-end, כך ה-`require-*-before-stop` builtins לעולם לא קיימות עבורה (לא ישים, לא שבור); `instruct` מתמוטטת ל-allow-with-logged-note (אין ערוץ הקשר נוסף); וגזימה סודה-פלט (`sanitize-*`) לא יכולה לכתוב כמו-חדש tool output דרך חוזה shell-hook. Hermes הוא **גם** מקור ביקורת offline — דוד קורא הפעלות שער שלה ישירות מ-`~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**היקף משתמש בלבד** — ל-OpenClaw אין תצורה של פרויקט/מקומי). כמו Hermes, OpenClaw היא **שער** multi-channel בעצמי-מארח, כך התקנה אחת מיירטת קריאות כלים מכל ערוץ ו-sub-agents פנימיים שלה. אכיפה מתרחשת דרך hook plugin של OpenClaw **בתוך-תהליך** (ה-hooks מבוססות-קובץ פנימיות שלה הן observation-only ולא יכולות לחסום), כך — כמו OpenCode/Pi — failproofai משודרת `openclaw-plugin/` package סטטי שטוען-אסינק-ספorna את בינרי failproofai ותרגום הפסק. ההתקנה רושמת את ספריית ה-plugin המישדרת בחזקה `openclaw.json`'s `plugins.load.paths[]` ומפעילה אותה תחת `plugins.entries.failproofai` (עם `hooks.allowConversationAccess: true`, נדרש עבור ה-raw-conversation hooks). המעריך משדר פסק `{permission, reason}` שטוח וה-shim ממפה אותו לצורה native של כל hook: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), ו-`before_agent_finalize → {action:"revise", reason}` (**Stop** — שער turn-end אמיתי, כך `require-*-before-stop` builtins **אוכפת** על OpenClaw, בניגוד ל-Hermes). אירועים וכלים שמות canonicalize צד-בינרי דרך `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) כך מדיניות מובנות קיימות ללא שינוי; ה-shim נכשל open בכל spawn/parse/timeout שגיאה. OpenClaw הוא **גם** מקור ביקורת offline — דוד קורא JSONL הפעלות שלה בכתובת `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (משתמש), `/.factory/hooks.json` (פרויקט) — ל-Factory אין היקף `local`. droid משודרת מערכת hook של פקודה חיצונית בסגנון Claude, אך עם שני quirks מאומתים live מול droid v0.171.0: (1) שמות אירועים חיים ברמה **העליונה** של `hooks.json` — יש **אין עטיפה `"hooks"`** (droid דוחה אחת); אירועי כלים (`PreToolUse`/`PostToolUse`) נושאים `"matcher": "*"`, אירועים שאינם כלים משמיטים אותה. (2) Deny מונע על ידי hook **exit code 2 + stderr**, לא החלטה JSON — ענף `factory` של המעריך מחזיר יציאה 2 עבור אירועי tool/prompt ו-`{decision:"block", reason}` רק באירוע turn-end `Stop` (ערוץ ה-force-retry היחיד של droid). אירועים כבר PascalCase (אין event map) והעומס הוא Claude snake_case; רק שמות כלים מנורמלים דרך `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory הוא **גם** מקור ביקורת offline — דוד קורא הפעלות on-disk JSONL שלה בכתובת `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (משתמש), `/.devin/config.json` (פרויקט) — ל-Devin אין היקף `local`. Devin הוא **pure Claude-clone** מאומת live מול devin v3000.1.27: היא משתמשת בסכמה סטנדרטית Claude של `"hooks"`-wrapper (כתיבות הן merge-preserving כך מפתחות אחרים של קובץ התצורה — `org_id`, `theme_mode`, … — שורדות), שמות אירועים שכבר PascalCase (אין event map, אין ענף handler), ויומן stdin payload snake_case Claude (אין normalization). ענף `devin` של המעריך מעכבת עם JSON `{"decision":"block","reason"}` ב-stdout בקוד יציאה 0 עבור **כל** אירוע (מאומת — הבלוק עקף `--permission-mode dangerous`); באירוע turn-end `Stop` הסיבה נושאת את הניסוח force-retry חובה אם כן `require-*-before-stop` builtins אוכפת. רק שמות כלים מנורמלים דרך `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` כבר canonical). Devin הוא **גם** מקור ביקורת offline — דוד קורא הפעלות SQLite שלה בכתובת `~/.local/share/devin/cli/sessions.db` (כל שורה `sessions` נושאת `working_directory` אמיתי, כך הפעלות קבוצה לפי cwd של פרויקט כמו Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (משתמש), `/.agents/hooks.json` (פרויקט) — ל-Antigravity אין היקף `local`. בניגוד ל-Factory/Devin, Antigravity יש את **שלה שלה** חוזה (לא Claude-clone), מאומת live מול agy v1.1.2. `hooks.json` משתמש בסכמה **named-hook**: המפתח ברמה-עליונה הוא שם hook *(`"failproofai"`) שערך שלו הוא מפה אירוע→handlers — אירועי כלים (`PreToolUse`/`PostToolUse`) לעטוף handlers ב-`{matcher:"*", hooks:[…]}`, בעודothat `PreInvocation`/`Stop` הם **שטוח** מערכי handlers (hook אחרים שמות משמרים). יומן stdin הוא **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai מנרמל אותו ל-snake_case לפני מדיניות רצות, וממפה PascalCase args של `run_command` (`CommandLine`/`Cwd`) דרך `ANTIGRAVITY_TOOL_INPUT_MAP`. ענף `antigravity` של המעריך משתמש בצורות התגובה **שלה שלה** של Antigravity: `{decision:"deny", reason}` חוסם tool/prompt (exit 0), `{decision:"continue", reason}` באירוע turn-end `Stop` re-enters את הלולאה (כך `require-*-before-stop` builtins אוכפת), ו-`{injectSteps:[{ephemeralMessage}]}` injects הנחיה על `PreInvocation` (→ `UserPromptSubmit`). שמות כלים canonicalize דרך `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity הוא **גם** מקור ביקורת offline — דוד קורא plain-JSONL תמלילים שלה בכתובת `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (אינדקס שיחה ב-`conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (משתמש), `/.agents/plugins/failproofai/hooks/hooks.json` (פרויקט) — ל-Goose אין היקף `local`. אכיפה משתמשת במערכת **hooks** של Goose, על-agents מפרט **Open Plugins**: המתקין רק זורק את ספריית ה-`failproofai` plugin ו-Goose auto-discovers אותה בעת ההתחלה (self-registering אותה לתוך `~/.config/goose/config.yaml`). `hooks.json` משתמשת בסכמה Open Plugins **עם** עטיפה `"hooks"` ברמה-עליונה, והמatcher הוא **מושמט** בכל אירוע — regex `"*"` ערום הוא regex לא חוקי המתאים לשום דבר (מאומת live מול goose v1.43.0). שמות אירועים כבר PascalCase (אין event map); ה-stdin payload משתמש `event`/`working_dir`, אשר המטפל מנרמל ל-`hook_event_name`/`cwd`. ענף `goose` של המעריך מעכבת עם JSON `{"decision":"block","reason"}` ב-stdout בקוד יציאה 0, מכובד באירוע **`PreToolUse`** בלבד (משודרת ב-goose ≥ v1.37.0) — אשר קיימת עבור כלי shell **וגם בתוך sub-agents מהודרים**, כך זהו נקודת הכניעה הקטן sufficient; כל טעות hook אחרת נכשלת **פתוח**. Goose יש **אין אירוע `Stop`**, כך ה-`require-*-before-stop` builtins אל תחול (כמו עם Hermes). שמות כלים canonicalize דרך `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) ומפתחות path דרך `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose הוא **גם** מקור ביקורת offline — דוד קורא הפעלות SQLite שלה בכתובת `~/.local/share/goose/sessions/sessions.db` (כל שורת `sessions` נושאת `working_dir` אמיתי, כך הפעלות קבוצה לפי cwd של פרויקט כמו Devin; `--no-session` scratch runs מסוננות). +- **`policies-config.json`** — אומר ל-failproofai אילו מדיניות להעריך ועם איזה params (משותף בכל agent CLIs) + +עבור `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` כדי לתכוונן agent ספציפי (מרחק-מופרד או חזור עבור כל תת-קבוצה): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -כאשר `--cli` מושמט, `failproofai` מגלה אילו CLI של agent מותקנות (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +כאשר `--cli` משמט, `failproofai` גילויה אילו agent CLIs מותקנות (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **CLI אחד זוהה** — בחירה אוטומטית של ה-CLI הזה ללא הנחיות. -- **מספר CLI זוהו** בטרמינל אינטראקטיבי — מציג הנחיות בחירה חד-בחירה בחצי-מקלדת מקובצות לחלק `Detected (N)` (עם שורה מצומצמת `Install for all N detected` + כל CLI זוהה בנפרד) וחלק `Not installed (M) · install hooks ahead of time` הרשום כל CLI לא זוהה שנתמך כאפשרות התקנה קדימה (↑↓ להזיז, Enter בחר, ^C יצא). זרימת ההסרה מציגה רק את החלק Detected. -- **מספר CLI זוהו** בריצה לא אינטראקטיבית (CI, ללא TTY) — מתקנת את כל CLI זוהה ללא הנחיות. -- **אף אחד לא זוהה** — יורדת חזרה ל`claude`, עם אזהרה שלא מצא בינארי agent ב-PATH; פקודת ה-hook עדיין נכתבה כך היא מופעלת ברגע שתתקין אחד. +- **ה-CLI אחת גילויה** — auto-selects אותו CLI ללא prompt. +- **ריבוי CLIs גילויה** בטרמינל אינטראקטיבי — מראה arrow-key single-select prompt מקובץ לתוך חלק `Detected (N)` (עם שורה aggregate `Install for all N detected` + כל CLI גילויה לפי אחד) וחלק `Not installed (M) · install hooks ahead of time` רישום כל unsupported CLI כאפשרות forward-install (↑↓ להזוז, Enter לבחור, ^C להפסיק). זרימת uninstall מראה רק חלק Detected. +- **מוקדש CLIs גילויה** בריצה non-interactive (CI, אין TTY) — מתקנים עבור כל CLIs גילויה ללא prompt. +- **אף אחד גילויה** — נופל חזרה לוklaude, עם אזהרה שאף בינרי agent לא נמצא ב-PATH; פקודת ה-hook עדיין כתובה כךהיא מתאימה ברגע שאתה מתקנים אחת. -אתה יכול לערוך `policies-config.json` ישירות בכל עת; השינויים נכנסים לתוקף מיד באירוע hook הבא ללא צורך בהפעלה מחדש. +אתה יכול לערוך `policies-config.json` ישירות בכל עת; שינויים נכנסים לתוקף מיידית באירוע hook הבא ללא צורך להפעיל מחדש. --- -## דוגמה: תצורה ברמת פרויקט עם ברירות ברירת מחדל לצוות +## דוגמה: תצורה ברמה-פרויקט עם ברירות מחדל של צוות -Commit `.failproofai/policies-config.json` למאגר שלך: +commit `.failproofai/policies-config.json` לריפוזיטורי שלך: ```json { @@ -247,4 +255,4 @@ Commit `.failproofai/policies-config.json` למאגר שלך: } ``` -כל מפתח יכול ליצור `.failproofai/policies-config.local.json` (מתוך gitignore) לעקיפות אישיות ללא הפרת עמיתים. \ No newline at end of file +כל מפתח יכול ליצור `.failproofai/policies-config.local.json` (gitignored) עבור עקיפות אישיות ללא להשפיע על teammates. \ No newline at end of file diff --git a/docs/he/dashboard.mdx b/docs/he/dashboard.mdx index 50ffc990..b366ead3 100644 --- a/docs/he/dashboard.mdx +++ b/docs/he/dashboard.mdx @@ -1,11 +1,11 @@ --- --- -title: לוח הבקרה +title: לוח בקרה description: "עקוב אחר הפעלות של סוכנים, בדוק קריאות כלים וניהול מדיניות" icon: chart-line --- -לוח הבקרה של failproofai הוא אפליקציית ווב מקומית לניטור הפעלות סוכני ה-AI שלך וניהול מדיניות. ראה מה עשו הסוכנים שלך בזמן שהיית רחוק. +לוח הבקרה של failproofai הוא יישום אינטרנט מקומי לניטור הפעלות סוכני ה-AI שלך וניהול מדיניות. ראו מה עשו הסוכנים שלכם בזמן שלא היתם כאן. --- @@ -17,101 +17,105 @@ failproofai נפתח בכתובת `http://localhost:8020`. -לוח הבקרה קורא ישירות מקובץ המערכת - תיקיות Claude Code שלך וקובצי הקונפיגורציה של failproofai. שום דבר לא כתוב לשירות מרחוק. +לוח הבקרה קורא ישירות מהמערכת הקבצים - תיקיות הפרויקט של Claude Code וקבצי הקונפיגורציה של failproofai. כלום לא נכתב לשירות מרוחק. --- ## עמודים -### Projects +### פרויקטים -מפרט את כל Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, ו-Hermes שנמצאו במחשב שלך. פרויקטי Claude מגולים מ-`~/.claude/projects/` (או הנתיב שנקבע על ידי `CLAUDE_PROJECTS_PATH`); פרויקטי Codex מגולים על ידי סריקת כל תמליל תחת `~/.codex/sessions///
/*.jsonl` וקיבוץ לפי `cwd` שנרשם בתיעוד הראשון של ההפעלה; פרויקטי Copilot CLI מגולים על ידי סריקת כל `~/.copilot/session-state//workspace.yaml` (ניתן להגדיר דרך `COPILOT_HOME`) וקיבוץ לפי שדה `cwd` שלו; פרויקטי Cursor Agent מגולים על ידי סריקת מטא-נתונים לכל הפעלה תחת `~/.cursor/agent-sessions//` (ניתן להגדיר דרך `CURSOR_HOME`, עם סדרי גיבוי `conversations/` ו-`sessions/`) עבור סקלר `cwd` ב-`meta.json` / `session.json` / `workspace.yaml`; פרויקטי OpenCode מגולים על ידי שאילתת SQLite DB שלה ב-`~/.local/share/opencode/opencode.db` דרך `opencode db --format json` (אנו קוראים את טבלאות `session` ו-`project` וקיבוץ לפי `project_id`); פרויקטי Pi מגולים על ידי סריקת תמליל JSONL לכל הפעלה תחת `~/.pi/agent/sessions//_.jsonl` (ניתן להגדיר דרך `PI_SESSIONS_DIR`) ושליפת `cwd` מתיעוד הראשון של כל הפעלה; פרויקטי Gemini CLI מגולים על ידי סריקת `~/.gemini/tmp//chats/session--.jsonl` (ניתן להגדיר דרך `GEMINI_SESSIONS_DIR`) והחזרת ה-cwd הקנוני ממסמן `.project_root` הסמוך; הפעלות שער Hermes נקראות ישירות מחנות SQLite שלה ב-`~/.hermes/state.db` (ניתן להגדיר דרך `HERMES_DB_PATH`) וקיבוץ לפרויקטי `hermes-` לפי `source` (Slack/Telegram/cli/cron — להפעלות שער אין cwd). פרויקט ששימש מספר CLIs מרואה כשורה יחידה עם כל התגים המתאימים. השתמש בתפריט **CLI** מעל הטבלה לסינון לפי סוכן CLI ספציפי; ה-URL משמר את הבחירה שלך כ-`?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +מוצגים כל פרויקטי Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity ו-Goose שנמצאו במחשב שלך. פרויקטי Claude מתגלים מ-`~/.claude/projects/` (או הנתיב שהוגדר על-ידי `CLAUDE_PROJECTS_PATH`); פרויקטי Codex מתגלים על-ידי סריקה של כל תמלול תחת `~/.codex/sessions///
/*.jsonl` וקיבוץ לפי ה-`cwd` המוקלט בתיעוד הראשון של כל הפעלה; פרויקטי Copilot CLI מתגלים על-ידי סריקה של כל `~/.copilot/session-state//workspace.yaml` (ניתן להגדרה דרך `COPILOT_HOME`) וקיבוץ לפי שדה ה-`cwd` שלו; פרויקטי Cursor Agent מתגלים על-ידי סריקה של מטא-נתונים לכל הפעלה תחת `~/.cursor/agent-sessions//` (ניתן להגדרה דרך `CURSOR_HOME`, עם `conversations/` ו-`sessions/` כגיבויים) לחיפוש סקלר `cwd` ב-`meta.json` / `session.json` / `workspace.yaml`; פרויקטי OpenCode מתגלים על-ידי שאילתה של בסיס הנתונים SQLite שלו בכתובת `~/.local/share/opencode/opencode.db` דרך `opencode db --format json` (אנחנו קוראים את טבלאות `session` ו-`project` וקיבוץ לפי `project_id`); פרויקטי Pi מתגלים על-ידי סריקה של תמלולי JSONL לכל הפעלה תחת `~/.pi/agent/sessions//_.jsonl` (ניתן להגדרה דרך `PI_SESSIONS_DIR`) ושליפת ה-`cwd` מתיעוד הראשון של כל הפעלה; הפעלות שער Hermes קרויות ישירות מהחנות SQLite שלו בכתובת `~/.hermes/state.db` (ניתן להגדרה דרך `HERMES_DB_PATH`) וקיבוץ לפרויקטי `hermes-` לפי `source` (Slack/Telegram/cli/cron — להפעלות של שער אין cwd); הפעלות שער OpenClaw קרויות מ-`~/.openclaw/agents//sessions/*.jsonl` וקיבוץ לפרויקטי `openclaw-` (גם ללא cwd); פרויקטי Factory Droid מתגלים מתמלולי JSONL בכתובת `~/.factory/sessions//*.jsonl` וקיבוץ לפי cwd; פרויקטי Devin מבסיס הנתונים SQLite שלו בכתובת `~/.local/share/devin/cli/sessions.db` (קיבוץ לפי `working_directory` של כל הפעלה); פרויקטי Antigravity מתמלולי JSONL בכתובת `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` וקיבוץ לפי cwd; ופרויקטי Goose מבסיס הנתונים SQLite שלו בכתובת `~/.local/share/goose/sessions/sessions.db` (קיבוץ לפי `working_dir` של כל הפעלה). פרויקט ששימש מספר ממשקי CLI מוצג כשורה יחידה עם כל התגים התואמים. השתמשו בתפריט הנפתח **CLI** מעל הטבלה לסינון לפי סוכן CLI ספציפי; כתובת ה-URL משמרת את הבחירה שלכם כ-`?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. -כל פרויקט מציג: -- שם הפרויקט (מגובש מנתיב התיקייה) -- תג CLI — `Claude Code` (כתום), `OpenAI Codex` (סגול), `GitHub Copilot` (כחול), `Cursor Agent` (אזמרגד), `OpenCode` (ענבר), `Pi` (ורוד), `Gemini CLI` (שמיים), ו/או `Hermes` (אינדיגו) -- תאריך של פעילות הפעלה האחרונה +כל פרויקט מוצג עם: +- שם הפרויקט (מנוי מנתיב התיקייה) +- תג CLI — `Claude Code` (כתום), `OpenAI Codex` (סגול), `GitHub Copilot` (כחול), `Cursor Agent` (ירוק אזמרגד), `OpenCode` (צהוב), `Pi` (ורוד), ו/או `Hermes` (אינדיגו) +- תאריך של פעילות ההפעלה האחרונה -לחץ על פרויקט כדי לראות את הפעלות שלו. +לחצו על פרויקט כדי לראות את ההפעלות שלו. -### Sessions +### הפעלות -מפרט את כל הפעלות בתוך פרויקט. כל הפעלה מציגה: -- מזהה הפעלה -- חותמות זמן של התחלה וסיום +מוצגות כל ההפעלות בפרויקט. כל הפעלה מוצגת עם: +- זהות ההפעלה +- חותמות זמן התחלה וסיום - מספר קריאות כלים -- ספירת פעילות קורא (מדיניות שנשדרה) +- ספירת פעילות hook (מדיניות שהופעלו) -השתמש במסנן טווח התאריכים ובחיפוש מזהה הפעלה כדי לצמצם את הרשימה. הפעלות מחולקות לעמודים. +השתמשו בפילטר טווח התאריכים וחיפוש זהות ההפעלה כדי להצר את הרשימה. ההפעלות מופצות בעמודים. -לחץ על הפעלה כדי לפתוח את מצפה הפעלה. +לחצו על הפעלה כדי לפתוח את צפיין ההפעלה. -### מצפה הפעלה +### צפיין ההפעלה -מצפה הפעלה עונה על השאלה המרכזית לסוכנים אוטונומיים: מה עשה הסוכן, והאם הוא נשאר בעקוב? תג CLI ליד הכותרת מציין אם ההפעלה היא Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, או תמליל Hermes. הוא מציג ציר הזמן של כל מה שקרה בהפעלה: +צפיין ההפעלה משיב לשאלה העיקרית עבור סוכנים אוטונומיים: מה עשה הסוכן, והאם הוא נשאר על הנתיב? תג CLI ליד הכותרת מציין האם ההפעלה היא תמלול Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity או Goose. הוא מוצג בציר הזמן של כל מה שקרה בהפעלה: -- **הודעות** - תגובות טקסט של Claude והנחיות משתמש -- **קריאות כלים** - כל כלי שקרא Claude, עם הקלט והפלט שלו -- **פעילות מדיניות** - לכל קריאת כלים, אילו מדיניות נשדרה ואילו החלטה הן החזירו +- **הודעות** - תגובות הטקסט של Claude והנושאים של המשתמש +- **קריאות כלים** - כל כלי שהעלה Claude, עם הקלט והפלט שלו +- **פעילות מדיניות** - עבור כל קריאת כלים, אילו מדיניות הופעלו ואיזו החלטה הן החזירו -סרגל הנתונים בחלק העליון מציג משך הפעלה, סה"כ קריאות כלים, וסיכום החלטות קורא (ספירות allow / deny / instruct). +סרגל הנתונים בחלק העליון מוצג משך ההפעלה, סך הכל קריאות כלים, וסיכום של החלטות hook (ספירות allow / deny / instruct). -לחץ על כפתור **Download Logs** כדי לייצא את ההפעלה. עבור Claude Code, Codex, Copilot, Cursor, Pi, ו-Gemini תקבל את תמליל JSONL המקורי על הדיסק בדיוק כפי שהוא; עבור OpenCode (שהפעלות שלה חיות ב-SQLite, לא על הדיסק) תקבל מסמך JSON המשקף את טבלאות `session` / `messages` / `parts` הבסיסיות. +לחצו על כפתור **Download Logs** כדי לייצא את ההפעלה. עבור הפעלות Claude Code, Codex, Copilot, Cursor ו-Pi תקבלו את תמלול ה-JSONL המקורי בדיסק בדיוק כמו שהוא; עבור OpenCode (שההפעלות שלו חיות בـ SQLite, לא בדיסק) תקבלו מסמך JSON המשקף את טבלאות `session` / `messages` / `parts` הבסיסיות. -### Audit +### ביקורת -דוח מונע על ידי אישיות כיצד סוכן שלך אכן התנהג בהפעלות עבר. מריץ את אותה סריקה כמו CLI של `failproofai audit` אך מעניק לה כל על-מסך בר-שיתוף + ארבעה סעיפים מתחת לקפל: +דוח מונע אישיות כיצד הסוכן שלכם בעצם התנהל בהפעלות קודמות. מפעיל את אותה סריקה כמו CLI `failproofai audit` אך מחזיר אותה כפוסטר בעמוד יחיד וניתן לשיתוף + ארבעה חלקים מתחת לקיפול: -1. **Poster** — ממלא את viewport הראשון. אזור תפיסת PNG עצמי עם wordmark failproof_ai + תווית ביקורת · אינדקס ארכיטיפ (`№ NN of 08`) + תאריך ביקורת · ציון מספרי (0–100) + דירוג אחוזון כדור (`top 15%`) · שם הארכיטיפ (אחד מ-`the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + רצועת 3 מילות מפתח · `// only N% of agents are this archetype` שורת דלילות · אריח סמל 8×8 פיקסל · `audit yours → failproof.ai` כותרת רגל. שלושה כפתורי שיתוף יושבים ממש מחוץ לתיבת התפיסה: `post your archetype` (X intent), `share on linkedin`, `download poster`. התפיסה רצה דרך `html-to-image` כך שה-PNG תואם את העל-מסך בדיוק פיקסל על פיקסל (גבולות מקווקווים, מסיכת לוגו SVG, שיפועים, מטרי גופנים — הכל שמור). -2. **Strengths** — שורת רשימה רגועה ✓ של התנהגויות שהסוכן שלך כבר עושה נכון, הנגזרת מנתוני ביקורת חי (שיעור קריאות כלים נקי, ללא דחיפה ישירה לעיקרי, ללא נזילות זיהויים, ללא סערות ניסיון חוזרות) — כל אחת משטחת רק כאשר למדיניות הרלוונטית רשומה נקייה על פני חלון הביקורת. -3. **Quirks** — טבלה של מה שהחליק דרך, דורג לפי חומרה: `when · what slipped + the policy that would've caught it · severity pill · seen`, כאשר הישנות קוראת `new` (פעם אחת), `N× seen` (2–9 פעמים), או `recurring` (10+). -4. **How to improve** — שורת רשימה רגועה, אחת לכל מדיניות קבועה: שם מדיניות בלבן, תיאור בשורה אחת, פקודת התקנה + כפתור עותק בצד ימין. כותרת הסעיף קוראת `enable all N → projected · ` (הניקוד שהיית מגיע עם כל תיקון שהוחל), וכפתור `[install all]` שלו מעתיק את הפקודה המשולבת `failproofai policy add a b c …` לכל מדיניות קבועה. -5. **Come back better** — שתי כרטיסים זה לצד זה. שמאל: קבע תזכורת (`3d` / `7d` / `14d` / `30d` בוחר קדנציה; נשמר דרך `/api/auth/reminder` ברגע שמאומת). ימין: בטל את fullproof perks — `invite a friend` פותח מודאל שלוקח רשימה מופרדת בפסיקים / רווח / שורה חדשה של כתובות דוא"ל של חברים (מקסימום 10 לשליחה), מעלה אותם ל-`/api/audit/invite`, אשר מעביר אותם לאפליקציית `POST /v0/invite` של api-server. ה-api-server שולח דוא"ל אחד לכל נמען מ-`invite@failproof.ai` עם שליחה Cc'd וקביעת `Reply-To`, כך שהנמען רואה מי הזמין אותם והשליחה מקבלת עותק בתיבת הדואר הנכנס שלה. משתמשים אנונימיים מנותבים דרך `AuthDialog` תחילה כך שכתובת הדוא"ל של השליחה ידועה לפני שהזמנות יוצאות. זכאות / fulfillment perks הוא סדר עבודה בעקבות. +1. **פוסטר** — מילוא את מסגרת התצוגה הראשונה. אזור עצמאי לתיעוד PNG עם סימן failproof_ai + תווית ביקורת · אינדקס ארכיטיפ (`№ NN of 08`) + תאריך ביקורת · ציון מספרי (0–100) + דירוג אחוזון גלולה (`top 15%`) · שם הארכיטיפ (אחד מ-`the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + רצועת 3-מילה · `// only N% of agents are this archetype` שורת נדירות · אריח סיגיל 8×8 פיקסל · `audit yours → failproof.ai` כיתום. שלושה כפתורי שיתוף יושבים בדיוק מחוץ לתיבת התיעוד: `post your archetype` (כוונת X), `share on linkedin`, `download poster`. התיעוד חורץ דרך `html-to-image` כך ש-PNG תואם את הגרימה על-מסך פיקסל-לפיקסל (גבולות מקוקוקים, מסיכת לוגו SVG, טונות צבע, מדדי גופן — הכל שומר). -מונע על ידי זמן ההרצה של `failproofai audit` — ראה [Audit CLI](/he/cli/audit) עבור מנוע הסריקה הבסיסי, דגלים נתמכים, ובלתי ניתנים לשינוי של זיכרון מטמון לכל תמליל. לוח הבקרה שומר את התוצאה האחרונה ב-`~/.failproofai/audit-dashboard.json` (מצב `0600`, חריץ יחיד, הרצות חדשות משכתבות) כך שביקורי חוזרים מיידיים; **גם זיכרון מטמון לכל תמליל וגם תוצאה כוללת נדחו בקריאה ברגע שהם מעבר לגיל של 7 ימים** כך שלוח הבקרה לא משרת בשקט תוצאה בגיל שבוע — עבר ה-TTL `/audit` נופל דרך למצב הריק שלו וזמנים הרצה טרייה. לחיצה על `[ re-audit now ]` ליד תחתית הדוח POSTs `/api/audit/run` עם `noCache: true` — re-audit עוקף את זיכרון המטמון לכל תמליל ועורך סריקה מחדש של כל תמליל מההתחלה ולא משום שמחזירה בשקט את התוצאה המטומנת — לוח הבקרה פולל `/api/audit/status` ב-1Hz עד שההרצה מסיימת; רצועת התקדמות ורודה דביקה קובעת את ראש viewport במהלך ההרצה עם טיימר שחלוף, והתוצאה הטרייה מתחלפת במקום בעת הצלחה (ללא טעינת עמוד מלאה; re-audit כושל משאיר את הדוח הקודם שלם). בעת כשל הרצועה הופכת לאדומה עם עותק מפתח מ-`RerunError.kind` (`timeout` / `network` / `post_failed`). מצב ריק (ללא זיכרון מטמון או פג תוקף) ומצב אפס-הפעלות (זיכרון מטמון קיים אך הסריקה לא מצאה תמליל) משטחים בנפרד. +2. **נקודות חוזק** — רשימת שורות שקטות ✓ של התנהגויות שהסוכן שלכם כבר עושה נכון, מנוקדות מנתוני הביקורת החיים (שיעור קריאת כלים נקי, אין דחיפות ישירות ל-main, אפס דליפות אישור, אפס סערות ניסיון) — כל אחד מופיע רק כאשר למדיניות הרלוונטית יש רקורד נקי על פני חלון הביקורת. -### Policies +3. **מוזרויות** — טבלה של מה שהחליק דרך, דורגה לפי חומרה: `when · what slipped + the policy that would've caught it · severity pill · seen`, כאשר ההישנות קוראת `new` (פעם אחת), `N× seen` (2–9 פעמים), או `recurring` (10+). -עמוד דו-כרטיסיה לניהול מדיניות וסקירת פעילות. +4. **כיצד להשתפר** — רשימת שורות שקטות, אחת לכל מדיניות מנויה: שם מדיניות בלבן, תיאור בשורה אחת, פקודת התקנה + כפתור העתקה בצד ימין. כותרת הסעיף קוראת `enable all N → projected · ` (הציון שהיית מגיע אליו עם כל התיקון המיושם), וכפתור `[install all]` שלו מעתיק את הפקודה המשולבת `failproofai policy add a b c …` עבור כל מדיניות מנויה. + +5. **חזרו עם טובות יותר** — שתי כרטיסיות זו לצד זה. משמאל: הגדר הזכרון (`3d` / `7d` / `14d` / `30d` בוחר קדנציה; נשמר דרך `/api/auth/reminder` ברגע שמאומת). מימין: בטלו הטבות failproof — `invite a friend` פותח מודאל שמקבל רשימה של כתובות דוא"ל של חברים המופרדות בפסיקים/מרווח/קו חדש (מקסימום 10 לשליחה), POST אותן ל-`/api/audit/invite`, אשר משדרות לשדר ה-api של השרת `POST /v0/invite`. שרת ה-api שולח דוא"ל אחד לכל מקלט מ-`invite@failproof.ai` עם שולח ה-Cc והגדרת `Reply-To`, כך שהמקלט רואה מי הזמין אותו והשולח מקבל עותק בתיבת הדוא"ל שלו. משתמשים אנונימיים מנותבים דרך ה-`AuthDialog` תחילה כך ששדה הדוא"ל של השולח ידוע לפני שההזמנות יוצאות. זכות כניסה ומענק הטבות הוא עקיבה. + +מונע על-ידי זמן ההרצה `failproofai audit` — ראה [Audit CLI](/he/cli/audit) לסריקת המנוע הבסיסי, דגלים נתמכים, ובלתי משתנה מטמון לכל-תמלול. לוח הבקרה מטמן את התוצאה האחרונה בכתובת `~/.failproofai/audit-dashboard.json` (מצב `0600`, משבצת יחיד, הרצות חדשות דורסות) כך שביקורים חוזרים מיידיים; **גם מטמון ה-per-transcript וגם מטמון כל-התוצאה נדחקים על קריאה ברגע שהם ישנים יותר מ-7 ימים** כך שלוח הבקרה לעולם לא משדר בשקט תוצאה בן שבוע — בעבר ה-TTL `/audit` נופל דרך למצב ריק שלו ובקש הרצה טרייה. לחיצה על `[ re-audit now ]` ליד תחתית הדוח POST `/api/audit/run` עם `noCache: true` — ביקורת חוזרת עוקפת את מטמון ה-per-transcript וסורקת כל תמלול מחדש ללא מטמון במקום להחזיר בשקט את התוצאה המטומנת — ולוח הבקרה משוטטת `/api/audit/status` ב-1Hz עד שההרצה מסתיימת; רצועת התקדמות ורודה דביקה מוצמדת לחלק העליון של viewport במהלך הרצה עם טיימר חלוף, והתוצאה הטרייה מתחליפה במקום בהצלחה (ללא טעינה מחדש של דף מלא; ביקורת חוזרת כושלת משאירה את הדוח הקודם שלם). בכשל הרצועה הופכת לאדום עם העתקה שהונחתה לפי `RerunError.kind` (`timeout` / `network` / `post_failed`). מצב ריק (אין מטמון או פג) ומצב אפס-הפעלות (מטמון קיים אך הסריקה לא מצאה תמלולים) מוטלים בנפרד. + +### מדיניות + +דף בן שתי לשוניות לניהול מדיניות וביקורת פעילות. - - - בחר מספר כלים את סוכני ה-CLI שעליהם failproofai מגן מלוח יחיד — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, ו-Hermes כולם בעלי שורה עם סטטוס התקנה (`Active` / `Detected` / `Inactive`), נתיב הגדרות הטווח השנייה משתמש, והדגש צבע ממותג. בדוק או בטל את בדיקת ה-CLIs שאתה רוצה לחץ על `Apply changes` כדי להתקין/הסר את ההבדל בשלב אחד. CLIs שהבינארית שלהם מגולה ב-PATH מסומנים מראש. - - כיבוי או הדלקת מדיניות בודדות בלחיצה יחידה (כתיבה ל-`~/.failproofai/policies-config.json` — משותפת לכל CLI מותקן) - - הרחב מדיניות כדי להגדיר את הפרמטרים שלה (עבור מדיניות התומכות `policyParams`) - - קבע נתיב קובץ מדיניות מותאם + + - בחרו מרובות אילו ממשקי CLI סוכנים failproofai מגן עליהם מלוח יחיד — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, ו-Hermes כולם יש שורה עם מצב התקנה (`Active` / `Detected` / `Inactive`), נתיב הגדרות ההיקף של המשתמש, והדגש בצבע המותג. בחרו או בטלו את בחירת ממשקי ה-CLI שברצונכם וחצו `Apply changes` כדי להתקין/להסיר את ההפרש בשלב אחד. ממשקי CLI שהקובץ הבינארי שלהם מתגלה בנתיב מראש-נבדקים. + - הפעל או כבה מדיניות בודדות בלחיצה יחידה (כתוב ל-`~/.failproofai/policies-config.json` — משותף בכל ממשק CLI מותקן) + - הרחב מדיניות כדי להגדיר את הפרמטרים שלה (עבור מדיניות התומכת `policyParams`) + - הגדר נתיב קובץ מדיניות מותאם אישית - - - מלא היסטוריית עמודים של כל אירוע קורא שנשדר על כל הפעלות - - סנן לפי החלטה, סוג אירוע, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), שם מדיניות, או מזהה הפעלה - - כל שורה מציגה: חותמת זמן, שם מדיניות, החלטה, תג CLI (כתום = Claude Code, סגול = OpenAI Codex, כחול = GitHub Copilot, אזמרגד = Cursor Agent, ענבר = OpenCode, ורוד = Pi, שמיים = Gemini CLI, אינדיגו = Hermes), שם כלים, מזהה הפעלה, והסיבה להחלטות deny/instruct - - לחץ על מזהה הפעלה כדי לפתוח את התמליל שלה — מצפה גילוי אוטומטי אילו CLI נשדרה קורא (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) ומעניק את תג ה-CLI התואם בכותרת + + - היסטוריה מלאה בעמודים של כל אירוע hook שהופעל בכל ההפעלות + - סנן לפי החלטה, סוג אירוע, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), שם מדיניות, או זהות הפעלה + - כל שורה מוצגת: חותם זמן, שם מדיניות, החלטה, תג CLI (כתום = Claude Code, סגול = OpenAI Codex, כחול = GitHub Copilot, ירוק אזמרגד = Cursor Agent, צהוב = OpenCode, ורוד = Pi, אינדיגו = Hermes, טילאני = OpenClaw, ורד = Factory Droid, סגול = Devin, ציאן = Antigravity, לימי = Goose), שם כלים, זהות הפעלה, והסיבה להחלטות deny/instruct + - לחץ על זהות הפעלה לפתיחת התמלול שלה — הצופה מגלה באופן אוטומטי אילו CLI הפעיל את ה-hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) ומחזיר את תג ה-CLI התואם בכותרת --- -## Auto-refresh +## רענון אוטומטי -לוח הבקרה יש ממתג ריענון אוטומטי בניווט הדף העליון. כאשר הוא מופעל, העמוד הנוכחי מתרענן מעת לעת כדי להציג הפעלות חדשות ופעילות מדיניות כשהם מופיעים. חיוני לניטור הפעלות סוכן אוטונומי ארוכות. +לוח הבקרה יש קלט רענון אוטומטי בניווט העליון. כאשר הופעל, העמוד הנוכחי מתרענן מעת לעת כדי להציג הפעלות חדשות ופעילות מדיניות כאשר הן מופיעות. חיוני לניטור הפעלות סוכן אוטונומיות ממושכות. --- ## השבתת עמודים -אם אתה זקוק רק לחלקים מסוימים של לוח הבקרה, קבע `FAILPROOFAI_DISABLE_PAGES` לרשימה מפורדת בפסיקים של שמות עמוד: +אם אתה זקוק רק לחלקים מסוימים של לוח הבקרה, הגדר `FAILPROOFAI_DISABLE_PAGES` לרשימה מופרדת בפסיקים של שמות עמודים: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai ``` -ערכים תקפים: `policies`, `projects`, `audit`. +ערכים חוקיים: `policies`, `projects`, `audit`. --- ## הגדרת נתיב הפרויקטים -כברירת מחדל, לוח הבקרה קורא מספריית הפרויקטים הסטנדרטית של Claude Code. עקוף אותה לעיצובים מותאמים: +כברירת מחדל, לוח הבקרה קורא מתיקיית הפרויקטים הסטנדרטית של Claude Code. עקוף אותה לעבור הדרך מותאמות אישיות: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -119,32 +123,32 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## גישה מהוסט שאינו localhost +## גישה מהשם של מארח non-localhost -בעת הפעלת לוח הבקרה ב**מצב פיתוח** (`npm run dev`) וגישה אליו משם הוסט שאינו `localhost` - לדוגמא, תחום מותאם, IP מרחוק, או כתובת URL מחודרת - ייתכן שתראה אזהרה כמו: +כאשר הרצת לוח הבקרה ב**מצב dev** (`npm run dev`) וגישה אליו משם הוסט שאינו `localhost` - למשל, דומיין מותאם אישית, IP מרחוק, או כתובת URL בנתיב - ייתכן שתראו אזהרה כמו: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -זה Next.js החוסם גישה בין-מקור לרשת HMR (hot module reload) שלו, שהיא תכונת פיתוח בלבד. כדי להתיר את הוסט שלך, השתמש בדגל `--allowed-origins`: +זה Next.js חוסם גישה cross-origin ל-HMR (hot module reload) websocket שלו, שהיא תכונה dev-only. כדי לאפשר את המארח שלך, השתמש בדגל `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -עבור מספר הוסטים או כתובות IP, עבור רשימה מפורדת בפסיקים: +עבור מארחים או IP ריבים, עברו רשימה מופרדת בפסיקים: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -אתה יכול גם לקבוע את משתנה הסביבה `FAILPROOFAI_ALLOWED_DEV_ORIGINS` במקום זאת: +אתה יכול גם להגדיר את משתנה הסביבה `FAILPROOFAI_ALLOWED_DEV_ORIGINS` במקום: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -זה חל רק על מצב פיתוח. בעת הפעלת `failproofai` (מצב ייצור), אין רשת HMR ואין בעיית משאבי פיתוח בין-מקור. +זה חל רק על מצב dev. כשמשוטטים `failproofai` (מצב ייצור), אין websocket HMR ואין בעיית משאב dev cross-origin. \ No newline at end of file diff --git a/docs/he/getting-started.mdx b/docs/he/getting-started.mdx index 90d45c29..dd50d056 100644 --- a/docs/he/getting-started.mdx +++ b/docs/he/getting-started.mdx @@ -1,6 +1,6 @@ --- -title: תחילת עבודה -description: "התקן את failproofai, הפעל מדיניות, והנח לסוכניםשלך לפעול בצורה אמינה" +title: "תחילת העבודה" +description: "התקנת failproofai, הפעלת מדיניות והרצת סוכנים באמינות" icon: rocket --- @@ -30,16 +30,16 @@ bun add -g failproofai ## התחלה מהירה - - מדיניות הן כללים שרצים לפני ואחרי כל קריאה לכלי סוכן. הם תופסים פקודות הורסות, דליפת סודות וטעויות אחרות לפני שהם גורמים לנזק. + + מדיניות היא כללים שפועלים לפני ואחרי כל קריאת כלי של סוכן. הם תופסים פקודות הרסניות, דליפות סודות ומצבי כשל אחרים לפני שהם גורמים נזק. ```bash failproofai policies --install ``` - זה כותב ערכי hook ל-CLI של סוכנים מותקנים (Claude Code של `~/.claude/settings.json`, OpenAI Codex של `~/.codex/hooks.json`, GitHub Copilot CLI של `~/.copilot/hooks/failproofai.json`, Cursor Agent של `~/.cursor/hooks.json`, OpenCode של plugin shim שנוצר ב-`~/.config/opencode/plugins/failproofai.mjs` בתוספת ערך רישום במערך `plugin` של `~/.config/opencode/opencode.json`, Pi של `~/.pi/agent/settings.json`, Gemini CLI של `~/.gemini/settings.json`, או Hermes של `~/.hermes/config.yaml`). כאשר יותר מאחד קיים תתבקע לבחור; העבר `--cli claude codex copilot cursor opencode pi gemini hermes` (כל קבוצה משנית) כדי לדלג על ההודעה. + פעולה זו כותבת ערכי hook ל-CLI של הסוכנים שהתקנת (של Claude Code `~/.claude/settings.json`, של OpenAI Codex `~/.codex/hooks.json`, של GitHub Copilot CLI `~/.copilot/hooks/failproofai.json`, של Cursor Agent `~/.cursor/hooks.json`, של OpenCode בקובץ ה-plugin shim שנוצר `~/.config/opencode/plugins/failproofai.mjs` בתוספת רשומת רישום במערך `plugin` של `~/.config/opencode/opencode.json`, של Pi `~/.pi/agent/settings.json`, של Hermes `~/.hermes/config.yaml`, של OpenClaw `~/.openclaw/openclaw.json`, של Factory Droid `~/.factory/hooks.json`, של Devin CLI `~/.config/devin/config.json`, של Antigravity CLI `~/.gemini/config/hooks.json`, או של Goose בתיקיית ה-plugin שגוגלת אוטומטית `~/.agents/plugins/failproofai/hooks/hooks.json`). כאשר יותר מאחד קיים תתבקע לבחור; העבר `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (כל תת-קבוצה) לדילוג על ההודעה. - תמיכה ב-GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ו-Gemini CLI היא **בטא** — התקן עם `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, או `--cli gemini`. Hermes (hermes-agent, שער Slack/Telegram) מותקן בטווח משתמש עם `--cli hermes` והוא **גם** מקור ביקורת לא מקוון. + GitHub Copilot CLI, Cursor Agent, OpenCode ו-Pi הם בתמיכה **בטא** — התקן עם `--cli copilot`, `--cli cursor`, `--cli opencode`, או `--cli pi`. Hermes (hermes-agent, שער Slack/Telegram) מותקן בהיקף משתמש עם `--cli hermes` וגם **כן** מקור ביקורת לא מקוון. OpenClaw (שער openclaw, עוזר רב-ערוצי מאירח עצמי) מותקן בהיקף משתמש עם `--cli openclaw` — אכיפה פועלת דרך hook-ים של plugin בתוך התהליך (`before_agent_finalize` הוא שער אמיתי בסוף תור, ולכן ה-builtins של `require-*-before-stop` אוכפים) — וגם **כן** מקור ביקורת לא מקוון. Factory Droid (`droid`) מותקן עם `--cli factory` (היקף משתמש + פרויקט) וגם **כן** מקור ביקורת לא מקוון. Devin CLI (`devin`, Cognition) מותקן עם `--cli devin` (היקף משתמש + פרויקט) וגם **כן** מקור ביקורת לא מקוון. Antigravity CLI (`agy`) מותקן עם `--cli antigravity` (היקף משתמש + פרויקט) וגם **כן** מקור ביקורת לא מקוון. Goose (codename goose, Block) מותקן עם `--cli goose` (היקף משתמש + פרויקט) — ההתקנן פשוט זורק תיקיית plugin ל-`~/.agents/plugins/failproofai/` ש-Goose גוגלת אוטומטית, וזה גם **כן** מקור ביקורת לא מקוון. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,62 +62,62 @@ bun add -g failproofai failproofai policies ``` - מציג כל מדיניות, האם היא מופעלת וכל פרמטרים שהוגדרו. + מציג כל מדיניות, האם היא מופעלת, וכל פרמטרים מוגדרים. - + ```bash failproofai ``` - פותח לוח בקרה מקומי ב-`http://localhost:8020` שבו אתה יכול לדפדף בהפעלות, לבדוק קריאות כלים ולנהל מדיניות. + פותח לוח בקרה מקומי ב-`http://localhost:8020` כאשר ניתן לעיין בהפעלות, לבחון קריאות כלי ולנהל מדיניות. - - הפעל את Claude Code כרגיל. אם הסוכן מנסה משהו מסוכן, failproofai יחתוך אותו באופן אוטומטי. השאר את זה רץ ללא השגחה וסקור מה קרה בלוח הבקרה. + + הפעל את Claude Code כרגיל. אם הסוכן מנסה משהו מסוכן, failproofai יחסום אותו באופן אוטומטי. השאר את זה לפעול ללא השגחה וסקור את מה שקרה בלוח הבקרה. --- -## איך מדיניות עובדת +## כיצד מדיניות פועלת -בכל פעם שסוכן מפעיל כלי, Claude Code קורא ל-failproofai כתהליך משנה: +בכל פעם שסוכן מריץ כלי, Claude Code קורא ל-failproofai כתהליך משנה: ```text -Claude Code → failproofai --hook PreToolUse → קורא JSON מ-stdin - מעריך מדיניות - כותב החלטה ל-stdout +Claude Code → failproofai --hook PreToolUse → קריאת JSON מ-stdin + הערכת מדיניות + כתיבת החלטה ל-stdout ``` כל מדיניות מחזירה אחת משלוש החלטות: -- **allow** - הסוכן ממשיך כרגיל -- **deny** - הפעולה נחסמת, לסוכן מובא הסבר -- **instruct** - הקשר נוסף נוסף להנמקת הסוכן +- **allow** - הסוכן ממשיך בדרך רגילה +- **deny** - הפעולה חסומה, הסוכן מודע למה +- **instruct** - הקשר נוסף מתווסף להנחיות של הסוכן -מדיניות רצה בתהליך המקומי שלך. שום דבר לא נשלח לשירות מרחוק. +מדיניות פועלת בתהליך המקומי שלך. שום דבר לא נשלח לשירות מרחוק. --- -## הגדר מדיניות של צוות עם מדיניות מבוססות קונבנציה +## הגדרת מדיניות צוות עם מדיניות מבוססות קונבנציה -הדרך המהירה ביותר לכונן תקנים איכות על פני הצוות שלך היא קונבנציית `.failproofai/policies/`. זרוק קובצי מדיניות לתיקייה זו והם נטענים באופן אוטומטי - ללא דגלים, ללא שינויי תצורה, ללא פקודות התקנה. +הדרך המהירה ביותר לקבוע תקני איכות בכל הצוות שלך היא הקונבנציה `/.failproofai/policies/`. זרוק קובצי מדיניות לתיקייה זו והם נטענים באופן אוטומטי — ללא דגלים, ללא שינויי תצורה, ללא פקודות התקנה. - + ```bash mkdir -p .failproofai/policies ``` - - העתק דוגמאות ההתחלה או כתוב את שלך: + + העתק דוגמאות התחלה או כתוב שלך: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - או צור אחד חדש: + או צור חדשה: ```js // .failproofai/policies/team-policies.mjs @@ -125,44 +129,44 @@ Claude Code → failproofai --hook PreToolUse → קורא JSON מ-stdin fn: async (ctx) => { if (ctx.toolName !== "Bash") return allow(); if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) { - return instruct("הרץ בדיקות לפני ביצוע commit."); + return instruct("Run tests before committing."); } return allow(); }, }); ``` - + ```bash git add .failproofai/policies/ - git commit -m "הוסף מדיניות איכות של צוות" + git commit -m "Add team quality policies" ``` - כל חבר בצוות שיש לו failproofai מותקן יקבל את המדיניות הללו באופן אוטומטי. אין צורך בהגדרה לכל מפתח. + כל חברת צוות שיש לה failproofai מותקן בוחר את המדיניות הללו באופן אוטומטי. אין צורך בהגדרה לכל מפתח. -בצע commit ל-`.failproofai/policies/` למאגר שלך כדי שהצוות כולו יחלוק את אותם התקנים. כאשר הצוות שלך מגלה אופני כישלון חדשים, הוסף מדיניות ודחוף - כולם מקבלים את העדכון בעל `git pull` הבא שלהם. לאורך זמן מדיניות אלה הופכות לתקן איכות חי המשתפר כל הזמן. +השתנות `.failproofai/policies/` לאחסן שלך כדי שכל הצוות יהיה בעל תקנים זהים. כשהצוות שלך מגלה מצבי כשל חדשים, הוסף מדיניות ודחף — כולם מקבלים את העדכון ב-`git pull` הבא שלהם. עם הזמן המדיניות הללו הופכות לתקן איכות חי שממשיך להשתפר. --- ## אחסון נתונים -כל תצורה ו-log נשארים במכונה שלך: +כל התצורה וההיומנים נשארים במכונה שלך: | נתיב | מה זה שומר | -|------|----------------| +|------|----------------------| | `~/.failproofai/policies-config.json` | תצורת מדיניות גלובלית | -| `~/.failproofai/hook-activity.jsonl` | היסטוריית הפעלת hook | -| `~/.failproofai/hook.log` | יומן ניפוי באגים לשגיאות hook מותאם אישית | -| `.failproofai/policies-config.json` | תצורה לפי פרויקט (מובא) | -| `.failproofai/policies-config.local.json` | עדכונים אישיים (gitignored) | +| `~/.failproofai/hook-activity.jsonl` | היסטוריית ביצוע hook | +| `~/.failproofai/hook.log` | יומן ניפוי לשגיאות hook מותאמות | +| `.failproofai/policies-config.json` | תצורה לפי-פרויקט (מושתנית) | +| `.failproofai/policies-config.local.json` | דריסות אישיות (gitignored) | --- -## הסרת התקנה +## הסרת ההתקנה ```bash failproofai policies --uninstall @@ -172,24 +176,24 @@ failproofai policies --uninstall --- -## צעדים הבאים +## שלבים הבאים - טווחים וקובץ תצורה בפורמט + היקפים ופורמט קובץ תצורה - - כל 26 מדיניות עם פרמטרים + + כל 26 המדיניות עם פרמטרים - + כתוב את המדיניות שלך ב-JavaScript - - עקוב אחר הפעלות וסקור פעילות מדיניות + + עיקוב הפעלות וסקירת פעילות מדיניות \ No newline at end of file diff --git a/docs/he/introduction.mdx b/docs/he/introduction.mdx index 90dc6a3d..8221ab18 100644 --- a/docs/he/introduction.mdx +++ b/docs/he/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI מספקת לסוכני AI 39 מדיניויות כשל מובנות שתופסות לולאות, דליפות סודות, קריאות כלים הרסניות ועוד בהתקנה יחידה." +description: "FailproofAI נותן לסוכני AI 39 מדיניות כישל מובנות שתופסות לולאות, דליפות סודות, קריאות כלים הרסניות ועוד בהתקנה אחת." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -hooks ומדיניויות ל**טיפול בכשלי AI**, **התאוששות משגיאות**, ו**אמינות LLM**. שמור על סוכני ה-AI שלך אמינים ופועלים באופן אוטונומי על פני **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, וה-**Agents SDK**. +וו וענקים ל**טיפול בכשלים של AI**, **התאוששות משגיאות**, ו**אמינות LLM**. שמור על סוכני ה-AI שלך אמינים וממשיכים לפעול באופן אוטונומי על פני **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, ו**Agents SDK**. -סוכני AI נכשלים בדרכים צפויות. הם מפעילים פקודות הרסניות, מדליפים סודות, חורגים מהמטלה, תקועים בלולאות, או דוחפים ישירות לענף הראשי. אם משאירים ללא פקוח עין, כשלים קטנים מתגברים להפסקות, דליפות אישורים, והפסד עבודה. +סוכני AI כושלים בדרכים צפויות. הם מריצים פקודות הרסניות, מדליפים סודות, סוטים מהמשימה, נתקעים בלולאות, או דוחפים ישירות לענף הראשי. אם משאירים אותם ללא השגחה, כשלים קטנים מסתלבלים להפסקות, דלף של אישורים, ועבודה שאבדה. -FailproofAI פותרת זאת עם **מדיניויות**. כללים אלה מתחברים לכל קריאת כלי סוכן כדי **לגלות כשלים**, **להפחית אותם** (חסום, הנחה, טיהור), ו**התריע עליך** כשמשהו דורש תשומת לב. לוח מחוונים מקומי מאפשר לך לסקור כל קריאת כלי, כשל סוכן, ופעולת התאוששות לאחר מכן. +FailproofAI פותר זאת עם **מדיניות**. כללים אלה מתחברים לכל קריאת כלים של סוכן כדי **לזהות כשלים**, **להפחית אותם** (חסימה, הוראה, ניקיון), ו**להתריע עליך** כשמשהו זקוק לתשומת לב. לוח מחוונים מקומי מאפשר לך לבדוק כל קריאת כלים, כשל סוכן, ופעולת התאוששות לאחר מכן. -אין נתונים משאירים את המכונה שלך. +שום נתון אינו עוזב את המכשיר שלך. -## התחל +## התחלה - - חסום פקודות הרסניות, מנע דליפות סודות, שמור סוכנים בתוך גבולות הפרויקט, ועוד. הכל מחוץ לקופסה. + + חסום פקודות הרסניות, מנע דליפת סודות, שמור על סוכנים בתוך גבולות הפרויקט, ועוד. הכל מחוץ לקופסה. - - כתוב כללים שלך בـ JavaScript עם API פשוט של allow / deny / instruct. + + כתוב כללים שלך ב-JavaScript עם API פשוט של allow / deny / instruct. - - ראה מה עשו הסוכנים שלך בזמן שהיית רחוק. עיין בהפעלות, בדוק קריאות כלים, סקור איפה נשרפו המדיניויות. + + ראה מה עשו הסוכנים שלך בזמן שהיית בחוץ. עיין בהפעלות, בדוק קריאות כלים, בדוק היכן מדיניות התפעלו. - כוונן כל מדיניות ללא קוד. הגדר רשימות אישור, ענפים מוגנים, או סף לפרויקט או בעולם. + כייל כל מדיניות ללא קוד. הגדר רשימות הרשאה, ענפים מוגנים, או סף לפי-פרויקט או באופן גלובלי. @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # enable policies (or skip — `failproofai` will offer to set them up on first run) -failproofai # launch the dashboard +failproofai policies --install # הפוך מדיניות (או דלג — `failproofai` יציע להגדיר אותם בהפעלה הראשונה) +failproofai # הפעל את לוח המחוונים ``` -ראה את מדריך [התחלה](/he/getting-started) להסבר מלא. \ No newline at end of file +ראה את מדריך ה[התחלה](/he/getting-started) לסיור המלא. \ No newline at end of file diff --git a/docs/hi/built-in-policies.mdx b/docs/hi/built-in-policies.mdx index a2350188..9b0b2a3b 100644 --- a/docs/hi/built-in-policies.mdx +++ b/docs/hi/built-in-policies.mdx @@ -1,40 +1,39 @@ --- ---- -title: अंतर्निहित नीतियाँ -description: "39 अंतर्निहित नीतियाँ जो एजेंट की आम विफलताओं को पकड़ती हैं" +title: अंतर्निहित नीतियां +description: "39 अंतर्निहित नीतियां जो एजेंट विफलता के सामान्य कारणों को पकड़ते हैं" icon: shield --- -failproofai के साथ 39 अंतर्निहित नीतियाँ आती हैं जो एजेंट की आम विफलताओं को पकड़ती हैं। प्रत्येक नीति एक विशिष्ट हुक ईवेंट प्रकार और उपकरण नाम पर सक्रिय होती है। उन्नीस नीतियाँ पैरामीटर स्वीकार करती हैं जो आपको कोड लिखे बिना उनके व्यवहार को ट्यून करने देती हैं। पाँच वर्कफ़्लो नीतियाँ Claude के रुकने से पहले एक commit → push → PR → CI पाइपलाइन को लागू करती हैं। +failproofai के साथ 39 अंतर्निहित नीतियां आती हैं जो एजेंट विफलता के सामान्य कारणों को पकड़ते हैं। प्रत्येक नीति एक विशिष्ट हुक ईवेंट प्रकार और उपकरण नाम पर सक्रिय होती है। उन्नीस नीतियां पैरामीटर स्वीकार करती हैं जो आपको कोड लिखे बिना उनके व्यवहार को ट्यून करने देते हैं। पाँच वर्कफ़्लो नीतियां Claude के रुकने से पहले एक कमिट → पुश → PR → CI पाइपलाइन को लागू करती हैं। --- ## अवलोकन -नीतियाँ श्रेणियों में विभाजित हैं: +नीतियों को श्रेणियों में समूहीकृत किया गया है: -| श्रेणी | नीतियाँ | हुक प्रकार | +| श्रेणी | नीतियां | हुक प्रकार | |----------|----------|-----------| -| [खतरनाक आदेश](#खतरनाक-आदेश) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | -| [इनफ्रा आदेश](#infra-आदेश) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [गोपनीयता (सैनिटाइज़र)](#गोपनीयता-सैनिटाइज़र) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | -| [वातावरण](#वातावरण) | block-env-files, protect-env-vars | PreToolUse | -| [फाइल एक्सेस](#फाइल-एक्सेस) | block-read-outside-cwd, block-secrets-write | PreToolUse | +| [खतरनाक कमांड](#खतरनाक-कमांड) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | +| [इंफ्रा कमांड](#इंफ्रा-कमांड) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | +| [गोपनीयता (सैनिटाइजर)](#गोपनीयता-सैनिटाइजर) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [पर्यावरण](#पर्यावरण) | block-env-files, protect-env-vars | PreToolUse | +| [फ़ाइल एक्सेस](#फ़ाइल-एक्सेस) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | | [डेटाबेस](#डेटाबेस) | warn-destructive-sql, warn-schema-alteration | PreToolUse | -| [चेतावनियाँ](#चेतावनियाँ) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | -| [पैकेज मैनेजर](#पैकेज-मैनेजर) | prefer-package-manager | PreToolUse | +| [चेतावनियां](#चेतावनियां) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | +| [पैकेज प्रबंधक](#पैकेज-प्रबंधक) | prefer-package-manager | PreToolUse | | [वर्कफ़्लो](#वर्कफ़्लो) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | - **`block-`** — एजेंट को आगे बढ़ने से रोकें। -- **`warn-`** — एजेंट को अतिरिक्त संदर्भ दें ताकि यह स्वयं को ठीक कर सके। -- **`sanitize-`** — एजेंट को देखने से पहले उपकरण आउटपुट से संवेदनशील डेटा हटाएँ। +- **`warn-`** — एजेंट को अतिरिक्त संदर्भ दें ताकि वह स्वयं को सही कर सके। +- **`sanitize-`** — एजेंट को देखने से पहले उपकरण आउटपुट से संवेदनशील डेटा को हटाएं। ### नेमस्पेस -प्रत्येक नीति एक `/` स्लॉट में रहती है। अंतर्निहित नीतियाँ **`failproofai/`** नेमस्पेस से संबंधित हैं — उदाहरण के लिए, `failproofai/sanitize-jwt`। नेमस्पेस तब collision को रोकता है जब आप कस्टम या तीसरे पक्ष की नीतियों को समान छोटे नामों के साथ भी लोड करते हैं। +प्रत्येक नीति एक `/` स्लॉट में रहती है। अंतर्निहित नीतियां **`failproofai/`** नेमस्पेस से संबंधित हैं — उदाहरण के लिए, `failproofai/sanitize-jwt`। नेमस्पेस टकराव को रोकता है जब आप कस्टम या तीसरे पक्ष की नीतियों को भी लोड करते हैं जिनके नाम समान होते हैं। -आपके कॉन्फ़िग में आप अंतर्निहित को उसके छोटे नाम या योग्य नाम दोनों से संदर्भित कर सकते हैं; दोनों रूप एक ही नीति को resolve करते हैं: +आपके कॉन्फ़िगरेशन में आप एक अंतर्निहित नीति को उसके संक्षिप्त नाम या योग्य नाम दोनों से संदर्भित कर सकते हैं; दोनों फॉर्म एक ही नीति को हल करते हैं: ```json { @@ -45,33 +44,33 @@ failproofai के साथ 39 अंतर्निहित नीतिय } ``` -यदि किसी नाम में कोई `/` नहीं है, failproofai इसे default नेमस्पेस `failproofai` के अंतर्गत मानता है। नाम जिनमें पहले से `/` है (जैसे `myorg/foo`, `custom/my-hook`) जैसे-जैसे रखे जाते हैं। -- **`require-`** — Stop ईवेंट को ब्लॉक करें जब तक शर्तें पूरी न हों। +यदि किसी नाम में `/` नहीं है, तो failproofai इसे डिफ़ॉल्ट नेमस्पेस `failproofai` से संबंधित मानता है। जिन नामों में पहले से `/` है (जैसे `myorg/foo`, `custom/my-hook`) उन्हें यथावत रखा जाता है। +- **`require-`** — Stop ईवेंट को तब तक ब्लॉक करें जब तक शर्तें पूरी न हो जाएं। --- -प्रत्येक नीति `policyParams` में एक वैकल्पिक `hint` फील्ड का समर्थन करती है। hint को deny या instruct message में जोड़ा जाता है जो Claude देखता है, नीति कोड को संशोधित किए बिना कार्रवाई योग्य मार्गदर्शन देते हुए। अंतर्निहित, कस्टम, और convention नीतियों के साथ काम करता है। विवरण के लिए [Configuration → hint](/hi/configuration#hint-cross-cutting) देखें। +प्रत्येक नीति `policyParams` में एक वैकल्पिक `hint` फ़ील्ड का समर्थन करती है। संकेत को deny या instruct संदेश में जोड़ा जाता है जो Claude देखता है, जो नीति कोड को संशोधित किए बिना कार्यशील निर्देश देता है। अंतर्निहित, कस्टम, और परंपरा नीतियों के साथ काम करता है। विवरण के लिए [कॉन्फ़िगरेशन → hint](/hi/configuration#hint-cross-cutting) देखें। --- -## खतरनाक आदेश +## खतरनाक कमांड -एजेंटों को उन ऑपरेशन चलाने से रोकें जो को पूर्ववत करना कठिन हो या जो होस्ट सिस्टम को नुकसान पहुंचा सकते हैं। +एजेंट को ऐसे ऑपरेशन चलाने से रोकें जो वापस लौटना मुश्किल हों या जो होस्ट सिस्टम को नुकसान पहुंचा सकते हों। ### `block-sudo` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `sudo` कमांड deny करता है। +**डिफ़ॉल्ट:** किसी भी `sudo` कमांड को अस्वीकार करता है। -`sudo` कीवर्ड सहित invocations को ब्लॉक करता है। पैटर्न मिलान कच्ची स्ट्रिंग के बजाय parsed कमांड टोकन पर किया जाता है, shell operator injection के माध्यम से bypass को रोकने के लिए। +`sudo` कीवर्ड युक्त आह्वान को ब्लॉक करता है। पैटर्न मिलान कच्ची स्ट्रिंग पर नहीं, बल्कि पार्स किए गए कमांड टोकन पर किया जाता है, ताकि शेल ऑपरेटर इंजेक्शन द्वारा बाईपास को रोका जा सके। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | सटीक कमांड प्रीफ़िक्स जो अनुमत हैं। प्रत्येक entry को parsed argv tokens के विरुद्ध मिलाया जाता है। | +| `allowPatterns` | `string[]` | `[]` | सटीक कमांड उपसर्ग जो अनुमत हैं। प्रत्येक प्रविष्टि को पार्स किए गए argv टोकन के विरुद्ध मिलाया जाता है। | **उदाहरण:** @@ -85,10 +84,10 @@ failproofai के साथ 39 अंतर्निहित नीतिय } ``` -इस कॉन्फ़िग के साथ, `sudo systemctl status nginx` अनुमत है, लेकिन `sudo rm /etc/hosts` deny किया जाता है। +इस कॉन्फ़िगरेशन के साथ, `sudo systemctl status nginx` की अनुमति है, लेकिन `sudo rm /etc/hosts` को अस्वीकार किया जाता है। -पैटर्न को कच्ची कमांड स्ट्रिंग के बजाय parsed tokens के विरुद्ध मिलाया जाता है। यह appended shell operators के माध्यम से bypass को रोकता है (उदाहरण के लिए `sudo systemctl status x; rm -rf /` `sudo systemctl status *` से match नहीं करता)। +पैटर्न को कच्ची कमांड स्ट्रिंग के विरुद्ध नहीं, बल्कि पार्स किए गए टोकन के विरुद्ध मिलाया जाता है। यह अपितृत शेल ऑपरेटरों द्वारा बाईपास को रोकता है (जैसे `sudo systemctl status x; rm -rf /` को `sudo systemctl status *` के विरुद्ध मेल नहीं खाता)। --- @@ -96,13 +95,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-rm-rf` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** `rm -rf`, `rm -fr`, और समान recursive deletion रूपों को deny करता है। +**डिफ़ॉल्ट:** `rm -rf`, `rm -fr`, और समान पुनरावर्ती विलोपन फॉर्म को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | पथ जो recursively delete करने के लिए सुरक्षित हैं (उदाहरण के लिए `/tmp`)। | +| `allowPaths` | `string[]` | `[]` | ऐसे पथ जो पुनरावर्ती रूप से हटाने के लिए सुरक्षित हैं (जैसे `/tmp`)। | **उदाहरण:** @@ -121,7 +120,7 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-curl-pipe-sh` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** `curl | bash`, `curl | sh`, `wget | bash`, और समान patterns को deny करता है। +**डिफ़ॉल्ट:** `curl | bash`, `curl | sh`, `wget | bash`, और समान पैटर्न को अस्वीकार करता है। कोई पैरामीटर नहीं। @@ -130,28 +129,28 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-failproofai-commands` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** उन कमांडों को deny करता है जो failproofai को स्वयं को uninstall या disable करने के लिए होंगे (उदाहरण के लिए `npm uninstall failproofai`, `failproofai policies --uninstall`)। +**डिफ़ॉल्ट:** ऐसी कमांड को अस्वीकार करता है जो failproofai को स्वयं को अनइंस्टॉल या अक्षम करती हैं (जैसे `npm uninstall failproofai`, `failproofai policies --uninstall`)। कोई पैरामीटर नहीं। --- -## infra आदेश +## इंफ्रा कमांड -कोडिंग एजेंटों को infrastructure CLIs चलाने या CI/CD pipelines को trigger करने से रोकें। इस श्रेणी में सभी नीतियाँ **opt-in** हैं (`defaultEnabled: false`) — एजेंट जिन्हें वैध रूप से `kubectl`, `terraform`, आदि को कॉल करने की आवश्यकता है, जब तक आप नीति को enable नहीं करते, तब तक बाधित नहीं होंगे। जब enabled हो, तो matched CLI का हर invocation deny किया जाता है जब तक कमांड `allowPatterns` में एक entry से match न हो। +कोडिंग एजेंट को इंफ्रास्ट्रक्चर CLI चलाने या CI/CD पाइपलाइन ट्रिगर करने से रोकें। इस श्रेणी में सभी नीतियां **ऑप्ट-इन** हैं (`defaultEnabled: false`) — एजेंट जिन्हें वास्तव में `kubectl`, `terraform`, आदि कॉल करने की आवश्यकता है, उन्हें नीति को सक्षम करने तक बाधित नहीं किया जाएगा। सक्षम होने पर, मिलान किए गए CLI के प्रत्येक आह्वान को अस्वीकार किया जाता है जब तक कि कमांड `allowPatterns` में एक प्रविष्टि से मेल न खाए। -पैटर्न grammar [`block-sudo`](#block-sudo) के समान है: tokens को parsed argv के विरुद्ध मिलाया जाता है, `*` एक token के लिए wildcard है, और कोई भी कमांड जिसमें एक standalone shell operator (`&&`, `||`, `|`, `;`) या embedded shell metacharacters वाला token है, injection bypasses को रोकने के लिए allowlist matching से पहले reject किया जाता है। +पैटर्न व्याकरण [`block-sudo`](#block-sudo) के समान है: टोकन को पार्स किए गए argv के विरुद्ध मिलाया जाता है, `*` एक टोकन के लिए वाइल्डकार्ड है, और किसी भी कमांड जिसमें एक स्वतंत्र शेल ऑपरेटर (`&&`, `||`, `|`, `;`) या एक टोकन है जिसमें एम्बेड किए गए शेल मेटाकैरेक्टर हैं, इंजेक्शन बाईपास को रोकने के लिए व्हाइटलिस्ट मिलान से पहले खारिज कर दिया जाता है। ### `block-kubectl` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `kubectl` invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `kubectl` आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | kubectl कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | kubectl कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -165,20 +164,20 @@ failproofai के साथ 39 अंतर्निहित नीतिय } ``` -इस कॉन्फ़िग के साथ, `kubectl get pods` अनुमत है लेकिन `kubectl apply -f deploy.yaml` deny किया जाता है। +इस कॉन्फ़िगरेशन के साथ, `kubectl get pods` की अनुमति है लेकिन `kubectl apply -f deploy.yaml` को अस्वीकार किया जाता है। --- ### `block-terraform` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `terraform` या `tofu` (OpenTofu) invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `terraform` या `tofu` (OpenTofu) आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | terraform/tofu कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | terraform/tofu कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -197,13 +196,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-aws-cli` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `aws` CLI invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `aws` CLI आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | aws CLI कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | aws CLI कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -222,13 +221,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-gcloud` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `gcloud` (Google Cloud) CLI invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `gcloud` (Google Cloud) CLI आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | gcloud कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | gcloud कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -247,13 +246,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-az-cli` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `az` (Azure) CLI invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `az` (Azure) CLI आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | az CLI कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | az CLI कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -272,13 +271,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-helm` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** कोई भी `helm` invocation deny करता है। +**डिफ़ॉल्ट:** किसी भी `helm` आह्वान को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | helm कमांड प्रीफ़िक्स जो अनुमत हैं। | +| `allowPatterns` | `string[]` | `[]` | helm कमांड उपसर्ग जो अनुमत हैं। | **उदाहरण:** @@ -297,7 +296,7 @@ failproofai के साथ 39 अंतर्निहित नीतिय ### `block-gh-pipeline` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** निम्नलिखित `gh` CLI subcommands को deny करता है जो state को mutate करते हैं या pipelines को trigger करते हैं: +**डिफ़ॉल्ट:** निम्नलिखित `gh` CLI सबकमांड को अस्वीकार करता है जो स्थिति को परिवर्तित करते हैं या पाइपलाइन ट्रिगर करते हैं: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -306,13 +305,13 @@ failproofai के साथ 39 अंतर्निहित नीतिय - `gh cache delete` - `gh secret set`, `gh secret delete` -Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list`, `gh release view`, और `gh api repos/.../...` इस नीति से match **नहीं** होते हैं — वे workflow checks के लिए नियमित रूप से आवश्यक हैं (failproofai का अपना `require-ci-green-before-stop` सहित)। +पढ़ने-केवल `gh` सबकमांड जैसे `gh pr view`, `gh pr list`, `gh run list`, `gh release view`, और `gh api repos/.../...` इस नीति से **नहीं** मेल खाते — वर्कफ़्लो जांच के लिए नियमित रूप से आवश्यक होते हैं (failproofai के अपने `require-ci-green-before-stop` सहित)। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | विशिष्ट scripted invocations जो allow करने के लिए हैं भले ही वे अन्यथा deny किए जाएँ। | +| `allowPatterns` | `string[]` | `[]` | विशिष्ट स्क्रिप्टेड आह्वान जिन्हें अनुमति देनी है भले ही वे अन्यथा अस्वीकृत हों। | **उदाहरण:** @@ -328,14 +327,14 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list --- -## गोपनीयता (सैनिटाइज़र) +## गोपनीयता (सैनिटाइजर) -एजेंटों को credentials को अपने context या output में leak करने से रोकें। Sanitizer नीतियाँ **PostToolUse** ईवेंट पर fire होती हैं। जब Claude Bash कमांड चलाता है, फाइल पढ़ता है, या कोई भी tool कॉल करता है, ये नीतियाँ आउटपुट को inspect करती हैं इससे पहले कि यह Claude को वापस दिया जाए। यदि एक secret pattern detect किया जाता है, तो नीति एक deny decision return करती है जो आउटपुट को वापस जाने से रोकता है। +एजेंट को क्रेडेंशियल को उनके संदर्भ या आउटपुट में लीक करने से रोकें। सैनिटाइजर नीतियां **PostToolUse** ईवेंट पर सक्रिय होती हैं। जब Claude एक Bash कमांड चलाता है, एक फ़ाइल पढ़ता है, या किसी भी उपकरण को कॉल करता है, तो ये नीतियां Claude को वापस करने से पहले आउटपुट का निरीक्षण करती हैं। यदि कोई गोपनीय पैटर्न पाया जाता है, तो नीति एक deny निर्णय देती है जो आउटपुट को वापस पास होने से रोकता है। ### `sanitize-jwt` -**ईवेंट:** PostToolUse (सभी tools) -**डिफ़ॉल्ट:** JWT tokens को redact करता है (तीन base64url segments `.` से separated)। +**ईवेंट:** PostToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** JWT टोकन को रिडैक्ट करता है (तीन base64url सेगमेंट `.` से अलग किए गए)। कोई पैरामीटर नहीं। @@ -343,14 +342,14 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `sanitize-api-keys` -**ईवेंट:** PostToolUse (सभी tools) -**डिफ़ॉल्ट:** सामान्य API key formats को redact करता है: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`), और Google API keys (`AIza`)। +**ईवेंट:** PostToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** सामान्य API कुंजी फॉर्मेट को रिडैक्ट करता है: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS एक्सेस कुंजियां (`AKIA`), Stripe कुंजियां (`sk_live_`, `sk_test_`), और Google API कुंजियां (`AIza`)। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | अतिरिक्त regex patterns जो secrets के रूप में treat करें। | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | गोपनीयता के रूप में मानने के लिए अतिरिक्त regex पैटर्न। | **उदाहरण:** @@ -371,8 +370,8 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `sanitize-connection-strings` -**ईवेंट:** PostToolUse (सभी tools) -**डिफ़ॉल्ट:** डेटाबेस connection strings को redact करता है जिनमें embedded credentials हैं (उदाहरण के लिए `postgresql://user:password@host/db`)। +**ईवेंट:** PostToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** डेटाबेस कनेक्शन स्ट्रिंग को रिडैक्ट करता है जिनमें एम्बेड किए गए क्रेडेंशियल हैं (जैसे `postgresql://user:password@host/db`)। कोई पैरामीटर नहीं। @@ -380,8 +379,8 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `sanitize-private-key-content` -**ईवेंट:** PostToolUse (सभी tools) -**डिफ़ॉल्ट:** PEM blocks को redact करता है (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, आदि)। +**ईवेंट:** PostToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** PEM ब्लॉक को रिडैक्ट करता है (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, आदि)। कोई पैरामीटर नहीं। @@ -389,23 +388,23 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `sanitize-bearer-tokens` -**ईवेंट:** PostToolUse (सभी tools) -**डिफ़ॉल्ट:** `Authorization: Bearer ` headers को redact करता है जहाँ token 20 या अधिक characters है। +**ईवेंट:** PostToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** `Authorization: Bearer ` हेडर को रिडैक्ट करता है जहां टोकन 20 या अधिक वर्ण हो। कोई पैरामीटर नहीं। --- -## वातावरण +## पर्यावरण -संवेदनशील environment configuration को एजेंटों द्वारा read या expose किए जाने से बचाएँ। +एजेंट द्वारा संवेदनशील पर्यावरण कॉन्फ़िगरेशन को पढ़ने या उजागर किए जाने से सुरक्षित करें। ### `block-env-files` **ईवेंट:** PreToolUse (Bash, Read) -**डिफ़ॉल्ट:** `.env` files को `cat .env`, file path के रूप में `.env` के साथ `Read` tool calls आदि के माध्यम से पढ़ने को deny करता है। +**डिफ़ॉल्ट:** `cat .env`, `.env` को फ़ाइल पथ के रूप में लेकर Read टूल कॉल के माध्यम से `.env` फ़ाइलों को पढ़ने से अस्वीकार करता है। -`.envrc` या अन्य environment-adjacent files को नहीं रोकता — केवल exactly `.env` नाम वाली files को। +`.envrc` या अन्य पर्यावरण-आसन्न फ़ाइलों को ब्लॉक नहीं करता — केवल `.env` नामक फ़ाइलों को। कोई पैरामीटर नहीं। @@ -414,26 +413,26 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `protect-env-vars` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** उन कमांडों को deny करता है जो environment variables को print करते हैं: `printenv`, `env`, `echo $VAR`। +**डिफ़ॉल्ट:** ऐसी कमांड को अस्वीकार करता है जो पर्यावरण चर को प्रिंट करते हैं: `printenv`, `env`, `echo $VAR`। कोई पैरामीटर नहीं। --- -## फाइल एक्सेस +## फ़ाइल एक्सेस -एजेंटों को project boundaries के भीतर और sensitive files से दूर रखें। +एजेंट को परियोजना सीमाओं के भीतर काम करने और संवेदनशील फ़ाइलों से दूर रखें। ### `block-read-outside-cwd` **ईवेंट:** PreToolUse (Read, Bash) -**डिफ़ॉल्ट:** project root के बाहर की files को पढ़ने को deny करता है। boundary `CLAUDE_PROJECT_DIR` है (एक बार प्रति session Claude Code द्वारा set), जिसमें fallback होता है session के current working directory में जब यह variable unset हो। live `cwd` के बजाय project root का उपयोग करने का मतलब है कि boundary स्थिर रहता है भले ही Claude subdirectory में `cd` कर जाए। +**डिफ़ॉल्ट:** परियोजना रूट के बाहर फ़ाइलों को पढ़ने से अस्वीकार करता है। सीमा `CLAUDE_PROJECT_DIR` है (Claude Code द्वारा प्रति सत्र एक बार सेट किया गया), जब वह चर अनुपस्थित हो तो सत्र की वर्तमान कार्य निर्देशिका को फॉलबैक के रूप में। लाइव `cwd` के बजाय परियोजना रूट का उपयोग करने का मतलब है कि सीमा स्थिर रहती है भले ही Claude किसी सबडायरेक्टरी में `cd` हो। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Absolute path prefixes जो अनुमत हैं भले ही project root के बाहर हों। | +| `allowPaths` | `string[]` | `[]` | निरपेक्ष पथ उपसर्ग जो परियोजना रूट के बाहर भी अनुमत हैं। | **उदाहरण:** @@ -452,13 +451,13 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ### `block-secrets-write` **ईवेंट:** PreToolUse (Write, Edit) -**डिफ़ॉल्ट:** private keys और certificates के लिए आमतौर पर उपयोग की जाने वाली files को write करने को deny करता है: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`। +**डिफ़ॉल्ट:** निजी कुंजी और प्रमाणपत्रों के लिए आमतौर पर उपयोग की जाने वाली फ़ाइलों में लिखने से अस्वीकार करता है: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | अतिरिक्त filename patterns (glob-style) जो block करें। | +| `additionalPatterns` | `string[]` | `[]` | ब्लॉक करने के लिए अतिरिक्त फ़ाइलनाम पैटर्न (glob-शैली)। | **उदाहरण:** @@ -476,18 +475,18 @@ Read-only `gh` subcommands जैसे `gh pr view`, `gh pr list`, `gh run list ## Git -accidental pushes, force-pushes, और branch mistakes को रोकें जो undo करना कठिन हो। +आकस्मिक पुश, फोर्स-पुश, और शाखा गलतियों को रोकें जो वापस लौटना मुश्किल हैं। ### `block-push-master` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** `git push origin main` और `git push origin master` को deny करता है। +**डिफ़ॉल्ट:** `git push origin main` और `git push origin master` को अस्वीकार करता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Branch नाम जिन्हें directly push नहीं किया जा सकता। | +| `protectedBranches` | `string[]` | `["main", "master"]` | शाखा नाम जिन्हें सीधे पुश नहीं किया जा सकता। | **उदाहरण:** @@ -502,7 +501,7 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ``` -सभी branches को push करने की अनुमति देने के लिए (इस नीति को `enabledPolicies` से remove किए बिना effectively disable करने के लिए), `protectedBranches: []` set करें। +सभी शाखाओं को पुश करने की अनुमति देने के लिए (इस नीति को `enabledPolicies` से हटाए बिना प्रभावी रूप से अक्षम करने के लिए), `protectedBranches: []` सेट करें। --- @@ -510,28 +509,28 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ### `block-work-on-main` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** `git commit`, `git merge`, `git rebase`, और `git cherry-pick` को deny करता है जबकि working tree `main` या `master` पर हो। Branch creation और switching (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) प्रभावित नहीं होते। +**डिफ़ॉल्ट:** `git commit`, `git merge`, `git rebase`, और `git cherry-pick` को अस्वीकार करता है जबकि कार्य वृक्ष `main` या `master` पर हो। शाखा निर्माण और स्विचिंग (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) प्रभावित नहीं होते। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Branch नाम जिन पर commit/merge/rebase/cherry-pick deny किया जाता है। | +| `protectedBranches` | `string[]` | `["main", "master"]` | शाखा नाम जिन पर commit/merge/rebase/cherry-pick अस्वीकार किया जाता है। | --- ### `block-force-push` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** `git push --force` और `git push -f` को deny करता है। +**डिफ़ॉल्ट:** `git push --force` और `git push -f` को अस्वीकार करता है। -कोई policy-specific पैरामीटर नहीं। cross-cutting [`hint`](/hi/configuration#hint-cross-cutting) का उपयोग करें alternatives suggest करने के लिए: +कोई नीति-विशिष्ट पैरामीटर नहीं। विकल्प सुझाने के लिए क्रॉस-कटिंग [`hint`](/hi/configuration#hint-cross-cutting) का उपयोग करें: ```json { "policyParams": { "block-force-push": { - "hint": "अपने current HEAD से एक नई branch बनाएँ (उदाहरण के लिए `git checkout -b `) और उसे push करें।" + "hint": "अपने वर्तमान HEAD से एक नई शाखा बनाएं (जैसे `git checkout -b `) और इसके बजाय उसे पुश करें।" } } } @@ -542,7 +541,7 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ### `warn-git-amend` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को सावधानी से proceed करने का instruct करता है जब `git commit --amend` चलाया जाए। कमांड को block नहीं करता। +**डिफ़ॉल्ट:** Claude को `git commit --amend` चलाते समय सावधानी से आगे बढ़ने के लिए निर्देश दें। कमांड को ब्लॉक नहीं करता। कोई पैरामीटर नहीं। @@ -551,7 +550,7 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ### `warn-git-stash-drop` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को `git stash drop` चलाने से पहले confirm करने का instruct करता है। कमांड को block नहीं करता। +**डिफ़ॉल्ट:** Claude को `git stash drop` चलाने से पहले पुष्टि करने के लिए निर्देश दें। कमांड को ब्लॉक नहीं करता। कोई पैरामीटर नहीं। @@ -560,7 +559,7 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ### `warn-all-files-staged` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को review करने का instruct करता है कि यह क्या stage कर रहा है जब `git add -A` या `git add .` चलाया जाए। कमांड को block नहीं करता। +**डिफ़ॉल्ट:** Claude को `git add -A` या `git add .` चलाते समय स्टेज कर रहे को समीक्षा करने के लिए निर्देश दें। कमांड को ब्लॉक नहीं करता। कोई पैरामीटर नहीं। @@ -568,12 +567,12 @@ accidental pushes, force-pushes, और branch mistakes को रोकें ## डेटाबेस -destructive SQL operations को execute होने से पहले पकड़ें अपने database के विरुद्ध। +विनाशकारी SQL ऑपरेशन को आपके डेटाबेस के विरुद्ध निष्पादित होने से पहले पकड़ें। ### `warn-destructive-sql` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को confirm करने का instruct करता है SQL चलाने से पहले जिसमें `DROP TABLE`, `DROP DATABASE`, या `WHERE` clause के बिना `DELETE` हो। +**डिफ़ॉल्ट:** Claude को `DROP TABLE`, `DROP DATABASE`, या `WHERE` क्लॉज़ के बिना `DELETE` युक्त SQL चलाने से पहले पुष्टि करने के लिए निर्देश दें। कोई पैरामीटर नहीं। @@ -582,26 +581,26 @@ destructive SQL operations को execute होने से पहले प ### `warn-schema-alteration` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को `ALTER TABLE` statements चलाने से पहले confirm करने का instruct करता है। +**डिफ़ॉल्ट:** Claude को `ALTER TABLE` स्टेटमेंट चलाने से पहले पुष्टि करने के लिए निर्देश दें। कोई पैरामीटर नहीं। --- -## चेतावनियाँ +## चेतावनियां -एजेंटों को potentially risky लेकिन non-destructive operations से पहले extra context दें। +एजेंट को संभावित रूप से जोखिम भरे लेकिन गैर-विनाशकारी ऑपरेशन से पहले अतिरिक्त संदर्भ दें। ### `warn-large-file-write` **ईवेंट:** PreToolUse (Write) -**डिफ़ॉल्ट:** Claude को 1024 KB से बड़ी files write करने से पहले confirm करने का instruct करता है। +**डिफ़ॉल्ट:** Claude को 1024 KB से बड़ी फ़ाइलें लिखने से पहले पुष्टि करने के लिए निर्देश दें। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | File size threshold kilobytes में जिसके ऊपर एक warning issue किया जाता है। | +| `thresholdKb` | `number` | `1024` | किलोबाइट में फ़ाइल आकार की सीमा जिसके ऊपर एक चेतावनी जारी की जाती है। | **उदाहरण:** @@ -616,7 +615,7 @@ destructive SQL operations को execute होने से पहले प ``` -Hook handler payloads पर 1 MB stdin limit enforce करता है। इस नीति को small content के साथ test करने के लिए, `thresholdKb` को 1024 से काफी कम value में set करें। +हुक हैंडलर पेलोड पर 1 MB stdin सीमा को लागू करता है। छोटी सामग्री के साथ इस नीति का परीक्षण करने के लिए, `thresholdKb` को 1024 के नीचे अच्छी तरह से एक मान पर सेट करें। --- @@ -624,7 +623,7 @@ Hook handler payloads पर 1 MB stdin limit enforce करता है। इ ### `warn-package-publish` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को `npm publish` चलाने से पहले confirm करने का instruct करता है। +**डिफ़ॉल्ट:** Claude को `npm publish` चलाने से पहले पुष्टि करने के लिए निर्देश दें। कोई पैरामीटर नहीं। @@ -633,7 +632,7 @@ Hook handler payloads पर 1 MB stdin limit enforce करता है। इ ### `warn-background-process` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को `nohup`, `&`, `disown`, या `screen` के via background processes launch करते समय सावधान रहने का instruct करता है। +**डिफ़ॉल्ट:** Claude को `nohup`, `&`, `disown`, या `screen` के माध्यम से बैकग्राउंड प्रक्रियाएं लॉन्च करते समय सावधान रहने के लिए निर्देश दें। कोई पैरामीटर नहीं। @@ -642,29 +641,29 @@ Hook handler payloads पर 1 MB stdin limit enforce करता है। इ ### `warn-global-package-install` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Claude को `npm install -g`, `yarn global add`, या virtual environment के बिना `pip install` चलाने से पहले confirm करने का instruct करता है। +**डिफ़ॉल्ट:** Claude को `npm install -g`, `yarn global add`, या वर्चुअल पर्यावरण के बिना `pip install` चलाने से पहले पुष्टि करने के लिए निर्देश दें। कोई पैरामीटर नहीं। --- -## पैकेज मैनेजर +## पैकेज प्रबंधक -enforce करें कि एजेंट किस पैकेज मैनेजर को use करने की अनुमति है। +एजेंट को किस पैकेज प्रबंधक का उपयोग करने की अनुमति है इसे लागू करें। ### `prefer-package-manager` **ईवेंट:** PreToolUse (Bash) -**डिफ़ॉल्ट:** Disabled। जब enabled हो, तो `allowed` list में नहीं होने वाली कोई भी पैकेज मैनेजर command को block करता है और Claude को allowed manager का उपयोग करके command को rewrite करने का कहता है। +**डिफ़ॉल्ट:** अक्षम। जब सक्षम किया जाता है, तो `allowed` सूची में नहीं होने वाली कोई भी पैकेज प्रबंधक कमांड को ब्लॉक करता है और Claude को एक अनुमत प्रबंधक का उपयोग करके कमांड को फिर से लिखने के लिए बताता है। -Detects: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo। +पहचान करता है: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo। | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | अनुमत पैकेज मैनेजर नाम। कोई भी detected manager जो इस list में नहीं है block किया जाता है। जब empty हो, तो नीति एक no-op है। | -| `blocked` | string[] | `[]` | अतिरिक्त मैनेजर नाम जो built-in list के अलावा block करें (उदाहरण के लिए `['pdm', 'pipx']`)। | +| `allowed` | string[] | `[]` | अनुमत पैकेज प्रबंधक नाम। इस सूची में नहीं होने वाली कोई भी पहचानी गई प्रबंधक को ब्लॉक किया जाता है। जब खाली हो, तो नीति एक नो-ऑप है। | +| `blocked` | string[] | `[]` | अंतर्निहित सूची से परे ब्लॉक करने के लिए अतिरिक्त प्रबंधक नाम (जैसे `['pdm', 'pipx']`)। | -Built-in block list covers: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo। इस list में नहीं होने वाले managers को append करने के लिए `blocked` का उपयोग करें। +अंतर्निहित ब्लॉक सूची शामिल है: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo। इस सूची में नहीं होने वाले प्रबंधकों को जोड़ने के लिए `blocked` का उपयोग करें। **उदाहरण कॉन्फ़िगरेशन:** @@ -680,18 +679,18 @@ Built-in block list covers: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv } ``` -इस कॉन्फ़िग के साथ, `pip install flask` और `pdm install flask` दोनों deny किए जाते हैं Claude को एक message के साथ जो कहता है `uv` या `bun` का उपयोग करने के लिए। `uv pip install flask` जैसी commands अनुमत हैं क्योंकि `uv` allowlist में है और पहले check किया जाता है। +इस कॉन्फ़िगरेशन के साथ, `pip install flask` और `pdm install flask` दोनों को Claude को `uv` या `bun` का उपयोग करने के लिए कहने वाले संदेश के साथ अस्वीकार किया जाता है। `uv pip install flask` जैसी कमांड की अनुमति है क्योंकि `uv` अनुमति सूची में है और पहले जांचा जाता है। --- ## AI व्यवहार -detect करें जब एजेंट stuck हों या unexpectedly behave करें। +जब एजेंट फंस जाते हैं या अप्रत्याशित रूप से व्यवहार करते हैं तो पहचानें। ### `warn-repeated-tool-calls` -**ईवेंट:** PreToolUse (सभी tools) -**डिफ़ॉल्ट:** Claude को reconsider करने का instruct करता है जब same tool को 3+ times identical parameters के साथ call किया जाए — एक common sign कि एजेंट एक loop में stuck है। +**ईवेंट:** PreToolUse (सभी उपकरण) +**डिफ़ॉल्ट:** Claude को एक ही उपकरण को 3+ बार समान पैरामीटर के साथ कॉल करते समय पुनर्विचार करने के लिए निर्देश दें — एजेंट को लूप में फंसने का एक सामान्य संकेत। कोई पैरामीटर नहीं। @@ -699,40 +698,39 @@ detect करें जब एजेंट stuck हों या unexpectedly b ## वर्कफ़्लो -एक disciplined end-of-session workflow को enforce करें। ये नीतियाँ **Stop** event पर fire होती हैं और एजेंट को stop करने से deny करती हैं जब तक प्रत्येक condition meet न हो। वे एक natural dependency chain का follow करती हैं: commit → push → PR → CI। यदि एक नीति deny करती है, तो chain में बाद की नीतियाँ skip किए जाते हैं (deny short-circuits)। +एक अनुशासित सत्र-अंत वर्कफ़्लो को लागू करें। ये नीतियां **Stop** ईवेंट पर सक्रिय होती हैं और एजेंट को तब तक रुकने से अस्वीकार करती हैं जब तक प्रत्येक शर्त पूरी न हो। वे एक प्राकृतिक निर्भरता श्रृंखला का पालन करते हैं: कमिट → पुश → PR → CI। यदि कोई नीति अस्वीकार करती है, तो श्रृंखला में बाद की नीतियों को छोड़ दिया जाता है (deny छोटे-परिपथ करता है)। -सभी वर्कफ़्लो नीतियाँ **fail-open** हैं: यदि required tool available नहीं है (उदाहरण के लिए `gh` installed नहीं, कोई git remote नहीं), तो नीति allow करती है एक informational message के साथ जो explain करता है कि check क्यों skip किया गया। +सभी वर्कफ़्लो नीतियां **fail-open** हैं: यदि आवश्यक उपकरण उपलब्ध नहीं है (जैसे `gh` स्थापित नहीं है, कोई git रिमोट नहीं), तो नीति एक सूचनात्मक संदेश के साथ अनुमति देती है कि जांच को क्यों छोड़ा गया है। -### Per-CLI Stop semantics +### प्रति-CLI Stop शब्दार्थ -Stop enforcement सातों supported CLIs में थोड़ा अलग दिखता है क्योंकि प्रत्येक एक अलग "agent finished" hook contract expose करता है। **outcome** same है — एजेंट workflow gate failing होने पर stop नहीं हो सकता — लेकिन **mechanics** अलग हैं। नीचे की table summarize करती है; केवल Pi के पास एक user-visible quirk है जो समझने के लायक है इससे पहले आप एक `require-*-before-stop` नीति को enable करें। +Stop प्रवर्तन छह समर्थित CLIs के पार थोड़ा अलग दिखता है क्योंकि प्रत्येक एक अलग "एजेंट समाप्त" हुक अनुबंध उजागर करता है। **परिणाम** समान है — एजेंट वर्कफ़्लो गेट विफल होने पर रुकने से दूर नहीं हो सकते — लेकिन **यांत्रिकी** अलग हैं। नीचे दी गई तालिका सारांश देती है; केवल Pi के पास एक उपयोगकर्ता-दृश्यमान विचित्र है जो `require-*-before-stop` नीति को सक्षम करने से पहले समझने लायक है। -| CLI | जब gate fires | आप क्या देखते हैं | +| CLI | गेट कब सक्रिय होता है | आप क्या देखते हैं | |---|---|---| -| Claude Code | Same agent loop, immediately | Claude काम करता रहता है — issue को fix करता है, फिर finish करने का दोबारा attempt करता है। आपको कोई interruption दिखाई नहीं देता। | -| Codex | Same agent loop, immediately | Claude के समान। | -| GitHub Copilot CLI | Same agent loop, immediately | Claude के समान (Copilot के `{decision:"block", reason}` retry channel का उपयोग करता है — Copilot CLI 1.0.41 के विरुद्ध empirically verified)। | -| Cursor Agent | Same agent loop, immediately | Claude के समान (Cursor के `{followup_message}` channel का उपयोग करता है — `loop_limit` द्वारा capped, default 5 retries)। | -| Gemini CLI | Same agent loop, immediately | Claude के समान (Gemini के `{decision:"block", reason}` channel का उपयोग करता है `AfterAgent` पर)। | -| OpenCode | Same agent loop, immediately | Claude के समान (OpenCode के `client.session.prompt(...)` SDK call का उपयोग करता है `hookSpecificOutput.additionalContext` के through routed)। | -| **Pi (pi-coding-agent)** | **Next user turn** | **Pi visibly stops** जब gate fires — इसका agent loop exit होता है और आपको prompt में वापस किया जाता है। Gate फिर next time fires जब आप एक prompt submit करते हैं: failproofai एक `MANDATORY ACTION REQUIRED` directive को उस turn के system prompt में prepend करता है, LLM को instruct करते हुए workflow step (commit, push, आदि) को complete करने के लिए आप जो माँगते हैं उससे पहले। | +| Claude Code | एक ही एजेंट लूप, तुरंत | Claude काम करना जारी रखता है — समस्या को ठीक करता है, फिर फिर से समाप्त करने का प्रयास करता है। आपको कोई रुकावट दिखाई नहीं देती। | +| Codex | एक ही एजेंट लूप, तुरंत | Claude के समान। | +| GitHub Copilot CLI | एक ही एजेंट लूप, तुरंत | Claude के समान (Copilot के `{decision:"block", reason}` रिट्राई चैनल का उपयोग करता है — Copilot CLI 1.0.41 के विरुद्ध अनुभवजन्य रूप से सत्यापित)। | +| Cursor Agent | एक ही एजेंट लूप, तुरंत | Claude के समान (Cursor के `{followup_message}` चैनल का उपयोग करता है — `loop_limit` से सीमित, डिफ़ॉल्ट 5 पुनः प्रयास)। | +| OpenCode | एक ही एजेंट लूप, तुरंत | Claude के समान (`hookSpecificOutput.additionalContext` के माध्यम से OpenCode के `client.session.prompt(...)` SDK कॉल का उपयोग करता है)। | +| **Pi (pi-coding-agent)** | **अगला उपयोगकर्ता मोड़** | **Pi दृश्य रूप से रुक जाता है** जब गेट सक्रिय होता है — इसका एजेंट लूप बाहर निकलता है और आप प्रॉम्प्ट पर वापस आते हैं। गेट फिर अगली बार सक्रिय होता है जब आप एक प्रॉम्प्ट जमा करते हैं: failproofai एक `MANDATORY ACTION REQUIRED` निर्देश को उस मोड़ के सिस्टम प्रॉम्प्ट के सामने जोड़ता है, LLM को वर्कफ़्लो चरण को पूरा करने के लिए निर्देश देता है (कमिट, पुश, आदि) जो भी आप चाहते हैं वह करने से पहले। | -**Pi limitation.** Pi के `AgentEndEvent` (Claude के `Stop` hook के upstream equivalent) के पास कोई Result type नहीं है — जब यह fires, Pi के agent loop पहले ही exit हो चुका है। Pi को Claude / Copilot / Cursor / Gemini / OpenCode के तरीके से same loop को retry के लिए force नहीं किया जा सकता। failproofai gate को Pi के `before_agent_start` event में shift करता है (जो next user prompt के बाद fires) ताकि workflow check अभी भी enforce हो, बस next turn पर current के बजाय। +**Pi सीमा।** Pi के `AgentEndEvent` (Claude के `Stop` हुक के समान अपस्ट्रीम) का कोई Result प्रकार नहीं है — जब तक यह सक्रिय होता है, Pi का एजेंट लूप पहले से ही बाहर निकल चुका होता है। Claude / Copilot / Cursor / OpenCode की तरह Pi को समान लूप को फिर से करने के लिए बाध्य नहीं किया जा सकता। failproofai गेट को Pi के `before_agent_start` ईवेंट में स्थानांतरित करता है (जो अगले उपयोगकर्ता प्रॉम्प्ट के बाद सक्रिय होता है) ताकि वर्कफ़्लो जांच अभी भी वर्तमान के बजाय अगले मोड़ पर लागू हो। -**इसका व्यावहारिक मतलब क्या है:** +**व्यवहार में इसका मतलब क्या है:** -- Pi stop करने के बाद, deny reason को in-memory में Pi session id द्वारा keyed capture किया जाता है। बिल्कुल next prompt आप same Pi process में submit करते हैं drains it: LLM को अपने system prompt के top में `MANDATORY ACTION REQUIRED` directive दिखाई देता है, commit करता है (या push / PR खोलता है / CI wait करता है), और फिर ही आपके request के साथ continue करता है। Captured deny reason एक one-shot है — एक बार drain होने के बाद, gate clear है। -- Gate Pi के process lifetime द्वारा bounded है। यदि आप Pi को `Ctrl+C` करते हैं या turns के बीच quit करते हैं, in-memory entry process के साथ drop हो जाता है और gate miss हो जाता है। Claude, Copilot, Cursor, Gemini, और OpenCode के पास same bound है (एजेंट को kill करो और gate miss हो जाता है) — Pi बस इसे अधिक visible बनाता है क्योंकि एजेंट visibly exit होता है gate firing से पहले। -- Pending deny भी `session_shutdown` पर किसी भी कारण के लिए clear किया जाता है (`new` / `resume` / `fork` / `quit`), तो prior session से एक stale gate same Pi process में started fresh session में leak नहीं हो सकता। +- Pi बंद होने के बाद, अस्वीकार का कारण Pi सत्र ID द्वारा कुंजीकृत मेमोरी में कैप्चर किया जाता है। अगला प्रॉम्प्ट जो आप उसी Pi प्रक्रिया में जमा करते हैं, इसे निकालता है: LLM को अपने सिस्टम प्रॉम्प्ट के शीर्ष पर `MANDATORY ACTION REQUIRED` निर्देश दिखाई देता है, कमिट करने के लिए (या पुश / PR खोलना / CI के लिए प्रतीक्षा करना) और फिर आपके अनुरोध के साथ आगे बढ़ना। कैप्चर किया गया अस्वीकार कारण एक-शॉट है — एक बार निकाल दिया गया, गेट स्पष्ट है। +- गेट Pi की प्रक्रिया जीवनकाल द्वारा बंधा हुआ है। यदि आप Pi को `Ctrl+C` करते हैं या मोड़ के बीच बाहर निकलते हैं, तो प्रक्रिया के साथ मेमोरी प्रविष्टि को छोड़ दिया जाता है और गेट को मिस किया जाता है। Claude, Copilot, Cursor, और OpenCode के पास समान बंधन है (एजेंट को मार दें और गेट को मिस किया जाता है) — Pi इसे अधिक दृश्यमान बनाता है क्योंकि एजेंट दृश्य रूप से बाहर निकलता है इससे पहले गेट सक्रिय होता है। +- एक pending deny भी `session_shutdown` पर किसी भी कारण (`new` / `resume` / `fork` / `quit`) के लिए साफ़ किया जाता है, ताकि एक पूर्व सत्र से एक पुरानी गेट उसी Pi प्रक्रिया में शुरू किए गए एक ताजा सत्र में लीक न हो सके। -यदि आपको Claude-style same-loop retry चाहिए, run अपनी `Stop` नीतियों के अंतर्गत किसी और छः supported CLIs के। हम Pi upstream को track कर रहे हैं एक future Result type के लिए `AgentEndEvent` पर जो हमें इस gap को close करने देगा। +यदि आपको Claude-शैली समान-लूप रिट्राई की आवश्यकता है, तो अपनी `Stop` नीतियों को अन्य पाँच समर्थित CLIs में से किसी एक के तहत चलाएं। हम Pi अपस्ट्रीम को ट्रैक कर रहे हैं एक भविष्य के Result प्रकार के लिए जो हमें इस अंतर को बंद करने देगा `AgentEndEvent` पर। ### `require-commit-before-stop` **ईवेंट:** Stop -**डिफ़ॉल्ट:** Stopping को deny करता है जब uncommitted changes हों (modified, staged, या untracked files)। Informational message return करता है जब working directory clean हो। +**डिफ़ॉल्ट:** बिना कमिट किए गए परिवर्तन (संशोधित, स्टेज किए गए, या अन-ट्रैक किए गए फ़ाइलें) होने पर रुकने को अस्वीकार करता है। कार्य निर्देशिका साफ़ होने पर एक सूचनात्मक संदेश देता है। कोई पैरामीटर नहीं। @@ -741,13 +739,13 @@ Stop enforcement सातों supported CLIs में थोड़ा अल ### `require-push-before-stop` **ईवेंट:** Stop -**डिफ़ॉल्ट:** Stopping को deny करता है जब unpushed commits हों या जब current branch के पास कोई remote tracking branch नहीं हो। Suggest करता है `git push -u` tracking branch create करने के लिए यदि आवश्यक हो। Fails open यदि कोई remote configured नहीं है। +**डिफ़ॉल्ट:** अप्रयुक्त कमिट होने पर या जब वर्तमान शाखा के पास कोई रिमोट ट्रैकिंग शाखा नहीं है तो रुकने को अस्वीकार करता है। आवश्यकता पड़ने पर ट्रैकिंग शाखा बनाने के लिए `git push -u` का सुझाव देता है। कोई रिमोट कॉन्फ़िगर न होने पर fail open होता है। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | Remote name जिसे push करें। | +| `remote` | `string` | `"origin"` | पुश करने के लिए रिमोट नाम। | **उदाहरण:** @@ -766,13 +764,13 @@ Stop enforcement सातों supported CLIs में थोड़ा अल ### `require-pr-before-stop` **ईवेंट:** Stop -**डिफ़ॉल्ट:** Stopping को deny करता है जब current branch के लिए कोई pull request exist न हो, या जब existing PR merge किए बिना closed हो। Instruct करता है Claude को `gh pr create` के साथ PR create करने के लिए। जब PR **merged** हो, नीति allow करती है (काम ship हो गया है) और message hint देता है branch को switch करने के लिए (`git checkout main && git pull`)। +**डिफ़ॉल्ट:** जब वर्तमान शाखा के लिए कोई pull request मौजूद नहीं है, या जब मौजूदा PR बिना मर्ज किए बंद है, तो रुकने को अस्वीकार करता है। Claude को `gh pr create` के साथ एक PR बनाने के लिए निर्देश देता है। जब PR **मर्ज** किया जाता है, तो नीति की अनुमति देती है (काम शिप हो गया है) और संदेश शाखा को स्विच करने का सुझाव देता है (`git checkout main && git pull`)। कोई पैरामीटर नहीं। -इस नीति के लिए [GitHub CLI](https://cli.github.com/) (`gh`) को installed और authenticated होना आवश्यक है। -एक personal access token के साथ `gh auth login` चलाएँ जिसके पास `repo` scope हो pull requests में read access के लिए। यदि `gh` installed नहीं है या authenticated नहीं है, तो नीति fail open होती है और Claude को reason report करती है। +इस नीति को [GitHub CLI](https://cli.github.com/) (`gh`) को स्थापित और प्रमाणित करने की आवश्यकता है। +`gh auth login` को एक व्यक्तिगत एक्सेस टोकन के साथ चलाएं जिसमें pull requests के लिए पढ़ने की एक्सेस के लिए `repo` दायरा है। यदि `gh` स्थापित नहीं है या प्रमाणित नहीं है, तो नीति fail open होती है और कारण की रिपोर्ट करती है। --- @@ -780,21 +778,21 @@ Stop enforcement सातों supported CLIs में थोड़ा अल ### `require-no-conflicts-before-stop` **ईवेंट:** Stop -**डिफ़ॉल्ट:** Stopping को deny करता है जब current branch base branch में cleanly merge न हो सकता हो। नीति पहले confirm करती है कि एक `OPEN` PR GitHub पर branch के लिए exist करता है — बिना उसके, कोई merge target नहीं है enforce करने के लिए, तो पूरी नीति short-circuit करके allow होती है। एक बार `OPEN` PR confirm होने के बाद, दो independent probes चलते हैं: +**डिफ़ॉल्ट:** जब वर्तमान शाखा मूल शाखा में साफ़-साफ़ मर्ज नहीं कर सकती तो रुकने को अस्वीकार करता है। नीति पहले GitHub पर शाखा के लिए एक `OPEN` PR की पुष्टि करती है — इसके बिना, कोई मर्ज लक्ष्य नहीं है लागू करने के लिए, तो पूरी नीति अनुमति देने के लिए short-circuit करता है। एक `OPEN` PR की पुष्टि हो जाने के बाद, दो स्वतंत्र जांचें चलाई जाती हैं: -1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`। Conflict पर, deny message conflicted files को name करता है ताकि Claude को पता चले कि क्या resolve करना है। -2. **GitHub** — `gh pr view --json mergeable,state` result को reuse करता है पहले से ही precheck में fetch किया गया। Conflicts को catch करता है जो एक stale local `origin/` को miss करेगा (उदाहरण के लिए कोई last fetch के बाद `main` पर एक conflicting PR land करता है)। एक `CONFLICTING` result deny करता है। एक `UNKNOWN` result भी deny करता है और Claude को instruct करता है ~10 seconds wait करने और re-check करने के लिए stop attempt करने से पहले — यह false negatives को रोकता है जबकि GitHub recompute करता है। +1. **स्थानीय** — `git merge-tree --write-tree --name-only origin/ HEAD`। conflict पर, अस्वीकार संदेश conflicted फ़ाइलों का नाम देता है ताकि Claude को पता हो कि सटीक रूप से क्या हल करना है। +2. **GitHub** — पहले से precheck में fetch किए गए `gh pr view --json mergeable,state` परिणाम का पुन: उपयोग करता है। उन conflicts को पकड़ता है जो एक पुरानी स्थानीय `origin/` को मिस करती है (जैसे कोई व्यक्ति `main` पर एक conflicting PR लैंड करता है पिछले fetch के बाद से)। एक `CONFLICTING` परिणाम अस्वीकार करता है। एक `UNKNOWN` परिणाम भी अस्वीकार करता है और Claude को ~10 सेकंड प्रतीक्षा करने और फिर से जांचने के लिए निर्देश देता है — यह false negatives को रोकते हुए Recompute को रोकता है। -Entirely skip (allow) करता है जब: `gh` installed नहीं है, branch के लिए कोई PR exist नहीं है, PR की state `OPEN` नहीं है (उदाहरण के लिए `MERGED`, `CLOSED`), या `gh pr view` unparseable output return करता है। भी fail open करता है जब `origin/` locally missing है या जब कोई commits base से ahead नहीं हैं — वे Layer 1 fall-throughs अभी भी cached PR mergeability को consult करते हैं allow करने से पहले। +छोड़ता है पूरी तरह से (allows) जब: `gh` स्थापित नहीं है, शाखा के लिए कोई PR नहीं है, PR की स्थिति `OPEN` नहीं है (जैसे `MERGED`, `CLOSED`), या `gh pr view` अपार्सेबल आउटपुट देता है। स्थानीय रूप से `origin/` लुप्त होने पर या जब कोई commits आगे नहीं हैं तो fail open भी करता है — वे Layer 1 fall-throughs अभी भी अनुमति देने से पहले cached PR mergeability से परामर्श लेते हैं। **पैरामीटर:** | पैरामीटर | प्रकार | डिफ़ॉल्ट | विवरण | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Base branch जिसके विरुद्ध conflicts को check करें। | +| `baseBranch` | `string` | `"main"` | conflicts के लिए जांचने के लिए मूल शाखा। | -GitHub CLI (`gh`) इस नीति के लिए आवश्यक है। नीति `gh pr view` का उपयोग करता है confirm करने के लिए कि branch के लिए एक `OPEN` PR exist करता है किसी भी conflict probe को चलाने से पहले — बिना `gh` के, नीति short-circuit करके allow करती है। Pull requests में read access के लिए `repo` scope के साथ personal access token के साथ `gh auth login` चलाएँ। +इस नीति के लिए GitHub CLI (`gh`) की आवश्यकता है। नीति कोई conflict जांच चलाने से पहले एक `OPEN` PR के अस्तित्व की पुष्टि करने के लिए `gh pr view` का उपयोग करता है — `gh` के बिना, नीति allow करने के लिए short-circuit करता है। Pull requests के लिए पढ़ने की एक्सेस के लिए `repo` दायरे के साथ एक व्यक्तिगत एक्सेस टोकन के साथ `gh auth login` चलाएं। --- @@ -802,30 +800,19 @@ GitHub CLI (`gh`) इस नीति के लिए आवश्यक है ### `require-ci-green-before-stop` **ईवेंट:** Stop -**डिफ़ॉल्ट:** Stopping को deny करता है जब CI checks failing या अभी चल रही हों current branch पर। दोनों GitHub Actions workflow runs और third-party bot checks को check करता है (उदाहरण के लिए CodeRabbit, SonarCloud, Codecov)। `skipped`, `cancelled`, और `neutral` conclusions को non-failing के रूप में treat करता है (latter उदाहरण के लिए Socket Security alerts को outside contributor PRs पर cover करता है, जहाँ app intentionally neutral report करता है success/failure के बजाय)। Informational message return करता है जब सभी checks pass करते हैं। +**डिफ़ॉल्ट:** जब CI checks विफल हो रहे हों या अभी भी वर्तमान शाखा पर चल रहे हों तो रुकने को अस्वीकार करता है। GitHub Actions वर्कफ़्लो चलाएं और third-party बॉट checks दोनों को जांचता है (जैसे CodeRabbit, SonarCloud, Codecov)। `skipped`, `cancelled`, और `neutral` निष्कर्षों को non-failing के रूप में मानता है (बाद वाला उदाहरण के लिए Socket Security alerts बाहरी contributor PRs पर कवर करता है, जहां ऐप intentionally success/failure के बजाय neutral रिपोर्ट करता है)। सभी checks पास होने पर एक सूचनात्मक संदेश देता है। कोई पैरामीटर नहीं। -यह नीति [GitHub CLI](https://cli.github.com/) (`gh`) को installed और authenticated होना आवश्यक करती है। -Actions workflow runs और Checks API में read access के लिए `repo` scope के साथ personal access token के साथ `gh auth login` चलाएँ। यदि `gh` installed नहीं है या authenticated नहीं है, तो नीति fail open होती है और Claude को reason report करती है। +इस नीति को [GitHub CLI](https://cli.github.com/) (`gh`) को स्थापित और प्रमाणित करने की आवश्यकता है। +Actions वर्कफ़्लो चलाता है और Checks API के लिए पढ़ने की एक्सेस के लिए `repo` दायरे के साथ एक व्यक्तिगत एक्सेस टोकन के साथ `gh auth login` चलाएं। यदि `gh` स्थापित नहीं है या प्रमाणित नहीं है, तो नीति fail open होती है और कारण की रिपोर्ट करती है। --- --- -## व्यक्तिगत नीतियों को disable करना - -अपने कॉन्फ़िग में `enabledPolicies` से एक विशिष्ट नीति को remove करें, या dashboard के Policies tab में इसे toggle off करें। - -```json -{ - "enabledPolicies": [ - "block-rm-rf", - "sanitize-api-keys" - ] -} -``` +## व्यक्तिगत नीतियों को अक्षम करना -नीतियाँ जो `enabledPolicies` में listed नहीं हैं run नहीं होती, भले ही `policyParams` entries उनके लिए exist करें। \ No newline at end of file +अपने कॉन्फ़िगरेशन में `enabledPolicies` से एक विशिष्ट नीति को हटाएं, या डैशबोर्ड के नीति टैब में इसे बंद करें \ No newline at end of file diff --git a/docs/hi/cli/audit.mdx b/docs/hi/cli/audit.mdx index 8bbfbf96..97ddb64a 100644 --- a/docs/hi/cli/audit.mdx +++ b/docs/hi/cli/audit.mdx @@ -1,19 +1,18 @@ --- ---- -title: गत सत्रों का ऑडिट (beta) -description: "पिछले ट्रांसक्रिप्ट्स में एजेंट द्वारा कितनी बार अपव्यय या जोखिम भरे काम किए गए, इसकी गणना करें" +title: पिछले सत्रों का ऑडिट करें (beta) +description: "पिछले ट्रांसक्रिप्ट में एजेंट ने कितनी बार बेकार या जोखिम भरे काम किए, यह गिनें" --- - **बीटा फीचर।** ऑडिट बीटा के रूप में भेजा जा रहा है जबकि हम प्रारंभिक फीडबैक एकत्र कर रहे हैं। - डिटेक्टर कैटलॉग और रिपोर्ट फॉर्मेट अगले स्थिर संस्करण से पहले बदल सकते हैं। यदि कुछ गलत लगे तो कृपया एक issue खोलें। + **बीटा फीचर।** ऑडिट बीटा के रूप में शिप होता है जबकि हम शुरुआती फीडबैक एकत्र करते हैं। + अगली स्थिर रिलीज़ से पहले डिटेक्टर कैटलॉग और रिपोर्ट फॉर्मेट बदल सकते हैं। यदि कुछ गलत दिखे तो कृपया एक issue खोलें। -ऑडिट आपके पिछले एजेंट-CLI ट्रांसक्रिप्ट्स को failproofai की policy इंजन के माध्यम से फिर से चलाता है और **`/audit` डैशबोर्ड पेज** पर एक साझा करने योग्य, विजुअल रिपोर्ट प्रस्तुत करता है — आपके एजेंट की आर्केटाइप, एक 0–100 स्कोर, और बिल्कुल यह कि कौन-सी policies क्या पकड़ी होती। +ऑडिट आपके पिछले एजेंट-CLI ट्रांसक्रिप्ट को failproofai की पॉलिसी इंजन के माध्यम से दोबारा चलाता है और **`/audit` डैशबोर्ड पेज** पर एक शेयरेबल, विजुअल रिपोर्ट रेंडर करता है — आपके एजेंट का आर्कटाइप, 0–100 स्कोर, और बिल्कुल कौन सी पॉलिसीज़ क्या पकड़ती। ## इसे चलाएं -तीन तरीके हैं — सभी एक ही `/audit` रिपोर्ट पर पहुंचते हैं। +तीन तरीके — सभी एक ही `/audit` रिपोर्ट पर पहुंचते हैं। @@ -33,10 +32,10 @@ failproofai - `npx -y failproofai audit` failproofai को फेच करता है, स्कैन चलाता है, और आपके लिए डैशबोर्ड खोलता है — पहले कुछ इंस्टॉल करने की जरूरत नहीं। + `npx -y failproofai audit` failproofai को फेच करता है, स्कैन चलाता है, और आपके लिए डैशबोर्ड खोलता है — पहले कुछ भी इंस्टॉल करने की जरूरत नहीं। - `failproofai audit` आपके टर्मिनल में स्कैन चलाता है, फिर समाप्त होने पर `localhost:8020/audit` को स्वचालित रूप से खोलता है। + `failproofai audit` आपके टर्मिनल में स्कैन चलाता है, फिर जब वह पूरा हो तो `localhost:8020/audit` को स्वचालित रूप से खोलता है। `failproofai` चलाएं और navbar में **Audit** पर क्लिक करें (Policies और Projects के बीच), या सीधे `/audit` खोलें। @@ -44,45 +43,45 @@ failproofai - उपयोग देखने के लिए `failproofai audit -h` (या `--help`) चलाएं। ऑडिट **पूरी तरह ऑफलाइन** चलता है — कोई खाता या नेटवर्क आवश्यक नहीं — और डैशबोर्ड तब तक सेवा देता रहता है जब तक आप इसे `Ctrl+C` से रोक न दें। + उपयोग देखने के लिए `failproofai audit -h` (या `--help`) चलाएं। ऑडिट **पूरी तरह ऑफलाइन** चलता है — कोई अकाउंट या नेटवर्क आवश्यक नहीं — और डैशबोर्ड तब तक सेवा देता रहता है जब तक आप इसे `Ctrl+C` से बंद न करें। -डैशबोर्ड इस मशीन पर पिछले एजेंट CLI ट्रांसक्रिप्ट्स को स्कैन करता है (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) और रिपोर्ट करता है कि एजेंट ने कितनी बार ऐसी चीजें कीं जिन्हें रोकने के लिए failproofai बनाया गया है — env-var चेक, force push, अनावश्यक `cd ` प्रिफिक्स, sleep-polling लूप, अभी-अभी edited फाइलें दोबारा पढ़ना, और अन्य। +डैशबोर्ड इस मशीन पर पिछले एजेंट CLI ट्रांसक्रिप्ट स्कैन करता है (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) और रिपोर्ट करता है कि एजेंट ने कितनी बार failproofai को रोकने के लिए बनाई गई चीजें कीं — env-var चेक, force pushes, बेकार `cd ` प्रीफिक्स, sleep-polling लूप्स, अभी-अभी एडिट की गई फाइलें दोबारा पढ़ना, और बहुत कुछ। -प्रत्येक ट्रांसक्रिप्ट के लिए, हर tool-use इवेंट 39 builtin policies के माध्यम से **और** 8 audit-only डिटेक्टर्स के माध्यम से फिर से चलाया जाता है जो ऐसे पैटर्न को पकड़ते हैं जो अभी तक runtime policies द्वारा कवर नहीं हैं। गिनती सभी सत्रों में प्रति policy/डिटेक्टर एकत्र की जाती है। +प्रत्येक ट्रांसक्रिप्ट के लिए, हर tool-use इवेंट को 39 बिल्टइन पॉलिसीज़ **और** 8 ऑडिट-केवल डिटेक्टर्स के माध्यम से दोबारा चलाया जाता है जो ऐसे पैटर्न पकड़ते हैं जो अभी तक रनटाइम पॉलिसीज़ द्वारा कवर नहीं हैं। गणनाएं सभी सत्रों में प्रति पॉलिसी / डिटेक्टर एकत्र की जाती हैं। -## आप क्या पाते हैं +## आपको क्या मिलता है -`/audit` पेज एक एकल-स्क्रीन, साझा करने योग्य **पोस्टर** है जिसके बाद चार नीचे-फोल्ड अनुभाग हैं: +`/audit` पेज एक सिंगल-स्क्रीन, शेयरेबल **पोस्टर** है जिसके बाद चार fold-के-नीचे सेक्शन हैं: -1. **पोस्टर** — एक नजर में आपके एजेंट की पहचान: इसकी **archetype** (8 में से एक — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), इसके persona keywords, वह archetype कितनी दुर्लभ है, और एक **0–100 स्कोर** with a tier band (`S` से `bottom tier`)। साझा करने के लिए बनाया गया — X या LinkedIn पर पोस्ट करें, या इसे PNG के रूप में डाउनलोड करें। -2. **`// strengths`** — स्कैन से वास्तविक संख्याओं के रूप में आपका एजेंट पहले से क्या अच्छा करता है (जैसे clean-tool-call %, `0` push-to-main प्रयास), केवल तब दिखाया जाता है जब संबंधित policy का स्वच्छ रिकॉर्ड हो। -3. **`// quirks`** — जो फिसल गया: failproofai के पकड़े गए व्यवहारों की एक ranked तालिका — *यह कब* अंतिम बार हुआ, *क्या फिसल गया* (और जो builtin इसे ब्लॉक कर देता), इसकी *severity*, और यह कितनी बार *देखा गया* (`new` / `recurring` / `N× seen`)। -4. **`// how to improve`** — निर्धारित फिक्स सूची: प्रति policy एक पंक्ति copy-paste `failproofai policy add ` के साथ, प्लस एक **install all** बटन जो हर recommendation को एक ही समय में सक्षम करता है और आपका **projected score** दिखाता है यदि आप करें। -5. **`// come back better`** — आदत बनाएं: एक re-audit ईमेल **reminder** सेट करें (`3d` / `7d` / `14d` / `30d`) या अभी फिर से ऑडिट करें, और **एक मित्र को आमंत्रित करें** अपना स्वयं का ऑडिट चलाने के लिए (failproof.ai से भेजा जाता है, आपको Cc किया जाता है)। Reminders और invites को साइन-इन की आवश्यकता है — [`failproofai auth`](/hi/cli/auth) देखें। +1. **पोस्टर** — आपके एजेंट की पहचान एक नज़र में: इसका **आर्कटाइप** (8 में से एक — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), इसके व्यक्तित्व कीवर्ड, वह आर्कटाइप कितना दुर्लभ है, और एक **0–100 स्कोर** टियर बैंड के साथ (`S` से `bottom tier`)। शेयर करने के लिए बनाया गया — X या LinkedIn पर पोस्ट करें, या इसे PNG के रूप में डाउनलोड करें। +2. **`// strengths`** — आपका एजेंट पहले से क्या अच्छा करता है, स्कैन से वास्तविक संख्याओं के रूप में (जैसे clean-tool-call %, `0` push-to-main प्रयास), केवल जहां प्रासंगिक पॉलिसी का एक स्वच्छ रिकॉर्ड है। +3. **`// quirks`** — जो फिसल गया: failproofai द्वारा पकड़े जाने वाले व्यवहारों की एक रैंक की गई टेबल — *कब* यह आखिरी बार हुआ, *क्या फिसल गया* (और बिल्टइन जो इसे ब्लॉक करता), इसकी *गंभीरता*, और यह कितनी बार *दिखा* (`new` / `recurring` / `N× seen`)। +4. **`// how to improve`** — निर्धारित फिक्स सूची: प्रति पॉलिसी एक पंक्ति कॉपी-पेस्ट `failproofai policy add ` के साथ, साथ ही एक **install all** बटन जो हर सिफारिश को एक बार में सक्षम करता है और आपका **अनुमानित स्कोर** दिखाता है यदि आप ऐसा करते। +5. **`// come back better`** — आदत बनाएं: एक फिर-से-ऑडिट ईमेल **reminder** सेट करें (`3d` / `7d` / `14d` / `30d`) या अभी फिर-से-ऑडिट करें, और **एक दोस्त को आमंत्रित करें** अपना खुद का ऑडिट चलाने के लिए (failproof.ai से भेजा गया, आपको Cc किया गया)। Reminders और invites के लिए साइन-इन आवश्यक है — [`failproofai auth`](/hi/cli/auth) देखें। -## Audit-only डिटेक्टर्स +## ऑडिट-केवल डिटेक्टर्स -ये "stupid behavior" पैटर्न को डिटेक्ट करते हैं जो (अभी तक) रीयल टाइम में enforce नहीं किए जाते हैं। वे केवल ऑडिट के दौरान चलते हैं और कभी live tool call को ब्लॉक नहीं करते हैं। +ये "स्टूपिड बिहेवियर" पैटर्न डिटेक्ट करते हैं जो (अभी तक) रीयल टाइम में लागू नहीं हैं। ये केवल ऑडिट के दौरान चलते हैं और कभी भी लाइव tool call को ब्लॉक नहीं करते। -| डिटेक्टर | यह क्या गिनता है | +| डिटेक्टर | क्या गिनता है | |---|---| -| `redundant-cd-cwd` | `cd && …` से शुरू होने वाली Bash commands भले ही commands पहले से ही `cwd` में चलती हों। | -| `prefer-edit-over-read-cat` | एक एकल source फाइल पर `cat`/`head`/`tail`/`less`/`more` — `Read` tool का उपयोग करें। | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` in-place edits — `Edit` tool का उपयोग करें। | -| `prefer-write-over-heredoc` | फाइलें लिखने के लिए Heredoc / multi-line `echo > file` — `Write` tool का उपयोग करें। | -| `sleep-polling-loop` | लंबा `sleep N` (≥ 30s) या `while …; sleep …; done` polling लूप। | -| `find-from-root` | `find /`, `find /home`, `find /usr`, आदि — `cwd` तक स्कोप करें। | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, hooks को छोड़ते हुए। | -| `reread-after-edit` | एक फाइल का `Read` जो उसी सत्र में अभी-अभी `Edit`/`Write` हुई थी। | +| `redundant-cd-cwd` | `cd && …` से शुरू होने वाली Bash कमांड भले ही कमांड पहले से ही `cwd` में चलते हों। | +| `prefer-edit-over-read-cat` | एक एकल सोर्स फाइल पर `cat`/`head`/`tail`/`less`/`more` — Read टूल का उपयोग करें। | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` इन-प्लेस एडिट्स — Edit टूल का उपयोग करें। | +| `prefer-write-over-heredoc` | Heredoc / मल्टी-लाइन `echo > file` फाइलें लिखना — Write टूल का उपयोग करें। | +| `sleep-polling-loop` | लंबे `sleep N` (≥ 30s) या `while …; sleep …; done` पोलिंग लूप्स। | +| `find-from-root` | `find /`, `find /home`, `find /usr`, आदि — `cwd` में scope करें। | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, हुक्स को स्किप करता है। | +| `reread-after-edit` | एक फाइल का `Read` जो अभी-अभी उसी सत्र में `Edit`/`Write` था। | -## कैशेस +## कैश -- **Per-transcript कैश** `~/.failproofai/cache/audit/.json` पर `(mtime, size, engineVersion, detectorVersion)` द्वारा keyed — जब ट्रांसक्रिप्ट या policy/detector कोड बदलता है तो स्वचालित रूप से invalidate होता है। प्रत्येक entry एक `cachedAt` timestamp को **TTL metadata** के रूप में भी स्टोर करता है (कैश key का भाग नहीं); **7 दिन** से पुरानी entries को पढ़ते समय अस्वीकार किया जाता है ताकि लंबे समय तक रहने वाले परिणाम विकसित होने वाले detector intent को पार न करें। -- **Whole-result कैश** `~/.failproofai/audit-dashboard.json` पर (mode 0600)। डैशबोर्ड को re-running के बिना navigation पर तुरंत प्रस्तुत करने देता है। **7-day TTL** के बाद भी पढ़ते समय अस्वीकार किया जाता है — `/audit` तब इसकी empty state में गिरता है और एक fresh run को प्रेरित करता है। रिपोर्ट के नीचे के पास `[ re-audit now ]` पर क्लिक करें refresh के लिए — re-audit `noCache: true` भेजता है, इसलिए यह per-transcript कैश को बाईपास करता है और cached result देने के बजाय हर ट्रांसक्रिप्ट को फिर से स्कैन करता है; run एक sticky top strip के माध्यम से progress स्ट्रीम करता है और success पर परिणाम को जगह में स्वैप करता है (कोई page reload नहीं; एक failed re-audit पिछली रिपोर्ट को रखता है)। +- **प्रति-ट्रांसक्रिप्ट कैश** `~/.failproofai/cache/audit/.json` पर `(mtime, size, engineVersion, detectorVersion)` से key किया गया — स्वचालित रूप से अमान्य होता है जब ट्रांसक्रिप्ट या पॉलिसी/डिटेक्टर कोड बदलता है। प्रत्येक entry में **TTL metadata** के रूप में एक `cachedAt` टाइमस्टैम्प भी होता है (कैश key का हिस्सा नहीं); **7 दिन** से पुरानी entries को read पर खारिज कर दिया जाता है ताकि लंबे समय के परिणाम विकसित होने वाले डिटेक्टर intent को आउटलाइव न करें। +- **संपूर्ण-परिणाम कैश** `~/.failproofai/audit-dashboard.json` पर (mode 0600)। डैशबोर्ड को बिना re-run किए नेविगेशन पर तुरंत रेंडर करने देता है। **7-दिन TTL** के बाद read पर भी खारिज कर दिया जाता है — `/audit` फिर अपनी खाली स्थिति में गिरता है और एक fresh run के लिए प्रेरित करता है। रिपोर्ट के निचले हिस्से के पास `[ re-audit now ]` पर क्लिक करें refresh करने के लिए — re-audit `noCache: true` भेजता है, इसलिए यह प्रति-ट्रांसक्रिप्ट कैश को बायपास करता है और cached result रिटर्न करने के बजाय हर ट्रांसक्रिप्ट को दोबारा स्कैन करता है; run एक sticky top strip के माध्यम से progress स्ट्रीम करता है और success पर परिणाम को जगह में स्वैप करता है (कोई पेज reload नहीं; एक failed re-audit पिछली रिपोर्ट रखता है)। ## नोट्स -- **कोई mutation नहीं।** ऑडिट read-only mode में फिर से चलता है। `warn-repeated-tool-calls` को छोड़ दिया जाता है क्योंकि इसका per-session sidecar अन्यथा modify हो जाएगा। -- **Workflow policies छोड़ दिए जाते हैं।** `require-*-before-stop` policies केवल `Stop` events और live git state के विरुद्ध `execSync` पर fire होती हैं — इनका meaningful "what would have happened in 2025" interpretation नहीं है, इसलिए वे audit counts में दिखाई नहीं देते हैं। -- **Custom policies छोड़ दिए जाते हैं।** User-supplied custom hooks को फिर से चलाया नहीं जाता (वे original session के बाद से बदल सकते हैं)। \ No newline at end of file +- **कोई mutation नहीं।** ऑडिट read-only mode में दोबारा चलाता है। `warn-repeated-tool-calls` को स्किप किया जाता है क्योंकि इसका per-session sidecar अन्यथा संशोधित होता। +- **वर्कफ़्लो पॉलिसीज़ स्किप की गई।** `require-*-before-stop` पॉलिसीज़ केवल `Stop` events और live git state के विरुद्ध `execSync` पर फायर करती हैं — उनका "2025 में क्या हुआ होता" की कोई सार्थक व्याख्या नहीं है, इसलिए ये ऑडिट गणनाओं में दिखाई नहीं देते। +- **कस्टम पॉलिसीज़ स्किप की गई।** यूजर-सप्लाई की गई कस्टम hooks को दोबारा नहीं चलाया जाता (वे मूल सत्र के बाद से बदल सकते हैं)। \ No newline at end of file diff --git a/docs/hi/configuration.mdx b/docs/hi/configuration.mdx index 0f0fae5b..ee914238 100644 --- a/docs/hi/configuration.mdx +++ b/docs/hi/configuration.mdx @@ -1,10 +1,11 @@ --- +--- title: कॉन्फ़िगरेशन description: "कॉन्फ़िग फ़ाइल प्रारूप, तीन-स्कोप सिस्टम, और मर्ज नियम" icon: gear --- -failproofai JSON कॉन्फ़िगरेशन फ़ाइलों का उपयोग करता है यह नियंत्रित करने के लिए कि कौन सी नीतियां सक्रिय हैं, वे कैसे व्यवहार करती हैं, और कहां से कस्टम नीतियां लोड की जाती हैं। कॉन्फ़िगरेशन आपकी टीम के साथ साझा करने के लिए आसान बनाया गया है - इसे अपने रेपो में कमिट करें और हर डेवलपर को एक जैसा एजेंट सेफ्टी नेट मिले। +failproofai JSON कॉन्फ़िगरेशन फ़ाइलों का उपयोग करता है यह नियंत्रित करने के लिए कि कौन सी नीतियां सक्रिय हैं, वे कैसे व्यवहार करती हैं, और कहां से कस्टम नीतियां लोड की जाती हैं। कॉन्फ़िगरेशन को आपकी टीम के साथ साझा करना आसान बनाने के लिए डिज़ाइन किया गया है - इसे अपने रिपो में कमिट करें और हर डेवलपर को एक जैसी एजेंट सुरक्षा मिलेगी। --- @@ -12,41 +13,41 @@ failproofai JSON कॉन्फ़िगरेशन फ़ाइलों क तीन कॉन्फ़िगरेशन स्कोप हैं, जिनका मूल्यांकन प्राथमिकता क्रम में किया जाता है: -| स्कोप | फ़ाइल पाथ | उद्देश्य | +| स्कोप | फ़ाइल पथ | उद्देश्य | |-------|-----------|---------| -| **project** | `.failproofai/policies-config.json` | प्रति-रेपो सेटिंग्स, संस्करण नियंत्रण में कमिट की गई | -| **local** | `.failproofai/policies-config.local.json` | व्यक्तिगत प्रति-रेपो ओवरराइड, gitignored | -| **global** | `~/.failproofai/policies-config.json` | उपयोगकर्ता-स्तरीय डिफ़ॉल्ट सभी प्रोजेक्ट्स में | +| **project** | `.failproofai/policies-config.json` | प्रति-रिपो सेटिंग्स, संस्करण नियंत्रण में कमिट की गई | +| **local** | `.failproofai/policies-config.local.json` | व्यक्तिगत प्रति-रिपो ओवरराइड, gitignored | +| **global** | `~/.failproofai/policies-config.json` | उपयोगकर्ता-स्तर की डिफ़ॉल्ट सेटिंग्स सभी प्रोजेक्ट्स में | -जब failproofai को एक हुक ईवेंट मिलता है, तो यह सभी तीन फ़ाइलों को लोड और मर्ज करता है जो वर्तमान कार्य निर्देशिका के लिए मौजूद हैं। +जब failproofai को कोई हुक इवेंट प्राप्त होता है, तो यह वर्तमान कार्यशील निर्देशिका के लिए मौजूद सभी तीन फ़ाइलों को लोड और मर्ज करता है। ### मर्ज नियम -**`enabledPolicies`** - सभी तीन स्कोप का संघ। कोई भी नीति जो किसी भी स्तर पर सक्षम है, सक्रिय होती है। +**`enabledPolicies`** - सभी तीन स्कोप का संघ। किसी भी स्तर पर सक्षम की गई नीति सक्रिय होती है। ```text project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← deduplicated union +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← डुप्लिकेट-रहित संघ ``` -**`policyParams`** - पहला स्कोप जो किसी दिए गए नीति के लिए पैरामीटर परिभाषित करता है वह पूरी तरह जीत जाता है। नीति के पैरामीटर के मान में कोई गहरा मर्जिंग नहीं होता। +**`policyParams`** - पहला स्कोप जो किसी दी गई नीति के लिए पैरामीटर परिभाषित करता है, पूरी तरह जीत जाता है। नीति के पैरामीटर्स के भीतर मानों का कोई गहरा मर्ज नहीं होता है। ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project wins, global ignored +resolved: { allowPatterns: ["sudo apt-get update"] } ← project जीत जाता है, global को नज़रअंदाज़ किया जाता है ``` ```text -project: (no block-sudo entry) -local: (no block-sudo entry) +project: (कोई block-sudo प्रविष्टि नहीं) +local: (कोई block-sudo प्रविष्टि नहीं) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to global +resolved: { allowPatterns: ["sudo systemctl status"] } ← global में गिरता है ``` **`customPoliciesPath`** - पहला स्कोप जो इसे परिभाषित करता है, जीत जाता है। @@ -102,7 +103,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo प्रकार: `string[]` -सक्षम करने के लिए नीति के नाम की सूची। नाम बिल्कुल `failproofai policies` द्वारा दिखाए गए नीति पहचानकर्ता से मेल खाना चाहिए। संपूर्ण सूची के लिए [बिल्ट-इन पॉलिसीज़](/hi/built-in-policies) देखें। +सक्षम करने के लिए नीति के नामों की सूची। नामों को `failproofai policies` द्वारा दिखाए गए नीति पहचानकर्ताओं से बिल्कुल मेल खाना चाहिए। पूरी सूची के लिए [Built-in Policies](/hi/built-in-policies) देखें। `enabledPolicies` में नहीं होने वाली नीतियां निष्क्रिय होती हैं, भले ही उनके पास `policyParams` में प्रविष्टियां हों। @@ -110,17 +111,17 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo प्रकार: `Record>` -प्रति-नीति पैरामीटर ओवरराइड। बाहरी कुंजी नीति का नाम है; आंतरिक कुंजियां नीति-विशिष्ट हैं। प्रत्येक नीति [बिल्ट-इन पॉलिसीज़](/hi/built-in-policies) में अपने उपलब्ध पैरामीटर को दस्तावेज़ित करती है। +प्रति-नीति पैरामीटर ओवरराइड। बाहरी कुंजी नीति का नाम है; आंतरिक कुंजियां नीति-विशिष्ट हैं। प्रत्येक नीति [Built-in Policies](/hi/built-in-policies) में अपने उपलब्ध पैरामीटर्स का दस्तावेज़ देती है। -यदि किसी नीति के पैरामीटर हैं लेकिन आप उन्हें निर्दिष्ट नहीं करते, तो नीति के बिल्ट-इन डिफ़ॉल्ट का उपयोग किया जाता है। वे उपयोगकर्ता जो `policyParams` को बिल्कुल कॉन्फ़िगर नहीं करते, उन्हें पिछले संस्करणों के समान व्यवहार मिलता है। +यदि किसी नीति के पैरामीटर हैं लेकिन आप उन्हें निर्दिष्ट नहीं करते हैं, तो नीति के बिल्ट-इन डिफ़ॉल्ट का उपयोग किया जाता है। जो उपयोगकर्ता `policyParams` को बिल्कुल कॉन्फ़िगर नहीं करते हैं, उन्हें पिछले संस्करणों के समान व्यवहार मिलता है। -नीति के पैरामीटर ब्लॉक के अंदर अज्ञात कुंजियों को हुक-फायर समय पर चुप्पी से अनदेखा किया जाता है लेकिन जब आप `failproofai policies` चलाते हैं तो चेतावनियों के रूप में फ़्लैग किया जाता है। +नीति के पैरामीटर्स ब्लॉक के अंदर अज्ञात कुंजियों को हुक-फायर समय पर चुप्पी से अनदेखा किया जाता है लेकिन `failproofai policies` चलाने पर चेतावनियों के रूप में झंडे लगाए जाते हैं। #### `hint` (क्रॉस-कटिंग) प्रकार: `string` (वैकल्पिक) -एक संदेश जो जोड़ा जाता है कारण जब कोई नीति `deny` या `instruct` देता है। इसका उपयोग Claude को नीति को संशोधित किए बिना कार्रवाई योग्य निर्देशन देने के लिए करें। +एक संदेश जो कारण में जोड़ा जाता है जब कोई नीति `deny` या `instruct` लौटाती है। इसका उपयोग नीति को स्वयं संशोधित किए बिना Claude को कार्रवाई योग्य मार्गदर्शन देने के लिए करें। किसी भी नीति प्रकार के साथ काम करता है — बिल्ट-इन, कस्टम (`custom/`), प्रोजेक्ट कन्वेंशन (`.failproofai-project/`), या उपयोगकर्ता कन्वेंशन (`.failproofai-user/`)। @@ -128,53 +129,53 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo { "policyParams": { "block-force-push": { - "hint": "Try creating a fresh branch instead." + "hint": "इसके बजाय एक ताज़ी शाखा बनाने का प्रयास करें।" }, "block-sudo": { "allowPatterns": ["sudo apt-get"], - "hint": "Use apt-get directly without sudo." + "hint": "sudo के बिना सीधे apt-get का उपयोग करें।" }, "custom/my-policy": { - "hint": "Ask the user for approval first." + "hint": "पहले उपयोगकर्ता से अनुमति लें।" } } } ``` -जब `block-force-push` अस्वीकार करता है, तो Claude को यह दिखता है: *"Force-pushing is blocked. Try creating a fresh branch instead."* +जब `block-force-push` अस्वीकार करता है, Claude देखता है: *"Force-pushing को ब्लॉक किया गया है। इसके बजाय एक ताज़ी शाखा बनाने का प्रयास करें।"* -गैर-स्ट्रिंग मान और खाली स्ट्रिंग्स को चुप्पी से अनदेखा किया जाता है। यदि `hint` सेट नहीं है, तो व्यवहार अपरिवर्तित रहता है (पश्चविमुखी-संगत)। +गैर-स्ट्रिंग मान और खाली स्ट्रिंग्स को चुप्पी से अनदेखा किया जाता है। यदि `hint` सेट नहीं है, तो व्यवहार अपरिवर्तित रहता है (पिछड़ी अनुकूलता)। ### `customPoliciesPath` -प्रकार: `string` (निरपेक्ष पाथ) +प्रकार: `string` (पूर्ण पथ) -कस्टम हुक नीतियों वाली JavaScript फ़ाइल का पाथ। यह स्वचालित रूप से `failproofai policies --install --custom ` द्वारा सेट किया जाता है (पाथ को निरपेक्ष के लिए हल किया जाता है फिर संग्रहीत किया जाता है)। +कस्टम हुक नीतियों वाली JavaScript फ़ाइल का पथ। यह `failproofai policies --install --custom ` द्वारा स्वचालित रूप से सेट किया जाता है (पथ को संग्रहीत करने से पहले पूर्ण में हल किया जाता है)। -फ़ाइल प्रत्येक हुक ईवेंट पर ताज़ी लोड की जाती है - कोई कैशिंग नहीं है। विस्तार के लिए [कस्टम पॉलिसीज़](/hi/custom-policies) देखें। +फ़ाइल को हर हुक इवेंट पर ताज़ा लोड किया जाता है - कोई कैशिंग नहीं है। विवरण के लिए [Custom Policies](/hi/custom-policies) देखें। ### कन्वेंशन-आधारित नीतियां -स्पष्ट `customPoliciesPath` के अलावा, failproofai स्वचालित रूप से `.failproofai/policies/` निर्देशिकाओं से नीति फ़ाइलों की खोज करता है और लोड करता है: +स्पष्ट `customPoliciesPath` के अलावा, failproofai `.failproofai/policies/` निर्देशिकाओं से नीति फ़ाइलों को स्वचालित रूप से खोजता है और लोड करता है: | स्तर | निर्देशिका | स्कोप | |-------|-----------|-------| -| परियोजना | `.failproofai/policies/` | संस्करण नियंत्रण के माध्यम से टीम के साथ साझा किया गया | -| उपयोगकर्ता | `~/.failproofai/policies/` | व्यक्तिगत, सभी प्रोजेक्ट्स पर लागू | +| Project | `.failproofai/policies/` | संस्करण नियंत्रण के माध्यम से टीम के साथ साझा किया गया | +| User | `~/.failproofai/policies/` | व्यक्तिगत, सभी प्रोजेक्ट्स पर लागू होता है | -**फ़ाइल मिलान:** केवल `*policies.{js,mjs,ts}` से मेल खाने वाली फ़ाइलें लोड की जाती हैं (उदा. `security-policies.mjs`, `workflow-policies.js`)। निर्देशिका में अन्य फ़ाइलें अनदेखी की जाती हैं। +**फ़ाइल मिलान:** केवल `*policies.{js,mjs,ts}` से मेल खाने वाली फ़ाइलें लोड की जाती हैं (उदाहरण के लिए `security-policies.mjs`, `workflow-policies.js`)। निर्देशिका में अन्य फ़ाइलों को अनदेखा किया जाता है। -**कोई कॉन्फ़िग की आवश्यकता नहीं:** कन्वेंशन नीतियों के लिए `policies-config.json` में प्रविष्टियों की आवश्यकता नहीं है। बस निर्देशिका में फ़ाइलें डालें और अगली हुक ईवेंट पर उन्हें चुना जाएगा। +**कोई कॉन्फ़िग आवश्यक नहीं:** कन्वेंशन नीतियों को `policies-config.json` में किसी प्रविष्टि की आवश्यकता नहीं होती है। बस निर्देशिका में फ़ाइलें डालें और वे अगले हुक इवेंट पर उठाई जाती हैं। -**यूनियन लोडिंग:** प्रोजेक्ट और उपयोगकर्ता दोनों कन्वेंशन निर्देशिकाएं स्कैन की जाती हैं। दोनों स्तरों से सभी मेल खाने वाली फ़ाइलें लोड की जाती हैं (`customPoliciesPath` के विपरीत जो पहले-स्कोप-जीत का उपयोग करता है)। +**यूनियन लोडिंग:** प्रोजेक्ट और उपयोगकर्ता दोनों कन्वेंशन निर्देशिकाएं स्कैन की जाती हैं। दोनों स्तरों से सभी मेल खाने वाली फ़ाइलें लोड की जाती हैं (`customPoliciesPath` के विपरीत जो पहला-स्कोप-जीत का उपयोग करता है)। -अधिक विवरण और उदाहरणों के लिए [कस्टम पॉलिसीज़](/hi/custom-policies) देखें। +अधिक विवरण और उदाहरण के लिए [Custom Policies](/hi/custom-policies) देखें। ### `llm` प्रकार: `object` (वैकल्पिक) -उन नीतियों के लिए LLM क्लाइंट कॉन्फ़िगरेशन जो AI कॉल करते हैं। अधिकांश सेटअप के लिए आवश्यक नहीं है। +उन नीतियों के लिए LLM क्लाइंट कॉन्फ़िगरेशन जो AI कॉल करती हैं। अधिकांश सेटअप के लिए आवश्यक नहीं है। ```json { @@ -189,20 +190,24 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← falls through to glo ## CLI से कॉन्फ़िगरेशन प्रबंधित करना -`policies --install` और `policies --uninstall` कमांड आपके एजेंट CLI की हुक सेटिंग्स फ़ाइल (हुक एंट्री पॉइंट) में लिखते हैं, जबकि `policies-config.json` वह फ़ाइल है जिसे आप सीधे प्रबंधित करते हैं। दोनों अलग हैं: - -- **एजेंट CLI सेटिंग्स** — एजेंट को बताता है कि प्रत्येक टूल उपयोग पर `failproofai --hook ` को कॉल करना है: - - **Claude Code**: `~/.claude/settings.json` (उपयोगकर्ता), `/.claude/settings.json` (प्रोजेक्ट), `/.claude/settings.local.json` (लोकल) - - **OpenAI Codex**: `~/.codex/hooks.json` (उपयोगकर्ता), `/.codex/hooks.json` (प्रोजेक्ट) — Codex के पास `local` स्कोप नहीं है - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (उपयोगकर्ता), `/.github/hooks/failproofai.json` (प्रोजेक्ट) — Copilot के पास कोई `local` स्कोप नहीं है। हुक एंट्रीज़ Copilot के OS-keyed `bash`/`powershell` कमांड फ़ील्ड का उपयोग करते हैं `timeoutSec` के साथ; फ़ाइल एक टॉप-लेवल `version: 1` मार्कर ले जाती है। Copilot CLI समर्थन **beta** है जबकि हम `events.jsonl` रिकॉर्ड स्कीमा को सत्यापित करते हैं (जिसे सार्वजनिक दस्तावेज़ निर्दिष्ट नहीं करते) अधिक वास्तविक-दुनिया सत्रों के विरुद्ध। - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (उपयोगकर्ता), `/.cursor/hooks.json` (प्रोजेक्ट) — Cursor के पास कोई `local` स्कोप नहीं है। हुक एंट्रीज़ Claude-shaped `{type, command, timeout}` फॉर्म का उपयोग करते हैं (कोई `bash`/`powershell` विभाजन नहीं), लेकिन camelCase ईवेंट कुंजियों के तहत संग्रहीत (`preToolUse`, `beforeSubmitPrompt`, …) Cursor के [hooks schema](https://cursor.com/docs/hooks) के अनुसार एक फ्लैट ऐरे में; फ़ाइल एक टॉप-लेवल `version: 1` मार्कर ले जाती है। हैंडलर camelCase → PascalCase को `CURSOR_EVENT_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। Cursor Agent समर्थन **beta** है जबकि हम Cursor के ट्रांसक्रिप्ट को सत्यापित करते हैं (सार्वजनिक दस्तावेज़ में निर्दिष्ट नहीं) अधिक वास्तविक-दुनिया इंस्टॉल्स के विरुद्ध। - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (उपयोगकर्ता), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (प्रोजेक्ट) — OpenCode के पास कोई `local` स्कोप नहीं है। अन्य छह CLI के विपरीत, OpenCode के पास **कोई बाहरी-कमांड हुक सिस्टम नहीं है**: यह JS/TS प्लगइन को `opencode.json` में `plugin: []` ऐरे के माध्यम से स्पष्ट रूप से पंजीकृत करके इन-प्रॉसेस लोड करता है (`.opencode/plugins/` से ऑटो-डिस्कवरी **नहीं** है कि प्लगइन opencode v1.14.33 पर कैसे लोड होते हैं)। इंस्टॉल एक छोटा जेनरेटेड प्लगइन शिम छोड़ता है जो failproofai बाइनरी को subprocess-कॉल करता है और बाइनरी के Claude-shape JSON प्रतिक्रिया को प्लगइन शब्दावली में वापस अनुवाद करता है: `throw new Error()` टूल-ईवेंट deny के लिए (टूल कॉल को रद्द करता है), `client.session.prompt(...)` instruct AND के लिए `Stop` / `SubagentStop` deny (deny कारण को अगले उपयोगकर्ता संदेश के रूप में जमा करता है — एकमात्र force-retry चैनल क्योंकि `session.idle` केवल-अधिसूचना है और इससे throw करना एक no-op है), और allow के लिए no-op। शिम both टूल नाम (lowercase → PascalCase `OPENCODE_TOOL_MAP` के माध्यम से) और tool-input arg कुंजियां (camelCase → snake_case `OPENCODE_TOOL_INPUT_MAP` के माध्यम से `Read` / `Write` / `Edit` के लिए, उदा. `filePath` → `file_path`, `oldString` → `old_string`) कैनोनिकलाइज़ करता है बाइनरी में अग्रेषित करने से पहले, इसलिए path-checking builtins जैसे `block-read-outside-cwd`, `block-env-files`, और `block-secrets-write` OpenCode tool कॉल पर अपरिवर्तित रूप से चलते हैं। सत्र opencode के SQLite DB में `~/.local/share/opencode/opencode.db` में रहते हैं; डैशबोर्ड का सत्र दर्शक `opencode db --format json` और `opencode export ` के माध्यम से उन्हें पढ़ता है। OpenCode समर्थन **beta** है जबकि हम संस्करणों में व्यवहार को सत्यापित करते हैं और अधिक वास्तविक-दुनिया सत्रों के विरुद्ध। [OpenCode plugins docs](https://opencode.ai/docs/plugins/) देखें। - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (उपयोगकर्ता), `/.pi/settings.json` (प्रोजेक्ट) — Pi के पास कोई `local` स्कोप नहीं है। Pi स्टार्टअप पर TypeScript extension पैकेज लोड करता है; सेटिंग्स फ़ाइल एक फ्लैट स्ट्रिंग ऐरे `{"packages": ["./relative/path", …]}` है। failproofai एक single packages-array एंट्री लिखता है जो अपनी bundled `pi-extension/` निर्देशिका की ओर इशारा करता है। एक्सटेंशन आंतरिक रूप से Pi के `tool_call` / `user_bash` / `input` / `session_start` ईवेंट्स की सदस्यता लेता है और `failproofai --hook --cli pi` के लिए shell बाहर निकालता है; हैंडलर underscore_lower_snake_case → PascalCase को `PI_EVENT_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। Tool input args को `PI_TOOL_INPUT_MAP` के माध्यम से भी कैनोनिकलाइज़ किया जाता है (Pi के Read / Write / Edit `path` के बजाय `file_path` प्रदान करते हैं; शीर्ष-स्तरीय कुंजी को मैप करना `block-env-files` और `block-secrets-write` को चलने देता है — `block-read-outside-cwd` पहले से ही एक `path` fallback था)। Pi समर्थन **beta** है जबकि Pi का एक्सटेंशन API और session-log लेआउट स्थिर होता है। - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (उपयोगकर्ता), `/.gemini/settings.json` (प्रोजेक्ट) — Gemini के पास कोई `local` स्कोप नहीं है (यह `/etc/gemini-cli/settings.json` पर एक `system` स्कोप दस्तावेज़ित करता है जो failproofai उजागर नहीं करता)। हुक एंट्रीज़ Claude के `{type, command, timeout}` फॉर्म का उपयोग करते हैं Gemini के `{matcher, hooks: [...]}` matcher स्कीमा में लपेटा गया `matcher: "*"` के साथ डिफ़ॉल्ट रूप से। ईवेंट्स PascalCase हैं (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); हैंडलर `GEMINI_EVENT_MAP` के माध्यम से Claude canonical नामों में मैप करता है। टूल नाम snake_case हैं (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — हैंडलर `GEMINI_TOOL_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। नीति मूल्यांकनकर्ता Gemini का फ्लैट `{decision: "deny", reason}` shape (Gemini के "Golden Rule" exit-0 contract के अनुसार पसंद किया जाता है), `{hookSpecificOutput: {hookEventName, additionalContext}}` context injection के लिए BeforeAgent / AfterTool / SessionStart पर, और `{decision: "block", reason}` AfterAgent पर force-retry semantics के लिए उत्सर्जित करता है। Gemini CLI समर्थन **beta** है जबकि हम वास्तविक-दुनिया कवरेज को चौड़ा करते हैं। [Gemini CLI hooks docs](https://geminicli.com/docs/hooks/) देखें। - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**उपयोगकर्ता स्कोप केवल** — Hermes के पास कोई project/local कॉन्फ़िग नहीं है)। Hermes एक Slack/Telegram **गेटवे** है, इसलिए एक इंस्टॉल हर प्लेटफॉर्म (Slack/Telegram/cli/cron) **और** आंतरिक subagents से tool कॉल को इंटरसेप्ट करता है। हुक एंट्रीज़ एक `{command, timeout}` pair (**सेकंड में** timeout) हैं एक `hooks:` map के तहत Hermes के snake_case ईवेंट्स द्वारा keyed (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); हैंडलर ईवेंट्स को `HERMES_EVENT_MAP` के माध्यम से और टूल नाम को `HERMES_TOOL_MAP` के माध्यम से कैनोनिकलाइज़ करता है ताकि बिल्ट-इन नीतियां अपरिवर्तित रूप से चलें। कॉन्फ़िग एक comment-preserving YAML `Document` round-trip के माध्यम से संपादित किया जाता है ताकि ऑपरेटर की अन्य सेटिंग्स जीवित रहें, और install `hooks_auto_accept: true` सेट करता है ताकि headless gateway (कोई TTY नहीं) consent प्रॉम्प्ट के बिना हुक चलाए। मूल्यांकनकर्ता Hermes के `{"decision":"block","reason"}` stdout contract उत्सर्जित करता है (Hermes exit कोड को अनदेखा करता है)। **सीमाएं:** Hermes के पास कोई turn-end `Stop` ईवेंट नहीं है, इसलिए `require-*-before-stop` builtins कभी इसके लिए नहीं चलते (inapplicable, broken नहीं); `instruct` allow-with-logged-note में degrade होता है (कोई additional-context चैनल नहीं); और output-secret redaction (`sanitize-*`) shell-hook contract के ऊपर tool output को rewrite नहीं कर सकता। Hermes **भी** एक offline **audit** स्रोत है — डैशबोर्ड अपने gateway सत्रों को सीधे `~/.hermes/state.db` से पढ़ता है। -- **`policies-config.json`** — failproofai को बताता है कि कौन सी नीतियों का मूल्यांकन करना है और किस पैरामीटर के साथ (सभी एजेंट CLIs में साझा) - -एक विशिष्ट एजेंट को target करने के लिए `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` पास करें (space-separated या repeated किसी भी subset के लिए): +`policies --install` और `policies --uninstall` कमांड आपके एजेंट CLI की हुक सेटिंग्स फ़ाइल (हुक प्रविष्टि बिंदु) में लिखते हैं, जबकि `policies-config.json` वह फ़ाइल है जिसे आप सीधे प्रबंधित करते हैं। ये दोनों अलग हैं: + +- **एजेंट CLI सेटिंग्स** — एजेंट को प्रत्येक टूल उपयोग पर `failproofai --hook ` को कॉल करने के लिए कहता है: + - **Claude Code**: `~/.claude/settings.json` (user), `/.claude/settings.json` (project), `/.claude/settings.local.json` (local) + - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex के पास कोई `local` स्कोप नहीं है + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot के पास कोई `local` स्कोप नहीं है। हुक प्रविष्टियां Copilot के OS-keyed `bash`/`powershell` कमांड फ़ील्ड का उपयोग करती हैं `timeoutSec` के साथ; फ़ाइल शीर्ष-स्तर `version: 1` मार्कर रखती है। Copilot CLI समर्थन **beta** में है जबकि हम `events.jsonl` रिकॉर्ड स्कीमा को सत्यापित करते हैं (जिसे सार्वजनिक दस्तावेज़ निर्दिष्ट नहीं करते)। **VS Code Copilot Chat agent mode (Preview)** हुक कॉन्फ़िग को `.github/hooks/*.json`, `~/.copilot/hooks/*.json`, और `~/.claude/settings.json` से पढ़ता है (`chat.hookFilesLocations` सेटिंग द्वारा शासित) Claude-shaped `{hookSpecificOutput:{permissionDecision:"deny",…}}` अनुबंध का उपयोग करते हुए — वही सटीक पथ जो `copilot` इंटीग्रेशन और `claude` इंटीग्रेशन (`~/.claude/settings.json`) पहले से लिखते हैं, इसलिए `failproofai policies --install --cli copilot` (या `--cli claude`) **VS Code agent mode में पहले से ही कानून लागू करता है** कोई अलग `vscode` इंटीग्रेशन आवश्यक नहीं है (VS Code की खोज लॉग से पुष्टि की गई)। + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor के पास कोई `local` स्कोप नहीं है। हुक प्रविष्टियां Claude-shaped `{type, command, timeout}` फॉर्म का उपयोग करती हैं (कोई `bash`/`powershell` विभाजन नहीं), लेकिन Cursor की [hooks schema](https://cursor.com/docs/hooks) प्रति camelCase event keys (`preToolUse`, `beforeSubmitPrompt`, …) में एक फ्लैट सरणी के तहत संग्रहीत होती हैं; फ़ाइल शीर्ष-स्तर `version: 1` मार्कर रखती है। हैंडलर camelCase → PascalCase को `CURSOR_EVENT_MAP` के माध्यम से विहित करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित फायर हों। Cursor Agent समर्थन **beta** में है जबकि हम Cursor के ट्रांसक्रिप्ट ऑन-डिस्क प्रारूप (सार्वजनिक दस्तावेज़ में निर्दिष्ट नहीं) को अधिक वास्तविक इंस्टॉल के विरुद्ध सत्यापित करते हैं। + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode के पास कोई `local` स्कोप नहीं है। अन्य पांच CLIs के विपरीत, OpenCode के पास **कोई बाहरी-कमांड हुक सिस्टम नहीं है**: यह `opencode.json` में `plugin: []` सरणी के माध्यम से स्पष्ट रूप से पंजीकृत JS/TS प्लगइन को in-process लोड करता है (`.opencode/plugins/` से auto-discovery यह **नहीं** है कि opencode v1.14.33 पर प्लगइन कैसे लोड होते हैं)। Install एक छोटी जनरेट की गई प्लगइन शिम को छोड़ता है जो failproofai बाइनरी को subprocess-कॉल करता है और बाइनरी के Claude-shape JSON प्रतिक्रिया को प्लगइन शब्दार्थ में वापस अनुवाद करता है: tool-event deny के लिए `throw new Error()` (टूल कॉल को रद्द करता है), instruct और `Stop` / `SubagentStop` deny दोनों के लिए `client.session.prompt(...)` (अगले उपयोगकर्ता संदेश के रूप में deny कारण प्रस्तुत करता है — एकमात्र बल-retry चैनल क्योंकि `session.idle` अधिसूचना-केवल है और इससे फेंकना एक नो-ऑप है), और allow के लिए नो-ऑप। शिम टूल नामों (lowercase → PascalCase via `OPENCODE_TOOL_MAP`) और टूल-इनपुट arg keys (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` for `Read` / `Write` / `Edit`, उदाहरण `filePath` → `file_path`, `oldString` → `old_string`) दोनों को विहित करता है बाइनरी को अग्रेषित करने से पहले, इसलिए `block-read-outside-cwd`, `block-env-files`, और `block-secrets-write` जैसी पथ-जांच builtins OpenCode टूल कॉल पर अपरिवर्तित फायर होती हैं। Sessions opencode के SQLite DB में `~/.local/share/opencode/opencode.db` पर रहते हैं; डैशबोर्ड का session viewer उन्हें `opencode db --format json` और `opencode export ` के माध्यम से पढ़ता है। OpenCode समर्थन **beta** में है जबकि हम संस्करणों में व्यवहार और अधिक वास्तविक-विश्व sessions के विरुद्ध सत्यापित करते हैं। [OpenCode plugins docs](https://opencode.ai/docs/plugins/) देखें। + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi के पास कोई `local` स्कोप नहीं है। Pi स्टार्टअप पर TypeScript एक्सटेंशन पैकेज लोड करता है; सेटिंग्स फ़ाइल एक फ्लैट स्ट्रिंग सरणी `{"packages": ["./relative/path", …]}` है। failproofai एक एकल packages-array प्रविष्टि लिखता है जो अपनी bundled `pi-extension/` निर्देशिका की ओर इशारा करती है। एक्सटेंशन आंतरिक रूप से Pi के `tool_call` / `user_bash` / `input` / `session_start` इवेंट्स को subscribe करता है और `failproofai --hook --cli pi` में शेल करता है; हैंडलर underscore_lower_snake_case → PascalCase को `PI_EVENT_MAP` के माध्यम से विहित करता है ताकि मौजूदा बिल्ट-इन नीतियां अपरिवर्तित फायर हों। टूल इनपुट args भी `PI_TOOL_INPUT_MAP` के माध्यम से विहित किए जाते हैं (Pi का Read / Write / Edit `path` के बजाय `file_path` देते हैं; शीर्ष-स्तर कुंजी को मैप करने से `block-env-files` और `block-secrets-write` फायर हो सकते हैं — `block-read-outside-cwd` पहले से ही एक `path` fallback था)। Pi समर्थन **beta** में है जबकि Pi का एक्सटेंशन API और session-log लेआउट स्थिर हो रहा है। + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**केवल user scope** — Hermes के पास कोई project/local config नहीं है)। Hermes एक Slack/Telegram **गेटवे** है, इसलिए एक इंस्टॉल हर प्लेटफॉर्म से टूल कॉल को इंटरसेप्ट करता है (Slack/Telegram/cli/cron) **और** आंतरिक subagents। हुक प्रविष्टियां Hermes के snake_case इवेंट्स (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) द्वारा keyed एक `hooks:` मैप के अंतर्गत एक `{command, timeout}` जोड़ी होती हैं; हैंडलर इवेंट्स को `HERMES_EVENT_MAP` के माध्यम से विहित करता है और टूल नामों को `HERMES_TOOL_MAP` के माध्यम से विहित करता है ताकि बिल्ट-इन नीतियां अपरिवर्तित फायर हों। कॉन्फ़िग को एक comment-preserving YAML `Document` राउंड-ट्रिप के माध्यम से संपादित किया जाता है ताकि ऑपरेटर की अन्य सेटिंग्स survive हों, और install `hooks_auto_accept: true` सेट करता है ताकि headless गेटवे (कोई TTY नहीं) कोई consent prompt के बिना हुक चलाए। evaluator Hermes के `{"decision":"block","reason"}` stdout अनुबंध को emit करता है (Hermes exit codes को अनदेखा करता है)। **सीमाएं:** Hermes के पास कोई turn-end `Stop` इवेंट नहीं है, इसलिए `require-*-before-stop` builtins इसके लिए कभी फायर नहीं होते (लागू नहीं, टूटा नहीं); `instruct` allow-with-logged-note में degrade होता है (कोई अतिरिक्त-context चैनल नहीं); और output-secret redaction (`sanitize-*`) shell-hook अनुबंध पर टूल output को rewrite नहीं कर सकता। Hermes **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके गेटवे sessions को `~/.hermes/state.db` से सीधे पढ़ता है। + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**केवल user scope** — OpenClaw के पास कोई project/local config नहीं है)। Hermes की तरह, OpenClaw एक self-hosted multi-channel **गेटवे** है, इसलिए एक इंस्टॉल हर चैनल और इसके आंतरिक subagents से टूल कॉल को इंटरसेप्ट करता है। Enforcement OpenClaw के **in-process plugin hooks** के माध्यम से चलता है (इसकी फ़ाइल-आधारित आंतरिक hooks observation-only हैं और ब्लॉक नहीं कर सकते), इसलिए — OpenCode/Pi की तरह — failproofai एक स्टैटिक `openclaw-plugin/` पैकेज शिप करता है जो failproofai बाइनरी को async-spawn करता है और verdict का अनुवाद करता है। Install shipped प्लगइन dir को `openclaw.json` के `plugins.load.paths[]` में रजिस्टर करता है और इसे `plugins.entries.failproofai` के अंतर्गत enable करता है (`hooks.allowConversationAccess: true` के साथ, raw-conversation hooks के लिए आवश्यक)। evaluator एक फ्लैट `{permission, reason}` verdict emit करता है और शिम इसे प्रत्येक हुक के native return shape में मैप करता है: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), और `before_agent_finalize → {action:"revise", reason}` (**Stop** — एक real turn-end gate, इसलिए `require-*-before-stop` builtins **OpenClaw पर enforce करते हैं**, Hermes के विपरीत)। इवेंट्स और टूल नामों को `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` के माध्यम से बाइनरी-side पर विहित किया जाता है (`exec→Bash`, `read→Read`, …) ताकि बिल्ट-इन नीतियां अपरिवर्तित फायर हों; शिम किसी भी spawn/parse/timeout error पर open fail करता है। OpenClaw **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके JSONL sessions को `~/.openclaw/agents//sessions/.jsonl` पर पढ़ता है। + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (user), `/.factory/hooks.json` (project) — Factory के पास कोई `local` स्कोप नहीं है। droid एक Claude-style बाहरी-कमांड हुक सिस्टम शिप करता है, लेकिन droid v0.171.0 के विरुद्ध live सत्यापित दो quirks के साथ: (1) इवेंट नामों `hooks.json` के **top level** पर रहते हैं — कोई **`"hooks"` wrapper** नहीं है (droid इसे अस्वीकार करता है); टूल इवेंट्स (`PreToolUse`/`PostToolUse`) `"matcher": "*"` रखते हैं, गैर-टूल इवेंट्स इसे छोड़ते हैं। (2) Deny हुक **exit code 2 + stderr** द्वारा driven है, एक JSON decision द्वारा नहीं — evaluator की `factory` शाखा tool/prompt इवेंट्स के लिए exit 2 लौटाता है और turn-end `Stop` इवेंट पर `{decision:"block", reason}` लौटाता है (droid का एकमात्र बल-retry चैनल)। इवेंट्स पहले से ही PascalCase हैं (कोई event map नहीं) और payload Claude snake_case है; केवल टूल नामों को `FACTORY_TOOL_MAP` के माध्यम से विहित किया जाता है (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …)। Factory **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके on-disk JSONL sessions को `~/.factory/sessions//.jsonl` पर पढ़ता है। + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (user), `/.devin/config.json` (project) — Devin के पास कोई `local` स्कोप नहीं है। Devin एक **pure Claude-clone** है devin v3000.1.27 के विरुद्ध live सत्यापित: यह standard Claude `"hooks"`-wrapper स्कीमा (लिखता है merge-preserving हैं ताकि config फ़ाइल की अन्य कुंजियां — `org_id`, `theme_mode`, … — survive हों), पहले से ही-PascalCase इवेंट नामों (कोई event map नहीं, कोई handler branch नहीं), और एक Claude snake_case stdin payload (कोई normalization नहीं) का उपयोग करता है। evaluator की `devin` शाखा **हर** इवेंट पर exit 0 पर `{"decision":"block","reason"}` JSON के साथ deny करता है (सत्यापित — ब्लॉक ने `--permission-mode dangerous` को override किया); turn-end `Stop` इवेंट पर reason MANDATORY-ACTION बल-retry wording रखता है ताकि `require-*-before-stop` builtins enforce हों। केवल टूल नामों को `DEVIN_TOOL_MAP` के माध्यम से विहित किया जाता है (`exec→Bash`; `tool_input.command` पहले से ही canonical है)। Devin **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके SQLite sessions को `~/.local/share/devin/cli/sessions.db` पर पढ़ता है (प्रत्येक `sessions` row एक real `working_directory` रखता है, इसलिए sessions Devin की तरह project cwd द्वारा group होते हैं)। + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (user), `/.agents/hooks.json` (project) — Antigravity के पास कोई `local` स्कोप नहीं है। Factory/Devin के विपरीत, Antigravity के पास अपना **खुद का** अनुबंध है (Claude-clone नहीं), agy v1.1.2 के विरुद्ध live सत्यापित। `hooks.json` एक **named-hook** स्कीमा का उपयोग करता है: top-level key एक हुक *name* (`"failproofai"`) है जिसका value एक इवेंट→handlers मैप है — टूल इवेंट्स (`PreToolUse`/`PostToolUse`) handlers को `{matcher:"*", hooks:[…]}` में wrap करते हैं, जबकि `PreInvocation`/`Stop` **flat** handler arrays हैं (अन्य named hooks preserve हैं)। stdin payload **camelCase protojson** है (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai इसे policies चलाने से पहले snake_case में normalize करता है, और `run_command` की PascalCase args (`CommandLine`/`Cwd`) को `ANTIGRAVITY_TOOL_INPUT_MAP` के माध्यम से मैप करता है। evaluator की `antigravity` शाखा Antigravity के **खुद के** response shapes का उपयोग करती है: `{decision:"deny", reason}` एक tool/prompt को ब्लॉक करता है (exit 0), `{decision:"continue", reason}` turn-end `Stop` पर loop को फिर से enter करता है (इसलिए `require-*-before-stop` builtins enforce करते हैं), और `{injectSteps:[{ephemeralMessage}]}` `PreInvocation` पर एक instruction को inject करता है (→ `UserPromptSubmit`)। टूल नामों को `ANTIGRAVITY_TOOL_MAP` के माध्यम से विहित किया जाता है (`run_command→Bash`, `view_file→Read`, …)। Antigravity **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके plain-JSONL transcripts को `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` पर पढ़ता है (conversation index `conversation_summaries.db` में)। + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (user), `/.agents/plugins/failproofai/hooks/hooks.json` (project) — Goose के पास कोई `local` स्कोप नहीं है। Enforcement Goose के **hooks** सिस्टम का उपयोग करता है, cross-agent **Open Plugins** spec: installer बस `failproofai` प्लगइन dir को छोड़ता है और Goose स्टार्टअप पर इसे auto-discover करता है (इसे `~/.config/goose/config.yaml` में self-register करते हुए)। `hooks.json` Open Plugins स्कीमा **with** top-level `"hooks"` wrapper का उपयोग करता है, और matcher हर इवेंट पर **omitted** होता है — एक bare `"*"` एक invalid regex है जो कुछ भी match नहीं करता (goose v1.43.0 के विरुद्ध live सत्यापित)। इवेंट नामों पहले से ही PascalCase हैं (कोई event map नहीं); stdin payload `event`/`working_dir` का उपयोग करता है, जिसे हैंडलर `hook_event_name`/`cwd` में normalize करता है। evaluator की `goose` शाखा exit 0 पर `{"decision":"block","reason"}` JSON के साथ deny करती है, **`PreToolUse`** इवेंट पर honored है (goose ≥ v1.37.0 में shipped) — जो शेल टूल के लिए **और delegated subagents के अंदर** फायर होता है, इसलिए यह एकमात्र sufficient deny point है; कोई अन्य हुक error open fail करता है। Goose के पास **कोई `Stop` इवेंट** नहीं है, इसलिए `require-*-before-stop` builtins apply नहीं होते (Hermes की तरह)। टूल नामों को `GOOSE_TOOL_MAP` के माध्यम से विहित किया जाता है (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) और path keys को `GOOSE_TOOL_INPUT_MAP` के माध्यम से (`path`/`source` → `file_path`)। Goose **यह भी** एक offline **audit** स्रोत है — डैशबोर्ड इसके SQLite sessions को `~/.local/share/goose/sessions/sessions.db` पर पढ़ता है (प्रत्येक `sessions` row एक real `working_dir` रखता है, इसलिए Devin की तरह sessions project cwd द्वारा group होते हैं; `--no-session` scratch runs filtered हैं)। +- **`policies-config.json`** — failproofai को बताता है कि कौन सी नीतियों को मूल्यांकन करना है और किन पैरामीटर्स के साथ (सभी एजेंट CLIs में साझा) + +किसी विशिष्ट एजेंट को target करने के लिए `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` को pass करें (space-separated या किसी subset के लिए repeated): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +215,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -जब `--cli` omit किया जाता है, `failproofai` पता लगाता है कि कौन से एजेंट CLIs installed हैं (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +जब `--cli` omitted होता है, `failproofai` detect करता है कि कौन से एजेंट CLIs install हैं (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **एक CLI detected** — prompt के बिना उस CLI को auto-select करता है। -- **Multiple CLIs detected** एक interactive terminal में — एक arrow-key single-select प्रॉम्प्ट दिखाता है एक `Detected (N)` section (एक `Install for all N detected` aggregate row + प्रत्येक detected CLI individually के साथ) और एक `Not installed (M) · install hooks ahead of time` section में grouped (हर undetected supported CLI को एक forward-install विकल्प के रूप में सूचीबद्ध करता है (↑↓ move करने के लिए, Enter select करने के लिए, ^C quit करने के लिए))। uninstall flow केवल Detected section दिखाता है। -- **Multiple CLIs detected** एक non-interactive run में (CI, कोई TTY नहीं) — prompt के बिना सभी detected CLIs के लिए install करता है। -- **None detected** — `claude` को fallback करता है, एक warning के साथ कि कोई एजेंट बाइनरी PATH में नहीं मिला; हुक कमांड अभी भी लिखा जाता है ताकि यह तुरंत सक्रिय हो जाए जब आप एक install करते हैं। +- **एक CLI detect किया गया** — बिना पूछे उस CLI को auto-select करता है। +- **कई CLIs detect किए गए** एक interactive terminal में — एक arrow-key single-select prompt दिखाता है `Detected (N)` section में grouped (एक `Install for all N detected` aggregate row + प्रत्येक detected CLI को individually) और एक `Not installed (M) · install hooks ahead of time` section हर undetected supported CLI को forward-install option के रूप में list करते हुए (↑↓ move करने के लिए, Enter select करने के लिए, ^C quit करने के लिए)। uninstall flow केवल Detected section दिखाता है। +- **कई CLIs detect किए गए** एक non-interactive run में (CI, कोई TTY नहीं) — बिना पूछे सभी detected CLIs के लिए install करता है। +- **कोई detect नहीं किया** — `claude` को fallback करता है, warning के साथ कि PATH में कोई एजेंट बाइनरी नहीं मिला; हुक कमांड अभी भी लिखा जाता है ताकि जैसे ही आप एक install करें यह activate हो। -आप किसी भी समय `policies-config.json` को सीधे edit कर सकते हैं; changes अगली हुक ईवेंट पर तुरंत प्रभावी होते हैं restart की आवश्यकता नहीं है। +आप किसी भी समय `policies-config.json` को सीधे संपादित कर सकते हैं; परिवर्तन अगले हुक इवेंट पर बिना restart के तुरंत लागू होते हैं। --- -## उदाहरण: टीम डिफ़ॉल्ट के साथ प्रोजेक्ट-लेवल कॉन्फ़िग +## उदाहरण: टीम डिफ़ॉल्ट्स के साथ project-level कॉन्फ़िग -अपने रेपो में `.failproofai/policies-config.json` को कमिट करें: +`.failproofai/policies-config.json` को अपने रिपो में कमिट करें: ```json { @@ -247,4 +256,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -प्रत्येक डेवलपर फिर व्यक्तिगत overrides के लिए `.failproofai/policies-config.local.json` (gitignored) बना सकता है बिना teammates को प्रभावित किए। \ No newline at end of file +प्रत्येक डेवलपर फिर व्यक्तिगत ओवरराइड के लिए `.failproofai/policies-config.local.json` (gitignored) बना सकता है बिना टीमके सदस्यों को प्रभावित किए। \ No newline at end of file diff --git a/docs/hi/dashboard.mdx b/docs/hi/dashboard.mdx index b3a6c202..b0b215b9 100644 --- a/docs/hi/dashboard.mdx +++ b/docs/hi/dashboard.mdx @@ -1,10 +1,10 @@ --- title: डैशबोर्ड -description: "एजेंट सेशन की निगरानी करें, टूल कॉल की समीक्षा करें, और नीतियों को प्रबंधित करें" +description: "एजेंट सेशन की निगरानी करें, टूल कॉल की समीक्षा करें, और नीतियों का प्रबंधन करें" icon: chart-line --- -failproofai डैशबोर्ड आपके AI एजेंट सेशन की निगरानी करने और नीतियों को प्रबंधित करने के लिए एक स्थानीय वेब एप्लिकेशन है। देखें कि आपके एजेंट आपकी अनुपस्थिति में क्या कर रहे थे। +failproofai डैशबोर्ड आपके AI एजेंट सेशन की निगरानी और नीतियों के प्रबंधन के लिए एक स्थानीय वेब एप्लिकेशन है। देखें कि आपके एजेंट आपकी अनुपस्थिति में क्या करते थे। --- @@ -16,89 +16,89 @@ failproofai `http://localhost:8020` पर खुलता है। -डैशबोर्ड फाइलसिस्टम से सीधे पढ़ता है - आपके Claude Code प्रोजेक्ट फोल्डर और failproofai कॉन्फ़िगरेशन फाइलें। किसी रिमोट सेवा में कुछ नहीं लिखा जाता है। +डैशबोर्ड सीधे फाइल सिस्टम से पढ़ता है - आपके Claude Code प्रोजेक्ट फोल्डर और failproofai कॉन्फ़िग फाइलें। किसी भी रिमोट सेवा को कुछ भी नहीं लिखा जाता है। --- ## पृष्ठ -### प्रोजेक्ट +### प्रोजेक्ट्स -आपकी मशीन पर मिले सभी Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_, और Hermes प्रोजेक्ट सूचीबद्ध करता है। Claude प्रोजेक्ट `~/.claude/projects/` से खोजे जाते हैं (या `CLAUDE_PROJECTS_PATH` द्वारा निर्धारित पथ); Codex प्रोजेक्ट `~/.codex/sessions///
/*.jsonl` के तहत प्रत्येक ट्रांसक्रिप्ट को स्कैन करके और प्रत्येक सेशन के पहले रिकॉर्ड में दर्ज `cwd` के अनुसार समूहबद्ध करके खोजे जाते हैं; Copilot CLI प्रोजेक्ट प्रत्येक `~/.copilot/session-state//workspace.yaml` को स्कैन करके खोजे जाते हैं (`COPILOT_HOME` के माध्यम से कॉन्फ़िगर करने योग्य) और इसके `cwd` फील्ड के अनुसार समूहबद्ध किए जाते हैं; Cursor Agent प्रोजेक्ट `~/.cursor/agent-sessions//` के तहत प्रति-सेशन मेटाडेटा को स्कैन करके खोजे जाते हैं (`CURSOR_HOME` के माध्यम से कॉन्फ़िगर करने योग्य, `conversations/` और `sessions/` को फॉलबैक के रूप में जांचा जाता है) `meta.json` / `session.json` / `workspace.yaml` में `cwd` स्केलर के लिए; OpenCode प्रोजेक्ट `~/.local/share/opencode/opencode.db` पर इसके SQLite DB को `opencode db --format json` के माध्यम से क्वेरी करके खोजे जाते हैं (हम `session` और `project` तालिकाएं पढ़ते हैं और `project_id` के अनुसार समूहबद्ध करते हैं); Pi प्रोजेक्ट `~/.pi/agent/sessions//_.jsonl` के तहत प्रति-सेशन JSONL ट्रांसक्रिप्ट को स्कैन करके खोजे जाते हैं (`PI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और प्रत्येक सेशन के पहले रिकॉर्ड से `cwd` निकाला जाता है; Gemini CLI प्रोजेक्ट `~/.gemini/tmp//chats/session--.jsonl` को स्कैन करके खोजे जाते हैं (`GEMINI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और अनुवर्ती `.project_root` टेक्स्ट मार्कर से विहित cwd को पुनः प्राप्त किया जाता है; Hermes गेटवे सेशन सीधे इसके SQLite स्टोर से `~/.hermes/state.db` पर पढ़े जाते हैं (`HERMES_DB_PATH` के माध्यम से कॉन्फ़िगर करने योग्य) और `source` के अनुसार `hermes-` प्रोजेक्ट में समूहबद्ध किए जाते हैं (Slack/Telegram/cli/cron — गेटवे सेशन का कोई cwd नहीं है)। एक प्रोजेक्ट जिसे कई CLI द्वारा उपयोग किया गया है, एक एकल पंक्ति के रूप में सभी मेल खाने वाले बैज के साथ प्रदर्शित होता है। सारणी के ऊपर **CLI** ड्रॉपडाउन का उपयोग करके किसी विशिष्ट एजेंट CLI द्वारा फ़िल्टर करें; URL आपके चयन को `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` के रूप में संरक्षित करता है। +आपकी मशीन पर पाई जाने वाली सभी Claude Code, OpenAI Codex, GitHub Copilot CLI _(बीटा)_, Cursor Agent _(बीटा)_, OpenCode _(बीटा)_, Pi _(बीटा)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, और Goose प्रोजेक्ट्स को सूचीबद्ध करता है। Claude प्रोजेक्ट्स `~/.claude/projects/` से खोजे जाते हैं (या `CLAUDE_PROJECTS_PATH` द्वारा सेट किए गए पथ); Codex प्रोजेक्ट्स `~/.codex/sessions///
/*.jsonl` के तहत प्रत्येक ट्रांसक्रिप्ट को स्कैन करके और प्रत्येक सेशन के पहले रिकॉर्ड में दर्ज `cwd` के आधार पर समूहित करके खोजे जाते हैं; Copilot CLI प्रोजेक्ट्स प्रत्येक `~/.copilot/session-state//workspace.yaml` को स्कैन करके (`COPILOT_HOME` के माध्यम से कॉन्फ़िगर करने योग्य) और इसके `cwd` फील्ड के आधार पर समूहित करके खोजे जाते हैं; Cursor Agent प्रोजेक्ट्स `~/.cursor/agent-sessions//` के तहत प्रति-सेशन मेटाडेटा को स्कैन करके (`CURSOR_HOME` के माध्यम से कॉन्फ़िगर करने योग्य, `conversations/` और `sessions/` फॉलबैक के रूप में जांचे जाते हैं) `meta.json` / `session.json` / `workspace.yaml` में एक `cwd` स्केलर के लिए खोजे जाते हैं; OpenCode प्रोजेक्ट्स `opencode db --format json` के माध्यम से `~/.local/share/opencode/opencode.db` पर इसके SQLite DB को क्वेरी करके खोजे जाते हैं (हम `session` और `project` तालिकाओं को पढ़ते हैं और `project_id` के आधार पर समूहित करते हैं); Pi प्रोजेक्ट्स `~/.pi/agent/sessions//_.jsonl` के तहत प्रति-सेशन JSONL ट्रांसक्रिप्ट को स्कैन करके (`PI_SESSIONS_DIR` के माध्यम से कॉन्फ़िगर करने योग्य) और प्रत्येक सेशन के पहले रिकॉर्ड से `cwd` निकालकर खोजे जाते हैं; Hermes गेटवे सेशन सीधे `~/.hermes/state.db` पर इसके SQLite स्टोर से पढ़े जाते हैं (`HERMES_DB_PATH` के माध्यम से कॉन्फ़िगर करने योग्य) और `source` द्वारा `hermes-` प्रोजेक्ट्स में समूहित किए जाते हैं (Slack/Telegram/cli/cron — गेटवे सेशन के पास कोई cwd नहीं होता); OpenClaw गेटवे सेशन `~/.openclaw/agents//sessions/*.jsonl` से पढ़े जाते हैं और `openclaw-` प्रोजेक्ट्स में समूहित किए जाते हैं (cwd-रहित भी); Factory Droid प्रोजेक्ट्स `~/.factory/sessions//*.jsonl` पर JSONL ट्रांसक्रिप्ट से खोजे जाते हैं और cwd द्वारा समूहित किए जाते हैं; Devin प्रोजेक्ट्स `~/.local/share/devin/cli/sessions.db` पर इसके SQLite DB से (प्रत्येक सेशन के `working_directory` द्वारा समूहित); Antigravity प्रोजेक्ट्स `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` पर JSONL ट्रांसक्रिप्ट से और cwd द्वारा समूहित; और Goose प्रोजेक्ट्स `~/.local/share/goose/sessions/sessions.db` पर इसके SQLite DB से (प्रत्येक सेशन के `working_dir` द्वारा समूहित)। एक प्रोजेक्ट जो कई CLIs द्वारा उपयोग किया गया है, सभी मेल खाने वाले बैज के साथ एक पंक्ति के रूप में प्रदर्शित होता है। तालिका के ऊपर **CLI** ड्रॉपडाउन का उपयोग करके किसी विशेष एजेंट CLI द्वारा फ़िल्टर करें; URL आपके चयन को `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` के रूप में संरक्षित करता है। प्रत्येक प्रोजेक्ट दिखाता है: -- प्रोजेक्ट नाम (फोल्डर पथ से व्युत्पन्न) -- एक CLI बैज — `Claude Code` (नारंगी), `OpenAI Codex` (बैंगनी), `GitHub Copilot` (नीला), `Cursor Agent` (पन्ना), `OpenCode` (एम्बर), `Pi` (गुलाबी), `Gemini CLI` (आसमानी), और/या `Hermes` (गहरा नीला) +- प्रोजेक्ट नाम (फोल्डर पथ से प्राप्त) +- एक CLI बैज — `Claude Code` (नारंगी), `OpenAI Codex` (बैंगनी), `GitHub Copilot` (नीला), `Cursor Agent` (पन्ना), `OpenCode` (गहरा पीला), `Pi` (गुलाबी), और/या `Hermes` (नील) - सबसे हाल की सेशन गतिविधि की तारीख -एक प्रोजेक्ट पर क्लिक करके इसके सेशन देखें। +किसी प्रोजेक्ट के सेशन देखने के लिए उस पर क्लिक करें। -### सेशन +### सेशन्स -एक प्रोजेक्ट के भीतर सभी सेशन सूचीबद्ध करता है। प्रत्येक सेशन दिखाता है: +किसी प्रोजेक्ट के भीतर सभी सेशन को सूचीबद्ध करता है। प्रत्येक सेशन दिखाता है: - सेशन ID -- प्रारंभ और समाप्ति टाइमस्टैम्प +- शुरुआत और समाप्ति टाइमस्टैम्प - टूल कॉल की संख्या -- हुक गतिविधि गणना (नीतियां जो सक्रिय हुईं) +- हुक गतिविधि की गणना (नीतियां जो सक्रिय हुईं) -सूची को संकीर्ण करने के लिए दिनांक श्रेणी फ़िल्टर और सेशन ID खोज का उपयोग करें। सेशन पृष्ठांकित हैं। +सूची को कम करने के लिए दिनांक श्रेणी फ़िल्टर और सेशन ID खोज का उपयोग करें। सेशन पृष्ठांकित हैं। -सेशन दर्शक खोलने के लिए एक सेशन पर क्लिक करें। +सेशन व्यूअर खोलने के लिए किसी सेशन पर क्लिक करें। -### सेशन दर्शक +### सेशन व्यूअर -सेशन दर्शक स्वायत्त एजेंट के लिए मुख्य प्रश्न का उत्तर देता है: एजेंट ने क्या किया, और क्या वह ट्रैक पर रहा? शीर्षलेख के बगल में एक CLI बैज इंगित करता है कि सेशन Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI, या Hermes ट्रांसक्रिप्ट है। यह एक सेशन में हुई हर चीज की एक टाइमलाइन दिखाता है: +सेशन व्यूअर स्वायत्त एजेंट के लिए मुख्य प्रश्न का उत्तर देता है: एजेंट ने क्या किया, और क्या वह ट्रैक पर रहा? हेडर के बगल में एक CLI बैज इंगित करता है कि सेशन Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, या Goose ट्रांसक्रिप्ट है। यह एक सेशन में हुई सभी चीजों की एक टाइमलाइन दिखाता है: -- **संदेश** - Claude के टेक्स्ट प्रतिक्रियाएं और उपयोगकर्ता संकेत -- **टूल कॉल** - हर टूल जो Claude ने आह्वान किया, इसके इनपुट और आउटपुट के साथ -- **नीति गतिविधि** - प्रत्येक टूल कॉल के लिए, कौन सी नीतियां सक्रिय हुईं और उन्होंने कौन सा निर्णय लिया +- **संदेश** - Claude के पाठ प्रतिक्रियाएं और उपयोगकर्ता प्रॉम्प्ट +- **टूल कॉल** - Claude द्वारा आह्वान किए गए प्रत्येक टूल, इसके इनपुट और आउटपुट के साथ +- **नीति गतिविधि** - प्रत्येक टूल कॉल के लिए, कौन सी नीतियां सक्रिय हुईं और उन्होंने कौन सा निर्णय लौटाया -शीर्ष पर सांख्यिकी बार सेशन की अवधि, कुल टूल कॉल, और हुक निर्णयों का सारांश दिखाता है (अनुमति / अस्वीकृति / निर्देश गणना)। +शीर्ष पर स्टेट्स बार सेशन अवधि, कुल टूल कॉल, और हुक निर्णयों का सारांश दिखाता है (allow / deny / instruct गणना)। -सेशन निर्यात करने के लिए **डाउनलोड लॉग** बटन पर क्लिक करें। Claude Code, Codex, Copilot, Cursor, Pi, और Gemini सेशन के लिए आप मूल ऑन-डिस्क JSONL ट्रांसक्रिप्ट बाइट-दर-बाइट प्राप्त करते हैं; OpenCode के लिए (जिसके सेशन SQLite में रहते हैं, डिस्क पर नहीं) आप एक JSON दस्तावेज प्राप्त करते हैं जो अंतर्निहित `session` / `messages` / `parts` तालिकाओं को प्रतिबिंबित करता है। +**लॉग डाउनलोड करें** बटन पर क्लिक करके सेशन को निर्यात करें। Claude Code, Codex, Copilot, Cursor, और Pi सेशन के लिए आप बाइट-दर-बाइट मूल ऑन-डिस्क JSONL ट्रांसक्रिप्ट प्राप्त करते हैं; OpenCode (जिसके सेशन SQLite में रहते हैं, डिस्क पर नहीं) के लिए आप एक JSON दस्तावेज़ प्राप्त करते हैं जो अंतर्निहित `session` / `messages` / `parts` तालिकाओं को दर्पण करता है। ### ऑडिट -आपके एजेंट के पिछले सेशन में वास्तव में कैसे व्यवहार किया गया है, इस बारे में एक व्यक्तित्व-चालित रिपोर्ट। `failproofai audit` CLI के समान स्कैन चलाता है लेकिन इसे एक एकल-स्क्रीन शेयरेबल पोस्टर + चार नीचे-फोल्ड अनुभाग के रूप में प्रदान करता है: +आपके एजेंट के कैसे वास्तव में व्यवहार कर रहे हैं इसकी एक व्यक्तित्व-संचालित रिपोर्ट पिछले सेशन में। `failproofai audit` CLI के समान स्कैन चलाता है लेकिन इसे एक एकल-स्क्रीन साझा करने योग्य पोस्टर + चार नीचे-गुना अनुभाग के रूप में प्रस्तुत करता है: -1. **पोस्टर** — पहले व्यूपोर्ट को भरता है। failproof_ai वर्डमार्क + ऑडिट लेबल के साथ स्व-निहित PNG-कैप्चर क्षेत्र · आर्केटाइप इंडेक्स (`№ NN of 08`) + ऑडिट तारीख · संख्यात्मक स्कोर (0–100) + प्रतिशत रैंक गोली (`top 15%`) · आर्केटाइप नाम (एक `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost` में से) + 3-कीवर्ड पट्टी · `// only N% of agents are this archetype` दुर्लभता लाइन · 8×8 पिक्सल सिगिल टाइल · `audit yours → failproof.ai` फुटर। तीन शेयर बटन कैप्चर बॉक्स के बाहर बैठते हैं: `post your archetype` (X इरादा), `share on linkedin`, `download poster`। कैप्चर `html-to-image` के माध्यम से चलता है इसलिए PNG ऑन-स्क्रीन रेंडर से पिक्सल-दर-पिक्सल मेल खाता है (डैश किए गए बॉर्डर, SVG लोगो मास्क, ग्रेडिएंट, फ़ॉन्ट मेट्रिक्स — सभी संरक्षित)। -2. **शक्तियां** — शांत ✓ पंक्ति सूची के व्यवहार आपके एजेंट पहले से ही सही कर रहे हैं, लाइव ऑडिट डेटा से व्युत्पन्न (स्वच्छ टूल-कॉल दर, मुख्य में कोई सीधा पुश नहीं, शून्य क्रेडेंशियल लीक, शून्य पुनः प्रयास तूफान) — प्रत्येक तभी सामने आता है जब प्रासंगिक नीति के पास ऑडिट विंडो में एक स्वच्छ रिकॉर्ड हो। -3. **विचित्रताएं** — तालिका जो आगे बढ़ गया, गंभीरता के आधार पर क्रमबद्ध: `when · what slipped + the policy that would've caught it · severity pill · seen`, जहां पुनरावृत्ति `new` (एक बार), `N× seen` (2–9 बार), या `recurring` (10+) पढ़ता है। -4. **कैसे सुधारें** — शांत पंक्ति सूची, एक प्रति निर्धारित नीति: नीति नाम सफेद में, एक-पंक्ति विवरण, स्थापना आदेश + दाईं ओर कॉपी बटन। अनुभाग शीर्षलेख `enable all N → projected · ` पढ़ता है (वह स्कोर जो आप हर सुधार लागू करने के साथ पहुंचेंगे), और इसका `[install all]` बटन प्रत्येक निर्धारित नीति के लिए संयुक्त `failproofai policy add a b c …` कमांड को कॉपी करता है। -5. **बेहतर वापस आएं** — दो साथ-साथ कार्ड। बाएं: एक रिमाइंडर सेट करें (`3d` / `7d` / `14d` / `30d` कैडेंस पिकर; `/api/auth/reminder` के माध्यम से प्रमाणित होने के बाद बना रहता है)। दाएं: failproof विशेषाधिकार अनलॉक करें — `invite a friend` एक मोडल खोलता है जो अल्पविराम/स्पेस/न्यूलाइन-अलग दोस्त ईमेल की एक सूची लेता है (प्रति भेजने में अधिकतम 10), उन्हें `/api/audit/invite` को POST करता है, जो api-server के `POST /v0/invite` को अग्रेषित करता है। api-server प्रत्येक प्राप्तकर्ता को `invite@failproof.ai` से एक ईमेल भेजता है प्रेषक Cc'd और `Reply-To` सेट के साथ, इसलिए प्राप्तकर्ता देखता है कि किसने उन्हें आमंत्रित किया और प्रेषक को अपने इनबॉक्स में एक प्रति मिलती है। गुमनाम उपयोगकर्ता `AuthDialog` के माध्यम से रूट किए जाते हैं इसलिए आमंत्रण के बाहर जाने से पहले प्रेषक का ईमेल ज्ञात होता है। अधिकार / विशेषाधिकार पूर्ति एक अनुवर्ती है। +1. **पोस्टर** — पहले व्यूपोर्ट को भरता है। failproof_ai वर्डमार्क + ऑडिट लेबल के साथ स्व-निहित PNG-कैप्चर क्षेत्र · आर्कटाइप इंडेक्स (`№ NN of 08`) + ऑडिट तारीख · संख्यात्मक स्कोर (0–100) + प्रतिशतक रैंक गोली (`top 15%`) · आर्कटाइप नाम (एक `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost` में से) + 3-कीवर्ड स्ट्रिप · `// only N% of agents are this archetype` दुर्लभता लाइन · 8×8 पिक्सल सिगिल टाइल · `audit yours → failproof.ai` फूटर। तीन साझा करें बटन कैप्चर बॉक्स के ठीक बाहर बैठते हैं: `post your archetype` (X intent), `share on linkedin`, `download poster`। कैप्चर `html-to-image` के माध्यम से चलता है तो PNG ऑन-स्क्रीन रेंडर पिक्सल-दर-पिक्सल मेल खाता है (धराशायी सीमाएं, SVG लोगो मास्क, ग्रेडिएंट, फॉन्ट मेट्रिक्स — सभी संरक्षित)। +2. **शक्तियां** — शांत ✓ पंक्ति सूची आपके एजेंट के व्यवहार जो पहले से ही सही करते हैं, लाइव ऑडिट डेटा से प्राप्त (स्वच्छ टूल-कॉल दर, main में कोई सीधा पुश नहीं, शून्य क्रेडेंशियल लीक, शून्य पुनः प्रयास तूफान) — प्रत्येक केवल तभी दिखाया जाता है जब प्रासंगिक नीति ऑडिट विंडो में एक स्वच्छ रिकॉर्ड हो। +3. **विशेषताएं** — क्या गिरा हुआ है, गंभीरता द्वारा रैंक की गई तालिका: `when · what slipped + the policy that would've caught it · severity pill · seen`, जहां पुनरावृत्ति `new` (एक बार), `N× seen` (2–9 बार), या `recurring` (10+) को पढ़ता है। +4. **सुधार कैसे करें** — शांत पंक्ति सूची, एक प्रति नुस्खे की नीति के लिए: नीति का नाम सफेद में, एक-पंक्ति विवरण, इंस्टॉल कमांड + दाईं ओर कॉपी बटन। अनुभाग हेडर `enable all N → projected · ` को पढ़ता है (वह स्कोर जिस तक आप हर सुधार के साथ पहुंचेंगे), और इसका `[install all]` बटन हर नुस्खे की नीति के लिए संयुक्त `failproofai policy add a b c …` कमांड की प्रतिलिपि बनाता है। +5. **बेहतर वापस आएं** — दो साइड-बाय-साइड कार्ड। बाएं: एक अनुस्मारक सेट करें (`3d` / `7d` / `14d` / `30d` कैडेंस पिकर; प्रमाणित होने के बाद `/api/auth/reminder` के माध्यम से जारी रहता है)। दाएं: failproof सुविधा अनलॉक करें — `invite a friend` एक मोडल खोलता है जो एक अल्पविराम/स्पेस/न्यूलाइन-अलग मित्र ईमेल सूची लेता है (प्रति भेजने के लिए अधिकतम 10), उन्हें `/api/audit/invite` पर POSTs करता है, जो api-server के `POST /v0/invite` को अग्रेषित करता है। api-server `invite@failproof.ai` से एक प्रति प्राप्तकर्ता को ईमेल भेजता है और `Reply-To` भेजने वाले को Cc के साथ सेट करता है, तो प्राप्तकर्ता देखता है कि किसने उन्हें आमंत्रित किया है और भेजने वाला को अपने इनबॉक्स में एक प्रति मिलता है। गुमनाम उपयोगकर्ता पहले `AuthDialog` के माध्यम से रूट किए जाते हैं ताकि आमंत्रण जाने से पहले भेजने वाले का ईमेल ज्ञात हो। अधिकार / सुविधा पूरा करना एक अनुवर्ती है। -`failproofai audit` रनटाइम द्वारा संचालित — अंतर्निहित स्कैन इंजन, समर्थित झंडे, और प्रति-ट्रांसक्रिप्ट कैश इनवेरिएंट के लिए [Audit CLI](/hi/cli/audit) देखें। डैशबोर्ड सबसे हाल का परिणाम `~/.failproofai/audit-dashboard.json` पर कैश करता है (मोड `0600`, एकल स्लॉट, नए रन ओवरराइट करते हैं) इसलिए पुनः दौरे तत्काल हैं; **पढ़ने पर प्रति-ट्रांसक्रिप्ट और संपूर्ण-परिणाम दोनों कैश अस्वीकृत कर दिए जाते हैं एक बार वे 7 दिन से पुराने हो जाते हैं** इसलिए डैशबोर्ड कभी भी एक सप्ताह पुराना परिणाम चुप रहकर प्रदान नहीं करता है — TTL के पास `/audit` अपनी खाली स्थिति में गिरता है और एक ताजा रन के लिए संकेत देता है। रिपोर्ट के नीचे के पास `[ re-audit now ]` पर क्लिक करना `noCache: true` के साथ `/api/audit/run` को POST करता है — पुनः-ऑडिट प्रति-ट्रांसक्रिप्ट कैश को बाईपास करता है और प्रत्येक ट्रांसक्रिप्ट को शुरुआत से स्कैन करता है बजाय चुप रहकर कैश किए गए परिणाम को लौटाने के — और डैशबोर्ड रन समाप्त होने तक 1Hz पर `/api/audit/status` को पोल करता है; एक चिपचिपी गुलाबी प्रगति पट्टी रन के दौरान व्यूपोर्ट के शीर्ष पर खुद को पिन करती है एक समय बीता टाइमर के साथ, और सफलता पर ताजा परिणाम जगह में स्वैप करता है (कोई पूर्ण-पृष्ठ पुनः लोड नहीं; एक विफल पुनः-ऑडिट पूर्व रिपोर्ट को अक्षुण्ण छोड़ता है)। विफलता पर पट्टी `RerunError.kind` (`timeout` / `network` / `post_failed`) से कॉपी किए गए लाल हो जाती है। खाली स्थिति (कोई कैश या समाप्त नहीं) और शून्य-सेशन स्थिति (कैश मौजूद है लेकिन स्कैन को कोई ट्रांसक्रिप्ट नहीं मिली) अलग से सामने आती हैं। +`failproofai audit` रनटाइम द्वारा संचालित — अंतर्निहित स्कैन इंजन, समर्थित फ़्लैग, और प्रति-ट्रांसक्रिप्ट कैश अपरिवर्तनीयों के लिए [ऑडिट CLI](/hi/cli/audit) देखें। डैशबोर्ड सबसे हाल के परिणाम को `~/.failproofai/audit-dashboard.json` पर कैश करता है (मोड `0600`, एकल स्लॉट, नई रन को ओवरराइट करता है) ताकि पुनरावृत्ति तत्काल हो; **प्रति-ट्रांसक्रिप्ट और पूरे-परिणाम दोनों कैश को पढ़ने पर एक बार अस्वीकार कर दिया जाता है जब वे 7 दिन से अधिक पुराने हों** तो डैशबोर्ड कभी भी एक सप्ताह पुरानी परिणाम को चुप्पी से सेवा नहीं देता है — TTL के बाद `/audit` इसकी खाली स्थिति में गिरता है और एक ताजा रन का संकेत देता है। रिपोर्ट के निचले भाग के पास `[ re-audit now ]` पर क्लिक करने से `/api/audit/run` को `noCache: true` के साथ POSTs होता है — पुनः-ऑडिट प्रति-ट्रांसक्रिप्ट कैश को बाईपास करता है और बजाय चुप्पी से कैश की गई परिणाम लौटाने के प्रत्येक ट्रांसक्रिप्ट को शुरू से फिर से स्कैन करता है — और डैशबोर्ड रन समाप्त होने तक 1Hz पर `/api/audit/status` को पोल करता है; एक चिपचिपा गुलाबी प्रगति पट्टी रन के दौरान व्यूपोर्ट के शीर्ष में पिन होता है और एक बिताया हुआ टाइमर के साथ, और ताजा परिणाम सफलता पर स्थान में स्वैप करता है (कोई पूर्ण-पृष्ठ पुनः लोड नहीं; एक विफल पुनः-ऑडिट पूर्व रिपोर्ट को बरकरार रखता है)। विफलता पर पट्टी `RerunError.kind` (`timeout` / `network` / `post_failed`) को दूर किए गए कॉपी के साथ लाल हो जाता है। खाली स्थिति (कोई कैश या समाप्त) और शून्य-सेशन स्थिति (कैश मौजूद है लेकिन स्कैन ने कोई ट्रांसक्रिप्ट नहीं पाई) अलग से दिखाए जाते हैं। ### नीतियां -नीतियों को प्रबंधित करने और गतिविधि की समीक्षा करने के लिए एक दो-टैब पृष्ठ। +नीतियों के प्रबंधन और गतिविधि की समीक्षा करने के लिए एक दो-टैब पृष्ठ। - - एकल पैनल से failproofai किस एजेंट CLI की रक्षा करता है, इसे बहु-चयन करें — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, और Hermes सभी के पास स्थापना स्थिति (`Active` / `Detected` / `Inactive`) वाली एक पंक्ति है, उपयोगकर्ता-स्कोप सेटिंग्स पथ, और एक ब्रांड-रंगीन उच्चारण। आप जिन CLI चाहते हैं उन्हें चेक करें या अनचेक करें और `Apply changes` पर क्लिक करके एक चरण में इंस्टॉल/अनइंस्टॉल करने के लिए अंतर लागू करें। CLI जिनके बाइनरी को PATH पर पता चला है, पूर्व-जांच किए जाते हैं। - - एकल क्लिक के साथ व्यक्तिगत नीतियों को चालू या बंद करें (`~/.failproofai/policies-config.json` में लिखते हैं — हर इंस्टॉल किए गए CLI में साझा) - - एक नीति का विस्तार करके इसके पैरामीटर को कॉन्फ़िगर करें (उन नीतियों के लिए जो `policyParams` को समर्थन करती हैं) + - एक पैनल से failproofai सुरक्षा के लिए कौन सी एजेंट CLIs को मल्टी-सिलेक्ट करें — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, और Hermes सभी के पास इंस्टॉल स्थिति (`Active` / `Detected` / `Inactive`), उपयोगकर्ता-scope सेटिंग्स पथ, और एक ब्रांड-रंगीन लहजे वाली एक पंक्ति है। आप जो CLIs चाहते हैं उन्हें चेक या अनचेक करें और एक चरण में अंतर को इंस्टॉल/अनइंस्टॉल करने के लिए `Apply changes` पर क्लिक करें। CLIs जिनकी बाइनरी PATH पर पाई जाती है, वे पूर्व-जांचित हैं। + - एक एकल क्लिक के साथ व्यक्तिगत नीतियों को चालू या बंद करें (`~/.failproofai/policies-config.json` में लिखता है — हर इंस्टॉल किए गए CLI में साझा) + - एक नीति को विस्तारित करें इसके पैरामीटर को कॉन्फ़िगर करने के लिए (उन नीतियों के लिए जो `policyParams` का समर्थन करती हैं) - एक कस्टम नीति फाइल पथ सेट करें - - सभी सेशन में फायर किए गए प्रत्येक हुक ईवेंट का पूर्ण पृष्ठांकित इतिहास - - निर्णय, ईवेंट प्रकार, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), नीति नाम, या सेशन ID द्वारा फ़िल्टर करें - - प्रत्येक पंक्ति दिखाती है: टाइमस्टैम्प, नीति नाम, निर्णय, CLI बैज (नारंगी = Claude Code, बैंगनी = OpenAI Codex, नीला = GitHub Copilot, पन्ना = Cursor Agent, एम्बर = OpenCode, गुलाबी = Pi, आसमानी = Gemini CLI, गहरा नीला = Hermes), टूल नाम, सेशन ID, और अस्वीकृति/निर्देश निर्णयों का कारण - - ट्रांसक्रिप्ट खोलने के लिए एक सेशन ID पर क्लिक करें — दर्शक स्वचालित रूप से पता लगाता है कि कौन सा CLI हुक को आग लगाया (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) और शीर्षलेख में मेल खाने वाले CLI बैज को प्रदान करता है + - सभी सेशन में सक्रिय हुई हर हुक घटना का पूर्ण पृष्ठांकित इतिहास + - निर्णय, घटना प्रकार, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(बीटा)_ / Cursor Agent _(बीटा)_ / OpenCode _(बीटा)_ / Pi _(बीटा)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), नीति का नाम, या सेशन ID द्वारा फ़िल्टर करें + - प्रत्येक पंक्ति दिखाता है: टाइमस्टैम्प, नीति का नाम, निर्णय, CLI बैज (नारंगी = Claude Code, बैंगनी = OpenAI Codex, नीला = GitHub Copilot, पन्ना = Cursor Agent, गहरा पीला = OpenCode, गुलाबी = Pi, नील = Hermes, पन्ना = OpenClaw, गुलाब = Factory Droid, बैंगनी = Devin, फिरोजी = Antigravity, चूना = Goose), टूल का नाम, सेशन ID, और deny/instruct निर्णय का कारण + - इसके ट्रांसक्रिप्ट खोलने के लिए एक सेशन ID पर क्लिक करें — व्यूअर स्वतः-पहचान करता है कि कौन सी CLI ने हुक को सक्रिय किया (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) और हेडर में मेल खाते CLI बैज को प्रदर्शित करता है --- -## स्वचालित रीफ्रेश +## ऑटो-रिफ्रेश -डैशबोर्ड के शीर्ष नेविगेशन में एक स्वचालित-रीफ्रेश टॉगल है। सक्षम होने पर, वर्तमान पृष्ठ नए सेशन और नीति गतिविधि दिखाने के लिए आवधिक रूप से रीफ्रेश होता है जैसे वे प्रकट होते हैं। दीर्घकालिक स्वायत्त एजेंट सेशन की निगरानी के लिए आवश्यक। +डैशबोर्ड के शीर्ष नेविगेशन में एक ऑटो-रिफ्रेश टॉगल है। सक्षम होने पर, वर्तमान पृष्ठ समय-समय पर नए सेशन और नीति गतिविधि दिखाने के लिए ताजा करता है क्योंकि वे दिखाई देते हैं। दीर्घकालीन स्वायत्त एजेंट सेशन की निगरानी के लिए आवश्यक। --- -## पृष्ठ अक्षम करना +## पृष्ठों को अक्षम करना -यदि आपको डैशबोर्ड के केवल कुछ भाग की आवश्यकता है, तो `FAILPROOFAI_DISABLE_PAGES` को अल्पविराम-अलग पृष्ठ नामों की सूची पर सेट करें: +यदि आपको डैशबोर्ड के केवल कुछ भाग चाहिए, `FAILPROOFAI_DISABLE_PAGES` को पृष्ठ नामों की एक अल्पविराम-अलग सूची पर सेट करें: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -108,9 +108,9 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai --- -## प्रोजेक्ट पथ कॉन्फ़िगर करना +## प्रोजेक्ट्स पथ को कॉन्फ़िगर करना -डिफ़ॉल्ट रूप से, डैशबोर्ड मानक Claude Code प्रोजेक्ट निर्देशिका से पढ़ता है। कस्टम सेटअप के लिए इसे ओवरराइड करें: +डिफॉल्ट रूप से, डैशबोर्ड मानक Claude Code प्रोजेक्ट्स निर्देशिका से पढ़ता है। कस्टम सेटअप के लिए इसे ओवरराइड करें: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -120,30 +120,30 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ## गैर-localhost होस्ट से एक्सेस करना -जब डैशबोर्ड को **dev मोड** (`npm run dev`) में चला रहे हैं और इसे `localhost` के अलावा किसी होस्टनाम से एक्सेस कर रहे हैं - उदाहरण के लिए, एक कस्टम डोमेन, एक रिमोट IP, या एक सुरंग किए गए URL - आप यह चेतावनी देख सकते हैं: +जब डैशबोर्ड को **dev मोड** (`npm run dev`) में चलाया जा रहा हो और इसे `localhost` के अलावा किसी होस्टनाम से एक्सेस किया जा रहा हो - उदाहरण के लिए, एक कस्टम डोमेन, एक रिमोट IP, या एक टनल किया गया URL - आप एक चेतावनी जैसे देख सकते हैं: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -यह Next.js इसके HMR (हॉट मॉड्यूल रीलोड) वेबसॉकेट के लिए क्रॉस-ऑरिजिन एक्सेस को ब्लॉक कर रहा है, जो एक dev-only सुविधा है। आपके होस्ट को अनुमति देने के लिए, `--allowed-origins` फ्लैग का उपयोग करें: +यह Next.js अपने HMR (हॉट मॉड्यूल रीलोड) वेबसॉकेट में क्रॉस-ऑरिजिन एक्सेस को ब्लॉक कर रहा है, जो एक dev-केवल सुविधा है। अपने होस्ट को अनुमति देने के लिए, `--allowed-origins` फ़्लैग का उपयोग करें: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -कई होस्ट या IP के लिए, अल्पविराम-अलग सूची पास करें: +कई होस्ट या IPs के लिए, अल्पविराम-अलग सूची पास करें: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -आप इसके बजाय `FAILPROOFAI_ALLOWED_DEV_ORIGINS` पर्यावरण चर सेट कर सकते हैं: +आप `FAILPROOFAI_ALLOWED_DEV_ORIGINS` पर्यावरण चर को इसके बजाय सेट कर सकते हैं: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -यह केवल dev मोड पर लागू होता है। `failproofai` (उत्पादन मोड) चलाते समय, कोई HMR वेबसॉकेट नहीं है और कोई क्रॉस-ऑरिजिन dev संसाधन समस्या नहीं है। +यह केवल dev मोड पर लागू होता है। जब `failproofai` चलाया जाता है (उत्पादन मोड), कोई HMR वेबसॉकेट और कोई क्रॉस-ऑरिजिन dev संसाधन समस्या नहीं होती है। \ No newline at end of file diff --git a/docs/hi/getting-started.mdx b/docs/hi/getting-started.mdx index b7f3787d..55345c17 100644 --- a/docs/hi/getting-started.mdx +++ b/docs/hi/getting-started.mdx @@ -1,13 +1,13 @@ --- title: शुरुआत करें -description: "failproofai इंस्टॉल करें, policies को सक्षम करें, और अपने agents को विश्वसनीयता से चलाएं" +description: "failproofai इंस्टॉल करें, policies सक्षम करें, और अपने agents को विश्वसनीयता से चलाएं" icon: rocket --- ## आवश्यकताएं - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (वैकल्पिक - केवल स्रोत से बनाने के लिए आवश्यक) +- **Bun** >= 1.3.0 (वैकल्पिक - केवल source से build करते समय आवश्यक) --- @@ -30,16 +30,16 @@ bun add -g failproofai ## त्वरित शुरुआत - - Policies नियम हैं जो हर agent tool call से पहले और बाद में चलते हैं। ये विनाशकारी commands, secret leakage, और अन्य failure modes को नुकसान पहुंचने से पहले पकड़ते हैं। + + Policies वे नियम हैं जो हर agent tool call से पहले और बाद में चलते हैं। वे विनाशकारी commands, secret leakage, और अन्य failure modes को नुकसान पहुंचाने से पहले ही पकड़ लेते हैं। ```bash failproofai policies --install ``` - यह आपके इंस्टॉल किए गए agent CLIs में hook entries लिखता है (Claude Code के `~/.claude/settings.json`, OpenAI Codex के `~/.codex/hooks.json`, GitHub Copilot CLI के `~/.copilot/hooks/failproofai.json`, Cursor Agent के `~/.cursor/hooks.json`, OpenCode के generated plugin shim में `~/.config/opencode/plugins/failproofai.mjs` plus `~/.config/opencode/opencode.json` के `plugin` array में एक registration entry, Pi के `~/.pi/agent/settings.json`, Gemini CLI के `~/.gemini/settings.json`, या Hermes के `~/.hermes/config.yaml`)। जब एक से अधिक मौजूद हों तो आपसे prompt किया जाएगा; prompt को छोड़ने के लिए `--cli claude codex copilot cursor opencode pi gemini hermes` (कोई भी subset) पास करें। + यह आपके installed agent CLIs में hook entries लिखता है (Claude Code के `~/.claude/settings.json`, OpenAI Codex के `~/.codex/hooks.json`, GitHub Copilot CLI के `~/.copilot/hooks/failproofai.json`, Cursor Agent के `~/.cursor/hooks.json`, OpenCode के generated plugin shim में `~/.config/opencode/plugins/failproofai.mjs` के साथ-साथ `~/.config/opencode/opencode.json` के `plugin` array में एक registration entry, Pi के `~/.pi/agent/settings.json`, Hermes के `~/.hermes/config.yaml`, OpenClaw के `~/.openclaw/openclaw.json`, Factory Droid के `~/.factory/hooks.json`, Devin CLI के `~/.config/devin/config.json`, Antigravity CLI के `~/.gemini/config/hooks.json`, या Goose के auto-discovered plugin dir में `~/.agents/plugins/failproofai/hooks/hooks.json`)। जब एक से अधिक मौजूद हों तो आपसे prompt दिया जाएगा; `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (कोई भी subset) पास करके prompt को छोड़ें। - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, और Gemini CLI सपोर्ट **beta** है — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, या `--cli gemini` के साथ इंस्टॉल करें। Hermes (hermes-agent, एक Slack/Telegram gateway) user-scope के साथ `--cli hermes` के साथ इंस्टॉल होता है और **साथ ही** एक offline audit source है। + GitHub Copilot CLI, Cursor Agent, OpenCode, और Pi support **beta** में हैं — `--cli copilot`, `--cli cursor`, `--cli opencode`, या `--cli pi` के साथ इंस्टॉल करें। Hermes (hermes-agent, एक Slack/Telegram gateway) user-scope के साथ `--cli hermes` से इंस्टॉल होता है और **साथ ही** एक offline audit source है। OpenClaw (openclaw gateway, एक self-hosted multi-channel assistant) user-scope के साथ `--cli openclaw` से इंस्टॉल होता है — enforcement इसके in-process plugin hooks के माध्यम से चलता है (`before_agent_finalize` एक real turn-end gate है, इसलिए `require-*-before-stop` builtins लागू होते हैं) — और **साथ ही** एक offline audit source है। Factory Droid (`droid`) `--cli factory` के साथ इंस्टॉल होता है (user + project scope) और **साथ ही** एक offline audit source है। Devin CLI (`devin`, Cognition) `--cli devin` के साथ इंस्टॉल होता है (user + project scope) और **साथ ही** एक offline audit source है। Antigravity CLI (`agy`) `--cli antigravity` के साथ इंस्टॉल होता है (user + project scope) और **साथ ही** एक offline audit source है। Goose (codename goose, Block) `--cli goose` के साथ इंस्टॉल होता है (user + project scope) — इंस्टॉलर बस एक plugin dir को `~/.agents/plugins/failproofai/` में डालता है जिसे Goose auto-discovers करता है, और यह **साथ ही** एक offline audit source है। ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,17 +62,17 @@ bun add -g failproofai failproofai policies ``` - हर policy दिखाता है, चाहे वह सक्षम हो, और कोई भी configured parameters। + हर policy, चाहे वह सक्षम हो, और कोई भी configured parameters दिखाता है। ```bash failproofai ``` - `http://localhost:8020` पर एक local dashboard खोलता है जहां आप sessions को ब्राउज कर सकते हैं, tool calls की जांच कर सकते हैं, और policies को manage कर सकते हैं। + `http://localhost:8020` पर एक local dashboard खोलता है जहां आप sessions browse कर सकते हैं, tool calls inspect कर सकते हैं, और policies manage कर सकते हैं। - - Claude Code को सामान्य तरीके से शुरू करें। अगर agent कुछ जोखिम भरा करने की कोशिश करता है, तो failproofai इसे स्वचालित रूप से intercept करता है। इसे unattended चलाएं और dashboard में देखें कि क्या हुआ। + + Claude Code को सामान्य रूप से शुरू करें। यदि agent कुछ जोखिम भरा प्रयास करता है, तो failproofai इसे स्वचालित रूप से रोक देता है। इसे unattended चलने दें और dashboard में देखें कि क्या हुआ। @@ -76,29 +80,29 @@ bun add -g failproofai ## Policies कैसे काम करती हैं -हर बार जब एक agent किसी tool को चलाता है, Claude Code failproofai को एक subprocess के रूप में कॉल करता है: +हर बार जब एक agent tool चलाता है, Claude Code failproofai को एक subprocess के रूप में कॉल करता है: ```text -Claude Code → failproofai --hook PreToolUse → stdin JSON पढ़ता है - policies का मूल्यांकन करता है - stdout पर निर्णय लिखता है +Claude Code → failproofai --hook PreToolUse → reads stdin JSON + evaluates policies + writes decision to stdout ``` -प्रत्येक policy तीन निर्णयों में से एक देता है: +हर policy तीन निर्णयों में से एक देता है: - **allow** - agent सामान्य रूप से आगे बढ़ता है -- **deny** - कार्रवाई को ब्लॉक किया जाता है, agent को बताया जाता है कि क्यों -- **instruct** - agent के prompt में extra context जोड़ा जाता है +- **deny** - action को block किया जाता है, agent को बताया जाता है कि क्यों +- **instruct** - agent के prompt में अतिरिक्त context जोड़ा जाता है -Policies आपकी local process में चलती हैं। कुछ भी remote service को नहीं भेजा जाता है। +Policies आपके local process में चलती हैं। कुछ भी किसी remote service को नहीं भेजा जाता है। --- ## Convention-based policies के साथ team policies सेट अप करें -अपनी team के across quality standards स्थापित करने का सबसे तेज़ तरीका `.failproofai/policies/` convention है। इस directory में policy files डालें और वे automatically लोड हो जाती हैं — कोई flags नहीं, कोई config changes नहीं, कोई install commands नहीं। +अपनी पूरी team में quality standards स्थापित करने का सबसे तेज़ तरीका `.failproofai/policies/` convention है। इस directory में policy files डालें और वे स्वचालित रूप से लोड होते हैं — कोई flags नहीं, कोई config changes नहीं, कोई install commands नहीं। @@ -107,7 +111,7 @@ Policies आपकी local process में चलती हैं। कु ``` - Starter examples को कॉपी करें या अपने स्वयं के लिखें: + स्टार्टर examples को कॉपी करें या अपना खुद का लिखें: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -132,43 +136,43 @@ Policies आपकी local process में चलती हैं। कु }); ``` - + ```bash git add .failproofai/policies/ git commit -m "Add team quality policies" ``` - हर team member जिसके पास failproofai इंस्टॉल है, ये policies automatically pick up करता है। कोई per-developer setup की आवश्यकता नहीं है। + हर team member जिसके पास failproofai installed है, ये policies स्वचालित रूप से उठाता है। कोई per-developer setup की आवश्यकता नहीं है। -अपने repo में `.failproofai/policies/` को commit करें ताकि पूरी team एक ही standards शेयर करे। जैसे-जैसे आपकी team नए failure modes को discover करती है, policies को जोड़ें और push करें — हर कोई अपने अगले `git pull` पर update प्राप्त करता है। समय के साथ ये policies एक living quality standard बन जाती हैं जो बेहतर होती रहती हैं। +`.failproofai/policies/` को अपने repo में commit करें ताकि पूरी team एक ही standards share करे। जैसे-जैसे आपकी team नए failure modes खोजती है, policies जोड़ें और push करें — सभी को अपने अगले `git pull` पर update मिल जाता है। समय के साथ ये policies एक living quality standard बन जाती हैं जो लगातार सुधर रही होती हैं। --- -## डेटा स्टोरेज +## डेटा storage -सभी configuration और logs आपकी machine पर रहते हैं: +सभी configuration और logs आपकी machine पर ही रहते हैं: -| Path | क्या स्टोर करता है | +| Path | यह क्या store करता है | |------|----------------| | `~/.failproofai/policies-config.json` | Global policy config | | `~/.failproofai/hook-activity.jsonl` | Hook execution history | | `~/.failproofai/hook.log` | Custom hook errors के लिए debug log | | `.failproofai/policies-config.json` | Per-project config (committed) | -| `.failproofai/policies-config.local.json` | व्यक्तिगत overrides (gitignored) | +| `.failproofai/policies-config.local.json` | Personal overrides (gitignored) | --- -## अनइंस्टॉल करना +## Uninstalling ```bash failproofai policies --uninstall ``` -`~/.claude/settings.json` से hook entries को हटाता है। `~/.failproofai/` में config files को रखा जाता है। +`~/.claude/settings.json` से hook entries को हटा देता है। `~/.failproofai/` में config files रखी जाती हैं। --- @@ -181,15 +185,15 @@ failproofai policies --uninstall - सभी 26 policies with parameters + सभी 26 policies parameters के साथ - JavaScript में अपनी स्वयं की policies लिखें + JavaScript में अपनी खुद की policies लिखें - Sessions को monitor करें और policy activity की समीक्षा करें + Sessions को monitor करें और policy activity को review करें \ No newline at end of file diff --git a/docs/hi/introduction.mdx b/docs/hi/introduction.mdx index 1055e6cc..e6f83a8b 100644 --- a/docs/hi/introduction.mdx +++ b/docs/hi/introduction.mdx @@ -1,16 +1,15 @@ --- ---- title: "Failproof AI" -description: "FailproofAI आपके AI एजेंट्स को 39 बिल्ट-इन फेलियर पॉलिसीज देता है जो लूप्स, सीक्रेट लीक्स, डिस्ट्रक्टिव टूल कॉल्स और अन्य समस्याओं को एक सिंगल इंस्टॉल में कैच करता है।" +description: "FailproofAI AI एजेंटों को 39 बिल्ट-इन फेलियर पॉलिसीज देता है जो एक ही इंस्टॉल में लूप्स, सीक्रेट लीक्स, डिस्ट्रक्टिव टूल कॉल्स और बहुत कुछ को पकड़ते हैं।" --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI फेलियर हैंडलिंग**, **एरर रिकवरी**, और **LLM रिलायबिलिटी** के लिए हुक्स और पॉलिसीज। अपने AI एजेंट्स को **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, और **Agents SDK** में विश्वसनीय और स्वायत्त रूप से चलाते रहें। +**AI फेलियर हैंडलिंग**, **एरर रिकवरी**, और **LLM रिलायबिलिटी** के लिए हुक्स और पॉलिसीज। अपने AI एजेंटों को **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, और **Agents SDK** में विश्वसनीय और स्वायत्त रूप से चलता रखें। -AI एजेंट्स पूर्वानुमानित तरीकों से फेल होते हैं। वे डिस्ट्रक्टिव कमांड्स चलाते हैं, सीक्रेट्स लीक करते हैं, अपने टास्क से भटकते हैं, लूप्स में फंसते हैं, या सीधे मेन में पुश करते हैं। जब बिना निरीक्षण के छोड़ दिया जाता है, तो छोटी-मोटी विफलताएं आउटेजेस, लीक किए गए क्रेडेंशियल्स और खोए हुए कार्य में बदल जाती हैं। +AI एजेंट्स अनुमानित तरीकों से फेल होते हैं। वे डिस्ट्रक्टिव कमांड्स चलाते हैं, सीक्रेट्स लीक करते हैं, टास्क से भटकते हैं, लूप्स में फंस जाते हैं, या सीधे मेन में पुश करते हैं। अगर अनुपस्थित छोड़े जाएं, तो छोटी फेलियर्स आउटेजेस, लीक किए गए क्रेडेंशियल्स और खोए हुए काम में बदल जाते हैं। -FailproofAI इसे **पॉलिसीज** से हल करता है। ये नियम प्रत्येक एजेंट टूल कॉल में हुक करते हैं ताकि **फेलियर्स को डिटेक्ट** करें, **उन्हें कम करें** (ब्लॉक, इंस्ट्रक्ट, सैनिटाइज), और **आपको अलर्ट** करें जब कुछ ध्यान देने की जरूरत हो। एक लोकल डैशबोर्ड आपको बाद में प्रत्येक टूल कॉल, एजेंट फेलियर और रिकवरी एक्शन की समीक्षा करने देता है। +FailproofAI इसे **पॉलिसीज** से सॉल्व करता है। ये नियम हर एजेंट टूल कॉल में हुक करते हैं ताकि **फेलियर्स को डिटेक्ट** करें, **उन्हें कम करें** (ब्लॉक, इंस्ट्रक्ट, सैनिटाइज करें), और **आपको अलर्ट करें** जब कुछ ध्यान की जरूरत हो। एक लोकल डैशबोर्ड आपको हर टूल कॉल, एजेंट फेलियर, और रिकवरी एक्शन को बाद में रिव्यू करने देता है। कोई डेटा आपकी मशीन से बाहर नहीं जाता। @@ -19,19 +18,19 @@ FailproofAI इसे **पॉलिसीज** से हल करता ह - डिस्ट्रक्टिव कमांड्स को ब्लॉक करें, सीक्रेट लीकेज रोकें, एजेंट्स को प्रोजेक्ट बाउंड्रीज के अंदर रखें और बहुत कुछ। सब कुछ बॉक्स के बाहर से। + डिस्ट्रक्टिव कमांड्स को ब्लॉक करें, सीक्रेट लीकेज को रोकें, एजेंट्स को प्रोजेक्ट बाउंड्रीज के अंदर रखें, और बहुत कुछ। सब कुछ आउट ऑफ द बॉक्स। - सिंपल allow / deny / instruct API के साथ JavaScript में अपने नियम लिखें। + JavaScript में अपने नियम लिखें एक सरल allow / deny / instruct API के साथ। - देखें कि आपके एजेंट्स आपके दूर रहने के समय क्या करते थे। सेशन्स ब्राउज़ करें, टूल कॉल्स को इंस्पेक्ट करें, समीक्षा करें कि पॉलिसीज कहां फायर हुईं। + देखें कि आपके एजेंट्स जब आप दूर थे तब क्या करते थे। सेशन्स को ब्राउज करें, टूल कॉल्स को इंस्पेक्ट करें, रिव्यू करें कि पॉलिसीज कहां फायर हुईं। - बिना कोड के किसी भी पॉलिसी को ट्यून करें। अलाउलिस्ट्स, प्रोटेक्टेड ब्रांचेस, या थ्रेशहोल्ड्स प्रति-प्रोजेक्ट या ग्लोबली सेट करें। + किसी भी पॉलिसी को बिना कोड के ट्यून करें। एलाउलिस्ट्स, प्रोटेक्टेड ब्रांचेस, या थ्रेशहोल्ड्स प्रति-प्रोजेक्ट या ग्लोबली सेट करें। @@ -51,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # enable policies (या स्किप करें — `failproofai` पहली रन पर सेट अप करने का ऑफर देगा) +failproofai policies --install # पॉलिसीज को एनेबल करें (या स्किप करें — `failproofai` पहली बार रन करने पर सेटअप करने का ऑफर देगा) failproofai # डैशबोर्ड लॉन्च करें ``` -पूर्ण वॉकथ्रू के लिए [गेटिंग स्टार्टेड](/hi/getting-started) गाइड देखें। \ No newline at end of file +पूरी वॉकथ्रू के लिए [शुरुआत करना](/hi/getting-started) गाइड देखें। \ No newline at end of file diff --git a/docs/i18n/README.ar.md b/docs/i18n/README.ar.md index e5f60f40..4c9bcc56 100644 --- a/docs/i18n/README.ar.md +++ b/docs/i18n/README.ar.md @@ -19,9 +19,9 @@ **الترجمات:** [简体中文](./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. يقبض على الحلقات والإجراءات الخطيرة وتسرب الأسرار -قبل أن تصبح حوادث. لا توجد زمن انتظار. يعمل محليًا. +**حل فشل وقت التشغيل لوكلاء البرمجة. +يتدخل في Claude Code و Codex. يلتقط الحلقات والإجراءات الخطيرة وتسرب الأسرار +قبل أن تصبح حوادث. بدون زمن انتظار. يعمل محليًا.** @@ -31,67 +31,96 @@ --- -## واجهات سطر الأوامر المدعومة للعوامل +## واجهات سطر الأوامر المدعومة للوكلاء

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> تثبيت الخطافات لواحدة أو أي مزيج: `failproofai policies --install --cli opencode pi gemini` (أو `--cli claude codex copilot cursor opencode pi gemini hermes`). احذف `--cli` للكشف التلقائي عن واجهات سطر الأوامر المثبتة والمطالبة. +> ثبّت الخطاطيف لواحد أو أي مجموعة: `failproofai policies --install --cli opencode pi` (أو `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). تجاوز `--cli` للكشف التلقائي عن واجهات البرمجة المثبتة والمحادثة. +> +> **Hermes** (hermes-agent، بوابة Slack/Telegram) مدعومة لفرض الخطاطيف الحية (`--cli hermes` — تثبيت واحد يعترض استدعاءات الأدوات من كل منصة ووكيل فرعي) وإعادة تشغيل التدقيق بلا اتصال لجلسات البوابة من `~/.hermes/state.db`. +> +> **OpenClaw** (بوابة openclaw، مساعد متعدد القنوات يستضيف ذاتيًا) مدعومة لفرض الخطاطيف الحية (`--cli openclaw`، نطاق المستخدم) وإعادة تشغيل التدقيق بلا اتصال لجلسات JSONL (`~/.openclaw/agents//sessions/*.jsonl`). يستخدم الفرض خطاطيف المكون الإضافي داخل العملية من OpenClaw (مكون إضافي شامل `openclaw-plugin/` يولد failproofai بشكل غير متزامن — خطاطيفها الداخلية القائمة على الملفات تراقب فقط ولا يمكنها حظر): `before_tool_call` يحظر أداة، و `before_agent_finalize` هي بوابة حقيقية في نهاية الدور، لذا تفرض builtins `require-*-before-stop`. +> +> **Factory Droid** (`droid`) مدعومة لفرض الخطاطيف الحية (`--cli factory`، نطاق المستخدم والمشروع) وإعادة تشغيل التدقيق بلا اتصال لجلسات JSONL على القرص. يحظر droid استدعاءات الأدوات عند رمز الخروج من الخطاف **2** (ليس قرار JSON) ويشرّف `{decision:"block"}` فقط على حدث نهاية الدور `Stop` — failproofai ينبعث الشكل الصحيح لكل حدث تلقائيًا. +> +> **Devin CLI** (`devin`، Cognition) مدعومة لفرض الخطاطيف الحية (`--cli devin`، نطاق المستخدم والمشروع) وإعادة تشغيل التدقيق بلا اتصال لجلسات SQLite (`~/.local/share/devin/cli/sessions.db`). Devin هو **نسخة مطابقة خالصة لـ Claude** — نفس أسماء الأحداث، نفس حمولة snake_case، نفس تكوين `hooks`-wrapper (`~/.config/devin/config.json` / `/.devin/config.json`) — الحظر عبر JSON `{decision:"block"}` على كل حدث. +> +> **Antigravity CLI** (`agy`) مدعومة لفرض الخطاطيف الحية (`--cli antigravity`، نطاق المستخدم والمشروع) وإعادة تشغيل التدقيق بلا اتصال لجلسات JSONL العادية (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity لديها عقدها **الخاص** (ليست نسخة مطابقة لـ Claude): **خطاطيف مسماة** بـ `hooks.json` schema (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`)، حمولة stdin بـ camelCase تعيد failproofai تطبيعها، وأشكال استجابة خاصة بها — `{decision:"deny"}` لحظر أداة، `{decision:"continue"}` لفرض دور آخر في `Stop`، `{injectSteps}` لحقن تذكير قبل تشغيل النموذج. > -> **Hermes** (hermes-agent، بوابة Slack/Telegram) مدعومة لكل من **فرض الخطاف الحي** (`--cli hermes` — التثبيت الواحد يعترض استدعاءات الأدوات من كل منصة ووكيل فرعي) والتدقيق غير المتصل **إعادة تشغيل** لجلسات البوابة من قاعدة البيانات الواحدة `~/.hermes/state.db`. +> **Goose** (codename goose، Block) مدعومة لفرض الخطاطيف الحية (`--cli goose`، نطاق المستخدم والمشروع) وإعادة تشغيل التدقيق بلا اتصال لجلسات SQLite (`~/.local/share/goose/sessions/sessions.db`). يستخدم الفرض نظام **خطاطيف** Goose (مواصفة **Open Plugins** عبر الوكلاء) — يقوم المثبت فقط بإسقاط مجلد مكون إضافي على `~/.agents/plugins/failproofai/` ويكتشف Goose تلقائيًا. الحظر هو JSON `{"decision":"block"}` على حدث `PreToolUse` (الذي ينطلق لأداة shell وداخل الوكلاء الفرعيين المفوضين)، يتم التحقق منه مباشرة مقابل goose v1.43.0؛ Goose ليس لديه حدث نهاية دور `Stop`، لذا فإن builtins `require-*-before-stop` لا تنطبق (كما هو الحال مع Hermes). --- @@ -99,32 +128,32 @@ ```sh npm install -g failproofai -failproofai policies --install # أو فقط قم بتشغيل `failproofai` وقبل السؤال الأول +failproofai policies --install # أو فقط قم بتشغيل `failproofai` واقبل مطالبة التشغيل الأول failproofai ``` -30 سياسة مدمجة تُفعّل فوراً. لوحة التحكم على `localhost:8020`. تعطيل السؤال الأول باستخدام `FAILPROOFAI_NO_FIRST_RUN=1`. +30 سياسة مدمجة تُفعّل فورًا. لوحة القيادة على `localhost:8020`. تعطيل مطالبة التشغيل الأول باستخدام `FAILPROOFAI_NO_FIRST_RUN=1`. --- -## ما الذي يوقفه +## ما يوقفه -| السياسة | ما يحجبه | +| السياسة | ما يحظره | |---|---| | `block-push-master` | الدفع المباشر إلى `main` / `master` | | `block-force-push` | `git push --force` | -| `block-work-on-main` | الالتزامات والدمج وإعادة القاعدة على `main` / `master` | +| `block-work-on-main` | الالتزامات والدمج والإعادة الأساسية على `main` / `master` | | `block-rm-rf` | حذف الملفات بشكل متكرر | -| `sanitize-api-keys` | مفاتيح واجهة البرمجة تتسرب إلى سياق الوكيل | +| `sanitize-api-keys` | مفاتيح API تتسرب إلى سياق الوكيل | -→ [جميع السياسات المدمجة الـ 30](https://docs.befailproof.ai/built-in-policies) +→ [جميع 30 السياسات المدمجة](https://docs.befailproof.ai/built-in-policies) --- ## سياساتك الخاصة -ضع ملف في `.failproofai/policies/` — يتم تحميله تلقائياً، لا توجد علامات مطلوبة. -قم بالالتزام به وسيحصل الفريق بأكمله عليه في الطلب التالي. +أسقط ملفًا إلى `.failproofai/policies/` — يتم تحميله تلقائيًا، بدون الحاجة إلى أي رايات. +التزم بها وسيحصل الفريق بأكمله عليها في السحب التالي. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -140,13 +169,13 @@ customPolicies.add({ }); ``` -ثلاث قرارات متاحة لكل سياسة: +ثلاثة قرارات متاحة لكل سياسة: | القرار | التأثير | |---|---| | `allow()` | السماح بالعملية | -| `deny(message)` | حجبها — تعود الرسالة إلى الوكيل | -| `instruct(message)` | اسمح بها، لكن أضف سياق إلى موجه الوكيل التالي | +| `deny(message)` | حظرها — الرسالة تعود إلى الوكيل | +| `instruct(message)` | السماح بها، لكن أضف سياقًا إلى الموجه التالي للوكيل | → [دليل السياسات المخصصة](https://docs.befailproof.ai/custom-policies) @@ -154,44 +183,41 @@ customPolicies.add({ ## رؤية الجلسة -يتم تسجيل كل استدعاء أداة يقوم به الوكيل محليًا. لوحة التحكم توضح ما تم تشغيله، -وما تم حجبه، وما قالته السياسة للوكيل — لذلك لا تخمن -عندما يحدث خطأ ما. → [دليل لوحة التحكم](https://docs.befailproof.ai/dashboard) +كل استدعاء أداة يقوم به وكيلك يتم تسجيله محليًا. تعرض لوحة القيادة ما تم تشغيله، +ما تم حظره، وما أخبرت السياسة الوكيل به — حتى لا تخمن +عندما يسير شيء ما بشكل خاطئ. → [دليل لوحة القيادة](https://docs.befailproof.ai/dashboard) --- -## الوثائق +## التوثيق | | | |---|---| | [البدء السريع](https://docs.befailproof.ai/getting-started) | التثبيت والخطوات الأولى | -| [السياسات المدمجة](https://docs.befailproof.ai/built-in-policies) | جميع السياسات الـ 30 مع المعاملات | +| [السياسات المدمجة](https://docs.befailproof.ai/built-in-policies) | جميع 30 السياسات مع المعاملات | | [السياسات المخصصة](https://docs.befailproof.ai/custom-policies) | اكتب الخاصة بك | | [التكوين](https://docs.befailproof.ai/configuration) | نطاقات التكوين وقواعد الدمج | -| [لوحة التحكم](https://docs.befailproof.ai/dashboard) | مراقب الجلسة ونشاط السياسة | -| [العمارة](https://docs.befailproof.ai/architecture) | كيفية عمل نظام الخطاف | +| [لوحة القيادة](https://docs.befailproof.ai/dashboard) | مراقب الجلسة وأنشطة السياسة | +| [العمارة](https://docs.befailproof.ai/architecture) | كيفية عمل نظام الخطاطيف | --- ## الترخيص -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/`. راجع +> [بناء قبل أن تعمل خطاطيف dev داخل المستودع](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- -تم البناء بواسطة [Nivedit Jain](https://github.com/NiveditJain) و[Nikita Agarwal](https://github.com/nk-ag). +مصنوع بواسطة [Nivedit Jain](https://github.com/NiveditJain) و [Nikita Agarwal](https://github.com/nk-ag). [befailproof.ai](https://befailproof.ai) diff --git a/docs/i18n/README.de.md b/docs/i18n/README.de.md index 5c6f03dd..531950d1 100644 --- a/docs/i18n/README.de.md +++ b/docs/i18n/README.de.md @@ -17,8 +17,8 @@ **Ü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-Agents.** -Klinkt sich in Claude Code und Codex ein. Erkennt Endlosschleifen, gefährliche Aktionen und Secret-Leaks, +**Laufzeit-Fehlerbehandlung für Coding-Agenten.** +Klinkt sich in Claude Code und Codex ein. Erkennt Endlosschleifen, gefährliche Aktionen und geheime Datenlecks, bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. @@ -29,67 +29,96 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. --- -## Unterstützte Agent-CLIs +## Unterstützte Agenten-CLIs

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Hooks für eine oder eine beliebige Kombination installieren: `failproofai policies --install --cli opencode pi gemini` (oder `--cli claude codex copilot cursor opencode pi gemini hermes`). `--cli` weglassen, um installierte CLIs automatisch zu erkennen und zur Auswahl aufzufordern. +> Hooks für einen oder mehrere CLIs installieren: `failproofai policies --install --cli opencode pi` (oder `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). `--cli` weglassen, um installierte CLIs automatisch zu erkennen und eine Auswahl anzuzeigen. +> +> **Hermes** (hermes-agent, ein Slack/Telegram-Gateway) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli hermes` — eine einzige Installation fängt Tool-Aufrufe von jeder Plattform und jedem Subagenten ab) als auch für die Offline-**Audit**-Wiedergabe seiner Gateway-Sitzungen aus der einzelnen `~/.hermes/state.db` unterstützt. +> +> **OpenClaw** (openclaw gateway, ein selbst gehosteter Multi-Channel-Assistent) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli openclaw`, Benutzer-Scope) als auch für die Offline-**Audit**-Wiedergabe seiner JSONL-Sitzungen (`~/.openclaw/agents//sessions/*.jsonl`) unterstützt. Die Durchsetzung nutzt OpenClaws **In-Process-Plugin-Hooks** (ein mitgeliefertes `openclaw-plugin/`, das failproofai asynchron startet — dessen dateibasierte interne Hooks dienen nur zur Beobachtung und können nicht blockieren): `before_tool_call` blockiert ein Tool, und `before_agent_finalize` ist ein echtes Schrankentor am Zug-Ende, sodass die eingebauten `require-*-before-stop`-Richtlinien greifen. +> +> **Factory Droid** (`droid`) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli factory`, Benutzer- + Projekt-Scope) als auch für die Offline-**Audit**-Wiedergabe seiner JSONL-Sitzungen auf der Festplatte unterstützt. droid blockiert Tool-Aufrufe per Hook-**Exit-Code 2** (kein JSON-Entscheid) und berücksichtigt `{decision:"block"}` nur beim Zug-End-Ereignis `Stop` — failproofai gibt je nach Ereignis automatisch die richtige Form aus. +> +> **Devin CLI** (`devin`, Cognition) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli devin`, Benutzer- + Projekt-Scope) als auch für die Offline-**Audit**-Wiedergabe seiner SQLite-Sitzungen (`~/.local/share/devin/cli/sessions.db`) unterstützt. Devin ist ein **reiner Claude-Klon** — gleiche Ereignisnamen, gleiche snake_case-Nutzlast, gleiche `"hooks"`-Wrapper-Konfiguration (`~/.config/devin/config.json` / `/.devin/config.json`) — Blockierung via `{decision:"block"}` JSON bei jedem Ereignis. +> +> **Antigravity CLI** (`agy`) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli antigravity`, Benutzer- + Projekt-Scope) als auch für die Offline-**Audit**-Wiedergabe seiner JSONL-Sitzungen (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`) unterstützt. Antigravity hat seinen **eigenen** Vertrag (kein Claude-Klon): ein **named-hook**-`hooks.json`-Schema (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), eine camelCase-stdin-Nutzlast, die failproofai normalisiert, und eigene Antwortformen — `{decision:"deny"}` zum Blockieren eines Tools, `{decision:"continue"}` zum Erzwingen eines weiteren Zugs bei `Stop`, `{injectSteps}` zum Einfügen einer Erinnerung vor dem Modell-Lauf. > -> **Hermes** (hermes-agent, ein Slack/Telegram-Gateway) wird sowohl für **Live-Hook-Durchsetzung** (`--cli hermes` — eine Installation fängt Tool-Aufrufe von jeder Plattform und jedem Subagenten ab) als auch für das Offline-**Audit**-Replay seiner Gateway-Sitzungen aus der einzelnen `~/.hermes/state.db` unterstützt. +> **Goose** (Codename goose, Block) wird sowohl für die **Live-Hook-Durchsetzung** (`--cli goose`, Benutzer- + Projekt-Scope) als auch für die Offline-**Audit**-Wiedergabe seiner SQLite-Sitzungen (`~/.local/share/goose/sessions/sessions.db`) unterstützt. Die Durchsetzung nutzt Gooses **Hooks**-System (die agentenübergreifende **Open-Plugins**-Spezifikation) — das Installationsprogramm legt einfach ein Plugin-Verzeichnis unter `~/.agents/plugins/failproofai/` ab und Goose erkennt es automatisch. Die Blockierung erfolgt per `{"decision":"block"}` JSON beim `PreToolUse`-Ereignis (das beim Shell-Tool und innerhalb delegierter Subagenten ausgelöst wird), live verifiziert gegen goose v1.43.0; Goose hat kein Zug-End-Ereignis `Stop`, daher gelten die eingebauten `require-*-before-stop`-Richtlinien nicht (wie bei Hermes). --- @@ -97,32 +126,32 @@ bevor sie zu Vorfällen werden. Keine Latenz. Läuft lokal. ```sh npm install -g failproofai -failproofai policies --install # oder einfach `failproofai` ausführen und den Erststart-Prompt bestätigen +failproofai policies --install # oder einfach `failproofai` ausführen und die Erststart-Aufforderung bestätigen failproofai ``` -30 integrierte Richtlinien werden sofort aktiviert. Dashboard unter `localhost:8020`. Den Erststart-Prompt mit `FAILPROOFAI_NO_FIRST_RUN=1` deaktivieren. +30 eingebaute Richtlinien werden sofort aktiviert. Dashboard unter `localhost:8020`. Die Erststart-Aufforderung lässt sich mit `FAILPROOFAI_NO_FIRST_RUN=1` deaktivieren. --- ## Was blockiert wird -| Richtlinie | Was wird blockiert | +| Richtlinie | Was blockiert wird | |---|---| | `block-push-master` | Direkte Pushes auf `main` / `master` | | `block-force-push` | `git push --force` | | `block-work-on-main` | Commits, Merges, Rebases auf `main` / `master` | | `block-rm-rf` | Rekursives Löschen von Dateien | -| `sanitize-api-keys` | API-Keys, die in den Agent-Kontext gelangen | +| `sanitize-api-keys` | API-Schlüssel, die in den Agenten-Kontext gelangen | -→ [Alle 30 integrierten Richtlinien](https://docs.befailproof.ai/built-in-policies) +→ [Alle 30 eingebauten Richtlinien](https://docs.befailproof.ai/built-in-policies) --- ## Eigene Richtlinien -Eine Datei in `.failproofai/policies/` ablegen — sie wird automatisch geladen, ohne weitere Flags. -Ins Repository committen und das gesamte Team erhält sie beim nächsten Pull. +Eine Datei in `.failproofai/policies/` ablegen — sie wird automatisch geladen, ohne zusätzliche Flags. +Ins Repository einchecken, und das gesamte Team erhält sie beim nächsten Pull. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -138,23 +167,23 @@ customPolicies.add({ }); ``` -Jede Richtlinie kann eine von drei Entscheidungen treffen: +Jeder Richtlinie stehen drei Entscheidungen zur Verfügung: | Entscheidung | Wirkung | |---|---| -| `allow()` | Operation erlauben | -| `deny(message)` | Blockieren — die Nachricht wird an den Agent zurückgegeben | -| `instruct(message)` | Durchlassen, aber Kontext zum nächsten Prompt des Agents hinzufügen | +| `allow()` | Vorgang zulassen | +| `deny(message)` | Blockieren — Nachricht wird an den Agenten zurückgegeben | +| `instruct(message)` | Durchlassen, aber Kontext zum nächsten Prompt des Agenten hinzufügen | -→ [Anleitung für eigene Richtlinien](https://docs.befailproof.ai/custom-policies) +→ [Leitfaden für eigene Richtlinien](https://docs.befailproof.ai/custom-policies) --- -## Sitzungsübersicht +## Sitzungstransparenz -Jeder Tool-Aufruf des Agents wird lokal protokolliert. Das Dashboard zeigt, was ausgeführt wurde, -was blockiert wurde und was die Richtlinie dem Agent mitgeteilt hat — damit kein Rätseln entsteht, -wenn etwas schiefläuft. → [Dashboard-Anleitung](https://docs.befailproof.ai/dashboard) +Jeder Tool-Aufruf des Agenten wird lokal protokolliert. Das Dashboard zeigt, was ausgeführt wurde, +was blockiert wurde und was die Richtlinie dem Agenten mitgeteilt hat — damit man nicht im Dunkeln tappt, +wenn etwas schiefläuft. → [Dashboard-Leitfaden](https://docs.befailproof.ai/dashboard) --- @@ -162,10 +191,10 @@ wenn etwas schiefläuft. → [Dashboard-Anleitung](https://docs.befailproof.ai/d | | | |---|---| -| [Erste Schritte](https://docs.befailproof.ai/getting-started) | Installation und Einstieg | -| [Integrierte Richtlinien](https://docs.befailproof.ai/built-in-policies) | Alle 30 Richtlinien mit Parametern | -| [Eigene Richtlinien](https://docs.befailproof.ai/custom-policies) | Eigene Richtlinien schreiben | -| [Konfiguration](https://docs.befailproof.ai/configuration) | Konfigurationsbereiche und Zusammenführungsregeln | +| [Erste Schritte](https://docs.befailproof.ai/getting-started) | Installation und erste Schritte | +| [Eingebaute Richtlinien](https://docs.befailproof.ai/built-in-policies) | Alle 30 Richtlinien mit Parametern | +| [Eigene Richtlinien](https://docs.befailproof.ai/custom-policies) | Eigene Richtlinien erstellen | +| [Konfiguration](https://docs.befailproof.ai/configuration) | Konfigurations-Scopes und Zusammenführungsregeln | | [Dashboard](https://docs.befailproof.ai/dashboard) | Sitzungsmonitor und Richtlinienaktivität | | [Architektur](https://docs.befailproof.ai/architecture) | Funktionsweise des Hook-Systems | @@ -173,7 +202,7 @@ wenn etwas schiefläuft. → [Dashboard-Anleitung](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 separate Vereinbarung. Den vollständigen Text in [LICENSE](./LICENSE) nachlesen. +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 findet man in [LICENSE](./LICENSE). --- @@ -181,13 +210,10 @@ MIT mit [Commons Clause](https://commonsclause.com/) — kostenlos für den inte Siehe [CONTRIBUTING.md](./CONTRIBUTING.md). Neue Richtlinien, Randfälle und Übersetzungen sind herzlich willkommen. -> **Vor dem Start bauen.** Zuerst `bun install && bun run build` ausführen. Dieses Repository führt -> die eigenen Hooks von failproofai auf sich selbst aus, und sie lösen den `failproofai`-Import gegen das -> kompilierte `dist/`-Bundle auf — ohne einen Build tritt der Hook-Fehler `Cannot find package 'failproofai'` -> auf. Nach Änderungen an `src/` neu bauen. Siehe +> **Erst bauen, dann starten.** Zunächst `bun install && bun run build` ausführen. 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 treten `Cannot find package 'failproofai'`-Hook-Fehler auf. 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). --- -Entwickelt von [Nivedit Jain](https://github.com/NiveditJain) und [Nikita Agarwal](https://github.com/nk-ag). +Erstellt von [Nivedit Jain](https://github.com/NiveditJain) und [Nikita Agarwal](https://github.com/nk-ag). [befailproof.ai](https://befailproof.ai) diff --git a/docs/i18n/README.es.md b/docs/i18n/README.es.md index 8859f6b9..13b5a5ce 100644 --- a/docs/i18n/README.es.md +++ b/docs/i18n/README.es.md @@ -19,12 +19,12 @@ **Resolución de fallos en tiempo de ejecución para agentes de código.** Se integra con Claude Code y Codex. Detecta bucles, acciones peligrosas y filtraciones de secretos -antes de que se conviertan en incidentes. Cero latencia. Se ejecuta localmente. +antes de que se conviertan en incidentes. Latencia cero. Se ejecuta localmente.

- Failproof AI in action + Failproof AI en acción

--- @@ -35,61 +35,90 @@ antes de que se conviertan en incidentes. Cero latencia. Se ejecuta localmente. Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Instala hooks para uno o cualquier combinación: `failproofai policies --install --cli opencode pi gemini` (o `--cli claude codex copilot cursor opencode pi gemini hermes`). Omite `--cli` para detectar automáticamente los CLIs instalados y recibir una solicitud de confirmación. +> Instala hooks para uno o cualquier combinación: `failproofai policies --install --cli opencode pi` (o `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Omite `--cli` para detectar automáticamente los CLIs instalados y recibir un aviso. +> +> **Hermes** (hermes-agent, una pasarela de Slack/Telegram) es compatible tanto con la **aplicación de hooks en vivo** (`--cli hermes` — una sola instalación intercepta las llamadas de herramientas de cada plataforma y subagente) como con la **auditoría** offline mediante la reproducción de sus sesiones de pasarela desde el único `~/.hermes/state.db`. +> +> **OpenClaw** (openclaw gateway, un asistente multicanal autohospedado) es compatible tanto con la **aplicación de hooks en vivo** (`--cli openclaw`, ámbito de usuario) como con la **auditoría** offline mediante la reproducción de sus sesiones JSONL (`~/.openclaw/agents//sessions/*.jsonl`). La aplicación utiliza los **hooks de plugin en proceso** de OpenClaw (un `openclaw-plugin/` incluido que lanza failproofai de forma asíncrona — sus hooks internos basados en archivos son solo de observación y no pueden bloquear): `before_tool_call` bloquea una herramienta, y `before_agent_finalize` es una barrera real de fin de turno, por lo que los builtins `require-*-before-stop` se aplican. +> +> **Factory Droid** (`droid`) es compatible tanto con la **aplicación de hooks en vivo** (`--cli factory`, ámbito de usuario y proyecto) como con la **auditoría** offline mediante la reproducción de sus sesiones JSONL en disco. droid bloquea llamadas de herramientas a través del **código de salida 2** del hook (no mediante una decisión JSON) y solo respeta `{decision:"block"}` en el evento de fin de turno `Stop` — failproofai emite la forma correcta por evento de manera automática. +> +> **Devin CLI** (`devin`, Cognition) es compatible tanto con la **aplicación de hooks en vivo** (`--cli devin`, ámbito de usuario y proyecto) como con la **auditoría** offline mediante la reproducción de sus sesiones SQLite (`~/.local/share/devin/cli/sessions.db`). Devin es un **clon puro de Claude** — mismos nombres de eventos, mismo payload en snake_case, misma configuración con wrapper `"hooks"` (`~/.config/devin/config.json` / `/.devin/config.json`) — bloqueo mediante JSON `{decision:"block"}` en cada evento. +> +> **Antigravity CLI** (`agy`) es compatible tanto con la **aplicación de hooks en vivo** (`--cli antigravity`, ámbito de usuario y proyecto) como con la **auditoría** offline mediante la reproducción de sus sesiones JSONL simples (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity tiene su **propio** contrato (no es un clon de Claude): un esquema `hooks.json` con **hooks nombrados** (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), un payload stdin en camelCase que failproofai normaliza, y sus propias formas de respuesta — `{decision:"deny"}` para bloquear una herramienta, `{decision:"continue"}` para forzar otro turno en `Stop`, `{injectSteps}` para inyectar un recordatorio antes de que el modelo se ejecute. > -> **Hermes** (hermes-agent, una pasarela de Slack/Telegram) es compatible tanto con la **aplicación de hooks en vivo** (`--cli hermes` — una sola instalación intercepta las llamadas a herramientas desde cada plataforma y subagente) como con la **auditoría** offline de sus sesiones de pasarela desde el único `~/.hermes/state.db`. +> **Goose** (nombre en clave goose, Block) es compatible tanto con la **aplicación de hooks en vivo** (`--cli goose`, ámbito de usuario y proyecto) como con la **auditoría** offline mediante la reproducción de sus sesiones SQLite (`~/.local/share/goose/sessions/sessions.db`). La aplicación utiliza el sistema de **hooks** de Goose (la especificación **Open Plugins** multi-agente) — el instalador simplemente coloca un directorio de plugin en `~/.agents/plugins/failproofai/` y Goose lo detecta automáticamente. El bloqueo se realiza con JSON `{"decision":"block"}` en el evento `PreToolUse` (que se activa para la herramienta shell y dentro de subagentes delegados), verificado en vivo contra goose v1.43.0; Goose no tiene un evento `Stop` de fin de turno, por lo que los builtins `require-*-before-stop` no se aplican (igual que con Hermes). --- @@ -109,7 +138,7 @@ failproofai | Política | Qué bloquea | |---|---| -| `block-push-master` | Pushes directos a `main` / `master` | +| `block-push-master` | Envíos directos a `main` / `master` | | `block-force-push` | `git push --force` | | `block-work-on-main` | Commits, merges y rebases en `main` / `master` | | `block-rm-rf` | Eliminación recursiva de archivos | @@ -121,8 +150,8 @@ failproofai ## Tus propias políticas -Añade un archivo en `.failproofai/policies/` — se carga automáticamente, sin necesidad de flags. -Haz commit y todo el equipo lo obtendrá en el próximo pull. +Coloca un archivo en `.failproofai/policies/` — se carga automáticamente, sin necesidad de flags. +Súbelo al repositorio y todo el equipo lo tendrá en el próximo pull. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -143,18 +172,18 @@ Tres decisiones disponibles para cada política: | Decisión | Efecto | |---|---| | `allow()` | Permite la operación | -| `deny(message)` | La bloquea — el mensaje se envía de vuelta al agente | +| `deny(message)` | La bloquea — el mensaje se devuelve al agente | | `instruct(message)` | La deja pasar, pero añade contexto al siguiente prompt del agente | → [Guía de políticas personalizadas](https://docs.befailproof.ai/custom-policies) --- -## Visibilidad de la sesión +## Visibilidad de sesiones -Cada llamada a herramienta que realiza tu agente se registra localmente. El panel de control muestra qué se ejecutó, -qué fue bloqueado y qué le indicó la política al agente — para que no tengas que adivinar -cuando algo sale mal. → [Guía del panel de control](https://docs.befailproof.ai/dashboard) +Cada llamada de herramienta que realiza tu agente se registra localmente. El panel de control muestra qué se ejecutó, +qué fue bloqueado y qué le indicó la política al agente — así no tendrás que adivinar +qué salió mal. → [Guía del panel de control](https://docs.befailproof.ai/dashboard) --- @@ -163,9 +192,9 @@ cuando algo sale mal. → [Guía del panel de control](https://docs.befailproof. | | | |---|---| | [Primeros pasos](https://docs.befailproof.ai/getting-started) | Instalación y primeros pasos | -| [Políticas integradas](https://docs.befailproof.ai/built-in-policies) | Las 30 políticas con sus parámetros | +| [Políticas integradas](https://docs.befailproof.ai/built-in-policies) | Las 30 políticas con parámetros | | [Políticas personalizadas](https://docs.befailproof.ai/custom-policies) | Escribe las tuyas propias | -| [Configuración](https://docs.befailproof.ai/configuration) | Ámbitos de configuración y reglas de combinación | +| [Configuración](https://docs.befailproof.ai/configuration) | Ámbitos de configuración y reglas de fusión | | [Panel de control](https://docs.befailproof.ai/dashboard) | Monitor de sesiones y actividad de políticas | | [Arquitectura](https://docs.befailproof.ai/architecture) | Cómo funciona el sistema de hooks | @@ -173,19 +202,16 @@ cuando algo sale mal. → [Guía del panel de control](https://docs.befailproof. ## Licencia -MIT con [Commons Clause](https://commonsclause.com/) — gratuito para uso interno y personal; la reventa comercial de failproofai en sí requiere un acuerdo separado. Consulta [LICENSE](./LICENSE) para el texto completo. +MIT con [Commons Clause](https://commonsclause.com/) — de uso gratuito para uso interno y personal; la reventa comercial de failproofai en sí requiere un acuerdo aparte. Consulta [LICENSE](./LICENSE) para el texto completo. --- -## Contribuciones +## Contribuir -Consulta [CONTRIBUTING.md](./CONTRIBUTING.md). Son bienvenidas nuevas políticas, casos límite y traducciones. +Consulta [CONTRIBUTING.md](./CONTRIBUTING.md). Se aceptan nuevas políticas, casos límite y traducciones. -> **Compila antes de empezar.** Ejecuta primero `bun install && bun run build`. Este repositorio ejecuta -> sus 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 `Cannot find package 'failproofai'`. -> Recompila después de modificar `src/`. Consulta -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **Compila antes de empezar.** Ejecuta primero `bun install && bun run build`. Este repositorio ejecuta sus propios hooks de failproofai sobre sí mismo, y resuelven la importación de `failproofai` contra el bundle compilado en `dist/` — sin una compilación obtendrás errores de hook `Cannot find package 'failproofai'`. Vuelve a compilar después de modificar `src/`. Consulta +> [Compila antes de que funcionen los hooks de desarrollo internos del repositorio](./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 47f8ff7e..1b8745c6 100644 --- a/docs/i18n/README.fr.md +++ b/docs/i18n/README.fr.md @@ -17,7 +17,7 @@ **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 code.** +**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 avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. @@ -35,61 +35,90 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Installez les hooks pour un ou plusieurs CLI au choix : `failproofai policies --install --cli opencode pi gemini` (ou `--cli claude codex copilot cursor opencode pi gemini hermes`). Omettez `--cli` pour détecter automatiquement les CLI installés et recevoir une invite de sélection. +> Installez les hooks pour un ou plusieurs CLI à la fois : `failproofai policies --install --cli opencode pi` (ou `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Omettez `--cli` pour détecter automatiquement les CLI installés et être invité à choisir. +> +> **Hermes** (hermes-agent, une passerelle Slack/Telegram) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli hermes` — une seule installation intercepte les appels d'outils de chaque plateforme et sous-agent) et la **relecture en mode audit** hors ligne de ses sessions de passerelle depuis le fichier unique `~/.hermes/state.db`. +> +> **OpenClaw** (openclaw gateway, un assistant multi-canaux auto-hébergé) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli openclaw`, portée utilisateur) et la **relecture en mode audit** hors ligne de ses sessions JSONL (`~/.openclaw/agents//sessions/*.jsonl`). L'application utilise les **hooks de plugin in-process** d'OpenClaw (un `openclaw-plugin/` livré qui lance failproofai de façon asynchrone — ses hooks internes basés sur des fichiers sont en observation uniquement et ne peuvent pas bloquer) : `before_tool_call` bloque un outil, et `before_agent_finalize` est une vraie barrière de fin de tour, donc les fonctions intégrées `require-*-before-stop` s'appliquent. +> +> **Factory Droid** (`droid`) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli factory`, portée utilisateur + projet) et la **relecture en mode audit** hors ligne de ses sessions JSONL sur disque. droid bloque les appels d'outils via le **code de sortie 2** du hook (et non une décision JSON) et ne respecte `{decision:"block"}` que sur l'événement de fin de tour `Stop` — failproofai émet automatiquement la bonne forme selon l'événement. +> +> **Devin CLI** (`devin`, Cognition) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli devin`, portée utilisateur + projet) et la **relecture en mode audit** hors ligne de ses sessions SQLite (`~/.local/share/devin/cli/sessions.db`). Devin est un **clone pur de Claude** — mêmes noms d'événements, même payload en snake_case, même configuration avec wrapper `"hooks"` (`~/.config/devin/config.json` / `/.devin/config.json`) — blocage via `{decision:"block"}` JSON sur chaque événement. +> +> **Antigravity CLI** (`agy`) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli antigravity`, portée utilisateur + projet) et la **relecture en mode audit** hors ligne de ses sessions plain-JSONL (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity possède son **propre** contrat (pas un clone de Claude) : un schéma `hooks.json` avec **hooks nommés** (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), un payload stdin en camelCase que failproofai normalise, et ses propres formes de réponse — `{decision:"deny"}` pour bloquer un outil, `{decision:"continue"}` pour forcer un autre tour à `Stop`, `{injectSteps}` pour injecter un rappel avant l'exécution du modèle. > -> **Hermes** (hermes-agent, une passerelle Slack/Telegram) est pris en charge à la fois pour l'**application des hooks en temps réel** (`--cli hermes` — une seule installation intercepte les appels d'outils de chaque plateforme et sous-agent) et pour la **relecture d'audit** hors ligne de ses sessions de passerelle depuis l'unique `~/.hermes/state.db`. +> **Goose** (nom de code goose, Block) est pris en charge à la fois pour l'**application de hooks en direct** (`--cli goose`, portée utilisateur + projet) et la **relecture en mode audit** hors ligne de ses sessions SQLite (`~/.local/share/goose/sessions/sessions.db`). L'application utilise le système de **hooks** de Goose (la spécification **Open Plugins** inter-agents) — l'installateur dépose simplement un répertoire de plugin dans `~/.agents/plugins/failproofai/` et Goose le détecte automatiquement. Le blocage s'effectue via `{"decision":"block"}` JSON sur l'événement `PreToolUse` (qui se déclenche pour l'outil shell et à l'intérieur des sous-agents délégués), vérifié en direct contre goose v1.43.0 ; Goose ne possède pas d'événement de fin de tour `Stop`, donc les fonctions intégrées `require-*-before-stop` ne s'appliquent pas (comme avec Hermes). --- @@ -97,23 +126,23 @@ avant qu'ils ne deviennent des incidents. Zéro latence. Fonctionne en local. ```sh npm install -g failproofai -failproofai policies --install # or just run `failproofai` and accept the first-run prompt +failproofai policies --install # ou lancez simplement `failproofai` et acceptez l'invite de première exécution failproofai ``` -30 politiques intégrées s'activent immédiatement. Tableau de bord disponible sur `localhost:8020`. Désactivez l'invite au premier démarrage avec `FAILPROOFAI_NO_FIRST_RUN=1`. +30 politiques intégrées s'activent immédiatement. Tableau de bord disponible sur `localhost:8020`. Désactivez l'invite de première exécution avec `FAILPROOFAI_NO_FIRST_RUN=1`. --- ## Ce qu'il bloque -| Politique | Ce qui est bloqué | +| Politique | Ce qu'elle bloque | |---|---| | `block-push-master` | Les pushs directs vers `main` / `master` | | `block-force-push` | `git push --force` | -| `block-work-on-main` | Commits, merges, rebases sur `main` / `master` | -| `block-rm-rf` | Suppression récursive de fichiers | -| `sanitize-api-keys` | Fuites de clés API dans le contexte de l'agent | +| `block-work-on-main` | Les commits, merges et rebases sur `main` / `master` | +| `block-rm-rf` | La suppression récursive de fichiers | +| `sanitize-api-keys` | Les clés API qui fuient dans le contexte de l'agent | → [Les 30 politiques intégrées](https://docs.befailproof.ai/built-in-policies) @@ -121,8 +150,8 @@ failproofai ## Vos propres politiques -Déposez un fichier dans `.failproofai/policies/` — il se charge automatiquement, sans aucun indicateur. -Commitez-le et toute l'équipe en bénéficiera au prochain pull. +Déposez un fichier dans `.failproofai/policies/` — il se charge automatiquement, sans aucun flag. +Commitez-le et toute l'équipe en bénéficie au prochain pull. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -142,9 +171,9 @@ Trois décisions disponibles pour chaque politique : | Décision | Effet | |---|---| -| `allow()` | Autoriser l'opération | -| `deny(message)` | La bloquer — le message est renvoyé à l'agent | -| `instruct(message)` | La laisser passer, mais ajouter du contexte à la prochaine invite de l'agent | +| `allow()` | Autorise l'opération | +| `deny(message)` | La bloque — le message est renvoyé à l'agent | +| `instruct(message)` | La laisse passer, mais ajoute du contexte à la prochaine invite de l'agent | → [Guide des politiques personnalisées](https://docs.befailproof.ai/custom-policies) @@ -152,9 +181,9 @@ Trois décisions disponibles pour chaque politique : ## Visibilité des sessions -Chaque appel d'outil effectué par votre agent est journalisé localement. Le tableau de bord affiche ce qui s'est exécuté, -ce qui a été bloqué, et ce que la politique a transmis à l'agent — afin que vous ne soyez pas dans le flou -en cas de problème. → [Guide du tableau de bord](https://docs.befailproof.ai/dashboard) +Chaque appel d'outil effectué par votre agent est enregistré localement. Le tableau de bord affiche ce qui s'est exécuté, +ce qui a été bloqué et ce que la politique a indiqué à l'agent — vous n'avez plus à deviner +quand quelque chose tourne mal. → [Guide du tableau de bord](https://docs.befailproof.ai/dashboard) --- @@ -179,9 +208,9 @@ MIT avec [Commons Clause](https://commonsclause.com/) — libre pour un usage in ## Contribution -Voir [CONTRIBUTING.md](./CONTRIBUTING.md). 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 d'abord `bun install && bun run build`. Ce dépôt utilise ses propres hooks failproofai sur lui-même, et ils résolvent l'import `failproofai` depuis le bundle `dist/` compilé — sans compilation, vous obtiendrez des erreurs de hook `Cannot find package 'failproofai'`. Recompilez après avoir modifié `src/`. Voir +> **Compilez avant de commencer.** Exécutez d'abord `bun install && bun run build`. Ce dépôt fait tourner 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 toute modification de `src/`. Voir > [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 7022d350..3d3213db 100644 --- a/docs/i18n/README.he.md +++ b/docs/i18n/README.he.md @@ -8,7 +8,7 @@
-failproof ai +failproof ai [![npm](https://img.shields.io/npm/v/failproofai?style=flat-square&color=CB3837)](https://www.npmjs.com/package/failproofai) [![CI](https://img.shields.io/github/actions/workflow/status/failproofai/failproofai/ci.yml?branch=main&style=flat-square&label=CI)](https://github.com/failproofai/failproofai/actions) @@ -19,9 +19,9 @@ **תרגומים:** [简体中文](./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. תופסים לולאות, פעולות מסוכנות ודיווחי סודות -לפני שהם הופכים לתקריות. אפס זיכרון זמני. פועל בעמודה השדורה. +**פתרון כשלי זמן ריצה לסוכני קוד.** +מתחבר ל-Claude Code ו-Codex. תופס לולאות, פעולות מסוכנות ודליפות סודות +לפני שהם הופכים לתקריות. אפס עיכוב. פועל בעל.
@@ -37,61 +37,90 @@ Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> התקן hooks לאחד או לכל שילוב: `failproofai policies --install --cli opencode pi gemini` (או `--cli claude codex copilot cursor opencode pi gemini hermes`). השמט `--cli` לגילוי אוטומטי של CLIs מותקנים ולהנחיה. +> התקן hooks עבור אחד או כל שילוב: `failproofai policies --install --cli opencode pi` (או `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). השמט `--cli` לגילוי אוטומטי של CLIs מותקנים והנחיה. +> +> **Hermes** (hermes-agent, שער Slack/Telegram) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli hermes` — התקנה אחת מיירטת קריאות כלים מכל פלטפורמה וסוכן משנה) ו**ביקורת** לא מקוונת של הפעלות השער שלו מ-`~/.hermes/state.db`. +> +> **OpenClaw** (שער openclaw, עוזר פתוח לכל ערוצים) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli openclaw`, תחום משתמש) ו**ביקורת** לא מקוונת של הפעלות JSONL שלו (`~/.openclaw/agents//sessions/*.jsonl`). אכיפה משתמשת ב**hooks hook לתוך-תהליך** של OpenClaw (plugin משלח שמזווג failproofai באופן אסינכרוני — hooks קבועים קבועים שלו הם תצפית בלבד ולא יכולים לחסום): `before_tool_call` חוסם כלי, ו-`before_agent_finalize` הוא שער תיאום אמיתי, כך שה-builtins `require-*-before-stop` אוכפים. +> +> **Factory Droid** (`droid`) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli factory`, תחום משתמש + פרויקט) ו**ביקורת** לא מקוונת של הפעלות JSONL שלו על הדיסק. droid חוסם קריאות כלים מ-exit code 2 של hook (לא החלטה JSON) וכבד `{decision:"block"}` רק באירוע התיאום `Stop` בסוף - failproofai פולט את הצורה הנכונה לפי אירוע באופן אוטומטי. +> +> **Devin CLI** (`devin`, Cognition) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli devin`, תחום משתמש + פרויקט) ו**ביקורת** לא מקוונת של הפעלות SQLite שלו (`~/.local/share/devin/cli/sessions.db`). Devin הוא **שיבוט Claude טהור** — אותו שמות אירועים, אותו payload snake_case, אותה תצורה `hooks`-wrapper (`~/.config/devin/config.json` / `/.devin/config.json`) — חסימה דרך `{decision:"block"}` JSON בכל אירוע. +> +> **Antigravity CLI** (`agy`) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli antigravity`, תחום משתמש + פרויקט) ו**ביקורת** לא מקוונת של הפעלות plain-JSONL שלו (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity יש **שלו** ערך (לא שיבוט Claude): סכימה `hooks.json` **מקבל-hook** (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), payload stdin camelCase שה-failproofai מנרמל, וצורות תגובה שלו - `{decision:"deny"}` לחסום כלי, `{decision:"continue"}` לכפות סיבוב נוסף ב-`Stop`, `{injectSteps}` להזריק תזכורת לפני שהמודל פועל. > -> **Hermes** (hermes-agent, שער Slack/Telegram) נתמך גם ל**אכיפת hook חי** (`--cli hermes` — התקנה אחת מיירטת קריאות כלים מכל פלטפורמה וסוכן משנה) וגם **ביקורת** במצב לא מקוון של הפעלות השער שלו מ`~/.hermes/state.db` הבודד. +> **Goose** (קוד קוד קוד, Block) נתמך לשתי האפשרויות: **אכיפת hook בזמן אמת** (`--cli goose`, תחום משתמש + פרויקט) ו**ביקורת** לא מקוונת של הפעלות SQLite שלו (`~/.local/share/goose/sessions/sessions.db`). אכיפה משתמשת במערכת **hooks** של Goose (ספק Open Plugins **חוצה-סוכן**) — המתקין פשוט משמיע ספריית plugin ב-`~/.agents/plugins/failproofai/` ו-Goose מגלה אותה באופן אוטומטי. חסימה היא `{"decision":"block"}` JSON באירוע `PreToolUse` (אשר יורה עבור כלי הקליפה ובתוך סוכנים משנים שנדלגו), מאומת בעיתוי אמת מול goose v1.43.0; Goose אין אירוע סוף תיאום `Stop`, כך ה-builtins `require-*-before-stop` לא חלים (כמו ב-Hermes). --- @@ -99,11 +128,11 @@ ```sh npm install -g failproofai -failproofai policies --install # או פשוט הרץ `failproofai` וקבל את ההנחיה בהפעלה ראשונה +failproofai policies --install # או פשוט הרץ `failproofai` והסכם ללחץ הראשון failproofai ``` -30 מדיניויות מובנות מופעלות מיד. לוח בקרה ב-`localhost:8020`. בטל את הנחיית ההפעלה הראשונה עם `FAILPROOFAI_NO_FIRST_RUN=1`. +30 מדיניות מובנות מופעלות מיד. לוח בקרה ב-`localhost:8020`. השבת את הנחיה הריצה הראשונה עם `FAILPROOFAI_NO_FIRST_RUN=1`. --- @@ -111,20 +140,20 @@ failproofai | מדיניות | מה זה חוסם | |---|---| -| `block-push-master` | דחיפה ישירה ל-`main` / `master` | +| `block-push-master` | דחיפות ישירות ל-`main` / `master` | | `block-force-push` | `git push --force` | | `block-work-on-main` | commits, merges, rebases ב-`main` / `master` | | `block-rm-rf` | מחיקת קבצים רקורסיבית | -| `sanitize-api-keys` | API keys דולפים להקשר של סוכן | +| `sanitize-api-keys` | מפתחות API דולפים לשיבוט context | -→ [כל 30 המדיניויות המובנות](https://docs.befailproof.ai/built-in-policies) +→ [כל 30 מדיניות מובנות](https://docs.befailproof.ai/built-in-policies) --- ## המדיניויות שלך -זרוק קובץ ל-`.failproofai/policies/` — הוא טוען באופן אוטומטי, ללא דגלים. -בצע commit וכל הצוות יקבל אותו בפול הבא. +הנח קובץ ל-`.failproofai/policies/` — זה טוען באופן אוטומטי, אין צורך בדגלים. +Commit זה והצוות כולו מקבל את זה בפול הבא. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -134,7 +163,7 @@ customPolicies.add({ match: { events: ["PreToolUse"] }, fn: async (ctx) => { if (ctx.toolInput?.file_path?.includes("production")) - return deny("כתיבה לנתיבי production מחסומה."); + return deny("Writes to production paths are blocked."); return allow(); }, }); @@ -144,19 +173,19 @@ customPolicies.add({ | החלטה | השפעה | |---|---| -| `allow()` | אשר את הפעולה | -| `deny(message)` | חסום אותה — ההודעה חוזרת לסוכן | -| `instruct(message)` | תן לה לעבור, אך הוסף הקשר להנחיה הבאה של הסוכן | +| `allow()` | אפשר את הפעולה | +| `deny(message)` | חסום את זה — ההודעה חוזרת לסוכן | +| `instruct(message)` | תן לזה לעבור, אך הוסף context להנחיה הבאה של הסוכן | -→ [מדריך מדיניויות מותאמות אישית](https://docs.befailproof.ai/custom-policies) +→ [מדריך מדיניויות מותאם אישית](https://docs.befailproof.ai/custom-policies) --- -## גלויות הפעלה +## יכולת צפייה בהפעלה -כל קריאת כלים שהסוכן שלך עושה מתועדת בעמודה השדורה. לוח הבקרה מראה מה רץ, -מה היה חסום, ומה המדיניות אמרה לסוכן — כך שאתה לא מנחש -כשמשהו הולך בצעד הלא נכון. → [מדריך לוח הבקרה](https://docs.befailproof.ai/dashboard) +כל קריאת כלי שהסוכן שלך עושה מתורגלת בעל. לוח הבקרה מראה מה הריץ, +מה חוסם, ומה המדיניות אמרה לסוכן — כך שאתה לא מנחש +כאשר משהו משתבש. → [מדריך לוח בקרה](https://docs.befailproof.ai/dashboard) --- @@ -164,30 +193,30 @@ customPolicies.add({ | | | |---|---| -| [התחלה](https://docs.befailproof.ai/getting-started) | התקנה ושלבים ראשונים | -| [מדיניויות מובנות](https://docs.befailproof.ai/built-in-policies) | כל 30 המדיניויות עם פרמטרים | -| [מדיניויות מותאמות אישית](https://docs.befailproof.ai/custom-policies) | כתוב שלך | -| [תצורה](https://docs.befailproof.ai/configuration) | טווחי תצורה וכללי מיזוג | -| [לוח בקרה](https://docs.befailproof.ai/dashboard) | מוניטור הפעלה ופעילות מדיניות | -| [ארכיטקטורה](https://docs.befailproof.ai/architecture) | איך מערכת ה-hook עובדת | +| [התחלה בעבודה](https://docs.befailproof.ai/getting-started) | התקנה וצעדים ראשונים | +| [מדיניויות מובנות](https://docs.befailproof.ai/built-in-policies) | כל 30 מדיניויות עם פרמטרים | +| [מדיניויות מותאם אישית](https://docs.befailproof.ai/custom-policies) | כתוב שלך | +| [תצורה](https://docs.befailproof.ai/configuration) | תחומים ותצורה וכללי מיזוג | +| [לוח בקרה](https://docs.befailproof.ai/dashboard) | צג הפעלה ופעילות מדיניות | +| [ארכיטקטורה](https://docs.befailproof.ai/architecture) | כיצד מערכת ה-hook פועלת | --- ## רישיון -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` תחילה. המאגר הזה מריץ -> את ה-hooks שלו עצמו, והם פותרים את ייבוא `failproofai` כנגד ה-bundle המחומר `dist/` — -> ללא בנייה תוכל להיתקל בשגיאות hook `Cannot find package 'failproofai'`. בנה מחדש -> לאחר שינוי `src/`. ראה -> [בנה לפני שה-dev hooks בתוך המאגר יעבדו](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **בנה לפני שתתחיל.** הרץ `bun install && bun run build` קודם. repo זה מפעיל +> hooks של failproofai בעצמו, והם פותרים את הייבוא failproofai כנגד +> הצרור `dist/` שהורכב — ללא בנייה תפגע ב-`Cannot find package 'failproofai'` +> שגיאות hook. בנה מחדש לאחר שינוי `src/`. ראה +> [בנה לפני שה-hooks של הפיתוח בתוך-repo יעבדו](./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 d25e5512..829e47aa 100644 --- a/docs/i18n/README.hi.md +++ b/docs/i18n/README.hi.md @@ -18,8 +18,8 @@ **अनुवाद:** [简体中文](./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 में हुक करता है। लूप, खतरनाक कार्यों और सीक्रेट लीक को -पकड़ता है इससे पहले कि वे समस्या बनें। शून्य विलंबता। स्थानीय रूप से चलता है। +Claude Code और Codex में हुक करता है। लूप्स, खतरनाक कार्यों और गोपनीय रिसाव को रोकता है +इससे पहले कि वे समस्याएं बन जाएं। शून्य विलंबता। स्थानीय रूप से चलता है। @@ -35,61 +35,90 @@ Claude Code और Codex में हुक करता है। लूप, Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> एक या किसी भी संयोजन के लिए हुक इंस्टॉल करें: `failproofai policies --install --cli opencode pi gemini` (या `--cli claude codex copilot cursor opencode pi gemini hermes`)। स्वचालित रूप से स्थापित CLIs का पता लगाने और संकेत देने के लिए `--cli` को छोड़ दें। +> एक या किसी भी संयोजन के लिए हुक इंस्टॉल करें: `failproofai policies --install --cli opencode pi` (या `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`)। स्वचालित रूप से इंस्टॉल किए गए CLIs का पता लगाने और प्रॉम्प्ट करने के लिए `--cli` को छोड़ दें। +> +> **Hermes** (hermes-agent, एक Slack/Telegram गेटवे) **लाइव-हुक प्रवर्तन** (`--cli hermes` — एक इंस्टॉल हर प्लेटफॉर्म और सबएजेंट से टूल कॉल को रोकता है) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके गेटवे सेशन को एकल `~/.hermes/state.db` से फिर से चलाएं। +> +> **OpenClaw** (openclaw गेटवे, एक स्व-होस्टेड बहु-चैनल सहायक) **लाइव-हुक प्रवर्तन** (`--cli openclaw`, उपयोगकर्ता-स्कोप) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके JSONL सेशन को फिर से चलाएं (`~/.openclaw/agents//sessions/*.jsonl`)। प्रवर्तन OpenClaw के **इन-प्रक्रिया प्लगइन हुक्स** का उपयोग करता है (एक प्रदान किया गया `openclaw-plugin/` जो failproofai को async-spawn करता है — इसके फाइल-आधारित आंतरिक हुक्स केवल अवलोकन-केवल हैं और ब्लॉक नहीं कर सकते): `before_tool_call` एक टूल को ब्लॉक करता है, और `before_agent_finalize` एक वास्तविक टर्न-अंत गेट है, इसलिए `require-*-before-stop` बिल्ट-इन प्रवर्तित होते हैं। +> +> **Factory Droid** (`droid`) **लाइव-हुक प्रवर्तन** (`--cli factory`, उपयोगकर्ता + प्रोजेक्ट स्कोप) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके ऑन-डिस्क JSONL सेशन को फिर से चलाएं। droid हुक **exit code 2** (एक JSON निर्णय नहीं) से टूल कॉल ब्लॉक करता है और केवल टर्न-अंत `Stop` इवेंट पर `{decision:"block"}` को सम्मानित करता है — failproofai प्रत्येक इवेंट के लिए स्वचालित रूप से सही आकार उत्सर्जित करता है। +> +> **Devin CLI** (`devin`, Cognition) **लाइव-हुक प्रवर्तन** (`--cli devin`, उपयोगकर्ता + प्रोजेक्ट स्कोप) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके SQLite सेशन को फिर से चलाएं (`~/.local/share/devin/cli/sessions.db`)। Devin एक **शुद्ध Claude-क्लोन** है — समान इवेंट नाम, समान snake_case पेलोड, समान `hooks`-रैपर कॉन्फ़िग (`~/.config/devin/config.json` / `/.devin/config.json`) — प्रत्येक इवेंट पर `{decision:"block"}` JSON के माध्यम से ब्लॉक करना। +> +> **Antigravity CLI** (`agy`) **लाइव-हुक प्रवर्तन** (`--cli antigravity`, उपयोगकर्ता + प्रोजेक्ट स्कोप) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके plain-JSONL सेशन को फिर से चलाएं (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`)। Antigravity के अपने अनुबंध हैं (Claude-क्लोन नहीं): एक **नामित-हुक** `hooks.json` स्कीमा (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), एक camelCase stdin पेलोड जो failproofai सामान्य करता है, और इसके अपने प्रतिक्रिया आकार — `{decision:"deny"}` एक टूल ब्लॉक करने के लिए, `{decision:"continue"}` `Stop` पर एक और टर्न के लिए, `{injectSteps}` मॉडल के चलने से पहले एक अनुस्मारक इंजेक्ट करने के लिए। > -> **Hermes** (hermes-agent, एक Slack/Telegram गेटवे) **लाइव-हुक प्रवर्तन** (`--cli hermes` — एक इंस्टॉल प्रत्येक प्लेटफॉर्म और सबएजेंट से टूल कॉल को रोकता है) और इसके गेटवे सत्रों की ऑफलाइन **ऑडिट** रिप्ले दोनों के लिए समर्थित है। +> **Goose** (codename goose, Block) **लाइव-हुक प्रवर्तन** (`--cli goose`, उपयोगकर्ता + प्रोजेक्ट स्कोप) और ऑफलाइन **ऑडिट** के लिए समर्थित है। इसके SQLite सेशन को फिर से चलाएं (`~/.local/share/goose/sessions/sessions.db`)। प्रवर्तन Goose के **hooks** सिस्टम का उपयोग करता है (cross-agent **Open Plugins** spec) — इंस्टॉलर बस एक प्लगइन dir को `~/.agents/plugins/failproofai/` पर ड्रॉप करता है और Goose इसे स्वचालित रूप से खोजता है। ब्लॉकिंग `PreToolUse` इवेंट पर `{"decision":"block"}` JSON है (जो शेल टूल और प्रतिनिधि सबएजेंट के अंदर फायर होता है), goose v1.43.0 के विरुद्ध लाइव सत्यापित; Goose के पास कोई टर्न-अंत `Stop` इवेंट नहीं है, इसलिए `require-*-before-stop` बिल्ट-इन लागू नहीं होते (Hermes की तरह)। --- @@ -97,11 +126,11 @@ Claude Code और Codex में हुक करता है। लूप, ```sh npm install -g failproofai -failproofai policies --install # या बस `failproofai` चलाएं और पहली बार के संकेत को स्वीकार करें +failproofai policies --install # या बस `failproofai` चलाएं और पहली बार चलाने के प्रॉम्प्ट को स्वीकार करें failproofai ``` -30 बिल्ट-इन नीतियां तुरंत सक्रिय हो जाती हैं। `localhost:8020` पर डैशबोर्ड। पहली बार के संकेत को `FAILPROOFAI_NO_FIRST_RUN=1` के साथ अक्षम करें। +30 बिल्ट-इन नीतियां तुरंत सक्रिय होती हैं। डैशबोर्ड `localhost:8020` पर। पहली बार चलाने के प्रॉम्प्ट को अक्षम करें `FAILPROOFAI_NO_FIRST_RUN=1` के साथ। --- @@ -111,18 +140,18 @@ failproofai |---|---| | `block-push-master` | `main` / `master` के लिए सीधे पुश | | `block-force-push` | `git push --force` | -| `block-work-on-main` | `main` / `master` पर प्रतिबद्धता, विलय, रीबेस | -| `block-rm-rf` | पुनरावर्ती फ़ाइल हटाना | -| `sanitize-api-keys` | API कुंजियां एजेंट संदर्भ में लीक हो रही हैं | +| `block-work-on-main` | `main` / `master` पर कमिट, मर्ज, rebase | +| `block-rm-rf` | रिकर्सिव फाइल हटाना | +| `sanitize-api-keys` | एजेंट संदर्भ में API कुंजियों का रिसाव | → [सभी 30 बिल्ट-इन नीतियां](https://docs.befailproof.ai/built-in-policies) --- -## आपकी अपनी नीतियां +## अपनी स्वयं की नीतियां -`.failproofai/policies/` में एक फ़ाइल ड्रॉप करें — यह स्वचालित रूप से लोड होती है, किसी फ्लैग की आवश्यकता नहीं है। -इसे प्रतिबद्ध करें और पूरी टीम को अगले पुल पर यह मिल जाता है। +`.failproofai/policies/` में एक फाइल ड्रॉप करें — यह स्वचालित रूप से लोड होती है, कोई झंडे की आवश्यकता नहीं है। +इसे कमिट करें और पूरी टीम को अगले पुल पर मिलेगा। ```js import { customPolicies, deny, allow } from "failproofai"; @@ -138,55 +167,52 @@ customPolicies.add({ }); ``` -प्रत्येक नीति के लिए तीन निर्णय उपलब्ध हैं: +प्रत्येक नीति के लिए उपलब्ध तीन निर्णय: | निर्णय | प्रभाव | |---|---| | `allow()` | ऑपरेशन की अनुमति दें | | `deny(message)` | इसे ब्लॉक करें — संदेश एजेंट को वापस जाता है | -| `instruct(message)` | इसे जाने दें, लेकिन एजेंट के अगले प्रॉम्प्ट में संदर्भ जोड़ें | +| `instruct(message)` | इसे थ्रू करने दें, लेकिन एजेंट के अगले प्रॉम्प्ट में संदर्भ जोड़ें | → [कस्टम नीतियां गाइड](https://docs.befailproof.ai/custom-policies) --- -## सत्र दृश्यता +## सेशन दृश्यता -आपके एजेंट द्वारा किया जाने वाला प्रत्येक टूल कॉल स्थानीय रूप से लॉग किया जाता है। डैशबोर्ड दिखाता है कि क्या चला, -क्या ब्लॉक किया गया, और नीति ने एजेंट को क्या बताया — इसलिए आप अनुमान नहीं लगा रहे हैं +आपका एजेंट हर टूल कॉल करता है वह स्थानीय रूप से लॉग किया जाता है। डैशबोर्ड दिखाता है कि क्या चलता है, +क्या ब्लॉक किया गया था, और नीति ने एजेंट को क्या बताया — इसलिए आप अनुमान नहीं लगा रहे हैं जब कुछ गलत हो जाता है। → [डैशबोर्ड गाइड](https://docs.befailproof.ai/dashboard) --- -## दस्तावेज़ +## डॉक्यूमेंटेशन | | | |---|---| | [शुरुआत करना](https://docs.befailproof.ai/getting-started) | इंस्टॉलेशन और पहले कदम | | [बिल्ट-इन नीतियां](https://docs.befailproof.ai/built-in-policies) | सभी 30 नीतियां पैरामीटर के साथ | -| [कस्टम नीतियां](https://docs.befailproof.ai/custom-policies) | अपनी खुद की लिखें | +| [कस्टम नीतियां](https://docs.befailproof.ai/custom-policies) | अपनी स्वयं की लिखें | | [कॉन्फ़िगरेशन](https://docs.befailproof.ai/configuration) | कॉन्फ़िग स्कोप और मर्ज नियम | -| [डैशबोर्ड](https://docs.befailproof.ai/dashboard) | सत्र मॉनिटर और नीति गतिविधि | +| [डैशबोर्ड](https://docs.befailproof.ai/dashboard) | सेशन मॉनिटर और नीति गतिविधि | | [आर्किटेक्चर](https://docs.befailproof.ai/architecture) | हुक सिस्टम कैसे काम करता है | --- ## लाइसेंस -[Commons Clause](https://commonsclause.com/) के साथ MIT — आंतरिक और व्यक्तिगत उपयोग के लिए मुफ्त; failproofai का व्यावसायिक पुनर्विक्रय एक अलग समझौते की आवश्यकता है। पूर्ण पाठ के लिए [LICENSE](./LICENSE) देखें। +MIT with [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) देखें। --- -[Nivedit Jain](https://github.com/NiveditJain) और [Nikita Agarwal](https://github.com/nk-ag) द्वारा बनाया गया। +[Nivedit Jain](https://github.com/NiveditJain) और [Nikita Agarwal](https://github.com/nk-ag) द्वारा निर्मित। [befailproof.ai](https://befailproof.ai) diff --git a/docs/i18n/README.it.md b/docs/i18n/README.it.md index c6a4bac7..2a4e9422 100644 --- a/docs/i18n/README.it.md +++ b/docs/i18n/README.it.md @@ -17,9 +17,9 @@ **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 dei guasti di runtime per gli agenti di codice.** -Si integra con Claude Code e Codex. Cattura loop, azioni pericolose e fughe di segreti -prima che diventino incidenti. Latenza zero. Eseguito localmente. +**Risoluzione dei guasti runtime per agenti di codifica.** +Si integra con Claude Code e Codex. Cattura cicli infiniti, azioni pericolose e fughe di segreti +prima che diventino incidenti. Latenza zero. Funziona localmente. @@ -29,67 +29,96 @@ prima che diventino incidenti. Latenza zero. Eseguito localmente. --- -## CLI degli agenti supportati +## CLI di agenti supportati

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Installa gli hook per uno o qualsiasi combinazione: `failproofai policies --install --cli opencode pi gemini` (o `--cli claude codex copilot cursor opencode pi gemini hermes`). Ometti `--cli` per rilevare automaticamente le CLI installate e ricevere un prompt. +> Installa gli hook per uno o una combinazione di questi: `failproofai policies --install --cli opencode pi` (oppure `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Ometti `--cli` per il rilevamento automatico dei CLI installati e un prompt. +> +> **Hermes** (hermes-agent, un gateway Slack/Telegram) è supportato per l'applicazione live degli hook (`--cli hermes` — una sola installazione intercetta le chiamate di strumenti da tutte le piattaforme e subagenti) e per il replay offline di audit dalle sessioni del gateway nel file `~/.hermes/state.db`. +> +> **OpenClaw** (openclaw gateway, un assistente multi-canale self-hosted) è supportato per l'applicazione live degli hook (`--cli openclaw`, scope utente) e per il replay offline di audit delle sessioni JSONL (`~/.openclaw/agents//sessions/*.jsonl`). L'applicazione utilizza i plugin hook in-process di OpenClaw (un `openclaw-plugin/` fornito che spawn in modo asincrono failproofai — i suoi hook interni basati su file sono solo osservativi e non possono bloccare): `before_tool_call` blocca uno strumento, e `before_agent_finalize` è una porta di fine turno vera, quindi i builtin `require-*-before-stop` garantiscono l'applicazione. +> +> **Factory Droid** (`droid`) è supportato per l'applicazione live degli hook (`--cli factory`, scope utente + progetto) e per il replay offline di audit delle sessioni JSONL su disco. droid blocca le chiamate di strumenti dal codice di uscita hook **2** (non una decisione JSON) e onora `{decision:"block"}` solo sull'evento di fine turno `Stop` — failproofai emette automaticamente la forma corretta per ogni evento. +> +> **Devin CLI** (`devin`, Cognition) è supportato per l'applicazione live degli hook (`--cli devin`, scope utente + progetto) e per il replay offline di audit dalle sessioni SQLite (`~/.local/share/devin/cli/sessions.db`). Devin è un clone puro di Claude — stessi nomi di evento, stesso payload snake_case, stessa configurazione del wrapper `"hooks"` (`~/.config/devin/config.json` / `/.devin/config.json`) — il blocco avviene tramite JSON `{decision:"block"}` su ogni evento. +> +> **Antigravity CLI** (`agy`) è supportato per l'applicazione live degli hook (`--cli antigravity`, scope utente + progetto) e per il replay offline di audit dalle sessioni plain-JSONL (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity ha il suo proprio contratto (non un clone di Claude): uno schema hook denominato `hooks.json` (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), un payload stdin camelCase che failproofai normalizza, e le sue proprie forme di risposta — `{decision:"deny"}` per bloccare uno strumento, `{decision:"continue"}` per forzare un altro turno a `Stop`, `{injectSteps}` per iniettare un promemoria prima che il modello sia eseguito. > -> **Hermes** (hermes-agent, un gateway Slack/Telegram) è supportato sia per l'**applicazione dei hook in diretta** (`--cli hermes` — un'unica installazione intercetta le chiamate ai tool da ogni piattaforma e subagente) che per il **controllo** offline della riproduzione delle sue sessioni gateway dal singolo `~/.hermes/state.db`. +> **Goose** (codename goose, Block) è supportato per l'applicazione live degli hook (`--cli goose`, scope utente + progetto) e per il replay offline di audit dalle sessioni SQLite (`~/.local/share/goose/sessions/sessions.db`). L'applicazione utilizza il sistema di hook di Goose (la specifica **Open Plugins** multi-agente) — l'installer semplicemente deposita una directory di plugin in `~/.agents/plugins/failproofai/` e Goose la scopre automaticamente. Il blocco è JSON `{"decision":"block"}` sull'evento `PreToolUse` (che si attiva per lo strumento shell e all'interno di subagenti delegati), verificato dal vivo rispetto a goose v1.43.0; Goose non ha un evento di fine turno `Stop`, quindi i builtin `require-*-before-stop` non si applicano (come con Hermes). --- @@ -97,11 +126,11 @@ prima che diventino incidenti. Latenza zero. Eseguito localmente. ```sh npm install -g failproofai -failproofai policies --install # oppure esegui semplicemente `failproofai` e accetta il prompt al primo avvio +failproofai policies --install # oppure esegui semplicemente `failproofai` e accetta il prompt della prima esecuzione failproofai ``` -30 politiche integrate si attivano immediatamente. Dashboard disponibile su `localhost:8020`. Disabilita il prompt al primo avvio con `FAILPROOFAI_NO_FIRST_RUN=1`. +30 politiche integrate si attivano immediatamente. Dashboard su `localhost:8020`. Disabilita il prompt della prima esecuzione con `FAILPROOFAI_NO_FIRST_RUN=1`. --- @@ -112,17 +141,17 @@ failproofai | `block-push-master` | Push diretti a `main` / `master` | | `block-force-push` | `git push --force` | | `block-work-on-main` | Commit, merge, rebase su `main` / `master` | -| `block-rm-rf` | Eliminazione ricorsiva di file | -| `sanitize-api-keys` | Fughe di chiavi API nel contesto dell'agente | +| `block-rm-rf` | Cancellazione ricorsiva di file | +| `sanitize-api-keys` | Chiavi API che fuggono nel contesto dell'agente | → [Tutte le 30 politiche integrate](https://docs.befailproof.ai/built-in-policies) --- -## Le tue politiche personali +## Tue proprie politiche -Inserisci un file in `.failproofai/policies/` — carica automaticamente, nessun flag necessario. -Committalo e l'intero team lo riceverà al prossimo pull. +Deposita un file in `.failproofai/policies/` — si carica automaticamente, nessun flag necessario. +Eseguine il commit e l'intero team lo avrà al prossimo pull. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -143,8 +172,8 @@ Tre decisioni disponibili per ogni politica: | Decisione | Effetto | |---|---| | `allow()` | Permetti l'operazione | -| `deny(message)` | Bloccala — il messaggio torna all'agente | -| `instruct(message)` | Lasciarla passare, ma aggiungi contesto al prossimo prompt dell'agente | +| `deny(message)` | Blocca — il messaggio torna all'agente | +| `instruct(message)` | Lascia passare, ma aggiungi contesto al prossimo prompt dell'agente | → [Guida alle politiche personalizzate](https://docs.befailproof.ai/custom-policies) @@ -152,9 +181,9 @@ Tre decisioni disponibili per ogni politica: ## Visibilità della sessione -Ogni chiamata ai tool effettuata dal tuo agente viene registrata localmente. Il dashboard mostra -cosa è stato eseguito, cosa è stato bloccato e cosa ha detto la politica all'agente — così non devi -indovinare quando qualcosa va male. → [Guida al dashboard](https://docs.befailproof.ai/dashboard) +Ogni chiamata di strumento che il tuo agente effettua viene registrata localmente. La dashboard mostra cosa è stato eseguito, +cosa è stato bloccato e cosa la politica ha detto all'agente — quindi non stai indovinando +quando qualcosa va male. → [Guida della dashboard](https://docs.befailproof.ai/dashboard) --- @@ -162,28 +191,32 @@ indovinare quando qualcosa va male. → [Guida al dashboard](https://docs.befail | | | |---|---| -| [Per Iniziare](https://docs.befailproof.ai/getting-started) | Installazione e primi passi | -| [Politiche Integrate](https://docs.befailproof.ai/built-in-policies) | Tutte le 30 politiche con parametri | -| [Politiche Personalizzate](https://docs.befailproof.ai/custom-policies) | Scrivi le tue | -| [Configurazione](https://docs.befailproof.ai/configuration) | Ambiti di configurazione e regole di merge | -| [Dashboard](https://docs.befailproof.ai/dashboard) | Monitor delle sessioni e attività delle politiche | -| [Architettura](https://docs.befailproof.ai/architecture) | Come funziona il sistema di hook | +| [Getting Started](https://docs.befailproof.ai/getting-started) | Installazione e primi passi | +| [Built-in Policies](https://docs.befailproof.ai/built-in-policies) | Tutte le 30 politiche con parametri | +| [Custom Policies](https://docs.befailproof.ai/custom-policies) | Scrivi le tue | +| [Configuration](https://docs.befailproof.ai/configuration) | Scope di configurazione e regole di merge | +| [Dashboard](https://docs.befailproof.ai/dashboard) | Monitor di sessione e attività della politica | +| [Architecture](https://docs.befailproof.ai/architecture) | Come funziona il sistema di hook | --- ## Licenza -MIT con [Commons Clause](https://commonsclause.com/) — gratuito per uso interno e personale; la rivendita commerciale di failproofai stesso richiede un accordo separato. Consulta [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 benvenuti. +Vedi [CONTRIBUTING.md](./CONTRIBUTING.md). Nuove politiche, casi limite e traduzioni sono tutti benvenuti. -> **Compila prima di iniziare.** Esegui prima `bun install && bun run build`. 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/`. Consulta [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **Compila prima di iniziare.** Esegui `bun install && bun run build` per primo. Questo repository esegue +> i propri hook di failproofai su se stesso, e risolvono l'import `failproofai` rispetto al +> bundle compilato `dist/` — senza una compilazione otterrai errori hook `Cannot find package 'failproofai'`. +> Ricompila dopo aver modificato `src/`. Vedi +> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). --- -Realizzato da [Nivedit Jain](https://github.com/NiveditJain) e [Nikita Agarwal](https://github.com/nk-ag). +Creato da [Nivedit Jain](https://github.com/NiveditJain) e [Nikita Agarwal](https://github.com/nk-ag). [befailproof.ai](https://befailproof.ai) diff --git a/docs/i18n/README.ja.md b/docs/i18n/README.ja.md index 521e8204..e45a3876 100644 --- a/docs/i18n/README.ja.md +++ b/docs/i18n/README.ja.md @@ -17,9 +17,9 @@ **翻訳:** [简体中文](./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 にフックして、ループ・危険な操作・シークレット漏洩を -インシデントになる前に検知。レイテンシーゼロ。ローカルで動作。 +**コーディングエージェントのランタイム障害をその場で解決。** +Claude Code と Codex にフックして、ループ・危険な操作・シークレットの漏洩を +インシデントになる前にキャッチします。レイテンシーゼロ。ローカルで動作。 @@ -35,61 +35,90 @@ Claude Code と Codex にフックして、ループ・危険な操作・シー Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> 1つまたは任意の組み合わせでフックをインストールできます: `failproofai policies --install --cli opencode pi gemini`(または `--cli claude codex copilot cursor opencode pi gemini hermes`)。`--cli` を省略するとインストール済み CLI を自動検出してプロンプトを表示します。 +> 1つまたは複数の組み合わせでフックをインストールできます: `failproofai policies --install --cli opencode pi`(または `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`)。`--cli` を省略すると、インストール済みの CLI を自動検出してプロンプトが表示されます。 +> +> **Hermes**(hermes-agent、Slack/Telegram ゲートウェイ)は、**ライブフック適用**(`--cli hermes` — 1回のインストールですべてのプラットフォームとサブエージェントのツール呼び出しをインターセプト)とゲートウェイセッションのオフライン**監査**リプレイ(単一の `~/.hermes/state.db` から)の両方に対応しています。 +> +> **OpenClaw**(openclaw gateway、セルフホスト型マルチチャネルアシスタント)は、**ライブフック適用**(`--cli openclaw`、ユーザースコープ)と JSONL セッションのオフライン**監査**リプレイ(`~/.openclaw/agents//sessions/*.jsonl`)の両方に対応しています。適用には OpenClaw の**インプロセスプラグインフック**を使用します(同梱の `openclaw-plugin/` が failproofai を非同期でスポーン — ファイルベースの内部フックは観察のみで、ブロックはできません): `before_tool_call` でツールをブロックし、`before_agent_finalize` は実際のターン終了ゲートとして機能するため、`require-*-before-stop` ビルトインが有効です。 +> +> **Factory Droid**(`droid`)は、**ライブフック適用**(`--cli factory`、ユーザー + プロジェクトスコープ)とオンディスク JSONL セッションのオフライン**監査**リプレイの両方に対応しています。droid はフックの**終了コード 2**でツール呼び出しをブロックし(JSON による判定ではない)、ターン終了の `Stop` イベントでのみ `{decision:"block"}` を受け付けます — failproofai はイベントごとに自動的に適切な形式を出力します。 +> +> **Devin CLI**(`devin`、Cognition)は、**ライブフック適用**(`--cli devin`、ユーザー + プロジェクトスコープ)と SQLite セッションのオフライン**監査**リプレイ(`~/.local/share/devin/cli/sessions.db`)の両方に対応しています。Devin は **Claude の完全なクローン** — 同じイベント名、同じ snake_case ペイロード、同じ `"hooks"` ラッパー設定(`~/.config/devin/config.json` / `/.devin/config.json`)— すべてのイベントで `{decision:"block"}` JSON によるブロックに対応しています。 +> +> **Antigravity CLI**(`agy`)は、**ライブフック適用**(`--cli antigravity`、ユーザー + プロジェクトスコープ)とプレーン JSONL セッションのオフライン**監査**リプレイ(`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`)の両方に対応しています。Antigravity は**独自の**コントラクトを持ちます(Claude クローンではありません): **名前付きフック** `hooks.json` スキーマ(`~/.gemini/config/hooks.json` / `/.agents/hooks.json`)、failproofai が正規化する camelCase の stdin ペイロード、および独自のレスポンス形式 — ツールのブロックには `{decision:"deny"}`、`Stop` 時に別のターンを強制するには `{decision:"continue"}`、モデル実行前にリマインダーを挿入するには `{injectSteps}` を使用します。 > -> **Hermes**(hermes-agent、Slack/Telegram ゲートウェイ)は、**ライブフック強制実行**(`--cli hermes` — 1回のインストールですべてのプラットフォームとサブエージェントのツール呼び出しをインターセプト)と、単一の `~/.hermes/state.db` からのゲートウェイセッションのオフライン**監査**リプレイの両方に対応しています。 +> **Goose**(コードネーム goose、Block 社)は、**ライブフック適用**(`--cli goose`、ユーザー + プロジェクトスコープ)と SQLite セッションのオフライン**監査**リプレイ(`~/.local/share/goose/sessions/sessions.db`)の両方に対応しています。適用には Goose の**フック**システム(クロスエージェントの **Open Plugins** 仕様)を使用します — インストーラーが `~/.agents/plugins/failproofai/` にプラグインディレクトリを配置するだけで、Goose が自動検出します。ブロックは `PreToolUse` イベントで `{"decision":"block"}` JSON を使用します(シェルツールおよび委譲されたサブエージェント内でも発火します)。goose v1.43.0 で実際に確認済みです。Goose にはターン終了の `Stop` イベントがないため、`require-*-before-stop` ビルトインは適用されません(Hermes と同様)。 --- @@ -97,17 +126,17 @@ Claude Code と Codex にフックして、ループ・危険な操作・シー ```sh npm install -g failproofai -failproofai policies --install # または `failproofai` を実行して初回起動プロンプトに同意 +failproofai policies --install # または `failproofai` を実行して初回起動プロンプトに従う failproofai ``` -30個の組み込みポリシーが即座に有効化されます。ダッシュボードは `localhost:8020` で確認できます。`FAILPROOFAI_NO_FIRST_RUN=1` を設定すると初回起動プロンプトを無効化できます。 +30 個のビルトインポリシーが即座に有効になります。ダッシュボードは `localhost:8020` で確認できます。`FAILPROOFAI_NO_FIRST_RUN=1` を設定すると初回起動プロンプトを無効化できます。 --- -## ブロックされる操作 +## 防止できること -| ポリシー | ブロックされる内容 | +| ポリシー | ブロックする操作 | |---|---| | `block-push-master` | `main` / `master` への直接プッシュ | | `block-force-push` | `git push --force` | @@ -115,14 +144,14 @@ failproofai | `block-rm-rf` | 再帰的なファイル削除 | | `sanitize-api-keys` | エージェントコンテキストへの API キー漏洩 | -→ [組み込みポリシー一覧(全30件)](https://docs.befailproof.ai/built-in-policies) +→ [全 30 件のビルトインポリシー](https://docs.befailproof.ai/built-in-policies) --- ## 独自ポリシーの作成 -`.failproofai/policies/` にファイルを置くだけで自動的に読み込まれます。フラグは不要です。 -コミットすればチーム全員が次回の pull 時に取得できます。 +`.failproofai/policies/` にファイルを配置するだけで自動的に読み込まれます。フラグは不要です。 +コミットすれば、次回プル時にチーム全員に反映されます。 ```js import { customPolicies, deny, allow } from "failproofai"; @@ -138,7 +167,7 @@ customPolicies.add({ }); ``` -各ポリシーで使用できる3つの判定: +すべてのポリシーで利用できる3つの判定: | 判定 | 効果 | |---|---| @@ -152,7 +181,7 @@ customPolicies.add({ ## セッションの可視化 -エージェントが行ったすべてのツール呼び出しはローカルに記録されます。ダッシュボードでは実行内容・ブロックされた内容・ポリシーがエージェントに伝えた内容を確認できるため、何か問題が起きたときに推測に頼る必要がありません。→ [ダッシュボードガイド](https://docs.befailproof.ai/dashboard) +エージェントが行ったすべてのツール呼び出しはローカルに記録されます。ダッシュボードでは、実行された内容・ブロックされた内容・ポリシーがエージェントに伝えた内容を確認できるため、問題発生時に推測に頼る必要がありません。→ [ダッシュボードガイド](https://docs.befailproof.ai/dashboard) --- @@ -161,7 +190,7 @@ customPolicies.add({ | | | |---|---| | [はじめに](https://docs.befailproof.ai/getting-started) | インストールと最初のステップ | -| [組み込みポリシー](https://docs.befailproof.ai/built-in-policies) | パラメーター付き全30ポリシー | +| [ビルトインポリシー](https://docs.befailproof.ai/built-in-policies) | パラメータ付き全 30 ポリシー | | [カスタムポリシー](https://docs.befailproof.ai/custom-policies) | 独自ポリシーの作成方法 | | [設定](https://docs.befailproof.ai/configuration) | 設定スコープとマージルール | | [ダッシュボード](https://docs.befailproof.ai/dashboard) | セッションモニターとポリシーアクティビティ | @@ -171,17 +200,17 @@ 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/` を変更した後は再ビルドしてください。詳細は [Build before the in-repo dev hooks will work](./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) を参照してください。 --- -[Nivedit Jain](https://github.com/NiveditJain) と [Nikita Agarwal](https://github.com/nk-ag) により開発。 +[Nivedit Jain](https://github.com/NiveditJain) と [Nikita Agarwal](https://github.com/nk-ag) によって開発されました。 [befailproof.ai](https://befailproof.ai) diff --git a/docs/i18n/README.ko.md b/docs/i18n/README.ko.md index 2b49b7e7..1790f5ad 100644 --- a/docs/i18n/README.ko.md +++ b/docs/i18n/README.ko.md @@ -17,9 +17,9 @@ **번역:** [简体中文](./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에 연동됩니다. 루프, 위험한 동작, 시크릿 유출을 -인시던트가 되기 전에 차단합니다. 지연 시간 없음. 로컬에서 실행. +인시던트로 번지기 전에 차단합니다. 지연 없음. 로컬 실행. @@ -29,67 +29,96 @@ Claude Code 및 Codex에 연동됩니다. 루프, 위험한 동작, 시크릿 --- -## 지원하는 에이전트 CLI +## 지원되는 에이전트 CLI

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> 하나 또는 여러 CLI를 조합하여 훅을 설치할 수 있습니다: `failproofai policies --install --cli opencode pi gemini` (또는 `--cli claude codex copilot cursor opencode pi gemini hermes`). `--cli`를 생략하면 설치된 CLI를 자동으로 감지하고 선택을 안내합니다. +> 하나 또는 여러 CLI를 조합하여 훅을 설치할 수 있습니다: `failproofai policies --install --cli opencode pi` (또는 `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). `--cli`를 생략하면 설치된 CLI를 자동으로 감지하고 선택을 묻습니다. +> +> **Hermes** (hermes-agent, Slack/Telegram 게이트웨이)는 **라이브 훅 적용** (`--cli hermes` — 한 번의 설치로 모든 플랫폼과 서브에이전트의 툴 호출을 가로챔)과 단일 `~/.hermes/state.db`에서 게이트웨이 세션의 오프라인 **감사** 재생 모두를 지원합니다. +> +> **OpenClaw** (openclaw gateway, 셀프호스팅 멀티채널 어시스턴트)는 **라이브 훅 적용** (`--cli openclaw`, 사용자 범위)과 JSONL 세션(`~/.openclaw/agents//sessions/*.jsonl`)의 오프라인 **감사** 재생 모두를 지원합니다. 적용은 OpenClaw의 **인-프로세스 플러그인 훅** (failproofai를 비동기로 실행하는 `openclaw-plugin/` 포함)을 사용합니다 — 파일 기반 내부 훅은 관찰 전용으로 차단 불가: `before_tool_call`은 툴을 차단하고, `before_agent_finalize`는 실제 턴 종료 게이트이므로 `require-*-before-stop` 내장 정책이 적용됩니다. +> +> **Factory Droid** (`droid`)는 **라이브 훅 적용** (`--cli factory`, 사용자 + 프로젝트 범위)과 온디스크 JSONL 세션의 오프라인 **감사** 재생 모두를 지원합니다. droid는 훅 **종료 코드 2** (JSON 결정 아님)로 툴 호출을 차단하며, 턴 종료 `Stop` 이벤트에서만 `{decision:"block"}`을 적용합니다 — failproofai는 이벤트별로 올바른 형식을 자동으로 내보냅니다. +> +> **Devin CLI** (`devin`, Cognition)는 **라이브 훅 적용** (`--cli devin`, 사용자 + 프로젝트 범위)과 SQLite 세션(`~/.local/share/devin/cli/sessions.db`)의 오프라인 **감사** 재생 모두를 지원합니다. Devin은 **순수 Claude 클론** — 동일한 이벤트 이름, 동일한 snake_case 페이로드, 동일한 `"hooks"` 래퍼 설정(`~/.config/devin/config.json` / `/.devin/config.json`) — 모든 이벤트에서 `{decision:"block"}` JSON으로 차단합니다. +> +> **Antigravity CLI** (`agy`)는 **라이브 훅 적용** (`--cli antigravity`, 사용자 + 프로젝트 범위)과 플레인 JSONL 세션(`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`)의 오프라인 **감사** 재생 모두를 지원합니다. Antigravity는 **자체** 계약(Claude 클론 아님)을 가집니다: **named-hook** `hooks.json` 스키마(`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), failproofai가 정규화하는 camelCase stdin 페이로드, 자체 응답 형식 — 툴 차단은 `{decision:"deny"}`, Stop 시 추가 턴 강제는 `{decision:"continue"}`, 모델 실행 전 리마인더 주입은 `{injectSteps}`. > -> **Hermes** (hermes-agent, Slack/Telegram 게이트웨이)는 **실시간 훅 적용** (`--cli hermes` — 한 번의 설치로 모든 플랫폼과 서브에이전트의 툴 호출을 가로챔)과 단일 `~/.hermes/state.db`의 게이트웨이 세션 오프라인 **감사** 재생을 모두 지원합니다. +> **Goose** (codename goose, Block)는 **라이브 훅 적용** (`--cli goose`, 사용자 + 프로젝트 범위)과 SQLite 세션(`~/.local/share/goose/sessions/sessions.db`)의 오프라인 **감사** 재생 모두를 지원합니다. 적용은 Goose의 **훅** 시스템(크로스 에이전트 **Open Plugins** 스펙)을 사용 — 설치 시 `~/.agents/plugins/failproofai/`에 플러그인 디렉토리를 생성하고 Goose가 자동으로 감지합니다. 차단은 `PreToolUse` 이벤트(셸 툴 및 위임된 서브에이전트 내부에서 발생)에서 `{"decision":"block"}` JSON을 사용하며, goose v1.43.0에서 라이브 검증되었습니다; Goose에는 턴 종료 `Stop` 이벤트가 없으므로 `require-*-before-stop` 내장 정책은 적용되지 않습니다(Hermes와 동일). --- @@ -97,32 +126,32 @@ Claude Code 및 Codex에 연동됩니다. 루프, 위험한 동작, 시크릿 ```sh npm install -g failproofai -failproofai policies --install # 또는 `failproofai`를 실행하고 최초 실행 프롬프트에 동의 +failproofai policies --install # 또는 `failproofai`를 실행하고 최초 실행 프롬프트에서 수락 failproofai ``` -30개의 기본 제공 정책이 즉시 활성화됩니다. 대시보드는 `localhost:8020`에서 확인할 수 있습니다. `FAILPROOFAI_NO_FIRST_RUN=1`로 최초 실행 프롬프트를 비활성화할 수 있습니다. +30개의 내장 정책이 즉시 활성화됩니다. 대시보드는 `localhost:8020`에서 확인하세요. 최초 실행 프롬프트는 `FAILPROOFAI_NO_FIRST_RUN=1`로 비활성화할 수 있습니다. --- -## 차단하는 항목 +## 차단 대상 | 정책 | 차단 내용 | |---|---| -| `block-push-master` | `main` / `master`에 직접 푸시 | +| `block-push-master` | `main` / `master`로의 직접 푸시 | | `block-force-push` | `git push --force` | | `block-work-on-main` | `main` / `master`에서의 커밋, 머지, 리베이스 | | `block-rm-rf` | 재귀적 파일 삭제 | -| `sanitize-api-keys` | 에이전트 컨텍스트로 유출되는 API 키 | +| `sanitize-api-keys` | 에이전트 컨텍스트에 유출되는 API 키 | -→ [30개 기본 제공 정책 전체 목록](https://docs.befailproof.ai/built-in-policies) +→ [30개 내장 정책 전체 목록](https://docs.befailproof.ai/built-in-policies) --- -## 커스텀 정책 +## 나만의 정책 작성 -`.failproofai/policies/` 디렉토리에 파일을 추가하면 별도의 플래그 없이 자동으로 로드됩니다. -커밋해두면 다음 풀 시 팀 전체에 적용됩니다. +`.failproofai/policies/`에 파일을 넣으면 자동으로 로드됩니다 — 별도 플래그 불필요. +커밋하면 팀 전원이 다음 풀 시 적용받습니다. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -138,12 +167,12 @@ customPolicies.add({ }); ``` -모든 정책에서 사용할 수 있는 세 가지 결정: +모든 정책에서 사용 가능한 세 가지 결정: | 결정 | 효과 | |---|---| | `allow()` | 작업 허용 | -| `deny(message)` | 차단 — 메시지가 에이전트에 반환됨 | +| `deny(message)` | 차단 — 메시지가 에이전트로 반환됨 | | `instruct(message)` | 통과 허용, 단 에이전트의 다음 프롬프트에 컨텍스트 추가 | → [커스텀 정책 가이드](https://docs.befailproof.ai/custom-policies) @@ -152,9 +181,9 @@ customPolicies.add({ ## 세션 가시성 -에이전트가 수행하는 모든 툴 호출은 로컬에 기록됩니다. 대시보드에서는 실행된 내용, -차단된 내용, 정책이 에이전트에 전달한 내용을 확인할 수 있어 — 문제가 발생했을 때 -추측할 필요가 없습니다. → [대시보드 가이드](https://docs.befailproof.ai/dashboard) +에이전트가 수행하는 모든 툴 호출은 로컬에 기록됩니다. 대시보드에서 실행된 항목, +차단된 항목, 정책이 에이전트에 전달한 내용을 확인할 수 있어 — 문제가 발생했을 때 +추측하지 않아도 됩니다. → [대시보드 가이드](https://docs.befailproof.ai/dashboard) --- @@ -162,8 +191,8 @@ customPolicies.add({ | | | |---|---| -| [시작하기](https://docs.befailproof.ai/getting-started) | 설치 및 첫 번째 단계 | -| [기본 제공 정책](https://docs.befailproof.ai/built-in-policies) | 파라미터 포함 30개 정책 전체 목록 | +| [시작하기](https://docs.befailproof.ai/getting-started) | 설치 및 첫 단계 | +| [내장 정책](https://docs.befailproof.ai/built-in-policies) | 매개변수를 포함한 30개 정책 전체 | | [커스텀 정책](https://docs.befailproof.ai/custom-policies) | 직접 작성하기 | | [설정](https://docs.befailproof.ai/configuration) | 설정 범위 및 병합 규칙 | | [대시보드](https://docs.befailproof.ai/dashboard) | 세션 모니터 및 정책 활동 | @@ -173,7 +202,7 @@ customPolicies.add({ ## 라이선스 -[Commons Clause](https://commonsclause.com/)가 적용된 MIT 라이선스 — 내부 및 개인 사용은 무료이며, failproofai 자체의 상업적 재판매는 별도 계약이 필요합니다. 전문은 [LICENSE](./LICENSE)를 참조하세요. +MIT with [Commons Clause](https://commonsclause.com/) — 내부 및 개인 사용은 무료; failproofai 자체의 상업적 재판매는 별도 계약이 필요합니다. 전문은 [LICENSE](./LICENSE)를 참고하세요. --- @@ -181,10 +210,7 @@ customPolicies.add({ [CONTRIBUTING.md](./CONTRIBUTING.md)를 참고하세요. 새로운 정책, 엣지 케이스, 번역 모두 환영합니다. -> **시작 전에 빌드하세요.** 먼저 `bun install && bun run build`를 실행하세요. 이 저장소는 -> failproofai 자체 훅을 자기 자신에게 적용하며, 컴파일된 `dist/` 번들에서 `failproofai` 임포트를 해석합니다 — -> 빌드 없이는 `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.pt-br.md b/docs/i18n/README.pt-br.md index 967087e9..33d2af98 100644 --- a/docs/i18n/README.pt-br.md +++ b/docs/i18n/README.pt-br.md @@ -19,7 +19,7 @@ **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 -antes que se tornem incidentes. Latência zero. Roda localmente. +antes que se tornem incidentes. Latência zero. Executa localmente. @@ -35,61 +35,90 @@ antes que se tornem incidentes. Latência zero. Roda localmente. Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Instale hooks para um ou qualquer combinação: `failproofai policies --install --cli opencode pi gemini` (ou `--cli claude codex copilot cursor opencode pi gemini hermes`). Omita `--cli` para detectar automaticamente os CLIs instalados e ser solicitado a escolher. +> Instale hooks para um ou qualquer combinação: `failproofai policies --install --cli opencode pi` (ou `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Omita `--cli` para detectar automaticamente os CLIs instalados e exibir um prompt. +> +> **Hermes** (hermes-agent, um gateway Slack/Telegram) é suportado tanto para **imposição de hooks ao vivo** (`--cli hermes` — uma única instalação intercepta chamadas de ferramentas de todas as plataformas e subagentes) quanto para **auditoria** offline com replay de suas sessões de gateway a partir do único `~/.hermes/state.db`. +> +> **OpenClaw** (openclaw gateway, um assistente multicanal auto-hospedado) é suportado tanto para **imposição de hooks ao vivo** (`--cli openclaw`, escopo de usuário) quanto para **auditoria** offline com replay de suas sessões JSONL (`~/.openclaw/agents//sessions/*.jsonl`). A imposição utiliza os **hooks de plugin in-process** do OpenClaw (um `openclaw-plugin/` incluído que invoca failproofai de forma assíncrona — seus hooks internos baseados em arquivo são apenas observação e não podem bloquear): `before_tool_call` bloqueia uma ferramenta, e `before_agent_finalize` é um portão real de fim de turno, portanto os builtins `require-*-before-stop` são aplicados. +> +> **Factory Droid** (`droid`) é suportado tanto para **imposição de hooks ao vivo** (`--cli factory`, escopo de usuário + projeto) quanto para **auditoria** offline com replay de suas sessões JSONL em disco. O droid bloqueia chamadas de ferramentas com **código de saída 2** do hook (não uma decisão JSON) e respeita `{decision:"block"}` apenas no evento `Stop` de fim de turno — failproofai emite o formato correto por evento automaticamente. +> +> **Devin CLI** (`devin`, Cognition) é suportado tanto para **imposição de hooks ao vivo** (`--cli devin`, escopo de usuário + projeto) quanto para **auditoria** offline com replay de suas sessões SQLite (`~/.local/share/devin/cli/sessions.db`). Devin é um **clone puro do Claude** — mesmos nomes de eventos, mesmo payload em snake_case, mesma configuração com wrapper `"hooks"` (`~/.config/devin/config.json` / `/.devin/config.json`) — bloqueio via JSON `{decision:"block"}` em todos os eventos. +> +> **Antigravity CLI** (`agy`) é suportado tanto para **imposição de hooks ao vivo** (`--cli antigravity`, escopo de usuário + projeto) quanto para **auditoria** offline com replay de suas sessões em JSONL simples (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). O Antigravity possui seu **próprio** contrato (não é um clone do Claude): um esquema `hooks.json` com **hooks nomeados** (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), um payload stdin em camelCase que failproofai normaliza, e seus próprios formatos de resposta — `{decision:"deny"}` para bloquear uma ferramenta, `{decision:"continue"}` para forçar outro turno no `Stop`, `{injectSteps}` para injetar um lembrete antes de o modelo ser executado. > -> **Hermes** (hermes-agent, um gateway para Slack/Telegram) é suportado tanto para **aplicação de hooks em tempo real** (`--cli hermes` — uma única instalação intercepta chamadas de ferramentas de todas as plataformas e subagentes) quanto para **auditoria** offline a partir de sessões do gateway gravadas no `~/.hermes/state.db`. +> **Goose** (codinome goose, Block) é suportado tanto para **imposição de hooks ao vivo** (`--cli goose`, escopo de usuário + projeto) quanto para **auditoria** offline com replay de suas sessões SQLite (`~/.local/share/goose/sessions/sessions.db`). A imposição utiliza o sistema de **hooks** do Goose (a especificação **Open Plugins** cross-agent) — o instalador apenas cria um diretório de plugin em `~/.agents/plugins/failproofai/` e o Goose o detecta automaticamente. O bloqueio é feito com JSON `{"decision":"block"}` no evento `PreToolUse` (que dispara para a ferramenta shell e dentro de subagentes delegados), verificado ao vivo contra o goose v1.43.0; o Goose não possui evento `Stop` de fim de turno, portanto os builtins `require-*-before-stop` não se aplicam (assim como no Hermes). --- @@ -97,15 +126,15 @@ antes que se tornem incidentes. Latência zero. Roda localmente. ```sh npm install -g failproofai -failproofai policies --install # ou simplesmente execute `failproofai` e aceite o prompt da primeira execução +failproofai policies --install # ou simplesmente execute `failproofai` e aceite o prompt de primeira execução failproofai ``` -30 políticas nativas são ativadas imediatamente. Dashboard disponível em `localhost:8020`. Desative o prompt da primeira execução com `FAILPROOFAI_NO_FIRST_RUN=1`. +30 políticas integradas são ativadas imediatamente. Dashboard em `localhost:8020`. Desative o prompt de primeira execução com `FAILPROOFAI_NO_FIRST_RUN=1`. --- -## O que ele bloqueia +## O que ele impede | Política | O que bloqueia | |---|---| @@ -113,16 +142,16 @@ failproofai | `block-force-push` | `git push --force` | | `block-work-on-main` | Commits, merges e rebases em `main` / `master` | | `block-rm-rf` | Exclusão recursiva de arquivos | -| `sanitize-api-keys` | Vazamento de chaves de API no contexto do agente | +| `sanitize-api-keys` | Chaves de API vazando para o contexto do agente | -→ [Todas as 30 políticas nativas](https://docs.befailproof.ai/built-in-policies) +→ [Todas as 30 políticas integradas](https://docs.befailproof.ai/built-in-policies) --- ## Suas próprias políticas -Adicione um arquivo em `.failproofai/policies/` — ele é carregado automaticamente, sem nenhuma flag necessária. -Faça o commit e toda a equipe receberá a política no próximo pull. +Adicione um arquivo em `.failproofai/policies/` — ele é carregado automaticamente, sem necessidade de flags. +Faça commit e toda a equipe receberá na próxima atualização. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -150,11 +179,11 @@ Três decisões disponíveis para cada política: --- -## Visibilidade da sessão +## Visibilidade das sessões Cada chamada de ferramenta feita pelo seu agente é registrada localmente. O dashboard mostra o que foi executado, -o que foi bloqueado e o que a política comunicou ao agente — para que você não fique no escuro -quando algo der errado. → [Guia do dashboard](https://docs.befailproof.ai/dashboard) +o que foi bloqueado e o que a política informou ao agente — para que você não fique no escuro +quando algo der errado. → [Guia do Dashboard](https://docs.befailproof.ai/dashboard) --- @@ -162,28 +191,28 @@ quando algo der errado. → [Guia do dashboard](https://docs.befailproof.ai/dash | | | |---|---| -| [Primeiros Passos](https://docs.befailproof.ai/getting-started) | Instalação e primeiras etapas | -| [Políticas Nativas](https://docs.befailproof.ai/built-in-policies) | Todas as 30 políticas com parâmetros | -| [Políticas Personalizadas](https://docs.befailproof.ai/custom-policies) | Crie as suas próprias | +| [Primeiros Passos](https://docs.befailproof.ai/getting-started) | Instalação e primeiros passos | +| [Políticas Integradas](https://docs.befailproof.ai/built-in-policies) | Todas as 30 políticas com parâmetros | +| [Políticas Personalizadas](https://docs.befailproof.ai/custom-policies) | Escreva as suas próprias | | [Configuração](https://docs.befailproof.ai/configuration) | Escopos de configuração e regras de mesclagem | -| [Dashboard](https://docs.befailproof.ai/dashboard) | Monitor de sessão e atividade de políticas | +| [Dashboard](https://docs.befailproof.ai/dashboard) | Monitor de sessões e atividade de políticas | | [Arquitetura](https://docs.befailproof.ai/architecture) | Como o sistema de hooks funciona | --- ## Licença -MIT com [Commons Clause](https://commonsclause.com/) — gratuito para uso interno e pessoal; a revenda comercial do failproofai em si requer um acordo separado. Consulte [LICENSE](./LICENSE) para o texto completo. +MIT com [Commons Clause](https://commonsclause.com/) — gratuito para uso interno e pessoal; a revenda comercial do próprio failproofai requer um acordo separado. Consulte [LICENSE](./LICENSE) para o texto completo. --- ## Contribuindo -Consulte [CONTRIBUTING.md](./CONTRIBUTING.md). Novas políticas, casos extremos e traduções são sempre 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 +> **Compile 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 o import `failproofai` a partir do -> bundle compilado em `dist/` — sem um build você encontrará erros de hook `Cannot find package 'failproofai'`. +> bundle compilado em `dist/` — sem uma compilação você encontrará erros de hook `Cannot find package 'failproofai'`. > Recompile após alterar `src/`. Consulte > [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 e84b9461..a6289e22 100644 --- a/docs/i18n/README.ru.md +++ b/docs/i18n/README.ru.md @@ -17,14 +17,14 @@ **Переводы:** [简体中文](./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. Перехватывает циклы, опасные действия и утечки секретов +**Разрешение ошибок времени выполнения для кодирующих агентов.** +Интеграция с Claude Code и Codex. Перехватывает циклы, опасные действия и утечки секретов до того, как они станут инцидентами. Нулевая задержка. Работает локально.

- failproofai в действии + Failproof AI в действии

--- @@ -35,61 +35,90 @@ Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Установите hooks для одного или любой комбинации: `failproofai policies --install --cli opencode pi gemini` (или `--cli claude codex copilot cursor opencode pi gemini hermes`). Опустите `--cli` для автоматического обнаружения установленных CLI и подсказок. +> Установите хуки для одного или любой комбинации: `failproofai policies --install --cli opencode pi` (или `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Опустите `--cli` для автоматического обнаружения установленных CLI и подтверждения. +> +> **Hermes** (hermes-agent, шлюз Slack/Telegram) поддерживается как для **живого принудительного выполнения хуков** (`--cli hermes` — одна установка перехватывает вызовы инструментов со всех платформ и подагентов), так и для автономного **аудита** повторного воспроизведения его сеансов шлюза из одного `~/.hermes/state.db`. +> +> **OpenClaw** (шлюз openclaw, многоканальный помощник с самостоятельным размещением) поддерживается как для **живого принудительного выполнения хуков** (`--cli openclaw`, пользовательская область), так и для автономного **аудита** повторного воспроизведения его сеансов JSONL (`~/.openclaw/agents//sessions/*.jsonl`). Принудительное выполнение использует **встроенные хуки плагинов** OpenClaw (поставляемый `openclaw-plugin/`, который асинхронно запускает failproofai — его встроенные хуки на основе файлов только для наблюдения и не могут блокировать): `before_tool_call` блокирует инструмент, а `before_agent_finalize` — это реальный вентиль конца хода, поэтому встроенные функции `require-*-before-stop` применяются. +> +> **Factory Droid** (`droid`) поддерживается как для **живого принудительного выполнения хуков** (`--cli factory`, область пользователя и проекта), так и для автономного **аудита** повторного воспроизведения его сеансов JSONL на диске. droid блокирует вызовы инструментов по коду выхода хука **2** (не решение JSON) и соблюдает `{decision:"block"}` только при событии конца хода `Stop` — failproofai автоматически выдает правильную форму по событиям. +> +> **Devin CLI** (`devin`, Cognition) поддерживается как для **живого принудительного выполнения хуков** (`--cli devin`, область пользователя и проекта), так и для автономного **аудита** повторного воспроизведения его сеансов SQLite (`~/.local/share/devin/cli/sessions.db`). Devin — это **чистый клон Claude** — те же имена событий, тот же snake_case полезной нагрузки, та же конфигурация оболочки `hooks` (`~/.config/devin/config.json` / `/.devin/config.json`) — блокировка через JSON `{decision:"block"}` при каждом событии. +> +> **Antigravity CLI** (`agy`) поддерживается как для **живого принудительного выполнения хуков** (`--cli antigravity`, область пользователя и проекта), так и для автономного **аудита** повторного воспроизведения его обычных сеансов JSONL (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity имеет **свой собственный** контракт (не клон Claude): схема **именованного хука** `hooks.json` (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), полезная нагрузка stdin в camelCase, которую failproofai нормализует, и его собственные формы ответов — `{decision:"deny"}` для блокировки инструмента, `{decision:"continue"}` для принудительного другого хода в `Stop`, `{injectSteps}` для внедрения напоминания перед запуском модели. > -> **Hermes** (hermes-agent, шлюз Slack/Telegram) поддерживается как для **live-hook принудительного исполнения** (`--cli hermes` — одна установка перехватывает вызовы инструментов с каждой платформы и субагента), так и для автономного **аудита** воспроизведения сессий шлюза из отдельного `~/.hermes/state.db`. +> **Goose** (кодовое имя goose, Block) поддерживается как для **живого принудительного выполнения хуков** (`--cli goose`, область пользователя и проекта), так и для автономного **аудита** повторного воспроизведения его сеансов SQLite (`~/.local/share/goose/sessions/sessions.db`). Принудительное выполнение использует систему **хуков** Goose (межагентная спецификация **Open Plugins**) — установщик просто выкладывает каталог плагинов в `~/.agents/plugins/failproofai/` и Goose автоматически его обнаруживает. Блокировка — это JSON `{"decision":"block"}` при событии `PreToolUse` (которое срабатывает для инструмента shell и внутри делегированных подагентов), проверено живо для goose v1.43.0; Goose не имеет события конца хода `Stop`, поэтому встроенные функции `require-*-before-stop` не применяются (как с Hermes). --- @@ -97,23 +126,23 @@ ```sh npm install -g failproofai -failproofai policies --install # или просто запустите `failproofai` и примите первую подсказку +failproofai policies --install # или просто запустите `failproofai` и примите первый запрос failproofai ``` -30 встроенных политик активируются немедленно. Панель управления на `localhost:8020`. Отключите первую подсказку с помощью `FAILPROOFAI_NO_FIRST_RUN=1`. +30 встроенных политик активируются немедленно. Панель управления на `localhost:8020`. Отключите первый запрос с помощью `FAILPROOFAI_NO_FIRST_RUN=1`. --- -## Что это блокирует +## Что он блокирует | Политика | Что она блокирует | |---|---| | `block-push-master` | Прямые push в `main` / `master` | | `block-force-push` | `git push --force` | -| `block-work-on-main` | Коммиты, merges, rebases в `main` / `master` | +| `block-work-on-main` | Коммиты, слияния, перебазирование на `main` / `master` | | `block-rm-rf` | Рекурсивное удаление файлов | -| `sanitize-api-keys` | Утечки API ключей в контекст агента | +| `sanitize-api-keys` | API ключи, попадающие в контекст агента | → [Все 30 встроенных политик](https://docs.befailproof.ai/built-in-policies) @@ -121,7 +150,7 @@ failproofai ## Ваши собственные политики -Поместите файл в `.failproofai/policies/` — он загружается автоматически, флаги не требуются. +Поместите файл в `.failproofai/policies/` — он загружается автоматически без флагов. Закоммитьте его, и вся команда получит его при следующем pull. ```js @@ -132,7 +161,7 @@ customPolicies.add({ match: { events: ["PreToolUse"] }, fn: async (ctx) => { if (ctx.toolInput?.file_path?.includes("production")) - return deny("Записи в production пути заблокированы."); + return deny("Writes to production paths are blocked."); return allow(); }, }); @@ -144,16 +173,16 @@ customPolicies.add({ |---|---| | `allow()` | Разрешить операцию | | `deny(message)` | Заблокировать её — сообщение возвращается агенту | -| `instruct(message)` | Пропустить её, но добавить контекст в следующую подсказку агента | +| `instruct(message)` | Пропустить, но добавить контекст в следующий запрос агента | → [Руководство по пользовательским политикам](https://docs.befailproof.ai/custom-policies) --- -## Видимость сессии +## Видимость сеанса -Каждый вызов инструмента, который делает ваш агент, записывается локально. Панель управления показывает, что запустилось, -что было заблокировано, и что политика сообщила агенту — поэтому вы не гадаете, +Каждый вызов инструмента, который делает ваш агент, регистрируется локально. Панель управления показывает, что выполнялось, +что было заблокировано и что политика сообщила агенту — так что вы не гадаете, когда что-то идёт не так. → [Руководство панели управления](https://docs.befailproof.ai/dashboard) --- @@ -166,22 +195,23 @@ customPolicies.add({ | [Встроенные политики](https://docs.befailproof.ai/built-in-policies) | Все 30 политик с параметрами | | [Пользовательские политики](https://docs.befailproof.ai/custom-policies) | Напишите свои | | [Конфигурация](https://docs.befailproof.ai/configuration) | Области конфигурации и правила слияния | -| [Панель управления](https://docs.befailproof.ai/dashboard) | Монитор сессии и активность политик | -| [Архитектура](https://docs.befailproof.ai/architecture) | Как работает система hooks | +| [Панель управления](https://docs.befailproof.ai/dashboard) | Монитор сеанса и активность политик | +| [Архитектура](https://docs.befailproof.ai/architecture) | Как работает система хуков | --- ## Лицензия -MIT с [Commons Clause](https://commonsclause.com/) — бесплатно для внутреннего и личного использования; коммерческая перепродажа самого failproofai требует отдельного соглашения. Полный текст см. в [LICENSE](./LICENSE). +MIT с [Commons Clause](https://commonsclause.com/) — бесплатно для внутреннего и личного использования; коммерческое перепродажа самого failproofai требует отдельного соглашения. Полный текст см. в [LICENSE](./LICENSE). --- -## Участие в разработке +## Разработка -See [CONTRIBUTING.md](./CONTRIBUTING.md). Новые политики, граничные случаи и переводы всегда приветствуются. +См. [CONTRIBUTING.md](./CONTRIBUTING.md). Новые политики, граничные случаи и переводы приветствуются. -> **Соберите проект перед началом.** Сначала запустите `bun install && bun run build`. Этот репозиторий запускает собственные hooks failproofai на себе, и они разрешают импорт `failproofai` относительно скомпилированного пакета `dist/` — без build вы получите ошибки hooks `Cannot find package 'failproofai'`. Пересоберите после изменения `src/`. See [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **Соберите перед началом.** Сначала запустите `bun install && bun run build`. Этот репозиторий запускает собственные хуки failproofai на себе, и они разрешают импорт `failproofai` для скомпилированного пакета `dist/` — без сборки вы получите ошибки хуков `Cannot find package 'failproofai'`. Пересоберите после изменения `src/`. См. +> [Соберите перед тем, как встроенные хуки dev будут работать](./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 579f34ba..46907940 100644 --- a/docs/i18n/README.tr.md +++ b/docs/i18n/README.tr.md @@ -17,112 +17,141 @@ **Ç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ı hatası çözümü.** -Claude Code ve Codex'e bağlanır. Döngüleri, tehlikeli işlemleri ve gizli diliş sızıntılarını -olaylar haline gelmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır. +**Kodlama ajanları için çalışma zamanı hata çözümü.** +Claude Code ve Codex'e bağlanır. Döngüleri, tehlikeli işlemleri ve gizli bilgi sızıntılarını +sorun haline gelmeden önce yakalar. Sıfır gecikme. Yerel olarak çalışır.

- Failproof AI çalışmada + Failproof AI aksiyonda

--- -## Desteklenen ajan CLI'ları +## Desteklenen ajan CLIsı

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Bir veya herhangi bir kombinasyon için kanca yükleyin: `failproofai policies --install --cli opencode pi gemini` (veya `--cli claude codex copilot cursor opencode pi gemini hermes`). Yüklü CLI'ları otomatik olarak algılamak ve istemek için `--cli` öğesini atlayın. +> Bir veya daha fazla kombinasyon için hook yükleyin: `failproofai policies --install --cli opencode pi` (veya `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Kurulu CLIsları otomatik olarak algılamak ve sorulmak için `--cli` seçeneğini atla. +> +> **Hermes** (hermes-agent, bir Slack/Telegram ağ geçidi) hem **canlı-hook zorlama** (`--cli hermes` — tek bir yükleme her platform ve alt ajantan gelen araç çağrılarını engeller) hem de çevrimdışı **denetim** yürütmesi için desteklenir `~/.hermes/state.db` adresinden. +> +> **OpenClaw** (openclaw ağ geçidi, kendi kendine barındırılan çok kanallı asistan) hem **canlı-hook zorlama** (`--cli openclaw`, kullanıcı kapsamı) hem de çevrimdışı **denetim** yürütmesi için desteklenir `~/.openclaw/agents//sessions/*.jsonl` adresinden. Zorlama, OpenClaw'ın **süreç içi eklenti hook'larını** kullanır (failproofai'yi eşzamansız olarak oluşturan sevk edilmiş bir `openclaw-plugin/` — dosya tabanlı iç hook'ları yalnızca gözlem amaçlıdır ve engelle kabiliyetine sahip değildir): `before_tool_call` bir aracı engeller ve `before_agent_finalize` gerçek bir dönem sonu kapısıdır, bu nedenle `require-*-before-stop` yerleşik özellikleri uygular. +> +> **Factory Droid** (`droid`) hem **canlı-hook zorlama** (`--cli factory`, kullanıcı + proje kapsamı) hem de çevrimdışı **denetim** yürütmesi için desteklenir. droid araç çağrılarını hook çıkış kodu 2'de engeller (JSON kararı değil) ve `{decision:"block"}` yalnızca dönem sonu `Stop` olayında onurlandırır — failproofai olayın her biri için otomatik olarak doğru şekli yayar. +> +> **Devin CLI** (`devin`, Cognition) hem **canlı-hook zorlama** (`--cli devin`, kullanıcı + proje kapsamı) hem de çevrimdışı **denetim** yürütmesi için desteklenir `~/.local/share/devin/cli/sessions.db` adresinden. Devin bir **saf Claude klonu**dur — aynı olay adları, aynı snake_case yükü, aynı `"hooks"`-sarmalayıcı yapılandırması (`~/.config/devin/config.json` / `/.devin/config.json`) — her olay üzerinde `{decision:"block"}` JSON ile engelleme yapılır. +> +> **Antigravity CLI** (`agy`) hem **canlı-hook zorlama** (`--cli antigravity`, kullanıcı + proje kapsamı) hem de çevrimdışı **denetim** yürütmesi için desteklenir `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` adresinden. Antigravity'nin **kendi** sözleşmesi vardır (Claude klonu değil): bir **adlandırılmış-hook** `hooks.json` şeması (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), failproofai'nin normalleştirdiği bir camelCase stdin yükü ve kendi yanıt şekilleri — bir aracı engelleme için `{decision:"deny"}`, `Stop` adresinde başka bir dönem zorlamak için `{decision:"continue"}`, model çalışmadan önce hatırlatıcı enjekte etmek için `{injectSteps}`. > -> **Hermes** (hermes-agent, bir Slack/Telegram ağ geçidi) hem **canlı kanca uygulaması** (`--cli hermes` — bir kurulum her platformdan ve alt ajantan araç çağrılarını keser) hem de çevrimdışı **denetim** için desteklenir. tek `~/.hermes/state.db` dosyasından ağ geçidi oturumlarının tekrar oynatılması. +> **Goose** (codename goose, Block) hem **canlı-hook zorlama** (`--cli goose`, kullanıcı + proje kapsamı) hem de çevrimdışı **denetim** yürütmesi için desteklenir `~/.local/share/goose/sessions/sessions.db` adresinden. Zorlama, Goose'un **hook'lar** sistemini kullanır (çok ajantan **Open Plugins** spesifikasyonu) — yükleyici sadece bir eklenti dizini `~/.agents/plugins/failproofai/` adresine düşürür ve Goose otomatik olarak keşfeder. Engelleme, `PreToolUse` olayında `{"decision":"block"}` JSON'dur (shell aracı ve temsilci edilen alt ajanlar için çalışır), goose v1.43.0'a karşı canlı olarak doğrulanır; Goose'un `Stop` olay adında bir dönem sonu yok, bu nedenle `require-*-before-stop` yerleşik özellikleri uygulanmaz (Hermes'te olduğu gibi). --- -## Kurulum +## Yükle ```sh npm install -g failproofai -failproofai policies --install # veya sadece `failproofai` çalıştırın ve ilk çalıştırma istemini kabul edin +failproofai policies --install # veya sadece `failproofai` çalıştırın ve ilk çalıştırma isteğini kabul edin failproofai ``` -30 yerleşik ilke hemen etkinleşir. Pano `localhost:8020` adresinde. İlk çalıştırma istemini `FAILPROOFAI_NO_FIRST_RUN=1` ile devre dışı bırakın. +30 yerleşik politika hemen etkinleşir. Pano `localhost:8020` adresindedir. İlk çalıştırma isteğini `FAILPROOFAI_NO_FIRST_RUN=1` ile devre dışı bırakın. --- -## Neleri durdurur +## Neyi engeller? -| İlke | Neyi engeller | +| Politika | Engellediği şey | |---|---| -| `block-push-master` | `main` / `master` öğesine doğrudan itme işlemleri | +| `block-push-master` | `main` / `master` adresine doğrudan itme | | `block-force-push` | `git push --force` | -| `block-work-on-main` | `main` / `master` üzerine işlemeler, birleştirmeler, yeniden temeller | +| `block-work-on-main` | `main` / `master` adresinde değişiklikler, birleştirmeler, rebase işlemleri | | `block-rm-rf` | Özyinelemeli dosya silme | | `sanitize-api-keys` | API anahtarlarının ajan bağlamına sızması | -→ [Tüm 30 yerleşik ilke](https://docs.befailproof.ai/built-in-policies) +→ [Tüm 30 yerleşik politika](https://docs.befailproof.ai/built-in-policies) --- -## Kendi ilkeleriniz +## Kendi politikalarınız -`.failproofai/policies/` içine bir dosya bırakın — otomatik olarak yüklenir, bayrak gerekmez. -Taahhüt edin ve tüm takım bir sonraki çekişte alacaktır. +`.failproofai/policies/` adresine bir dosya bırakın — otomatik olarak yüklenir, bayrak gerekmez. +Bunu işleyin ve tüm ekip bir sonraki çekişte bunu alacaktır. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -132,29 +161,29 @@ customPolicies.add({ match: { events: ["PreToolUse"] }, fn: async (ctx) => { if (ctx.toolInput?.file_path?.includes("production")) - return deny("Üretim yollarına yazma işlemleri engellendi."); + return deny("Writes to production paths are blocked."); return allow(); }, }); ``` -Her ilkeye sunulan üç karar: +Her politika için üç karar seçeneği mevcuttur: | Karar | Etki | |---|---| | `allow()` | İşleme izin ver | -| `deny(message)` | Engelle — ileti ajana geri gider | -| `instruct(message)` | İzin ver, ama ajana sonraki tavsiyeye bağlam ekle | +| `deny(message)` | Engelle — ileti ajanın yanında görünür | +| `instruct(message)` | Geçmesine izin ver, ancak ajanın bir sonraki istemesine bağlam ekle | -→ [Özel ilkeler rehberi](https://docs.befailproof.ai/custom-policies) +→ [Özel politikalar rehberi](https://docs.befailproof.ai/custom-policies) --- ## Oturum görünürlüğü -Ajanınızın yaptığı her araç çağrısı yerel olarak günlüğe kaydedilir. Pano neyin çalıştığını, -neyin engellediğini ve ilkenin ajana ne söylediğini gösterir — böylece bir şey -yanlış gittiğinde tahmin etmezsiniz. → [Pano rehberi](https://docs.befailproof.ai/dashboard) +Ajanınız yaptığı her araç çağrısı yerel olarak kaydedilir. Pano, ne çalıştığını, +ne engellediğini ve politikanın ajanına ne söylediğini gösterir — bu nedenle +bir şey yanlış gittiğinde tahmin ediyorsunuz. → [Pano rehberi](https://docs.befailproof.ai/dashboard) --- @@ -162,26 +191,26 @@ yanlış gittiğinde tahmin etmezsiniz. → [Pano rehberi](https://docs.befailpr | | | |---|---| -| [Başlangıç](https://docs.befailproof.ai/getting-started) | Kurulum ve ilk adımlar | -| [Yerleşik İlkeler](https://docs.befailproof.ai/built-in-policies) | Tüm 30 ilke ve parametreleri | -| [Özel İlkeler](https://docs.befailproof.ai/custom-policies) | Kendi ilkelerinizi yazın | +| [Başlangıç](https://docs.befailproof.ai/getting-started) | Yükleme ve ilk adımlar | +| [Yerleşik Politikalar](https://docs.befailproof.ai/built-in-policies) | Tüm 30 politika parametreleriyle | +| [Özel Politikalar](https://docs.befailproof.ai/custom-policies) | Kendi politikanızı yazın | | [Yapılandırma](https://docs.befailproof.ai/configuration) | Yapılandırma kapsamları ve birleştirme kuralları | -| [Pano](https://docs.befailproof.ai/dashboard) | Oturum monitörü ve ilke etkinliği | -| [Mimari](https://docs.befailproof.ai/architecture) | Kanca sistemi nasıl çalışır | +| [Pano](https://docs.befailproof.ai/dashboard) | Oturum monitörü ve politika etkinliği | +| [Mimari](https://docs.befailproof.ai/architecture) | Hook sistemi nasıl çalışır | --- ## Lisans -MIT ve [Commons Clause](https://commonsclause.com/) — dahili ve kişisel kullanım için ücretsiz; failproofai'nin ticari yeniden satışı ayrı bir anlaşma gerektirir. Tam metin için [LICENSE](./LICENSE) bölümüne bakın. +MIT ile [Commons Clause](https://commonsclause.com/) — dahili ve kişisel kullanım için ücretsiz; failproofai'nin ticari yeniden satışı ayrı bir anlaşma gerektirir. Tam metin için [LICENSE](./LICENSE) dosyasına bakın. --- -## Katkıda bulunmak +## Katkı -[CONTRIBUTING.md](./CONTRIBUTING.md) bölümüne bakın. Yeni ilkeler, sınır durumları ve çeviriler hepsi hoş geldiniz. +[CONTRIBUTING.md](./CONTRIBUTING.md) dosyasına bakın. Yeni politikalar, uç durumlar ve çeviriler hoş geldiniz. -> **Başlamadan önce derleyin.** Önce `bun install && bun run build` komutunu çalıştırın. Bu depo, failproofai'nin kendi kancalarını kendisinde çalıştırır ve `failproofai` ithalatını derlenmiş `dist/` paketi karşı çözer — bir derleme olmadan `Cannot find package 'failproofai'` kanca hatalarına çarparsınız. `src/` değişikliğinden sonra yeniden derleyin. [Depo içi geliştirme kanalarının çalışması için önce derleme](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) bölümüne bakın. +> **Başlamadan önce derle.** Önce `bun install && bun run build` komutunu çalıştırın. Bu depo failproofai'nin kendi hook'larını kendisinde çalıştırır ve `failproofai` ithalatını derlenmiş `dist/` paketi karşısında çözer — bir yapı olmadan `Cannot find package 'failproofai'` hook hataları oluşur. `src/` değiştirdikten sonra yeniden derleyin. [In-repo dev hook'ları çalışması için önce derle](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work) bölümüne bakın. --- diff --git a/docs/i18n/README.vi.md b/docs/i18n/README.vi.md index d0ff72b8..affe6b02 100644 --- a/docs/i18n/README.vi.md +++ b/docs/i18n/README.vi.md @@ -15,11 +15,11 @@ [![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) -**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) -**Giải quyết sự cố runtime cho các agents lập trình.** +**Giải quyết lỗi runtime cho các agent code. Kết nối với Claude Code và Codex. Bắt các vòng lặp, hành động nguy hiểm và rò rỉ bí mật -trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy cục bộ. +trước khi chúng gây hậu quả. Độ trễ bằng không. Chạy locally.** @@ -29,67 +29,96 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c --- -## Các CLI agent được hỗ trợ +## Agent CLI được hỗ trợ

Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> Cài đặt hooks cho một hoặc bất kỳ tổ hợp nào: `failproofai policies --install --cli opencode pi gemini` (hoặc `--cli claude codex copilot cursor opencode pi gemini hermes`). Bỏ qua `--cli` để tự động phát hiện các CLI được cài đặt và nhắc lựa chọn. +> Cài đặt hook cho một hoặc bất kỳ tổ hợp nào: `failproofai policies --install --cli opencode pi` (hoặc `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`). Bỏ qua `--cli` để tự động phát hiện các CLI được cài đặt và nhắc. +> +> **Hermes** (hermes-agent, một gateway Slack/Telegram) được hỗ trợ cho cả **live-hook enforcement** (`--cli hermes` — một lần cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng và subagent) và **audit** offline của các phiên gateway từ tệp `~/.hermes/state.db` duy nhất. +> +> **OpenClaw** (openclaw gateway, một assistant multi-channel tự lưu trữ) được hỗ trợ cho cả **live-hook enforcement** (`--cli openclaw`, user-scope) và **audit** offline của các phiên JSONL (`~/.openclaw/agents//sessions/*.jsonl`). Enforcement sử dụng **in-process plugin hooks** của OpenClaw (một `openclaw-plugin/` được gửi kèm mà async-spawns failproofai — các hook dựa trên tệp nội bộ của nó chỉ có thể quan sát và không thể chặn): `before_tool_call` chặn một công cụ, và `before_agent_finalize` là một cổng turn-end thực sự, vì vậy các built-in `require-*-before-stop` thực thi. +> +> **Factory Droid** (`droid`) được hỗ trợ cho cả **live-hook enforcement** (`--cli factory`, user + project scope) và **audit** offline của các phiên JSONL trên đĩa. droid chặn các lệnh gọi công cụ từ **exit code 2** của hook (không phải quyết định JSON) và chỉ tuân theo `{decision:"block"}` trên sự kiện `Stop` turn-end — failproofai tự động phát ra hình dạng phù hợp cho mỗi sự kiện. +> +> **Devin CLI** (`devin`, Cognition) được hỗ trợ cho cả **live-hook enforcement** (`--cli devin`, user + project scope) và **audit** offline của các phiên SQLite (`~/.local/share/devin/cli/sessions.db`). Devin là một **Claude-clone tinh khiết** — cùng tên sự kiện, cùng payload snake_case, cùng cấu hình trình bao (`~/.config/devin/config.json` / `/.devin/config.json`) — chặn qua JSON `{decision:"block"}` trên mọi sự kiện. +> +> **Antigravity CLI** (`agy`) được hỗ trợ cho cả **live-hook enforcement** (`--cli antigravity`, user + project scope) và **audit** offline của các phiên plain-JSONL (`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`). Antigravity có hợp đồng **riêng** của nó (không phải Claude-clone): một schema `hooks.json` **named-hook** (`~/.gemini/config/hooks.json` / `/.agents/hooks.json`), một payload stdin camelCase mà failproofai chuẩn hóa, và các hình dạng phản hồi của nó — `{decision:"deny"}` để chặn một công cụ, `{decision:"continue"}` để buộc một turn khác tại `Stop`, `{injectSteps}` để chèn một nhắc nhở trước khi mô hình chạy. > -> **Hermes** (hermes-agent, một gateway Slack/Telegram) được hỗ trợ cho cả **thực thi live-hook** (`--cli hermes` — một cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng và subagent) và **kiểm toán** ngoại tuyến của các phiên gateway của nó từ `~/.hermes/state.db` duy nhất. +> **Goose** (codename goose, Block) được hỗ trợ cho cả **live-hook enforcement** (`--cli goose`, user + project scope) và **audit** offline của các phiên SQLite (`~/.local/share/goose/sessions/sessions.db`). Enforcement sử dụng hệ thống **hooks** của Goose (spec **Open Plugins** cross-agent) — trình cài đặt chỉ cần thả một thư mục plugin tại `~/.agents/plugins/failproofai/` và Goose tự động khám phá nó. Chặn là JSON `{"decision":"block"}` trên sự kiện `PreToolUse` (được kích hoạt cho shell tool và bên trong các subagent được ủy quyền), xác minh live so với goose v1.43.0; Goose không có sự kiện `Stop` turn-end, vì vậy các built-in `require-*-before-stop` không áp dụng (như với Hermes). --- @@ -97,11 +126,11 @@ trước khi chúng trở thành sự cố. Độ trễ bằng không. Chạy c ```sh npm install -g failproofai -failproofai policies --install # hoặc chỉ chạy `failproofai` và chấp nhận lời nhắc lần đầu +failproofai policies --install # hoặc chỉ chạy `failproofai` và chấp nhận nhắc first-run failproofai ``` -30 chính sách tích hợp kích hoạt ngay lập tức. Bảng điều khiển tại `localhost:8020`. Tắt lời nhắc lần đầu với `FAILPROOFAI_NO_FIRST_RUN=1`. +30 chính sách built-in kích hoạt ngay lập tức. Dashboard tại `localhost:8020`. Vô hiệu hóa nhắc first-run bằng `FAILPROOFAI_NO_FIRST_RUN=1`. --- @@ -109,20 +138,20 @@ failproofai | Chính sách | Những gì nó chặn | |---|---| -| `block-push-master` | Đẩy trực tiếp đến `main` / `master` | +| `block-push-master` | Đẩy trực tiếp tới `main` / `master` | | `block-force-push` | `git push --force` | | `block-work-on-main` | Commits, merges, rebases trên `main` / `master` | | `block-rm-rf` | Xóa tệp đệ quy | -| `sanitize-api-keys` | Các khóa API rò rỉ vào ngữ cảnh agent | +| `sanitize-api-keys` | Các khóa API rò rỉ vào bối cảnh agent | -→ [Tất cả 30 chính sách tích hợp](https://docs.befailproof.ai/built-in-policies) +→ [Tất cả 30 chính sách built-in](https://docs.befailproof.ai/built-in-policies) --- ## Các chính sách của riêng bạn -Thả một tệp vào `.failproofai/policies/` — nó tải tự động, không cần cờ nào. -Commit nó và toàn bộ nhóm sẽ nhận được nó trong pull tiếp theo. +Thả một tệp vào `.failproofai/policies/` — nó tự động tải, không cần cờ. +Commit nó và toàn bộ nhóm sẽ có nó trên pull tiếp theo. ```js import { customPolicies, deny, allow } from "failproofai"; @@ -143,8 +172,8 @@ Ba quyết định có sẵn cho mọi chính sách: | Quyết định | Hiệu ứng | |---|---| | `allow()` | Cho phép hoạt động | -| `deny(message)` | Chặn nó — thông báo quay lại agent | -| `instruct(message)` | Cho phép thực hiện, nhưng thêm ngữ cảnh vào lời nhắc tiếp theo của agent | +| `deny(message)` | Chặn nó — tin nhắn quay lại agent | +| `instruct(message)` | Cho phép nó qua, nhưng thêm bối cảnh vào nhắc tiếp theo của agent | → [Hướng dẫn chính sách tùy chỉnh](https://docs.befailproof.ai/custom-policies) @@ -152,9 +181,9 @@ Ba quyết định có sẵn cho mọi chính sách: ## Khả năng hiển thị phiên -Mọi lệnh gọi công cụ mà agent của bạn thực hiện đều được ghi nhật ký cục bộ. Bảng điều khiển hiển thị những gì đã chạy, -những gì bị chặn và những gì chính sách đã nói với agent — để bạn không phải đoán -khi có sự cố. → [Hướng dẫn bảng điều khiển](https://docs.befailproof.ai/dashboard) +Mọi lệnh gọi công cụ mà agent của bạn thực hiện đều được ghi lại cục bộ. Dashboard hiển thị những gì chạy, +những gì bị chặn, và những gì chính sách đã nói với agent — vì vậy bạn không phải đoán +khi có gì đó sai. → [Hướng dẫn Dashboard](https://docs.befailproof.ai/dashboard) --- @@ -163,29 +192,29 @@ khi có sự cố. → [Hướng dẫn bảng điều khiển](https://docs.befa | | | |---|---| | [Bắt đầu](https://docs.befailproof.ai/getting-started) | Cài đặt và các bước đầu tiên | -| [Chính sách tích hợp](https://docs.befailproof.ai/built-in-policies) | Tất cả 30 chính sách với các tham số | -| [Chính sách tùy chỉnh](https://docs.befailproof.ai/custom-policies) | Viết chính sách của riêng bạn | +| [Chính sách Built-in](https://docs.befailproof.ai/built-in-policies) | Tất cả 30 chính sách với các tham số | +| [Chính sách Tùy chỉnh](https://docs.befailproof.ai/custom-policies) | Viết của riêng bạn | | [Cấu hình](https://docs.befailproof.ai/configuration) | Phạm vi cấu hình và quy tắc hợp nhất | -| [Bảng điều khiển](https://docs.befailproof.ai/dashboard) | Giám sát phiên và hoạt động chính sách | +| [Dashboard](https://docs.befailproof.ai/dashboard) | Theo dõi phiên và hoạt động chính sách | | [Kiến trúc](https://docs.befailproof.ai/architecture) | Cách hệ thống hook hoạt động | --- ## 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; bán lại failproofai yêu cầu một thỏa thuận riêng. Xem [LICENSE](./LICENSE) để biết toàn bộ văn bản. +MIT với [Commons Clause](https://commonsclause.com/) — miễn phí cho sử dụng nội bộ và cá nhân; 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). Các chính sách mới, trường hợp đặc biệt và bản dịch đều được chào đón. +Xem [CONTRIBUTING.md](./CONTRIBUTING.md). Các chính sách mới, trường hợp biên 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. Repository này chạy -> các hook riêng của failproofai trên chính nó, và chúng giải quyết nhập `failproofai` dựa trên -> gói `dist/` được biên dịch — nếu không có bản 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 -> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work). +> **Xây dựng trước khi bạn bắt đầu.** Chạy `bun install && bun run build` trước. Kho này chạy +> các hook của failproofai trên chính nó, và chúng giải quyết nhập `failproofai` so với +> bundle `dist/` đã biên dịch — mà không cần xây dựng bạn sẽ gặp các 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 in-repo 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 b6112fe9..83a2beda 100644 --- a/docs/i18n/README.zh.md +++ b/docs/i18n/README.zh.md @@ -17,8 +17,8 @@ **翻译版本:** [简体中文](./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,在循环、危险操作和密钥泄露演变成事故之前将其拦截。零延迟,本地运行。 +**为编码智能体提供运行时故障处理能力。** +接入 Claude Code 和 Codex,在循环、危险操作和密钥泄露演变为生产事故之前将其拦截。零延迟,本地运行。 @@ -34,61 +34,90 @@ Claude Code -        - +      + OpenAI Codex -        - +      + GitHub Copilot -        - +      + Cursor Agent -

-

- +      + OpenCode -        - +      + Pi -        - +

+

+ - - Gemini CLI + + Hermes -        - +      + + OpenClaw + +      + - - Hermes + + Factory Droid + + +      + + Devin CLI + +      + + Antigravity CLI + +      + + + + Goose

-> 可为一个或多个 CLI 安装 hooks:`failproofai policies --install --cli opencode pi gemini`(或 `--cli claude codex copilot cursor opencode pi gemini hermes`)。省略 `--cli` 参数将自动检测已安装的 CLI 并提示选择。 +> 可为单个或任意组合的 CLI 安装钩子:`failproofai policies --install --cli opencode pi`(或 `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`)。省略 `--cli` 则自动检测已安装的 CLI 并进行提示。 +> +> **Hermes**(hermes-agent,一个 Slack/Telegram 网关)支持**实时钩子强制执行**(`--cli hermes`——单次安装即可拦截来自所有平台和子智能体的工具调用)以及离线**审计**回放其网关会话(来自单一的 `~/.hermes/state.db`)。 +> +> **OpenClaw**(openclaw gateway,一个自托管的多渠道助手)支持**实时钩子强制执行**(`--cli openclaw`,用户级作用域)以及离线**审计**回放其 JSONL 会话(`~/.openclaw/agents//sessions/*.jsonl`)。强制执行使用 OpenClaw 的**进程内插件钩子**(一个随附的 `openclaw-plugin/`,异步派生 failproofai——其基于文件的内部钩子仅供观察,无法拦截):`before_tool_call` 可阻断工具,`before_agent_finalize` 是真正的轮次结束关卡,因此 `require-*-before-stop` 内置策略可生效。 +> +> **Factory Droid**(`droid`)支持**实时钩子强制执行**(`--cli factory`,用户 + 项目作用域)以及离线**审计**回放其磁盘上的 JSONL 会话。droid 通过钩子**退出码 2**(而非 JSON 决策)来阻断工具调用,并且仅在轮次结束的 `Stop` 事件上接受 `{decision:"block"}`——failproofai 会自动为每种事件输出正确的格式。 +> +> **Devin CLI**(`devin`,Cognition)支持**实时钩子强制执行**(`--cli devin`,用户 + 项目作用域)以及离线**审计**回放其 SQLite 会话(`~/.local/share/devin/cli/sessions.db`)。Devin 是一个**纯 Claude 克隆**——相同的事件名称、相同的 snake_case 载荷、相同的 `"hooks"` 包装器配置(`~/.config/devin/config.json` / `/.devin/config.json`)——通过每个事件上的 `{decision:"block"}` JSON 进行拦截。 +> +> **Antigravity CLI**(`agy`)支持**实时钩子强制执行**(`--cli antigravity`,用户 + 项目作用域)以及离线**审计**回放其纯 JSONL 会话(`~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`)。Antigravity 有其**自有**协议(并非 Claude 克隆):一套**命名钩子** `hooks.json` 模式(`~/.gemini/config/hooks.json` / `/.agents/hooks.json`),一个 failproofai 会规范化的 camelCase stdin 载荷,以及自有的响应格式——`{decision:"deny"}` 拦截工具,`{decision:"continue"}` 在 `Stop` 时强制进入下一轮,`{injectSteps}` 在模型运行前注入提示。 > -> **Hermes**(hermes-agent,一个 Slack/Telegram 网关)同时支持**实时 hook 执行**(`--cli hermes` — 一次安装即可拦截所有平台和子智能体的工具调用)以及离线**审计**回放,可从单一的 `~/.hermes/state.db` 文件回放其网关会话。 +> **Goose**(代号 goose,Block 出品)支持**实时钩子强制执行**(`--cli goose`,用户 + 项目作用域)以及离线**审计**回放其 SQLite 会话(`~/.local/share/goose/sessions/sessions.db`)。强制执行使用 Goose 的**钩子**系统(跨智能体的 **Open Plugins** 规范)——安装程序只需将插件目录放置于 `~/.agents/plugins/failproofai/`,Goose 即可自动发现。拦截方式为在 `PreToolUse` 事件上返回 `{"decision":"block"}` JSON(该事件在 shell 工具调用时以及委托子智能体内部均会触发),已针对 goose v1.43.0 进行实测验证;Goose 没有轮次结束的 `Stop` 事件,因此 `require-*-before-stop` 内置策略不适用(与 Hermes 相同)。 --- @@ -100,19 +129,19 @@ failproofai policies --install # 或直接运行 `failproofai` 并接受首次 failproofai ``` -30 条内置策略即时生效。访问 `localhost:8020` 查看控制台。使用 `FAILPROOFAI_NO_FIRST_RUN=1` 禁用首次运行提示。 +30 条内置策略立即生效。控制面板地址:`localhost:8020`。设置 `FAILPROOFAI_NO_FIRST_RUN=1` 可禁用首次运行提示。 --- -## 拦截范围 +## 能拦截什么 | 策略 | 拦截内容 | |---|---| | `block-push-master` | 直接推送到 `main` / `master` 分支 | | `block-force-push` | `git push --force` | -| `block-work-on-main` | 在 `main` / `master` 上提交、合并、变基 | +| `block-work-on-main` | 在 `main` / `master` 上进行提交、合并、变基 | | `block-rm-rf` | 递归删除文件 | -| `sanitize-api-keys` | API 密钥泄露到智能体上下文 | +| `sanitize-api-keys` | API 密钥泄露到智能体上下文中 | → [全部 30 条内置策略](https://docs.befailproof.ai/built-in-policies) @@ -120,7 +149,8 @@ failproofai ## 自定义策略 -将文件放入 `.failproofai/policies/` 目录即可自动加载,无需任何额外参数。提交到代码库后,团队所有成员在下次拉取时即可生效。 +将文件放入 `.failproofai/policies/` 目录——无需任何参数,自动加载。 +提交到版本库后,团队所有成员在下次拉取时即可获得该策略。 ```js import { customPolicies, deny, allow } from "failproofai"; @@ -141,16 +171,16 @@ customPolicies.add({ | 决策 | 效果 | |---|---| | `allow()` | 允许该操作 | -| `deny(message)` | 阻止该操作——消息将返回给智能体 | -| `instruct(message)` | 放行该操作,但向智能体的下一个提示词中追加上下文信息 | +| `deny(message)` | 拦截——消息返回给智能体 | +| `instruct(message)` | 放行,但在智能体下一个提示中附加上下文 | → [自定义策略指南](https://docs.befailproof.ai/custom-policies) --- -## 会话可见性 +## 会话可视化 -智能体发起的每次工具调用都会在本地记录日志。控制台展示已执行的操作、被拦截的操作以及策略向智能体反馈的内容——让你在出现问题时不再茫然无措。→ [控制台指南](https://docs.befailproof.ai/dashboard) +智能体发出的每一次工具调用均在本地记录。控制面板展示运行了哪些操作、哪些被拦截,以及策略向智能体反馈了什么内容——出现问题时无需凭空猜测。→ [控制面板指南](https://docs.befailproof.ai/dashboard) --- @@ -159,27 +189,27 @@ customPolicies.add({ | | | |---|---| | [快速上手](https://docs.befailproof.ai/getting-started) | 安装与入门步骤 | -| [内置策略](https://docs.befailproof.ai/built-in-policies) | 全部 30 条策略及参数说明 | -| [自定义策略](https://docs.befailproof.ai/custom-policies) | 编写自己的策略 | +| [内置策略](https://docs.befailproof.ai/built-in-policies) | 全部 30 条策略及其参数 | +| [自定义策略](https://docs.befailproof.ai/custom-policies) | 编写你自己的策略 | | [配置](https://docs.befailproof.ai/configuration) | 配置作用域与合并规则 | -| [控制台](https://docs.befailproof.ai/dashboard) | 会话监控与策略活动 | -| [架构](https://docs.befailproof.ai/architecture) | Hook 系统的工作原理 | +| [控制面板](https://docs.befailproof.ai/dashboard) | 会话监控与策略活动 | +| [架构](https://docs.befailproof.ai/architecture) | 钩子系统的工作原理 | --- ## 许可证 -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 的 hooks,这些 hooks 从编译后的 `dist/` 包中解析 `failproofai` 导入——如果未执行构建,将会遇到 `Cannot find package 'failproofai'` hook 错误。修改 `src/` 后需重新构建。详见 [构建后才能使用仓库内开发 hooks](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work)。 +> **开始前请先构建。** 先运行 `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)。 --- -由 [Nivedit Jain](https://github.com/NiveditJain) 和 [Nikita Agarwal](https://github.com/nk-ag) 共同打造。 +由 [Nivedit Jain](https://github.com/NiveditJain) 和 [Nikita Agarwal](https://github.com/nk-ag) 构建。 [befailproof.ai](https://befailproof.ai) diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 3d19c679..71a591e4 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -5,7 +5,7 @@ description: "FailproofAI gives AI agents 39 built-in failure policies that catc [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks and policies for **AI failure handling**, **error recovery**, and **LLM reliability**. Keep your AI agents reliable and running autonomously across **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, and the **Agents SDK**. +Hooks and policies for **AI failure handling**, **error recovery**, and **LLM reliability**. Keep your AI agents reliable and running autonomously across **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, and the **Agents SDK**. AI agents fail in predictable ways. They run destructive commands, leak secrets, drift off-task, get stuck in loops, or push directly to main. Left unattended, small failures cascade into outages, leaked credentials, and lost work. diff --git a/docs/it/built-in-policies.mdx b/docs/it/built-in-policies.mdx index b13f76c4..89504243 100644 --- a/docs/it/built-in-policies.mdx +++ b/docs/it/built-in-policies.mdx @@ -1,22 +1,23 @@ --- +--- title: Politiche integrate -description: "Tutte le 39 politiche integrate che catturano i comuni fallimenti degli agent" +description: "Tutte le 39 politiche integrate che rilevano i difetti comuni degli agenti" icon: shield --- -failproofai viene fornito con 39 politiche integrate che catturano i comuni fallimenti degli agent. Ogni politica si attiva su un tipo di hook event specifico e sul nome dello strumento. Diciannove politiche accettano parametri che ti permettono di regolarne il comportamento senza scrivere codice. Cinque politiche di workflow applicano una pipeline commit → push → PR → CI prima che Claude si fermi. +failproofai include 39 politiche integrate che rilevano i difetti comuni degli agenti. Ogni politica si attiva su un tipo di evento hook e nome strumento specifici. Diciannove politiche accettano parametri che ti permettono di regolarne il comportamento senza scrivere codice. Cinque politiche di workflow applicano una pipeline commit → push → PR → CI prima che Claude si fermi. --- ## Panoramica -Le politiche sono raggruppate per categorie: +Le politiche sono raggruppate in categorie: | Categoria | Politiche | Tipo di hook | |----------|----------|-----------| | [Comandi pericolosi](#comandi-pericolosi) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [Comandi infra](#comandi-infra) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [Segreti (sanitizer)](#segreti-sanitizer) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [Segreti (sanitizzatori)](#segreti-sanitizzatori) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | | [Ambiente](#ambiente) | block-env-files, protect-env-vars | PreToolUse | | [Accesso ai file](#accesso-ai-file) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | @@ -25,15 +26,15 @@ Le politiche sono raggruppate per categorie: | [Gestori di pacchetti](#gestori-di-pacchetti) | prefer-package-manager | PreToolUse | | [Workflow](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — ferma l'agent dall'andare avanti. -- **`warn-`** — fornisce all'agent un contesto aggiuntivo affinché possa correggersi automaticamente. -- **`sanitize-`** — ripulisce i dati sensibili dall'output dello strumento prima che l'agent li veda. +- **`block-`** — ferma l'agente dal proseguire. +- **`warn-`** — fornisci al agente un contesto aggiuntivo in modo che possa auto-correggersi. +- **`sanitize-`** — ripulisci i dati sensibili dall'output dello strumento prima che l'agente li veda. -### Namespace +### Spazi dei nomi -Ogni politica si trova in uno slot `/`. Le politiche integrate appartengono al namespace **`failproofai/`** — ad esempio, `failproofai/sanitize-jwt`. Lo namespace previene collisioni quando carichi anche politiche personalizzate o di terze parti con nomi brevi simili. +Ogni politica si trova in uno slot `/`. Le politiche integrate appartengono allo spazio dei nomi **`failproofai/`** — ad esempio, `failproofai/sanitize-jwt`. Lo spazio dei nomi previene collisioni quando carichi anche politiche personalizzate o di terze parti con nomi brevi simili. -Nella tua configurazione puoi fare riferimento a una politica integrata con il suo nome breve o con il nome qualificato; entrambe le forme si risolvono nella stessa politica: +Nella tua configurazione puoi fare riferimento a una politica integrata sia con il suo nome breve che con il suo nome qualificato; entrambe le forme si risolvono nella stessa politica: ```json { @@ -44,33 +45,33 @@ Nella tua configurazione puoi fare riferimento a una politica integrata con il s } ``` -Se un nome non contiene `/`, failproofai lo tratta come appartenente al namespace predefinito `failproofai`. I nomi che contengono già `/` (ad es. `myorg/foo`, `custom/my-hook`) vengono mantenuti così come sono. -- **`require-`** — blocca l'evento Stop fino a quando le condizioni non sono soddisfatte. +Se un nome non contiene `/`, failproofai lo tratta come appartenente allo spazio dei nomi predefinito `failproofai`. I nomi che contengono già `/` (ad es. `myorg/foo`, `custom/my-hook`) sono mantenuti così come sono. +- **`require-`** — blocca l'evento Stop finché le condizioni non sono soddisfatte. --- -Ogni politica supporta un campo `hint` facoltativo in `policyParams`. L'hint viene aggiunto al messaggio di negazione o istruzione che Claude vede, fornendo una guida pratica senza modificare il codice della politica. Funziona con politiche integrate, personalizzate e di convenzione. Vedi [Configurazione → hint](/it/configuration#hint-cross-cutting) per i dettagli. +Ogni politica supporta un campo opzionale `hint` in `policyParams`. L'hint viene aggiunto al messaggio di negazione o istruzione che Claude vede, fornendo una guida pratica senza modificare il codice della politica. Funziona con politiche integrate, personalizzate e di convenzione. Consulta [Configuration → hint](/it/configuration#hint-cross-cutting) per i dettagli. --- ## Comandi pericolosi -Impedisci agli agent di eseguire operazioni difficili da annullare o che potrebbero danneggiare il sistema host. +Impedisci agli agenti di eseguire operazioni difficili da annullare o che potrebbero danneggiare il sistema host. ### `block-sudo` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi comando `sudo`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi comando `sudo`. -Blocca gli invocazioni che includono la parola chiave `sudo`. L'abbinamento del pattern viene eseguito su token di comando analizzati, non sulla stringa grezza, per prevenire bypass tramite iniezione di operatori shell. +Blocca le invocazioni che includono la parola chiave `sudo`. La corrispondenza del modello viene eseguita sui token di comando analizzati, non sulla stringa grezza, per prevenire il bypass tramite iniezione di operatori shell. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefissi di comando esatti che sono consentiti. Ogni voce viene abbinata ai token argv analizzati. | +| `allowPatterns` | `string[]` | `[]` | Prefissi di comando esatti consentiti. Ogni voce viene confrontata con i token argv analizzati. | **Esempio:** @@ -87,19 +88,19 @@ Blocca gli invocazioni che includono la parola chiave `sudo`. L'abbinamento del Con questa configurazione, `sudo systemctl status nginx` è consentito, ma `sudo rm /etc/hosts` è negato. -I pattern vengono abbinati ai token analizzati, non alla stringa di comando grezza. Ciò previene il bypass tramite operatori shell aggiunti (ad es. `sudo systemctl status x; rm -rf /` non corrisponde a `sudo systemctl status *`). +I modelli vengono confrontati con i token analizzati, non con la stringa di comando grezza. Questo previene il bypass tramite operatori shell aggiunti (ad es. `sudo systemctl status x; rm -rf /` non corrisponde a `sudo systemctl status *`). --- ### `block-rm-rf` -**Event:** PreToolUse (Bash) -**Default:** Nega `rm -rf`, `rm -fr` e altre forme di eliminazione ricorsiva simili. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega `rm -rf`, `rm -fr` e forme simili di eliminazione ricorsiva. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPaths` | `string[]` | `[]` | Percorsi che è sicuro eliminare ricorsivamente (ad es. `/tmp`). | @@ -119,8 +120,8 @@ I pattern vengono abbinati ai token analizzati, non alla stringa di comando grez ### `block-curl-pipe-sh` -**Event:** PreToolUse (Bash) -**Default:** Nega `curl | bash`, `curl | sh`, `wget | bash` e pattern simili. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega `curl | bash`, `curl | sh`, `wget | bash` e modelli simili. Nessun parametro. @@ -128,8 +129,8 @@ Nessun parametro. ### `block-failproofai-commands` -**Event:** PreToolUse (Bash) -**Default:** Nega i comandi che disinstallerebbero o disabiliterebbero failproofai stesso (ad es. `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega comandi che disinstallerebbero o disabiliterebbero failproofai stesso (ad es. `npm uninstall failproofai`, `failproofai policies --uninstall`). Nessun parametro. @@ -137,18 +138,18 @@ Nessun parametro. ## Comandi infra -Impedisci agli agent di codifica di eseguire CLI di infrastruttura o attivare pipeline CI/CD. Tutte le politiche di questa categoria sono **opt-in** (`defaultEnabled: false`) — gli agent che hanno legittimamente bisogno di chiamare `kubectl`, `terraform`, ecc. non saranno disturbati a meno che non abiliti la politica. Quando abilitata, ogni invocazione della CLI abbinata viene negata a meno che il comando non corrisponda a una voce in `allowPatterns`. +Impedisci agli agenti di codifica di eseguire CLI infrastrutturali o attivare pipeline CI/CD. Tutte le politiche in questa categoria sono **opzionali** (`defaultEnabled: false`) — gli agenti che legittimamente devono chiamare `kubectl`, `terraform`, ecc. non saranno disturbati a meno che tu non abiliti la politica. Una volta abilitata, ogni invocazione della CLI corrispondente viene negata a meno che il comando non corrisponda a una voce in `allowPatterns`. -La grammatica del pattern è la stessa di [`block-sudo`](#block-sudo): i token vengono abbinati ai argv analizzati, `*` è un carattere jolly per un token, e qualsiasi comando contenente un operatore shell standalone (`&&`, `||`, `|`, `;`) o un token con metacaratteri shell incorporati viene rifiutato prima dell'abbinamento della lista di consentiti per prevenire bypass di iniezione. +La grammatica del modello è la stessa di [`block-sudo`](#block-sudo): i token vengono confrontati con argv analizzato, `*` è un wildcard per un token, e qualsiasi comando contenente un operatore shell standalone (`&&`, `||`, `|`, `;`) o un token con metacaratteri shell incorporati viene rifiutato prima della corrispondenza della lista di autorizzazione per prevenire bypass di iniezione. ### `block-kubectl` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione di `kubectl`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione `kubectl`. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Prefissi di comando kubectl consentiti. | @@ -170,12 +171,12 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-terraform` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione di `terraform` o `tofu` (OpenTofu). +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione `terraform` o `tofu` (OpenTofu). **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Prefissi di comando terraform/tofu consentiti. | @@ -195,14 +196,14 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-aws-cli` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione della CLI `aws`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione CLI `aws`. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefissi di comando della CLI aws consentiti. | +| `allowPatterns` | `string[]` | `[]` | Prefissi di comando CLI aws consentiti. | **Esempio:** @@ -220,12 +221,12 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-gcloud` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione della CLI `gcloud` (Google Cloud). +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione CLI `gcloud` (Google Cloud). **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Prefissi di comando gcloud consentiti. | @@ -245,14 +246,14 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-az-cli` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione della CLI `az` (Azure). +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione CLI `az` (Azure). **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefissi di comando della CLI az consentiti. | +| `allowPatterns` | `string[]` | `[]` | Prefissi di comando CLI az consentiti. | **Esempio:** @@ -270,12 +271,12 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-helm` -**Event:** PreToolUse (Bash) -**Default:** Nega qualsiasi invocazione di `helm`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega qualsiasi invocazione `helm`. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPatterns` | `string[]` | `[]` | Prefissi di comando helm consentiti. | @@ -295,8 +296,8 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f ### `block-gh-pipeline` -**Event:** PreToolUse (Bash) -**Default:** Nega i seguenti sottocomandi della CLI `gh` che mutano lo stato o attivano pipeline: +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega i seguenti sottocomandi CLI `gh` che mutano lo stato o attivano pipeline: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -305,13 +306,13 @@ Con questa configurazione, `kubectl get pods` è consentito ma `kubectl apply -f - `gh cache delete` - `gh secret set`, `gh secret delete` -I sottocomandi di sola lettura di `gh` come `gh pr view`, `gh pr list`, `gh run list`, `gh release view` e `gh api repos/.../...` **non** vengono abbinati da questa politica — sono regolarmente necessari per i controlli del workflow (incluso il proprio `require-ci-green-before-stop` di failproofai). +I sottocomandi `gh` di sola lettura come `gh pr view`, `gh pr list`, `gh run list`, `gh release view` e `gh api repos/.../...` **non** sono corrispondenti da questa politica — sono regolarmente necessari per i controlli del workflow (incluso il `require-ci-green-before-stop` di failproofai). **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Invocazioni specifiche con script consentite anche se sarebbero altrimenti negate. | +| `allowPatterns` | `string[]` | `[]` | Invocazioni specifiche da script da consentire anche se sarebbero altrimenti negate. | **Esempio:** @@ -327,14 +328,14 @@ I sottocomandi di sola lettura di `gh` come `gh pr view`, `gh pr list`, `gh run --- -## Segreti (sanitizer) +## Segreti (sanitizzatori) -Impedisci agli agent di far trapelare credenziali nel loro contesto o output. Le politiche sanitizer si attivano su eventi **PostToolUse**. Quando Claude esegue un comando Bash, legge un file o chiama qualsiasi strumento, queste politiche ispezionano l'output prima che venga restituito a Claude. Se viene rilevato un pattern di segreto, la politica restituisce una decisione di negazione che impedisce al output di essere passato indietro. +Impedisci agli agenti di perdere credenziali nel loro contesto o output. Le politiche sanitizzatrici si attivano su eventi **PostToolUse**. Quando Claude esegue un comando Bash, legge un file o chiama qualsiasi strumento, queste politiche ispezionano l'output prima che venga restituito a Claude. Se viene rilevato un modello di segreto, la politica restituisce una decisione di negazione che impedisce all'output di essere passato indietro. ### `sanitize-jwt` -**Event:** PostToolUse (tutti gli strumenti) -**Default:** Oscura i token JWT (tre segmenti base64url separati da `.`). +**Evento:** PostToolUse (tutti gli strumenti) +**Predefinito:** Redige i token JWT (tre segmenti base64url separati da `.`). Nessun parametro. @@ -342,14 +343,14 @@ Nessun parametro. ### `sanitize-api-keys` -**Event:** PostToolUse (tutti gli strumenti) -**Default:** Oscura i formati comuni di chiave API: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PAT (`ghp_`), chiavi di accesso AWS (`AKIA`), chiavi Stripe (`sk_live_`, `sk_test_`) e chiavi API Google (`AIza`). +**Evento:** PostToolUse (tutti gli strumenti) +**Predefinito:** Redige i formati di chiave API comuni: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), chiavi di accesso AWS (`AKIA`), chiavi Stripe (`sk_live_`, `sk_test_`), e chiavi API Google (`AIza`). **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Pattern regex aggiuntivi da trattare come segreti. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Modelli regex aggiuntivi da trattare come segreti. | **Esempio:** @@ -370,8 +371,8 @@ Nessun parametro. ### `sanitize-connection-strings` -**Event:** PostToolUse (tutti gli strumenti) -**Default:** Oscura le stringhe di connessione al database che contengono credenziali incorporate (ad es. `postgresql://user:password@host/db`). +**Evento:** PostToolUse (tutti gli strumenti) +**Predefinito:** Redige le stringhe di connessione al database che contengono credenziali incorporate (ad es. `postgresql://user:password@host/db`). Nessun parametro. @@ -379,8 +380,8 @@ Nessun parametro. ### `sanitize-private-key-content` -**Event:** PostToolUse (tutti gli strumenti) -**Default:** Oscura i blocchi PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, ecc.). +**Evento:** PostToolUse (tutti gli strumenti) +**Predefinito:** Redige i blocchi PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, ecc.). Nessun parametro. @@ -388,8 +389,8 @@ Nessun parametro. ### `sanitize-bearer-tokens` -**Event:** PostToolUse (tutti gli strumenti) -**Default:** Oscura gli header `Authorization: Bearer ` dove il token contiene 20 o più caratteri. +**Evento:** PostToolUse (tutti gli strumenti) +**Predefinito:** Redige le intestazioni `Authorization: Bearer ` dove il token è di 20 o più caratteri. Nessun parametro. @@ -397,14 +398,14 @@ Nessun parametro. ## Ambiente -Proteggi la configurazione dell'ambiente sensibile dall'essere letta o esposta da agent. +Proteggi la configurazione dell'ambiente sensibile dalla lettura o dall'esposizione da parte degli agenti. ### `block-env-files` -**Event:** PreToolUse (Bash, Read) -**Default:** Nega la lettura di file `.env` tramite `cat .env`, chiamate dello strumento Read con `.env` come percorso del file, ecc. +**Evento:** PreToolUse (Bash, Read) +**Predefinito:** Nega la lettura dei file `.env` tramite `cat .env`, chiamate dello strumento Read con `.env` come percorso del file, ecc. -Non blocca `.envrc` o altri file adiacenti all'ambiente — solo file denominati esattamente `.env`. +Non blocca `.envrc` o altri file correlati all'ambiente — solo i file denominati esattamente `.env`. Nessun parametro. @@ -412,8 +413,8 @@ Nessun parametro. ### `protect-env-vars` -**Event:** PreToolUse (Bash) -**Default:** Nega i comandi che stampano variabili d'ambiente: `printenv`, `env`, `echo $VAR`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega i comandi che stampano le variabili di ambiente: `printenv`, `env`, `echo $VAR`. Nessun parametro. @@ -421,16 +422,16 @@ Nessun parametro. ## Accesso ai file -Mantieni gli agent dentro i confini del progetto e lontani dai file sensibili. +Mantieni gli agenti lavorando entro i confini del progetto e lontano dai file sensibili. ### `block-read-outside-cwd` -**Event:** PreToolUse (Read, Bash) -**Default:** Nega la lettura di file al di fuori della radice del progetto. Il confine è `CLAUDE_PROJECT_DIR` (impostato una volta per sessione da Claude Code), con fallback alla directory di lavoro corrente della sessione quando quella variabile non è impostata. Utilizzare la radice del progetto piuttosto che il `cwd` in tempo reale significa che il confine rimane stabile anche dopo che Claude fa `cd` in una subdirectory. +**Evento:** PreToolUse (Read, Bash) +**Predefinito:** Nega la lettura di file al di fuori della radice del progetto. Il confine è `CLAUDE_PROJECT_DIR` (impostato una volta per sessione da Claude Code), con fallback alla directory di lavoro corrente della sessione quando quella variabile non è impostata. L'utilizzo della radice del progetto piuttosto che del `cwd` attivo significa che il confine rimane stabile anche dopo che Claude esegue `cd` in una sottodirectory. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `allowPaths` | `string[]` | `[]` | Prefissi di percorso assoluto consentiti anche se al di fuori della radice del progetto. | @@ -450,14 +451,14 @@ Mantieni gli agent dentro i confini del progetto e lontani dai file sensibili. ### `block-secrets-write` -**Event:** PreToolUse (Write, Edit) -**Default:** Nega le scritture su file comunemente utilizzati per chiavi private e certificati: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Evento:** PreToolUse (Write, Edit) +**Predefinito:** Nega le scritture ai file comunemente usati per chiavi private e certificati: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | Pattern di nome file aggiuntivi (stile glob) da bloccare. | +| `additionalPatterns` | `string[]` | `[]` | Modelli di nome file aggiuntivi (stile glob) da bloccare. | **Esempio:** @@ -475,16 +476,16 @@ Mantieni gli agent dentro i confini del progetto e lontani dai file sensibili. ## Git -Previeni push accidentali, force-push e errori di branch difficili da annullare. +Previeni i push accidentali, i force-push e gli errori di branch difficili da annullare. ### `block-push-master` -**Event:** PreToolUse (Bash) -**Default:** Nega `git push origin main` e `git push origin master`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega `git push origin main` e `git push origin master`. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | Nomi di branch che non possono essere pushati direttamente. | @@ -501,19 +502,19 @@ Previeni push accidentali, force-push e errori di branch difficili da annullare. ``` -Per consentire il push a tutti i branch (disabilitando effettivamente questa politica senza rimuoverla da `enabledPolicies`), imposta `protectedBranches: []`. +Per consentire il push in tutti i branch (effettivamente disabilitando questa politica senza rimuoverla da `enabledPolicies`), impostare `protectedBranches: []`. --- ### `block-work-on-main` -**Event:** PreToolUse (Bash) -**Default:** Nega `git commit`, `git merge`, `git rebase` e `git cherry-pick` mentre l'albero di lavoro è su `main` o `master`. La creazione e il cambio di branch (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) non sono interessati. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega `git commit`, `git merge`, `git rebase` e `git cherry-pick` mentre l'albero di lavoro è su `main` o `master`. La creazione e il cambio di branch (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) non sono interessati. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | Nomi di branch su cui commit/merge/rebase/cherry-pick è negato. | @@ -521,8 +522,8 @@ Per consentire il push a tutti i branch (disabilitando effettivamente questa pol ### `block-force-push` -**Event:** PreToolUse (Bash) -**Default:** Nega `git push --force` e `git push -f`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Nega `git push --force` e `git push -f`. Nessun parametro specifico della politica. Usa il [`hint`](/it/configuration#hint-cross-cutting) cross-cutting per suggerire alternative: @@ -530,7 +531,7 @@ Nessun parametro specifico della politica. Usa il [`hint`](/it/configuration#hin { "policyParams": { "block-force-push": { - "hint": "Crea un nuovo branch dal tuo HEAD attuale (ad es. `git checkout -b `) e fai il push di quello." + "hint": "Crea un nuovo branch dal tuo HEAD attuale (ad es. `git checkout -b `) e pusha quello invece." } } } @@ -540,8 +541,8 @@ Nessun parametro specifico della politica. Usa il [`hint`](/it/configuration#hin ### `warn-git-amend` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a procedere con cautela quando esegue `git commit --amend`. Non blocca il comando. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a procedere con cautela quando esegue `git commit --amend`. Non blocca il comando. Nessun parametro. @@ -549,8 +550,8 @@ Nessun parametro. ### `warn-git-stash-drop` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a confermare prima di eseguire `git stash drop`. Non blocca il comando. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a confermare prima di eseguire `git stash drop`. Non blocca il comando. Nessun parametro. @@ -558,8 +559,8 @@ Nessun parametro. ### `warn-all-files-staged` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a rivedere cosa sta staged quando esegue `git add -A` o `git add .`. Non blocca il comando. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a rivedere cosa sta preparando quando esegue `git add -A` o `git add .`. Non blocca il comando. Nessun parametro. @@ -567,12 +568,12 @@ Nessun parametro. ## Database -Cattura le operazioni SQL distruttive prima che vengono eseguite sul tuo database. +Rileva le operazioni SQL distruttive prima che vengano eseguite contro il tuo database. ### `warn-destructive-sql` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a confermare prima di eseguire SQL contenente `DROP TABLE`, `DROP DATABASE` o `DELETE` senza una clausola `WHERE`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a confermare prima di eseguire SQL contenente `DROP TABLE`, `DROP DATABASE` o `DELETE` senza una clausola `WHERE`. Nessun parametro. @@ -580,8 +581,8 @@ Nessun parametro. ### `warn-schema-alteration` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a confermare prima di eseguire istruzioni `ALTER TABLE`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a confermare prima di eseguire le istruzioni `ALTER TABLE`. Nessun parametro. @@ -589,18 +590,18 @@ Nessun parametro. ## Avvisi -Fornisci agli agent un contesto extra prima di operazioni potenzialmente rischiose ma non distruttive. +Fornisci ai agenti un contesto extra prima di operazioni potenzialmente rischiose ma non distruttive. ### `warn-large-file-write` -**Event:** PreToolUse (Write) -**Default:** Istruisce Claude a confermare prima di scrivere file più grandi di 1024 KB. +**Evento:** PreToolUse (Write) +**Predefinito:** Istruisce Claude a confermare prima di scrivere file più grandi di 1024 KB. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | Soglia di dimensione file in kilobyte al di sopra della quale viene emesso un avviso. | +| `thresholdKb` | `number` | `1024` | Soglia di dimensione del file in kilobyte al di sopra della quale viene emesso un avviso. | **Esempio:** @@ -615,15 +616,15 @@ Fornisci agli agent un contesto extra prima di operazioni potenzialmente rischio ``` -Il gestore dell'hook applica un limite stdin di 1 MB sui payload. Per testare questa politica con contenuto piccolo, imposta `thresholdKb` a un valore ben al di sotto di 1024. +Il gestore dell'hook applica un limite stdin di 1 MB sui payload. Per testare questa politica con contenuti piccoli, imposta `thresholdKb` su un valore ben al di sotto di 1024. --- ### `warn-package-publish` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a confermare prima di eseguire `npm publish`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a confermare prima di eseguire `npm publish`. Nessun parametro. @@ -631,8 +632,8 @@ Nessun parametro. ### `warn-background-process` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a fare attenzione quando avvia processi in background tramite `nohup`, `&`, `disown` o `screen`. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a prestare attenzione quando lancia processi di background tramite `nohup`, `&`, `disown` o `screen`. Nessun parametro. @@ -640,8 +641,8 @@ Nessun parametro. ### `warn-global-package-install` -**Event:** PreToolUse (Bash) -**Default:** Istruisce Claude a confermare prima di eseguire `npm install -g`, `yarn global add` o `pip install` senza un ambiente virtuale. +**Evento:** PreToolUse (Bash) +**Predefinito:** Istruisce Claude a confermare prima di eseguire `npm install -g`, `yarn global add` o `pip install` senza un ambiente virtuale. Nessun parametro. @@ -649,21 +650,21 @@ Nessun parametro. ## Gestori di pacchetti -Applica quale gestore di pacchetti l'agent è autorizzato a utilizzare. +Applica quale gestore di pacchetti l'agente è autorizzato a utilizzare. ### `prefer-package-manager` -**Event:** PreToolUse (Bash) -**Default:** Disabilitato. Quando abilitato, blocca qualsiasi comando del gestore di pacchetti non nell'elenco `allowed` e dice a Claude di riscrivere il comando usando un gestore autorizzato. +**Evento:** PreToolUse (Bash) +**Predefinito:** Disabilitato. Una volta abilitato, blocca qualsiasi comando del gestore di pacchetti non nella lista `allowed` e istruisce Claude a riscrivere il comando usando un gestore consentito. Rileva: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Nomi dei gestori di pacchetti autorizzati. Qualsiasi gestore rilevato non in questo elenco è bloccato. Quando vuoto, la politica è una no-op. | -| `blocked` | string[] | `[]` | Nomi di gestori aggiuntivi da bloccare oltre l'elenco integrato (ad es. `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Nomi dei gestori di pacchetti consentiti. Qualsiasi gestore rilevato non in questa lista è bloccato. Quando vuoto, la politica è un no-op. | +| `blocked` | string[] | `[]` | Nomi di gestori aggiuntivi da bloccare oltre la lista incorporata (ad es. `['pdm', 'pipx']`). | -L'elenco di blocco integrato copre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Usa `blocked` per aggiungere gestori non in questo elenco. +La lista di blocco incorporata copre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Usa `blocked` per aggiungere gestori non in questa lista. **Configurazione di esempio:** @@ -679,18 +680,18 @@ L'elenco di blocco integrato copre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, } ``` -Con questa configurazione, `pip install flask` e `pdm install flask` sono entrambi negati con un messaggio che dice a Claude di usare `uv` o `bun` invece. I comandi come `uv pip install flask` sono consentiti perché `uv` è nell'elenco di consentiti e viene controllato per primo. +Con questa configurazione, `pip install flask` e `pdm install flask` sono entrambi negati con un messaggio che istruisce Claude a usare `uv` o `bun` invece. I comandi come `uv pip install flask` sono consentiti perché `uv` è nella lista di autorizzazione e viene controllato per primo. --- ## Comportamento AI -Rileva quando gli agent rimangono bloccati o si comportano inaspettatamente. +Rileva quando gli agenti rimangono bloccati o si comportano in modo inaspettato. ### `warn-repeated-tool-calls` -**Event:** PreToolUse (tutti gli strumenti) -**Default:** Istruisce Claude a riconsiderare quando lo stesso strumento viene chiamato 3+ volte con parametri identici — un segno comune che l'agent è bloccato in un loop. +**Evento:** PreToolUse (tutti gli strumenti) +**Predefinito:** Istruisce Claude a riconsiderare quando lo stesso strumento viene chiamato 3+ volte con parametri identici — un segno comune che l'agente è bloccato in un ciclo. Nessun parametro. @@ -698,40 +699,39 @@ Nessun parametro. ## Workflow -Applica un workflow di fine sessione disciplinato. Queste politiche si attivano sull'evento **Stop** e negano all'agent di fermarsi fino a quando ogni condizione non è soddisfatta. Seguono una catena di dipendenza naturale: commit → push → PR → CI. Se una politica nega, le politiche successive nella catena vengono saltate (negare shortcircuit). +Applica un workflow disciplinato di fine sessione. Queste politiche si attivano sull'evento **Stop** e negano all'agente di fermarsi finché ogni condizione non è soddisfatta. Seguono una naturale catena di dipendenze: commit → push → PR → CI. Se una politica nega, le politiche successive nella catena vengono saltate (la negazione short-circuit). -Tutte le politiche di workflow sono **fail-open**: se lo strumento richiesto non è disponibile (ad es. `gh` non installato, nessun remote git), la politica consente con un messaggio informativo che spiega perché il controllo è stato saltato. +Tutte le politiche di workflow sono **fail-open**: se lo strumento richiesto non è disponibile (ad es. `gh` non installato, nessun git remote), la politica consente con un messaggio informativo che spiega perché il controllo è stato saltato. -### Semantica di Stop per CLI +### Semantica Stop per CLI -L'applicazione di Stop varia leggermente tra i sette CLI supportati perché ognuno espone un contratto di hook diverso per il completamento dell'agent. Il **risultato** è lo stesso — l'agent non riuscirà a fermarsi mentre un gate di workflow sta fallendo — ma la **meccanica** differisce. La tabella sottostante riassume; solo Pi ha una peculiarità visibile all'utente che vale la pena comprendere prima di abilitare una politica `require-*-before-stop`. +L'applicazione Stop sembra leggermente diversa tra i sei CLI supportati perché ognuno espone un diverso contratto di hook agent finito. Il **risultato** è lo stesso — l'agente non se la fa passare fermandosi mentre un gate del workflow sta fallendo — ma i **meccanismi** differiscono. La tabella seguente riassume; solo Pi ha una peculiarità visibile all'utente che vale la pena comprendere prima di abilitare una politica `require-*-before-stop`. -| CLI | Quando si attiva il gate | Cosa vedi | +| CLI | Quando il gate si attiva | Cosa vedi | |---|---|---| -| Claude Code | Stesso loop dell'agent, immediatamente | Claude continua a lavorare — corregge il problema, quindi tenta di terminare di nuovo. Nessuna interruzione visibile. | -| Codex | Stesso loop dell'agent, immediatamente | Come Claude. | -| GitHub Copilot CLI | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale di retry `{decision:"block", reason}` di Copilot — verificato empiricamente contro Copilot CLI 1.0.41). | -| Cursor Agent | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale `{followup_message}` di Cursor — limitato a `loop_limit`, default 5 retry). | -| Gemini CLI | Stesso loop dell'agent, immediatamente | Come Claude (usa il canale `{decision:"block", reason}` di Gemini su `AfterAgent`). | -| OpenCode | Stesso loop dell'agent, immediatamente | Come Claude (usa la chiamata SDK `client.session.prompt(...)` di OpenCode instradato tramite `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **Turno utente successivo** | **Pi si ferma visibilmente** quando il gate si attiva — il suo loop di agent esce e sei riportato al prompt. Il gate si attiva quindi la prossima volta che invii un prompt: failproofai prepone una direttiva `MANDATORY ACTION REQUIRED` al prompt di sistema di quel turno, istruendo il LLM a completare il passo del workflow (commit, push, ecc.) prima di fare tutto quello che hai chiesto. | +| Claude Code | Stesso ciclo dell'agente, immediatamente | Claude continua a lavorare — risolve il problema, quindi tenta di finire di nuovo. Nessun'interruzione visibile per te. | +| Codex | Stesso ciclo dell'agente, immediatamente | Uguale a Claude. | +| GitHub Copilot CLI | Stesso ciclo dell'agente, immediatamente | Uguale a Claude (usa il canale di ritentativo `{decision:"block", reason}` di Copilot — verificato empiricamente rispetto a Copilot CLI 1.0.41). | +| Cursor Agent | Stesso ciclo dell'agente, immediatamente | Uguale a Claude (usa il canale `{followup_message}` di Cursor — limitato a `loop_limit`, default 5 ritentative). | +| OpenCode | Stesso ciclo dell'agente, immediatamente | Uguale a Claude (usa la chiamata SDK `client.session.prompt(...)` di OpenCode instradata attraverso `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **Turno utente successivo** | **Pi si ferma visibilmente** quando il gate si attiva — il suo ciclo dell'agente esce e sei ritornato al prompt. Il gate si attiva quindi la prossima volta che invii un prompt: failproofai prepone una direttiva `MANDATORY ACTION REQUIRED` al prompt di sistema di quel turno, istruendo l'LLM a completare il passaggio del workflow (commit, push, ecc.) prima di fare quello che hai chiesto. | -**Limitazione di Pi.** L'evento `AgentEndEvent` di Pi (l'equivalente upstream dell'hook `Stop` di Claude) non ha un tipo Result — nel momento in cui si attiva, il loop di agent di Pi è già uscito. Pi non può essere forzato a riprovare lo stesso loop nel modo in cui Claude / Copilot / Cursor / Gemini / OpenCode possono. failproofai sposta il gate all'evento `before_agent_start` di Pi (che si attiva dopo il prossimo prompt dell'utente) in modo che il controllo del workflow ancora si applichi, solo al turno successivo piuttosto che al turno corrente. +**Limitazione di Pi.** L'`AgentEndEvent` di Pi (l'equivalente upstream dell'hook `Stop` di Claude) non ha un tipo di Result — al momento in cui si attiva, il ciclo dell'agente di Pi è già uscito. Pi non può essere forzato a ritentare lo stesso ciclo nel modo in cui Claude / Copilot / Cursor / OpenCode possono. failproofai sposta il gate all'evento `before_agent_start` di Pi (che si attiva dopo il prompt utente successivo) in modo che il controllo del workflow ancora si applica, solo il turno successivo piuttosto che il turno attuale. -**Cosa significa nella pratica:** +**Cosa significa in pratica:** -- Dopo che Pi si ferma, il motivo della negazione viene catturato in memoria keyed dall'ID sessione di Pi. Il prossimo prompt che invii nello stesso processo Pi lo scarica: l'LLM vede la direttiva `MANDATORY ACTION REQUIRED` in cima al suo prompt di sistema, fa il commit (o push / apre il PR / aspetta CI), e solo allora continua con la tua richiesta. Il motivo della negazione catturato è monouso — una volta scaricato, il gate è pulito. -- Il gate è limitato dalla durata del processo di Pi. Se fai `Ctrl+C` su Pi o esci tra i turni, la voce in memoria viene eliminata insieme al processo e il gate viene mancato. Claude, Copilot, Cursor, Gemini e OpenCode hanno lo stesso limite (uccidi l'agent e il gate viene mancato) — Pi lo rende solo più visibile perché l'agent si ferma visibilmente prima che il gate si attivi. -- Una negazione in sospeso viene anche cancellata su `session_shutdown` per qualsiasi motivo (`new` / `resume` / `fork` / `quit`), quindi un gate stantio da una sessione precedente non può fuoriuscire in una sessione fresca avviata nello stesso processo Pi. +- Dopo che Pi si ferma, il motivo della negazione viene acquisito in memoria con chiave dell'id sessione Pi. Il prompt molto successivo che invii nella stessa sessione Pi lo scarica: l'LLM vede la direttiva `MANDATORY ACTION REQUIRED` in cima al suo prompt di sistema, esegue il commit (o push / apre il PR / aspetta CI), e solo allora continua con la tua richiesta. Il motivo della negazione acquisito è una tantum — una volta scaricato, il gate è chiaro. +- Il gate è limitato dalla durata del processo Pi. Se premi `Ctrl+C` Pi o esci tra i turni, la voce in memoria viene scartata insieme al processo e il gate viene mancato. Claude, Copilot, Cursor e OpenCode hanno lo stesso limite (uccidi l'agente e il gate viene mancato) — Pi lo rende solo più visibile perché l'agente esce visibilmente prima che il gate si attivi. +- Una negazione in sospeso viene anche cancellata su `session_shutdown` per qualsiasi motivo (`new` / `resume` / `fork` / `quit`), quindi un gate obsoleto da una sessione precedente non può trapelare in una sessione nuova avviata nello stesso processo Pi. -Se hai bisogno del retry dello stesso loop nello stile di Claude, esegui le tue politiche di `Stop` sotto uno dei sei altri CLI supportati. Stiamo monitorando Pi upstream per un tipo Result futuro su `AgentEndEvent` che ci permetterebbe di chiudere questo gap. +Se hai bisogno di un ritentativo dello stesso ciclo in stile Claude, esegui le tue politiche `Stop` su uno qualsiasi degli altri cinque CLI supportati. Stiamo tracciando Pi upstream per un futuro tipo di Result su `AgentEndEvent` che ci permetterebbe di colmare questo divario. ### `require-commit-before-stop` -**Event:** Stop -**Default:** Nega il stop quando ci sono modifiche non committate (file modificati, staged o untracked). Restituisce un messaggio informativo quando la directory di lavoro è pulita. +**Evento:** Stop +**Predefinito:** Nega la fermata quando ci sono modifiche non committate (file modificati, preparati o non tracciati). Restituisce un messaggio informativo quando la directory di lavoro è pulita. Nessun parametro. @@ -739,14 +739,14 @@ Nessun parametro. ### `require-push-before-stop` -**Event:** Stop -**Default:** Nega il stop quando ci sono commit non pushati o quando il branch corrente non ha un branch di tracking remoto. Suggerisce `git push -u` per creare un branch di tracking se necessario. Si apre se nessun remote è configurato. +**Evento:** Stop +**Predefinito:** Nega la fermata quando ci sono commit non pushati o quando il branch attuale non ha un branch di tracking remoto. Suggerisce `git push -u` per creare un branch di tracking se necessario. Fail open se nessun remote è configurato. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | Nome del remote a cui fare push. | +| `remote` | `string` | `"origin"` | Nome del remote su cui pushare. | **Esempio:** @@ -764,55 +764,55 @@ Nessun parametro. ### `require-pr-before-stop` -**Event:** Stop -**Default:** Nega il stop quando non esiste una pull request per il branch corrente, o quando la PR esistente è chiusa senza essere mergiata. Istruisce Claude a creare una PR con `gh pr create`. Quando la PR è **mergiata**, la politica consente (il lavoro è stato spedito) e il messaggio suggerisce di passare dal branch (`git checkout main && git pull`). +**Evento:** Stop +**Predefinito:** Nega la fermata quando non esiste una pull request per il branch attuale, o quando il PR esistente è chiuso senza essere mergiato. Istruisce Claude a creare un PR con `gh pr create`. Quando il PR è **mergiato**, la politica consente (il lavoro è stato spedito) e il messaggio suggerisce di staccarsi dal branch (`git checkout main && git pull`). Nessun parametro. -Questa politica richiede che la [GitHub CLI](https://cli.github.com/) (`gh`) sia installata e autenticata. -Esegui `gh auth login` con un token di accesso personale che ha scope `repo` per l'accesso in lettura alle -pull request. Se `gh` non è installato o non autenticato, la politica si apre e riporta il motivo a Claude. +Questa politica richiede [GitHub CLI](https://cli.github.com/) (`gh`) installato e autenticato. +Esegui `gh auth login` con un token di accesso personale che ha `repo` come scope per l'accesso in lettura ai +pull request. Se `gh` non è installato o non autenticato, la politica fail open e riporta il motivo a Claude. --- ### `require-no-conflicts-before-stop` -**Event:** Stop -**Default:** Nega il stop quando il branch corrente non può essere cleanly mergiato nel branch base. La politica prima conferma che esiste una PR `OPEN` su GitHub per il branch — senza una, non c'è target di merge da applicare, quindi l'intera politica shortcircuit per consentire. Una volta confermata una PR `OPEN`, due probe indipendenti vengono eseguite: +**Evento:** Stop +**Predefinito:** Nega la fermata quando il branch attuale non può mergiare in modo pulito nel branch base. La politica prima conferma che esiste un PR `OPEN` su GitHub per il branch — senza uno, non c'è nessun bersaglio di merge da applicare, quindi l'intera politica short-circuit per consentire. Una volta confermato un PR `OPEN`, due sonde indipendenti si eseguono: -1. **Locale** — `git merge-tree --write-tree --name-only origin/ HEAD`. Su conflitto, il messaggio di negazione nomina i file in conflitto in modo che Claude sappia esattamente cosa risolvere. -2. **GitHub** — riusa il risultato `gh pr view --json mergeable,state` già recuperato nel precheck. Cattura i conflitti che un `origin/` locale stantio perderebbe (ad es. qualcuno ha atterrato una PR in conflitto su `main` dall'ultimo fetch). Un risultato `CONFLICTING` nega. Un risultato `UNKNOWN` nega anche e istruisce Claude ad aspettare ~10 secondi e ri-controllare prima di tentare di fermarsi di nuovo — questo previene falsi negativi mentre GitHub ricalcola. +1. **Locale** — `git merge-tree --write-tree --name-only origin/ HEAD`. In caso di conflitto, il messaggio di negazione nomina i file in conflitto in modo che Claude sappia esattamente cosa risolvere. +2. **GitHub** — riusa il risultato `gh pr view --json mergeable,state` già recuperato nel precheck. Rileva i conflitti che un `origin/` locale stantio potrebbe perdere (ad es. qualcuno ha atterrato un PR in conflitto su `main` dall'ultimo fetch). Un risultato `CONFLICTING` nega. Un risultato `UNKNOWN` anche nega e istruisce Claude ad aspettare ~10 secondi e ri-controllare prima di tentare di fermarsi di nuovo — questo previene i falsi negativi mentre GitHub ricalcola. -Si salta interamente (consente) quando: `gh` non è installato, non esiste PR per il branch, lo stato della PR non è `OPEN` (ad es. `MERGED`, `CLOSED`), o `gh pr view` restituisce output non parseable. Si apre anche quando `origin/` manca localmente o quando non ci sono commit davanti a base — quei fallthrough del Layer 1 consultano ancora il mergeability della PR cachato prima di consentire. +Salta interamente (consente) quando: `gh` non è installato, nessun PR esiste per il branch, lo stato del PR non è `OPEN` (ad es. `MERGED`, `CLOSED`), o `gh pr view` restituisce output non parsificabile. Anche fail open quando `origin/` è mancante localmente o quando nessun commit è in anticipo rispetto al base — quelle scappatoie Layer 1 ancora consultano la mergeabilità del PR in cache prima di consentire. **Parametri:** -| Parametro | Tipo | Default | Descrizione | +| Parametro | Tipo | Predefinito | Descrizione | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Branch base contro cui controllare i conflitti. | +| `baseBranch` | `string` | `"main"` | Branch base su cui controllare i conflitti. | -GitHub CLI (`gh`) è richiesta per questa politica. La politica usa `gh pr view` per confermare -che una PR `OPEN` esiste prima di eseguire qualsiasi probe di conflitto — senza `gh`, la politica -shortcircuit per consentire. Esegui `gh auth login` con un token di accesso personale che ha -scope `repo` per l'accesso in lettura alle pull request. +GitHub CLI (`gh`) è richiesto per questa politica. La politica usa `gh pr view` per confermare +che esiste un PR `OPEN` prima di eseguire qualsiasi sonda di conflitto — senza `gh`, la politica +short-circuit per consentire. Esegui `gh auth login` con un token di accesso personale che ha +`repo` come scope per l'accesso in lettura ai pull request. --- ### `require-ci-green-before-stop` -**Event:** Stop -**Default:** Nega il stop quando i controlli CI stanno fallendo o sono ancora in corso sul branch corrente. Controlla sia i workflow di GitHub Actions che i controlli di bot di terze parti (ad es. CodeRabbit, SonarCloud, Codecov). Tratta `skipped`, `cancelled` e `neutral` conclusioni come non-fallenti (quest'ultimo copre ad es. avvisi Socket Security su PR di collaboratori esterni, dove l'app intenzionalmente riporta neutral anziché success/failure). Restituisce un messaggio informativo quando tutti i controlli passano. +**Evento:** Stop +**Predefinito:** Nega la fermata quando i controlli CI stanno fallendo o ancora in esecuzione sul branch attuale. Controlla sia le esecuzioni del workflow GitHub Actions che i controlli di bot di terze parti (ad es. CodeRabbit, SonarCloud, Codecov). Tratta le conclusioni `skipped`, `cancelled` e `neutral` come non-fallanti (quest'ultima copre ad es. gli avvisi di Socket Security su PR di collaboratori esterni, dove l'app intenzionalmente riporta neutral piuttosto che successo/fallimento). Restituisce un messaggio informativo quando tutti i controlli passano. Nessun parametro. -Questa politica richiede che la [GitHub CLI](https://cli.github.com/) (`gh`) sia installata e autenticata. -Esegui `gh auth login` con un token di accesso personale che ha scope `repo` per l'accesso in lettura a -workflow run di Actions e all'API Checks. Se `gh` non è installato o non autenticato, la politica si apre e riporta il motivo a Claude. +Questa politica richiede [GitHub CLI](https://cli.github.com/) (`gh`) installato e autenticato. +Esegui `gh auth login` con un token di accesso personale che ha `repo` come scope per l'accesso in lettura al +workflow Actions runs e all'API Checks. Se `gh` non è installato o non autenticato, la politica fail open e riporta il motivo a Claude. --- @@ -821,7 +821,7 @@ workflow run di Actions e all'API Checks. Se `gh` non è installato o non autent ## Disabilitare politiche individuali -Rimuovi una politica specifica da `enabledPolicies` nella tua configurazione, o disabilitala nella tab Politiche della dashboard. +Rimuovi una politica specifica da `enabledPolicies` nella tua configurazione, o disattivala nella scheda Politiche del dashboard. ```json { @@ -832,4 +832,4 @@ Rimuovi una politica specifica da `enabledPolicies` nella tua configurazione, o } ``` -Le politiche non elencate in `enabledPolicies` non vengono eseguite, anche se esistono voci `policyParams` per loro. \ No newline at end of file +Le politiche non elencate in `enabledPolicies` non si eseguono, anche se esistono voci `policyParams` per esse. \ No newline at end of file diff --git a/docs/it/cli/audit.mdx b/docs/it/cli/audit.mdx index 7e463043..919c79f7 100644 --- a/docs/it/cli/audit.mdx +++ b/docs/it/cli/audit.mdx @@ -1,23 +1,23 @@ --- -title: Controllare sessioni passate (beta) -description: "Conta quante volte l'agente ha fatto cose inefficienti o rischiose nei transcript passati" +title: Audit delle sessioni passate (beta) +description: "Conta quante volte l'agente ha fatto cose inutili o rischiose nei transcript passati" --- - **Funzione beta.** L'audit è fornito in beta mentre raccogliamo i primi feedback. + **Funzione beta.** L'audit è distribuito come beta mentre raccogliamo i feedback iniziali. Il catalogo dei rilevatori e il formato del report potrebbero cambiare prima della prossima versione stabile. Apri un issue se qualcosa non ti sembra giusto. -L'audit riesegue i tuoi transcript passati da agent-CLI attraverso il motore di policy di failproofai e genera un report visivo e condivisibile sulla **pagina dashboard `/audit`** — l'archetipo dell'agente, un punteggio 0–100, e esattamente quali policy avrebbero catturato cosa. +L'audit riproduce i tuoi transcript passati dell'agente-CLI attraverso il motore di policy di failproofai e genera un report visivo e condivisibile nella **pagina dashboard `/audit`** — l'archetipo dell'agente, un punteggio da 0–100, e esattamente quali policy avrebbero bloccato cosa. -## Eseguirlo +## Come eseguirlo -Tre modi per iniziare — tutti portano allo stesso report `/audit`. +Tre modi per entrare — tutti portano allo stesso report `/audit`. -```bash npx (nessuna installazione) +```bash npx (senza installazione) npx -y failproofai audit ``` @@ -32,62 +32,62 @@ failproofai - + `npx -y failproofai audit` scarica failproofai, esegue la scansione e apre il dashboard per te — niente da installare prima. - - `failproofai audit` esegue la scansione nel tuo terminale, poi apre automaticamente - `localhost:8020/audit` quando termina. + + `failproofai audit` esegue la scansione nel tuo terminale, poi apre + `localhost:8020/audit` automaticamente al termine. - Esegui `failproofai` e clicca **Audit** nella navbar (tra Policies e + Esegui `failproofai` e fai clic su **Audit** nella barra di navigazione (tra Policies e Projects), oppure apri `/audit` direttamente. - Esegui `failproofai audit -h` (o `--help`) per vedere l'utilizzo. L'audit funziona **completamente - offline** — nessun account o connessione di rete richiesti — e il dashboard continua a servire - finché non lo arresti con `Ctrl+C`. + Esegui `failproofai audit -h` (o `--help`) per vedere l'uso. L'audit gira **completamente + offline** — nessun account o rete richiesta — e il dashboard continua a servire + finché non lo interrompi con `Ctrl+C`. -Il dashboard scansiona i transcript passati da agent CLI su questa macchina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e segnala con che frequenza l'agente ha fatto cose che failproofai è costruito per bloccare — controlli di variabili d'ambiente, push forzati, prefissi `cd ` ridondanti, loop di polling con sleep, ri-letture di file appena modificati, e altro. +Il dashboard scansiona i transcript passati dell'agente CLI su questa macchina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e riporta quante volte l'agente ha fatto cose che failproofai è costruito per bloccare — controlli di variabili d'ambiente, push forzati, prefissi `cd ` ridondanti, loop di polling con sleep, rilettura di file appena modificati, e altro ancora. -Per ogni transcript, ogni evento tool-use viene rieseguito attraverso le 39 policy integrate **e** attraverso 8 rilevatori solo audit che catturano pattern non ancora coperti da policy runtime. I conteggi vengono aggregati per policy / rilevatore in tutte le sessioni. +Per ogni transcript, ogni evento di tool-use viene riprodotto attraverso le 39 policy builtin **e** attraverso 8 rilevatori solo-audit che catturano pattern non ancora coperti dalle policy di runtime. I conteggi vengono aggregati per policy / rilevatore in tutte le sessioni. -## Cosa ottieni +## Quello che ottieni -La pagina `/audit` è un **poster** a schermo intero e condivisibile seguito da quattro sezioni sotto il fold: +La pagina `/audit` è un **poster** su un'unica schermata e condivisibile seguito da quattro sezioni sottostanti: -1. **Poster** — l'identità del tuo agente a colpo d'occhio: il suo **archetipo** (uno tra 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), le sue parole chiave di persona, quanto raro è quell'archetipo, e un **punteggio 0–100** con una fascia di livello (`S` fino a `bottom tier`). Costruito per condividere — pubblica su X o LinkedIn, o scaricalo come PNG. -2. **`// strengths`** — cosa fa già bene il tuo agente, come numeri reali dalla scansione (es. clean-tool-call %, `0` tentativi push-to-main), mostrato solo dove la policy rilevante ha un record pulito. -3. **`// quirks`** — cosa è sfuggito: una tabella ordinata di comportamenti che failproofai avrebbe catturato — *quando* è successo per ultimo, *cosa è sfuggito* (e il builtin che l'avrebbe bloccato), la sua *severity*, e quante volte è stato *visto* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — la lista di correzioni prescritte: una riga per policy con un `failproofai policy add ` pronto da copiare-incollare, più un pulsante **install all** che abilita tutti i consigli contemporaneamente e mostra il tuo **punteggio previsto** se lo facessi. -5. **`// come back better`** — costruisci l'abitudine: imposta un **reminder** email di re-audit (`3d` / `7d` / `14d` / `30d`) o re-audit ora, e **invita un amico** a eseguire il loro audit (inviato da failproof.ai, Cc a te). I reminder e gli inviti richiedono login — vedi [`failproofai auth`](/it/cli/auth). +1. **Poster** — l'identità del tuo agente a colpo d'occhio: il suo **archetipo** (uno di 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), le sue parole chiave di persona, quanto raro sia quell'archetipo, e un **punteggio da 0–100** con una banda di livello (`S` fino a `bottom tier`). Costruito per condividere — posta su X o LinkedIn, o scaricalo come PNG. +2. **`// strengths`** — quello che il tuo agente fa già bene, come numeri reali dalla scansione (es. clean-tool-call %, `0` tentativi push-to-main), mostrato solo dove la policy rilevante ha un record pulito. +3. **`// quirks`** — quello che è sfuggito: una tabella classificata di comportamenti che failproofai avrebbe bloccato — *quando* è accaduto l'ultima volta, *cosa è sfuggito* (e il builtin che lo avrebbe bloccato), la sua *severity*, e quante volte è stato *visto* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — la lista delle correzioni prescritte: una riga per policy con `failproofai policy add ` copia-incolla, più un pulsante **install all** che abilita tutte le raccomandazioni contemporaneamente e mostra il tuo **projected score** se lo farai. +5. **`// come back better`** — costruisci l'abitudine: imposta un **reminder** di re-audit via email (`3d` / `7d` / `14d` / `30d`) o re-audit ora, e **invita un amico** a eseguire il proprio audit (inviato da failproof.ai, Cc'd a te). I reminder e gli inviti richiedono sign-in — vedi [`failproofai auth`](/it/cli/auth). -## Rilevatori solo audit +## Rilevatori solo-audit -Questi rilevano pattern di "comportamento stupido" non (ancora) forzati in tempo reale. Funzionano solo durante l'audit e non bloccano mai una chiamata tool in diretta. +Questi rilevano pattern di "comportamento stupido" non (ancora) applicati in tempo reale. Girano solo durante l'audit e non bloccano mai una chiamata di tool live. | Rilevatore | Cosa conta | |---|---| -| `redundant-cd-cwd` | Comandi Bash che iniziano con `cd && …` anche se i comandi già funzionano in `cwd`. | +| `redundant-cd-cwd` | Comandi Bash che iniziano con `cd && …` anche se i comandi girano già in `cwd`. | | `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` su un singolo file sorgente — usa lo strumento `Read`. | -| `prefer-edit-over-sed-awk` | In-place edits `sed -i` / `awk … > file` — usa lo strumento `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / `echo > file` multi-riga che scrivono file — usa lo strumento `Write`. | -| `sleep-polling-loop` | Long `sleep N` (≥ 30s) o loop di polling `while …; sleep …; done`. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, ecc. — limita a `cwd` invece. | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` in-place edits — usa lo strumento `Edit`. | +| `prefer-write-over-heredoc` | Heredoc / multi-riga `echo > file` che scrivono file — usa lo strumento `Write`. | +| `sleep-polling-loop` | Long `sleep N` (≥ 30s) o `while …; sleep …; done` polling loops. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — limita a `cwd` invece. | | `git-commit-no-verify` | `git commit … --no-verify` / `-n`, saltando gli hook. | | `reread-after-edit` | `Read` di un file che è stato appena `Edit`/`Write` nella stessa sessione. | ## Cache -- **Cache per-transcript** in `~/.failproofai/cache/audit/.json` indicizzata da `(mtime, size, engineVersion, detectorVersion)` — invalida automaticamente quando il transcript o il codice della policy/rilevatore cambia. Ogni voce memorizza anche un timestamp `cachedAt` come **metadati TTL** (non parte della chiave cache); le voci più vecchie di **7 giorni** vengono rifiutate alla lettura così i risultati di lunga durata non sopravvivono all'intento rilevatore in evoluzione. -- **Cache di risultato intero** in `~/.failproofai/audit-dashboard.json` (modalità 0600). Permette al dashboard di renderizzarsi istantaneamente sulla navigazione senza rieseguire. Anche rifiutato alla lettura passato il **TTL di 7 giorni** — `/audit` cade quindi nel suo stato vuoto e richiede un'esecuzione fresca. Clicca `[ re-audit now ]` vicino al fondo del report per aggiornare — re-audit invia `noCache: true`, quindi bypassa la cache per-transcript e riscansiona ogni transcript invece di restituire il risultato cache; l'esecuzione trasmette il progresso via una striscia appiccicosa in alto e scambia il risultato in posizione al successo (nessun reload della pagina; un re-audit fallito mantiene il report precedente). +- **Cache per-transcript** in `~/.failproofai/cache/audit/.json` con chiave `(mtime, size, engineVersion, detectorVersion)` — si invalida automaticamente quando il transcript o il codice policy/rilevatore cambia. Ogni entry memorizza anche un timestamp `cachedAt` come **metadati TTL** (non parte della chiave cache); le entry più vecchie di **7 giorni** vengono rifiutate in lettura in modo che i risultati longevi non superino l'intenzione rilevatore in evoluzione. +- **Cache del risultato completo** in `~/.failproofai/audit-dashboard.json` (modalità 0600). Permette al dashboard di renderizzare istantaneamente durante la navigazione senza re-eseguire. Anche rifiutato in lettura dopo il **TTL di 7 giorni** — `/audit` poi ritorna allo stato vuoto e richiede un'esecuzione fresca. Fai clic su `[ re-audit now ]` vicino al fondo del report per aggiornare — re-audit invia `noCache: true`, quindi bypassa il cache per-transcript e re-scansiona ogni transcript invece di restituire il risultato in cache; l'esecuzione trasmette il progresso tramite una striscia appiccicatizia in alto e sostituisce il risultato in place al successo (nessun ricaricamento della pagina; un re-audit fallito mantiene il report precedente). ## Note -- **Nessuna mutazione.** L'audit riesegue in modalità sola lettura. `warn-repeated-tool-calls` viene saltato perché il suo sidecar per-sessione verrebbe altrimenti modificato. -- **Policy di workflow saltate.** Le policy `require-*-before-stop` si attivano solo su eventi `Stop` e `execSync` contro lo stato git in diretta — non hanno un'interpretazione significativa "cosa sarebbe successo nel 2025", quindi non compaiono nei conteggi audit. -- **Policy personalizzate saltate.** Gli hook personalizzati forniti dall'utente non vengono rieseguiti (potrebbero essere cambiati dalla sessione originale). \ No newline at end of file +- **Nessuna mutazione.** L'audit viene riprodotto in modalità sola lettura. `warn-repeated-tool-calls` viene saltato perché il suo sidecar per-sessione altrimenti verrebbe modificato. +- **Policy workflow saltate.** Le policy `require-*-before-stop` si attivano solo su eventi `Stop` e `execSync` contro lo stato git live — non hanno un'interpretazione significativa "cosa sarebbe successo nel 2025", quindi non appaiono nei conteggi audit. +- **Policy custom saltate.** Gli hook forniti dall'utente non vengono riprodotti (potrebbero essere cambiati dalla sessione originale). \ No newline at end of file diff --git a/docs/it/configuration.mdx b/docs/it/configuration.mdx index ad260ca3..44b83c4c 100644 --- a/docs/it/configuration.mdx +++ b/docs/it/configuration.mdx @@ -1,22 +1,22 @@ --- title: Configurazione -description: "Formato file di configurazione, sistema a tre livelli e regole di merge" +description: "Formato file di configurazione, sistema a tre ambiti e regole di merge" icon: gear --- -failproofai utilizza file di configurazione JSON per controllare quali policy sono attive, come si comportano e da dove vengono caricate le policy personalizzate. La configurazione è progettata per essere facile da condividere con il tuo team - commitatela nel tuo repo e ogni sviluppatore avrà la stessa rete di protezione dell'agent. +failproofai utilizza file di configurazione JSON per controllare quali policy sono attive, come si comportano e da dove vengono caricate le policy personalizzate. La configurazione è progettata per essere facile da condividere con il tuo team - eseguine il commit nel tuo repository e ogni sviluppatore otterrà la stessa rete di sicurezza dell'agente. --- ## Ambiti di configurazione -Ci sono tre ambiti di configurazione, valutati in ordine di priorità: +Esistono tre ambiti di configurazione, valutati in ordine di priorità: | Ambito | Percorso file | Scopo | -|--------|---------------|-------| -| **project** | `.failproofai/policies-config.json` | Impostazioni per-repo, committate nel version control | -| **local** | `.failproofai/policies-config.local.json` | Override personali per-repo, gitignorate | -| **global** | `~/.failproofai/policies-config.json` | Default a livello utente su tutti i progetti | +|-------|-----------|---------| +| **project** | `.failproofai/policies-config.json` | Impostazioni per-repository, sottoposte a controllo versione | +| **local** | `.failproofai/policies-config.local.json` | Override personali per-repository, gitignored | +| **global** | `~/.failproofai/policies-config.json` | Impostazioni predefinite a livello utente su tutti i progetti | Quando failproofai riceve un evento hook, carica e unisce tutti e tre i file che esistono per la directory di lavoro corrente. @@ -29,10 +29,10 @@ project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← unione deduplificata +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← unione deduplicated ``` -**`policyParams`** - il primo ambito che definisce parametri per una data policy vince interamente. Non c'è merging profondo di valori all'interno dei parametri di una policy. +**`policyParams`** - il primo ambito che definisce i parametri per una data policy vince completamente. Non c'è merge profondo dei valori all'interno dei parametri di una policy. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } @@ -42,11 +42,11 @@ resolved: { allowPatterns: ["sudo apt-get update"] } ← project vince, global ``` ```text -project: (nessuna voce block-sudo) -local: (nessuna voce block-sudo) +project: (nessuna entry block-sudo) +local: (nessuna entry block-sudo) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← fallback a global +resolved: { allowPatterns: ["sudo systemctl status"] } ← ricade a global ``` **`customPoliciesPath`** - il primo ambito che lo definisce vince. @@ -55,7 +55,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← fallback a global --- -## Formato file di configurazione +## Formato del file di configurazione ```json { @@ -96,39 +96,39 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← fallback a global --- -## Riferimento campi +## Riferimento dei campi ### `enabledPolicies` -Type: `string[]` +Tipo: `string[]` -Elenco dei nomi di policy da abilitare. I nomi devono corrispondere esattamente agli identificatori di policy mostrati da `failproofai policies`. Vedi [Built-in Policies](/it/built-in-policies) per l'elenco completo. +Elenco dei nomi delle policy da abilitare. I nomi devono corrispondere esattamente agli identificatori delle policy mostrati da `failproofai policies`. Vedi [Built-in Policies](/it/built-in-policies) per l'elenco completo. -Le policy non in `enabledPolicies` sono inattive, anche se hanno voci in `policyParams`. +Le policy non in `enabledPolicies` sono inattive, anche se hanno entry in `policyParams`. ### `policyParams` -Type: `Record>` +Tipo: `Record>` -Override di parametri per-policy. La chiave esterna è il nome della policy; le chiavi interne sono specifiche della policy. Ogni policy documenta i suoi parametri disponibili in [Built-in Policies](/it/built-in-policies). +Override dei parametri per-policy. La chiave esterna è il nome della policy; le chiavi interne sono specifiche della policy. Ogni policy documenta i suoi parametri disponibili in [Built-in Policies](/it/built-in-policies). -Se una policy ha parametri ma non li specifichi, vengono utilizzati i default built-in della policy. Gli utenti che non configurano `policyParams` affatto otterranno un comportamento identico alle versioni precedenti. +Se una policy ha parametri ma non li specifichi, vengono utilizzati i valori predefiniti incorporati della policy. Gli utenti che non configurano affatto `policyParams` ottengono un comportamento identico alle versioni precedenti. -Le chiavi sconosciute all'interno del blocco dei parametri di una policy sono silenziosamente ignorate al momento dello scatto dell'hook ma segnalate come avvisi quando esegui `failproofai policies`. +Le chiavi sconosciute all'interno del blocco parametri di una policy vengono silenziosamente ignorate al momento dell'esecuzione dell'hook ma segnalate come avvisi quando esegui `failproofai policies`. -#### `hint` (cross-cutting) +#### `hint` (trasversale) -Type: `string` (optional) +Tipo: `string` (facoltativo) -Un messaggio aggiunto alla ragione quando una policy restituisce `deny` o `instruct`. Usalo per fornire a Claude una guida praticabile senza modificare la policy stessa. +Un messaggio aggiunto alla ragione quando una policy restituisce `deny` o `instruct`. Utilizzalo per fornire a Claude una guida attuabile senza modificare la policy stessa. -Funziona con qualsiasi tipo di policy — built-in, custom (`custom/`), project convention (`.failproofai-project/`), o user convention (`.failproofai-user/`). +Funziona con qualsiasi tipo di policy — incorporata, personalizzata (`custom/`), convenzione del progetto (`.failproofai-project/`), o convenzione utente (`.failproofai-user/`). ```json { "policyParams": { "block-force-push": { - "hint": "Prova a creare invece un nuovo branch." + "hint": "Prova a creare un nuovo branch." }, "block-sudo": { "allowPatterns": ["sudo apt-get"], @@ -141,40 +141,40 @@ Funziona con qualsiasi tipo di policy — built-in, custom (`custom/`), project } ``` -Quando `block-force-push` nega, Claude vede: *"Il force-push è bloccato. Prova a creare invece un nuovo branch."* +Quando `block-force-push` nega, Claude vede: *"Force-pushing è bloccato. Prova a creare un nuovo branch."* -I valori non-string e le stringhe vuote sono silenziosamente ignorati. Se `hint` non è impostato, il comportamento è invariato (backward-compatible). +I valori non-stringa e le stringhe vuote vengono silenziosamente ignorate. Se `hint` non è impostato, il comportamento rimane invariato (retrocompatibile). ### `customPoliciesPath` -Type: `string` (absolute path) +Tipo: `string` (percorso assoluto) -Percorso di un file JavaScript contenente policy hook personalizzate. Questo è impostato automaticamente da `failproofai policies --install --custom ` (il percorso è risolto ad assoluto prima di essere memorizzato). +Percorso di un file JavaScript contenente policy hook personalizzate. Viene impostato automaticamente da `failproofai policies --install --custom ` (il percorso viene risolto in assoluto prima di essere archiviato). -Il file viene caricato fresco ad ogni evento hook - non c'è caching. Vedi [Custom Policies](/it/custom-policies) per i dettagli di authoring. +Il file viene caricato di nuovo su ogni evento hook - non c'è cache. Vedi [Custom Policies](/it/custom-policies) per i dettagli di authoring. ### Policy basate su convenzione -In aggiunta a `customPoliciesPath` esplicito, failproofai scopre automaticamente e carica file di policy dalle directory `.failproofai/policies/`: +In aggiunta al `customPoliciesPath` esplicito, failproofai rileva e carica automaticamente i file di policy dalle directory `.failproofai/policies/`: | Livello | Directory | Ambito | -|---------|-----------|--------| -| Project | `.failproofai/policies/` | Condiviso con il team tramite version control | -| User | `~/.failproofai/policies/` | Personale, si applica a tutti i progetti | +|-------|-----------|-------| +| Progetto | `.failproofai/policies/` | Condiviso con il team tramite controllo versione | +| Utente | `~/.failproofai/policies/` | Personale, si applica a tutti i progetti | -**Corrispondenza file:** Solo i file che corrispondono a `*policies.{js,mjs,ts}` vengono caricati (ad es. `security-policies.mjs`, `workflow-policies.js`). Gli altri file nella directory sono ignorati. +**Corrispondenza file:** Solo i file corrispondenti a `*policies.{js,mjs,ts}` vengono caricati (es. `security-policies.mjs`, `workflow-policies.js`). Gli altri file nella directory vengono ignorati. -**Nessuna configurazione necessaria:** Le policy di convenzione non richiedono voci in `policies-config.json`. Basta inserire i file nella directory e verranno raccolti al prossimo evento hook. +**Nessuna configurazione necessaria:** Le policy di convenzione non richiedono entry in `policies-config.json`. Basta inserire i file nella directory e verranno raccolti al prossimo evento hook. -**Caricamento unione:** Entrambe le directory di convenzione di project e user vengono scansionate. Tutti i file corrispondenti da entrambi i livelli vengono caricati (a differenza di `customPoliciesPath` che usa il primo-ambito-vince). +**Caricamento di unione:** Entrambe le directory di convenzione del progetto e dell'utente vengono scansionate. Tutti i file corrispondenti da entrambi i livelli vengono caricati (a differenza di `customPoliciesPath` che utilizza first-scope-wins). -Vedi [Custom Policies](/it/custom-policies) per più dettagli ed esempi. +Vedi [Custom Policies](/it/custom-policies) per ulteriori dettagli ed esempi. ### `llm` -Type: `object` (optional) +Tipo: `object` (facoltativo) -Configurazione del client LLM per le policy che effettuano chiamate AI. Non richiesta per la maggior parte delle configurazioni. +Configurazione del client LLM per le policy che effettuano chiamate AI. Non richiesto per la maggior parte delle configurazioni. ```json { @@ -187,22 +187,26 @@ Configurazione del client LLM per le policy che effettuano chiamate AI. Non rich --- -## Gestione della configurazione dalla CLI +## Gestione della configurazione da CLI -I comandi `policies --install` e `policies --uninstall` scrivono nel file di impostazioni hook della CLI del tuo agent (i punti di ingresso dell'hook), mentre `policies-config.json` è il file che gestisci direttamente. I due sono separati: +I comandi `policies --install` e `policies --uninstall` scrivono nel file di impostazioni dell'hook della CLI del tuo agente (i punti di ingresso dell'hook), mentre `policies-config.json` è il file che gestisci direttamente. I due sono separati: -- **Impostazioni agent CLI** — dice all'agent di chiamare `failproofai --hook ` ad ogni uso di strumento: - - **Claude Code**: `~/.claude/settings.json` (user), `/.claude/settings.json` (project), `/.claude/settings.local.json` (local) - - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex non ha un ambito `local` - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot non ha un ambito `local`. Le voci hook usano i campi di comando `bash`/`powershell` di Copilot con chiave OS e `timeoutSec`; il file porta un marcatore `version: 1` di alto livello. Il supporto di Copilot CLI è **beta** mentre verifichiamo lo schema del record `events.jsonl` (che la documentazione pubblica non specifica) rispetto a più sessioni del mondo reale. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor non ha un ambito `local`. Le voci hook usano la forma `{type, command, timeout}` a forma di Claude (senza split `bash`/`powershell`), ma memorizzate sotto chiavi di evento camelCase (`preToolUse`, `beforeSubmitPrompt`, …) in un array piatto per lo [schema degli hook](https://cursor.com/docs/hooks) di Cursor; il file porta un marcatore `version: 1` di alto livello. Il gestore canonicalizza camelCase → PascalCase tramite `CURSOR_EVENT_MAP` quindi le policy built-in esistenti si attivano invariate. Il supporto di Cursor Agent è **beta** mentre verifichiamo il formato del transcript di Cursor su disco (non specificato nella documentazione pubblica) rispetto a più installazioni del mondo reale. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode non ha un ambito `local`. A differenza degli altri sei CLI, OpenCode ha **nessun sistema di hook per comando esterno**: carica plugin JS/TS in-process esplicitamente registrati tramite l'array `plugin: []` in `opencode.json` (l'auto-discovery da `.opencode/plugins/` **non** è come i plugin vengono caricati su opencode v1.14.33). L'installazione rilascia un piccolo shim plugin generato che subprocess-chiama il binario failproofai e traduce la risposta JSON a forma di Claude del binario di nuovo in semantica plugin: `throw new Error()` per tool-event deny (cancella la chiamata dello strumento), `client.session.prompt(...)` per instruct E per deny di `Stop` / `SubagentStop` (invia la ragione di deny come prossimo messaggio utente — l'unico canale force-retry dal momento che `session.idle` è notification-only e gettare da essa è un no-op), e no-op per allow. Lo shim canonicalizza sia i nomi di strumento (lowercase → PascalCase tramite `OPENCODE_TOOL_MAP`) che le chiavi degli argomenti di input dello strumento (camelCase → snake_case tramite `OPENCODE_TOOL_INPUT_MAP` per `Read` / `Write` / `Edit`, ad es. `filePath` → `file_path`, `oldString` → `old_string`) prima di inoltrarsi al binario, così il controllo dei percorsi built-in come `block-read-outside-cwd`, `block-env-files`, e `block-secrets-write` si attivano invariate sulle chiamate agli strumenti di OpenCode. Le sessioni vivono nel DB SQLite di opencode presso `~/.local/share/opencode/opencode.db`; il visualizzatore di sessioni della dashboard li legge tramite `opencode db --format json` e `opencode export `. Il supporto di OpenCode è **beta** mentre verifichiamo il comportamento attraverso versioni e rispetto a più sessioni del mondo reale. Vedi la [documentazione dei plugin di OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi non ha un ambito `local`. Pi carica pacchetti di estensioni TypeScript all'avvio; il file di impostazioni è un array di stringhe piatto `{"packages": ["./relative/path", …]}`. failproofai scrive una singola voce dell'array dei pacchetti che punta alla sua directory `pi-extension/` in bundle. L'estensione internamente si sottoscrive agli eventi `tool_call` / `user_bash` / `input` / `session_start` di Pi e guscio fuori a `failproofai --hook --cli pi`; il gestore canonicalizza underscore_lower_snake_case → PascalCase tramite `PI_EVENT_MAP` quindi le policy built-in esistenti si attivano invariate. Gli argomenti di input dello strumento sono anche canonicalizzati tramite `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit forniscono `path` piuttosto che `file_path`; mappare la chiave di top-level lascia che `block-env-files` e `block-secrets-write` si attivino — `block-read-outside-cwd` già aveva un fallback `path`). Il supporto di Pi è **beta** mentre l'API di estensione di Pi e il layout del log di sessione si stabilizzano. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini non ha un ambito `local` (documenta un ambito `system` presso `/etc/gemini-cli/settings.json` che failproofai non espone). Le voci hook usano la forma `{type, command, timeout}` di Claude avvolta nello schema matcher `{matcher, hooks: [...]}` di Gemini con `matcher: "*"` di default. Gli eventi sono PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); il gestore mappa ai nomi canonici Claude tramite `GEMINI_EVENT_MAP`. I nomi di strumento sono snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — il gestore canonicalizza tramite `GEMINI_TOOL_MAP` quindi le policy built-in esistenti si attivano invariate. L'evaluator di policy emette la forma piatta di Gemini `{decision: "deny", reason}` (preferita per il contratto Golden Rule di Gemini exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` per l'iniezione di contesto su BeforeAgent / AfterTool / SessionStart, e `{decision: "block", reason}` su AfterAgent per la semantica force-retry. Il supporto di Gemini CLI è **beta** mentre allargheremo la copertura del mondo reale. Vedi la [documentazione degli hook di Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**ambito utente solo** — Hermes non ha configurazione project/local). Hermes è un gateway **Slack/Telegram**, quindi un'installazione intercetta le chiamate di strumento da ogni piattaforma (Slack/Telegram/cli/cron) **e** subagent interni. Le voci hook sono una coppia `{command, timeout}` (timeout in **secondi**) sotto una mappa `hooks:` codificata dagli eventi snake_case di Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); il gestore canonicalizza gli eventi tramite `HERMES_EVENT_MAP` e i nomi di strumento tramite `HERMES_TOOL_MAP` quindi le policy built-in si attivano invariate. La configurazione è modificata tramite una `Document` YAML di preservazione dei commenti round-trip in modo che le altre impostazioni dell'operatore sopravvivano, e l'installazione imposta `hooks_auto_accept: true` così il gateway headless (no TTY) esegue gli hook senza un prompt di consenso. L'evaluator emette il contratto stdout `{"decision":"block","reason"}` di Hermes (Hermes ignora i codici di uscita). **Limitazioni:** Hermes non ha un evento end-turn `Stop`, quindi le policy built-in `require-*-before-stop` non si attivano mai per esso (inapplicabile, non rotto); `instruct` degrada a allow-with-logged-note (nessun canale additional-context); e la redazione di secret di output (`sanitize-*`) non può riscrivere l'output dello strumento sul contratto dell'hook di shell. Hermes è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni di gateway direttamente da `~/.hermes/state.db`. -- **`policies-config.json`** — dice a failproofai quali policy valutare e con quali parametri (condiviso su tutti gli agent CLI) +- **Impostazioni CLI dell'agente** — indica all'agente di chiamare `failproofai --hook ` su ogni utilizzo di strumento: + - **Claude Code**: `~/.claude/settings.json` (utente), `/.claude/settings.json` (progetto), `/.claude/settings.local.json` (locale) + - **OpenAI Codex**: `~/.codex/hooks.json` (utente), `/.codex/hooks.json` (progetto) — Codex non ha un ambito `local` + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (utente), `/.github/hooks/failproofai.json` (progetto) — Copilot non ha un ambito `local`. Le entry dell'hook utilizzano i campi dei comandi `bash`/`powershell` keyed-OS di Copilot con `timeoutSec`; il file riporta un marcatore di versione di primo livello `version: 1`. Il supporto CLI di Copilot è **beta** mentre verifichiamo lo schema di record `events.jsonl` (che i documenti pubblici non specificano) rispetto a più sessioni nel mondo reale. **La modalità agente VS Code Copilot Chat (Preview)** legge le configurazioni hook da `.github/hooks/*.json`, `~/.copilot/hooks/*.json` e `~/.claude/settings.json` (governati dall'impostazione `chat.hookFilesLocations`) utilizzando lo stesso contratto a forma di Claude `{hookSpecificOutput:{permissionDecision:"deny",…}}` — i percorsi esatti che l'integrazione `copilot` e l'integrazione `claude` (`~/.claude/settings.json`) scrivono già, quindi `failproofai policies --install --cli copilot` (o `--cli claude`) **già si applica in modalità agente VS Code** senza necessità di un'integrazione separata `vscode` (confermato live dai log di discovery di VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (utente), `/.cursor/hooks.json` (progetto) — Cursor non ha un ambito `local`. Le entry dell'hook utilizzano la forma `{type, command, timeout}` a forma di Claude (nessuna divisione `bash`/`powershell`), ma archiviate sotto chiavi di evento camelCase (`preToolUse`, `beforeSubmitPrompt`, …) in un array piatto per lo schema hooks di Cursor; il file riporta un marcatore di versione di primo livello `version: 1`. Il gestore canonicalizza camelCase → PascalCase via `CURSOR_EVENT_MAP` quindi le policy incorporate esistenti si attivano invariate. Il supporto Cursor Agent è **beta** mentre verifichiamo il formato di trascrizione su disco di Cursor (non specificato nei documenti pubblici) rispetto a più installazioni nel mondo reale. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (utente), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (progetto) — OpenCode non ha un ambito `local`. A differenza degli altri cinque CLI, OpenCode non ha **nessun sistema di hook di comando esterno**: carica plugin JS/TS in-process esplicitamente registrati tramite l'array `plugin: []` in `opencode.json` (l'auto-discovery da `.opencode/plugins/` **non** è come i plugin si caricano su opencode v1.14.33). L'installazione rilascia un piccolo shim plugin generato che chiamate-subprocess il binario failproofai e traduce la risposta JSON a forma di Claude del binario nella semantica dei plugin: `throw new Error()` per il rifiuto dell'evento dello strumento (annulla la chiamata dello strumento), `client.session.prompt(...)` per l'istruzione E per il rifiuto `Stop` / `SubagentStop` (invia il motivo del rifiuto come il prossimo messaggio utente — l'unico canale di force-retry poiché `session.idle` è solo notifica e lanciare da esso è un no-op), e no-op per allow. Lo shim canonicalizza sia i nomi degli strumenti (minuscolo → PascalCase via `OPENCODE_TOOL_MAP`) che i tasti arg input dello strumento (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` per `Read` / `Write` / `Edit`, es. `filePath` → `file_path`, `oldString` → `old_string`) prima di inoltrare al binario, quindi i builtin di controllo del percorso come `block-read-outside-cwd`, `block-env-files` e `block-secrets-write` si attivano invariati sulle chiamate degli strumenti OpenCode. Le sessioni vivono nel database SQLite di opencode a `~/.local/share/opencode/opencode.db`; il visualizzatore di sessioni della dashboard le legge tramite `opencode db --format json` e `opencode export `. Il supporto OpenCode è **beta** mentre verifichiamo il comportamento tra le versioni e rispetto a più sessioni nel mondo reale. Vedi la [documentazione dei plugin OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (utente), `/.pi/settings.json` (progetto) — Pi non ha un ambito `local`. Pi carica pacchetti di estensioni TypeScript all'avvio; il file delle impostazioni è un array di stringhe piatto `{"packages": ["./relative/path", …]}`. failproofai scrive una singola entry dell'array packages che punta alla sua directory `pi-extension/` bundled. L'estensione internamente si iscrive agli eventi `tool_call` / `user_bash` / `input` / `session_start` di Pi e chiama `failproofai --hook --cli pi`; il gestore canonicalizza underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP` quindi le policy incorporate esistenti si attivano invariate. Gli argomenti di input dello strumento vengono anche canonicalizzati via `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit fornisce `path` piuttosto che `file_path`; mappare la chiave di primo livello consente a `block-env-files` e `block-secrets-write` di attivarsi — `block-read-outside-cwd` aveva già un fallback `path`). Il supporto Pi è **beta** mentre l'API di estensione e il layout del log di sessione di Pi si stabilizzano. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**solo ambito utente** — Hermes non ha configurazione di progetto/locale). Hermes è un **gateway** Slack/Telegram, quindi un'installazione intercetta chiamate di strumenti da ogni piattaforma (Slack/Telegram/cli/cron) **e** subagenti interni. Le entry dell'hook sono una coppia `{command, timeout}` (timeout in **secondi**) sotto una mappa `hooks:` con chiavi per gli eventi snake_case di Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); il gestore canonicalizza gli eventi via `HERMES_EVENT_MAP` e i nomi degli strumenti via `HERMES_TOOL_MAP` quindi le policy incorporate si attivano invariate. La configurazione viene modificata tramite un giro di YAML `Document` che preserva i commenti quindi le altre impostazioni dell'operatore sopravvivono, e l'installazione imposta `hooks_auto_accept: true` quindi il gateway headless (nessun TTY) esegue gli hook senza un prompt di consenso. L'evaluator emette il contratto stdout `{"decision":"block","reason"}` di Hermes (Hermes ignora i codici di uscita). **Limitazioni:** Hermes non ha un evento `Stop` di fine turno, quindi i builtin `require-*-before-stop` non si attivano mai per esso (inapplicabile, non rotto); `instruct` degrada a allow-with-logged-note (nessun canale di contesto aggiuntivo); e la redazione di segreti di output (`sanitize-*`) non può riscrivere l'output dello strumento su il contratto hook della shell. Hermes è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni gateway direttamente da `~/.hermes/state.db`. + - **OpenClaw (gateway openclaw)**: `~/.openclaw/openclaw.json` (**solo ambito utente** — OpenClaw non ha configurazione di progetto/locale). Come Hermes, OpenClaw è un **gateway** multi-canale self-hosted, quindi un'installazione intercetta chiamate di strumenti da ogni canale e dai suoi subagenti interni. L'enforcement viene eseguito attraverso i **hook plugin in-process** di OpenClaw (i suoi hook interni basati su file sono solo osservazione e non possono bloccare), quindi — come OpenCode/Pi — failproofai spedisce un pacchetto `openclaw-plugin/` statico che async-genera il binario failproofai e traduce il verdetto. L'installer registra la directory del plugin spedito in `openclaw.json`'s `plugins.load.paths[]` e lo abilita sotto `plugins.entries.failproofai` (con `hooks.allowConversationAccess: true`, richiesto per gli hook di conversazione grezza). L'evaluator emette un verdetto `{permission, reason}` piatto e lo shim lo mappa a ogni forma nativa dell'hook: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), e `before_agent_finalize → {action:"revise", reason}` (**Stop** — un vero gate di fine turno, quindi i builtin `require-*-before-stop` **si applicano** su OpenClaw, a differenza di Hermes). Gli eventi e i nomi degli strumenti canonicalizzano il lato binario via `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) quindi le policy incorporate si attivano invariate; lo shim fallisce aperto su qualsiasi errore di spawn/parse/timeout. OpenClaw è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni JSONL a `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (utente), `/.factory/hooks.json` (progetto) — Factory non ha un ambito `local`. droid spedisce un sistema di hook di comando esterno a stile Claude, ma con due stranezze verificate live rispetto a droid v0.171.0: (1) i nomi degli eventi vivono al **livello superiore** di `hooks.json` — non c'è **nessun wrapper `"hooks"`** (droid lo rifiuta); gli eventi dello strumento (`PreToolUse`/`PostToolUse`) portano `"matcher": "*"`, gli eventi non-strumento lo omettono. (2) Deny è guidato dal codice di uscita dell'hook **2 + stderr**, non da una decisione JSON — il ramo `factory` dell'evaluator restituisce l'uscita 2 per gli eventi dello strumento/prompt e `{decision:"block", reason}` solo sull'evento `Stop` di fine turno (l'unico canale di force-retry di droid). Gli eventi sono già PascalCase (nessuna mappa di eventi) e il payload è snake_case di Claude; solo i nomi degli strumenti vengono canonicalizzati via `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni JSONL su disco a `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (utente), `/.devin/config.json` (progetto) — Devin non ha un ambito `local`. Devin è un **puro clone Claude** verificato live rispetto a devin v3000.1.27: utilizza lo schema `"hooks"`-wrapper Claude standard (le scritture preservano il merge quindi le altre chiavi del file di configurazione — `org_id`, `theme_mode`, … — sopravvivono), nomi di eventi già-PascalCase (nessuna mappa di eventi, nessun ramo di gestore), e un payload stdin snake_case di Claude (nessuna normalizzazione). Il ramo `devin` dell'evaluator nega con JSON `{"decision":"block","reason"}` su stdout all'uscita 0 per **ogni** evento (verificato — il blocco ha sovrascritto `--permission-mode dangerous`); sull'evento `Stop` di fine turno il motivo porta la formulazione force-retry OBBLIGATORIA quindi i builtin `require-*-before-stop` si applicano. Solo i nomi degli strumenti vengono canonicalizzati via `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` è già canonico). Devin è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni SQLite a `~/.local/share/devin/cli/sessions.db` (ogni riga `sessions` porta una vera `working_directory`, quindi le sessioni si raggruppano per project cwd come Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (utente), `/.agents/hooks.json` (progetto) — Antigravity non ha un ambito `local`. A differenza di Factory/Devin, Antigravity ha il **suo** contratto (non un clone Claude), verificato live rispetto a agy v1.1.2. `hooks.json` utilizza uno schema **named-hook**: la chiave di primo livello è un nome di hook (*`"failproofai"`) il cui valore è una mappa evento→handler — gli eventi dello strumento (`PreToolUse`/`PostToolUse`) avvolgono i handler in `{matcher:"*", hooks:[…]}`, mentre `PreInvocation`/`Stop` sono array di handler **piatti** (gli altri hook nominati vengono preservati). Il payload stdin è **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai lo normalizza a snake_case prima che le policy vengono eseguite, e mappa gli argomenti PascalCase di `run_command` (`CommandLine`/`Cwd`) via `ANTIGRAVITY_TOOL_INPUT_MAP`. Il ramo `antigravity` dell'evaluator utilizza le sue **proprie** forme di risposta: `{decision:"deny", reason}` blocca uno strumento/prompt (uscita 0), `{decision:"continue", reason}` sull'evento `Stop` di fine turno entra nuovamente nel loop (quindi i builtin `require-*-before-stop` si applicano), e `{injectSteps:[{ephemeralMessage}]}` inietta un'istruzione su `PreInvocation` (→ `UserPromptSubmit`). I nomi degli strumenti canonicalizzano via `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity è **anche** una fonte di **audit** offline — la dashboard legge i suoi trascritti plain-JSONL a `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (indice di conversazione in `conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (utente), `/.agents/plugins/failproofai/hooks/hooks.json` (progetto) — Goose non ha un ambito `local`. L'enforcement utilizza il sistema **hooks** di Goose, la specifica **Open Plugins** cross-agent: l'installer rilascia solo la directory del plugin `failproofai` e Goose lo auto-scopre all'avvio (auto-registrandolo in `~/.config/goose/config.yaml`). Il `hooks.json` utilizza uno schema Open Plugins **con** un wrapper `"hooks"` di primo livello, e il matcher è **omesso** su ogni evento — un `"*"` nudo è un'espressione regolare non valida che non corrisponde a nulla (verificato live rispetto a goose v1.43.0). I nomi degli eventi sono già PascalCase (nessuna mappa di eventi); il payload stdin utilizza `event`/`working_dir`, che il gestore normalizza a `hook_event_name`/`cwd`. Il ramo `goose` dell'evaluator nega con JSON `{"decision":"block","reason"}` su stdout all'uscita 0, onorato solo sull'evento **`PreToolUse`** (spedito in goose ≥ v1.37.0) — che si attiva per lo strumento shell **e all'interno di subagenti delegati**, quindi è il singolo punto di rifiuto sufficiente; qualsiasi altro errore di hook fallisce **aperto**. Goose non ha **nessun evento `Stop`**, quindi i builtin `require-*-before-stop` non si applicano (come con Hermes). I nomi degli strumenti canonicalizzano via `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) e le chiavi dei percorsi via `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose è **anche** una fonte di **audit** offline — la dashboard legge le sue sessioni SQLite a `~/.local/share/goose/sessions/sessions.db` (ogni riga `sessions` porta una vera `working_dir`, quindi le sessioni si raggruppano per project cwd come Devin; le esecuzioni scratch `--no-session` vengono filtrate). +- **`policies-config.json`** — dice a failproofai quali policy valutare e con quali parametri (condiviso tra tutti i CLI dell'agente) -Passa `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` per indirizzare un agent specifico (space-separated o ripetuto per qualsiasi subset): +Passa `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` per indirizzare un agente specifico (separati da spazio o ripetuti per qualsiasi sottoinsieme): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Quando `--cli` è omesso, `failproofai` rileva quali agent CLI sono installati (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Quando `--cli` viene omesso, `failproofai` rileva quali CLI dell'agente sono installate (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): - **Un CLI rilevato** — auto-seleziona quel CLI senza chiedere. -- **Più CLI rilevati** in un terminale interattivo — mostra un prompt single-select con tasti freccia raggruppati in una sezione `Detected (N)` (con una riga aggregata `Install for all N detected` + ogni CLI rilevato singolarmente) e una sezione `Not installed (M) · install hooks ahead of time` che elenca ogni CLI non rilevato supportato come opzione forward-install (↑↓ per muoversi, Enter per selezionare, ^C per uscire). Il flusso di disinstallazione mostra solo la sezione Detected. -- **Più CLI rilevati** in un'esecuzione non-interattiva (CI, no TTY) — installa per tutti i CLI rilevati senza chiedere. -- **Nessuno rilevato** — fallback a `claude`, con un avviso che nessun binario di agent è stato trovato in PATH; il comando hook è ancora scritto quindi si attiva non appena ne installi uno. +- **Più CLI rilevati** in un terminale interattivo — mostra un prompt di singola selezione con freccia raggruppato in una sezione `Detected (N)` (con una riga aggregata `Install for all N detected` + ogni CLI rilevato individualmente) e una sezione `Not installed (M) · install hooks ahead of time` che elenca ogni CLI supportato non rilevato come un'opzione di installazione forward (↑↓ per muovere, Invio per selezionare, ^C per uscire). Il flusso di disinstallazione mostra solo la sezione Detected. +- **Più CLI rilevati** in un'esecuzione non interattiva (CI, nessun TTY) — installa per tutti i CLI rilevati senza chiedere. +- **Nessuno rilevato** — ricade a `claude`, con un avvertimento che nessun binario di agente è stato trovato in PATH; il comando hook è ancora scritto così si attiva non appena installi uno. -Puoi modificare `policies-config.json` direttamente in qualsiasi momento; le modifiche hanno effetto immediatamente al prossimo evento hook senza necessità di restart. +Puoi modificare `policies-config.json` direttamente in qualsiasi momento; i cambiamenti hanno effetto immediatamente al prossimo evento hook senza necessità di riavvio. --- -## Esempio: configurazione a livello di project con default del team +## Esempio: configurazione a livello di progetto con valori predefiniti del team -Committa `.failproofai/policies-config.json` nel tuo repo: +Esegui il commit di `.failproofai/policies-config.json` al tuo repository: ```json { diff --git a/docs/it/dashboard.mdx b/docs/it/dashboard.mdx index a4dcc440..b1ce8ec6 100644 --- a/docs/it/dashboard.mdx +++ b/docs/it/dashboard.mdx @@ -1,10 +1,10 @@ --- title: Dashboard -description: "Monitora le sessioni degli agenti, rivedi le chiamate agli strumenti e gestisci i criteri" +description: "Monitora le sessioni degli agenti, esamina le chiamate di strumenti e gestisci le politiche" icon: chart-line --- -Il dashboard failproofai è un'applicazione web locale per monitorare le sessioni dei tuoi agenti AI e gestire i criteri. Scopri cosa hanno fatto i tuoi agenti mentre eri via. +Il dashboard di failproofai è un'applicazione web locale per monitorare le sessioni dei tuoi agenti IA e gestire le politiche. Scopri cosa hanno fatto i tuoi agenti mentre eri via. --- @@ -16,7 +16,7 @@ failproofai Si apre su `http://localhost:8020`. -Il dashboard legge direttamente dal filesystem - le tue cartelle di progetti Claude Code e i file di configurazione failproofai. Nulla viene scritto su un servizio remoto. +Il dashboard legge direttamente dal filesystem - i tuoi progetti Claude Code e i file di configurazione di failproofai. Nulla viene scritto su un servizio remoto. --- @@ -24,12 +24,12 @@ Il dashboard legge direttamente dal filesystem - le tue cartelle di progetti Cla ### Progetti -Elenca tutti i progetti Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ e Hermes trovati sulla tua macchina. I progetti Claude vengono rilevati da `~/.claude/projects/` (o dal percorso impostato da `CLAUDE_PROJECTS_PATH`); i progetti Codex vengono rilevati scansionando ogni trascrizione in `~/.codex/sessions///
/*.jsonl` e raggruppando per il `cwd` registrato nel primo record di ogni sessione; i progetti Copilot CLI vengono rilevati scansionando ogni `~/.copilot/session-state//workspace.yaml` (configurabile tramite `COPILOT_HOME`) e raggruppando per il suo campo `cwd`; i progetti Cursor Agent vengono rilevati scansionando i metadati per sessione in `~/.cursor/agent-sessions//` (configurabile tramite `CURSOR_HOME`, con `conversations/` e `sessions/` testati come fallback) per uno scalare `cwd` in `meta.json` / `session.json` / `workspace.yaml`; i progetti OpenCode vengono rilevati interrogando il suo DB SQLite in `~/.local/share/opencode/opencode.db` tramite `opencode db --format json` (leggiamo le tabelle `session` e `project` e raggruppiamo per `project_id`); i progetti Pi vengono rilevati scansionando trascrizioni JSONL per sessione in `~/.pi/agent/sessions//_.jsonl` (configurabile tramite `PI_SESSIONS_DIR`) e estraendo il `cwd` dal primo record di ogni sessione; i progetti Gemini CLI vengono rilevati scansionando `~/.gemini/tmp//chats/session--.jsonl` (configurabile tramite `GEMINI_SESSIONS_DIR`) e recuperando il cwd canonico dal marcatore di testo `.project_root` adiacente; le sessioni del gateway Hermes vengono lette direttamente dal suo archivio SQLite in `~/.hermes/state.db` (configurabile tramite `HERMES_DB_PATH`) e raggruppate in progetti `hermes-` per `source` (Slack/Telegram/cli/cron — le sessioni del gateway non hanno cwd). Un progetto utilizzato da più CLI viene visualizzato come una singola riga con tutti i badge corrispondenti. Utilizza il dropdown **CLI** sopra la tabella per filtrare per uno specifico agente CLI; l'URL preserva la tua selezione come `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Elenca tutti i progetti Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity e Goose trovati sulla tua macchina. I progetti Claude vengono individuati da `~/.claude/projects/` (o dal percorso impostato da `CLAUDE_PROJECTS_PATH`); i progetti Codex vengono individuati scansionando ogni trascrizione in `~/.codex/sessions///
/*.jsonl` e raggruppando per il `cwd` registrato nel primo record di ogni sessione; i progetti Copilot CLI vengono individuati scansionando ogni `~/.copilot/session-state//workspace.yaml` (configurabile tramite `COPILOT_HOME`) e raggruppando per il suo campo `cwd`; i progetti Cursor Agent vengono individuati scansionando i metadati per sessione in `~/.cursor/agent-sessions//` (configurabile tramite `CURSOR_HOME`, con `conversations/` e `sessions/` sondati come fallback) per uno scalare `cwd` in `meta.json` / `session.json` / `workspace.yaml`; i progetti OpenCode vengono individuati interrogando il suo DB SQLite in `~/.local/share/opencode/opencode.db` tramite `opencode db --format json` (leggiamo le tabelle `session` e `project` e raggruppiamo per `project_id`); i progetti Pi vengono individuati scansionando le trascrizioni JSONL per sessione in `~/.pi/agent/sessions//_.jsonl` (configurabile tramite `PI_SESSIONS_DIR`) ed estraendo il `cwd` dal primo record di ogni sessione; le sessioni del gateway Hermes vengono lette direttamente dal suo store SQLite in `~/.hermes/state.db` (configurabile tramite `HERMES_DB_PATH`) e raggruppate in progetti `hermes-` per `source` (Slack/Telegram/cli/cron — le sessioni del gateway non hanno cwd); le sessioni del gateway OpenClaw vengono lette da `~/.openclaw/agents//sessions/*.jsonl` e raggruppate in progetti `openclaw-` (anche senza cwd); i progetti Factory Droid vengono individuati dalle trascrizioni JSONL in `~/.factory/sessions//*.jsonl` e raggruppati per cwd; i progetti Devin dal suo DB SQLite in `~/.local/share/devin/cli/sessions.db` (raggruppati per il `working_directory` di ogni sessione); i progetti Antigravity dalle trascrizioni JSONL in `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` e raggruppati per cwd; e i progetti Goose dal suo DB SQLite in `~/.local/share/goose/sessions/sessions.db` (raggruppati per il `working_dir` di ogni sessione). Un progetto che è stato utilizzato da più CLI viene visualizzato come una singola riga con tutti i badge corrispondenti. Usa il dropdown **CLI** sopra la tabella per filtrare per uno specifico CLI agente; l'URL conserva la tua selezione come `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Ogni progetto mostra: - Nome del progetto (derivato dal percorso della cartella) -- Un badge CLI — `Claude Code` (arancione), `OpenAI Codex` (viola), `GitHub Copilot` (blu), `Cursor Agent` (smeraldo), `OpenCode` (ambra), `Pi` (rosa), `Gemini CLI` (cielo), e/o `Hermes` (indaco) -- Data dell'attività di sessione più recente +- Un badge CLI — `Claude Code` (arancione), `OpenAI Codex` (viola), `GitHub Copilot` (blu), `Cursor Agent` (smeraldo), `OpenCode` (ambra), `Pi` (rosa), e/o `Hermes` (indaco) +- Data dell'attività della sessione più recente Fai clic su un progetto per vedere le sue sessioni. @@ -38,61 +38,61 @@ Fai clic su un progetto per vedere le sue sessioni. Elenca tutte le sessioni all'interno di un progetto. Ogni sessione mostra: - ID della sessione - Timestamp di inizio e fine -- Numero di chiamate agli strumenti -- Conteggio dell'attività hook (criteri che si sono attivati) +- Numero di chiamate di strumenti +- Conteggio dell'attività degli hook (politiche che si sono attivate) -Utilizza il filtro dell'intervallo di date e la ricerca dell'ID della sessione per restringere l'elenco. Le sessioni sono impaginate. +Usa il filtro intervallo di date e la ricerca per ID sessione per restringere l'elenco. Le sessioni sono impaginate. Fai clic su una sessione per aprire il visualizzatore di sessione. ### Visualizzatore di sessione -Il visualizzatore di sessione risponde alla domanda chiave per gli agenti autonomi: cosa ha fatto l'agente e ha mantenuto il percorso corretto? Un badge CLI accanto all'intestazione indica se la sessione è una trascrizione di Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI o Hermes. Mostra una cronologia di tutto ciò che è accaduto in una sessione: +Il visualizzatore di sessione risponde alla domanda chiave per gli agenti autonomi: cosa ha fatto l'agente e è rimasto in traccia? Un badge CLI accanto all'intestazione indica se la sessione è una trascrizione Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity o Goose. Mostra una cronologia di tutto ciò che è accaduto in una sessione: -- **Messaggi** - Risposte di testo di Claude e prompt dell'utente -- **Chiamate agli strumenti** - Ogni strumento invocato da Claude, con il suo input e output -- **Attività dei criteri** - Per ogni chiamata allo strumento, quali criteri si sono attivati e quale decisione hanno restituito +- **Messaggi** - risposte di testo di Claude e prompt dell'utente +- **Chiamate di strumenti** - Ogni strumento che Claude ha invocato, con il suo input e output +- **Attività delle politiche** - Per ogni chiamata di strumento, quali politiche si sono attivate e quale decisione hanno restituito -La barra delle statistiche in alto mostra la durata della sessione, il totale delle chiamate agli strumenti e un riepilogo delle decisioni hook (conteggi allow / deny / instruct). +La barra delle statistiche in alto mostra la durata della sessione, il totale delle chiamate di strumenti e un riepilogo delle decisioni degli hook (conteggi allow / deny / instruct). -Fai clic sul pulsante **Download Logs** per esportare la sessione. Per le sessioni Claude Code, Codex, Copilot, Cursor, Pi e Gemini ricevi la trascrizione JSONL originale su disco byte-per-byte; per OpenCode (le cui sessioni si trovano in SQLite, non su disco) ricevi un documento JSON che rispecchia le tabelle `session` / `messages` / `parts` sottostanti. +Fai clic sul pulsante **Download Logs** per esportare la sessione. Per le sessioni Claude Code, Codex, Copilot, Cursor e Pi ottieni la trascrizione JSONL originale su disco byte per byte; per OpenCode (le cui sessioni si trovano in SQLite, non su disco) ottieni un documento JSON che rispecchia le tabelle `session` / `messages` / `parts` sottostanti. ### Audit -Un rapporto guidato dalla personalità su come il tuo agente si è effettivamente comportato nelle sessioni passate. Esegue la stessa scansione del CLI `failproofai audit` ma lo visualizza come un poster condivisibile a schermo singolo + quattro sezioni sotto la piega: +Un rapporto guidato dalla personalità su come il tuo agente si è effettivamente comportato nelle sessioni precedenti. Esegue la stessa scansione del CLI `failproofai audit` ma la rende come un poster condivisibile a schermo singolo + quattro sezioni sottostanti: -1. **Poster** — riempie il primo viewport. Regione di cattura PNG autonoma con il wordmark failproof_ai + etichetta di audit · indice archetipi (`№ NN of 08`) + data di audit · punteggio numerico (0–100) + pillola di classificazione percentile (`top 15%`) · nome dell'archetipo (uno tra `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + striscia di 3 parole chiave · riga di rarità `// only N% of agents are this archetype` · sigillo a piastrella 8×8 pixel · piè di pagina `audit yours → failproof.ai`. Tre pulsanti di condivisione si trovano appena fuori dalla casella di cattura: `post your archetype` (intento X), `share on linkedin`, `download poster`. La cattura viene eseguita tramite `html-to-image` in modo che il PNG corrisponda al rendering su schermo pixel per pixel (bordi tratteggiati, maschera logo SVG, gradienti, metriche dei caratteri — tutto preservato). -2. **Strengths** — elenco di righe calm ✓ dei comportamenti che il tuo agente fa già bene, derivati dai dati di audit dal vivo (tasso di chiamate agli strumenti pulito, nessun push diretto a main, zero fughe di credenziali, zero tempeste di retry) — ognuno visualizzato solo quando il criterio rilevante ha un record pulito nell'intervallo di audit. +1. **Poster** — riempie il primo viewport. Regione di cattura PNG indipendente con il wordmark failproof_ai + etichetta audit · indice archetipo (`№ NN di 08`) + data audit · punteggio numerico (0–100) + pillola di rango percentile (`top 15%`) · il nome dell'archetipo (uno di `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + striscia di 3 parole chiave · riga di rarità `// only N% of agents are this archetype` · tessera di sigillo 8×8 pixel · footer `audit yours → failproof.ai`. Tre pulsanti di condivisione si trovano appena fuori dalla casella di cattura: `post your archetype` (intenzione X), `share on linkedin`, `download poster`. La cattura viene eseguita tramite `html-to-image` quindi il PNG corrisponde al rendering sullo schermo pixel per pixel (bordi tratteggiati, maschera logo SVG, sfumature, metriche dei caratteri — tutto conservato). +2. **Strengths** — elenco di righe calme ✓ dei comportamenti che il tuo agente già fa bene, derivati dai dati audit dal vivo (velocità di chiamata di strumenti pulita, nessun push diretto su main, zero perdite di credenziali, zero tempeste di tentativi) — ciascuno visualizzato solo quando la politica pertinente ha un record pulito attraverso la finestra di audit. 3. **Quirks** — tabella di ciò che è sfuggito, classificato per gravità: `when · what slipped + the policy that would've caught it · severity pill · seen`, dove la ricorrenza legge `new` (una volta), `N× seen` (2–9 volte), o `recurring` (10+). -4. **How to improve** — elenco di righe calm, uno per criterio prescritto: nome del criterio in bianco, descrizione di una riga, comando di installazione + pulsante di copia sul lato destro. L'intestazione della sezione legge `enable all N → projected · ` (il punteggio che raggiungeresti con tutte le correzioni applicate), e il suo pulsante `[install all]` copia il comando combinato `failproofai policy add a b c …` per ogni criterio prescritto. -5. **Come back better** — due schede affiancate. Sinistra: imposta un promemoria (scelta di cadenza `3d` / `7d` / `14d` / `30d`; persiste tramite `/api/auth/reminder` una volta autenticato). Destra: sblocca i vantaggi failproof — `invite a friend` apre un modale che accetta un elenco di email di amici separati da virgola/spazio/newline (massimo 10 per invio), li invia tramite POST a `/api/audit/invite`, che viene inoltrato al server API `POST /v0/invite`. Il server API invia un'email per destinatario da `invite@failproof.ai` con il mittente in Cc e `Reply-To` impostato, in modo che il destinatario veda chi lo ha invitato e il mittente riceva una copia nella sua inbox. Gli utenti anonimi vengono indirizzati attraverso `AuthDialog` per primo in modo che l'email del mittente sia nota prima che gli inviti vengano inviati. L'adempimento dei diritti / vantaggi è un follow-up. +4. **How to improve** — elenco di righe calme, uno per ogni politica prescritta: nome della politica in bianco, descrizione in una riga, comando di installazione + pulsante di copia sul lato destro. L'intestazione della sezione legge `enable all N → projected · ` (il punteggio che raggiungeresti con tutte le correzioni applicate), e il suo pulsante `[install all]` copia il comando combinato `failproofai policy add a b c …` per ogni politica prescritta. +5. **Come back better** — due schede affiancate. Sinistra: imposta un promemoria (selettore cadenza `3d` / `7d` / `14d` / `30d`; persiste tramite `/api/auth/reminder` una volta autenticato). Destra: sblocca i vantaggi di failproof — `invite a friend` apre un modale che accetta un elenco di email di amici separati da virgola/spazio/nuova riga (max 10 per invio), li invia tramite POST a `/api/audit/invite`, che va al `POST /v0/invite` del server API. Il server API invia un'email per destinatario da `invite@failproof.ai` con il mittente in Cc e `Reply-To` impostato, quindi il destinatario vede chi lo ha invitato e il mittente riceve una copia nella propria inbox. Gli utenti anonimi vengono instradati tramite `AuthDialog` per primo in modo che l'email del mittente sia nota prima che gli inviti vengano inviati. L'adempimento dei diritti / vantaggi è un follow-up. -Guidato dal runtime `failproofai audit` — vedi [Audit CLI](/it/cli/audit) per il motore di scansione sottostante, i flag supportati e gli invarianti della cache per trascrizione. Il dashboard memorizza nella cache il risultato più recente in `~/.failproofai/audit-dashboard.json` (modalità `0600`, slot singolo, le nuove esecuzioni sovrascrivono) in modo che le revisioni siano istantanee; **sia le cache per trascrizione che di risultato completo vengono rifiutate alla lettura una volta che hanno più di 7 giorni** in modo che il dashboard non serva mai silenziosamente un risultato di una settimana fa — dopo il TTL `/audit` cade nello stato vuoto e chiede un'esecuzione nuova. Fare clic su `[ re-audit now ]` vicino al fondo del rapporto invia un POST a `/api/audit/run` con `noCache: true` — il re-audit ignora la cache per trascrizione e ripete la scansione di ogni trascrizione da zero piuttosto che restituire silenziosamente il risultato memorizzato nella cache — e il dashboard esegue il polling su `/api/audit/status` a 1Hz fino al termine dell'esecuzione; una striscia di progresso rosa appiccicatizia si fissa in cima al viewport durante l'esecuzione con un timer trascorso, e il risultato nuovo si scambia in posizione al successo (nessun ricaricamento della pagina completa; un re-audit non riuscito lascia il rapporto precedente intatto). In caso di errore la striscia diventa rossa con copia basata su `RerunError.kind` (`timeout` / `network` / `post_failed`). Lo stato vuoto (nessuna cache o scaduta) e lo stato zero-sessioni (cache esiste ma la scansione non ha trovato trascrizioni) sono visualizzati separatamente. +Guidato dal runtime `failproofai audit` — vedi [Audit CLI](/it/cli/audit) per il motore di scansione sottostante, i flag supportati e gli invarianti della cache per trascrizione. Il dashboard memorizza nella cache il risultato più recente in `~/.failproofai/audit-dashboard.json` (modalità `0600`, slot singolo, i nuovi run sovrascrivono) quindi le revisioni sono istantanee; **sia le cache per trascrizione che il risultato intero vengono rifiutate alla lettura una volta che hanno più di 7 giorni** quindi il dashboard non serve mai silenziosamente un risultato di una settimana fa — dopo il TTL `/audit` cade nello stato vuoto e richiede una nuova esecuzione. Facendo clic su `[ re-audit now ]` vicino al fondo del rapporto viene eseguito il POST `/api/audit/run` con `noCache: true` — il re-audit bypassa la cache per trascrizione e riscansiona ogni trascrizione da zero invece di restituire silenziosamente il risultato memorizzato nella cache — e il dashboard esegue il polling `/api/audit/status` a 1Hz fino al termine dell'esecuzione; una striscia di progresso rosa appiccicosa si attacca alla parte superiore del viewport durante l'esecuzione con un timer trascorso, e il risultato aggiornato viene scambiato al suo posto in caso di successo (nessun ricaricamento della pagina completa; un re-audit non riuscito lascia intatto il rapporto precedente). In caso di errore la striscia diventa rossa con copia codificata da `RerunError.kind` (`timeout` / `network` / `post_failed`). Lo stato vuoto (nessuna cache o scaduta) e lo stato zero-sessioni (cache esiste ma la scansione non ha trovato trascrizioni) vengono visualizzati separatamente. -### Criteri +### Politiche -Una pagina con due schede per gestire i criteri e rivedere l'attività. +Una pagina a due schede per gestire le politiche e rivedere l'attività. - - - Seleziona quale agenti CLI failproofai protegge da un singolo pannello — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI e Hermes hanno tutti una riga con stato di installazione (`Active` / `Detected` / `Inactive`), il percorso delle impostazioni dell'ambito utente e un accento di colore del marchio. Seleziona o deseleziona i CLI che desideri e fai clic su `Apply changes` per installare/disinstallare il diff in un unico passaggio. I CLI il cui binario viene rilevato su PATH sono pre-selezionati. - - Attiva o disattiva i singoli criteri con un singolo clic (scrive su `~/.failproofai/policies-config.json` — condiviso tra ogni CLI installata) - - Espandi un criterio per configurare i suoi parametri (per i criteri che supportano `policyParams`) - - Imposta un percorso file criteri personalizzato + + - Multi-seleziona quali CLI agenti failproofai protegge da un singolo pannello — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi e Hermes hanno tutti una riga con stato di installazione (`Active` / `Detected` / `Inactive`), il percorso delle impostazioni con ambito utente e un accento di marca. Seleziona o deseleziona i CLI che desideri e fai clic su `Apply changes` per installare/disinstallare la differenza in un passaggio. I CLI il cui binario è rilevato su PATH sono pre-selezionati. + - Attiva o disattiva le singole politiche con un solo clic (scrive in `~/.failproofai/policies-config.json` — condiviso in ogni CLI installato) + - Espandi una politica per configurarne i parametri (per le politiche che supportano `policyParams`) + - Imposta un percorso file di politiche personalizzato - Cronologia completa impaginata di ogni evento hook che si è attivato in tutte le sessioni - - Filtra per decisione, tipo di evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nome del criterio o ID della sessione - - Ogni riga mostra: timestamp, nome del criterio, decisione, badge CLI (arancione = Claude Code, viola = OpenAI Codex, blu = GitHub Copilot, smeraldo = Cursor Agent, ambra = OpenCode, rosa = Pi, cielo = Gemini CLI, indaco = Hermes), nome dello strumento, ID della sessione e il motivo delle decisioni deny/instruct - - Fai clic su un ID della sessione per aprire la sua trascrizione — il visualizzatore rileva automaticamente quale CLI ha attivato l'hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) e visualizza il badge CLI corrispondente nell'intestazione + - Filtra per decisione, tipo di evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), nome della politica o ID della sessione + - Ogni riga mostra: timestamp, nome della politica, decisione, badge CLI (arancione = Claude Code, viola = OpenAI Codex, blu = GitHub Copilot, smeraldo = Cursor Agent, ambra = OpenCode, rosa = Pi, indaco = Hermes, turchese = OpenClaw, rosa scuro = Factory Droid, violetto = Devin, ciano = Antigravity, lime = Goose), nome dello strumento, ID della sessione e il motivo delle decisioni deny/instruct + - Fai clic su un ID sessione per aprire la sua trascrizione — il visualizzatore rileva automaticamente quale CLI ha attivato l'hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) e visualizza il badge CLI corrispondente nell'intestazione --- -## Auto-refresh +## Aggiornamento automatico -Il dashboard ha un toggle di auto-refresh nella navigazione in alto. Se abilitato, la pagina corrente si aggiorna periodicamente per mostrare nuove sessioni e attività dei criteri man mano che compaiono. Essenziale per monitorare le sessioni degli agenti autonomi di lunga durata. +Il dashboard ha un interruttore di aggiornamento automatico nella navigazione in alto. Se abilitato, la pagina corrente si aggiorna periodicamente per mostrare nuove sessioni e attività delle politiche man mano che compaiono. Essenziale per monitorare le sessioni degli agenti autonomi a lunga esecuzione. --- @@ -110,7 +110,7 @@ Valori validi: `policies`, `projects`, `audit`. ## Configurazione del percorso dei progetti -Per impostazione predefinita, il dashboard legge dalla directory dei progetti standard di Claude Code. Sostituiscilo per configurazioni personalizzate: +Per impostazione predefinita, il dashboard legge dalla directory dei progetti Claude Code standard. Sostituiscila per configurazioni personalizzate: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -120,13 +120,13 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ## Accesso da un host non-localhost -Quando esegui il dashboard in **modalità di sviluppo** (`npm run dev`) e lo accedi da un hostname diverso da `localhost` - ad esempio, un dominio personalizzato, un IP remoto o un URL tunnelato - potresti vedere un avviso come: +Quando esegui il dashboard in **modalità dev** (`npm run dev`) e vi accedi da un nome host diverso da `localhost` - ad esempio, un dominio personalizzato, un IP remoto o un URL con tunnel - potresti visualizzare un avviso come: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Questo è Next.js che blocca l'accesso cross-origin al suo websocket HMR (hot module reload), che è una funzionalità solo per lo sviluppo. Per consentire il tuo host, utilizza il flag `--allowed-origins`: +Questo è Next.js che blocca l'accesso cross-origin al suo websocket HMR (hot module reload), che è una funzione solo per dev. Per consentire il tuo host, usa il flag `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com @@ -138,12 +138,12 @@ Per più host o IP, passa un elenco separato da virgole: npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -Puoi anche impostare la variabile di ambiente `FAILPROOFAI_ALLOWED_DEV_ORIGINS`: +Puoi anche impostare la variabile di ambiente `FAILPROOFAI_ALLOWED_DEV_ORIGINS` invece: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Questo si applica solo alla modalità di sviluppo. Quando esegui `failproofai` (modalità di produzione), non c'è websocket HMR e nessun problema di risorsa di sviluppo cross-origin. +Questo si applica solo alla modalità dev. Quando esegui `failproofai` (modalità produzione), non esiste un websocket HMR e nessun problema di risorse dev cross-origin. \ No newline at end of file diff --git a/docs/it/getting-started.mdx b/docs/it/getting-started.mdx index fb583f43..4deb77db 100644 --- a/docs/it/getting-started.mdx +++ b/docs/it/getting-started.mdx @@ -1,6 +1,5 @@ --- ---- -title: Guida introduttiva +title: Iniziare description: "Installa failproofai, abilita le policy e lascia che i tuoi agent funzionino in modo affidabile" icon: rocket --- @@ -8,7 +7,7 @@ icon: rocket ## Requisiti - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (opzionale - necessario solo per compilare dal codice sorgente) +- **Bun** >= 1.3.0 (opzionale - necessario solo per compilare da sorgente) --- @@ -32,15 +31,15 @@ bun add -g failproofai - Le policy sono regole che vengono eseguite prima e dopo ogni chiamata di strumento dell'agent. Catturano comandi distruttivi, fughe di segreti e altri modi di fallimento prima che causino danni. + Le policy sono regole che vengono eseguite prima e dopo ogni chiamata a tool dell'agent. Intercettano i comandi distruttivi, le fughe di segreti e altri scenari di fallimento prima che causino danni. ```bash failproofai policies --install ``` - Questo scrive voci di hook nei tuoi agent CLI installati (il file `~/.claude/settings.json` di Claude Code, il file `~/.codex/hooks.json` di OpenAI Codex, il file `~/.copilot/hooks/failproofai.json` di GitHub Copilot CLI, il file `~/.cursor/hooks.json` di Cursor Agent, lo shim del plugin generato di OpenCode in `~/.config/opencode/plugins/failproofai.mjs` più una voce di registrazione nell'array `plugin` di `~/.config/opencode/opencode.json`, il file `~/.pi/agent/settings.json` di Pi, il file `~/.gemini/settings.json` di Gemini CLI, o il file `~/.hermes/config.yaml` di Hermes). Quando è presente più di uno, ti verrà chiesto; passa `--cli claude codex copilot cursor opencode pi gemini hermes` (qualsiasi sottoinsieme) per saltare la richiesta. + Questo scrive le voci hook nelle CLI agent installate (Claude Code in `~/.claude/settings.json`, OpenAI Codex in `~/.codex/hooks.json`, GitHub Copilot CLI in `~/.copilot/hooks/failproofai.json`, Cursor Agent in `~/.cursor/hooks.json`, OpenCode nello shimfile plugin generato in `~/.config/opencode/plugins/failproofai.mjs` più una voce di registrazione nell'array `plugin` di `~/.config/opencode/opencode.json`, Pi in `~/.pi/agent/settings.json`, Hermes in `~/.hermes/config.yaml`, OpenClaw in `~/.openclaw/openclaw.json`, Factory Droid in `~/.factory/hooks.json`, Devin CLI in `~/.config/devin/config.json`, Antigravity CLI in `~/.gemini/config/hooks.json`, o Goose nella directory plugin auto-scoperta in `~/.agents/plugins/failproofai/hooks/hooks.json`). Quando è presente più di uno ti verrà chiesto; passa `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (qualsiasi sottoinsieme) per saltare il prompt. - Il supporto per GitHub Copilot CLI, Cursor Agent, OpenCode, Pi e Gemini CLI è in **beta** — installa con `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` o `--cli gemini`. Hermes (hermes-agent, un gateway Slack/Telegram) si installa con ambito utente con `--cli hermes` ed è **anche** una fonte di audit offline. + Il supporto per GitHub Copilot CLI, Cursor Agent, OpenCode e Pi è in **beta** — installa con `--cli copilot`, `--cli cursor`, `--cli opencode`, o `--cli pi`. Hermes (hermes-agent, un gateway Slack/Telegram) si installa con scope utente con `--cli hermes` ed è **anche** una fonte di audit offline. OpenClaw (gateway openclaw, un assistente multi-canale auto-hosted) si installa con scope utente con `--cli openclaw` — l'enforcement viene eseguito tramite i suoi hook plugin in-process (`before_agent_finalize` è un vero gate di fine turno, quindi i builtin `require-*-before-stop` fanno enforcement) — ed è **anche** una fonte di audit offline. Factory Droid (`droid`) si installa con `--cli factory` (scope utente + progetto) ed è **anche** una fonte di audit offline. Devin CLI (`devin`, Cognition) si installa con `--cli devin` (scope utente + progetto) ed è **anche** una fonte di audit offline. Antigravity CLI (`agy`) si installa con `--cli antigravity` (scope utente + progetto) ed è **anche** una fonte di audit offline. Goose (codename goose, Block) si installa con `--cli goose` (scope utente + progetto) — l'installer rilascia semplicemente una directory plugin in `~/.agents/plugins/failproofai/` che Goose auto-scopre, ed è **anche** una fonte di audit offline. ```bash failproofai policies --install --scope project @@ -49,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -59,17 +62,17 @@ bun add -g failproofai failproofai policies ``` - Mostra ogni policy, se è abilitata e eventuali parametri configurati. + Mostra ogni policy, se è abilitata e tutti i parametri configurati. - + ```bash failproofai ``` - Apre una dashboard locale su `http://localhost:8020` dove puoi sfogliare le sessioni, ispezionare le chiamate di strumento e gestire le policy. + Apre un dashboard locale in `http://localhost:8020` dove puoi consultare le sessioni, ispezionare le chiamate a tool e gestire le policy. - Avvia Claude Code come al solito. Se l'agent prova a fare qualcosa di rischioso, failproofai lo intercetta automaticamente. Lascialo in esecuzione incustodito e rivedi quello che è successo nella dashboard. + Avvia Claude Code come al solito. Se l'agent tenta qualcosa di rischioso, failproofai l'intercetta automaticamente. Lascialo in esecuzione incustodito e rivedi ciò che è accaduto nel dashboard. @@ -77,12 +80,12 @@ bun add -g failproofai ## Come funzionano le policy -Ogni volta che un agent esegue uno strumento, Claude Code chiama failproofai come sottoprocesso: +Ogni volta che un agent esegue un tool, Claude Code chiama failproofai come subprocess: ```text Claude Code → failproofai --hook PreToolUse → legge JSON da stdin - valuta le policy - scrive la decisione su stdout + valuta le policy + scrive la decisione su stdout ``` Ogni policy restituisce una di tre decisioni: @@ -97,9 +100,9 @@ Le policy vengono eseguite nel tuo processo locale. Nulla viene inviato a un ser --- -## Configura policy di team con policy basate su convenzione +## Configura le policy del team con policy basate su convenzione -Il modo più veloce per stabilire standard di qualità in tutto il team è la convenzione `.failproofai/policies/`. Inserisci file di policy in questa directory e vengono caricati automaticamente — nessun flag, nessun cambio di configurazione, nessun comando di installazione. +Il modo più veloce per stabilire standard di qualità in tutto il team è la convenzione `.failproofai/policies/`. Inserisci i file policy in questa directory e verranno caricati automaticamente — nessun flag, nessun cambiamento di config, nessun comando di installazione. @@ -107,14 +110,14 @@ Il modo più veloce per stabilire standard di qualità in tutto il team è la co mkdir -p .failproofai/policies ``` - + Copia gli esempi iniziali o scrivi i tuoi: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - O creane uno nuovo: + Oppure creane uno nuovo: ```js // .failproofai/policies/team-policies.mjs @@ -126,17 +129,17 @@ Il modo più veloce per stabilire standard di qualità in tutto il team è la co fn: async (ctx) => { if (ctx.toolName !== "Bash") return allow(); if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) { - return instruct("Esegui i test prima di fare il commit."); + return instruct("Esegui i test prima di fare commit."); } return allow(); }, }); ``` - + ```bash git add .failproofai/policies/ - git commit -m "Aggiungi policy di qualità del team" + git commit -m "Add team quality policies" ``` Ogni membro del team che ha failproofai installato raccoglie automaticamente queste policy. Nessuna configurazione per sviluppatore necessaria. @@ -144,7 +147,7 @@ Il modo più veloce per stabilire standard di qualità in tutto il team è la co -Fai il commit di `.failproofai/policies/` nel tuo repository in modo che tutto il team condivida gli stessi standard. Man mano che il tuo team scopre nuovi modi di fallimento, aggiungi policy e fai il push — ognuno riceve l'aggiornamento al prossimo `git pull`. Nel tempo queste policy diventano uno standard di qualità vivente che continua a migliorare. +Effettua il commit di `.failproofai/policies/` nel tuo repo in modo che tutto il team condivida gli stessi standard. Man mano che il tuo team scopre nuovi scenari di fallimento, aggiungi policy e fai il push — tutti ricevono l'aggiornamento al prossimo `git pull`. Nel tempo queste policy diventano uno standard di qualità vivente che continua a migliorare. --- @@ -153,13 +156,13 @@ Fai il commit di `.failproofai/policies/` nel tuo repository in modo che tutto i Tutta la configurazione e i log rimangono sulla tua macchina: -| Percorso | Cosa archivia | +| Percorso | Cosa memorizza | |------|----------------| -| `~/.failproofai/policies-config.json` | Configurazione globale delle policy | +| `~/.failproofai/policies-config.json` | Config global della policy | | `~/.failproofai/hook-activity.jsonl` | Cronologia dell'esecuzione degli hook | -| `~/.failproofai/hook.log` | Log di debug per errori degli hook personalizzati | -| `.failproofai/policies-config.json` | Configurazione per progetto (committed) | -| `.failproofai/policies-config.local.json` | Personalizzazioni personali (gitignored) | +| `~/.failproofai/hook.log` | Log di debug per errori custom degli hook | +| `.failproofai/policies-config.json` | Config per-progetto (committata) | +| `.failproofai/policies-config.local.json` | Override personali (gitignored) | --- @@ -169,19 +172,19 @@ Tutta la configurazione e i log rimangono sulla tua macchina: failproofai policies --uninstall ``` -Rimuove le voci degli hook da `~/.claude/settings.json`. I file di configurazione in `~/.failproofai/` vengono conservati. +Rimuove le voci hook da `~/.claude/settings.json`. I file di config in `~/.failproofai/` vengono mantenuti. --- -## Passaggi successivi +## Prossimi passi - Ambiti e formato del file di configurazione + Scopes e formato dei file di config - + Tutte le 26 policy con parametri diff --git a/docs/it/introduction.mdx b/docs/it/introduction.mdx index 0a1d097f..1208aeed 100644 --- a/docs/it/introduction.mdx +++ b/docs/it/introduction.mdx @@ -1,41 +1,41 @@ --- title: "Failproof AI" -description: "FailproofAI fornisce agli agenti AI 39 politiche di fallimento integrate che rilevano loop, perdite di segreti, chiamate di strumenti distruttive e altro ancora in una singola installazione." +description: "FailproofAI fornisce agli agenti AI 39 politiche di fallimento integrate che rilevano loop, perdite di segreti, chiamate di tool distruttive e altro ancora in una singola installazione." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hook e politiche per **gestione dei fallimenti dell'AI**, **recupero degli errori** e **affidabilità dell'LLM**. Mantieni i tuoi agenti AI affidabili e in esecuzione autonoma su **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** e **Agents SDK**. +Hook e politiche per **la gestione dei fallimenti dell'IA**, il **ripristino dagli errori** e l'**affidabilità degli LLM**. Mantieni i tuoi agenti IA affidabili e in esecuzione autonoma su **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** e **Agents SDK**. -Gli agenti AI falliscono in modi prevedibili. Eseguono comandi distruttivi, perdono segreti, si allontanano dall'obiettivo, rimangono bloccati in loop, o effettuano push direttamente al main. Se non controllati, piccoli fallimenti si trasformano in interruzioni, credenziali compromesse e lavoro perso. +Gli agenti IA falliscono in modi prevedibili. Eseguono comandi distruttivi, perdono segreti, si allontanano dai compiti, rimangono bloccati in loop o effettuano push direttamente su main. Se lasciati incustoditi, i piccoli fallimenti si trasformano in interruzioni di servizio, credenziali compromesse e lavoro perso. -FailproofAI risolve questo con le **politiche**. Queste regole si intercettano in ogni chiamata di strumento dell'agente per **rilevare i fallimenti**, **mitigarli** (bloccare, istruire, pulire) e **avvisarti** quando qualcosa richiede attenzione. Un dashboard locale ti permette di esaminare ogni chiamata di strumento, fallimento dell'agente e azione di recupero in seguito. +FailproofAI risolve questo problema con le **politiche**. Queste regole si collegano a ogni chiamata di tool dell'agente per **rilevare i fallimenti**, **mitigarli** (bloccare, istruire, sanificare) e **avvisarti** quando qualcosa richiede attenzione. Una dashboard locale ti consente di esaminare ogni chiamata di tool, fallimento dell'agente e azione di ripristino in seguito. Nessun dato lascia il tuo computer. -## Inizia subito +## Inizia - Blocca comandi distruttivi, previeni perdite di segreti, mantieni gli agenti entro i confini del progetto e altro ancora. Tutto già pronto. + Blocca i comandi distruttivi, previeni la perdita di segreti, mantieni gli agenti dentro i confini del progetto e altro ancora. Tutto pronto all'uso. - Scrivi le tue regole in JavaScript con un semplice API allow / deny / instruct. + Scrivi le tue regole in JavaScript con una semplice API allow / deny / instruct. - - Scopri cosa hanno fatto i tuoi agenti mentre eri assente. Naviga le sessioni, ispeziona le chiamate di strumenti, rivedi dove le politiche hanno agito. + + Scopri cosa hanno fatto i tuoi agenti mentre eri via. Sfoglia le sessioni, ispeziona le chiamate di tool, rivedi dove sono scattate le politiche. - - Regola qualsiasi politica senza codice. Imposta liste di autorizzazione, rami protetti o soglie per progetto o globalmente. + + Regola qualsiasi politica senza codice. Imposta allowlist, rami protetti o soglie per progetto o a livello globale. -## Avvio rapido +## Inizio rapido @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # abilita le politiche (o salta — `failproofai` ti offrirà di configurarle al primo avvio) -failproofai # avvia il dashboard +failproofai policies --install # abilita le politiche (o salta — `failproofai` ti oferirà di configurarle al primo avvio) +failproofai # avvia la dashboard ``` -Vedi la guida [Inizia subito](/it/getting-started) per la procedura dettagliata completa. \ No newline at end of file +Consulta la guida [Inizia](/it/getting-started) per la procedura dettagliata completa. \ No newline at end of file diff --git a/docs/ja/built-in-policies.mdx b/docs/ja/built-in-policies.mdx index f36abfd2..56cfaf70 100644 --- a/docs/ja/built-in-policies.mdx +++ b/docs/ja/built-in-policies.mdx @@ -1,10 +1,10 @@ --- title: 組み込みポリシー -description: "エージェントの一般的な障害モードを検出する39の組み込みポリシー" +description: "エージェントの一般的な失敗パターンを検出する39種類の組み込みポリシー" icon: shield --- -failproofai には、エージェントの一般的な障害モードを検出する39の組み込みポリシーが同梱されています。各ポリシーは特定のフックイベントタイプとツール名に対して発火します。19のポリシーはパラメーターを受け付けており、コードを書くことなく動作を調整できます。5つのワークフローポリシーは、Claude が停止する前にコミット → プッシュ → PR → CI のパイプラインを強制します。 +failproofai には、エージェントの一般的な失敗パターンを検出する39種類の組み込みポリシーが含まれています。各ポリシーは特定のフックイベントタイプとツール名に対して発火します。19種類のポリシーはパラメーターを受け付け、コードを書くことなく動作を調整できます。5種類のワークフローポリシーは、Claude が停止する前にコミット → プッシュ → PR → CI のパイプラインを強制します。 --- @@ -25,15 +25,15 @@ failproofai には、エージェントの一般的な障害モードを検出 | [パッケージマネージャー](#package-managers) | prefer-package-manager | PreToolUse | | [ワークフロー](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — エージェントの処理を停止する。 -- **`warn-`** — エージェントが自己修正できるよう追加のコンテキストを提供する。 -- **`sanitize-`** — エージェントが確認する前にツール出力から機密データを除去する。 +- **`block-`** — エージェントの処理を停止します。 +- **`warn-`** — エージェントが自己修正できるよう、追加のコンテキストを提供します。 +- **`sanitize-`** — エージェントが参照する前に、ツール出力から機密データを除去します。 ### 名前空間 -すべてのポリシーは `<名前空間>/<名前>` というスロットに存在します。組み込みポリシーは **`failproofai/`** 名前空間に属しています(例:`failproofai/sanitize-jwt`)。名前空間により、類似した短い名前のカスタムポリシーやサードパーティポリシーを読み込む際の衝突を防ぎます。 +すべてのポリシーは `/` というスロットに配置されます。組み込みポリシーは **`failproofai/`** 名前空間に属します(例:`failproofai/sanitize-jwt`)。名前空間により、同様の短い名前を持つカスタムポリシーやサードパーティポリシーを読み込む際の衝突を防ぎます。 -設定ファイルでは、組み込みポリシーを短縮名または完全修飾名のどちらでも参照でき、両方の形式が同じポリシーに解決されます: +設定では、組み込みポリシーを短縮名または完全修飾名のどちらでも参照できます。どちらの形式も同じポリシーに解決されます: ```json { @@ -44,33 +44,33 @@ failproofai には、エージェントの一般的な障害モードを検出 } ``` -名前に `/` が含まれない場合、failproofai はそれをデフォルト名前空間 `failproofai` に属するものとして扱います。すでに `/` を含む名前(例:`myorg/foo`、`custom/my-hook`)はそのまま保持されます。 -- **`require-`** — 条件が満たされるまで Stop イベントをブロックする。 +名前に `/` が含まれていない場合、failproofai はデフォルト名前空間 `failproofai` に属するものとして扱います。すでに `/` を含む名前(例:`myorg/foo`、`custom/my-hook`)はそのまま使用されます。 +- **`require-`** — 条件が満たされるまで Stop イベントをブロックします。 --- -すべてのポリシーは `policyParams` にオプションの `hint` フィールドをサポートします。ヒントは Claude が受け取る deny または instruct メッセージに追加され、ポリシーコードを変更せずに実用的なガイダンスを提供します。組み込み・カスタム・規約ポリシーのすべてで機能します。詳細は[設定 → hint](/ja/configuration#hint-cross-cutting)を参照してください。 +すべてのポリシーは `policyParams` でオプションの `hint` フィールドをサポートしています。hint は Claude が受け取る deny または instruct メッセージに追記され、ポリシーコードを変更することなく実行可能なガイダンスを提供します。組み込みポリシー、カスタムポリシー、規約ポリシーのいずれでも機能します。詳細は [設定 → hint](/ja/configuration#hint-cross-cutting) を参照してください。 --- -## 危険なコマンド +## 危険なコマンド {#dangerous-commands} -取り消しが困難な操作や、ホストシステムに損害を与える可能性のある操作をエージェントが実行するのを防ぎます。 +元に戻しにくい操作や、ホストシステムに損害を与える可能性のある操作をエージェントが実行しないようにします。 ### `block-sudo` **イベント:** PreToolUse (Bash) -**デフォルト:** `sudo` コマンドを含む任意のコマンドを拒否します。 +**デフォルト:** `sudo` コマンドをすべて拒否します。 -`sudo` キーワードを含む呼び出しをブロックします。パターンマッチングは生の文字列ではなく解析済みのコマンドトークンに対して行われるため、シェル演算子インジェクションによる回避を防ぎます。 +`sudo` キーワードを含む呼び出しをブロックします。パターンマッチングは生の文字列ではなくパースされたコマンドトークンに対して行われるため、シェルオペレーターインジェクションによる回避を防ぎます。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可されるコマンドの正確なプレフィックス。各エントリは解析済みの argv トークンと照合されます。 | +| `allowPatterns` | `string[]` | `[]` | 許可するコマンドプレフィックスの一覧。各エントリはパースされた argv トークンと照合されます。 | **例:** @@ -87,7 +87,7 @@ failproofai には、エージェントの一般的な障害モードを検出 この設定では、`sudo systemctl status nginx` は許可されますが、`sudo rm /etc/hosts` は拒否されます。 -パターンは生のコマンド文字列ではなく解析済みトークンと照合されます。これにより、追加されたシェル演算子による回避を防ぎます(例:`sudo systemctl status x; rm -rf /` は `sudo systemctl status *` にマッチしません)。 +パターンは生のコマンド文字列ではなくパースされたトークンと照合されます。これにより、シェルオペレーターを末尾に付加した回避を防ぎます(例:`sudo systemctl status x; rm -rf /` は `sudo systemctl status *` にマッチしません)。 --- @@ -95,13 +95,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-rm-rf` **イベント:** PreToolUse (Bash) -**デフォルト:** `rm -rf`、`rm -fr`、および類似の再帰的削除形式を拒否します。 +**デフォルト:** `rm -rf`、`rm -fr`、および類似の再帰削除コマンドを拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | 再帰的削除が安全なパス(例:`/tmp`)。 | +| `allowPaths` | `string[]` | `[]` | 再帰削除が許可されるパスの一覧(例:`/tmp`)。 | **例:** @@ -135,22 +135,22 @@ failproofai には、エージェントの一般的な障害モードを検出 --- -## インフラコマンド +## インフラコマンド {#infra-commands} -コーディングエージェントがインフラ CLI を実行したり、CI/CD パイプラインをトリガーしたりするのを停止します。このカテゴリのすべてのポリシーは**オプトイン**(`defaultEnabled: false`)です。正当に `kubectl` や `terraform` などを呼び出す必要があるエージェントは、ポリシーを有効にしない限り影響を受けません。有効にすると、コマンドが `allowPatterns` のエントリにマッチしない限り、マッチした CLI のすべての呼び出しが拒否されます。 +コーディングエージェントがインフラ CLI を実行したり、CI/CD パイプラインをトリガーしたりしないようにします。このカテゴリのすべてのポリシーは**オプトイン**(`defaultEnabled: false`)です。`kubectl` や `terraform` などを正当な目的で呼び出すエージェントは、ポリシーを有効にしない限り影響を受けません。有効にすると、一致する CLI のすべての呼び出しは、コマンドが `allowPatterns` のエントリに一致しない限り拒否されます。 -パターン文法は [`block-sudo`](#block-sudo) と同じです:トークンは解析済みの argv と照合され、`*` は1つのトークンのワイルドカードです。また、スタンドアロンのシェル演算子(`&&`、`||`、`|`、`;`)を含むコマンドや、埋め込まれたシェルメタ文字を含むトークンは、インジェクション回避を防ぐためにアローリストマッチングの前に拒否されます。 +パターン文法は [`block-sudo`](#block-sudo) と同じです。トークンはパースされた argv と照合され、`*` は1トークンのワイルドカードです。スタンドアロンのシェルオペレーター(`&&`、`||`、`|`、`;`)を含むコマンド、またはシェルメタキャラクターが埋め込まれたトークンを含むコマンドは、インジェクション回避を防ぐためにアローリストマッチングより先に拒否されます。 ### `block-kubectl` **イベント:** PreToolUse (Bash) -**デフォルト:** `kubectl` の任意の呼び出しを拒否します。 +**デフォルト:** `kubectl` の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される kubectl コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する kubectl コマンドプレフィックスの一覧。 | **例:** @@ -171,13 +171,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-terraform` **イベント:** PreToolUse (Bash) -**デフォルト:** `terraform` または `tofu`(OpenTofu)の任意の呼び出しを拒否します。 +**デフォルト:** `terraform` または `tofu`(OpenTofu)の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される terraform/tofu コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する terraform/tofu コマンドプレフィックスの一覧。 | **例:** @@ -196,13 +196,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-aws-cli` **イベント:** PreToolUse (Bash) -**デフォルト:** `aws` CLI の任意の呼び出しを拒否します。 +**デフォルト:** `aws` CLI の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される aws CLI コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する aws CLI コマンドプレフィックスの一覧。 | **例:** @@ -221,13 +221,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-gcloud` **イベント:** PreToolUse (Bash) -**デフォルト:** `gcloud`(Google Cloud)CLI の任意の呼び出しを拒否します。 +**デフォルト:** `gcloud`(Google Cloud)CLI の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される gcloud コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する gcloud コマンドプレフィックスの一覧。 | **例:** @@ -246,13 +246,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-az-cli` **イベント:** PreToolUse (Bash) -**デフォルト:** `az`(Azure)CLI の任意の呼び出しを拒否します。 +**デフォルト:** `az`(Azure)CLI の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される az CLI コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する az CLI コマンドプレフィックスの一覧。 | **例:** @@ -271,13 +271,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-helm` **イベント:** PreToolUse (Bash) -**デフォルト:** `helm` の任意の呼び出しを拒否します。 +**デフォルト:** `helm` の呼び出しをすべて拒否します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 許可される helm コマンドプレフィックス。 | +| `allowPatterns` | `string[]` | `[]` | 許可する helm コマンドプレフィックスの一覧。 | **例:** @@ -305,13 +305,13 @@ failproofai には、エージェントの一般的な障害モードを検出 - `gh cache delete` - `gh secret set`、`gh secret delete` -`gh pr view`、`gh pr list`、`gh run list`、`gh release view`、`gh api repos/.../...` などの読み取り専用の `gh` サブコマンドは、このポリシーの対象外です。これらはワークフローの確認(failproofai 自身の `require-ci-green-before-stop` を含む)に日常的に必要とされます。 +`gh pr view`、`gh pr list`、`gh run list`、`gh release view`、`gh api repos/.../...` などの読み取り専用の `gh` サブコマンドはこのポリシーの対象外です。これらはワークフロー確認(failproofai 独自の `require-ci-green-before-stop` を含む)で日常的に使用されます。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 通常は拒否される場合でも許可する特定のスクリプト化された呼び出し。 | +| `allowPatterns` | `string[]` | `[]` | 通常は拒否される特定のスクリプト呼び出しを許可するためのパターン。 | **例:** @@ -327,9 +327,9 @@ failproofai には、エージェントの一般的な障害モードを検出 --- -## シークレット(サニタイザー) +## シークレット(サニタイザー) {#secrets-sanitizers} -エージェントが認証情報をコンテキストや出力に漏洩させるのを防ぎます。サニタイザーポリシーは **PostToolUse** イベントで発火します。Claude が Bash コマンドを実行したり、ファイルを読み込んだり、ツールを呼び出したりすると、これらのポリシーは出力が Claude に返される前に検査します。シークレットパターンが検出された場合、ポリシーは出力が返されるのを防ぐ deny 決定を返します。 +エージェントが認証情報をコンテキストや出力に漏洩しないようにします。サニタイザーポリシーは **PostToolUse** イベントで発火します。Claude が Bash コマンドを実行したり、ファイルを読み込んだり、ツールを呼び出したりすると、これらのポリシーは出力が Claude に返される前に検査します。シークレットパターンが検出された場合、ポリシーは出力が返されないようにする deny 判定を返します。 ### `sanitize-jwt` @@ -395,16 +395,16 @@ failproofai には、エージェントの一般的な障害モードを検出 --- -## 環境 +## 環境 {#environment} -エージェントによる機密環境設定の読み取りや露出を防ぎます。 +エージェントが機密な環境設定を読み取ったり公開したりしないよう保護します。 ### `block-env-files` **イベント:** PreToolUse (Bash, Read) -**デフォルト:** `cat .env` や `.env` をファイルパスとして指定した `Read` ツール呼び出しなど、`.env` ファイルの読み取りを拒否します。 +**デフォルト:** `cat .env` や `.env` をファイルパスとする `Read` ツール呼び出しなど、`.env` ファイルの読み取りを拒否します。 -`.envrc` やその他の環境関連ファイルはブロックせず、正確に `.env` という名前のファイルのみを対象とします。 +`.envrc` やその他の環境関連ファイルはブロックしません。`.env` という名前のファイルのみが対象です。 パラメーターなし。 @@ -413,26 +413,26 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `protect-env-vars` **イベント:** PreToolUse (Bash) -**デフォルト:** 環境変数を表示するコマンド(`printenv`、`env`、`echo $VAR`)を拒否します。 +**デフォルト:** `printenv`、`env`、`echo $VAR` など、環境変数を出力するコマンドを拒否します。 パラメーターなし。 --- -## ファイルアクセス +## ファイルアクセス {#file-access} -エージェントをプロジェクトの境界内に留め、機密ファイルへのアクセスを防ぎます。 +エージェントがプロジェクトの境界内で作業し、機密ファイルにアクセスしないようにします。 ### `block-read-outside-cwd` **イベント:** PreToolUse (Read, Bash) -**デフォルト:** プロジェクトルート外のファイル読み取りを拒否します。境界は `CLAUDE_PROJECT_DIR`(Claude Code がセッションごとに1回設定)で、この変数が未設定の場合はセッションの現在の作業ディレクトリにフォールバックします。ライブの `cwd` ではなくプロジェクトルートを使用することで、Claude がサブディレクトリに `cd` した後も境界が安定したまま保たれます。 +**デフォルト:** プロジェクトルート外のファイルの読み取りを拒否します。境界は `CLAUDE_PROJECT_DIR`(Claude Code がセッションごとに1回設定)で、この変数が設定されていない場合はセッションの現在の作業ディレクトリにフォールバックします。ライブの `cwd` ではなくプロジェクトルートを使用することで、Claude がサブディレクトリに `cd` した後も境界が安定します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | プロジェクトルート外であっても許可される絶対パスプレフィックス。 | +| `allowPaths` | `string[]` | `[]` | プロジェクトルート外でも許可する絶対パスプレフィックスの一覧。 | **例:** @@ -451,7 +451,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-secrets-write` **イベント:** PreToolUse (Write, Edit) -**デフォルト:** 秘密鍵や証明書によく使用されるファイルへの書き込みを拒否します:`id_rsa`、`id_ed25519`、`*.key`、`*.pem`、`*.p12`、`*.pfx`。 +**デフォルト:** 秘密鍵や証明書によく使われるファイルへの書き込みを拒否します:`id_rsa`、`id_ed25519`、`*.key`、`*.pem`、`*.p12`、`*.pfx`。 **パラメーター:** @@ -473,9 +473,9 @@ failproofai には、エージェントの一般的な障害モードを検出 --- -## Git +## Git {#git} -取り消しが困難な誤ったプッシュ、強制プッシュ、ブランチミスを防ぎます。 +元に戻しにくい、誤ったプッシュ、フォースプッシュ、ブランチ操作を防ぎます。 ### `block-push-master` @@ -486,7 +486,7 @@ failproofai には、エージェントの一般的な障害モードを検出 | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | 直接プッシュできないブランチ名。 | +| `protectedBranches` | `string[]` | `["main", "master"]` | 直接プッシュできないブランチ名の一覧。 | **例:** @@ -501,7 +501,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ``` -すべてのブランチへのプッシュを許可する(`enabledPolicies` からポリシーを削除せずに実質的に無効化する)には、`protectedBranches: []` を設定してください。 +全ブランチへのプッシュを許可する(`enabledPolicies` からポリシーを削除せずに実質的に無効化する)には、`protectedBranches: []` を設定してください。 --- @@ -509,13 +509,13 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `block-work-on-main` **イベント:** PreToolUse (Bash) -**デフォルト:** ワーキングツリーが `main` または `master` 上にある場合、`git commit`、`git merge`、`git rebase`、`git cherry-pick` を拒否します。ブランチの作成と切り替え(`git checkout`、`git checkout -b`、`git switch`、`git switch -c`)は影響を受けません。 +**デフォルト:** `main` または `master` ブランチで作業中に `git commit`、`git merge`、`git rebase`、`git cherry-pick` を拒否します。ブランチの作成や切り替え(`git checkout`、`git checkout -b`、`git switch`、`git switch -c`)は影響を受けません。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | commit/merge/rebase/cherry-pick が拒否されるブランチ名。 | +| `protectedBranches` | `string[]` | `["main", "master"]` | コミット/マージ/リベース/チェリーピックを拒否するブランチ名の一覧。 | --- @@ -524,7 +524,7 @@ failproofai には、エージェントの一般的な障害モードを検出 **イベント:** PreToolUse (Bash) **デフォルト:** `git push --force` および `git push -f` を拒否します。 -ポリシー固有のパラメーターはありません。代替案を提案するには、共通の [`hint`](/ja/configuration#hint-cross-cutting) を使用してください: +ポリシー固有のパラメーターはありません。代替手段を提案するには、横断的な [`hint`](/ja/configuration#hint-cross-cutting) を使用してください: ```json { @@ -541,7 +541,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `warn-git-amend` **イベント:** PreToolUse (Bash) -**デフォルト:** `git commit --amend` を実行する際に慎重に進むよう Claude に指示します。コマンドをブロックしません。 +**デフォルト:** `git commit --amend` を実行する際、慎重に進むよう Claude に指示します。コマンドはブロックしません。 パラメーターなし。 @@ -550,7 +550,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `warn-git-stash-drop` **イベント:** PreToolUse (Bash) -**デフォルト:** `git stash drop` を実行する前に確認するよう Claude に指示します。コマンドをブロックしません。 +**デフォルト:** `git stash drop` を実行する前に確認するよう Claude に指示します。コマンドはブロックしません。 パラメーターなし。 @@ -559,20 +559,20 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `warn-all-files-staged` **イベント:** PreToolUse (Bash) -**デフォルト:** `git add -A` または `git add .` を実行する際に、ステージングする内容を確認するよう Claude に指示します。コマンドをブロックしません。 +**デフォルト:** `git add -A` または `git add .` を実行する際、ステージングしようとしている内容を確認するよう Claude に指示します。コマンドはブロックしません。 パラメーターなし。 --- -## データベース +## データベース {#database} -データベースに対して実行される前に破壊的な SQL 操作を検出します。 +データベースに対して実行される前に、破壊的な SQL 操作を検出します。 ### `warn-destructive-sql` **イベント:** PreToolUse (Bash) -**デフォルト:** `DROP TABLE`、`DROP DATABASE`、または `WHERE` 句なしの `DELETE` を含む SQL を実行する前に確認するよう Claude に指示します。 +**デフォルト:** `DROP TABLE`、`DROP DATABASE`、または `WHERE` 句のない `DELETE` を含む SQL を実行する前に確認するよう Claude に指示します。 パラメーターなし。 @@ -581,15 +581,15 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `warn-schema-alteration` **イベント:** PreToolUse (Bash) -**デフォルト:** `ALTER TABLE` 文を実行する前に確認するよう Claude に指示します。 +**デフォルト:** `ALTER TABLE` ステートメントを実行する前に確認するよう Claude に指示します。 パラメーターなし。 --- -## 警告 +## 警告 {#warnings} -潜在的にリスクはあるが破壊的ではない操作の前に、エージェントに追加のコンテキストを提供します。 +潜在的にリスクはあるが非破壊的な操作の前に、エージェントに追加のコンテキストを提供します。 ### `warn-large-file-write` @@ -600,7 +600,7 @@ failproofai には、エージェントの一般的な障害モードを検出 | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | 警告が発行されるファイルサイズのしきい値(キロバイト)。 | +| `thresholdKb` | `number` | `1024` | 警告を発するファイルサイズの閾値(キロバイト単位)。 | **例:** @@ -615,7 +615,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ``` -フックハンドラーはペイロードに対して 1 MB の stdin 制限を適用します。小さいコンテンツでこのポリシーをテストするには、`thresholdKb` を 1024 よりも十分に低い値に設定してください。 +フックハンドラーはペイロードに対して 1 MB の stdin 制限を設けています。このポリシーを小さなコンテンツでテストするには、`thresholdKb` を 1024 より十分に小さい値に設定してください。 --- @@ -632,7 +632,7 @@ failproofai には、エージェントの一般的な障害モードを検出 ### `warn-background-process` **イベント:** PreToolUse (Bash) -**デフォルト:** `nohup`、`&`、`disown`、または `screen` を使用してバックグラウンドプロセスを起動する際に注意するよう Claude に指示します。 +**デフォルト:** `nohup`、`&`、`disown`、または `screen` でバックグラウンドプロセスを起動する際に注意するよう Claude に指示します。 パラメーターなし。 @@ -647,23 +647,23 @@ failproofai には、エージェントの一般的な障害モードを検出 --- -## パッケージマネージャー +## パッケージマネージャー {#package-managers} -エージェントが使用できるパッケージマネージャーを強制します。 +エージェントが使用を許可されているパッケージマネージャーを強制します。 ### `prefer-package-manager` **イベント:** PreToolUse (Bash) -**デフォルト:** 無効。有効にすると、`allowed` リストにないパッケージマネージャーコマンドをブロックし、許可されたマネージャーを使用してコマンドを書き直すよう Claude に指示します。 +**デフォルト:** 無効。有効にすると、`allowed` リストにないパッケージマネージャーコマンドをブロックし、許可されたマネージャーを使用してコマンドを書き直すよう Claude に伝えます。 -検出対象:pip、pip3、python -m pip、npm、npx、yarn、pnpm、pnpx、bun、bunx、uv、poetry、pipenv、conda、cargo。 +検出対象:pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo。 | パラメーター | 型 | デフォルト | 説明 | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | 許可するパッケージマネージャー名。このリストにない検出済みのマネージャーはブロックされます。空の場合、ポリシーは何もしません。 | -| `blocked` | string[] | `[]` | 組み込みリストに加えてブロックする追加のマネージャー名(例:`['pdm', 'pipx']`)。 | +| `allowed` | string[] | `[]` | 許可するパッケージマネージャー名の一覧。このリストにない検出済みのマネージャーはブロックされます。空の場合、ポリシーは何もしません。 | +| `blocked` | string[] | `[]` | 組み込みリスト以外に追加でブロックするマネージャー名(例:`['pdm', 'pipx']`)。 | -組み込みブロックリストは次を対象とします:pip、pip3、npm、npx、yarn、pnpm、pnpx、bun、bunx、uv、poetry、pipenv、conda、cargo。このリストにないマネージャーを追加するには `blocked` を使用してください。 +組み込みのブロックリストには pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo が含まれます。このリストにないマネージャーを追加するには `blocked` を使用してください。 **設定例:** @@ -679,59 +679,58 @@ failproofai には、エージェントの一般的な障害モードを検出 } ``` -この設定では、`pip install flask` と `pdm install flask` はどちらも、`uv` または `bun` を使用するよう指示するメッセージとともに拒否されます。`uv pip install flask` のようなコマンドは、`uv` がアローリストに含まれており最初にチェックされるため許可されます。 +この設定では、`pip install flask` と `pdm install flask` はどちらも拒否され、`uv` または `bun` を使用するよう Claude に伝えます。`uv pip install flask` はアローリストで `uv` が最初に確認されるため許可されます。 --- -## AI の動作 +## AI の動作 {#ai-behavior} -エージェントが行き詰まったり予期しない動作をしていないかを検出します。 +エージェントが行き詰まったり、予期しない動作をしたりした場合に検出します。 ### `warn-repeated-tool-calls` **イベント:** PreToolUse(全ツール) -**デフォルト:** 同じツールが同一のパラメーターで3回以上呼び出された場合に再考するよう Claude に指示します。これはエージェントがループにはまっている一般的なサインです。 +**デフォルト:** 同じツールが同一パラメーターで3回以上呼び出された場合、再考するよう Claude に指示します。これはエージェントがループにはまっているよくある兆候です。 パラメーターなし。 --- -## ワークフロー +## ワークフロー {#workflow} -セッション終了時に規律あるワークフローを強制します。これらのポリシーは **Stop** イベントで発火し、各条件が満たされるまでエージェントの停止を拒否します。コミット → プッシュ → PR → CI という自然な依存チェーンに従います。ポリシーが拒否した場合、チェーン内のそれ以降のポリシーはスキップされます(deny はショートサーキット)。 +セッション終了時の規律あるワークフローを強制します。これらのポリシーは **Stop** イベントで発火し、各条件が満たされるまでエージェントの停止を拒否します。コミット → プッシュ → PR → CI という自然な依存チェーンに従います。ポリシーが拒否した場合、チェーン内の後続ポリシーはスキップされます(deny によるショートサーキット)。 -すべてのワークフローポリシーは**フェイルオープン**です:必要なツールが利用できない場合(例:`gh` がインストールされていない、git リモートがない)、ポリシーはチェックがスキップされた理由を説明する情報メッセージとともに許可します。 +すべてのワークフローポリシーは **フェイルオープン** です。必要なツールが利用できない場合(例:`gh` がインストールされていない、git リモートがない)、ポリシーはチェックをスキップした理由を Claude に通知するメッセージとともに許可します。 ### CLI ごとの Stop セマンティクス -Stop の強制は、サポートされている7つの CLI によって若干異なります。各 CLI が異なる「エージェント終了」フックコントラクトを公開しているためです。**結果**は同じです(ワークフローゲートが失敗している間、エージェントは停止できません)が、**仕組み**は異なります。以下の表に要約します。`require-*-before-stop` ポリシーを有効にする前に理解しておく価値のある、ユーザーに見える挙動があるのは Pi のみです。 +Stop の強制は、6つのサポート対象 CLI によって若干異なります。各 CLI はそれぞれ異なる「エージェント完了」フックコントラクトを公開しているためです。**結果**は同じです(ワークフローゲートが失敗している間、エージェントは停止できません)が、**仕組み**は異なります。以下の表にまとめます。なお、`require-*-before-stop` ポリシーを有効にする前に理解しておく価値のある、ユーザーに見える特性を持つのは Pi のみです。 -| CLI | ゲートが発火するタイミング | 表示される内容 | +| CLI | ゲートが発火するタイミング | 表示内容 | |---|---|---| -| Claude Code | 同じエージェントループ内で即座に | Claude が作業を継続し、問題を修正してから再び終了を試みます。ユーザーには中断が見えません。 | -| Codex | 同じエージェントループ内で即座に | Claude と同じです。 | -| GitHub Copilot CLI | 同じエージェントループ内で即座に | Claude と同じです(Copilot の `{decision:"block", reason}` リトライチャネルを使用 — Copilot CLI 1.0.41 で実証的に検証済み)。 | -| Cursor Agent | 同じエージェントループ内で即座に | Claude と同じです(Cursor の `{followup_message}` チャネルを使用 — デフォルト5回の `loop_limit` に上限あり)。 | -| Gemini CLI | 同じエージェントループ内で即座に | Claude と同じです(`AfterAgent` 上の Gemini の `{decision:"block", reason}` チャネルを使用)。 | -| OpenCode | 同じエージェントループ内で即座に | Claude と同じです(`hookSpecificOutput.additionalContext` を通じてルーティングされた OpenCode の `client.session.prompt(...)` SDK 呼び出しを使用)。 | -| **Pi (pi-coding-agent)** | **次のユーザーターン** | **Pi はゲートが発火すると目に見えて停止します** — エージェントループが終了し、プロンプトに戻ります。次にプロンプトを送信した際にゲートが発火します:failproofai はそのターンのシステムプロンプトの先頭に `MANDATORY ACTION REQUIRED` ディレクティブを付加し、あなたのリクエストを実行する前にワークフローステップ(コミット、プッシュなど)を完了するよう LLM に指示します。 | +| Claude Code | 同じエージェントループ、即座に | Claude は作業を続け、問題を修正してから再度終了を試みます。ユーザーには中断は見えません。 | +| Codex | 同じエージェントループ、即座に | Claude と同様です。 | +| GitHub Copilot CLI | 同じエージェントループ、即座に | Claude と同様です(Copilot の `{decision:"block", reason}` リトライチャネルを使用 — Copilot CLI 1.0.41 に対して実証的に検証済み)。 | +| Cursor Agent | 同じエージェントループ、即座に | Claude と同様です(Cursor の `{followup_message}` チャネルを使用 — `loop_limit`、デフォルト5回のリトライで上限)。 | +| OpenCode | 同じエージェントループ、即座に | Claude と同様です(OpenCode の `client.session.prompt(...)` SDK 呼び出しを `hookSpecificOutput.additionalContext` 経由でルーティング)。 | +| **Pi (pi-coding-agent)** | **次のユーザーターン** | **ゲートが発火すると Pi は見た目上停止します** — エージェントループが終了し、プロンプトに戻ります。ゲートは次にプロンプトを送信したときに発火します:failproofai はそのターンのシステムプロンプトの先頭に `MANDATORY ACTION REQUIRED` ディレクティブを付加し、ユーザーのリクエストを処理する前にワークフロー手順(コミット、プッシュなど)を完了するよう LLM に指示します。 | -**Pi の制限事項。** Pi の `AgentEndEvent`(Claude の `Stop` フックに相当するアップストリーム)には Result タイプがありません。発火した時点で Pi のエージェントループはすでに終了しています。Claude / Copilot / Cursor / Gemini / OpenCode のように Pi を同じループで再試行させることはできません。failproofai はゲートを Pi の `before_agent_start` イベント(次のユーザープロンプトの後に発火)にシフトするため、ワークフローチェックは依然として強制されますが、現在のターンではなく次のターンで適用されます。 +**Pi の制限について。** Pi の `AgentEndEvent`(Claude の `Stop` フックに相当するアップストリームイベント)には Result 型がありません。発火する時点で Pi のエージェントループはすでに終了しています。Pi は Claude / Copilot / Cursor / OpenCode のように同じループをリトライさせることができません。failproofai はゲートを Pi の `before_agent_start` イベント(次のユーザープロンプト後に発火)にシフトすることで、ワークフローチェックを引き続き強制しますが、現在のターンではなく次のターンで行われます。 **実際の動作:** -- Pi が停止した後、deny の理由は Pi のセッション ID をキーとしてメモリ内に保存されます。同じ Pi プロセスで次に送信したプロンプトがそれを消費します:LLM はシステムプロンプトの先頭で `MANDATORY ACTION REQUIRED` ディレクティブを確認し、コミット(またはプッシュ / PR 作成 / CI 待機)してから、あなたのリクエストを続行します。保存された deny の理由は一度消費されるとクリアされ、ゲートは解除されます。 -- ゲートは Pi のプロセスの存続期間に縛られます。ターンの間に Pi を `Ctrl+C` で終了するか終了した場合、メモリ内のエントリはプロセスとともに削除され、ゲートは失われます。Claude、Copilot、Cursor、Gemini、OpenCode も同じ制約があります(エージェントを強制終了するとゲートは失われます)。Pi はエージェントがゲートの発火前に目に見えて終了するため、これがより顕著に現れます。 -- 保留中の deny は、任意の理由(`new` / `resume` / `fork` / `quit`)による `session_shutdown` でもクリアされるため、前のセッションの古いゲートが同じ Pi プロセスで開始された新しいセッションに漏れることはありません。 +- Pi が停止した後、deny の理由は Pi のセッション ID をキーとしてメモリ内にキャプチャされます。同じ Pi プロセスで次に送信したプロンプトでドレインされます:LLM はシステムプロンプトの先頭に `MANDATORY ACTION REQUIRED` ディレクティブを見て、コミット(またはプッシュ / PR 作成 / CI 待機)を行ってからリクエストを続行します。キャプチャされた deny の理由はワンショットで、一度ドレインされるとゲートはクリアされます。 +- ゲートは Pi のプロセスライフタイムに制限されます。ターン間に Pi を `Ctrl+C` で終了またはquitした場合、メモリ内エントリはプロセスとともに破棄され、ゲートは見逃されます。Claude、Copilot、Cursor、OpenCode も同じ制限を持ちます(エージェントを強制終了するとゲートが見逃されます)— Pi はエージェントがゲートが発火する前に明示的に終了するため、より目立ちます。 +- 保留中の deny は `session_shutdown` 時に(`new` / `resume` / `fork` / `quit` のいずれの理由でも)クリアされるため、以前のセッションからの古いゲートが同じ Pi プロセスで開始された新しいセッションに漏れることはありません。 -Claude スタイルの同ループ再試行が必要な場合は、他の6つのサポートされている CLI のいずれかで `Stop` ポリシーを実行してください。`AgentEndEvent` に Result タイプを追加するためのアップストリームの Pi の更新を追跡しており、これによりこのギャップを解消できる可能性があります。 +Claude スタイルの同一ループリトライが必要な場合は、他の5つのサポート対象 CLI のいずれかで `Stop` ポリシーを実行してください。`AgentEndEvent` の将来の Result 型に向けて Pi アップストリームを追跡しており、このギャップを解消できるよう取り組んでいます。 ### `require-commit-before-stop` **イベント:** Stop -**デフォルト:** コミットされていない変更(変更済み、ステージ済み、または未追跡ファイル)がある場合に停止を拒否します。作業ディレクトリがクリーンな場合は情報メッセージを返します。 +**デフォルト:** コミットされていない変更(修正済み、ステージ済み、または未追跡ファイル)がある場合に停止を拒否します。作業ディレクトリがクリーンな場合は情報メッセージを返します。 パラメーターなし。 @@ -765,13 +764,13 @@ Claude スタイルの同ループ再試行が必要な場合は、他の6つの ### `require-pr-before-stop` **イベント:** Stop -**デフォルト:** 現在のブランチにプルリクエストが存在しない場合、または既存の PR がマージされずにクローズされた場合に停止を拒否します。`gh pr create` を使用して PR を作成するよう Claude に指示します。PR が**マージ済み**の場合、ポリシーは許可し(作業がリリースされたため)、ブランチから切り替えるヒント(`git checkout main && git pull`)を提示します。 +**デフォルト:** 現在のブランチにプルリクエストが存在しない場合、またはマージされずにクローズされた場合に停止を拒否します。`gh pr create` で PR を作成するよう Claude に指示します。PR が**マージ**された場合、ポリシーは許可し(作業が完了しているため)、ブランチを切り替えるよう示唆します(`git checkout main && git pull`)。 パラメーターなし。 このポリシーには [GitHub CLI](https://cli.github.com/)(`gh`)のインストールと認証が必要です。 -プルリクエストへの読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。`gh` がインストールされていないか認証されていない場合、ポリシーはフェイルオープンし、理由を Claude に報告します。 +プルリクエストへの読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。`gh` がインストールされていないか認証されていない場合、ポリシーはフェイルオープンし、その理由を Claude に報告します。 --- @@ -779,21 +778,21 @@ Claude スタイルの同ループ再試行が必要な場合は、他の6つの ### `require-no-conflicts-before-stop` **イベント:** Stop -**デフォルト:** 現在のブランチがベースブランチにクリーンにマージできない場合に停止を拒否します。まず GitHub 上のブランチに `OPEN` 状態の PR があることを確認します。PR がなければ強制するマージターゲットがないため、ポリシー全体が allow にショートサーキットします。`OPEN` の PR が確認されると、2つの独立したプローブが実行されます: +**デフォルト:** 現在のブランチがベースブランチにクリーンにマージできない場合に停止を拒否します。ポリシーはまずそのブランチに GitHub 上の `OPEN` な PR があることを確認します。PR がない場合、強制するマージターゲットがないため、ポリシー全体がショートサーキットして許可します。`OPEN` な PR が確認されると、2つの独立した検査が実行されます: -1. **ローカル** — `git merge-tree --write-tree --name-only origin/ HEAD`。コンフリクトが発生した場合、Claude が何を解決すべきかを正確に把握できるよう、deny メッセージにコンフリクトしたファイル名が含まれます。 -2. **GitHub** — プレチェックですでに取得した `gh pr view --json mergeable,state` の結果を再利用します。古いローカルの `origin/` では見逃してしまうコンフリクトを検出します(例:最後のフェッチ以降に `main` に競合する PR がマージされた場合)。`CONFLICTING` の結果は拒否されます。`UNKNOWN` の結果も拒否され、再度停止を試みる前に約10秒待って再確認するよう Claude に指示します。これは GitHub が再計算する間の偽陰性を防ぎます。 +1. **ローカル** — `git merge-tree --write-tree --name-only origin/ HEAD`。競合が発生した場合、deny メッセージに競合ファイルの名前が含まれるため、Claude は何を解決すべきかを正確に把握できます。 +2. **GitHub** — プリチェックで既に取得した `gh pr view --json mergeable,state` の結果を再利用します。ローカルの古い `origin/` では見逃してしまう競合(例:最後のフェッチ以降に誰かが `main` に競合する PR をマージした場合)を検出します。`CONFLICTING` の結果は拒否します。`UNKNOWN` の結果も拒否し、GitHub が再計算する前に再試行を防ぐため、約10秒待ってから再確認するよう Claude に指示します。 -以下の場合は完全にスキップ(allow)します:`gh` がインストールされていない、ブランチに PR が存在しない、PR の状態が `OPEN` でない(例:`MERGED`、`CLOSED`)、または `gh pr view` が解析不能な出力を返す。ローカルに `origin/` がない場合や、ベースより先にコミットがない場合もフェイルオープンします。ただし、それらのレイヤー1フォールスルーは、許可する前にキャッシュされた PR のマージ可能性を確認します。 +次の場合は完全にスキップ(許可)します:`gh` がインストールされていない、ブランチに PR が存在しない、PR の状態が `OPEN` でない(例:`MERGED`、`CLOSED`)、または `gh pr view` が解析できない出力を返す場合。ローカルに `origin/` がない場合、またはベースより前のコミットがない場合もフェイルオープンしますが、これらのレイヤー1フォールスルーは許可する前にキャッシュ済みの PR マージ可能性を引き続き参照します。 **パラメーター:** | パラメーター | 型 | デフォルト | 説明 | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | コンフリクトを確認するベースブランチ。 | +| `baseBranch` | `string` | `"main"` | 競合チェックを行うベースブランチ。 | -このポリシーには GitHub CLI(`gh`)が必要です。ポリシーはコンフリクトプローブを実行する前に `gh pr view` を使用して `OPEN` の PR が存在することを確認します。`gh` がない場合、ポリシーは allow にショートサーキットします。プルリクエストへの読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。 +このポリシーには GitHub CLI(`gh`)が必要です。ポリシーは競合検査を実行する前に `gh pr view` を使用して `OPEN` な PR が存在することを確認します。`gh` がない場合、ポリシーはショートサーキットして許可します。プルリクエストへの読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。 --- @@ -801,13 +800,13 @@ Claude スタイルの同ループ再試行が必要な場合は、他の6つの ### `require-ci-green-before-stop` **イベント:** Stop -**デフォルト:** 現在のブランチで CI チェックが失敗しているか実行中の場合に停止を拒否します。GitHub Actions ワークフロー実行とサードパーティのボットチェック(例:CodeRabbit、SonarCloud、Codecov)の両方を確認します。`skipped`、`cancelled`、`neutral` の結論は失敗として扱いません(後者は例えば Socket Security が外部コントリビューターの PR に対して success/failure ではなく neutral を意図的に報告するケースをカバーします)。すべてのチェックが通過した場合は情報メッセージを返します。 +**デフォルト:** 現在のブランチで CI チェックが失敗中または実行中の場合に停止を拒否します。GitHub Actions のワークフロー実行と、サードパーティのボットチェック(CodeRabbit、SonarCloud、Codecov など)の両方をチェックします。`skipped`、`cancelled`、`neutral` の結論は失敗として扱いません(後者は例えば外部コントリビューターの PR における Socket Security アラートをカバーします。このアプリは意図的に success/failure ではなく neutral を報告します)。すべてのチェックが通過した場合、情報メッセージを返します。 パラメーターなし。 このポリシーには [GitHub CLI](https://cli.github.com/)(`gh`)のインストールと認証が必要です。 -Actions ワークフロー実行と Checks API への読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。`gh` がインストールされていないか認証されていない場合、ポリシーはフェイルオープンし、理由を Claude に報告します。 +Actions ワークフロー実行と Checks API への読み取りアクセスのために `repo` スコープを持つ個人アクセストークンで `gh auth login` を実行してください。`gh` がインストールされていないか認証されていない場合、ポリシーはフェイルオープンし、その理由を Claude に報告します。 --- @@ -816,7 +815,7 @@ Actions ワークフロー実行と Checks API への読み取りアクセスの ## 個別ポリシーの無効化 -設定の `enabledPolicies` から特定のポリシーを削除するか、ダッシュボードの「ポリシー」タブでオフにしてください。 +設定の `enabledPolicies` から特定のポリシーを削除するか、ダッシュボードの「Policies」タブでオフに切り替えます。 ```json { @@ -827,4 +826,4 @@ Actions ワークフロー実行と Checks API への読み取りアクセスの } ``` -`enabledPolicies` にリストされていないポリシーは、`policyParams` のエントリが存在していても実行されません。 \ No newline at end of file +`enabledPolicies` に列挙されていないポリシーは、`policyParams` にエントリが存在していても実行されません。 \ No newline at end of file diff --git a/docs/ja/cli/audit.mdx b/docs/ja/cli/audit.mdx index 4b218e71..68f7203e 100644 --- a/docs/ja/cli/audit.mdx +++ b/docs/ja/cli/audit.mdx @@ -1,19 +1,19 @@ --- -title: 過去セッションの監査(ベータ) -description: "過去のトランスクリプトで、エージェントが無駄または危険な操作を行った頻度を集計する" +title: 過去のセッションを監査する(ベータ版) +description: "過去のトランスクリプトを通じてエージェントが無駄または危険な行動を行った頻度を集計する" --- - **ベータ機能。** 監査機能は早期フィードバックを収集する段階でベータとして提供されています。 - 次の安定版リリース前に、検出器カタログやレポート形式が変更される可能性があります。 - 問題があれば Issue を開いてください。 + **ベータ機能。** 早期フィードバックを収集しながらベータ版として提供しています。 + 次の安定版リリース前に、ディテクターのカタログやレポート形式が変更される可能性があります。 + 何か問題があれば、Issueを開いてください。 -監査機能は、過去のエージェント CLI トランスクリプトを failproofai のポリシーエンジンで再実行し、**`/audit` ダッシュボードページ**に共有可能なビジュアルレポートを表示します。エージェントのアーキタイプ、0〜100 のスコア、そしてどのポリシーが何を検出したかを詳細に確認できます。 +この監査機能は、過去のエージェントCLIトランスクリプトをfailproofaiのポリシーエンジンで再生し、**`/audit` ダッシュボードページ**に共有可能なビジュアルレポートとして表示します。エージェントのアーキタイプ、0〜100のスコア、そして各ポリシーが何を検出したかを正確に確認できます。 ## 実行方法 -3 つの起動方法があり、いずれも同じ `/audit` レポートに遷移します。 +3つの方法があります。どれも同じ `/audit` レポートに到達します。 @@ -33,56 +33,56 @@ failproofai - `npx -y failproofai audit` は failproofai を取得してスキャンを実行し、ダッシュボードを自動で開きます。事前インストールは不要です。 + `npx -y failproofai audit` はfailproofaiを取得してスキャンを実行し、ダッシュボードを自動で開きます。事前のインストールは不要です。 - + `failproofai audit` はターミナルでスキャンを実行し、完了後に自動で `localhost:8020/audit` を開きます。 - `failproofai` を実行してナビゲーションバーの **Audit** をクリック(Policies と Projects の間)するか、`/audit` に直接アクセスします。 + `failproofai` を実行してナビゲーションバーの **Audit**(PoliciesとProjectsの間)をクリックするか、`/audit` を直接開いてください。 - 使い方を確認するには `failproofai audit -h`(または `--help`)を実行してください。監査は**完全オフライン**で動作し、アカウントやネットワーク接続は不要です。`Ctrl+C` で停止するまでダッシュボードはサービスを継続します。 + `failproofai audit -h`(または `--help`)を実行すると使用方法が確認できます。監査は**完全オフライン**で動作し、アカウントやネットワーク接続は不要です。`Ctrl+C` で停止するまでダッシュボードは提供され続けます。 -ダッシュボードはこのマシン上の過去のエージェント CLI トランスクリプト(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi、Gemini)をスキャンし、failproofai が防止するように設計された操作の発生頻度を報告します。対象は環境変数チェック、フォースプッシュ、冗長な `cd ` プレフィックス、スリープポーリングループ、編集直後のファイル再読み込みなどです。 +ダッシュボードはこのマシン上の過去のエージェントCLIトランスクリプト(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi)をスキャンし、failproofaiが防ぐために設計された行動をエージェントがどの程度行っていたかをレポートします。環境変数チェック、強制プッシュ、冗長な `cd ` プレフィックス、スリープポーリングループ、編集直後のファイル再読み込みなどが対象です。 -各トランスクリプトについて、すべてのツール使用イベントが 39 のビルトインポリシー**および** 8 つの監査専用検出器で再実行されます(後者はランタイムポリシーでまだカバーされていないパターンを検出します)。カウントはポリシー・検出器ごとにすべてのセッションで集計されます。 +各トランスクリプトについて、すべてのツール使用イベントが39のビルトインポリシー**および**ランタイムポリシーではまだカバーされていないパターンを検出する8つの監査専用ディテクターで再生されます。カウントはすべてのセッションにわたってポリシー/ディテクターごとに集計されます。 -## レポートの内容 +## 確認できる内容 -`/audit` ページは 1 画面の共有可能な**ポスター**と、スクロール下の 4 つのセクションで構成されています。 +`/audit` ページは1画面の共有可能な**ポスター**と、その下の4つのセクションで構成されています。 -1. **ポスター** — エージェントのプロフィールが一目でわかる。**アーキタイプ**(8 種類のうちの 1 つ — `optimist`、`cowboy`、`explorer`、`goldfish`、`paranoid architect`、`precision builder`、`hammer`、`ghost`)、ペルソナキーワード、そのアーキタイプのレア度、**0〜100 スコア**とティアバンド(`S` から `bottom tier` まで)。X や LinkedIn への投稿や PNG ダウンロードにも対応した共有向けデザインです。 -2. **`// strengths`** — スキャン結果から得た実際の数値でエージェントが既によくできていることを表示(例:クリーンなツール呼び出しの割合、`main` へのプッシュ試行数 `0` 回)。関連ポリシーに問題がない場合のみ表示されます。 -3. **`// quirks`** — 見逃された動作:failproofai が検出できたはずの動作を優先度順に並べたテーブル。*最後に発生した日時*、*何が見逃されたか*(および対応するビルトイン)、*深刻度*、発生頻度(`new` / `recurring` / `N× seen`)が表示されます。 -4. **`// how to improve`** — 推奨修正リスト:コピー&ペースト可能な `failproofai policy add ` コマンドをポリシーごとに 1 行表示。すべての推奨設定を一括で有効化する **install all** ボタンと、適用した場合の**予測スコア**も確認できます。 -5. **`// come back better`** — 習慣を作る:再監査メール**リマインダー**(`3d` / `7d` / `14d` / `30d`)の設定や今すぐ再監査の実行、そして**友人への招待**(failproof.ai から送信、自分に Cc)ができます。リマインダーと招待にはサインインが必要です。[`failproofai auth`](/ja/cli/auth) を参照してください。 +1. **ポスター** — エージェントのアイデンティティを一目で把握:**アーキタイプ**(8種類のうち1つ — `optimist`、`cowboy`、`explorer`、`goldfish`、`paranoid architect`、`precision builder`、`hammer`、`ghost`)、ペルソナキーワード、そのアーキタイプの希少性、そしてティアバンド付きの**0〜100スコア**(`S` から `bottom tier`)。XやLinkedInへの投稿やPNGとしてのダウンロードに対応した共有向けデザイン。 +2. **`// strengths`** — エージェントがすでに得意としていること。スキャンの実際の数値で表示(例:クリーンツールコール%、プッシュ to main 試行 `0` 回)。関連するポリシーに問題がない場合のみ表示。 +3. **`// quirks`** — 見過ごされた行動:failproofaiが検出できたはずの動作の順位付きテーブル。*いつ*最後に発生したか、*何が検出されたか*(および検出したはずのビルトイン)、*深刻度*、*確認頻度*(`new` / `recurring` / `N× seen`)を表示。 +4. **`// how to improve`** — 推奨修正リスト:ポリシーごとにコピペ可能な `failproofai policy add ` が1行で表示され、**すべてインストール**ボタンですべての推奨を一度に有効化できます。実施した場合の**予測スコア**も確認できます。 +5. **`// come back better`** — 習慣を身につける:再監査メール**リマインダー**(`3d` / `7d` / `14d` / `30d`)の設定や今すぐ再監査、**友達を招待**して自分の監査を実行させる(failproof.aiから送信、あなたにCc)。リマインダーと招待にはサインインが必要です。[`failproofai auth`](/ja/cli/auth) を参照してください。 -## 監査専用検出器 +## 監査専用ディテクター -これらはリアルタイムで強制されていない(まだ)「非効率な動作」パターンを検出します。監査時のみ実行され、ライブのツール呼び出しをブロックすることはありません。 +これらはリアルタイムで(まだ)強制されていない「不適切な動作」パターンを検出します。監査時のみ実行され、ライブのツールコールをブロックすることはありません。 -| 検出器 | カウント対象 | +| ディテクター | カウント内容 | |---|---| -| `redundant-cd-cwd` | コマンドはすでに `cwd` で実行されているにもかかわらず、`cd && …` で始まる Bash コマンド。 | -| `prefer-edit-over-read-cat` | 単一のソースファイルへの `cat`/`head`/`tail`/`less`/`more` — `Read` ツールを使用すべき。 | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` によるインプレース編集 — `Edit` ツールを使用すべき。 | -| `prefer-write-over-heredoc` | ヒアドキュメント / 複数行の `echo > file` によるファイル書き込み — `Write` ツールを使用すべき。 | -| `sleep-polling-loop` | 長い `sleep N`(≥ 30 秒)や `while …; sleep …; done` のポーリングループ。 | -| `find-from-root` | `find /`、`find /home`、`find /usr` など — `cwd` にスコープを絞るべき。 | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n` によるフックのスキップ。 | -| `reread-after-edit` | 同一セッション内で `Edit`/`Write` した直後のファイルへの `Read`。 | +| `redundant-cd-cwd` | コマンドがすでに `cwd` で実行されているにもかかわらず `cd && …` で始まるBashコマンド。 | +| `prefer-edit-over-read-cat` | 単一のソースファイルに対する `cat`/`head`/`tail`/`less`/`more` — `Read` ツールを使用してください。 | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` によるインプレース編集 — `Edit` ツールを使用してください。 | +| `prefer-write-over-heredoc` | Heredoc / 複数行の `echo > file` によるファイル書き込み — `Write` ツールを使用してください。 | +| `sleep-polling-loop` | 長い `sleep N`(≥ 30秒)または `while …; sleep …; done` のポーリングループ。 | +| `find-from-root` | `find /`、`find /home`、`find /usr` など — `cwd` にスコープを絞ってください。 | +| `git-commit-no-verify` | フックをスキップする `git commit … --no-verify` / `-n`。 | +| `reread-after-edit` | 同じセッション内で `Edit`/`Write` した直後のファイルへの `Read`。 | ## キャッシュ -- **トランスクリプトごとのキャッシュ** は `~/.failproofai/cache/audit/.json` に保存され、`(mtime, size, engineVersion, detectorVersion)` をキーとしています。トランスクリプトやポリシー・検出器コードが変更されると自動的に無効化されます。各エントリには `cachedAt` タイムスタンプが **TTL メタデータ**として保存されます(キャッシュキーには含まれません)。**7 日**以上経過したエントリは読み込み時に拒否されるため、長期間のキャッシュが検出器の意図の変化に追いつけないという問題を防ぎます。 -- **結果全体のキャッシュ** は `~/.failproofai/audit-dashboard.json`(モード 0600)に保存されます。再実行なしでダッシュボードを即座に表示できます。こちらも **7 日 TTL** を超えると読み込み時に拒否されます。その場合 `/audit` は空の状態に戻り、新しい実行を促します。レポート下部の `[ re-audit now ]` をクリックすると更新できます。再監査は `noCache: true` を送信するため、トランスクリプトごとのキャッシュをバイパスしてすべてのトランスクリプトを再スキャンします(キャッシュ結果は返しません)。実行中はページ上部のスティッキーストリップに進捗が表示され、成功時にはページリロードなしで結果がその場で更新されます(再監査に失敗した場合は以前のレポートが維持されます)。 +- **トランスクリプトごとのキャッシュ**:`~/.failproofai/cache/audit/.json` に保存され、`(mtime, size, engineVersion, detectorVersion)` をキーとします。トランスクリプトまたはポリシー/ディテクターコードが変更されると自動的に無効化されます。各エントリには `cachedAt` タイムスタンプが**TTLメタデータ**として保存されます(キャッシュキーの一部ではありません)。**7日**以上経過したエントリは読み取り時に拒否され、長期間保存された結果がディテクターの進化した意図と乖離しないようにしています。 +- **全体結果キャッシュ**:`~/.failproofai/audit-dashboard.json`(モード0600)に保存されます。再実行なしにダッシュボードのナビゲーションを即座にレンダリングできます。こちらも**7日TTL**を超えると読み取り時に拒否され、`/audit` は空の状態に戻り、新しい実行を促します。レポート下部の `[ re-audit now ]` をクリックして更新できます。再監査は `noCache: true` を送信するため、トランスクリプトごとのキャッシュをバイパスし、キャッシュ結果を返す代わりにすべてのトランスクリプトを再スキャンします。実行はスティッキーなトップストリップで進捗をストリーミングし、成功時にページリロードなしで結果をインプレースで置き換えます(再監査が失敗した場合は前のレポートを保持します)。 ## 注意事項 -- **変更なし。** 監査は読み取り専用モードで再実行されます。`warn-repeated-tool-calls` はセッションごとのサイドカーが変更されてしまうためスキップされます。 -- **ワークフローポリシーのスキップ。** `require-*-before-stop` ポリシーは `Stop` イベント時にのみ発火し、ライブの git 状態に対して `execSync` を実行します。「2025 年に何が起きたか」という文脈では意味のある解釈ができないため、監査カウントには含まれません。 -- **カスタムポリシーのスキップ。** ユーザーが定義したカスタムフックは再実行されません(元のセッション以降に変更された可能性があるため)。 \ No newline at end of file +- **変更なし。** 監査は読み取り専用モードで再生されます。`warn-repeated-tool-calls` は、セッションごとのサイドカーが変更されてしまうためスキップされます。 +- **ワークフローポリシーをスキップ。** `require-*-before-stop` ポリシーは `Stop` イベント時にのみ発火し、ライブのgit状態に対して `execSync` を実行します。「2025年に何が起きたか」という意味のある解釈が存在しないため、監査カウントには表示されません。 +- **カスタムポリシーをスキップ。** ユーザー提供のカスタムフックは再生されません(元のセッション以降に変更されている可能性があるため)。 \ No newline at end of file diff --git a/docs/ja/configuration.mdx b/docs/ja/configuration.mdx index 9c428489..198ea748 100644 --- a/docs/ja/configuration.mdx +++ b/docs/ja/configuration.mdx @@ -1,38 +1,38 @@ --- title: 設定 -description: "設定ファイルのフォーマット、3つのスコープ、マージルール" +description: "設定ファイルのフォーマット、3スコープシステム、およびマージルール" icon: gear --- -failproofai は JSON 設定ファイルを使用して、どのポリシーを有効にするか、それらの動作、カスタムポリシーのロード元を制御します。設定はチームと共有しやすい設計になっています。リポジトリにコミットすれば、すべての開発者が同じエージェントの安全網を利用できます。 +failproofai は JSON 設定ファイルを使用して、どのポリシーを有効にするか、どのように動作させるか、カスタムポリシーをどこから読み込むかを制御します。設定はチームと共有しやすいように設計されています。リポジトリにコミットすれば、すべての開発者が同じエージェント安全網を利用できます。 --- ## 設定スコープ -設定には3つのスコープがあり、優先順位の高い順に評価されます: +設定スコープは優先度順に評価される 3 つがあります: -| スコープ | ファイルパス | 目的 | +| スコープ | ファイルパス | 用途 | |-------|-----------|---------| -| **project** | `.failproofai/policies-config.json` | リポジトリごとの設定。バージョン管理にコミット | -| **local** | `.failproofai/policies-config.local.json` | 個人用のリポジトリごとの上書き設定。gitignore 対象 | +| **project** | `.failproofai/policies-config.json` | リポジトリ単位の設定、バージョン管理にコミット | +| **local** | `.failproofai/policies-config.local.json` | 個人用のリポジトリ単位のオーバーライド、gitignore 済み | | **global** | `~/.failproofai/policies-config.json` | すべてのプロジェクトに適用されるユーザーレベルのデフォルト | -failproofai がフックイベントを受信すると、現在の作業ディレクトリに存在する3つのファイルすべてをロードしてマージします。 +failproofai はフックイベントを受信すると、現在の作業ディレクトリに存在するすべての設定ファイルを読み込んでマージします。 ### マージルール -**`enabledPolicies`** — 3つのスコープの和集合。いずれかのレベルで有効になっているポリシーはアクティブになります。 +**`enabledPolicies`** — 3 つのスコープの和集合。いずれかのレベルで有効化されたポリシーはアクティブになります。 ```text project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← 重複を除いた和集合 +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← 重複排除された和集合 ``` -**`policyParams`** — 特定のポリシーに対してパラメーターを定義した最初のスコープが完全に優先されます。ポリシーのパラメーター内での深いマージは行われません。 +**`policyParams`** — あるポリシーのパラメーターを最初に定義したスコープが全面的に優先されます。ポリシーのパラメーター内での値のディープマージは行われません。 ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } @@ -42,8 +42,8 @@ resolved: { allowPatterns: ["sudo apt-get update"] } ← project が優先、g ``` ```text -project: (block-sudo のエントリなし) -local: (block-sudo のエントリなし) +project: (block-sudo エントリなし) +local: (block-sudo エントリなし) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } resolved: { allowPatterns: ["sudo systemctl status"] } ← global にフォールスルー @@ -100,29 +100,29 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← global にフォー ### `enabledPolicies` -型: `string[]` +型:`string[]` -有効にするポリシー名のリスト。名前は `failproofai policies` で表示されるポリシー識別子と完全に一致する必要があります。完全なリストは[組み込みポリシー](/ja/built-in-policies)を参照してください。 +有効化するポリシー名のリスト。名前は `failproofai policies` で表示されるポリシー識別子と完全に一致する必要があります。完全なリストは[組み込みポリシー](/ja/built-in-policies)を参照してください。 -`enabledPolicies` に含まれていないポリシーは、`policyParams` にエントリがあっても無効です。 +`enabledPolicies` に含まれないポリシーは、`policyParams` にエントリがあっても非アクティブになります。 ### `policyParams` -型: `Record>` +型:`Record>` -ポリシーごとのパラメーター上書き設定。外側のキーはポリシー名、内側のキーはポリシー固有のものです。各ポリシーで使用可能なパラメーターは[組み込みポリシー](/ja/built-in-policies)に記載されています。 +ポリシーごとのパラメーターオーバーライド。外側のキーはポリシー名で、内側のキーはポリシー固有のものです。各ポリシーの利用可能なパラメーターは[組み込みポリシー](/ja/built-in-policies)に記載されています。 -ポリシーにパラメーターがある場合でも指定しなければ、そのポリシーの組み込みデフォルト値が使用されます。`policyParams` を設定しないユーザーは、以前のバージョンと同じ動作になります。 +ポリシーにパラメーターがあっても指定しない場合、ポリシーの組み込みデフォルトが使用されます。`policyParams` をまったく設定しないユーザーは、以前のバージョンと同一の動作になります。 -ポリシーのパラメーターブロック内の未知のキーは、フック実行時には無視されますが、`failproofai policies` を実行すると警告として表示されます。 +ポリシーのパラメーターブロック内の不明なキーは、フック実行時に無視されますが、`failproofai policies` を実行したときに警告としてフラグが立てられます。 -#### `hint`(横断的設定) +#### `hint`(横断的) -型: `string`(省略可能) +型:`string`(省略可能) -ポリシーが `deny` または `instruct` を返す際に、理由として追記されるメッセージです。ポリシー自体を変更せずに Claude へ具体的な指示を伝えるために使用します。 +ポリシーが `deny` または `instruct` を返したときに、その理由に付加されるメッセージ。ポリシー自体を変更せずに Claude へ実行可能なガイダンスを提供するために使用します。 -組み込み、カスタム(`custom/`)、プロジェクト規約(`.failproofai-project/`)、ユーザー規約(`.failproofai-user/`)など、あらゆるポリシータイプで使用できます。 +組み込み、カスタム(`custom/`)、プロジェクト規約(`.failproofai-project/`)、ユーザー規約(`.failproofai-user/`)のあらゆるポリシー型で動作します。 ```json { @@ -141,40 +141,40 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← global にフォー } ``` -`block-force-push` が拒否する場合、Claude には次のように表示されます:*「Force-pushing is blocked. Try creating a fresh branch instead.」* +`block-force-push` が拒否すると、Claude には次のように表示されます:*「Force-pushing is blocked. Try creating a fresh branch instead.」* -文字列以外の値や空文字列は無視されます。`hint` が設定されていない場合は従来の動作と変わりません(後方互換性あり)。 +非文字列値と空文字列は無視されます。`hint` が設定されていない場合、動作は変わりません(後方互換性あり)。 ### `customPoliciesPath` -型: `string`(絶対パス) +型:`string`(絶対パス) カスタムフックポリシーを含む JavaScript ファイルへのパス。`failproofai policies --install --custom ` によって自動的に設定されます(パスは保存前に絶対パスに解決されます)。 -ファイルはフックイベントのたびに再読み込みされます。キャッシュは行われません。作成方法の詳細は[カスタムポリシー](/ja/custom-policies)を参照してください。 +ファイルはフックイベントごとに新たに読み込まれます。キャッシュは行われません。作成方法の詳細は[カスタムポリシー](/ja/custom-policies)を参照してください。 ### 規約ベースのポリシー -明示的な `customPoliciesPath` に加えて、failproofai は `.failproofai/policies/` ディレクトリからポリシーファイルを自動的に検出してロードします: +明示的な `customPoliciesPath` に加え、failproofai は `.failproofai/policies/` ディレクトリからポリシーファイルを自動的に探して読み込みます: | レベル | ディレクトリ | スコープ | |-------|-----------|-------| -| プロジェクト | `.failproofai/policies/` | バージョン管理を通じてチームと共有 | -| ユーザー | `~/.failproofai/policies/` | 個人用。すべてのプロジェクトに適用 | +| プロジェクト | `.failproofai/policies/` | バージョン管理経由でチームと共有 | +| ユーザー | `~/.failproofai/policies/` | 個人用、すべてのプロジェクトに適用 | -**ファイルのマッチング:** `*policies.{js,mjs,ts}` に一致するファイルのみロードされます(例:`security-policies.mjs`、`workflow-policies.js`)。ディレクトリ内のその他のファイルは無視されます。 +**ファイルのマッチング:** `*policies.{js,mjs,ts}` にマッチするファイルのみ読み込まれます(例:`security-policies.mjs`、`workflow-policies.js`)。ディレクトリ内のその他のファイルは無視されます。 -**設定不要:** 規約ポリシーは `policies-config.json` へのエントリが不要です。ディレクトリにファイルを置くだけで、次のフックイベント時に自動的に読み込まれます。 +**設定不要:** 規約ポリシーは `policies-config.json` へのエントリが不要です。ファイルをディレクトリに置くだけで、次のフックイベント時に自動的に検出されます。 -**ユニオンロード:** プロジェクトとユーザーの規約ディレクトリが両方スキャンされます。両方のレベルから一致したすべてのファイルがロードされます(`customPoliciesPath` が最初のスコープ優先なのとは異なります)。 +**ユニオン読み込み:** プロジェクトとユーザーの両方の規約ディレクトリがスキャンされます。両方のレベルのすべてのマッチするファイルが読み込まれます(`customPoliciesPath` が最初のスコープ優先であるのとは異なります)。 -詳細と例は[カスタムポリシー](/ja/custom-policies)を参照してください。 +詳細と例については[カスタムポリシー](/ja/custom-policies)を参照してください。 ### `llm` -型: `object`(省略可能) +型:`object`(省略可能) -AI 呼び出しを行うポリシーのための LLM クライアント設定。ほとんどの環境では不要です。 +AI 呼び出しを行うポリシー用の LLM クライアント設定。ほとんどの場合は不要です。 ```json { @@ -189,20 +189,24 @@ AI 呼び出しを行うポリシーのための LLM クライアント設定。 ## CLI からの設定管理 -`policies --install` および `policies --uninstall` コマンドはエージェント CLI のフック設定ファイル(フックエントリポイント)に書き込みますが、`policies-config.json` は直接管理するファイルです。両者は別々のものです: +`policies --install` および `policies --uninstall` コマンドはエージェント CLI のフック設定ファイル(フックエントリポイント)に書き込みます。一方、`policies-config.json` は直接管理するファイルです。この 2 つは別物です: -- **エージェント CLI の設定** — エージェントがツール使用のたびに `failproofai --hook ` を呼び出すよう指示します: +- **エージェント CLI の設定** — ツール使用のたびにエージェントが `failproofai --hook ` を呼び出すよう指示します: - **Claude Code**: `~/.claude/settings.json`(ユーザー)、`/.claude/settings.json`(プロジェクト)、`/.claude/settings.local.json`(ローカル) - **OpenAI Codex**: `~/.codex/hooks.json`(ユーザー)、`/.codex/hooks.json`(プロジェクト)— Codex には `local` スコープがありません - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json`(ユーザー)、`/.github/hooks/failproofai.json`(プロジェクト)— Copilot には `local` スコープがありません。フックエントリは Copilot の OS キー付き `bash`/`powershell` コマンドフィールドと `timeoutSec` を使用し、ファイルにはトップレベルの `version: 1` マーカーが付きます。`events.jsonl` レコードスキーマ(公開ドキュメントに記載なし)を実際の使用環境で検証中のため、Copilot CLI のサポートは**ベータ版**です。 - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json`(ユーザー)、`/.cursor/hooks.json`(プロジェクト)— Cursor には `local` スコープがありません。フックエントリは Claude 形式の `{type, command, timeout}` を使用しますが、Cursor の[フックスキーマ](https://cursor.com/docs/hooks)に従いキャメルケースのイベントキー(`preToolUse`、`beforeSubmitPrompt` など)のフラット配列として保存され、ファイルにはトップレベルの `version: 1` マーカーが付きます。ハンドラーは `CURSOR_EVENT_MAP` を通じてキャメルケース → PascalCase に正規化するため、既存の組み込みポリシーはそのまま動作します。Cursor のトランスクリプトのオンディスクフォーマット(公開ドキュメントに未記載)を実際の環境で検証中のため、Cursor Agent のサポートは**ベータ版**です。 - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(ユーザー)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(プロジェクト)— OpenCode には `local` スコープがありません。他の6つの CLI とは異なり、OpenCode には**外部コマンドフックシステムがありません**。`opencode.json` の `plugin: []` 配列で明示的に登録された JS/TS プラグインをインプロセスでロードします(`.opencode/plugins/` からの自動検出は opencode v1.14.33 でのプラグインロード方法では**ありません**)。インストール時に小さな生成プラグインシムが配置され、failproofai バイナリをサブプロセスで呼び出し、バイナリの Claude 形式 JSON レスポンスをプラグインセマンティクスに変換します:ツールイベントの deny には `throw new Error()`(ツール呼び出しをキャンセル)、instruct および `Stop` / `SubagentStop` の deny には `client.session.prompt(...)`(deny の理由を次のユーザーメッセージとして送信 — `session.idle` が通知専用で例外をスローしても無効なため、強制リトライの唯一のチャネル)、allow には no-op を使用します。シムはツール名(小文字 → `OPENCODE_TOOL_MAP` を通じた PascalCase)とツール入力引数のキー(`OPENCODE_TOOL_INPUT_MAP` を通じたキャメルケース → スネークケース:`Read` / `Write` / `Edit` の `filePath` → `file_path`、`oldString` → `old_string` など)を正規化してからバイナリに転送するため、`block-read-outside-cwd`、`block-env-files`、`block-secrets-write` などのパスチェック組み込みポリシーは OpenCode のツール呼び出しでもそのまま動作します。セッションは `~/.local/share/opencode/opencode.db` の OpenCode の SQLite DB に保存され、ダッシュボードのセッションビューアーは `opencode db --format json` と `opencode export ` を通じて読み取ります。バージョン間の動作や実際の使用環境での検証中のため、OpenCode のサポートは**ベータ版**です。[OpenCode プラグインドキュメント](https://opencode.ai/docs/plugins/)を参照してください。 - - **Pi _(beta)_**: `~/.pi/agent/settings.json`(ユーザー)、`/.pi/settings.json`(プロジェクト)— Pi には `local` スコープがありません。Pi は起動時に TypeScript 拡張パッケージをロードします。設定ファイルはフラットな文字列配列 `{"packages": ["./relative/path", …]}` です。failproofai はバンドルされた `pi-extension/` ディレクトリを指す単一の packages 配列エントリを書き込みます。拡張機能は内部で Pi の `tool_call` / `user_bash` / `input` / `session_start` イベントを購読し、`failproofai --hook --cli pi` をシェルアウトします。ハンドラーは `PI_EVENT_MAP` を通じてアンダースコア付き小文字スネークケース → PascalCase に正規化するため、既存の組み込みポリシーはそのまま動作します。ツール入力引数も `PI_TOOL_INPUT_MAP` を通じて正規化されます(Pi の Read / Write / Edit は `file_path` ではなく `path` を使用。トップレベルキーのマッピングにより `block-env-files` と `block-secrets-write` が動作します — `block-read-outside-cwd` にはすでに `path` フォールバックがあります)。Pi の拡張 API とセッションログのレイアウトが安定化するまで Pi のサポートは**ベータ版**です。 - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json`(ユーザー)、`/.gemini/settings.json`(プロジェクト)— Gemini には `local` スコープがありません(failproofai が公開していない `/etc/gemini-cli/settings.json` の `system` スコープを文書化しています)。フックエントリは Claude の `{type, command, timeout}` 形式を Gemini の `{matcher, hooks: [...]}` マッチャースキーマでラップし、デフォルトで `matcher: "*"` を使用します。イベントは PascalCase(`SessionStart`、`BeforeAgent`、`AfterAgent`、`BeforeModel`、`AfterModel`、`BeforeToolSelection`、`BeforeTool`、`AfterTool`、`PreCompress`、`Notification`、`SessionEnd`)で、ハンドラーは `GEMINI_EVENT_MAP` を通じて Claude の標準名にマッピングします。ツール名はスネークケース(`run_shell_command`、`read_file`、`write_file`、`replace` など)で、ハンドラーは `GEMINI_TOOL_MAP` を通じて正規化するため、既存の組み込みポリシーはそのまま動作します。ポリシー評価器は Gemini のフラットな `{decision: "deny", reason}` 形式(Gemini の「ゴールデンルール」exit-0 契約に基づく推奨)、BeforeAgent / AfterTool / SessionStart でのコンテキスト注入用 `{hookSpecificOutput: {hookEventName, additionalContext}}`、AfterAgent での強制リトライセマンティクス用 `{decision: "block", reason}` を出力します。実際の使用環境でのカバレッジを拡大中のため、Gemini CLI のサポートは**ベータ版**です。[Gemini CLI フックドキュメント](https://geminicli.com/docs/hooks/)を参照してください。 - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml`(**ユーザースコープのみ** — Hermes にはプロジェクト/ローカル設定がありません)。Hermes は Slack/Telegram の**ゲートウェイ**であるため、1回のインストールでSlack/Telegram/cli/cron など全プラットフォームからのツール呼び出しと内部サブエージェントを傍受します。フックエントリは Hermes のスネークケースイベント(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`)をキーとする `hooks:` マップ下の `{command, timeout}` ペア(タイムアウトは**秒**単位)です。ハンドラーは `HERMES_EVENT_MAP` でイベントを、`HERMES_TOOL_MAP` でツール名を正規化するため、組み込みポリシーはそのまま動作します。設定はコメントを保持する YAML `Document` のラウンドトリップで編集されるため、オペレーターの他の設定は保持されます。インストール時に `hooks_auto_accept: true` が設定されるため、ヘッドレスゲートウェイ(TTY なし)は同意プロンプトなしでフックを実行します。評価器は Hermes の `{"decision":"block","reason"}` stdout 契約を出力します(Hermes は終了コードを無視)。**制限事項:** Hermes にはターン終了の `Stop` イベントがないため、`require-*-before-stop` 組み込みポリシーは動作しません(非適用、バグではありません)。`instruct` は allow-with-logged-note に降格します(追加コンテキストチャネルなし)。出力シークレットのリダクション(`sanitize-*`)はシェルフックの契約上ツール出力を書き換えられません。Hermes は**オフライン監査**ソースでもあり、ダッシュボードはゲートウェイセッションを `~/.hermes/state.db` から直接読み取ります。 -- **`policies-config.json`** — failproofai が評価するポリシーとそのパラメーターを指定します(すべてのエージェント CLI で共有) - -特定のエージェントを対象にするには `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` を渡します(スペース区切りまたは繰り返しで複数指定可能): + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json`(ユーザー)、`/.github/hooks/failproofai.json`(プロジェクト)— Copilot には `local` スコープがありません。フックエントリは Copilot の OS キー付き `bash`/`powershell` コマンドフィールドと `timeoutSec` を使用し、ファイルにはトップレベルの `version: 1` マーカーが含まれます。Copilot CLI サポートは**ベータ**です。公開ドキュメントに仕様が記載されていない `events.jsonl` レコードスキーマを、より多くの実際のセッションで検証中です。**VS Code Copilot Chat エージェントモード(Preview)**は `.github/hooks/*.json`、`~/.copilot/hooks/*.json`、`~/.claude/settings.json` からフック設定を読み込み(`chat.hookFilesLocations` 設定によって制御)、同じ Claude 形式の `{hookSpecificOutput:{permissionDecision:"deny",…}}` コントラクトを使用します。これらのパスは `copilot` インテグレーションと `claude` インテグレーション(`~/.claude/settings.json`)がすでに書き込むパスと同じです。そのため `failproofai policies --install --cli copilot`(または `--cli claude`)は、**別途 `vscode` インテグレーションを用意することなく、VS Code エージェントモードですでに適用されます**(VS Code のディスカバリーログから動作確認済み)。 + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json`(ユーザー)、`/.cursor/hooks.json`(プロジェクト)— Cursor には `local` スコープがありません。フックエントリは Claude 形式の `{type, command, timeout}` を使用します(`bash`/`powershell` の分割なし)。ただし Cursor の[フックスキーマ](https://cursor.com/docs/hooks)に従い、キャメルケースのイベントキー(`preToolUse`、`beforeSubmitPrompt` など)の配列としてフラットに格納されます。ファイルにはトップレベルの `version: 1` マーカーが含まれます。ハンドラーは `CURSOR_EVENT_MAP` を使用してキャメルケースをパスカルケースに正規化するため、既存の組み込みポリシーは変更なく動作します。Cursor Agent サポートは**ベータ**です。Cursor のトランスクリプトのディスク上フォーマット(公開ドキュメントに仕様なし)を、より多くの実際のインストールで検証中です。 + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(ユーザー)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(プロジェクト)— OpenCode には `local` スコープがありません。他の 5 つの CLI とは異なり、OpenCode には**外部コマンドフックシステムがありません**。OpenCode は `opencode.json` の `plugin: []` 配列に明示的に登録されたインプロセス JS/TS プラグインを読み込みます(`.opencode/plugins/` からの自動検出は opencode v1.14.33 でのプラグイン読み込み方法では**ありません**)。インストール時に、failproofai バイナリをサブプロセスで呼び出し、バイナリの Claude 形式 JSON レスポンスをプラグインセマンティクスに変換する小さなプラグインシムを生成して配置します:ツールイベントの deny には `throw new Error()`(ツール呼び出しをキャンセル)、instruct および `Stop` / `SubagentStop` の deny には `client.session.prompt(...)`(deny の理由を次のユーザーメッセージとして送信 — `session.idle` は通知専用でそこから throw しても no-op であるため、これが唯一の強制リトライチャネル)、allow には no-op を使用します。シムはツール名(小文字 → `OPENCODE_TOOL_MAP` 経由でパスカルケース)とツール入力の引数キー(`OPENCODE_TOOL_INPUT_MAP` 経由でキャメルケース → スネークケース、`Read` / `Write` / `Edit` の `filePath` → `file_path`、`oldString` → `old_string` など)をバイナリに転送する前に正規化するため、`block-read-outside-cwd`、`block-env-files`、`block-secrets-write` などのパスチェック組み込みポリシーは OpenCode のツール呼び出しでも変更なく動作します。セッションは opencode の SQLite DB(`~/.local/share/opencode/opencode.db`)に保存され、ダッシュボードのセッションビューアーは `opencode db --format json` と `opencode export ` を使用して読み込みます。OpenCode サポートは**ベータ**です。バージョン間の動作と実際のセッションでの動作を検証中です。[OpenCode プラグインドキュメント](https://opencode.ai/docs/plugins/)も参照してください。 + - **Pi _(beta)_**: `~/.pi/agent/settings.json`(ユーザー)、`/.pi/settings.json`(プロジェクト)— Pi には `local` スコープがありません。Pi は起動時に TypeScript 拡張パッケージを読み込みます。設定ファイルはフラットな文字列配列 `{"packages": ["./relative/path", …]}` です。failproofai はバンドルされた `pi-extension/` ディレクトリを指す単一の packages 配列エントリを書き込みます。拡張機能は内部で Pi の `tool_call` / `user_bash` / `input` / `session_start` イベントにサブスクライブし、`failproofai --hook --cli pi` をシェルアウトします。ハンドラーは `PI_EVENT_MAP` を使用してアンダースコア小文字スネークケース → パスカルケースに正規化するため、既存の組み込みポリシーは変更なく動作します。ツール入力引数も `PI_TOOL_INPUT_MAP` 経由で正規化されます(Pi の Read / Write / Edit は `file_path` ではなく `path` を使用。トップレベルキーをマッピングすることで `block-env-files` と `block-secrets-write` が動作するようになります — `block-read-outside-cwd` にはすでに `path` のフォールバックがありました)。Pi サポートは**ベータ**です。Pi の拡張機能 API とセッションログのレイアウトが安定するまでの間です。 + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml`(**ユーザースコープのみ** — Hermes にはプロジェクト/ローカル設定がありません)。Hermes は Slack/Telegram **ゲートウェイ**であるため、1 回のインストールですべてのプラットフォーム(Slack/Telegram/cli/cron)**および**内部サブエージェントからのツール呼び出しをインターセプトします。フックエントリは Hermes のスネークケースイベント(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`)をキーとする `hooks:` マップの下に `{command, timeout}` ペア(タイムアウトは**秒**単位)として格納されます。ハンドラーは `HERMES_EVENT_MAP` でイベントを、`HERMES_TOOL_MAP` でツール名を正規化するため、組み込みポリシーは変更なく動作します。設定はコメント保持の YAML `Document` ラウンドトリップで編集されるため、オペレーターの他の設定が維持されます。また、インストール時に `hooks_auto_accept: true` が設定されるため、ヘッドレスゲートウェイ(TTY なし)は同意プロンプトなしでフックを実行します。エバリュエーターは Hermes の `{"decision":"block","reason"}` stdout コントラクトを出力します(Hermes は終了コードを無視します)。**制限事項:** Hermes にはターン終了の `Stop` イベントがないため、`require-*-before-stop` 組み込みポリシーは動作しません(適用不可であり、壊れているわけではありません)。`instruct` は allow-with-logged-note にデグレードします(追加コンテキストチャネルなし)。また出力シークレットのリダクション(`sanitize-*`)はシェルフックコントラクト経由でツール出力を書き換えできません。Hermes は**オフライン監査**ソースでもあります — ダッシュボードは `~/.hermes/state.db` からゲートウェイセッションを直接読み込みます。 + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json`(**ユーザースコープのみ** — OpenClaw にはプロジェクト/ローカル設定がありません)。Hermes と同様に、OpenClaw はセルフホスト型のマルチチャネル**ゲートウェイ**であるため、1 回のインストールですべてのチャネルとその内部サブエージェントからのツール呼び出しをインターセプトします。適用は OpenClaw の**インプロセスプラグインフック**を通じて行われます(ファイルベースの内部フックは観察専用でブロックできません)。そのため OpenCode/Pi と同様に、failproofai は静的な `openclaw-plugin/` パッケージを同梱しており、failproofai バイナリを非同期でスポーンして評決を変換します。インストール時に `openclaw.json` の `plugins.load.paths[]` に同梱プラグインディレクトリを登録し、`plugins.entries.failproofai` の下で有効化します(生の会話フックに必要な `hooks.allowConversationAccess: true` を含む)。エバリュエーターはフラットな `{permission, reason}` 評決を出力し、シムはそれを各フックのネイティブ戻り形式にマッピングします:`before_tool_call → {block:true, blockReason}`(**PreToolUse**)、`before_agent_run → {outcome:"block", reason}`(**UserPromptSubmit**)、`before_agent_finalize → {action:"revise", reason}`(**Stop** — 本物のターン終了ゲートであるため、`require-*-before-stop` 組み込みポリシーは Hermes とは異なり OpenClaw で**適用されます**)。イベントとツール名はバイナリ側で `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP`(`exec→Bash`、`read→Read` など)を使用して正規化されるため、組み込みポリシーは変更なく動作します。シムはスポーン/パース/タイムアウトエラー時にはフェイルオープンします。OpenClaw は**オフライン監査**ソースでもあります — ダッシュボードは `~/.openclaw/agents//sessions/.jsonl` の JSONL セッションを読み込みます。 + - **Factory Droid (`droid`)**: `~/.factory/hooks.json`(ユーザー)、`/.factory/hooks.json`(プロジェクト)— Factory には `local` スコープがありません。droid は Claude スタイルの外部コマンドフックシステムを搭載していますが、droid v0.171.0 で実際に確認された 2 つの特殊性があります:(1) イベント名は `hooks.json` の**トップレベル**に配置されます — **`"hooks"` ラッパーはありません**(droid はそれを拒否します)。ツールイベント(`PreToolUse`/`PostToolUse`)は `"matcher": "*"` を持ち、非ツールイベントにはそれがありません。(2) Deny は JSON による決定ではなく、フックの**終了コード 2 + stderr** によって駆動されます — エバリュエーターの `factory` ブランチはツール/プロンプトイベントで終了コード 2 を返し、ターン終了の `Stop` イベント(droid の唯一の強制リトライチャネル)でのみ `{decision:"block", reason}` を返します。イベントはすでにパスカルケースであり(イベントマップなし)、ペイロードは Claude スネークケースです。ツール名のみ `FACTORY_TOOL_MAP`(`Execute→Bash`、`Create→Write`、`FetchUrl→WebFetch` など)で正規化されます。Factory は**オフライン監査**ソースでもあります — ダッシュボードは `~/.factory/sessions//.jsonl` のオンディスク JSONL セッションを読み込みます。 + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json`(ユーザー)、`/.devin/config.json`(プロジェクト)— Devin には `local` スコープがありません。Devin は devin v3000.1.27 で実際に確認された**純粋な Claude クローン**です。標準の Claude `"hooks"` ラッパースキーマを使用し(書き込みはマージ保持であるため、設定ファイルの他のキー — `org_id`、`theme_mode` など — が維持されます)、すでにパスカルケースのイベント名(イベントマップなし、ハンドラーブランチなし)、Claude スネークケースの stdin ペイロード(正規化なし)を使用します。エバリュエーターの `devin` ブランチはすべてのイベントで終了コード 0 で `{"decision":"block","reason"}` JSON を stdout に出力して deny します(確認済み — block は `--permission-mode dangerous` をオーバーライドしました)。ターン終了の `Stop` イベントでは、`require-*-before-stop` 組み込みポリシーが適用されるよう、理由に MANDATORY-ACTION の強制リトライ文言が含まれます。ツール名のみ `DEVIN_TOOL_MAP`(`exec→Bash`;`tool_input.command` はすでに正規化済み)で正規化されます。Devin は**オフライン監査**ソースでもあります — ダッシュボードは `~/.local/share/devin/cli/sessions.db` の SQLite セッションを読み込みます(各 `sessions` 行には実際の `working_directory` があるため、Claude と同様にプロジェクトの cwd でセッションをグループ化できます)。 + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json`(ユーザー)、`/.agents/hooks.json`(プロジェクト)— Antigravity には `local` スコープがありません。Factory/Devin とは異なり、Antigravity は agy v1.1.2 で実際に確認された**独自の**コントラクトを持っています(Claude クローンではありません)。`hooks.json` は**名前付きフック**スキーマを使用します。トップレベルのキーはフックの*名前*(`"failproofai"`)で、その値はイベント→ハンドラーのマップです — ツールイベント(`PreToolUse`/`PostToolUse`)はハンドラーを `{matcher:"*", hooks:[…]}` でラップし、`PreInvocation`/`Stop` は**フラット**なハンドラー配列です(他の名前付きフックは保持されます)。stdin ペイロードは**キャメルケースの protojson**(`toolCall:{name,args}`、`conversationId`、`workspacePaths`、`transcriptPath`)です — failproofai はポリシー実行前にスネークケースに正規化し、`run_command` のパスカルケース引数(`CommandLine`/`Cwd`)を `ANTIGRAVITY_TOOL_INPUT_MAP` 経由でマッピングします。エバリュエーターの `antigravity` ブランチは Antigravity**独自の**レスポンス形式を使用します:`{decision:"deny", reason}` でツール/プロンプトをブロック(終了コード 0)、ターン終了の `Stop` で `{decision:"continue", reason}` を返すとループが再開(`require-*-before-stop` 組み込みポリシーが適用されます)、`PreInvocation`(→ `UserPromptSubmit`)では `{injectSteps:[{ephemeralMessage}]}` でインストラクションを挿入します。ツール名は `ANTIGRAVITY_TOOL_MAP`(`run_command→Bash`、`view_file→Read` など)で正規化されます。Antigravity は**オフライン監査**ソースでもあります — ダッシュボードは `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` のプレーン JSONL トランスクリプトを読み込みます(会話のインデックスは `conversation_summaries.db`)。 + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json`(ユーザー)、`/.agents/plugins/failproofai/hooks/hooks.json`(プロジェクト)— Goose には `local` スコープがありません。適用は Goose の**フック**システム、クロスエージェントの **Open Plugins** 仕様を使用します。インストーラーは `failproofai` プラグインディレクトリを配置するだけで、Goose は起動時にそれを自動検出して `~/.config/goose/config.yaml` に自己登録します。`hooks.json` はトップレベルの `"hooks"` ラッパーを持つ Open Plugins スキーマを使用し、すべてのイベントでマッチャーが**省略されます** — 単純な `"*"` は何もマッチしない無効な正規表現です(goose v1.43.0 で実際に確認済み)。イベント名はすでにパスカルケースです(イベントマップなし)。stdin ペイロードは `event`/`working_dir` を使用しており、ハンドラーはそれを `hook_event_name`/`cwd` に正規化します。エバリュエーターの `goose` ブランチは終了コード 0 で `{"decision":"block","reason"}` JSON を stdout に出力して deny しますが、**`PreToolUse`** イベント(goose ≥ v1.37.0 で搭載)でのみ有効です — これはシェルツール**と委任されたサブエージェント内**の両方で動作するため、単一の十分な deny ポイントです。その他のフックエラーは**フェイルオープン**します。Goose には**`Stop` イベントがない**ため、`require-*-before-stop` 組み込みポリシーは適用されません(Hermes と同様)。ツール名は `GOOSE_TOOL_MAP`(`shell→Bash`、`write→Write`、`todo__todo_write→TodoWrite` など)で、パスキーは `GOOSE_TOOL_INPUT_MAP`(`path`/`source` → `file_path`)で正規化されます。Goose は**オフライン監査**ソースでもあります — ダッシュボードは `~/.local/share/goose/sessions/sessions.db` の SQLite セッションを読み込みます(各 `sessions` 行には実際の `working_dir` があるため、Devin と同様にプロジェクトの cwd でセッションをグループ化できます。`--no-session` の一時実行はフィルタリングされます)。 +- **`policies-config.json`** — どのポリシーを評価するか、どのパラメーターで評価するかを failproofai に伝えます(すべてのエージェント CLI で共有) + +特定のエージェントを対象にするには `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` を渡します(スペース区切りまたは繰り返しで任意のサブセットを指定): ```bash failproofai policies --install --cli codex --scope project @@ -210,19 +214,23 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -`--cli` を省略すると、`failproofai` はインストール済みのエージェント CLI を自動検出します(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli` を省略した場合、`failproofai` はどのエージェント CLI がインストールされているかを検出します(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **CLI が1つ検出された場合** — プロンプトなしでその CLI を自動選択します。 -- **複数の CLI が検出され、インタラクティブターミナルの場合** — `Detected (N)` セクション(`Install for all N detected` の集約行と検出された各 CLI)と `Not installed (M) · install hooks ahead of time` セクション(検出されなかったサポート対象 CLI を前もってインストールするオプションとして一覧表示)にグループ化された矢印キー操作の単一選択プロンプトを表示します(↑↓で移動、Enterで選択、^Cで終了)。アンインストールフローでは Detected セクションのみ表示されます。 -- **複数の CLI が検出され、非インタラクティブ実行(CI、TTY なし)の場合** — プロンプトなしですべての検出された CLI にインストールします。 -- **何も検出されない場合** — エージェントバイナリが PATH に見つからないという警告とともに `claude` にフォールバックします。フックコマンドは書き込まれるため、インストール後すぐに有効になります。 +- **1 つの CLI を検出** — プロンプトなしでその CLI を自動選択します。 +- **複数の CLI を検出**(インタラクティブターミナル)— `検出済み (N)` セクション(`N 件すべてにインストール` の集約行と各検出済み CLI を個別に表示)と `未インストール (M) · 事前にフックをインストール` セクション(サポートされているが未検出の CLI をすべて先行インストールオプションとして一覧表示)に分類された矢印キーによる単一選択プロンプトを表示します(↑↓で移動、Enter で選択、^C で終了)。アンインストールフローには検出済みセクションのみが表示されます。 +- **複数の CLI を検出**(非インタラクティブ実行、TTY なし)— プロンプトなしで検出されたすべての CLI にインストールします。 +- **何も検出されない** — `claude` にフォールバックし、PATH にエージェントバイナリが見つからなかった旨の警告を表示します。フックコマンドは書き込まれるため、インストール後すぐにアクティブになります。 -`policies-config.json` はいつでも直接編集できます。変更は次のフックイベント時に即座に反映され、再起動は不要です。 +`policies-config.json` はいつでも直接編集できます。変更は再起動不要で次のフックイベント時に即座に反映されます。 --- @@ -247,4 +255,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -各開発者はチームメートに影響を与えることなく個人用の上書き設定として `.failproofai/policies-config.local.json`(gitignore 対象)を作成できます。 \ No newline at end of file +各開発者はチームメンバーに影響を与えることなく個人的なオーバーライドのために `.failproofai/policies-config.local.json`(gitignore 済み)を作成できます。 \ No newline at end of file diff --git a/docs/ja/dashboard.mdx b/docs/ja/dashboard.mdx index 5462eed4..bef4de40 100644 --- a/docs/ja/dashboard.mdx +++ b/docs/ja/dashboard.mdx @@ -1,10 +1,10 @@ --- title: ダッシュボード -description: "エージェントセッションの監視、ツールコールの確認、ポリシーの管理" +description: "エージェントセッションの監視、ツール呼び出しの確認、ポリシーの管理" icon: chart-line --- -failproofai ダッシュボードは、AIエージェントセッションの監視とポリシー管理のためのローカルWebアプリケーションです。作業中にエージェントが何を行ったかを確認できます。 +failproofai ダッシュボードは、AI エージェントセッションの監視とポリシー管理を行うローカル Web アプリケーションです。あなたが席を外している間にエージェントが行った操作を確認できます。 --- @@ -16,75 +16,75 @@ failproofai `http://localhost:8020` で開きます。 -ダッシュボードはファイルシステムから直接読み取ります — Claude Code のプロジェクトフォルダと failproofai の設定ファイルを参照します。リモートサービスへの書き込みは一切行われません。 +ダッシュボードはファイルシステムから直接読み込みます — Claude Code のプロジェクトフォルダーと failproofai の設定ファイルが対象です。リモートサービスへの書き込みは一切行いません。 --- -## ページ一覧 +## ページ ### プロジェクト -マシン上で見つかったすべての Claude Code、OpenAI Codex、GitHub Copilot CLI _(ベータ)_、Cursor Agent _(ベータ)_、OpenCode _(ベータ)_、Pi _(ベータ)_、Gemini CLI _(ベータ)_、および Hermes プロジェクトを一覧表示します。Claude プロジェクトは `~/.claude/projects/`(または `CLAUDE_PROJECTS_PATH` で設定されたパス)から検出されます。Codex プロジェクトは `~/.codex/sessions///
/*.jsonl` 以下のすべてのトランスクリプトをスキャンし、各セッションの最初のレコードに記録された `cwd` でグループ化することで検出されます。Copilot CLI プロジェクトは各 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME` で設定可能)をスキャンし、`cwd` フィールドでグループ化することで検出されます。Cursor Agent プロジェクトは `~/.cursor/agent-sessions//`(`CURSOR_HOME` で設定可能。`conversations/` と `sessions/` をフォールバックとして探索)以下のセッションごとのメタデータをスキャンし、`meta.json` / `session.json` / `workspace.yaml` 内の `cwd` スカラーから検出されます。OpenCode プロジェクトは `opencode db --format json` を通じて `~/.local/share/opencode/opencode.db` の SQLite DB を照会することで検出されます(`session` テーブルと `project` テーブルを読み取り、`project_id` でグループ化)。Pi プロジェクトは `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR` で設定可能)以下のセッションごとの JSONL トランスクリプトをスキャンし、各セッションの最初のレコードから `cwd` を取得することで検出されます。Gemini CLI プロジェクトは `~/.gemini/tmp//chats/session--.jsonl`(`GEMINI_SESSIONS_DIR` で設定可能)をスキャンし、隣接する `.project_root` テキストマーカーから正規の cwd を復元することで検出されます。Hermes ゲートウェイセッションは `~/.hermes/state.db`(`HERMES_DB_PATH` で設定可能)の SQLite ストアから直接読み取られ、`source`(Slack/Telegram/cli/cron — ゲートウェイセッションには cwd がありません)によって `hermes-` プロジェクトにグループ化されます。複数の CLI で使用されたプロジェクトは、該当するすべてのバッジを付けた1行として表示されます。テーブル上部の **CLI** ドロップダウンを使用して特定のエージェント CLI でフィルタリングできます。URLには選択内容が `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` として保持されます。 +マシン上で見つかったすべての Claude Code、OpenAI Codex、GitHub Copilot CLI _(ベータ)_、Cursor Agent _(ベータ)_、OpenCode _(ベータ)_、Pi _(ベータ)_、Hermes、OpenClaw、Factory Droid、Devin、Antigravity、Goose のプロジェクトを一覧表示します。Claude プロジェクトは `~/.claude/projects/`(または `CLAUDE_PROJECTS_PATH` で設定されたパス)から検出されます。Codex プロジェクトは `~/.codex/sessions///
/*.jsonl` 配下のすべてのトランスクリプトをスキャンし、各セッションの最初のレコードに記録された `cwd` でグループ化して検出されます。Copilot CLI プロジェクトは各 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME` で変更可能)をスキャンし、`cwd` フィールドでグループ化して検出されます。Cursor Agent プロジェクトは `~/.cursor/agent-sessions//`(`CURSOR_HOME` で変更可能。フォールバックとして `conversations/` と `sessions/` も探索)配下のセッションごとのメタデータから `meta.json` / `session.json` / `workspace.yaml` 内の `cwd` スカラーを検索して検出されます。OpenCode プロジェクトは `~/.local/share/opencode/opencode.db` の SQLite DB を `opencode db --format json` 経由でクエリして検出されます(`session` テーブルと `project` テーブルを読み取り、`project_id` でグループ化)。Pi プロジェクトは `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR` で変更可能)配下のセッションごとの JSONL トランスクリプトをスキャンし、各セッションの最初のレコードから `cwd` を取得して検出されます。Hermes ゲートウェイセッションは `~/.hermes/state.db`(`HERMES_DB_PATH` で変更可能)の SQLite ストアから直接読み取り、`source`(Slack / Telegram / cli / cron — ゲートウェイセッションには cwd がありません)ごとに `hermes-` プロジェクトとしてグループ化されます。OpenClaw ゲートウェイセッションは `~/.openclaw/agents//sessions/*.jsonl` から読み取られ、`openclaw-` プロジェクトにグループ化されます(こちらも cwd なし)。Factory Droid プロジェクトは `~/.factory/sessions//*.jsonl` の JSONL トランスクリプトから検出され、cwd でグループ化されます。Devin プロジェクトは `~/.local/share/devin/cli/sessions.db` の SQLite DB から(各セッションの `working_directory` でグループ化)、Antigravity プロジェクトは `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` の JSONL トランスクリプトから cwd でグループ化して、Goose プロジェクトは `~/.local/share/goose/sessions/sessions.db` の SQLite DB から(各セッションの `working_dir` でグループ化)それぞれ検出されます。複数の CLI で使用されたプロジェクトは、すべてのバッジが付いた単一の行として表示されます。テーブル上部の **CLI** ドロップダウンで特定のエージェント CLI に絞り込むことができます。URL は選択内容を `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` として保持します。 各プロジェクトには以下が表示されます: -- プロジェクト名(フォルダパスから導出) -- CLI バッジ — `Claude Code`(オレンジ)、`OpenAI Codex`(パープル)、`GitHub Copilot`(ブルー)、`Cursor Agent`(エメラルド)、`OpenCode`(アンバー)、`Pi`(ピンク)、`Gemini CLI`(スカイ)、および/または `Hermes`(インディゴ) -- 最新のセッションアクティビティの日付 +- プロジェクト名(フォルダーパスから導出) +- CLI バッジ — `Claude Code`(オレンジ)、`OpenAI Codex`(パープル)、`GitHub Copilot`(ブルー)、`Cursor Agent`(エメラルド)、`OpenCode`(アンバー)、`Pi`(ピンク)、`Hermes`(インディゴ) +- 最新セッションのアクティビティ日時 -プロジェクトをクリックするとそのセッションが表示されます。 +プロジェクトをクリックすると、そのセッション一覧が表示されます。 ### セッション プロジェクト内のすべてのセッションを一覧表示します。各セッションには以下が表示されます: - セッション ID - 開始・終了タイムスタンプ -- ツールコール数 -- フックアクティビティ数(発動したポリシー) +- ツール呼び出し回数 +- フックアクティビティ数(発火したポリシーの数) -日付範囲フィルターとセッション ID 検索でリストを絞り込めます。セッションはページ分割されます。 +日付範囲フィルターとセッション ID 検索で絞り込みができます。セッションはページネーションで表示されます。 -セッションをクリックするとセッションビューアーが開きます。 +セッションをクリックすると、セッションビューアーが開きます。 ### セッションビューアー -セッションビューアーは、自律エージェントにとっての核心的な問いに答えます:エージェントは何を行い、正しく動作していたか?ヘッダー横の CLI バッジは、セッションが Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI、または Hermes のトランスクリプトであるかを示します。セッション内で起きたすべてのことのタイムラインが表示されます: +セッションビューアーは、自律エージェントにとって重要な問いに答えます:エージェントは何をしたか、そして正しい方向に進んでいたか?ヘッダーの横の CLI バッジは、そのセッションが Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Hermes、OpenClaw、Factory Droid、Devin、Antigravity、Goose のいずれのトランスクリプトかを示します。セッション内で発生したすべての出来事のタイムラインが表示されます: -- **メッセージ** - Claude のテキスト応答とユーザープロンプト -- **ツールコール** - Claude が呼び出したすべてのツール(入力と出力を含む) -- **ポリシーアクティビティ** - 各ツールコールに対して発動したポリシーとその判定結果 +- **メッセージ** — Claude のテキスト応答とユーザープロンプト +- **ツール呼び出し** — Claude が呼び出したすべてのツール(入力と出力を含む) +- **ポリシーアクティビティ** — 各ツール呼び出しに対して、どのポリシーが発火し、どのような判断を返したか -上部のステータスバーには、セッション時間、総ツールコール数、フック判定のサマリー(allow / deny / instruct の件数)が表示されます。 +上部のスタッツバーには、セッション時間、総ツール呼び出し数、フック判断のサマリー(allow / deny / instruct の件数)が表示されます。 -**ログをダウンロード** ボタンをクリックするとセッションをエクスポートできます。Claude Code、Codex、Copilot、Cursor、Pi、Gemini のセッションはディスク上の JSONL トランスクリプトをバイト単位でそのまま取得できます。OpenCode(セッションがディスク上ではなく SQLite に保存されている)の場合は、基礎となる `session` / `messages` / `parts` テーブルを反映した JSON ドキュメントが取得されます。 +**ログをダウンロード** ボタンをクリックすると、セッションをエクスポートできます。Claude Code、Codex、Copilot、Cursor、Pi のセッションはディスク上の JSONL トランスクリプトをバイト単位でそのまま取得できます。OpenCode(セッションがディスクではなく SQLite に保存されている)の場合は、`session` / `messages` / `parts` テーブルを反映した JSON ドキュメントが取得されます。 ### 監査 -過去のセッション全体でエージェントが実際にどのように行動していたかを個性的なレポートとして表示します。`failproofai audit` CLI と同じスキャンを実行し、1画面で共有可能なポスターと4つの折り畳みセクションとして表示します: +過去のセッション全体を通じたエージェントの実際の行動を、個性的なレポートとして表示します。`failproofai audit` CLI と同じスキャンを実行しますが、1 画面で共有可能なポスター+4 つの追加セクションとしてレンダリングされます: -1. **ポスター** — 最初のビューポートを埋めます。failproof_ai のワードマーク + 監査ラベル · アーキタイプインデックス(`№ NN of 08`)+ 監査日 · 数値スコア(0〜100)+ パーセンタイルランクピル(`top 15%`)· アーキタイプ名(`the optimist`、`the cowboy`、`the explorer`、`the goldfish`、`the paranoid architect`、`the precision builder`、`the hammer`、`the ghost` のいずれか)+ 3キーワードストリップ · `// only N% of agents are this archetype` レアリティライン · 8×8ピクセルのシジルタイル · `audit yours → failproof.ai` フッターを含む自己完結型の PNG キャプチャ領域。3つの共有ボタンがキャプチャボックスのすぐ外に配置されます:`post your archetype`(X インテント)、`share on linkedin`、`download poster`。キャプチャは `html-to-image` を通じて実行されるため、PNG は画面上のレンダリングとピクセル単位で一致します(破線の境界線、SVG ロゴマスク、グラデーション、フォントメトリクス — すべて保持)。 -2. **強み** — エージェントがすでに正しく行っている動作の穏やかな ✓ 行リスト。ライブ監査データから導出されます(クリーンなツールコール率、main への直接プッシュなし、認証情報の漏洩ゼロ、リトライストームなし)— 監査ウィンドウ全体でクリーンな記録を持つポリシーに関連するもののみ表示されます。 -3. **問題点** — 見逃された内容を深刻度順にランク付けしたテーブル:`いつ · 何が漏れたか + それを検出したはずのポリシー · 深刻度ピル · 発生回数`。再発回数は `new`(1回)、`N× seen`(2〜9回)、`recurring`(10回以上)と表示されます。 -4. **改善方法** — 推奨ポリシーごとの穏やかな行リスト:白いポリシー名、1行の説明、右側にインストールコマンド + コピーボタン。セクションヘッダーには `enable all N → projected · `(すべての修正を適用した場合のスコア)が表示され、`[install all]` ボタンは推奨されるすべてのポリシーの `failproofai policy add a b c …` コマンドをコピーします。 -5. **より良い状態で戻ろう** — 2つの横並びカード。左:リマインダーの設定(`3d` / `7d` / `14d` / `30d` の頻度ピッカー。認証後 `/api/auth/reminder` を通じて永続化)。右:failproof の特典を解放 — `invite a friend` はコンマ/スペース/改行区切りの友人のメールアドレスリスト(1回の送信で最大10件)を受け取るモーダルを開き、`/api/audit/invite` に POST します。このエンドポイントは api-server の `POST /v0/invite` に転送します。api-server は `invite@failproof.ai` から各受信者に1通のメールを送信し、送信者を Cc に追加して `Reply-To` を設定するため、受信者は誰が招待したかがわかり、送信者も受信トレイにコピーが届きます。匿名ユーザーは、招待前に送信者のメールアドレスを確認するために `AuthDialog` に誘導されます。権利付与 / 特典の履行は今後対応予定です。 +1. **ポスター** — 最初のビューポートいっぱいに表示されます。failproof_ai ワードマーク+監査ラベル・アーキタイプインデックス(`№ NN of 08`)+監査日・数値スコア(0〜100)+パーセンタイルランクピル(`top 15%`)・アーキタイプ名(`the optimist`、`the cowboy`、`the explorer`、`the goldfish`、`the paranoid architect`、`the precision builder`、`the hammer`、`the ghost` のいずれか)+3 キーワードストリップ・`// only N% of agents are this archetype` レアリティライン・8×8 ピクセルのシジルタイル・`audit yours → failproof.ai` フッターを含む、独立した PNG キャプチャ領域です。キャプチャボックスのすぐ外側に 3 つのシェアボタンがあります:`post your archetype`(X インテント)、`share on linkedin`、`download poster`。キャプチャは `html-to-image` で実行されるため、PNG は画面上のレンダリングとピクセル単位で一致します(破線ボーダー、SVG ロゴマスク、グラデーション、フォントメトリクスすべて保持)。 +2. **長所** — エージェントがすでに正しく行っている動作を落ち着いた ✓ リストで表示します。ライブ監査データ(クリーンなツール呼び出し率、main への直接プッシュなし、認証情報の漏洩ゼロ、リトライストームゼロ)から導出され、監査ウィンドウ全体で関連ポリシーがクリーンな記録を持つ場合にのみ表示されます。 +3. **問題点** — 深刻度でランク付けされた漏れの一覧テーブル:`いつ · 何が漏れたか+検知できたポリシー · 深刻度ピル · 発生回数`。再発回数は `new`(1 回)、`N× seen`(2〜9 回)、`recurring`(10 回以上)で表示されます。 +4. **改善方法** — 推奨ポリシーごとに 1 行のリスト:ポリシー名(白文字)、1 行の説明、右側にインストールコマンド+コピーボタン。セクションヘッダーには `enable all N → projected · `(すべての修正を適用した場合に到達するスコア)が表示され、`[install all]` ボタンをクリックすると、推奨されるすべてのポリシーをまとめた `failproofai policy add a b c …` コマンドがコピーされます。 +5. **より良く戻ってくる** — 2 つの並んだカード。左側:リマインダーの設定(`3d` / `7d` / `14d` / `30d` の間隔ピッカー。認証後は `/api/auth/reminder` を通じて保持)。右側:failproof 特典のアンロック — `invite a friend` はカンマ・スペース・改行区切りの友人メールアドレスリスト(1 回の送信につき最大 10 件)を入力するモーダルを開き、`/api/audit/invite` に POST して api-server の `POST /v0/invite` に転送します。api-server は `invite@failproof.ai` から受信者 1 人ずつメールを送信し、送信者は Cc に追加され `Reply-To` が設定されるため、受信者は誰から招待されたかがわかり、送信者も受信トレイにコピーが届きます。匿名ユーザーは先に `AuthDialog` に誘導され、招待送信前に送信者のメールアドレスが確認されます。特典の付与は今後の対応予定です。 -`failproofai audit` ランタイムによって駆動されます — 基礎となるスキャンエンジン、サポートされているフラグ、トランスクリプトごとのキャッシュの不変条件については [監査 CLI](/ja/cli/audit) を参照してください。ダッシュボードは最新の結果を `~/.failproofai/audit-dashboard.json`(モード `0600`、シングルスロット、新しい実行で上書き)にキャッシュするため、再訪問は即座に表示されます。**トランスクリプトごとおよび結果全体のキャッシュは、7日以上古くなった時点で読み取り時に拒否されます**。そのため、ダッシュボードが1週間前の結果を暗黙的に提供することはありません — TTL を過ぎると `/audit` は空の状態にフォールスルーし、新しい実行を促します。レポートの下部近くにある `[ re-audit now ]` をクリックすると、`noCache: true` で `/api/audit/run` に POST されます — 再監査はトランスクリプトごとのキャッシュをバイパスし、キャッシュされた結果を返すのではなくすべてのトランスクリプトをゼロから再スキャンします — ダッシュボードは実行が完了するまで 1Hz で `/api/audit/status` をポーリングします。実行中は経過タイマー付きのピンクのプログレスストリップがビューポートの上部に固定表示され、成功すると最新の結果がページをフルリロードせずに差し替えられます(再監査に失敗した場合は以前のレポートがそのまま残ります)。失敗した場合、ストリップは赤くなり、`RerunError.kind`(`timeout` / `network` / `post_failed`)に基づいたコピーが表示されます。空の状態(キャッシュなしまたは期限切れ)とセッションゼロの状態(キャッシュは存在するがスキャンでトランスクリプトが見つからなかった)は別々に表示されます。 +`failproofai audit` ランタイムで動作します — 基盤となるスキャンエンジン、対応フラグ、トランスクリプトごとのキャッシュ不変条件については [監査 CLI](/ja/cli/audit) を参照してください。ダッシュボードは最新の結果を `~/.failproofai/audit-dashboard.json`(モード `0600`、単一スロット、新しい実行で上書き)にキャッシュするため、再訪問は即座に表示されます。**トランスクリプトごとのキャッシュと全体結果のキャッシュは、7 日より古くなった時点で読み込み時に拒否されます**。そのため、ダッシュボードが 1 週間前の結果を黙って返すことはありません — TTL を過ぎると `/audit` は空の状態にフォールバックし、新しい実行を促します。レポート下部の `[ re-audit now ]` をクリックすると `noCache: true` で `/api/audit/run` に POST されます — 再監査はトランスクリプトごとのキャッシュをバイパスし、キャッシュ済みの結果を黙って返すのではなく、すべてのトランスクリプトをゼロから再スキャンします — ダッシュボードは実行が完了するまで 1Hz で `/api/audit/status` をポーリングします。実行中はビューポート上部にスティッキーなピンク色の進行状況バーが表示され、経過タイマーも表示されます。成功すると新しい結果がその場でスワップインされます(ページ全体のリロードなし。再監査が失敗した場合は以前のレポートが保持されます)。失敗時はバーが赤くなり、`RerunError.kind`(`timeout` / `network` / `post_failed`)に応じたメッセージが表示されます。空の状態(キャッシュなしまたは期限切れ)とゼロセッション状態(キャッシュは存在するがスキャンでトランスクリプトが見つからなかった)は別々に表示されます。 ### ポリシー -ポリシーの管理とアクティビティの確認のための2タブページ。 +ポリシーの管理とアクティビティの確認を行う 2 タブのページです。 - - 1つのパネルから failproofai が保護するエージェント CLI を複数選択できます — Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、Gemini CLI、および Hermes にはそれぞれインストール状況(`Active` / `Detected` / `Inactive`)、ユーザースコープの設定パス、ブランドカラーのアクセントを持つ行があります。対象の CLI にチェックを入れるか外して `Apply changes` をクリックすると、差分を1ステップでインストール/アンインストールできます。PATH 上でバイナリが検出された CLI は事前にチェックされています。 - - 個別のポリシーをワンクリックで有効/無効に切り替えます(`~/.failproofai/policies-config.json` に書き込まれます — インストールされたすべての CLI で共有) - - パラメーターをサポートするポリシーの設定を展開して変更します(`policyParams` をサポートするポリシーの場合) - - カスタムポリシーファイルのパスを設定します + - 1 つのパネルから failproofai が保護するエージェント CLI を複数選択できます — Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、Hermes のそれぞれに、インストール状態(`Active` / `Detected` / `Inactive`)、ユーザースコープの設定パス、ブランドカラーのアクセントが付いた行があります。保護したい CLI にチェックを入れ、`Apply changes` をクリックすると差分のインストール/アンインストールが一括実行されます。PATH 上でバイナリが検出された CLI は事前にチェックされています。 + - 個々のポリシーをワンクリックで有効/無効に切り替えられます(`~/.failproofai/policies-config.json` に書き込まれ、インストールされたすべての CLI で共有されます) + - ポリシーを展開してパラメーターを設定できます(`policyParams` をサポートするポリシーの場合) + - カスタムポリシーファイルのパスを設定できます - - すべてのセッションで発動したすべてのフックイベントの完全なページ分割履歴 - - 判定、イベントタイプ、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(ベータ)_ / Cursor Agent _(ベータ)_ / OpenCode _(ベータ)_ / Pi _(ベータ)_ / Gemini CLI _(ベータ)_ / Hermes)、ポリシー名、またはセッション ID でフィルタリング - - 各行には:タイムスタンプ、ポリシー名、判定、CLI バッジ(オレンジ = Claude Code、パープル = OpenAI Codex、ブルー = GitHub Copilot、エメラルド = Cursor Agent、アンバー = OpenCode、ピンク = Pi、スカイ = Gemini CLI、インディゴ = Hermes)、ツール名、セッション ID、deny/instruct 判定の理由が表示されます - - セッション ID をクリックするとトランスクリプトが開きます — ビューアーはどの CLI がフックを発動させたかを自動検出し(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Gemini CLI `~/.gemini/tmp//chats/.jsonl`、Hermes `~/.hermes/state.db`)、ヘッダーに対応する CLI バッジを表示します + - すべてのセッションにわたって発火したすべてのフックイベントの完全なページネーション履歴 + - 判断、イベントタイプ、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(ベータ)_ / Cursor Agent _(ベータ)_ / OpenCode _(ベータ)_ / Pi _(ベータ)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose)、ポリシー名、セッション ID でフィルタリング可能 + - 各行には:タイムスタンプ、ポリシー名、判断、CLI バッジ(オレンジ = Claude Code、パープル = OpenAI Codex、ブルー = GitHub Copilot、エメラルド = Cursor Agent、アンバー = OpenCode、ピンク = Pi、インディゴ = Hermes、ティール = OpenClaw、ローズ = Factory Droid、バイオレット = Devin、シアン = Antigravity、ライム = Goose)、ツール名、セッション ID、deny/instruct 判断の理由が表示されます + - セッション ID をクリックするとそのトランスクリプトが開きます — ビューアーはフックを発火させた CLI(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Hermes `~/.hermes/state.db`、OpenClaw `~/.openclaw/agents//sessions/*.jsonl`、Factory Droid `~/.factory/sessions//.jsonl`、Devin `~/.local/share/devin/cli/sessions.db`、Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`、Goose `~/.local/share/goose/sessions/sessions.db`)を自動検出し、ヘッダーに対応する CLI バッジをレンダリングします @@ -92,13 +92,13 @@ failproofai ## 自動更新 -ダッシュボードの上部ナビゲーションには自動更新トグルがあります。有効にすると、現在のページが定期的に更新され、新しいセッションとポリシーアクティビティがリアルタイムで表示されます。長時間実行される自律エージェントセッションの監視に不可欠です。 +ダッシュボードのトップナビゲーションには自動更新トグルがあります。有効にすると、現在のページが定期的に更新され、新しいセッションとポリシーアクティビティがリアルタイムで表示されます。長時間実行される自律エージェントセッションの監視に必須の機能です。 --- ## ページの無効化 -ダッシュボードの一部のみが必要な場合は、`FAILPROOFAI_DISABLE_PAGES` にページ名のカンマ区切りリストを設定します: +ダッシュボードの一部のみが必要な場合は、`FAILPROOFAI_DISABLE_PAGES` にページ名のカンマ区切りリストを設定してください: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +110,7 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai ## プロジェクトパスの設定 -デフォルトでは、ダッシュボードは標準の Claude Code プロジェクトディレクトリから読み取ります。カスタム設定の場合はオーバーライドしてください: +デフォルトでは、ダッシュボードは標準の Claude Code プロジェクトディレクトリから読み込みます。カスタム設定の場合は上書きできます: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -126,24 +126,24 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -これは、Next.js が HMR(ホットモジュールリロード)WebSocket へのクロスオリジンアクセスをブロックしているためです。HMR は開発専用の機能です。ホストを許可するには `--allowed-origins` フラグを使用します: +これは Next.js が HMR(ホットモジュールリロード)WebSocket へのクロスオリジンアクセスをブロックしているためです(開発専用の機能です)。ホストを許可するには `--allowed-origins` フラグを使用してください: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -複数のホストや IP の場合は、カンマ区切りのリストを渡します: +複数のホストや IP を指定する場合は、カンマ区切りリストで渡してください: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -`FAILPROOFAI_ALLOWED_DEV_ORIGINS` 環境変数を使用して設定することもできます: +環境変数 `FAILPROOFAI_ALLOWED_DEV_ORIGINS` で設定することもできます: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -これは開発モードにのみ適用されます。`failproofai`(本番モード)を実行する場合、HMR WebSocket もクロスオリジン開発リソースの問題も発生しません。 +これは開発モードにのみ適用されます。`failproofai`(本番モード)を実行している場合は、HMR WebSocket もクロスオリジン開発リソースの問題も発生しません。 \ No newline at end of file diff --git a/docs/ja/getting-started.mdx b/docs/ja/getting-started.mdx index 59b11f83..f01191fa 100644 --- a/docs/ja/getting-started.mdx +++ b/docs/ja/getting-started.mdx @@ -1,13 +1,13 @@ --- title: はじめに -description: "failproofai をインストールし、ポリシーを有効化して、エージェントを安定稼働させましょう" +description: "failproofaiをインストールし、ポリシーを有効化して、エージェントを安定して動かしましょう" icon: rocket --- ## 動作要件 - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0(任意 — ソースからビルドする場合のみ必要) +- **Bun** >= 1.3.0(オプション — ソースからビルドする場合のみ必要) --- @@ -31,15 +31,15 @@ bun add -g failproofai - ポリシーは、エージェントのツール呼び出しの前後に実行されるルールです。破壊的なコマンド、シークレットの漏洩、その他の障害モードを、実害が出る前に検出します。 + ポリシーとは、エージェントのツール呼び出しの前後に実行されるルールです。破壊的なコマンド、シークレットの漏洩、その他の障害パターンを、実害が発生する前に検出します。 ```bash failproofai policies --install ``` - このコマンドは、インストール済みのエージェント CLI にフックエントリを書き込みます(Claude Code の `~/.claude/settings.json`、OpenAI Codex の `~/.codex/hooks.json`、GitHub Copilot CLI の `~/.copilot/hooks/failproofai.json`、Cursor Agent の `~/.cursor/hooks.json`、OpenCode の `~/.config/opencode/plugins/failproofai.mjs` と `~/.config/opencode/opencode.json` の `plugin` 配列へのエントリ、Pi の `~/.pi/agent/settings.json`、Gemini CLI の `~/.gemini/settings.json`、または Hermes の `~/.hermes/config.yaml`)。複数が存在する場合はプロンプトで選択を求められます。`--cli claude codex copilot cursor opencode pi gemini hermes`(任意のサブセット)を渡すとプロンプトをスキップできます。 + このコマンドは、インストール済みのエージェント CLI にフックエントリを書き込みます(Claude Code の `~/.claude/settings.json`、OpenAI Codex の `~/.codex/hooks.json`、GitHub Copilot CLI の `~/.copilot/hooks/failproofai.json`、Cursor Agent の `~/.cursor/hooks.json`、OpenCode の生成プラグインシム `~/.config/opencode/plugins/failproofai.mjs` および `~/.config/opencode/opencode.json` の `plugin` 配列への登録エントリ、Pi の `~/.pi/agent/settings.json`、Hermes の `~/.hermes/config.yaml`、OpenClaw の `~/.openclaw/openclaw.json`、Factory Droid の `~/.factory/hooks.json`、Devin CLI の `~/.config/devin/config.json`、Antigravity CLI の `~/.gemini/config/hooks.json`、または Goose の自動検出プラグインディレクトリ `~/.agents/plugins/failproofai/hooks/hooks.json`)。複数が存在する場合はプロンプトが表示されます。`--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`(任意のサブセット)を渡すとプロンプトをスキップできます。 - GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI のサポートは**ベータ版**です — それぞれ `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi`、`--cli gemini` でインストールしてください。Hermes(hermes-agent、Slack/Telegram ゲートウェイ)は `--cli hermes` でユーザースコープにインストールでき、オフライン監査ソースとしても機能します。 + GitHub Copilot CLI、Cursor Agent、OpenCode、Pi のサポートは**ベータ版**です — それぞれ `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi` でインストールしてください。Hermes(hermes-agent、Slack/Telegram ゲートウェイ)はユーザースコープで `--cli hermes` によりインストールされ、**オフライン監査ソース**としても機能します。OpenClaw(openclaw ゲートウェイ、セルフホスト型マルチチャネルアシスタント)はユーザースコープで `--cli openclaw` によりインストールされます。`before_agent_finalize` が実際のターン終了ゲートとして機能するため、`require-*-before-stop` 組み込みポリシーが有効になります。こちらも**オフライン監査ソース**です。Factory Droid(`droid`)は `--cli factory`(ユーザー + プロジェクトスコープ)でインストールされ、**オフライン監査ソース**としても機能します。Devin CLI(`devin`、Cognition)は `--cli devin`(ユーザー + プロジェクトスコープ)でインストールされ、**オフライン監査ソース**としても機能します。Antigravity CLI(`agy`)は `--cli antigravity`(ユーザー + プロジェクトスコープ)でインストールされ、**オフライン監査ソース**としても機能します。Goose(コードネーム goose、Block)は `--cli goose`(ユーザー + プロジェクトスコープ)でインストールされます。インストーラーは `~/.agents/plugins/failproofai/` にプラグインディレクトリを作成するだけで、Goose が自動検出します。こちらも**オフライン監査ソース**です。 ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,7 +62,7 @@ bun add -g failproofai failproofai policies ``` - すべてのポリシー、その有効・無効の状態、および設定済みパラメータが表示されます。 + すべてのポリシー、有効/無効の状態、設定済みのパラメータが表示されます。 ```bash @@ -68,7 +72,7 @@ bun add -g failproofai `http://localhost:8020` にローカルダッシュボードが開きます。セッションの閲覧、ツール呼び出しの確認、ポリシーの管理が行えます。 - Claude Code を通常通り起動してください。エージェントがリスクのある操作を試みた場合、failproofai が自動的にインターセプトします。放置したまま実行し、あとでダッシュボードで何が起きたかを確認できます。 + 通常通り Claude Code を起動してください。エージェントがリスクのある操作を試みた場合、failproofai が自動的にインターセプトします。放置したまま実行し、ダッシュボードで結果を確認できます。 @@ -84,21 +88,21 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON writes decision to stdout ``` -各ポリシーは次の 3 つの判定のいずれかを返します。 +各ポリシーは次の3つのいずれかの判断を返します。 -- **allow** — エージェントは通常通り処理を続行する -- **deny** — アクションがブロックされ、エージェントにその理由が通知される -- **instruct** — エージェントのプロンプトに追加コンテキストが付加される +- **allow** — エージェントは通常通り処理を続行します +- **deny** — アクションがブロックされ、エージェントに理由が通知されます +- **instruct** — エージェントのプロンプトに追加コンテキストが付与されます -ポリシーはローカルプロセス内で実行されます。リモートサービスへのデータ送信は一切行われません。 +ポリシーはローカルプロセス内で実行されます。リモートサービスへの送信は一切ありません。 --- -## 規約ベースのポリシーでチームポリシーを設定する +## 規約ベースのポリシーでチームのポリシーを設定する -チーム全体に品質基準を確立する最も手軽な方法は、`.failproofai/policies/` の規約です。このディレクトリにポリシーファイルを置くだけで自動的に読み込まれます — フラグも、設定変更も、インストールコマンドも不要です。 +チーム全体に品質基準を素早く導入するには、`.failproofai/policies/` の規約が最も手軽です。このディレクトリにポリシーファイルを置くだけで自動的に読み込まれます — フラグも設定変更もインストールコマンドも不要です。 @@ -113,7 +117,7 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - または新しいファイルを作成します。 + または新しく作成する場合: ```js // .failproofai/policies/team-policies.mjs @@ -138,27 +142,27 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON git commit -m "Add team quality policies" ``` - failproofai をインストールしているすべてのチームメンバーが、これらのポリシーを自動的に取得します。開発者ごとの個別設定は不要です。 + failproofai をインストールしているすべてのチームメンバーが、これらのポリシーを自動的に取得します。開発者ごとのセットアップは不要です。 -`.failproofai/policies/` をリポジトリにコミットすることで、チーム全員が同じ基準を共有できます。新たな障害モードが見つかったらポリシーを追加してプッシュするだけで、次の `git pull` 時に全員へ反映されます。こうして蓄積されたポリシーは、継続的に改善される生きた品質基準となります。 +`.failproofai/policies/` をリポジトリにコミットすることで、チーム全員が同じ基準を共有できます。新たな障害パターンが見つかった際にポリシーを追加してプッシュすれば、次の `git pull` 時に全員へ自動的に反映されます。こうしてポリシーは継続的に改善される生きた品質基準になっていきます。 --- -## データの保存場所 +## データの保存先 -すべての設定とログはお使いのマシン上に保存されます。 +すべての設定とログはローカルマシンに保存されます。 | パス | 保存内容 | -|------|----------| +|------|----------------| | `~/.failproofai/policies-config.json` | グローバルポリシー設定 | | `~/.failproofai/hook-activity.jsonl` | フック実行履歴 | | `~/.failproofai/hook.log` | カスタムフックエラーのデバッグログ | -| `.failproofai/policies-config.json` | プロジェクト別設定(コミット対象) | -| `.failproofai/policies-config.local.json` | 個人用オーバーライド(gitignore 対象) | +| `.failproofai/policies-config.json` | プロジェクト単位の設定(コミット対象) | +| `.failproofai/policies-config.local.json` | 個人の上書き設定(gitignore 対象) | --- @@ -168,7 +172,7 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON failproofai policies --uninstall ``` -`~/.claude/settings.json` からフックエントリを削除します。`~/.failproofai/` 内の設定ファイルはそのまま保持されます。 +`~/.claude/settings.json` からフックエントリを削除します。`~/.failproofai/` 内の設定ファイルは保持されます。 --- @@ -181,11 +185,11 @@ failproofai policies --uninstall - パラメータを含む全 26 ポリシー + パラメータ付きの全26ポリシー - JavaScript で独自のポリシーを作成する + JavaScript で独自ポリシーを作成する diff --git a/docs/ja/introduction.mdx b/docs/ja/introduction.mdx index aa59b0ff..913dbe4e 100644 --- a/docs/ja/introduction.mdx +++ b/docs/ja/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI は AI エージェントに39種類の組み込み障害ポリシーを提供し、ループ・シークレット漏洩・破壊的なツール呼び出しなどをワンインストールで検出します。" +description: "FailproofAI は AI エージェントに 39 の組み込み障害ポリシーを提供し、ループ・シークレット漏洩・破壊的なツール呼び出しなどを 1 回のインストールで検出します。" --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI 障害ハンドリング**・**エラーリカバリー**・**LLM の信頼性**向上のためのフックとポリシー。**Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Gemini CLI**、**Hermes**、そして **Agents SDK** 上で、AI エージェントを安定かつ自律的に動作させ続けます。 +**AI 障害ハンドリング**、**エラーリカバリー**、**LLM の信頼性**のためのフックとポリシー。**Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Hermes**、**OpenClaw**、**Factory Droid**、**Devin CLI**、**Antigravity CLI**、および **Agents SDK** 上で AI エージェントを安定させ、自律的に稼働し続けます。 -AI エージェントの障害は、予測可能なパターンで発生します。破壊的なコマンドの実行、シークレットの漏洩、タスクからの逸脱、ループへの陥没、main ブランチへの直接プッシュ——放置すれば、小さな障害がサービス停止、認証情報の流出、作業の消失へと連鎖します。 +AI エージェントは予測可能な形で失敗します。破壊的なコマンドを実行したり、シークレットを漏洩させたり、タスクから逸脱したり、ループにはまったり、main ブランチに直接プッシュしたりします。放置すれば、小さな失敗が障害・認証情報の漏洩・作業の消失へと連鎖します。 -FailproofAI はこれを**ポリシー**で解決します。これらのルールはエージェントのすべてのツール呼び出しにフックし、**障害を検出**し、**軽減**(ブロック・指示・サニタイズ)し、対応が必要な場合に**アラートを通知**します。ローカルダッシュボードで、あとからすべてのツール呼び出し・エージェント障害・リカバリーアクションを確認できます。 +FailproofAI はこれを**ポリシー**で解決します。これらのルールはすべてのエージェントツール呼び出しにフックし、**障害を検出**し、**対処**(ブロック・指示・サニタイズ)し、注意が必要なときに**アラートを送信**します。ローカルダッシュボードでは、すべてのツール呼び出し・エージェント障害・リカバリーアクションを後から確認できます。 -データはマシンの外に出ません。 +データは一切、あなたのマシンの外に出ません。 ## はじめに - - 破壊的なコマンドのブロック、シークレット漏洩の防止、エージェントをプロジェクト境界内に収める、など。すべてすぐに使えます。 + + 破壊的なコマンドのブロック、シークレット漏洩の防止、エージェントのプロジェクト境界内への制限など、すべてすぐに使えます。 - シンプルな allow / deny / instruct API を使い、JavaScript で独自のルールを記述できます。 + シンプルな allow / deny / instruct API を使って、JavaScript で独自のルールを記述できます。 - 離席中にエージェントが何をしていたかを確認。セッションの閲覧、ツール呼び出しの詳細確認、ポリシーが発動した箇所のレビューが可能です。 + 離れている間にエージェントが何をしたか確認できます。セッションの閲覧、ツール呼び出しの検査、ポリシーが発動した箇所のレビューが可能です。 - コード不要でポリシーを調整。許可リスト・保護ブランチ・しきい値をプロジェクト単位またはグローバルに設定できます。 + コードなしで任意のポリシーを調整できます。許可リスト、保護ブランチ、しきい値をプロジェクト単位またはグローバルに設定できます。 @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -詳細な手順については [Getting started](/ja/getting-started) ガイドをご覧ください。 \ No newline at end of file +詳細な手順については、[はじめにガイド](/ja/getting-started)をご覧ください。 \ No newline at end of file diff --git a/docs/ko/built-in-policies.mdx b/docs/ko/built-in-policies.mdx index 3ba3d9c5..27a05d3d 100644 --- a/docs/ko/built-in-policies.mdx +++ b/docs/ko/built-in-policies.mdx @@ -1,18 +1,18 @@ --- title: 기본 제공 정책 -description: "일반적인 에이전트 오류 패턴을 감지하는 39가지 기본 제공 정책" +description: "에이전트의 일반적인 장애 패턴을 감지하는 39가지 기본 제공 정책" icon: shield --- -failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가지 기본 제공 정책이 포함되어 있습니다. 각 정책은 특정 훅 이벤트 유형과 도구 이름에 대해 실행됩니다. 19개의 정책은 코드 작성 없이 동작을 조정할 수 있는 매개변수를 허용합니다. 5개의 워크플로 정책은 Claude가 중단되기 전에 커밋 → 푸시 → PR → CI 파이프라인을 강제합니다. +failproofai는 에이전트의 일반적인 장애 패턴을 감지하는 39가지 기본 제공 정책을 제공합니다. 각 정책은 특정 훅 이벤트 타입과 도구 이름에 대해 실행됩니다. 19개의 정책은 코드를 작성하지 않고도 동작을 조정할 수 있는 파라미터를 지원합니다. 5개의 워크플로 정책은 Claude가 중지하기 전에 커밋 → 푸시 → PR → CI 파이프라인을 강제합니다. --- ## 개요 -정책은 다음 카테고리로 그룹화됩니다: +정책은 다음 카테고리로 분류됩니다: -| 카테고리 | 정책 | 훅 유형 | +| 카테고리 | 정책 | 훅 타입 | |----------|----------|-----------| | [위험한 명령어](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [인프라 명령어](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | @@ -31,13 +31,9 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### 네임스페이스 -모든 정책은 `/` 슬롯에 속합니다. 기본 제공 정책은 -**`failproofai/`** 네임스페이스에 속합니다 — 예를 들어 `failproofai/sanitize-jwt`. 이 -네임스페이스는 비슷한 짧은 이름을 가진 커스텀 또는 서드파티 정책을 함께 로드할 때 -충돌을 방지합니다. +모든 정책은 `/` 슬롯에 위치합니다. 기본 제공 정책은 **`failproofai/`** 네임스페이스에 속합니다 — 예를 들어 `failproofai/sanitize-jwt`. 네임스페이스는 유사한 단축 이름을 가진 커스텀 또는 서드파티 정책을 함께 로드할 때 충돌을 방지합니다. -설정 파일에서 기본 제공 정책을 짧은 이름 또는 전체 이름 중 하나로 참조할 수 있으며, -두 형식 모두 동일한 정책으로 해석됩니다: +설정에서 기본 제공 정책은 단축 이름 또는 정규화된 이름으로 참조할 수 있으며, 두 형식 모두 동일한 정책으로 해석됩니다: ```json { @@ -48,15 +44,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 } ``` -이름에 `/`가 없으면 failproofai는 기본 네임스페이스인 `failproofai`에 속하는 것으로 -처리합니다. 이미 `/`를 포함한 이름(예: `myorg/foo`, `custom/my-hook`)은 그대로 -유지됩니다. +이름에 `/`가 없으면 failproofai는 기본 네임스페이스 `failproofai`에 속하는 것으로 간주합니다. 이미 `/`를 포함하는 이름(예: `myorg/foo`, `custom/my-hook`)은 그대로 유지됩니다. - **`require-`** — 조건이 충족될 때까지 Stop 이벤트를 차단합니다. --- -모든 정책은 `policyParams`에서 선택적 `hint` 필드를 지원합니다. hint는 Claude가 보는 deny 또는 instruct 메시지에 추가되어, 정책 코드를 수정하지 않고도 실행 가능한 안내를 제공합니다. 기본 제공, 커스텀, 컨벤션 정책 모두에서 동작합니다. 자세한 내용은 [구성 → hint](/ko/configuration#hint-cross-cutting)를 참조하세요. +모든 정책은 `policyParams`에서 선택적 `hint` 필드를 지원합니다. hint는 Claude가 보는 deny 또는 instruct 메시지에 추가되어, 정책 코드를 수정하지 않고도 실행 가능한 안내를 제공합니다. 기본 제공, 커스텀, 컨벤션 정책 모두에서 동작합니다. 자세한 내용은 [설정 → hint](/ko/configuration#hint-cross-cutting)를 참조하세요. --- @@ -70,13 +64,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** `sudo` 명령어를 포함하는 모든 명령을 거부합니다. -`sudo` 키워드를 포함하는 호출을 차단합니다. 패턴 매칭은 원시 문자열이 아닌 파싱된 명령 토큰에 대해 수행되어 셸 연산자 주입을 통한 우회를 방지합니다. +`sudo` 키워드를 포함하는 호출을 차단합니다. 패턴 매칭은 원시 문자열이 아닌 파싱된 명령어 토큰에 대해 수행되어, 셸 연산자 주입을 통한 우회를 방지합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 정확한 명령 접두사. 각 항목은 파싱된 argv 토큰에 대해 매칭됩니다. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 정확한 명령어 접두사. 각 항목은 파싱된 argv 토큰에 대해 매칭됩니다. | **예시:** @@ -90,10 +84,10 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 } ``` -이 설정에서 `sudo systemctl status nginx`는 허용되지만 `sudo rm /etc/hosts`는 거부됩니다. +이 설정에서 `sudo systemctl status nginx`는 허용되지만, `sudo rm /etc/hosts`는 거부됩니다. -패턴은 원시 명령 문자열이 아닌 파싱된 토큰에 대해 매칭됩니다. 이는 추가된 셸 연산자를 통한 우회를 방지합니다 (예: `sudo systemctl status x; rm -rf /`는 `sudo systemctl status *`와 매칭되지 않습니다). +패턴은 원시 명령어 문자열이 아닌 파싱된 토큰에 대해 매칭됩니다. 이를 통해 추가된 셸 연산자를 통한 우회를 방지합니다(예: `sudo systemctl status x; rm -rf /`는 `sudo systemctl status *`와 매칭되지 않습니다). --- @@ -103,11 +97,11 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** `rm -rf`, `rm -fr` 및 유사한 재귀 삭제 형식을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | 재귀적으로 삭제해도 안전한 경로 (예: `/tmp`). | +| `allowPaths` | `string[]` | `[]` | 재귀 삭제가 안전한 경로(예: `/tmp`). | **예시:** @@ -128,35 +122,35 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** `curl | bash`, `curl | sh`, `wget | bash` 및 유사한 패턴을 거부합니다. -매개변수 없음. +파라미터 없음. --- ### `block-failproofai-commands` **이벤트:** PreToolUse (Bash) -**기본값:** failproofai 자체를 제거하거나 비활성화하는 명령을 거부합니다 (예: `npm uninstall failproofai`, `failproofai policies --uninstall`). +**기본값:** failproofai 자체를 제거하거나 비활성화하는 명령(예: `npm uninstall failproofai`, `failproofai policies --uninstall`)을 거부합니다. -매개변수 없음. +파라미터 없음. --- ## 인프라 명령어 -코딩 에이전트가 인프라 CLI를 실행하거나 CI/CD 파이프라인을 트리거하지 못하도록 차단합니다. 이 카테고리의 모든 정책은 **옵트인** (`defaultEnabled: false`)입니다 — `kubectl`, `terraform` 등을 정상적으로 호출해야 하는 에이전트는 정책을 활성화하지 않는 한 영향을 받지 않습니다. 활성화되면 명령이 `allowPatterns`의 항목과 일치하지 않는 한 매칭된 CLI의 모든 호출이 거부됩니다. +코딩 에이전트가 인프라 CLI를 실행하거나 CI/CD 파이프라인을 트리거하지 못하도록 방지합니다. 이 카테고리의 모든 정책은 **옵트인** 방식(`defaultEnabled: false`)입니다 — `kubectl`, `terraform` 등을 합법적으로 호출해야 하는 에이전트는 정책을 명시적으로 활성화하지 않는 한 영향을 받지 않습니다. 활성화된 경우, 명령이 `allowPatterns`의 항목과 일치하지 않으면 해당 CLI의 모든 호출이 거부됩니다. -패턴 문법은 [`block-sudo`](#block-sudo)와 동일합니다: 토큰은 파싱된 argv에 대해 매칭되고, `*`는 한 토큰에 대한 와일드카드이며, 독립적인 셸 연산자(`&&`, `||`, `|`, `;`)를 포함하거나 임베디드 셸 메타문자가 있는 토큰을 포함하는 명령은 주입 우회를 방지하기 위해 허용 목록 매칭 전에 거부됩니다. +패턴 문법은 [`block-sudo`](#block-sudo)와 동일합니다: 토큰은 파싱된 argv에 대해 매칭되고, `*`는 하나의 토큰에 대한 와일드카드이며, 독립적인 셸 연산자(`&&`, `||`, `|`, `;`)나 임베디드 셸 메타문자를 포함하는 토큰을 포함하는 명령어는 인젝션 우회를 방지하기 위해 허용 목록 매칭 전에 거부됩니다. ### `block-kubectl` **이벤트:** PreToolUse (Bash) **기본값:** 모든 `kubectl` 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 kubectl 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 kubectl 명령어 접두사. | **예시:** @@ -177,13 +171,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-terraform` **이벤트:** PreToolUse (Bash) -**기본값:** 모든 `terraform` 또는 `tofu` (OpenTofu) 호출을 거부합니다. +**기본값:** 모든 `terraform` 또는 `tofu`(OpenTofu) 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 terraform/tofu 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 terraform/tofu 명령어 접두사. | **예시:** @@ -204,11 +198,11 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** 모든 `aws` CLI 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 aws CLI 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 aws CLI 명령어 접두사. | **예시:** @@ -227,13 +221,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-gcloud` **이벤트:** PreToolUse (Bash) -**기본값:** 모든 `gcloud` (Google Cloud) CLI 호출을 거부합니다. +**기본값:** 모든 `gcloud`(Google Cloud) CLI 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 gcloud 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 gcloud 명령어 접두사. | **예시:** @@ -252,13 +246,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-az-cli` **이벤트:** PreToolUse (Bash) -**기본값:** 모든 `az` (Azure) CLI 호출을 거부합니다. +**기본값:** 모든 `az`(Azure) CLI 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 az CLI 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 az CLI 명령어 접두사. | **예시:** @@ -279,11 +273,11 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** 모든 `helm` 호출을 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 허용되는 helm 명령 접두사. | +| `allowPatterns` | `string[]` | `[]` | 허용되는 helm 명령어 접두사. | **예시:** @@ -311,13 +305,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 - `gh cache delete` - `gh secret set`, `gh secret delete` -`gh pr view`, `gh pr list`, `gh run list`, `gh release view`, `gh api repos/.../...`와 같은 읽기 전용 `gh` 서브커맨드는 이 정책에서 매칭되지 **않습니다** — 이러한 명령은 워크플로 확인(failproofai의 `require-ci-green-before-stop` 포함)에 일상적으로 필요합니다. +`gh pr view`, `gh pr list`, `gh run list`, `gh release view`, `gh api repos/.../...`와 같은 읽기 전용 `gh` 서브커맨드는 이 정책에 매칭되지 **않습니다** — 이는 워크플로 확인(failproofai의 `require-ci-green-before-stop` 포함)에 일상적으로 필요합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 그렇지 않으면 거부될 특정 스크립트 호출을 허용합니다. | +| `allowPatterns` | `string[]` | `[]` | 거부 대상이더라도 허용할 특정 스크립트 호출. | **예시:** @@ -335,25 +329,25 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ## 시크릿 (새니타이저) -에이전트가 컨텍스트나 출력에 자격 증명을 노출하지 못하도록 방지합니다. 새니타이저 정책은 **PostToolUse** 이벤트에서 실행됩니다. Claude가 Bash 명령을 실행하거나, 파일을 읽거나, 도구를 호출할 때 이 정책들은 Claude에게 반환되기 전에 출력을 검사합니다. 시크릿 패턴이 감지되면 정책은 출력이 다시 전달되지 못하도록 거부 결정을 반환합니다. +에이전트가 컨텍스트나 출력에 자격 증명을 노출하지 못하도록 방지합니다. 새니타이저 정책은 **PostToolUse** 이벤트에서 실행됩니다. Claude가 Bash 명령을 실행하거나, 파일을 읽거나, 도구를 호출할 때, 이 정책들은 출력이 Claude에게 반환되기 전에 검사합니다. 시크릿 패턴이 감지되면, 정책은 출력이 다시 전달되지 못하도록 차단 결정을 반환합니다. ### `sanitize-jwt` **이벤트:** PostToolUse (모든 도구) -**기본값:** JWT 토큰(`.`으로 구분된 세 개의 base64url 세그먼트)을 난독화합니다. +**기본값:** JWT 토큰(`.`으로 구분된 세 개의 base64url 세그먼트)을 삭제합니다. -매개변수 없음. +파라미터 없음. --- ### `sanitize-api-keys` **이벤트:** PostToolUse (모든 도구) -**기본값:** 일반적인 API 키 형식을 난독화합니다: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS 액세스 키 (`AKIA`), Stripe 키 (`sk_live_`, `sk_test_`), Google API 키 (`AIza`). +**기본값:** 일반적인 API 키 형식을 삭제합니다: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PAT (`ghp_`), AWS 액세스 키 (`AKIA`), Stripe 키 (`sk_live_`, `sk_test_`), Google API 키 (`AIza`). -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| | `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | 시크릿으로 처리할 추가 정규식 패턴. | @@ -377,27 +371,27 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `sanitize-connection-strings` **이벤트:** PostToolUse (모든 도구) -**기본값:** 자격 증명이 포함된 데이터베이스 연결 문자열을 난독화합니다 (예: `postgresql://user:password@host/db`). +**기본값:** 임베디드 자격 증명을 포함하는 데이터베이스 연결 문자열(예: `postgresql://user:password@host/db`)을 삭제합니다. -매개변수 없음. +파라미터 없음. --- ### `sanitize-private-key-content` **이벤트:** PostToolUse (모든 도구) -**기본값:** PEM 블록(`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` 등)을 난독화합니다. +**기본값:** PEM 블록(`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` 등)을 삭제합니다. -매개변수 없음. +파라미터 없음. --- ### `sanitize-bearer-tokens` **이벤트:** PostToolUse (모든 도구) -**기본값:** 토큰이 20자 이상인 `Authorization: Bearer ` 헤더를 난독화합니다. +**기본값:** 토큰이 20자 이상인 `Authorization: Bearer ` 헤더를 삭제합니다. -매개변수 없음. +파라미터 없음. --- @@ -408,11 +402,11 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-env-files` **이벤트:** PreToolUse (Bash, Read) -**기본값:** `cat .env`, `.env`를 파일 경로로 하는 `Read` 도구 호출 등을 통한 `.env` 파일 읽기를 거부합니다. +**기본값:** `cat .env`, `.env`를 파일 경로로 사용하는 `Read` 도구 호출 등을 통한 `.env` 파일 읽기를 거부합니다. -`.envrc` 또는 기타 환경 관련 파일은 차단하지 않으며, 정확히 `.env`로 명명된 파일만 차단합니다. +`.envrc` 또는 다른 환경 관련 파일은 차단하지 않습니다 — 정확히 `.env`로 명명된 파일만 차단합니다. -매개변수 없음. +파라미터 없음. --- @@ -421,22 +415,22 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** 환경 변수를 출력하는 명령을 거부합니다: `printenv`, `env`, `echo $VAR`. -매개변수 없음. +파라미터 없음. --- ## 파일 접근 -에이전트가 프로젝트 경계 안에서만 작업하고 민감한 파일에 접근하지 못하도록 유지합니다. +에이전트가 프로젝트 경계 내에서 작업하고 민감한 파일에 접근하지 못하도록 합니다. ### `block-read-outside-cwd` **이벤트:** PreToolUse (Read, Bash) -**기본값:** 프로젝트 루트 외부의 파일 읽기를 거부합니다. 경계는 `CLAUDE_PROJECT_DIR`(Claude Code가 세션당 한 번 설정)이며, 해당 변수가 설정되지 않은 경우 세션의 현재 작업 디렉토리로 폴백합니다. 라이브 `cwd` 대신 프로젝트 루트를 사용하면 Claude가 하위 디렉토리로 `cd`한 후에도 경계가 안정적으로 유지됩니다. +**기본값:** 프로젝트 루트 외부의 파일 읽기를 거부합니다. 경계는 `CLAUDE_PROJECT_DIR`(Claude Code에서 세션당 한 번 설정됨)이며, 해당 변수가 설정되지 않은 경우 세션의 현재 작업 디렉토리로 대체됩니다. 실시간 `cwd` 대신 프로젝트 루트를 사용하면 Claude가 하위 디렉토리로 `cd`한 후에도 경계가 안정적으로 유지됩니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| | `allowPaths` | `string[]` | `[]` | 프로젝트 루트 외부에 있더라도 허용되는 절대 경로 접두사. | @@ -457,13 +451,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-secrets-write` **이벤트:** PreToolUse (Write, Edit) -**기본값:** 개인 키와 인증서에 일반적으로 사용되는 파일에 대한 쓰기를 거부합니다: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**기본값:** 개인 키 및 인증서에 일반적으로 사용되는 파일 쓰기를 거부합니다: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | 차단할 추가 파일명 패턴 (글로브 스타일). | +| `additionalPatterns` | `string[]` | `[]` | 차단할 추가 파일명 패턴(글로브 스타일). | **예시:** @@ -488,9 +482,9 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** `git push origin main` 및 `git push origin master`를 거부합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | 직접 푸시할 수 없는 브랜치 이름. | @@ -507,7 +501,7 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ``` -모든 브랜치에 대한 푸시를 허용하려면(`enabledPolicies`에서 정책을 제거하지 않고 효과적으로 비활성화), `protectedBranches: []`로 설정하세요. +모든 브랜치에 대한 푸시를 허용하려면(이 정책을 `enabledPolicies`에서 제거하지 않고 효과적으로 비활성화), `protectedBranches: []`로 설정하세요. --- @@ -515,11 +509,11 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `block-work-on-main` **이벤트:** PreToolUse (Bash) -**기본값:** 작업 트리가 `main` 또는 `master`에 있는 동안 `git commit`, `git merge`, `git rebase`, `git cherry-pick`을 거부합니다. 브랜치 생성 및 전환(`git checkout`, `git checkout -b`, `git switch`, `git switch -c`)은 영향받지 않습니다. +**기본값:** 작업 트리가 `main` 또는 `master`에 있을 때 `git commit`, `git merge`, `git rebase`, `git cherry-pick`을 거부합니다. 브랜치 생성 및 전환(`git checkout`, `git checkout -b`, `git switch`, `git switch -c`)은 영향을 받지 않습니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| | `protectedBranches` | `string[]` | `["main", "master"]` | commit/merge/rebase/cherry-pick이 거부되는 브랜치 이름. | @@ -530,7 +524,7 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 **이벤트:** PreToolUse (Bash) **기본값:** `git push --force` 및 `git push -f`를 거부합니다. -정책별 매개변수 없음. 크로스커팅 [`hint`](/ko/configuration#hint-cross-cutting)를 사용하여 대안을 제안할 수 있습니다: +정책별 파라미터 없음. 크로스 커팅 [`hint`](/ko/configuration#hint-cross-cutting)를 사용하여 대안을 제안할 수 있습니다: ```json { @@ -547,27 +541,27 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `warn-git-amend` **이벤트:** PreToolUse (Bash) -**기본값:** `git commit --amend` 실행 시 Claude에게 신중하게 진행하도록 안내합니다. 명령을 차단하지 않습니다. +**기본값:** `git commit --amend` 실행 시 Claude에게 신중하게 진행하도록 안내합니다. 명령을 차단하지는 않습니다. -매개변수 없음. +파라미터 없음. --- ### `warn-git-stash-drop` **이벤트:** PreToolUse (Bash) -**기본값:** `git stash drop` 실행 전 Claude에게 확인하도록 안내합니다. 명령을 차단하지 않습니다. +**기본값:** `git stash drop` 실행 전에 Claude에게 확인하도록 안내합니다. 명령을 차단하지는 않습니다. -매개변수 없음. +파라미터 없음. --- ### `warn-all-files-staged` **이벤트:** PreToolUse (Bash) -**기본값:** `git add -A` 또는 `git add .` 실행 시 Claude에게 스테이징 중인 내용을 검토하도록 안내합니다. 명령을 차단하지 않습니다. +**기본값:** `git add -A` 또는 `git add .` 실행 시 스테이징할 내용을 검토하도록 Claude에게 안내합니다. 명령을 차단하지는 않습니다. -매개변수 없음. +파라미터 없음. --- @@ -578,18 +572,18 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `warn-destructive-sql` **이벤트:** PreToolUse (Bash) -**기본값:** `DROP TABLE`, `DROP DATABASE` 또는 `WHERE` 절 없는 `DELETE`가 포함된 SQL 실행 전 Claude에게 확인하도록 안내합니다. +**기본값:** `DROP TABLE`, `DROP DATABASE`, 또는 `WHERE` 절 없는 `DELETE`를 포함하는 SQL 실행 전에 Claude에게 확인하도록 안내합니다. -매개변수 없음. +파라미터 없음. --- ### `warn-schema-alteration` **이벤트:** PreToolUse (Bash) -**기본값:** `ALTER TABLE` 구문 실행 전 Claude에게 확인하도록 안내합니다. +**기본값:** `ALTER TABLE` 문 실행 전에 Claude에게 확인하도록 안내합니다. -매개변수 없음. +파라미터 없음. --- @@ -600,13 +594,13 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `warn-large-file-write` **이벤트:** PreToolUse (Write) -**기본값:** 1024 KB를 초과하는 파일 작성 전 Claude에게 확인하도록 안내합니다. +**기본값:** 1024 KB보다 큰 파일 쓰기 전에 Claude에게 확인하도록 안내합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | 경고가 발생하는 파일 크기 임계값 (킬로바이트). | +| `thresholdKb` | `number` | `1024` | 경고가 발생하는 파일 크기 임계값(킬로바이트). | **예시:** @@ -621,7 +615,7 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ``` -훅 핸들러는 페이로드에 대해 1 MB stdin 제한을 적용합니다. 작은 콘텐츠로 이 정책을 테스트하려면 `thresholdKb`를 1024보다 훨씬 낮은 값으로 설정하세요. +훅 핸들러는 페이로드에 대해 1 MB stdin 제한을 적용합니다. 소용량 콘텐츠로 이 정책을 테스트하려면 `thresholdKb`를 1024보다 훨씬 낮은 값으로 설정하세요. --- @@ -629,27 +623,27 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `warn-package-publish` **이벤트:** PreToolUse (Bash) -**기본값:** `npm publish` 실행 전 Claude에게 확인하도록 안내합니다. +**기본값:** `npm publish` 실행 전에 Claude에게 확인하도록 안내합니다. -매개변수 없음. +파라미터 없음. --- ### `warn-background-process` **이벤트:** PreToolUse (Bash) -**기본값:** `nohup`, `&`, `disown`, `screen`을 통한 백그라운드 프로세스 실행 시 Claude에게 주의하도록 안내합니다. +**기본값:** `nohup`, `&`, `disown`, `screen`을 통해 백그라운드 프로세스를 시작할 때 Claude에게 주의하도록 안내합니다. -매개변수 없음. +파라미터 없음. --- ### `warn-global-package-install` **이벤트:** PreToolUse (Bash) -**기본값:** `npm install -g`, `yarn global add`, 또는 가상 환경 없이 `pip install` 실행 전 Claude에게 확인하도록 안내합니다. +**기본값:** `npm install -g`, `yarn global add`, 또는 가상 환경 없는 `pip install` 실행 전에 Claude에게 확인하도록 안내합니다. -매개변수 없음. +파라미터 없음. --- @@ -660,14 +654,14 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 ### `prefer-package-manager` **이벤트:** PreToolUse (Bash) -**기본값:** 비활성화됨. 활성화되면 `allowed` 목록에 없는 패키지 매니저 명령을 차단하고 허용된 매니저를 사용하여 명령을 재작성하도록 Claude에게 안내합니다. +**기본값:** 비활성화. 활성화되면 `allowed` 목록에 없는 패키지 매니저 명령을 차단하고 Claude에게 허용된 매니저를 사용하도록 명령을 재작성하도록 안내합니다. 감지 대상: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | 허용되는 패키지 매니저 이름. 이 목록에 없는 감지된 매니저는 차단됩니다. 비어 있으면 정책은 아무 작업도 수행하지 않습니다. | -| `blocked` | string[] | `[]` | 기본 제공 목록 이외에 추가로 차단할 매니저 이름 (예: `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | 허용되는 패키지 매니저 이름. 이 목록에 없는 감지된 매니저는 차단됩니다. 비어있으면 정책은 아무 동작도 하지 않습니다. | +| `blocked` | string[] | `[]` | 기본 제공 목록 외에 추가로 차단할 매니저 이름(예: `['pdm', 'pipx']`). | 기본 제공 차단 목록: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. 이 목록에 없는 매니저를 추가하려면 `blocked`를 사용하세요. @@ -685,74 +679,73 @@ failproofai에는 일반적인 에이전트 오류 패턴을 감지하는 39가 } ``` -이 설정에서 `pip install flask`와 `pdm install flask`는 모두 거부되며, Claude에게 대신 `uv` 또는 `bun`을 사용하도록 메시지가 표시됩니다. `uv pip install flask`와 같은 명령은 `uv`가 허용 목록에 있고 먼저 확인되므로 허용됩니다. +이 설정에서 `pip install flask`와 `pdm install flask`는 모두 거부되며, Claude에게 `uv` 또는 `bun`을 사용하라는 메시지가 표시됩니다. `uv pip install flask`와 같은 명령은 `uv`가 허용 목록에 있고 먼저 확인되므로 허용됩니다. --- ## AI 동작 -에이전트가 막히거나 예상치 못한 동작을 할 때 감지합니다. +에이전트가 멈추거나 예기치 않게 동작하는 경우를 감지합니다. ### `warn-repeated-tool-calls` **이벤트:** PreToolUse (모든 도구) -**기본값:** 동일한 도구가 동일한 매개변수로 3회 이상 호출될 때 Claude에게 재고하도록 안내합니다 — 에이전트가 루프에 갇혀 있다는 일반적인 신호입니다. +**기본값:** 동일한 도구가 동일한 파라미터로 3회 이상 호출될 때 Claude에게 재고하도록 안내합니다 — 이는 에이전트가 루프에 갇혔다는 일반적인 신호입니다. -매개변수 없음. +파라미터 없음. --- ## 워크플로 -세션 종료 시 체계적인 워크플로를 강제합니다. 이 정책들은 **Stop** 이벤트에서 실행되며 각 조건이 충족될 때까지 에이전트가 중단하지 못하도록 거부합니다. 자연스러운 의존성 체인을 따릅니다: 커밋 → 푸시 → PR → CI. 정책이 거부하면 체인의 이후 정책은 건너뜁니다 (거부 시 단락). +세션 종료 시 체계적인 워크플로를 강제합니다. 이 정책들은 **Stop** 이벤트에서 실행되며, 각 조건이 충족될 때까지 에이전트가 중지하지 못하도록 차단합니다. 자연스러운 의존성 체인을 따릅니다: 커밋 → 푸시 → PR → CI. 정책이 거부하면, 체인의 이후 정책은 건너뜁니다(거부 시 단락). -모든 워크플로 정책은 **fail-open** 방식입니다: 필요한 도구를 사용할 수 없는 경우(예: `gh` 미설치, git 리모트 없음) 정책은 확인이 건너뛰어진 이유를 알리는 정보 메시지와 함께 허용합니다. +모든 워크플로 정책은 **fail-open** 방식입니다: 필요한 도구를 사용할 수 없는 경우(예: `gh`가 설치되지 않음, git 원격 없음), 정책은 확인이 건너뛰어진 이유를 설명하는 정보 메시지와 함께 허용합니다. -### CLI별 Stop 시맨틱 +### CLI별 Stop 동작 방식 -Stop 적용은 지원되는 7개 CLI에서 각각 다른 "에이전트 완료" 훅 계약을 노출하기 때문에 약간씩 다르게 동작합니다. **결과**는 동일합니다 — 에이전트는 워크플로 게이트가 실패하는 동안 중단할 수 없습니다 — 하지만 **메커니즘**은 다릅니다. 아래 표에 요약되어 있습니다; `require-*-before-stop` 정책을 활성화하기 전에 이해할 가치가 있는 사용자에게 보이는 특이점은 Pi에만 있습니다. +Stop 강제 방식은 6개의 지원 CLI에 따라 약간씩 다릅니다. 각 CLI가 서로 다른 "에이전트 완료" 훅 계약을 노출하기 때문입니다. **결과**는 동일합니다 — 에이전트는 워크플로 게이트가 실패하는 동안 중지할 수 없습니다 — 하지만 **메커니즘**은 다릅니다. 아래 표에 요약되어 있으며, `require-*-before-stop` 정책을 활성화하기 전에 이해할 가치가 있는 사용자가 볼 수 있는 특이점은 Pi에만 있습니다. -| CLI | 게이트 실행 시점 | 표시되는 내용 | +| CLI | 게이트 실행 시점 | 표시 내용 | |---|---|---| -| Claude Code | 동일한 에이전트 루프, 즉시 | Claude가 계속 작업합니다 — 문제를 수정한 후 다시 완료를 시도합니다. 사용자에게 보이는 중단 없음. | -| Codex | 동일한 에이전트 루프, 즉시 | Claude와 동일. | -| GitHub Copilot CLI | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Copilot의 `{decision:"block", reason}` 재시도 채널 사용 — Copilot CLI 1.0.41에 대해 경험적으로 검증됨). | -| Cursor Agent | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Cursor의 `{followup_message}` 채널 사용 — `loop_limit`으로 제한, 기본값 5회 재시도). | -| Gemini CLI | 동일한 에이전트 루프, 즉시 | Claude와 동일 (Gemini의 `{decision:"block", reason}` 채널을 `AfterAgent`에서 사용). | -| OpenCode | 동일한 에이전트 루프, 즉시 | Claude와 동일 (OpenCode의 `client.session.prompt(...)` SDK 호출을 `hookSpecificOutput.additionalContext`를 통해 라우팅). | -| **Pi (pi-coding-agent)** | **다음 사용자 턴** | **Pi는 게이트가 실행될 때 눈에 띄게 중단됩니다** — 에이전트 루프가 종료되고 프롬프트로 돌아옵니다. 그런 다음 다음에 프롬프트를 제출할 때 게이트가 실행됩니다: failproofai는 해당 턴의 시스템 프롬프트에 `MANDATORY ACTION REQUIRED` 지시문을 앞에 추가하여 LLM이 요청한 작업을 수행하기 전에 워크플로 단계(커밋, 푸시 등)를 완료하도록 안내합니다. | +| Claude Code | 동일한 에이전트 루프, 즉시 | Claude가 계속 작업합니다 — 문제를 수정한 후 다시 완료를 시도합니다. 사용자에게 중단이 표시되지 않습니다. | +| Codex | 동일한 에이전트 루프, 즉시 | Claude와 동일합니다. | +| GitHub Copilot CLI | 동일한 에이전트 루프, 즉시 | Claude와 동일합니다(Copilot의 `{decision:"block", reason}` 재시도 채널 사용 — Copilot CLI 1.0.41에서 경험적으로 확인됨). | +| Cursor Agent | 동일한 에이전트 루프, 즉시 | Claude와 동일합니다(Cursor의 `{followup_message}` 채널 사용 — `loop_limit`으로 제한, 기본 5회 재시도). | +| OpenCode | 동일한 에이전트 루프, 즉시 | Claude와 동일합니다(OpenCode의 `client.session.prompt(...)` SDK 호출이 `hookSpecificOutput.additionalContext`를 통해 라우팅됨). | +| **Pi (pi-coding-agent)** | **다음 사용자 턴** | **Pi는 게이트가 실행될 때 눈에 띄게 중지됩니다** — 에이전트 루프가 종료되고 프롬프트로 돌아갑니다. 그런 다음 다음 번에 프롬프트를 제출할 때 게이트가 실행됩니다: failproofai는 해당 턴의 시스템 프롬프트 앞에 `MANDATORY ACTION REQUIRED` 지시문을 추가하여 LLM이 요청한 작업을 수행하기 전에 워크플로 단계(커밋, 푸시 등)를 완료하도록 안내합니다. | -**Pi 제한사항.** Pi의 `AgentEndEvent`(Claude의 `Stop` 훅에 해당하는 업스트림)에는 Result 타입이 없습니다 — 실행될 때쯤이면 Pi의 에이전트 루프가 이미 종료된 상태입니다. Pi는 Claude / Copilot / Cursor / Gemini / OpenCode처럼 동일한 루프를 강제로 재시도할 수 없습니다. failproofai는 게이트를 Pi의 `before_agent_start` 이벤트(다음 사용자 프롬프트 후에 실행됨)로 이동하므로 워크플로 확인은 현재 턴이 아닌 다음 턴에 적용됩니다. +**Pi 제한 사항.** Pi의 `AgentEndEvent`(Claude의 `Stop` 훅에 해당하는 업스트림 이벤트)는 Result 타입이 없습니다 — 실행될 때 Pi의 에이전트 루프는 이미 종료된 상태입니다. Pi는 Claude / Copilot / Cursor / OpenCode처럼 동일한 루프를 강제로 재시도할 수 없습니다. failproofai는 게이트를 Pi의 `before_agent_start` 이벤트(다음 사용자 프롬프트 후 실행)로 이동시켜 워크플로 확인이 여전히 강제되도록 합니다 — 단, 현재 턴이 아닌 다음 턴에. -**실제로 의미하는 것:** +**실제로 의미하는 바:** -- Pi가 중단된 후, 거부 이유는 Pi 세션 id로 키된 인메모리에 캡처됩니다. 동일한 Pi 프로세스에서 다음에 제출하는 프롬프트가 이를 소비합니다: LLM은 시스템 프롬프트 상단에 `MANDATORY ACTION REQUIRED` 지시문을 보고, 커밋(또는 푸시 / PR 열기 / CI 대기)을 수행한 후 요청을 계속합니다. 캡처된 거부 이유는 일회성입니다 — 소비되면 게이트가 해제됩니다. -- 게이트는 Pi의 프로세스 수명에 의해 제한됩니다. 턴 사이에 Pi를 `Ctrl+C`하거나 종료하면 인메모리 항목이 프로세스와 함께 삭제되고 게이트가 놓칩니다. Claude, Copilot, Cursor, Gemini, OpenCode도 동일한 제한이 있습니다(에이전트를 종료하면 게이트가 놓침) — Pi는 에이전트가 게이트가 실행되기 전에 눈에 띄게 종료되므로 더 명확하게 보입니다. -- 보류 중인 거부는 어떤 이유로든(`new` / `resume` / `fork` / `quit`) `session_shutdown` 시에도 지워지므로, 이전 세션의 오래된 게이트가 동일한 Pi 프로세스에서 시작된 새 세션으로 누출될 수 없습니다. +- Pi가 중지된 후, 거부 이유는 Pi 세션 ID를 키로 메모리에 캡처됩니다. 동일한 Pi 프로세스에서 제출하는 바로 다음 프롬프트가 이를 처리합니다: LLM은 시스템 프롬프트 상단에 `MANDATORY ACTION REQUIRED` 지시문을 보고, 커밋(또는 푸시/PR 생성/CI 대기)을 수행한 후 요청을 계속 처리합니다. 캡처된 거부 이유는 한 번만 처리됩니다 — 처리되면 게이트가 해제됩니다. +- 게이트는 Pi 프로세스 수명으로 제한됩니다. 턴 사이에 Pi를 `Ctrl+C`하거나 종료하면, 인메모리 항목이 프로세스와 함께 삭제되어 게이트가 누락됩니다. Claude, Copilot, Cursor, OpenCode도 동일한 제한이 있습니다(에이전트를 종료하면 게이트가 누락됨) — Pi는 에이전트가 게이트 실행 전에 눈에 띄게 종료되기 때문에 더 명확하게 보일 뿐입니다. +- 보류 중인 거부는 어떤 이유로든(`new` / `resume` / `fork` / `quit`) `session_shutdown` 시에도 해제되므로, 이전 세션의 오래된 게이트가 동일한 Pi 프로세스에서 시작된 새 세션으로 누출될 수 없습니다. -동일 루프 재시도가 필요하다면 다른 6개의 지원 CLI 중 하나에서 `Stop` 정책을 실행하세요. 이 격차를 해소할 수 있는 `AgentEndEvent`의 향후 Result 타입에 대해 Pi 업스트림을 추적 중입니다. +Claude 스타일의 동일 루프 재시도가 필요하다면, 다른 5개의 지원 CLI 중 하나에서 `Stop` 정책을 실행하세요. Pi 업스트림에서 이 격차를 해소할 수 있는 `AgentEndEvent`의 향후 Result 타입을 추적하고 있습니다. ### `require-commit-before-stop` **이벤트:** Stop -**기본값:** 커밋되지 않은 변경 사항(수정됨, 스테이징됨, 또는 추적되지 않는 파일)이 있을 때 중단을 거부합니다. 작업 디렉토리가 깨끗하면 정보 메시지를 반환합니다. +**기본값:** 커밋되지 않은 변경 사항(수정, 스테이징, 또는 추적되지 않은 파일)이 있을 때 중지를 거부합니다. 작업 디렉토리가 깨끗할 때 정보 메시지를 반환합니다. -매개변수 없음. +파라미터 없음. --- ### `require-push-before-stop` **이벤트:** Stop -**기본값:** 푸시되지 않은 커밋이 있거나 현재 브랜치에 원격 추적 브랜치가 없을 때 중단을 거부합니다. 필요한 경우 추적 브랜치를 생성하기 위해 `git push -u`를 제안합니다. 리모트가 설정되지 않은 경우 fail-open 방식으로 동작합니다. +**기본값:** 푸시되지 않은 커밋이 있거나 현재 브랜치에 원격 추적 브랜치가 없을 때 중지를 거부합니다. 필요한 경우 추적 브랜치를 생성하기 위해 `git push -u`를 제안합니다. 원격이 설정되지 않은 경우 fail-open 방식으로 동작합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | 푸시할 리모트 이름. | +| `remote` | `string` | `"origin"` | 푸시할 원격 이름. | **예시:** @@ -771,15 +764,13 @@ Stop 적용은 지원되는 7개 CLI에서 각각 다른 "에이전트 완료" ### `require-pr-before-stop` **이벤트:** Stop -**기본값:** 현재 브랜치에 대한 풀 리퀘스트가 없거나 기존 PR이 병합 없이 닫힌 경우 중단을 거부합니다. `gh pr create`로 PR을 생성하도록 Claude에게 안내합니다. PR이 **병합**되면 정책은 허용하고(작업이 배포됨) 브랜치에서 전환하도록 힌트를 제공합니다(`git checkout main && git pull`). +**기본값:** 현재 브랜치에 대한 풀 리퀘스트가 없거나 기존 PR이 병합 없이 닫혔을 때 중지를 거부합니다. Claude에게 `gh pr create`로 PR을 생성하도록 안내합니다. PR이 **병합**되면, 정책은 허용하며(작업이 배포됨) 브랜치에서 전환하도록 힌트를 제공합니다(`git checkout main && git pull`). -매개변수 없음. +파라미터 없음. -이 정책은 [GitHub CLI](https://cli.github.com/) (`gh`)가 설치되어 인증되어 있어야 합니다. -풀 리퀘스트에 대한 읽기 액세스를 위해 `repo` 스코프가 있는 개인 액세스 토큰으로 -`gh auth login`을 실행하세요. `gh`가 설치되지 않았거나 인증되지 않은 경우 정책은 -fail-open 방식으로 동작하고 이유를 Claude에게 보고합니다. +이 정책을 사용하려면 [GitHub CLI](https://cli.github.com/)(`gh`)가 설치되어 인증되어 있어야 합니다. +풀 리퀘스트에 대한 읽기 접근을 위해 `repo` 스코프를 가진 개인 액세스 토큰으로 `gh auth login`을 실행하세요. `gh`가 설치되지 않았거나 인증되지 않은 경우, 정책은 fail-open으로 동작하고 이유를 Claude에게 보고합니다. --- @@ -787,21 +778,21 @@ fail-open 방식으로 동작하고 이유를 Claude에게 보고합니다. ### `require-no-conflicts-before-stop` **이벤트:** Stop -**기본값:** 현재 브랜치가 베이스 브랜치에 깨끗하게 병합될 수 없을 때 중단을 거부합니다. 정책은 먼저 해당 브랜치에 대한 GitHub의 `OPEN` PR이 있는지 확인합니다 — PR이 없으면 강제할 병합 대상이 없으므로 전체 정책이 allow로 단락됩니다. `OPEN` PR이 확인되면 두 가지 독립적인 프로브가 실행됩니다: +**기본값:** 현재 브랜치가 베이스 브랜치에 깨끗하게 병합될 수 없을 때 중지를 거부합니다. 정책은 먼저 해당 브랜치에 GitHub에서 `OPEN` 상태의 PR이 있는지 확인합니다 — PR이 없으면 강제할 병합 대상이 없으므로, 전체 정책이 단락되어 허용됩니다. `OPEN` PR이 확인되면, 두 가지 독립적인 프로브가 실행됩니다: -1. **로컬** — `git merge-tree --write-tree --name-only origin/ HEAD`. 충돌 시 거부 메시지에 충돌된 파일 이름이 포함되어 Claude가 정확히 무엇을 해결해야 하는지 알 수 있습니다. -2. **GitHub** — 사전 확인에서 이미 가져온 `gh pr view --json mergeable,state` 결과를 재사용합니다. 오래된 로컬 `origin/`가 놓칠 수 있는 충돌을 감지합니다 (예: 마지막 fetch 이후 누군가가 `main`에 충돌하는 PR을 병합한 경우). `CONFLICTING` 결과는 거부됩니다. `UNKNOWN` 결과도 거부되며 Claude에게 다시 중단을 시도하기 전에 약 10초 기다리고 재확인하도록 안내합니다 — 이는 GitHub가 재계산하는 동안의 false negative를 방지합니다. +1. **로컬** — `git merge-tree --write-tree --name-only origin/ HEAD`. 충돌이 발생하면, 거부 메시지에 충돌된 파일 이름이 포함되어 Claude가 정확히 무엇을 해결해야 하는지 알 수 있습니다. +2. **GitHub** — 사전 확인에서 이미 가져온 `gh pr view --json mergeable,state` 결과를 재사용합니다. 오래된 로컬 `origin/`가 놓칠 수 있는 충돌을 감지합니다(예: 마지막 fetch 이후 누군가가 `main`에 충돌하는 PR을 병합한 경우). `CONFLICTING` 결과는 거부됩니다. `UNKNOWN` 결과도 거부되며 Claude에게 다시 중지를 시도하기 전에 약 10초 대기하고 재확인하도록 안내합니다 — 이는 GitHub가 재계산하는 동안 거짓 음성을 방지합니다. -다음 경우에 전체 건너뜁니다(허용): `gh`가 설치되지 않음, 브랜치에 대한 PR이 없음, PR의 상태가 `OPEN`이 아님 (예: `MERGED`, `CLOSED`), 또는 `gh pr view`가 파싱 불가능한 출력을 반환. `origin/`가 로컬에 없거나 베이스보다 앞선 커밋이 없을 때도 fail-open 방식으로 동작합니다 — 이러한 Layer 1 폴스루는 허용하기 전에 캐시된 PR 병합 가능성을 계속 참조합니다. +다음 경우 완전히 건너뜁니다(허용): `gh`가 설치되지 않음, 브랜치에 PR이 없음, PR 상태가 `OPEN`이 아님(예: `MERGED`, `CLOSED`), 또는 `gh pr view`가 파싱 불가능한 출력을 반환함. 로컬에 `origin/`가 없거나 베이스보다 앞선 커밋이 없을 때도 fail-open으로 동작합니다 — 이러한 Layer 1 폴스루는 허용 전에 캐시된 PR 병합 가능성을 여전히 참조합니다. -**매개변수:** +**파라미터:** -| 매개변수 | 타입 | 기본값 | 설명 | +| 파라미터 | 타입 | 기본값 | 설명 | |-------|------|---------|-------------| | `baseBranch` | `string` | `"main"` | 충돌을 확인할 베이스 브랜치. | -이 정책에는 GitHub CLI (`gh`)가 필요합니다. 정책은 충돌 프로브를 실행하기 전에 `gh pr view`를 사용하여 `OPEN` PR이 존재하는지 확인합니다 — `gh` 없이는 정책이 allow로 단락됩니다. 풀 리퀘스트에 대한 읽기 액세스를 위해 `repo` 스코프가 있는 개인 액세스 토큰으로 `gh auth login`을 실행하세요. +이 정책을 사용하려면 GitHub CLI(`gh`)가 필요합니다. 정책은 충돌 프로브를 실행하기 전에 `gh pr view`를 사용하여 `OPEN` PR이 존재하는지 확인합니다 — `gh` 없이는 정책이 단락되어 허용됩니다. 풀 리퀘스트에 대한 읽기 접근을 위해 `repo` 스코프를 가진 개인 액세스 토큰으로 `gh auth login`을 실행하세요. --- @@ -809,15 +800,13 @@ fail-open 방식으로 동작하고 이유를 Claude에게 보고합니다. ### `require-ci-green-before-stop` **이벤트:** Stop -**기본값:** 현재 브랜치에서 CI 확인이 실패하거나 아직 실행 중일 때 중단을 거부합니다. GitHub Actions 워크플로 실행과 서드파티 봇 확인(예: CodeRabbit, SonarCloud, Codecov)을 모두 확인합니다. `skipped`, `cancelled`, `neutral` 결론은 실패로 처리하지 않습니다 (후자는 예를 들어 앱이 의도적으로 성공/실패 대신 neutral을 보고하는 외부 기여자 PR의 Socket Security 알림을 포함). 모든 확인이 통과되면 정보 메시지를 반환합니다. +**기본값:** 현재 브랜치에서 CI 확인이 실패하거나 아직 실행 중일 때 중지를 거부합니다. GitHub Actions 워크플로 실행과 서드파티 봇 확인(예: CodeRabbit, SonarCloud, Codecov)을 모두 확인합니다. `skipped`, `cancelled`, `neutral` 결론은 실패로 처리하지 않습니다(후자는 예를 들어 외부 기여자 PR에서 앱이 의도적으로 성공/실패 대신 neutral을 보고하는 Socket Security 알림을 커버합니다). 모든 확인이 통과되면 정보 메시지를 반환합니다. -매개변수 없음. +파라미터 없음. -이 정책은 [GitHub CLI](https://cli.github.com/) (`gh`)가 설치되어 인증되어 있어야 합니다. -Actions 워크플로 실행 및 Checks API에 대한 읽기 액세스를 위해 `repo` 스코프가 있는 -개인 액세스 토큰으로 `gh auth login`을 실행하세요. `gh`가 설치되지 않았거나 인증되지 않은 -경우 정책은 fail-open 방식으로 동작하고 이유를 Claude에게 보고합니다. +이 정책을 사용하려면 [GitHub CLI](https://cli.github.com/)(`gh`)가 설치되어 인증되어 있어야 합니다. +Actions 워크플로 실행 및 Checks API에 대한 읽기 접근을 위해 `repo` 스코프를 가진 개인 액세스 토큰으로 `gh auth login`을 실행하세요. `gh`가 설치되지 않았거나 인증되지 않은 경우, 정책은 fail-open으로 동작하고 이유를 Claude에게 보고합니다. --- @@ -826,7 +815,7 @@ Actions 워크플로 실행 및 Checks API에 대한 읽기 액세스를 위해 ## 개별 정책 비활성화 -설정 파일의 `enabledPolicies`에서 특정 정책을 제거하거나, 대시보드의 정책 탭에서 해제하세요. +설정의 `enabledPolicies`에서 특정 정책을 제거하거나, 대시보드의 Policies 탭에서 비활성화하세요. ```json { @@ -837,4 +826,4 @@ Actions 워크플로 실행 및 Checks API에 대한 읽기 액세스를 위해 } ``` -`enabledPolicies`에 나열되지 않은 정책은 `policyParams` 항목이 존재하더라도 실행되지 않습니다. \ No newline at end of file +`policyParams` 항목이 존재하더라도 `enabledPolicies`에 나열되지 않은 정책은 실행되지 않습니다. \ No newline at end of file diff --git a/docs/ko/cli/audit.mdx b/docs/ko/cli/audit.mdx index 2162ed39..e2e9ac87 100644 --- a/docs/ko/cli/audit.mdx +++ b/docs/ko/cli/audit.mdx @@ -1,25 +1,25 @@ --- title: 과거 세션 감사 (베타) -description: "과거 트랜스크립트에서 에이전트가 낭비적이거나 위험한 작업을 얼마나 자주 수행했는지 집계" +description: "과거 트랜스크립트에서 에이전트가 낭비하거나 위험한 행동을 한 빈도를 집계합니다" --- **베타 기능.** 초기 피드백을 수집하는 동안 감사 기능은 베타로 제공됩니다. - 다음 안정 버전 전까지 감지기 카탈로그 및 보고서 형식이 변경될 수 있습니다. - 이상한 점이 있으면 이슈를 열어 주세요. + 다음 안정 버전 출시 전까지 디텍터 카탈로그와 리포트 형식이 변경될 수 있습니다. + 문제가 있으면 이슈를 열어 주세요. 감사 기능은 과거 에이전트 CLI 트랜스크립트를 failproofai의 정책 엔진을 통해 재실행하고, -**`/audit` 대시보드 페이지**에 공유 가능한 시각적 보고서를 렌더링합니다 — -에이전트의 아키타입, 0~100점 점수, 그리고 어떤 정책이 무엇을 잡아냈을지 정확히 표시합니다. +**`/audit` 대시보드 페이지**에 공유 가능한 시각적 리포트를 렌더링합니다 — 에이전트의 아키타입, +0~100 점수, 그리고 어떤 정책이 무엇을 잡아냈는지 상세히 보여줍니다. ## 실행 방법 -세 가지 방법 모두 동일한 `/audit` 보고서로 연결됩니다. +세 가지 방법 모두 동일한 `/audit` 리포트로 이동합니다. -```bash npx (설치 불필요) +```bash npx (no install) npx -y failproofai audit ``` @@ -27,69 +27,64 @@ npx -y failproofai audit failproofai audit ``` -```bash failproofai (대시보드) +```bash failproofai (dashboard) failproofai ``` - - `npx -y failproofai audit`는 failproofai를 가져와 스캔을 실행하고 대시보드를 - 자동으로 열어줍니다 — 사전 설치가 필요 없습니다. + + `npx -y failproofai audit`는 failproofai를 가져와 스캔을 실행하고 대시보드를 자동으로 열어줍니다 — 사전 설치가 필요 없습니다. - `failproofai audit`는 터미널에서 스캔을 실행한 후 완료 시 자동으로 - `localhost:8020/audit`를 엽니다. + `failproofai audit`는 터미널에서 스캔을 실행한 후 완료되면 `localhost:8020/audit`을 자동으로 엽니다. - `failproofai`를 실행하고 네비게이션 바(Policies와 Projects 사이)에서 - **Audit**을 클릭하거나, `/audit`를 직접 열어주세요. + `failproofai`를 실행하고 내비게이션 바에서 **Audit**을 클릭하거나 (Policies와 Projects 사이에 위치), `/audit`으로 직접 이동합니다. - 사용법을 확인하려면 `failproofai audit -h` (또는 `--help`)를 실행하세요. 감사는 - **완전 오프라인**으로 실행됩니다 — 계정이나 네트워크가 필요 없습니다 — 그리고 - 대시보드는 `Ctrl+C`로 중지할 때까지 계속 서비스됩니다. + `failproofai audit -h` (또는 `--help`)를 실행하면 사용법을 확인할 수 있습니다. 감사는 **완전히 오프라인**으로 실행되며 — 계정이나 네트워크가 필요 없습니다 — `Ctrl+C`로 중지할 때까지 대시보드는 계속 서빙됩니다. -대시보드는 이 머신의 과거 에이전트 CLI 트랜스크립트(Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini)를 스캔하고, failproofai가 막도록 설계된 작업들 — env-var 검사, 강제 푸시, 불필요한 `cd ` 접두사, sleep 폴링 루프, 방금 편집한 파일 재읽기 등 — 을 에이전트가 얼마나 자주 수행했는지 보고합니다. +대시보드는 이 머신의 과거 에이전트 CLI 트랜스크립트(Claude Code, Codex, Copilot, Cursor, OpenCode, Pi)를 스캔하여 failproofai가 방지하도록 설계된 행동들 — 환경 변수 확인, 강제 푸시, 불필요한 `cd ` 접두사, sleep-polling 루프, 방금 편집한 파일 재읽기 등 — 이 얼마나 자주 발생했는지 리포트합니다. -각 트랜스크립트에 대해 모든 도구 사용 이벤트는 39개의 내장 정책 **및** 런타임 정책으로 아직 처리되지 않는 패턴을 잡아내는 8개의 감사 전용 감지기를 통해 재실행됩니다. 횟수는 모든 세션에 걸쳐 정책/감지기별로 집계됩니다. +각 트랜스크립트에 대해 모든 도구 사용 이벤트는 39개의 빌트인 정책 **및** 런타임 정책으로 아직 커버되지 않은 패턴을 감지하는 8개의 감사 전용 디텍터를 통해 재실행됩니다. 모든 세션에 걸쳐 정책/디텍터별로 횟수가 집계됩니다. ## 제공 내용 -`/audit` 페이지는 단일 화면의 공유 가능한 **포스터**와 그 아래 네 개의 섹션으로 구성됩니다: +`/audit` 페이지는 단일 화면의 공유 가능한 **포스터**와 그 아래 네 개 섹션으로 구성됩니다: -1. **포스터** — 에이전트의 정체성을 한눈에: **아키타입** (8가지 중 하나 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), 페르소나 키워드, 해당 아키타입의 희귀도, 그리고 등급 밴드가 표시된 **0~100 점수** (`S`부터 `bottom tier`까지). 공유용으로 설계 — X나 LinkedIn에 게시하거나 PNG로 다운로드하세요. -2. **`// strengths`** — 에이전트가 이미 잘 하고 있는 것을 스캔의 실제 수치로 표시 (예: clean-tool-call %, `0`번의 push-to-main 시도) — 관련 정책에 깨끗한 기록이 있는 경우에만 표시됩니다. -3. **`// quirks`** — 빠져나간 것들: failproofai가 잡아냈을 동작의 순위 테이블 — *마지막으로 발생한 시점*, *무엇이 빠져나갔는지* (그리고 막았을 내장 정책), *심각도*, 그리고 얼마나 자주 *발견되었는지* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — 처방된 수정 목록: 복사하여 붙여넣을 수 있는 `failproofai policy add `가 포함된 정책당 한 행, 그리고 모든 권장 사항을 한 번에 활성화하고 **예상 점수**를 표시하는 **install all** 버튼. -5. **`// come back better`** — 습관 만들기: 재감사 이메일 **알림** 설정 (`3d` / `7d` / `14d` / `30d`) 또는 지금 바로 재감사, **친구 초대**로 자신의 감사를 실행하게 하기 (failproof.ai에서 발송, Cc를 나에게). 알림과 초대는 로그인이 필요합니다 — [`failproofai auth`](/ko/cli/auth)를 참고하세요. +1. **포스터** — 한눈에 보는 에이전트 정체성: **아키타입** (8가지 중 하나 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), 페르소나 키워드, 아키타입의 희귀도, 등급 밴드가 포함된 **0~100 점수** (`S`부터 `bottom tier`까지). 공유에 최적화 — X나 LinkedIn에 게시하거나 PNG로 다운로드할 수 있습니다. +2. **`// strengths`** — 에이전트가 이미 잘 하고 있는 것들을 스캔의 실제 수치로 표시합니다 (예: clean-tool-call %, `0`회의 push-to-main 시도). 해당 정책의 기록이 깨끗한 경우에만 표시됩니다. +3. **`// quirks`** — 놓친 것들: failproofai가 잡아냈을 행동들의 순위 테이블 — 마지막 발생 *시점*, 놓친 *내용* (및 이를 차단했을 빌트인), *심각도*, 발생 *횟수* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — 처방된 수정 목록: 복사-붙여넣기 가능한 `failproofai policy add `가 포함된 정책별 행, 모든 권장 사항을 한 번에 활성화하는 **install all** 버튼, 그리고 적용 시의 **예상 점수**. +5. **`// come back better`** — 습관 만들기: 재감사 이메일 **리마인더** 설정 (`3d` / `7d` / `14d` / `30d`) 또는 지금 재감사, 그리고 **친구 초대**로 직접 감사를 실행하게 하기 (failproof.ai에서 발송, 참조로 본인 포함). 리마인더와 초대는 로그인이 필요합니다 — [`failproofai auth`](/ko/cli/auth)를 참조하세요. -## 감사 전용 감지기 +## 감사 전용 디텍터 -이는 실시간으로 (아직) 적용되지 않는 "비효율적인 동작" 패턴을 감지합니다. 감사 중에만 실행되며 라이브 도구 호출을 절대 차단하지 않습니다. +이 디텍터들은 실시간으로 (아직) 적용되지 않는 "비효율적 행동" 패턴을 감지합니다. 감사 중에만 실행되며 라이브 도구 호출을 차단하지 않습니다. -| 감지기 | 집계 내용 | +| 디텍터 | 집계 내용 | |---|---| -| `redundant-cd-cwd` | 명령이 이미 `cwd`에서 실행됨에도 `cd && …`로 시작하는 Bash 명령. | +| `redundant-cd-cwd` | 명령이 이미 `cwd`에서 실행되고 있음에도 `cd && …`로 시작하는 Bash 명령. | | `prefer-edit-over-read-cat` | 단일 소스 파일에 대한 `cat`/`head`/`tail`/`less`/`more` — `Read` 도구를 사용하세요. | | `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` 인플레이스 편집 — `Edit` 도구를 사용하세요. | -| `prefer-write-over-heredoc` | Heredoc / 멀티라인 `echo > file`로 파일 작성 — `Write` 도구를 사용하세요. | +| `prefer-write-over-heredoc` | Heredoc / 멀티라인 `echo > file` 파일 쓰기 — `Write` 도구를 사용하세요. | | `sleep-polling-loop` | 긴 `sleep N` (≥ 30초) 또는 `while …; sleep …; done` 폴링 루프. | | `find-from-root` | `find /`, `find /home`, `find /usr` 등 — `cwd`로 범위를 제한하세요. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, 훅 건너뛰기. | -| `reread-after-edit` | 같은 세션에서 `Edit`/`Write`한 직후 해당 파일을 `Read`. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, 훅 건너뜀. | +| `reread-after-edit` | 같은 세션에서 방금 `Edit`/`Write`한 파일을 `Read`. | ## 캐시 -- **트랜스크립트별 캐시** — `~/.failproofai/cache/audit/.json`에 `(mtime, size, engineVersion, detectorVersion)`를 키로 저장 — 트랜스크립트 또는 정책/감지기 코드가 변경되면 자동으로 무효화됩니다. 각 항목은 **TTL 메타데이터**로 `cachedAt` 타임스탬프도 저장합니다 (캐시 키의 일부가 아님); **7일**이 지난 항목은 읽기 시 거부되므로 오래된 결과가 진화하는 감지기 의도를 초과하지 않습니다. -- **전체 결과 캐시** — `~/.failproofai/audit-dashboard.json` (모드 0600). 재실행 없이 대시보드를 즉시 렌더링할 수 있게 해줍니다. **7일 TTL**을 초과하면 읽기 시 거부 — `/audit`는 빈 상태로 폴백하고 새로운 실행을 요청합니다. 보고서 하단의 `[ re-audit now ]`를 클릭하여 새로고침 — 재감사는 `noCache: true`를 전송하므로 트랜스크립트별 캐시를 우회하고 캐시된 결과 대신 모든 트랜스크립트를 재스캔합니다; 실행은 고정된 상단 스트립을 통해 진행 상황을 스트리밍하고 성공 시 결과를 현재 위치에서 교체합니다 (페이지 리로드 없음; 재감사 실패 시 이전 보고서 유지). +- **트랜스크립트별 캐시** 위치: `~/.failproofai/cache/audit/.json`, `(mtime, size, engineVersion, detectorVersion)`을 키로 사용 — 트랜스크립트나 정책/디텍터 코드가 변경되면 자동으로 무효화됩니다. 각 항목에는 **TTL 메타데이터**로 `cachedAt` 타임스탬프가 저장됩니다 (캐시 키의 일부가 아님); **7일**이 지난 항목은 읽기 시 거부되어 오래된 결과가 진화하는 디텍터 의도를 넘어서는 것을 방지합니다. +- **전체 결과 캐시** 위치: `~/.failproofai/audit-dashboard.json` (모드 0600). 대시보드가 내비게이션 시 재실행 없이 즉시 렌더링될 수 있게 합니다. **7일 TTL**이 지나면 읽기 시 거부되며 — `/audit`은 빈 상태로 돌아가 새로운 실행을 유도합니다. 리포트 하단의 `[ re-audit now ]`를 클릭하여 새로 고침 — 재감사는 `noCache: true`를 전송하므로 트랜스크립트별 캐시를 우회하고 캐시된 결과를 반환하는 대신 모든 트랜스크립트를 재스캔합니다; 실행은 상단 고정 스트립을 통해 진행 상황을 스트리밍하고 성공 시 결과를 인플레이스로 교체합니다 (페이지 새로고침 없음; 재감사 실패 시 이전 리포트가 유지됨). ## 참고 사항 - **변경 없음.** 감사는 읽기 전용 모드로 재실행됩니다. `warn-repeated-tool-calls`는 세션별 사이드카가 수정될 수 있으므로 건너뜁니다. -- **워크플로 정책 건너뜀.** `require-*-before-stop` 정책은 `Stop` 이벤트에서만 실행되고 라이브 git 상태에 대해 `execSync`를 수행합니다 — "2025년에 어떤 일이 일어났을까"에 대한 의미 있는 해석이 없으므로 감사 횟수에 나타나지 않습니다. -- **커스텀 정책 건너뜀.** 사용자 제공 커스텀 훅은 재실행되지 않습니다 (원래 세션 이후 변경되었을 수 있음). \ No newline at end of file +- **워크플로 정책 건너뜀.** `require-*-before-stop` 정책은 `Stop` 이벤트에서만 발동하고 라이브 git 상태에 대해 `execSync`를 실행합니다 — "2025년에 무슨 일이 있었을까"에 대한 의미 있는 해석이 없으므로 감사 횟수에 나타나지 않습니다. +- **커스텀 정책 건너뜀.** 사용자가 제공한 커스텀 훅은 재실행되지 않습니다 (원래 세션 이후 변경되었을 수 있기 때문입니다). \ No newline at end of file diff --git a/docs/ko/configuration.mdx b/docs/ko/configuration.mdx index c90507f9..214f49ff 100644 --- a/docs/ko/configuration.mdx +++ b/docs/ko/configuration.mdx @@ -1,28 +1,28 @@ --- title: 설정 -description: "설정 파일 형식, 세 가지 범위 시스템, 그리고 병합 규칙" +description: "설정 파일 형식, 세 가지 범위 시스템, 병합 규칙" icon: gear --- -failproofai는 JSON 설정 파일을 사용하여 어떤 정책이 활성화되어 있는지, 정책이 어떻게 동작하는지, 그리고 커스텀 정책을 어디에서 불러올지를 제어합니다. 설정은 팀과 쉽게 공유할 수 있도록 설계되어 있습니다. 저장소에 커밋하면 모든 개발자가 동일한 에이전트 안전망을 갖게 됩니다. +failproofai는 JSON 설정 파일을 사용하여 어떤 정책이 활성화되어 있는지, 정책이 어떻게 동작하는지, 그리고 커스텀 정책을 어디서 불러올지를 제어합니다. 설정은 팀과 쉽게 공유할 수 있도록 설계되어 있습니다 — 저장소에 커밋하면 모든 개발자가 동일한 에이전트 안전망을 갖게 됩니다. --- ## 설정 범위 -설정 범위는 세 가지이며, 우선순위 순서대로 평가됩니다: +우선순위 순으로 평가되는 세 가지 설정 범위가 있습니다: -| 범위 | 파일 경로 | 용도 | +| 범위 | 파일 경로 | 목적 | |------|-----------|------| | **project** | `.failproofai/policies-config.json` | 저장소별 설정, 버전 관리에 커밋 | -| **local** | `.failproofai/policies-config.local.json` | 개인 저장소별 오버라이드, gitignore 처리 | +| **local** | `.failproofai/policies-config.local.json` | 개인 저장소별 재정의, gitignore 처리 | | **global** | `~/.failproofai/policies-config.json` | 모든 프로젝트에 적용되는 사용자 수준 기본값 | -failproofai가 훅 이벤트를 수신하면, 현재 작업 디렉터리에 존재하는 세 파일을 모두 로드하여 병합합니다. +failproofai가 훅 이벤트를 받으면, 현재 작업 디렉토리에 존재하는 세 파일을 모두 불러와 병합합니다. ### 병합 규칙 -**`enabledPolicies`** - 세 범위의 합집합입니다. 어느 수준에서든 활성화된 정책은 적용됩니다. +**`enabledPolicies`** — 세 범위의 합집합입니다. 어느 수준에서든 활성화된 정책은 적용됩니다. ```text project: ["block-sudo"] @@ -32,13 +32,13 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← 중복 제거된 합집합 ``` -**`policyParams`** - 특정 정책에 대해 파라미터를 정의한 첫 번째 범위가 전적으로 우선합니다. 정책 파라미터 내부 값의 깊은 병합은 이루어지지 않습니다. +**`policyParams`** — 특정 정책에 대한 파라미터를 먼저 정의한 범위가 완전히 우선합니다. 정책 파라미터 내부에서는 깊은 병합이 이루어지지 않습니다. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project 우선, global 무시 +resolved: { allowPatterns: ["sudo apt-get update"] } ← project가 우선, global은 무시됨 ``` ```text @@ -46,12 +46,12 @@ project: (block-sudo 항목 없음) local: (block-sudo 항목 없음) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← global까지 내려감 +resolved: { allowPatterns: ["sudo systemctl status"] } ← global로 폴스루 ``` -**`customPoliciesPath`** - 이를 정의한 첫 번째 범위가 우선합니다. +**`customPoliciesPath`** — 먼저 정의한 범위가 우선합니다. -**`llm`** - 이를 정의한 첫 번째 범위가 우선합니다. +**`llm`** — 먼저 정의한 범위가 우선합니다. --- @@ -96,13 +96,13 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← global까지 내려 --- -## 필드 레퍼런스 +## 필드 참조 ### `enabledPolicies` 타입: `string[]` -활성화할 정책 이름 목록입니다. 이름은 `failproofai policies`에서 표시되는 정책 식별자와 정확히 일치해야 합니다. 전체 목록은 [기본 제공 정책](/ko/built-in-policies)을 참고하세요. +활성화할 정책 이름 목록입니다. 이름은 `failproofai policies`에 표시되는 정책 식별자와 정확히 일치해야 합니다. 전체 목록은 [기본 제공 정책](/ko/built-in-policies)을 참조하세요. `enabledPolicies`에 없는 정책은 `policyParams`에 항목이 있더라도 비활성 상태입니다. @@ -110,19 +110,19 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← global까지 내려 타입: `Record>` -정책별 파라미터 오버라이드입니다. 외부 키는 정책 이름이고, 내부 키는 정책별로 다릅니다. 각 정책의 사용 가능한 파라미터는 [기본 제공 정책](/ko/built-in-policies)에 설명되어 있습니다. +정책별 파라미터 재정의입니다. 외부 키는 정책 이름이고, 내부 키는 정책 고유의 항목입니다. 각 정책의 사용 가능한 파라미터는 [기본 제공 정책](/ko/built-in-policies)에 설명되어 있습니다. -파라미터가 있는 정책에 파라미터를 지정하지 않으면 정책의 기본값이 사용됩니다. `policyParams`를 전혀 설정하지 않은 사용자는 이전 버전과 동일하게 동작합니다. +정책에 파라미터가 있지만 직접 지정하지 않으면 정책의 기본값이 사용됩니다. `policyParams`를 전혀 설정하지 않은 사용자는 이전 버전과 동일하게 동작합니다. -정책 파라미터 블록 내의 알 수 없는 키는 훅 실행 시 무시되지만, `failproofai policies` 실행 시 경고로 표시됩니다. +정책의 파라미터 블록 내 알 수 없는 키는 훅 실행 시 조용히 무시되지만, `failproofai policies`를 실행하면 경고로 표시됩니다. -#### `hint` (공통 설정) +#### `hint` (공통 적용) 타입: `string` (선택 사항) -정책이 `deny` 또는 `instruct`를 반환할 때 reason에 추가되는 메시지입니다. 정책 자체를 수정하지 않고도 Claude에게 실행 가능한 안내를 제공할 때 사용합니다. +정책이 `deny` 또는 `instruct`를 반환할 때 사유에 추가되는 메시지입니다. 정책 자체를 수정하지 않고도 Claude에게 실행 가능한 안내를 제공할 때 사용합니다. -기본 제공, 커스텀(`custom/`), 프로젝트 컨벤션(`.failproofai-project/`), 사용자 컨벤션(`.failproofai-user/`) 등 모든 정책 유형에서 사용할 수 있습니다. +기본 제공 정책, 커스텀 정책(`custom/`), 프로젝트 컨벤션(`.failproofai-project/`), 사용자 컨벤션(`.failproofai-user/`) 등 모든 정책 유형에서 작동합니다. ```json { @@ -141,40 +141,40 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← global까지 내려 } ``` -`block-force-push`가 거부할 경우 Claude는 다음과 같은 메시지를 받습니다: *"Force-pushing is blocked. Try creating a fresh branch instead."* +`block-force-push`가 거부하면 Claude는 다음과 같은 메시지를 받습니다: *"Force-pushing is blocked. Try creating a fresh branch instead."* -문자열이 아닌 값과 빈 문자열은 무시됩니다. `hint`가 설정되지 않으면 동작이 변경되지 않습니다(하위 호환성 유지). +문자열이 아닌 값과 빈 문자열은 조용히 무시됩니다. `hint`가 설정되지 않으면 동작은 변경되지 않습니다(하위 호환). ### `customPoliciesPath` 타입: `string` (절대 경로) -커스텀 훅 정책이 포함된 JavaScript 파일의 경로입니다. `failproofai policies --install --custom ` 명령으로 자동 설정됩니다(경로는 저장 전에 절대 경로로 변환됩니다). +커스텀 훅 정책이 담긴 JavaScript 파일의 경로입니다. `failproofai policies --install --custom `를 실행하면 자동으로 설정됩니다(경로는 저장 전에 절대 경로로 변환됩니다). -파일은 훅 이벤트마다 새로 로드되며 캐싱이 없습니다. 작성 방법은 [커스텀 정책](/ko/custom-policies)을 참고하세요. +이 파일은 매 훅 이벤트마다 새로 불러오며, 캐싱이 없습니다. 작성 방법은 [커스텀 정책](/ko/custom-policies)을 참조하세요. ### 컨벤션 기반 정책 -명시적인 `customPoliciesPath` 외에도, failproofai는 `.failproofai/policies/` 디렉터리에서 정책 파일을 자동으로 검색하여 로드합니다: +명시적인 `customPoliciesPath` 외에도, failproofai는 `.failproofai/policies/` 디렉토리에서 정책 파일을 자동으로 검색하여 불러옵니다: -| 수준 | 디렉터리 | 범위 | -|------|-----------|------| +| 수준 | 디렉토리 | 범위 | +|------|----------|------| | 프로젝트 | `.failproofai/policies/` | 버전 관리를 통해 팀과 공유 | | 사용자 | `~/.failproofai/policies/` | 개인용, 모든 프로젝트에 적용 | -**파일 매칭:** `*policies.{js,mjs,ts}` 패턴과 일치하는 파일만 로드됩니다(예: `security-policies.mjs`, `workflow-policies.js`). 디렉터리 내 다른 파일은 무시됩니다. +**파일 매칭:** `*policies.{js,mjs,ts}` 패턴과 일치하는 파일만 불러옵니다(예: `security-policies.mjs`, `workflow-policies.js`). 디렉토리 내 다른 파일은 무시됩니다. -**별도 설정 불필요:** 컨벤션 정책은 `policies-config.json`에 항목을 추가할 필요가 없습니다. 디렉터리에 파일을 넣기만 하면 다음 훅 이벤트 시 자동으로 인식됩니다. +**설정 불필요:** 컨벤션 정책은 `policies-config.json`에 별도로 등록할 필요가 없습니다. 디렉토리에 파일을 넣기만 하면 다음 훅 이벤트 시 자동으로 인식됩니다. -**합집합 로딩:** 프로젝트와 사용자 컨벤션 디렉터리가 모두 스캔됩니다. 두 수준에서 일치하는 모든 파일이 로드됩니다(첫 번째 범위 우선 방식을 사용하는 `customPoliciesPath`와 다릅니다). +**합집합 로딩:** 프로젝트와 사용자 컨벤션 디렉토리 모두 검색됩니다. 두 수준의 일치 파일이 모두 로드됩니다(`customPoliciesPath`는 첫 번째 범위 우선 방식인 것과 달리). -자세한 내용과 예시는 [커스텀 정책](/ko/custom-policies)을 참고하세요. +자세한 내용과 예시는 [커스텀 정책](/ko/custom-policies)을 참조하세요. ### `llm` 타입: `object` (선택 사항) -AI 호출을 수행하는 정책을 위한 LLM 클라이언트 설정입니다. 대부분의 경우 필요하지 않습니다. +AI 호출을 수행하는 정책을 위한 LLM 클라이언트 설정입니다. 대부분의 설정에서는 필요하지 않습니다. ```json { @@ -189,20 +189,24 @@ AI 호출을 수행하는 정책을 위한 LLM 클라이언트 설정입니다. ## CLI에서 설정 관리하기 -`policies --install` 및 `policies --uninstall` 명령은 에이전트 CLI의 훅 설정 파일(훅 진입점)에 기록하며, `policies-config.json`은 직접 관리하는 파일입니다. 두 가지는 별개입니다: +`policies --install` 및 `policies --uninstall` 명령은 에이전트 CLI의 훅 설정 파일(훅 진입점)에 쓰고, `policies-config.json`은 직접 관리하는 파일입니다. 두 가지는 별개입니다: - **에이전트 CLI 설정** — 에이전트가 각 도구 사용 시 `failproofai --hook `를 호출하도록 지시합니다: - **Claude Code**: `~/.claude/settings.json` (사용자), `/.claude/settings.json` (프로젝트), `/.claude/settings.local.json` (로컬) - - **OpenAI Codex**: `~/.codex/hooks.json` (사용자), `/.codex/hooks.json` (프로젝트) — Codex는 `local` 범위가 없습니다 - - **GitHub Copilot CLI _(베타)_**: `~/.copilot/hooks/failproofai.json` (사용자), `/.github/hooks/failproofai.json` (프로젝트) — Copilot에는 `local` 범위가 없습니다. 훅 항목은 Copilot의 OS별 `bash`/`powershell` 명령 필드와 `timeoutSec`를 사용하며, 파일 최상단에 `version: 1` 마커가 있습니다. `events.jsonl` 레코드 스키마(공개 문서에 명시되지 않음)를 더 많은 실제 세션을 통해 검증 중이므로 Copilot CLI 지원은 **베타** 상태입니다. - - **Cursor Agent _(베타)_**: `~/.cursor/hooks.json` (사용자), `/.cursor/hooks.json` (프로젝트) — Cursor에는 `local` 범위가 없습니다. 훅 항목은 Claude 형식의 `{type, command, timeout}` 구조를 사용하지만(`bash`/`powershell` 분리 없음), Cursor의 [훅 스키마](https://cursor.com/docs/hooks)에 따라 camelCase 이벤트 키(`preToolUse`, `beforeSubmitPrompt` 등) 아래 플랫 배열로 저장되며 파일 최상단에 `version: 1` 마커가 있습니다. 핸들러는 `CURSOR_EVENT_MAP`을 통해 camelCase → PascalCase로 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. Cursor의 트랜스크립트 온디스크 형식(공개 문서에 명시되지 않음)을 더 많은 실제 설치를 통해 검증 중이므로 Cursor Agent 지원은 **베타** 상태입니다. - - **OpenCode _(베타)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (사용자), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (프로젝트) — OpenCode에는 `local` 범위가 없습니다. 다른 여섯 CLI와 달리 OpenCode에는 **외부 명령 훅 시스템이 없습니다**: `opencode.json`의 `plugin: []` 배열을 통해 명시적으로 등록된 인프로세스 JS/TS 플러그인을 로드합니다(`.opencode/plugins/`에서의 자동 검색은 opencode v1.14.33에서 플러그인이 로드되는 방식이 **아닙니다**). 설치 시 failproofai 바이너리를 서브프로세스로 호출하고 바이너리의 Claude 형식 JSON 응답을 플러그인 시맨틱으로 변환하는 작은 생성된 플러그인 심을 배치합니다: 도구 이벤트 거부 시 `throw new Error()`(도구 호출 취소), instruct와 `Stop`/`SubagentStop` 거부 시 `client.session.prompt(...)`(거부 이유를 다음 사용자 메시지로 제출 — `session.idle`은 알림 전용이고 거기서 throw는 no-op이므로 유일한 강제 재시도 채널), allow 시 no-op. 심은 도구 이름(소문자 → PascalCase, `OPENCODE_TOOL_MAP` 사용)과 도구 입력 인수 키(camelCase → snake_case, `Read`/`Write`/`Edit`용 `OPENCODE_TOOL_INPUT_MAP` 사용, 예: `filePath` → `file_path`, `oldString` → `old_string`)를 바이너리에 전달하기 전에 정규화하므로 `block-read-outside-cwd`, `block-env-files`, `block-secrets-write` 같은 경로 확인 기본 정책이 OpenCode 도구 호출에서도 변경 없이 동작합니다. 세션은 `~/.local/share/opencode/opencode.db`의 opencode SQLite DB에 저장되며, 대시보드의 세션 뷰어는 `opencode db --format json` 및 `opencode export `를 통해 읽습니다. 버전 간 동작 및 더 많은 실제 세션 검증 중이므로 OpenCode 지원은 **베타** 상태입니다. [OpenCode 플러그인 문서](https://opencode.ai/docs/plugins/)를 참고하세요. - - **Pi _(베타)_**: `~/.pi/agent/settings.json` (사용자), `/.pi/settings.json` (프로젝트) — Pi에는 `local` 범위가 없습니다. Pi는 시작 시 TypeScript 확장 패키지를 로드하며, 설정 파일은 `{"packages": ["./relative/path", …]}` 형식의 플랫 문자열 배열입니다. failproofai는 번들된 `pi-extension/` 디렉터리를 가리키는 단일 packages 배열 항목을 씁니다. 확장은 내부적으로 Pi의 `tool_call`/`user_bash`/`input`/`session_start` 이벤트를 구독하고 `failproofai --hook --cli pi`를 셸아웃합니다. 핸들러는 `PI_EVENT_MAP`을 통해 underscore_lower_snake_case → PascalCase로 이벤트를 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. 도구 입력 인수도 `PI_TOOL_INPUT_MAP`을 통해 정규화됩니다(Pi의 Read/Write/Edit는 `file_path` 대신 `path`를 전달하며, 최상위 키를 매핑하면 `block-env-files`와 `block-secrets-write`가 동작합니다 — `block-read-outside-cwd`는 이미 `path` 폴백이 있었습니다). Pi의 확장 API와 세션 로그 레이아웃이 안정화되는 동안 Pi 지원은 **베타** 상태입니다. - - **Gemini CLI _(베타)_**: `~/.gemini/settings.json` (사용자), `/.gemini/settings.json` (프로젝트) — Gemini에는 `local` 범위가 없습니다(failproofai가 노출하지 않는 `/etc/gemini-cli/settings.json`의 `system` 범위가 문서에 있습니다). 훅 항목은 Claude의 `{type, command, timeout}` 형식을 Gemini의 `{matcher, hooks: [...]}` 매처 스키마로 감싸며 기본적으로 `matcher: "*"`를 사용합니다. 이벤트는 PascalCase입니다(`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`). 핸들러는 `GEMINI_EVENT_MAP`을 통해 Claude 표준 이름으로 매핑합니다. 도구 이름은 snake_case입니다(`run_shell_command`, `read_file`, `write_file`, `replace` 등) — 핸들러는 `GEMINI_TOOL_MAP`을 통해 정규화하므로 기존 기본 제공 정책이 변경 없이 동작합니다. 정책 평가기는 Gemini의 플랫 `{decision: "deny", reason}` 형식(Gemini의 "Golden Rule" exit-0 계약에 따른 선호 형식), BeforeAgent/AfterTool/SessionStart의 컨텍스트 주입을 위한 `{hookSpecificOutput: {hookEventName, additionalContext}}`, 그리고 강제 재시도 시맨틱을 위한 AfterAgent의 `{decision: "block", reason}`을 반환합니다. 실제 적용 범위를 넓히는 동안 Gemini CLI 지원은 **베타** 상태입니다. [Gemini CLI 훅 문서](https://geminicli.com/docs/hooks/)를 참고하세요. - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**사용자 범위만** — Hermes에는 프로젝트/로컬 설정이 없습니다). Hermes는 Slack/Telegram **게이트웨이**이므로, 설치 한 번으로 모든 플랫폼(Slack/Telegram/cli/cron)과 내부 서브에이전트의 도구 호출을 가로챕니다. 훅 항목은 Hermes의 snake_case 이벤트(`pre_tool_call`/`post_tool_call`/`on_session_start`/`on_session_end`/`subagent_stop`)를 키로 하는 `hooks:` 맵 아래 `{command, timeout}` 쌍(timeout은 **초** 단위)입니다. 핸들러는 `HERMES_EVENT_MAP`으로 이벤트를, `HERMES_TOOL_MAP`으로 도구 이름을 정규화하므로 기본 제공 정책이 변경 없이 동작합니다. 설정은 주석 보존 YAML `Document` 라운드트립을 통해 편집되므로 운영자의 다른 설정이 유지되며, 설치 시 `hooks_auto_accept: true`로 설정되어 헤드리스 게이트웨이(TTY 없음)가 동의 프롬프트 없이 훅을 실행합니다. 평가기는 Hermes의 `{"decision":"block","reason"}` stdout 계약을 반환합니다(Hermes는 종료 코드를 무시합니다). **제한 사항:** Hermes에는 턴 종료 `Stop` 이벤트가 없으므로 `require-*-before-stop` 기본 정책은 동작하지 않습니다(해당 없음, 오류 아님). `instruct`는 allow-with-logged-note로 격하됩니다(추가 컨텍스트 채널 없음). 출력 시크릿 편집(`sanitize-*`)은 셸 훅 계약으로 도구 출력을 재작성할 수 없습니다. Hermes는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.hermes/state.db`에서 게이트웨이 세션을 직접 읽습니다. -- **`policies-config.json`** — failproofai에게 어떤 정책을 어떤 파라미터로 평가할지 지시합니다(모든 에이전트 CLI에 공통 적용) - -특정 에이전트를 대상으로 하려면 `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes`를 전달하세요(여러 개는 공백으로 구분하거나 반복 사용): + - **OpenAI Codex**: `~/.codex/hooks.json` (사용자), `/.codex/hooks.json` (프로젝트) — Codex에는 `local` 범위가 없습니다 + - **GitHub Copilot CLI _(베타)_**: `~/.copilot/hooks/failproofai.json` (사용자), `/.github/hooks/failproofai.json` (프로젝트) — Copilot에는 `local` 범위가 없습니다. 훅 항목은 Copilot의 OS 키 `bash`/`powershell` 명령 필드와 `timeoutSec`를 사용하며, 파일 최상위에 `version: 1` 마커를 포함합니다. Copilot CLI 지원은 공개 문서에 명시되지 않은 `events.jsonl` 레코드 스키마를 더 많은 실제 세션에서 검증하는 동안 **베타** 상태입니다. **VS Code Copilot Chat 에이전트 모드 (Preview)**는 `.github/hooks/*.json`, `~/.copilot/hooks/*.json`, `~/.claude/settings.json`에서 훅 설정을 읽으며(`chat.hookFilesLocations` 설정에 의해 제어), Claude 형식의 `{hookSpecificOutput:{permissionDecision:"deny",…}}` 계약을 사용합니다 — `copilot` 통합과 `claude` 통합(`~/.claude/settings.json`)이 이미 쓰는 정확한 경로이므로, `failproofai policies --install --cli copilot` (또는 `--cli claude`)는 별도의 `vscode` 통합 없이도 **VS Code 에이전트 모드에서 이미 적용됩니다** (VS Code의 검색 로그에서 라이브로 확인됨). + - **Cursor Agent _(베타)_**: `~/.cursor/hooks.json` (사용자), `/.cursor/hooks.json` (프로젝트) — Cursor에는 `local` 범위가 없습니다. 훅 항목은 Claude 형식의 `{type, command, timeout}` 구조를 사용하지만(`bash`/`powershell` 분리 없음), Cursor의 [훅 스키마](https://cursor.com/docs/hooks)에 따라 평탄한 배열 형태의 camelCase 이벤트 키(`preToolUse`, `beforeSubmitPrompt`, …) 하에 저장됩니다. 파일 최상위에 `version: 1` 마커를 포함합니다. 핸들러는 `CURSOR_EVENT_MAP`을 통해 camelCase → PascalCase로 정규화하므로 기존 기본 제공 정책이 그대로 작동합니다. Cursor Agent 지원은 공개 문서에 명시되지 않은 Cursor의 트랜스크립트 온디스크 형식을 더 많은 실제 설치에서 검증하는 동안 **베타** 상태입니다. + - **OpenCode _(베타)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (사용자), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (프로젝트) — OpenCode에는 `local` 범위가 없습니다. 다른 다섯 CLI와 달리 OpenCode는 **외부 명령 훅 시스템이 없습니다**: `opencode.json`의 `plugin: []` 배열에 명시적으로 등록된 인프로세스 JS/TS 플러그인을 로드합니다(`.opencode/plugins/`에서의 자동 검색은 opencode v1.14.33에서 플러그인이 로드되는 방식이 **아닙니다**). 설치 시 작은 생성 플러그인 심이 추가되며, 이 심은 failproofai 바이너리를 서브프로세스로 호출하고 바이너리의 Claude 형식 JSON 응답을 플러그인 시맨틱으로 변환합니다: 도구 이벤트 거부 시 `throw new Error()` (도구 호출 취소), instruct 및 `Stop` / `SubagentStop` 거부 시 `client.session.prompt(...)` (거부 사유를 다음 사용자 메시지로 제출 — `session.idle`은 알림 전용이고 거기서 throw는 no-op이므로 유일한 강제 재시도 채널), allow 시 no-op. 심은 도구 이름(`OPENCODE_TOOL_MAP`을 통해 소문자 → PascalCase)과 도구 입력 인수 키(`OPENCODE_TOOL_INPUT_MAP`을 통해 `Read` / `Write` / `Edit`의 camelCase → snake_case, 예: `filePath` → `file_path`, `oldString` → `old_string`)를 바이너리로 전달하기 전에 정규화하므로, `block-read-outside-cwd`, `block-env-files`, `block-secrets-write` 같은 경로 확인 내장 정책이 OpenCode 도구 호출에서도 그대로 작동합니다. 세션은 `~/.local/share/opencode/opencode.db`의 OpenCode SQLite DB에 저장됩니다. 대시보드의 세션 뷰어는 `opencode db --format json` 및 `opencode export `를 통해 읽습니다. OpenCode 지원은 버전 간 동작 및 더 많은 실제 세션을 검증하는 동안 **베타** 상태입니다. [OpenCode 플러그인 문서](https://opencode.ai/docs/plugins/)를 참조하세요. + - **Pi _(베타)_**: `~/.pi/agent/settings.json` (사용자), `/.pi/settings.json` (프로젝트) — Pi에는 `local` 범위가 없습니다. Pi는 시작 시 TypeScript 확장 패키지를 로드합니다. 설정 파일은 평탄한 문자열 배열 `{"packages": ["./relative/path", …]}` 형태입니다. failproofai는 번들된 `pi-extension/` 디렉토리를 가리키는 단일 패키지 배열 항목을 씁니다. 확장은 내부적으로 Pi의 `tool_call` / `user_bash` / `input` / `session_start` 이벤트를 구독하고 `failproofai --hook --cli pi`를 셸 아웃합니다. 핸들러는 `PI_EVENT_MAP`을 통해 underscore_lower_snake_case → PascalCase로 정규화하므로 기존 기본 제공 정책이 그대로 작동합니다. 도구 입력 인수도 `PI_TOOL_INPUT_MAP`을 통해 정규화됩니다(Pi의 Read / Write / Edit는 `file_path` 대신 `path`를 사용하며, 최상위 키를 매핑하면 `block-env-files`와 `block-secrets-write`가 작동합니다 — `block-read-outside-cwd`는 이미 `path` 폴백이 있었습니다). Pi 지원은 Pi의 확장 API와 세션 로그 레이아웃이 안정화되는 동안 **베타** 상태입니다. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**사용자 범위만** — Hermes에는 프로젝트/로컬 설정이 없습니다). Hermes는 Slack/Telegram **게이트웨이**이므로, 하나의 설치로 모든 플랫폼(Slack/Telegram/cli/cron)의 도구 호출과 내부 서브에이전트를 가로챕니다. 훅 항목은 Hermes의 snake_case 이벤트(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) 키의 `hooks:` 맵 하에 `{command, timeout}` 쌍(timeout 단위: **초**)입니다. 핸들러는 `HERMES_EVENT_MAP`으로 이벤트를, `HERMES_TOOL_MAP`으로 도구 이름을 정규화하므로 기본 제공 정책이 그대로 작동합니다. 설정은 주석 보존 YAML `Document` 라운드트립으로 편집되므로 운영자의 다른 설정이 유지되며, 설치 시 `hooks_auto_accept: true`로 설정하여 헤드리스 게이트웨이(TTY 없음)가 동의 프롬프트 없이 훅을 실행합니다. 평가기는 Hermes의 `{"decision":"block","reason"}` stdout 계약을 출력합니다(Hermes는 종료 코드를 무시합니다). **제한 사항:** Hermes에는 턴 종료 `Stop` 이벤트가 없으므로 `require-*-before-stop` 내장 정책은 절대 실행되지 않습니다(해당 없음, 오류 아님). `instruct`는 allow-with-logged-note로 저하됩니다(추가 컨텍스트 채널 없음). 출력 비밀 제거(`sanitize-*`)는 셸 훅 계약을 통해 도구 출력을 재작성할 수 없습니다. Hermes는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.hermes/state.db`에서 게이트웨이 세션을 직접 읽습니다. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**사용자 범위만** — OpenClaw에는 프로젝트/로컬 설정이 없습니다). Hermes처럼 OpenClaw는 자체 호스팅 멀티채널 **게이트웨이**이므로, 하나의 설치로 모든 채널과 내부 서브에이전트의 도구 호출을 가로챕니다. 적용은 OpenClaw의 **인프로세스 플러그인 훅**을 통해 실행됩니다(파일 기반 내부 훅은 관찰 전용으로 차단 불가). 따라서 OpenCode/Pi처럼 failproofai는 failproofai 바이너리를 비동기 스폰하고 판결을 변환하는 정적 `openclaw-plugin/` 패키지를 제공합니다. 설치 시 제공된 플러그인 디렉토리를 `openclaw.json`의 `plugins.load.paths[]`에 등록하고 `plugins.entries.failproofai` 하에 활성화합니다(`hooks.allowConversationAccess: true` 포함, 원시 대화 훅에 필요). 평가기는 평탄한 `{permission, reason}` 판결을 출력하고 심이 이를 각 훅의 기본 반환 형태로 매핑합니다: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), `before_agent_finalize → {action:"revise", reason}` (**Stop** — 실제 턴 종료 게이트이므로 `require-*-before-stop` 내장 정책이 Hermes와 달리 OpenClaw에서 **적용됩니다**). 이벤트와 도구 이름은 바이너리 측에서 `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP`(`exec→Bash`, `read→Read`, …)을 통해 정규화되므로 기본 제공 정책이 그대로 작동합니다. 심은 스폰/파싱/타임아웃 오류 시 열린 상태로 실패합니다. OpenClaw는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.openclaw/agents//sessions/.jsonl`의 JSONL 세션을 읽습니다. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (사용자), `/.factory/hooks.json` (프로젝트) — Factory에는 `local` 범위가 없습니다. droid는 Claude 스타일 외부 명령 훅 시스템을 탑재하지만, droid v0.171.0에서 라이브로 확인된 두 가지 특이점이 있습니다: (1) 이벤트 이름이 `hooks.json` **최상위 레벨**에 위치합니다 — **`"hooks"` 래퍼가 없습니다**(droid는 거부합니다). 도구 이벤트(`PreToolUse`/`PostToolUse`)는 `"matcher": "*"`를 포함하고, 비도구 이벤트는 생략합니다. (2) 거부는 JSON 결정이 아닌 훅 **종료 코드 2 + stderr**로 구동됩니다 — 평가기의 `factory` 분기는 도구/프롬프트 이벤트에서 종료 코드 2를 반환하고, 턴 종료 `Stop` 이벤트에서만 `{decision:"block", reason}`을 반환합니다(droid의 유일한 강제 재시도 채널). 이벤트는 이미 PascalCase입니다(이벤트 맵 없음). 페이로드는 Claude snake_case이며, 도구 이름만 `FACTORY_TOOL_MAP`(`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …)을 통해 정규화됩니다. Factory는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.factory/sessions//.jsonl`의 온디스크 JSONL 세션을 읽습니다. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (사용자), `/.devin/config.json` (프로젝트) — Devin에는 `local` 범위가 없습니다. Devin은 devin v3000.1.27에서 라이브로 확인된 **순수 Claude 클론**입니다: 표준 Claude `"hooks"` 래퍼 스키마를 사용하며(쓰기는 병합 보존 방식이므로 설정 파일의 다른 키 — `org_id`, `theme_mode`, … — 가 유지됨), 이미 PascalCase인 이벤트 이름(이벤트 맵 없음, 핸들러 분기 없음), Claude snake_case stdin 페이로드(정규화 없음)를 사용합니다. 평가기의 `devin` 분기는 종료 코드 0에서 **모든** 이벤트에 대해 `{"decision":"block","reason"}` JSON을 stdout으로 출력하여 거부합니다(확인됨 — 블록이 `--permission-mode dangerous`를 재정의함). 턴 종료 `Stop` 이벤트에서는 사유에 MANDATORY-ACTION 강제 재시도 문구가 포함되므로 `require-*-before-stop` 내장 정책이 적용됩니다. 도구 이름만 `DEVIN_TOOL_MAP`(`exec→Bash`; `tool_input.command`는 이미 표준형)을 통해 정규화됩니다. Devin은 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.local/share/devin/cli/sessions.db`의 SQLite 세션을 읽습니다(`sessions` 각 행에 실제 `working_directory`가 있어 Claude처럼 프로젝트 cwd별로 세션이 그룹화됩니다). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (사용자), `/.agents/hooks.json` (프로젝트) — Antigravity에는 `local` 범위가 없습니다. Factory/Devin과 달리 Antigravity는 agy v1.1.2에서 라이브로 확인된 **자체 계약**을 가집니다(Claude 클론 아님). `hooks.json`은 **이름 있는 훅** 스키마를 사용합니다: 최상위 키는 훅 *이름*(`"failproofai"`)이고 그 값은 이벤트→핸들러 맵입니다 — 도구 이벤트(`PreToolUse`/`PostToolUse`)는 핸들러를 `{matcher:"*", hooks:[…]}`로 감싸고, `PreInvocation`/`Stop`은 **평탄한** 핸들러 배열입니다(다른 이름 있는 훅은 보존됨). stdin 페이로드는 **camelCase protojson**(`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`)입니다 — failproofai는 정책 실행 전에 이를 snake_case로 정규화하고, `ANTIGRAVITY_TOOL_INPUT_MAP`을 통해 `run_command`의 PascalCase 인수(`CommandLine`/`Cwd`)를 매핑합니다. 평가기의 `antigravity` 분기는 Antigravity의 **자체** 응답 형태를 사용합니다: `{decision:"deny", reason}`은 도구/프롬프트를 차단하고(종료 0), `{decision:"continue", reason}`은 턴 종료 `Stop` 시 루프를 재진입하므로(따라서 `require-*-before-stop` 내장 정책이 적용됨), `{injectSteps:[{ephemeralMessage}]}`는 `PreInvocation`(→ `UserPromptSubmit`)에서 명령을 주입합니다. 도구 이름은 `ANTIGRAVITY_TOOL_MAP`(`run_command→Bash`, `view_file→Read`, …)을 통해 정규화됩니다. Antigravity는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl`의 평탄한 JSONL 트랜스크립트를 읽습니다(대화 인덱스는 `conversation_summaries.db`에 있음). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (사용자), `/.agents/plugins/failproofai/hooks/hooks.json` (프로젝트) — Goose에는 `local` 범위가 없습니다. 적용은 Goose의 **훅** 시스템인 크로스에이전트 **Open Plugins** 스펙을 사용합니다: 설치 시 `failproofai` 플러그인 디렉토리를 추가하면 Goose가 시작 시 자동 검색합니다(`~/.config/goose/config.yaml`에 자동 등록). `hooks.json`은 최상위 `"hooks"` 래퍼가 있는 Open Plugins 스키마를 사용하며, 모든 이벤트에서 matcher가 **생략됩니다** — 단순 `"*"`는 아무것도 매칭하지 않는 잘못된 정규식입니다(goose v1.43.0에서 라이브로 확인됨). 이벤트 이름은 이미 PascalCase입니다(이벤트 맵 없음). stdin 페이로드는 `event`/`working_dir`를 사용하며, 핸들러가 이를 `hook_event_name`/`cwd`로 정규화합니다. 평가기의 `goose` 분기는 종료 코드 0에서 `{"decision":"block","reason"}` JSON을 stdout으로 출력하며, **`PreToolUse`** 이벤트에서만 적용됩니다(goose ≥ v1.37.0에 탑재) — 이는 셸 도구에 대해 발생하며 **위임된 서브에이전트 내부에서도** 발생하므로, 단일 충분한 거부 지점입니다. 다른 훅 오류는 **열린 상태로** 실패합니다. Goose에는 **`Stop` 이벤트가 없으므로** `require-*-before-stop` 내장 정책은 적용되지 않습니다(Hermes와 동일). 도구 이름은 `GOOSE_TOOL_MAP`(`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …)을 통해 정규화되고, 경로 키는 `GOOSE_TOOL_INPUT_MAP`(`path`/`source` → `file_path`)을 통해 정규화됩니다. Goose는 **오프라인 감사** 소스이기도 합니다 — 대시보드는 `~/.local/share/goose/sessions/sessions.db`의 SQLite 세션을 읽습니다(각 `sessions` 행에 실제 `working_dir`가 있어 Devin처럼 프로젝트 cwd별로 세션이 그룹화됩니다. `--no-session` 스크래치 실행은 필터링됩니다). +- **`policies-config.json`** — failproofai가 어떤 정책을 어떤 파라미터로 평가할지를 지시합니다(모든 에이전트 CLI에서 공유됨) + +특정 에이전트를 대상으로 하려면 `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`를 전달하세요(공백으로 구분하거나 반복 사용하여 부분 집합 지정 가능): ```bash failproofai policies --install --cli codex --scope project @@ -210,23 +214,27 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -`--cli`를 생략하면 `failproofai`가 설치된 에이전트 CLI를 자동으로 감지합니다(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli`를 생략하면 `failproofai`가 설치된 에이전트 CLI를 자동으로 감지합니다(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **CLI 1개 감지** — 확인 없이 해당 CLI를 자동 선택합니다. -- **여러 CLI 감지** (대화형 터미널) — 화살표 키 단일 선택 프롬프트를 표시합니다. `Detected (N)` 섹션(전체 감지 CLI에 대한 `Install for all N detected` 통합 행 + 각 감지된 CLI 개별 항목)과, 사전 설치를 위한 모든 미감지 지원 CLI를 나열하는 `Not installed (M) · install hooks ahead of time` 섹션으로 구성됩니다(↑↓로 이동, Enter로 선택, ^C로 종료). 제거 흐름은 Detected 섹션만 표시합니다. -- **여러 CLI 감지** (비대화형 실행, TTY 없음, CI 등) — 확인 없이 감지된 모든 CLI에 설치합니다. -- **감지 없음** — `claude`로 폴백하며, PATH에서 에이전트 바이너리를 찾을 수 없다는 경고를 표시합니다. 훅 명령은 그래도 기록되므로 설치 즉시 활성화됩니다. +- **하나의 CLI 감지됨** — 프롬프트 없이 해당 CLI를 자동 선택합니다. +- **여러 CLI 감지됨** (대화형 터미널) — `Detected (N)` 섹션(`Install for all N detected` 집합 행 + 각 감지된 CLI 개별 항목)과 `Not installed (M) · install hooks ahead of time` 섹션(감지되지 않은 지원 CLI를 미리 설치 옵션으로 나열)으로 구성된 화살표 키 단일 선택 프롬프트를 표시합니다(↑↓로 이동, Enter로 선택, ^C로 종료). 제거 흐름에는 Detected 섹션만 표시됩니다. +- **여러 CLI 감지됨** (비대화형 실행, CI, TTY 없음) — 프롬프트 없이 감지된 모든 CLI에 설치합니다. +- **감지 없음** — `claude`로 폴백하며, PATH에서 에이전트 바이너리를 찾을 수 없다는 경고를 표시합니다. 훅 명령은 여전히 작성되므로 설치 후 즉시 활성화됩니다. `policies-config.json`은 언제든지 직접 편집할 수 있으며, 변경 사항은 재시작 없이 다음 훅 이벤트부터 즉시 적용됩니다. --- -## 예시: 팀 기본값이 포함된 프로젝트 수준 설정 +## 예시: 팀 기본값이 있는 프로젝트 수준 설정 `.failproofai/policies-config.json`을 저장소에 커밋하세요: @@ -247,4 +255,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -각 개발자는 팀원에게 영향을 주지 않고 개인 오버라이드를 위해 `.failproofai/policies-config.local.json`(gitignore 처리)을 생성할 수 있습니다. \ No newline at end of file +그러면 각 개발자는 `.failproofai/policies-config.local.json`(gitignore 처리됨)을 만들어 팀원에게 영향을 주지 않고 개인적인 재정의를 할 수 있습니다. \ No newline at end of file diff --git a/docs/ko/dashboard.mdx b/docs/ko/dashboard.mdx index eaa09fbc..80253ef6 100644 --- a/docs/ko/dashboard.mdx +++ b/docs/ko/dashboard.mdx @@ -1,14 +1,14 @@ --- title: 대시보드 -description: "에이전트 세션 모니터링, 툴 호출 검토 및 정책 관리" +description: "에이전트 세션 모니터링, 도구 호출 검토 및 정책 관리" icon: chart-line --- -failproofai 대시보드는 AI 에이전트 세션을 모니터링하고 정책을 관리하기 위한 로컬 웹 애플리케이션입니다. 자리를 비운 동안 에이전트가 무엇을 했는지 확인하세요. +failproofai 대시보드는 AI 에이전트 세션을 모니터링하고 정책을 관리하는 로컬 웹 애플리케이션입니다. 자리를 비운 사이 에이전트가 수행한 작업을 확인하세요. --- -## 대시보드 시작하기 +## 대시보드 시작 ```bash failproofai @@ -16,7 +16,7 @@ failproofai `http://localhost:8020`에서 열립니다. -대시보드는 파일 시스템에서 직접 데이터를 읽습니다 — Claude Code 프로젝트 폴더와 failproofai 설정 파일에서 읽어오며, 원격 서비스에는 아무것도 기록되지 않습니다. +대시보드는 파일 시스템에서 직접 읽습니다 — Claude Code 프로젝트 폴더와 failproofai 설정 파일을 읽어옵니다. 원격 서비스에는 아무것도 기록되지 않습니다. --- @@ -24,22 +24,22 @@ failproofai ### 프로젝트 -머신에서 발견된 모든 Claude Code, OpenAI Codex, GitHub Copilot CLI _(베타)_, Cursor Agent _(베타)_, OpenCode _(베타)_, Pi _(베타)_, Gemini CLI _(베타)_, Hermes 프로젝트를 나열합니다. Claude 프로젝트는 `~/.claude/projects/`(또는 `CLAUDE_PROJECTS_PATH`로 설정된 경로)에서 검색됩니다. Codex 프로젝트는 `~/.codex/sessions///
/*.jsonl` 아래의 모든 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에 기록된 `cwd`로 그룹화하여 검색됩니다. Copilot CLI 프로젝트는 각 `~/.copilot/session-state//workspace.yaml`(`COPILOT_HOME`으로 구성 가능)을 스캔하고 `cwd` 필드로 그룹화하여 검색됩니다. Cursor Agent 프로젝트는 `~/.cursor/agent-sessions//`(`CURSOR_HOME`으로 구성 가능, `conversations/` 및 `sessions/`가 폴백으로 검색됨) 아래의 세션별 메타데이터를 스캔하여 `meta.json` / `session.json` / `workspace.yaml`의 `cwd` 스칼라로 검색됩니다. OpenCode 프로젝트는 `opencode db --format json`을 통해 `~/.local/share/opencode/opencode.db`의 SQLite DB를 쿼리하여 검색되며(`session` 및 `project` 테이블을 읽고 `project_id`로 그룹화), Pi 프로젝트는 `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR`으로 구성 가능) 아래의 세션별 JSONL 트랜스크립트를 스캔하고 각 세션의 첫 번째 레코드에서 `cwd`를 가져와 검색됩니다. Gemini CLI 프로젝트는 `~/.gemini/tmp//chats/session--.jsonl`(`GEMINI_SESSIONS_DIR`으로 구성 가능)을 스캔하고 인접한 `.project_root` 텍스트 마커에서 정규 cwd를 복원하여 검색됩니다. Hermes 게이트웨이 세션은 `~/.hermes/state.db`(`HERMES_DB_PATH`으로 구성 가능)의 SQLite 저장소에서 직접 읽어오며 `source`(Slack/Telegram/cli/cron — 게이트웨이 세션에는 cwd가 없음)로 `hermes-` 프로젝트로 그룹화됩니다. 여러 CLI에서 사용된 프로젝트는 일치하는 모든 배지가 있는 단일 행으로 표시됩니다. 테이블 위의 **CLI** 드롭다운을 사용하여 특정 에이전트 CLI로 필터링하세요. URL은 선택 내용을 `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`로 보존합니다. +머신에서 발견된 모든 Claude Code, OpenAI Codex, GitHub Copilot CLI _(베타)_, Cursor Agent _(베타)_, OpenCode _(베타)_, Pi _(베타)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, Goose 프로젝트를 나열합니다. Claude 프로젝트는 `~/.claude/projects/`(또는 `CLAUDE_PROJECTS_PATH`로 설정된 경로)에서 탐색됩니다. Codex 프로젝트는 `~/.codex/sessions///
/*.jsonl` 아래의 모든 트랜스크립트를 스캔하여 각 세션의 첫 번째 레코드에 기록된 `cwd`를 기준으로 그룹화됩니다. Copilot CLI 프로젝트는 각 `~/.copilot/session-state//workspace.yaml`을 스캔하여(`COPILOT_HOME`으로 설정 가능) `cwd` 필드를 기준으로 그룹화됩니다. Cursor Agent 프로젝트는 `~/.cursor/agent-sessions//`(`CURSOR_HOME`으로 설정 가능, `conversations/` 및 `sessions/`가 폴백으로 탐색됨)의 세션별 메타데이터를 스캔하여 `meta.json` / `session.json` / `workspace.yaml`의 `cwd` 스칼라를 기준으로 탐색됩니다. OpenCode 프로젝트는 `~/.local/share/opencode/opencode.db`의 SQLite DB를 `opencode db --format json`을 통해 쿼리하여 탐색되며(`session` 및 `project` 테이블을 읽어 `project_id`로 그룹화), Pi 프로젝트는 `~/.pi/agent/sessions//_.jsonl`(`PI_SESSIONS_DIR`으로 설정 가능) 아래의 세션별 JSONL 트랜스크립트를 스캔하여 각 세션의 첫 번째 레코드에서 `cwd`를 추출합니다. Hermes 게이트웨이 세션은 `~/.hermes/state.db`(`HERMES_DB_PATH`로 설정 가능)의 SQLite 저장소에서 직접 읽어 `source`(Slack/Telegram/cli/cron — 게이트웨이 세션에는 cwd 없음)를 기준으로 `hermes-` 프로젝트로 그룹화됩니다. OpenClaw 게이트웨이 세션은 `~/.openclaw/agents//sessions/*.jsonl`에서 읽어 `openclaw-` 프로젝트로 그룹화됩니다(마찬가지로 cwd 없음). Factory Droid 프로젝트는 `~/.factory/sessions//*.jsonl`의 JSONL 트랜스크립트에서 탐색되어 cwd를 기준으로 그룹화됩니다. Devin 프로젝트는 `~/.local/share/devin/cli/sessions.db`의 SQLite DB에서(각 세션의 `working_directory`로 그룹화), Antigravity 프로젝트는 `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`의 JSONL 트랜스크립트에서 cwd를 기준으로 그룹화됩니다. Goose 프로젝트는 `~/.local/share/goose/sessions/sessions.db`의 SQLite DB에서(각 세션의 `working_dir`로 그룹화) 탐색됩니다. 여러 CLI에서 사용된 프로젝트는 일치하는 모든 배지를 포함하는 단일 행으로 표시됩니다. 표 위의 **CLI** 드롭다운을 사용하여 특정 에이전트 CLI로 필터링할 수 있으며, URL에 선택 항목이 `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`로 유지됩니다. -각 프로젝트에는 다음이 표시됩니다: +각 프로젝트에 표시되는 정보: - 프로젝트 이름 (폴더 경로에서 파생) -- CLI 배지 — `Claude Code` (주황색), `OpenAI Codex` (보라색), `GitHub Copilot` (파란색), `Cursor Agent` (에메랄드), `OpenCode` (호박색), `Pi` (분홍색), `Gemini CLI` (하늘색), 및/또는 `Hermes` (남색) +- CLI 배지 — `Claude Code` (주황), `OpenAI Codex` (보라), `GitHub Copilot` (파랑), `Cursor Agent` (에메랄드), `OpenCode` (앰버), `Pi` (핑크), 및/또는 `Hermes` (인디고) - 가장 최근 세션 활동 날짜 -프로젝트를 클릭하면 해당 세션이 표시됩니다. +프로젝트를 클릭하면 해당 세션을 확인할 수 있습니다. ### 세션 -프로젝트 내 모든 세션을 나열합니다. 각 세션에는 다음이 표시됩니다: +프로젝트 내의 모든 세션을 나열합니다. 각 세션에 표시되는 정보: - 세션 ID - 시작 및 종료 타임스탬프 -- 툴 호출 수 -- 훅 활동 수 (실행된 정책) +- 도구 호출 횟수 +- 훅 활동 횟수 (실행된 정책) 날짜 범위 필터와 세션 ID 검색을 사용하여 목록을 좁힐 수 있습니다. 세션은 페이지로 나뉩니다. @@ -47,44 +47,44 @@ failproofai ### 세션 뷰어 -세션 뷰어는 자율 에이전트에 대한 핵심 질문에 답합니다: 에이전트가 무엇을 했으며, 제대로 작동했는가? 헤더 옆의 CLI 배지는 세션이 Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI 또는 Hermes 트랜스크립트인지 나타냅니다. 세션에서 발생한 모든 일의 타임라인을 보여줍니다: +세션 뷰어는 자율 에이전트에서 가장 중요한 질문에 답합니다: 에이전트가 무엇을 했으며, 올바른 방향을 유지했는가? 헤더 옆의 CLI 배지는 해당 세션이 Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity, Goose 트랜스크립트 중 어느 것인지 나타냅니다. 세션에서 발생한 모든 사건의 타임라인이 표시됩니다: - **메시지** - Claude의 텍스트 응답과 사용자 프롬프트 -- **툴 호출** - Claude가 호출한 모든 툴, 입력 및 출력 포함 -- **정책 활동** - 각 툴 호출에 대해 어떤 정책이 실행되었고 어떤 결정을 내렸는지 +- **도구 호출** - Claude가 호출한 모든 도구와 입력 및 출력 +- **정책 활동** - 각 도구 호출에 대해 어떤 정책이 실행되었고 어떤 결정이 반환되었는지 -상단의 통계 바에는 세션 지속 시간, 총 툴 호출 수, 훅 결정 요약(allow / deny / instruct 수)이 표시됩니다. +상단의 통계 표시줄에는 세션 지속 시간, 총 도구 호출 횟수, 훅 결정 요약(allow / deny / instruct 횟수)이 표시됩니다. -**로그 다운로드** 버튼을 클릭하여 세션을 내보냅니다. Claude Code, Codex, Copilot, Cursor, Pi, Gemini 세션의 경우 디스크의 원본 JSONL 트랜스크립트를 바이트 단위로 그대로 받을 수 있으며, OpenCode(세션이 디스크가 아닌 SQLite에 저장됨)의 경우 기본 `session` / `messages` / `parts` 테이블을 미러링하는 JSON 문서를 받습니다. +**로그 다운로드** 버튼을 클릭하여 세션을 내보낼 수 있습니다. Claude Code, Codex, Copilot, Cursor, Pi 세션은 디스크에 저장된 원본 JSONL 트랜스크립트를 바이트 단위로 그대로 제공하며, OpenCode 세션(SQLite에 저장됨, 디스크 파일 없음)은 기본 `session` / `messages` / `parts` 테이블을 미러링한 JSON 문서를 제공합니다. ### 감사 -과거 세션에서 에이전트가 실제로 어떻게 동작했는지에 대한 개성 있는 보고서입니다. `failproofai audit` CLI와 동일한 스캔을 실행하지만 단일 화면 공유 가능 포스터 + 아래 4개 섹션으로 렌더링됩니다: +과거 세션 전반에 걸쳐 에이전트의 실제 행동 방식을 성격 기반으로 분석한 보고서입니다. `failproofai audit` CLI와 동일한 스캔을 실행하지만, 단일 화면에서 공유 가능한 포스터와 스크롤 아래의 네 가지 섹션으로 렌더링합니다: -1. **포스터** — 첫 번째 뷰포트를 채웁니다. failproof_ai 워드마크 + 감사 레이블 · 아키타입 인덱스(`№ NN of 08`) + 감사 날짜 · 수치 점수(0–100) + 백분위 순위 pill(`top 15%`) · 아키타입 이름(다음 중 하나: `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + 3개 키워드 스트립 · `// only N% of agents are this archetype` 희귀도 문구 · 8×8 픽셀 시길 타일 · `audit yours → failproof.ai` 푸터가 포함된 독립적인 PNG 캡처 영역. 캡처 박스 바로 바깥에 공유 버튼 3개가 있습니다: `post your archetype` (X 인텐트), `share on linkedin`, `download poster`. 캡처는 `html-to-image`를 통해 실행되므로 PNG가 화면 렌더링과 픽셀 단위로 일치합니다(점선 테두리, SVG 로고 마스크, 그라디언트, 폰트 메트릭 — 모두 보존). -2. **강점** — 에이전트가 이미 올바르게 수행하는 동작의 ✓ 행 목록으로, 라이브 감사 데이터(깔끔한 툴 호출 비율, main으로의 직접 푸시 없음, 자격 증명 누출 없음, 재시도 폭풍 없음)에서 도출됩니다 — 관련 정책이 감사 기간 동안 깨끗한 기록을 가진 경우에만 표시됩니다. -3. **문제점** — 심각도 순으로 정렬된 문제 테이블: `발생 시점 · 발생한 문제 + 이를 감지했을 정책 · 심각도 pill · 발생 횟수`, 재발 횟수는 `new` (1회), `N× seen` (2–9회), `recurring` (10회 이상)으로 표시됩니다. -4. **개선 방법** — 권장 정책별 행 목록: 흰색으로 표시된 정책 이름, 한 줄 설명, 오른쪽에 설치 명령 + 복사 버튼. 섹션 헤더는 `enable all N → projected · `(모든 수정 사항 적용 시 도달할 점수)로 표시되며, `[install all]` 버튼은 모든 권장 정책에 대한 `failproofai policy add a b c …` 명령을 복사합니다. -5. **더 나아지기** — 두 개의 나란히 배치된 카드. 왼쪽: 리마인더 설정(`3d` / `7d` / `14d` / `30d` 주기 선택기; 인증 후 `/api/auth/reminder`를 통해 유지). 오른쪽: failproof 혜택 잠금 해제 — `invite a friend`는 쉼표/공백/줄바꿈으로 구분된 친구 이메일 목록(발송당 최대 10개)을 입력하는 모달을 열고, `/api/audit/invite`에 POST하여 api-server의 `POST /v0/invite`로 전달합니다. api-server는 `invite@failproof.ai`에서 수신자별로 이메일을 발송하며, 발신자가 참조(Cc)로 포함되고 `Reply-To`가 설정되어 수신자는 초대한 사람이 누구인지 알 수 있고 발신자는 받은 편지함에서 복사본을 받습니다. 익명 사용자는 초대가 발송되기 전에 발신자의 이메일이 확인될 수 있도록 먼저 `AuthDialog`로 라우팅됩니다. 자격 / 혜택 이행은 후속 작업입니다. +1. **포스터** — 첫 번째 뷰포트를 채웁니다. failproof_ai 워드마크 + 감사 레이블 · 아키타입 인덱스(`№ NN of 08`) + 감사 날짜 · 숫자 점수(0–100) + 백분위 순위 필(`top 15%`) · 아키타입 이름(`the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost` 중 하나) + 3개 키워드 스트립 · `// only N% of agents are this archetype` 희귀도 문구 · 8×8 픽셀 시길 타일 · `audit yours → failproof.ai` 푸터가 포함된 독립적인 PNG 캡처 영역입니다. 캡처 박스 바로 바깥에 세 개의 공유 버튼이 있습니다: `post your archetype` (X 인텐트), `share on linkedin`, `download poster`. 캡처는 `html-to-image`를 통해 실행되므로 PNG가 화면 렌더링과 픽셀 단위로 일치합니다(점선 테두리, SVG 로고 마스크, 그라디언트, 폰트 메트릭 — 모두 보존). +2. **강점** — 에이전트가 이미 올바르게 수행하고 있는 행동의 차분한 ✓ 행 목록으로, 라이브 감사 데이터(깨끗한 도구 호출 비율, 메인에 직접 푸시 없음, 자격 증명 유출 없음, 재시도 폭풍 없음)에서 도출됩니다 — 관련 정책이 감사 기간 전반에 걸쳐 깨끗한 기록을 가진 경우에만 표시됩니다. +3. **특이점** — 심각도 순으로 정렬된 누락된 사항 표: `발생 시점 · 누락된 내용 + 이를 감지했을 정책 · 심각도 필 · 발생 횟수`, 여기서 재발 횟수는 `new`(1회), `N× seen`(2–9회), 또는 `recurring`(10회 이상)으로 표시됩니다. +4. **개선 방법** — 권장 정책별 차분한 행 목록: 흰색의 정책 이름, 한 줄 설명, 오른쪽에 설치 명령 + 복사 버튼. 섹션 헤더에는 `enable all N → projected · `(모든 수정 사항 적용 시 도달할 점수)가 표시되며, `[install all]` 버튼은 모든 권장 정책에 대한 `failproofai policy add a b c …` 명령 전체를 복사합니다. +5. **더 나아지기** — 나란히 배치된 두 카드. 왼쪽: 리마인더 설정(`3d` / `7d` / `14d` / `30d` 주기 선택기; 인증 후 `/api/auth/reminder`를 통해 유지). 오른쪽: failproof 특전 잠금 해제 — `invite a friend`는 쉼표/공백/줄바꿈으로 구분된 친구 이메일 목록을 입력받는 모달을 열고(전송당 최대 10개), `/api/audit/invite`에 POST하며, 이는 api-server의 `POST /v0/invite`로 전달됩니다. api-server는 `invite@failproof.ai`에서 수신자당 이메일 한 통을 보내며, 발신자는 Cc를 받고 `Reply-To`가 설정되어 수신자가 누가 초대했는지 알 수 있고 발신자도 받은 편지함에 사본을 받습니다. 익명 사용자는 초대가 발송되기 전에 발신자 이메일을 확인하기 위해 먼저 `AuthDialog`로 라우팅됩니다. 권한 부여 / 특전 이행은 후속 작업입니다. -`failproofai audit` 런타임으로 구동됩니다 — 기본 스캔 엔진, 지원되는 플래그, 트랜스크립트별 캐시 불변성은 [감사 CLI](/ko/cli/audit)를 참조하세요. 대시보드는 최신 결과를 `~/.failproofai/audit-dashboard.json`(모드 `0600`, 단일 슬롯, 새 실행 시 덮어쓰기)에 캐시하여 재방문이 즉각적으로 이루어지도록 합니다. **트랜스크립트별 캐시와 전체 결과 캐시 모두 7일이 지나면 읽기 시 거부됩니다** — 따라서 대시보드는 일주일 된 결과를 자동으로 제공하지 않으며, TTL이 지나면 `/audit`은 빈 상태로 전환되고 새로운 실행을 요청합니다. 보고서 하단의 `[ re-audit now ]`를 클릭하면 `noCache: true`로 `/api/audit/run`에 POST됩니다 — 재감사는 트랜스크립트별 캐시를 우회하고 캐시된 결과를 자동으로 반환하지 않고 모든 트랜스크립트를 처음부터 다시 스캔합니다 — 대시보드는 실행이 완료될 때까지 1Hz로 `/api/audit/status`를 폴링합니다. 실행 중에는 뷰포트 상단에 경과 타이머가 있는 고정 분홍색 진행 표시줄이 고정되며, 완료 시 새로운 결과가 즉시 교체됩니다(전체 페이지 새로고침 없음; 재감사 실패 시 이전 보고서는 그대로 유지). 실패 시 표시줄은 `RerunError.kind`(`timeout` / `network` / `post_failed`)에 따른 메시지와 함께 빨간색으로 전환됩니다. 빈 상태(캐시 없음 또는 만료)와 세션 없음 상태(캐시는 있지만 스캔에서 트랜스크립트를 찾지 못함)는 별도로 표시됩니다. +`failproofai audit` 런타임으로 구동됩니다 — 기본 스캔 엔진, 지원 플래그, 트랜스크립트별 캐시 불변성에 대한 자세한 내용은 [감사 CLI](/ko/cli/audit)를 참조하세요. 대시보드는 최신 결과를 `~/.failproofai/audit-dashboard.json`(모드 `0600`, 단일 슬롯, 새 실행 시 덮어씀)에 캐시하여 재방문 시 즉시 로딩됩니다. **트랜스크립트별 캐시와 전체 결과 캐시 모두 7일이 지나면 읽을 때 거부되므로** 대시보드가 일주일 된 결과를 조용히 제공하는 일이 없습니다 — TTL을 초과하면 `/audit`은 빈 상태로 폴스루되어 새로운 실행을 요청합니다. 보고서 하단 근처의 `[ re-audit now ]`를 클릭하면 `noCache: true`로 `/api/audit/run`에 POST됩니다 — 재감사는 트랜스크립트별 캐시를 우회하여 캐시된 결과를 조용히 반환하는 대신 모든 트랜스크립트를 처음부터 다시 스캔합니다 — 실행이 완료될 때까지 대시보드는 1Hz로 `/api/audit/status`를 폴링합니다. 실행 중에는 경과 시간 타이머와 함께 분홍색 진행 표시줄이 뷰포트 상단에 고정되며, 성공 시 새 결과가 전체 페이지 새로고침 없이 즉시 교체됩니다(재감사 실패 시 이전 보고서가 유지됨). 실패 시 표시줄이 빨간색으로 변하며 `RerunError.kind`(`timeout` / `network` / `post_failed`)에 따른 메시지가 표시됩니다. 빈 상태(캐시 없음 또는 만료됨)와 세션 없음 상태(캐시는 있지만 스캔에서 트랜스크립트를 찾지 못함)는 별도로 표시됩니다. ### 정책 -정책 관리 및 활동 검토를 위한 두 탭 페이지입니다. +정책 관리와 활동 검토를 위한 두 탭 페이지입니다. - - 단일 패널에서 failproofai가 보호할 에이전트 CLI를 다중 선택 — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI, Hermes 각각에 설치 상태(`Active` / `Detected` / `Inactive`), 사용자 범위 설정 경로, 브랜드 색상 강조가 있는 행이 있습니다. 원하는 CLI를 체크 또는 체크 해제하고 `Apply changes`를 클릭하면 한 번에 차이를 설치/제거합니다. PATH에서 바이너리가 감지된 CLI는 미리 체크됩니다. - - 단일 클릭으로 개별 정책을 켜거나 끕니다(`~/.failproofai/policies-config.json`에 기록 — 모든 설치된 CLI에서 공유됨) - - 정책을 펼쳐 매개변수를 구성합니다(`policyParams`를 지원하는 정책의 경우) - - 사용자 지정 정책 파일 경로 설정 + - 단일 패널에서 failproofai가 보호할 에이전트 CLI를 다중 선택 — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Hermes 각각의 행에 설치 상태(`Active` / `Detected` / `Inactive`), 사용자 범위 설정 경로, 브랜드 색상 강조가 표시됩니다. 원하는 CLI를 체크 또는 체크 해제하고 `Apply changes`를 클릭하면 차이분을 한 번에 설치/제거합니다. PATH에서 바이너리가 감지된 CLI는 미리 체크됩니다. + - 클릭 한 번으로 개별 정책 켜기/끄기 (`~/.failproofai/policies-config.json`에 기록 — 설치된 모든 CLI에서 공유) + - 정책을 확장하여 파라미터 설정 (`policyParams`를 지원하는 정책에 한함) + - 사용자 정의 정책 파일 경로 설정 - - 모든 세션에서 실행된 모든 훅 이벤트의 전체 페이지네이션 기록 - - 결정, 이벤트 유형, CLI(Claude Code / OpenAI Codex / GitHub Copilot _(베타)_ / Cursor Agent _(베타)_ / OpenCode _(베타)_ / Pi _(베타)_ / Gemini CLI _(베타)_ / Hermes), 정책 이름 또는 세션 ID로 필터링 - - 각 행에는 타임스탬프, 정책 이름, 결정, CLI 배지(주황색 = Claude Code, 보라색 = OpenAI Codex, 파란색 = GitHub Copilot, 에메랄드 = Cursor Agent, 호박색 = OpenCode, 분홍색 = Pi, 하늘색 = Gemini CLI, 남색 = Hermes), 툴 이름, 세션 ID, deny/instruct 결정 이유가 표시됩니다 - - 세션 ID를 클릭하면 트랜스크립트가 열립니다 — 뷰어는 어떤 CLI가 훅을 실행했는지(Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`)를 자동으로 감지하고 헤더에 일치하는 CLI 배지를 렌더링합니다 + - 모든 세션에서 실행된 모든 훅 이벤트의 전체 페이지네이션 히스토리 + - 결정, 이벤트 유형, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(베타)_ / Cursor Agent _(베타)_ / OpenCode _(베타)_ / Pi _(베타)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), 정책 이름, 세션 ID로 필터링 + - 각 행에 표시: 타임스탬프, 정책 이름, 결정, CLI 배지 (주황 = Claude Code, 보라 = OpenAI Codex, 파랑 = GitHub Copilot, 에메랄드 = Cursor Agent, 앰버 = OpenCode, 핑크 = Pi, 인디고 = Hermes, 청록 = OpenClaw, 로즈 = Factory Droid, 바이올렛 = Devin, 시안 = Antigravity, 라임 = Goose), 도구 이름, 세션 ID, deny/instruct 결정의 이유 + - 세션 ID를 클릭하면 해당 트랜스크립트가 열립니다 — 뷰어가 훅을 실행한 CLI를 자동 감지하고 (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) 헤더에 일치하는 CLI 배지를 렌더링합니다 @@ -92,13 +92,13 @@ failproofai ## 자동 새로고침 -대시보드 상단 탐색에는 자동 새로고침 토글이 있습니다. 활성화하면 현재 페이지가 주기적으로 새로고침되어 새로운 세션과 정책 활동이 나타날 때 표시됩니다. 장시간 실행되는 자율 에이전트 세션을 모니터링하는 데 필수적입니다. +대시보드 상단 내비게이션에는 자동 새로고침 토글이 있습니다. 활성화하면 현재 페이지가 주기적으로 새로고침되어 새 세션과 정책 활동이 나타나는 즉시 표시됩니다. 장시간 실행되는 자율 에이전트 세션을 모니터링할 때 필수적입니다. --- ## 페이지 비활성화 -대시보드의 일부 기능만 필요한 경우 `FAILPROOFAI_DISABLE_PAGES`를 쉼표로 구분된 페이지 이름 목록으로 설정하세요: +대시보드의 일부 기능만 필요한 경우, `FAILPROOFAI_DISABLE_PAGES`에 쉼표로 구분된 페이지 이름 목록을 설정하세요: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -108,9 +108,9 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai --- -## 프로젝트 경로 구성 +## 프로젝트 경로 설정 -기본적으로 대시보드는 표준 Claude Code 프로젝트 디렉토리에서 읽습니다. 사용자 정의 설정의 경우 재정의하세요: +기본적으로 대시보드는 표준 Claude Code 프로젝트 디렉토리에서 읽습니다. 사용자 정의 설정을 위해 재정의할 수 있습니다: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,15 +118,15 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## localhost가 아닌 호스트에서 접근하기 +## localhost가 아닌 호스트에서 접근 -**개발 모드**(`npm run dev`)에서 대시보드를 실행하고 localhost가 아닌 호스트 이름(예: 사용자 지정 도메인, 원격 IP, 터널링된 URL)에서 접근할 때 다음과 같은 경고가 표시될 수 있습니다: +**개발 모드**(`npm run dev`)로 대시보드를 실행하고 `localhost` 이외의 호스트 이름(예: 사용자 정의 도메인, 원격 IP, 터널 URL)에서 접근하는 경우 다음과 같은 경고가 표시될 수 있습니다: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -이는 Next.js가 개발 전용 기능인 HMR(핫 모듈 리로드) 웹소켓에 대한 크로스 오리진 접근을 차단하는 것입니다. 호스트를 허용하려면 `--allowed-origins` 플래그를 사용하세요: +이는 Next.js가 HMR(핫 모듈 리로드) 웹소켓에 대한 크로스 오리진 접근을 차단하는 것으로, 개발 전용 기능입니다. 호스트를 허용하려면 `--allowed-origins` 플래그를 사용하세요: ```bash npm run dev -- --allowed-origins dashboard.example.com @@ -138,12 +138,12 @@ npm run dev -- --allowed-origins dashboard.example.com npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -`FAILPROOFAI_ALLOWED_DEV_ORIGINS` 환경 변수를 대신 설정할 수도 있습니다: +또는 `FAILPROOFAI_ALLOWED_DEV_ORIGINS` 환경 변수를 대신 설정할 수 있습니다: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -이는 개발 모드에만 적용됩니다. `failproofai`(프로덕션 모드)를 실행할 때는 HMR 웹소켓과 크로스 오리진 개발 리소스 문제가 없습니다. +이는 개발 모드에만 적용됩니다. `failproofai`(프로덕션 모드)를 실행할 때는 HMR 웹소켓이 없으며 크로스 오리진 개발 리소스 문제도 없습니다. \ No newline at end of file diff --git a/docs/ko/getting-started.mdx b/docs/ko/getting-started.mdx index 6b7ff502..b4501670 100644 --- a/docs/ko/getting-started.mdx +++ b/docs/ko/getting-started.mdx @@ -31,15 +31,15 @@ bun add -g failproofai - 정책은 에이전트의 모든 도구 호출 전후에 실행되는 규칙입니다. 파괴적인 명령, 시크릿 유출, 그 외 여러 장애 상황을 피해가 발생하기 전에 차단합니다. + 정책은 에이전트의 모든 도구 호출 전후에 실행되는 규칙입니다. 파괴적인 명령, 시크릿 유출, 그 밖의 장애 유형을 피해가 발생하기 전에 차단합니다. ```bash failproofai policies --install ``` - 이 명령은 설치된 에이전트 CLI에 훅 항목을 기록합니다 (Claude Code의 `~/.claude/settings.json`, OpenAI Codex의 `~/.codex/hooks.json`, GitHub Copilot CLI의 `~/.copilot/hooks/failproofai.json`, Cursor Agent의 `~/.cursor/hooks.json`, OpenCode의 `~/.config/opencode/plugins/failproofai.mjs` 생성 플러그인 심 및 `~/.config/opencode/opencode.json`의 `plugin` 배열 등록 항목, Pi의 `~/.pi/agent/settings.json`, Gemini CLI의 `~/.gemini/settings.json`, Hermes의 `~/.hermes/config.yaml`). 둘 이상의 CLI가 설치되어 있으면 선택 프롬프트가 표시됩니다. `--cli claude codex copilot cursor opencode pi gemini hermes` (원하는 조합)를 전달하면 프롬프트를 건너뜁니다. + 이 명령은 설치된 에이전트 CLI의 훅 항목을 기록합니다 (Claude Code의 `~/.claude/settings.json`, OpenAI Codex의 `~/.codex/hooks.json`, GitHub Copilot CLI의 `~/.copilot/hooks/failproofai.json`, Cursor Agent의 `~/.cursor/hooks.json`, OpenCode의 `~/.config/opencode/plugins/failproofai.mjs` 생성 플러그인 심 및 `~/.config/opencode/opencode.json`의 `plugin` 배열 등록 항목, Pi의 `~/.pi/agent/settings.json`, Hermes의 `~/.hermes/config.yaml`, OpenClaw의 `~/.openclaw/openclaw.json`, Factory Droid의 `~/.factory/hooks.json`, Devin CLI의 `~/.config/devin/config.json`, Antigravity CLI의 `~/.gemini/config/hooks.json`, 또는 Goose의 `~/.agents/plugins/failproofai/hooks/hooks.json` 자동 검색 플러그인 디렉터리). 여러 CLI가 설치되어 있으면 선택 프롬프트가 표시됩니다. `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (원하는 조합)를 전달하면 프롬프트를 건너뛸 수 있습니다. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI 지원은 **베타** 단계입니다 — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, 또는 `--cli gemini`로 설치하세요. Hermes (hermes-agent, Slack/Telegram 게이트웨이)는 `--cli hermes`로 사용자 범위에 설치되며 오프라인 감사 소스이기도 합니다. + GitHub Copilot CLI, Cursor Agent, OpenCode, Pi 지원은 **베타** 상태입니다 — `--cli copilot`, `--cli cursor`, `--cli opencode`, 또는 `--cli pi`로 설치하세요. Hermes(hermes-agent, Slack/Telegram 게이트웨이)는 `--cli hermes`로 사용자 범위에 설치되며 **오프라인 감사 소스**이기도 합니다. OpenClaw(openclaw 게이트웨이, 자체 호스팅 멀티채널 어시스턴트)는 `--cli openclaw`로 사용자 범위에 설치되며 — 인프로세스 플러그인 훅(`before_agent_finalize`는 실제 턴 종료 게이트이므로 `require-*-before-stop` 내장 정책이 적용됨)을 통해 강제 실행됩니다 — **오프라인 감사 소스**이기도 합니다. Factory Droid(`droid`)는 `--cli factory`(사용자 + 프로젝트 범위)로 설치되며 **오프라인 감사 소스**이기도 합니다. Devin CLI(`devin`, Cognition)는 `--cli devin`(사용자 + 프로젝트 범위)으로 설치되며 **오프라인 감사 소스**이기도 합니다. Antigravity CLI(`agy`)는 `--cli antigravity`(사용자 + 프로젝트 범위)로 설치되며 **오프라인 감사 소스**이기도 합니다. Goose(코드명 goose, Block)는 `--cli goose`(사용자 + 프로젝트 범위)로 설치됩니다 — 인스톨러가 `~/.agents/plugins/failproofai/`에 플러그인 디렉터리를 생성하면 Goose가 자동으로 검색하며, **오프라인 감사 소스**이기도 합니다. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,17 +62,17 @@ bun add -g failproofai failproofai policies ``` - 모든 정책과 활성화 여부, 설정된 파라미터를 표시합니다. + 모든 정책, 활성화 여부, 설정된 파라미터를 표시합니다. ```bash failproofai ``` - `http://localhost:8020`에 로컬 대시보드를 열어 세션을 탐색하고, 도구 호출을 검사하며, 정책을 관리할 수 있습니다. + `http://localhost:8020`에서 로컬 대시보드를 열어 세션 탐색, 도구 호출 검사, 정책 관리를 할 수 있습니다. - 평소처럼 Claude Code를 시작하세요. 에이전트가 위험한 작업을 시도하면 failproofai가 자동으로 차단합니다. 에이전트를 무인으로 실행한 후 대시보드에서 결과를 확인하세요. + 평소처럼 Claude Code를 시작하세요. 에이전트가 위험한 작업을 시도하면 failproofai가 자동으로 차단합니다. 무인 상태로 실행해 두고 대시보드에서 결과를 확인하세요. @@ -76,7 +80,7 @@ bun add -g failproofai ## 정책 작동 방식 -에이전트가 도구를 실행할 때마다 Claude Code는 failproofai를 서브프로세스로 호출합니다. +에이전트가 도구를 실행할 때마다 Claude Code는 failproofai를 서브프로세스로 호출합니다: ```text Claude Code → failproofai --hook PreToolUse → reads stdin JSON @@ -84,21 +88,21 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON writes decision to stdout ``` -각 정책은 다음 세 가지 결정 중 하나를 반환합니다. +각 정책은 세 가지 결정 중 하나를 반환합니다: -- **allow** - 에이전트가 정상적으로 진행됩니다 -- **deny** - 작업이 차단되고 에이전트에게 이유가 전달됩니다 -- **instruct** - 에이전트의 프롬프트에 추가 컨텍스트가 삽입됩니다 +- **allow** - 에이전트가 정상적으로 진행 +- **deny** - 작업이 차단되고 에이전트에게 이유가 전달됨 +- **instruct** - 에이전트의 프롬프트에 추가 컨텍스트가 삽입됨 -정책은 로컬 프로세스에서 실행됩니다. 원격 서비스로는 아무것도 전송되지 않습니다. +정책은 로컬 프로세스에서 실행됩니다. 원격 서비스로 전송되는 데이터는 없습니다. --- ## 컨벤션 기반 정책으로 팀 정책 설정하기 -팀 전체에 품질 기준을 빠르게 적용하는 방법은 `.failproofai/policies/` 컨벤션을 활용하는 것입니다. 이 디렉터리에 정책 파일을 넣으면 자동으로 로드됩니다 — 별도의 플래그, 설정 변경, 설치 명령이 필요 없습니다. +팀 전체에 품질 기준을 가장 빠르게 정립하는 방법은 `.failproofai/policies/` 컨벤션을 활용하는 것입니다. 이 디렉터리에 정책 파일을 넣으면 자동으로 로드됩니다 — 플래그, 설정 변경, 설치 명령이 전혀 필요 없습니다. @@ -107,13 +111,13 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON ``` - 스타터 예제를 복사하거나 직접 작성하세요. + 스타터 예제를 복사하거나 직접 작성하세요: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - 또는 새로 작성하세요. + 또는 새 파일을 만드세요: ```js // .failproofai/policies/team-policies.mjs @@ -138,19 +142,19 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON git commit -m "Add team quality policies" ``` - failproofai를 설치한 모든 팀원이 이 정책을 자동으로 적용받습니다. 개발자별 별도 설정이 필요 없습니다. + failproofai가 설치된 모든 팀원이 이 정책을 자동으로 적용받습니다. 개발자별 별도 설정이 필요 없습니다. -`.failproofai/policies/`를 저장소에 커밋하면 팀 전체가 동일한 기준을 공유할 수 있습니다. 팀이 새로운 장애 유형을 발견할 때마다 정책을 추가하고 푸시하세요 — 모든 팀원이 다음 `git pull` 시 업데이트를 받습니다. 시간이 지남에 따라 이 정책들은 지속적으로 발전하는 살아있는 품질 기준이 됩니다. +`.failproofai/policies/`를 저장소에 커밋하면 팀 전체가 동일한 기준을 공유합니다. 새로운 장애 유형을 발견할 때마다 정책을 추가하고 푸시하면 모든 팀원이 다음 `git pull` 시 업데이트를 받습니다. 시간이 지날수록 이 정책들은 지속적으로 개선되는 살아있는 품질 기준이 됩니다. --- ## 데이터 저장 -모든 설정과 로그는 로컬 머신에 저장됩니다. +모든 설정과 로그는 로컬 머신에 저장됩니다: | 경로 | 저장 내용 | |------|----------------| @@ -177,11 +181,11 @@ failproofai policies --uninstall - 범위 및 설정 파일 형식 + 범위와 설정 파일 형식 - - 파라미터가 있는 26가지 정책 전체 목록 + + 파라미터를 포함한 26개의 전체 정책 diff --git a/docs/ko/introduction.mdx b/docs/ko/introduction.mdx index b48424a0..5140c324 100644 --- a/docs/ko/introduction.mdx +++ b/docs/ko/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI는 단 한 번의 설치로 루프, 시크릿 유출, 파괴적인 도구 호출 등을 감지하는 39가지 내장 실패 정책을 AI 에이전트에 제공합니다." +description: "FailproofAI는 루프, 시크릿 유출, 파괴적인 도구 호출 등을 잡아내는 39가지 내장 실패 정책을 단 한 번의 설치로 AI 에이전트에 제공합니다." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI 실패 처리**, **오류 복구**, **LLM 안정성**을 위한 훅과 정책 모음입니다. **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, **Agents SDK** 전반에 걸쳐 AI 에이전트를 안정적으로 자율 실행할 수 있도록 지원합니다. +**AI 실패 처리**, **오류 복구**, **LLM 안정성**을 위한 훅과 정책 모음입니다. **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, 그리고 **Agents SDK**에서 AI 에이전트가 안정적으로, 자율적으로 실행되도록 유지하세요. -AI 에이전트는 예측 가능한 방식으로 실패합니다. 파괴적인 명령을 실행하거나, 시크릿을 유출하거나, 작업 범위를 벗어나거나, 루프에 빠지거나, main 브랜치에 직접 푸시하기도 합니다. 방치하면 사소한 실패가 서비스 장애, 자격 증명 유출, 작업 손실로 이어질 수 있습니다. +AI 에이전트는 예측 가능한 방식으로 실패합니다. 파괴적인 명령을 실행하거나, 시크릿을 유출하거나, 작업에서 벗어나거나, 루프에 빠지거나, main 브랜치에 직접 푸시하는 일이 발생합니다. 방치하면 작은 실패가 서비스 장애, 자격 증명 유출, 작업 손실로 이어집니다. -FailproofAI는 **정책**으로 이 문제를 해결합니다. 정책은 모든 에이전트 도구 호출에 연결되어 **실패를 감지**하고, **완화 조치**(차단, 지시, 정제)를 취하며, 주의가 필요할 때 **알림을 보냅니다**. 로컬 대시보드에서는 이후에 모든 도구 호출, 에이전트 실패, 복구 조치를 확인할 수 있습니다. +FailproofAI는 **정책(policies)**으로 이 문제를 해결합니다. 이 규칙들은 모든 에이전트 도구 호출에 연결되어 **실패를 감지**하고, **완화**하며(차단, 지시, 정제), 주의가 필요한 상황이 발생하면 **알림을 보냅니다**. 로컬 대시보드에서 이후에 모든 도구 호출, 에이전트 실패, 복구 작업을 검토할 수 있습니다. -데이터는 사용자의 머신 밖으로 나가지 않습니다. +데이터는 외부로 전송되지 않습니다. ## 시작하기 - 파괴적인 명령 차단, 시크릿 유출 방지, 에이전트를 프로젝트 범위 내로 제한하는 기능 등을 기본 제공합니다. + 파괴적인 명령 차단, 시크릿 유출 방지, 에이전트의 프로젝트 경계 유지 등 다양한 기능을 기본 제공합니다. - 간단한 allow / deny / instruct API로 JavaScript 기반의 자체 규칙을 작성하세요. + 간단한 allow / deny / instruct API를 사용해 JavaScript로 직접 규칙을 작성하세요. - 자리를 비운 동안 에이전트가 무엇을 했는지 확인하세요. 세션을 탐색하고, 도구 호출을 검사하며, 정책이 발동된 지점을 검토할 수 있습니다. + 자리를 비운 사이 에이전트가 무엇을 했는지 확인하세요. 세션을 탐색하고, 도구 호출을 검사하며, 정책이 발동된 위치를 검토할 수 있습니다. - 코드 없이 모든 정책을 조정하세요. 프로젝트별 또는 전역으로 허용 목록, 보호 브랜치, 임계값을 설정할 수 있습니다. + 코드 없이 모든 정책을 조정하세요. 프로젝트별 또는 전역으로 허용 목록, 보호된 브랜치, 임계값을 설정할 수 있습니다. diff --git a/docs/pt-br/built-in-policies.mdx b/docs/pt-br/built-in-policies.mdx index 6d84b6c4..212c2012 100644 --- a/docs/pt-br/built-in-policies.mdx +++ b/docs/pt-br/built-in-policies.mdx @@ -1,14 +1,14 @@ --- title: Políticas Integradas -description: "Todas as 39 políticas integradas que detectam falhas comuns de agentes" +description: "Todas as 39 políticas integradas que detectam modos comuns de falha de agentes" icon: shield --- -failproofai vem com 39 políticas integradas que detectam falhas comuns de agentes. Cada política é acionada em um tipo específico de evento de hook e nome de ferramenta. Dezenove políticas aceitam parâmetros que permitem ajustar seu comportamento sem escrever código. Cinco políticas de fluxo de trabalho impõem um pipeline de commit → push → PR → CI antes que o Claude pare. +failproofai vem com 39 políticas integradas que detectam modos comuns de falha de agentes. Cada política é acionada em um tipo específico de evento de hook e nome de ferramenta. Dezenove políticas aceitam parâmetros que permitem ajustar seu comportamento sem escrever código. Cinco políticas de fluxo de trabalho impõem um pipeline de commit → push → PR → CI antes que Claude pare. --- -## Visão geral +## Visão Geral As políticas são agrupadas em categorias: @@ -26,14 +26,18 @@ As políticas são agrupadas em categorias: | [Fluxo de trabalho](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | - **`block-`** — impede o agente de prosseguir. -- **`warn-`** — fornece ao agente contexto adicional para que ele possa se corrigir. -- **`sanitize-`** — remove dados sensíveis da saída da ferramenta antes que o agente os veja. +- **`warn-`** — fornece ao agente contexto adicional para que ele possa se autocorrigir. +- **`sanitize-`** — remove dados sensíveis da saída da ferramenta antes que o agente a veja. ### Namespaces -Cada política vive em um slot `/`. As políticas integradas pertencem ao namespace **`failproofai/`** — por exemplo, `failproofai/sanitize-jwt`. O namespace previne colisões quando você também carrega políticas personalizadas ou de terceiros com nomes curtos similares. +Cada política vive em um slot `/`. As políticas integradas pertencem ao +namespace **`failproofai/`** — por exemplo, `failproofai/sanitize-jwt`. O +namespace evita colisões quando você também carrega políticas personalizadas ou de terceiros +com nomes curtos semelhantes. -Na sua configuração, você pode referenciar uma política integrada pelo nome curto ou pelo nome qualificado; ambas as formas resolvem para a mesma política: +Na sua configuração, você pode se referir a uma política integrada pelo seu nome curto ou pelo seu +nome qualificado; ambas as formas resolvem para a mesma política: ```json { @@ -44,27 +48,29 @@ Na sua configuração, você pode referenciar uma política integrada pelo nome } ``` -Se um nome não contém `/`, o failproofai o trata como pertencente ao namespace padrão `failproofai`. Nomes que já contêm `/` (ex.: `myorg/foo`, `custom/my-hook`) são mantidos como estão. +Se um nome não contém `/`, failproofai o trata como pertencente ao namespace padrão +`failproofai`. Nomes que já contêm `/` (ex.: `myorg/foo`, +`custom/my-hook`) são mantidos como estão. - **`require-`** — bloqueia o evento Stop até que as condições sejam atendidas. --- -Toda política suporta um campo opcional `hint` em `policyParams`. O hint é anexado à mensagem de deny ou instruct que o Claude vê, fornecendo orientação prática sem modificar o código da política. Funciona com políticas integradas, personalizadas e de convenção. Veja [Configuração → hint](/pt-br/configuration#hint-cross-cutting) para detalhes. +Toda política suporta um campo opcional `hint` em `policyParams`. O hint é adicionado à mensagem de deny ou instruct que Claude vê, fornecendo orientações práticas sem modificar o código da política. Funciona com políticas integradas, personalizadas e de convenção. Consulte [Configuração → hint](/pt-br/configuration#hint-cross-cutting) para mais detalhes. --- ## Comandos perigosos -Impede agentes de executar operações difíceis de desfazer ou que possam danificar o sistema host. +Evita que agentes executem operações difíceis de desfazer ou que possam danificar o sistema host. ### `block-sudo` **Evento:** PreToolUse (Bash) **Padrão:** Nega qualquer comando `sudo`. -Bloqueia invocações que incluem a palavra-chave `sudo`. A correspondência de padrões é feita em tokens de comando analisados, não na string bruta, para evitar bypass via injeção de operadores shell. +Bloqueia invocações que incluem a palavra-chave `sudo`. A correspondência de padrão é feita em tokens de comando analisados, não na string bruta, para evitar bypass via injeção de operador shell. **Parâmetros:** @@ -87,7 +93,7 @@ Bloqueia invocações que incluem a palavra-chave `sudo`. A correspondência de Com esta configuração, `sudo systemctl status nginx` é permitido, mas `sudo rm /etc/hosts` é negado. -Os padrões são comparados com tokens analisados, não com a string de comando bruta. Isso previne bypass via operadores shell anexados (ex.: `sudo systemctl status x; rm -rf /` não corresponde a `sudo systemctl status *`). +Os padrões são comparados com tokens analisados, não com a string de comando bruta. Isso evita bypass via operadores shell anexados (ex.: `sudo systemctl status x; rm -rf /` não corresponde a `sudo systemctl status *`). --- @@ -95,13 +101,13 @@ Os padrões são comparados com tokens analisados, não com a string de comando ### `block-rm-rf` **Evento:** PreToolUse (Bash) -**Padrão:** Nega `rm -rf`, `rm -fr`, e formas similares de exclusão recursiva. +**Padrão:** Nega `rm -rf`, `rm -fr` e formas semelhantes de exclusão recursiva. **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Caminhos seguros para exclusão recursiva (ex.: `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Caminhos que são seguros para excluir recursivamente (ex.: `/tmp`). | **Exemplo:** @@ -120,7 +126,7 @@ Os padrões são comparados com tokens analisados, não com a string de comando ### `block-curl-pipe-sh` **Evento:** PreToolUse (Bash) -**Padrão:** Nega `curl | bash`, `curl | sh`, `wget | bash`, e padrões similares. +**Padrão:** Nega `curl | bash`, `curl | sh`, `wget | bash` e padrões similares. Sem parâmetros. @@ -129,7 +135,7 @@ Sem parâmetros. ### `block-failproofai-commands` **Evento:** PreToolUse (Bash) -**Padrão:** Nega comandos que desinstalariam ou desabilitariam o próprio failproofai (ex.: `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Padrão:** Nega comandos que desinstalarem ou desabilitarem o próprio failproofai (ex.: `npm uninstall failproofai`, `failproofai policies --uninstall`). Sem parâmetros. @@ -137,9 +143,9 @@ Sem parâmetros. ## Comandos de infraestrutura -Impede agentes de codificação de executar CLIs de infraestrutura ou acionar pipelines de CI/CD. Todas as políticas nesta categoria são **opt-in** (`defaultEnabled: false`) — agentes que legitimamente precisam chamar `kubectl`, `terraform`, etc. não serão afetados a menos que você habilite a política. Quando habilitada, toda invocação da CLI correspondente é negada, a menos que o comando corresponda a uma entrada em `allowPatterns`. +Impede que agentes de codificação executem CLIs de infraestrutura ou acionem pipelines de CI/CD. Todas as políticas nesta categoria são **opt-in** (`defaultEnabled: false`) — agentes que legitimamente precisam chamar `kubectl`, `terraform` etc. não serão interrompidos a menos que você habilite a política. Quando habilitada, toda invocação da CLI correspondente é negada, a menos que o comando corresponda a uma entrada em `allowPatterns`. -A gramática de padrões é a mesma de [`block-sudo`](#block-sudo): os tokens são comparados com argv analisado, `*` é um curinga para um token, e qualquer comando contendo um operador shell autônomo (`&&`, `||`, `|`, `;`) ou um token com metacaracteres shell embutidos é rejeitado antes da correspondência da lista de permissões para evitar bypasses de injeção. +A gramática de padrões é a mesma de [`block-sudo`](#block-sudo): os tokens são comparados com argv analisado, `*` é um curinga para um token, e qualquer comando contendo um operador shell independente (`&&`, `||`, `|`, `;`) ou um token com metacaracteres shell embutidos é rejeitado antes da correspondência com a lista de permissões, para evitar bypasses de injeção. ### `block-kubectl` @@ -150,7 +156,7 @@ A gramática de padrões é a mesma de [`block-sudo`](#block-sudo): os tokens s | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos kubectl que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando kubectl que são permitidos. | **Exemplo:** @@ -177,7 +183,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos terraform/tofu que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando terraform/tofu que são permitidos. | **Exemplo:** @@ -202,7 +208,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos da CLI aws que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando da CLI aws que são permitidos. | **Exemplo:** @@ -227,7 +233,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos gcloud que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando gcloud que são permitidos. | **Exemplo:** @@ -252,7 +258,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos da CLI az que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando da CLI az que são permitidos. | **Exemplo:** @@ -277,7 +283,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Prefixos de comandos helm que são permitidos. | +| `allowPatterns` | `string[]` | `[]` | Prefixos de comando helm que são permitidos. | **Exemplo:** @@ -296,7 +302,7 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f ### `block-gh-pipeline` **Evento:** PreToolUse (Bash) -**Padrão:** Nega os seguintes subcomandos da CLI `gh` que mutam estado ou acionam pipelines: +**Padrão:** Nega os seguintes subcomandos da CLI `gh` que alteram estado ou acionam pipelines: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -305,13 +311,13 @@ Com esta configuração, `kubectl get pods` é permitido, mas `kubectl apply -f - `gh cache delete` - `gh secret set`, `gh secret delete` -Subcomandos `gh` somente leitura, como `gh pr view`, `gh pr list`, `gh run list`, `gh release view`, e `gh api repos/.../...`, **não** são correspondidos por esta política — eles são rotineiramente necessários para verificações de fluxo de trabalho (incluindo o próprio `require-ci-green-before-stop` do failproofai). +Subcomandos `gh` somente leitura, como `gh pr view`, `gh pr list`, `gh run list`, `gh release view` e `gh api repos/.../...`, **não** são correspondidos por esta política — eles são rotineiramente necessários para verificações de fluxo de trabalho (incluindo o próprio `require-ci-green-before-stop` do failproofai). **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Invocações específicas com script a serem permitidas mesmo que normalmente seriam negadas. | +| `allowPatterns` | `string[]` | `[]` | Invocações específicas com script a permitir, mesmo que normalmente fossem negadas. | **Exemplo:** @@ -329,7 +335,7 @@ Subcomandos `gh` somente leitura, como `gh pr view`, `gh pr list`, `gh run list` ## Segredos (sanitizadores) -Impede agentes de vazar credenciais em seu contexto ou saída. As políticas de sanitização são acionadas em eventos **PostToolUse**. Quando o Claude executa um comando Bash, lê um arquivo ou chama qualquer ferramenta, essas políticas inspecionam a saída antes que ela seja retornada ao Claude. Se um padrão de segredo for detectado, a política retorna uma decisão de deny que impede a saída de ser repassada. +Impede que agentes vazem credenciais em seu contexto ou saída. As políticas sanitizadoras são acionadas em eventos **PostToolUse**. Quando Claude executa um comando Bash, lê um arquivo ou chama qualquer ferramenta, essas políticas inspecionam a saída antes que ela seja retornada a Claude. Se um padrão de segredo for detectado, a política retorna uma decisão de deny que impede a saída de ser repassada. ### `sanitize-jwt` @@ -343,13 +349,13 @@ Sem parâmetros. ### `sanitize-api-keys` **Evento:** PostToolUse (todas as ferramentas) -**Padrão:** Redige formatos comuns de chaves de API: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), chaves de acesso AWS (`AKIA`), chaves Stripe (`sk_live_`, `sk_test_`), e chaves de API do Google (`AIza`). +**Padrão:** Redige formatos comuns de chave de API: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), chaves de acesso AWS (`AKIA`), chaves Stripe (`sk_live_`, `sk_test_`) e chaves de API do Google (`AIza`). **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Padrões regex adicionais a serem tratados como segredos. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Padrões regex adicionais a tratar como segredos. | **Exemplo:** @@ -380,7 +386,7 @@ Sem parâmetros. ### `sanitize-private-key-content` **Evento:** PostToolUse (todas as ferramentas) -**Padrão:** Redige blocos PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, etc.). +**Padrão:** Redige blocos PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` etc.). Sem parâmetros. @@ -397,14 +403,14 @@ Sem parâmetros. ## Ambiente -Protege configurações de ambiente sensíveis de serem lidas ou expostas por agentes. +Protege a configuração sensível de ambiente para que não seja lida ou exposta por agentes. ### `block-env-files` **Evento:** PreToolUse (Bash, Read) -**Padrão:** Nega a leitura de arquivos `.env` via `cat .env`, chamadas da ferramenta `Read` com `.env` como caminho de arquivo, etc. +**Padrão:** Nega a leitura de arquivos `.env` via `cat .env`, chamadas à ferramenta `Read` com `.env` como caminho do arquivo etc. -Não bloqueia `.envrc` ou outros arquivos relacionados a ambiente — somente arquivos com o nome exato `.env`. +Não bloqueia `.envrc` ou outros arquivos relacionados ao ambiente — apenas arquivos chamados exatamente `.env`. Sem parâmetros. @@ -426,7 +432,7 @@ Mantém os agentes trabalhando dentro dos limites do projeto e longe de arquivos ### `block-read-outside-cwd` **Evento:** PreToolUse (Read, Bash) -**Padrão:** Nega a leitura de arquivos fora da raiz do projeto. O limite é `CLAUDE_PROJECT_DIR` (definido uma vez por sessão pelo Claude Code), com fallback para o diretório de trabalho atual da sessão quando essa variável não está definida. Usar a raiz do projeto em vez do `cwd` ativo significa que o limite permanece estável mesmo após o Claude fazer `cd` para um subdiretório. +**Padrão:** Nega a leitura de arquivos fora da raiz do projeto. O limite é `CLAUDE_PROJECT_DIR` (definido uma vez por sessão pelo Claude Code), com fallback para o diretório de trabalho atual da sessão quando essa variável não está definida. Usar a raiz do projeto em vez do `cwd` ativo significa que o limite permanece estável mesmo após Claude fazer `cd` para um subdiretório. **Parâmetros:** @@ -451,13 +457,13 @@ Mantém os agentes trabalhando dentro dos limites do projeto e longe de arquivos ### `block-secrets-write` **Evento:** PreToolUse (Write, Edit) -**Padrão:** Nega escritas em arquivos comumente usados para chaves privadas e certificados: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Padrão:** Nega gravações em arquivos comumente usados para chaves privadas e certificados: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | Padrões de nome de arquivo adicionais (estilo glob) a serem bloqueados. | +| `additionalPatterns` | `string[]` | `[]` | Padrões de nome de arquivo adicionais (estilo glob) a bloquear. | **Exemplo:** @@ -475,7 +481,7 @@ Mantém os agentes trabalhando dentro dos limites do projeto e longe de arquivos ## Git -Previne pushes acidentais, force-pushes e erros de branch difíceis de desfazer. +Evita pushes acidentais, force-pushes e erros de branch difíceis de desfazer. ### `block-push-master` @@ -486,7 +492,7 @@ Previne pushes acidentais, force-pushes e erros de branch difíceis de desfazer. | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Nomes de branches que não podem receber push diretamente. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Nomes de branch que não podem receber push direto. | **Exemplo:** @@ -501,7 +507,7 @@ Previne pushes acidentais, force-pushes e erros de branch difíceis de desfazer. ``` -Para permitir push em todos os branches (desabilitando efetivamente esta política sem removê-la de `enabledPolicies`), defina `protectedBranches: []`. +Para permitir push para todos os branches (desabilitando efetivamente esta política sem removê-la de `enabledPolicies`), defina `protectedBranches: []`. --- @@ -509,13 +515,13 @@ Para permitir push em todos os branches (desabilitando efetivamente esta políti ### `block-work-on-main` **Evento:** PreToolUse (Bash) -**Padrão:** Nega `git commit`, `git merge`, `git rebase`, e `git cherry-pick` enquanto a árvore de trabalho está em `main` ou `master`. Criação e troca de branches (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) não são afetados. +**Padrão:** Nega `git commit`, `git merge`, `git rebase` e `git cherry-pick` enquanto a árvore de trabalho está em `main` ou `master`. Criação e troca de branch (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) não são afetadas. **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Nomes de branches nos quais commit/merge/rebase/cherry-pick é negado. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Nomes de branch nos quais commit/merge/rebase/cherry-pick é negado. | --- @@ -524,7 +530,7 @@ Para permitir push em todos os branches (desabilitando efetivamente esta políti **Evento:** PreToolUse (Bash) **Padrão:** Nega `git push --force` e `git push -f`. -Sem parâmetros específicos de política. Use o [`hint`](/pt-br/configuration#hint-cross-cutting) transversal para sugerir alternativas: +Sem parâmetros específicos da política. Use o [`hint`](/pt-br/configuration#hint-cross-cutting) transversal para sugerir alternativas: ```json { @@ -541,7 +547,7 @@ Sem parâmetros específicos de política. Use o [`hint`](/pt-br/configuration#h ### `warn-git-amend` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a prosseguir com cuidado ao executar `git commit --amend`. Não bloqueia o comando. +**Padrão:** Instrui Claude a prosseguir com cuidado ao executar `git commit --amend`. Não bloqueia o comando. Sem parâmetros. @@ -550,7 +556,7 @@ Sem parâmetros. ### `warn-git-stash-drop` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a confirmar antes de executar `git stash drop`. Não bloqueia o comando. +**Padrão:** Instrui Claude a confirmar antes de executar `git stash drop`. Não bloqueia o comando. Sem parâmetros. @@ -559,7 +565,7 @@ Sem parâmetros. ### `warn-all-files-staged` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a revisar o que está sendo adicionado ao stage quando executa `git add -A` ou `git add .`. Não bloqueia o comando. +**Padrão:** Instrui Claude a revisar o que está adicionando ao stage ao executar `git add -A` ou `git add .`. Não bloqueia o comando. Sem parâmetros. @@ -572,7 +578,7 @@ Detecta operações SQL destrutivas antes que sejam executadas no banco de dados ### `warn-destructive-sql` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a confirmar antes de executar SQL contendo `DROP TABLE`, `DROP DATABASE`, ou `DELETE` sem uma cláusula `WHERE`. +**Padrão:** Instrui Claude a confirmar antes de executar SQL contendo `DROP TABLE`, `DROP DATABASE` ou `DELETE` sem uma cláusula `WHERE`. Sem parâmetros. @@ -581,7 +587,7 @@ Sem parâmetros. ### `warn-schema-alteration` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a confirmar antes de executar instruções `ALTER TABLE`. +**Padrão:** Instrui Claude a confirmar antes de executar instruções `ALTER TABLE`. Sem parâmetros. @@ -589,12 +595,12 @@ Sem parâmetros. ## Avisos -Fornece contexto extra aos agentes antes de operações potencialmente arriscadas, mas não destrutivas. +Fornece aos agentes contexto extra antes de operações potencialmente arriscadas, mas não destrutivas. ### `warn-large-file-write` **Evento:** PreToolUse (Write) -**Padrão:** Instrui o Claude a confirmar antes de escrever arquivos maiores que 1024 KB. +**Padrão:** Instrui Claude a confirmar antes de gravar arquivos maiores que 1024 KB. **Parâmetros:** @@ -615,7 +621,7 @@ Fornece contexto extra aos agentes antes de operações potencialmente arriscada ``` -O handler do hook impõe um limite de 1 MB no stdin para payloads. Para testar esta política com conteúdo pequeno, defina `thresholdKb` para um valor bem abaixo de 1024. +O handler de hook impõe um limite de 1 MB de stdin em payloads. Para testar esta política com conteúdo pequeno, defina `thresholdKb` com um valor bem abaixo de 1024. --- @@ -623,7 +629,7 @@ O handler do hook impõe um limite de 1 MB no stdin para payloads. Para testar e ### `warn-package-publish` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a confirmar antes de executar `npm publish`. +**Padrão:** Instrui Claude a confirmar antes de executar `npm publish`. Sem parâmetros. @@ -632,7 +638,7 @@ Sem parâmetros. ### `warn-background-process` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a ter cuidado ao iniciar processos em segundo plano via `nohup`, `&`, `disown`, ou `screen`. +**Padrão:** Instrui Claude a ter cuidado ao iniciar processos em segundo plano via `nohup`, `&`, `disown` ou `screen`. Sem parâmetros. @@ -641,7 +647,7 @@ Sem parâmetros. ### `warn-global-package-install` **Evento:** PreToolUse (Bash) -**Padrão:** Instrui o Claude a confirmar antes de executar `npm install -g`, `yarn global add`, ou `pip install` sem um ambiente virtual. +**Padrão:** Instrui Claude a confirmar antes de executar `npm install -g`, `yarn global add` ou `pip install` sem um ambiente virtual. Sem parâmetros. @@ -649,21 +655,21 @@ Sem parâmetros. ## Gerenciadores de pacotes -Define quais gerenciadores de pacotes o agente está autorizado a usar. +Define quais gerenciadores de pacotes o agente pode usar. ### `prefer-package-manager` **Evento:** PreToolUse (Bash) -**Padrão:** Desabilitado. Quando habilitado, bloqueia qualquer comando de gerenciador de pacotes que não esteja na lista `allowed` e instrui o Claude a reescrever o comando usando um gerenciador permitido. +**Padrão:** Desabilitado. Quando habilitado, bloqueia qualquer comando de gerenciador de pacotes que não esteja na lista `allowed` e diz a Claude para reescrever o comando usando um gerenciador permitido. Detecta: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | Parâmetro | Tipo | Padrão | Descrição | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Nomes de gerenciadores de pacotes permitidos. Qualquer gerenciador detectado que não esteja nesta lista é bloqueado. Quando vazia, a política é uma no-op. | -| `blocked` | string[] | `[]` | Nomes de gerenciadores adicionais a serem bloqueados além da lista integrada (ex.: `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Nomes de gerenciadores de pacotes permitidos. Qualquer gerenciador detectado que não esteja nesta lista é bloqueado. Quando vazio, a política é inoperante. | +| `blocked` | string[] | `[]` | Nomes de gerenciadores adicionais a bloquear além da lista integrada (ex.: `['pdm', 'pipx']`). | -A lista de bloqueio integrada cobre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Use `blocked` para adicionar gerenciadores que não estão nesta lista. +A lista de bloqueio integrada cobre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Use `blocked` para adicionar gerenciadores que não estão nessa lista. **Exemplo de configuração:** @@ -679,7 +685,7 @@ A lista de bloqueio integrada cobre: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, } ``` -Com esta configuração, `pip install flask` e `pdm install flask` são ambos negados com uma mensagem instruindo o Claude a usar `uv` ou `bun`. Comandos como `uv pip install flask` são permitidos porque `uv` está na lista de permissões e é verificado primeiro. +Com esta configuração, `pip install flask` e `pdm install flask` são ambos negados com uma mensagem dizendo a Claude para usar `uv` ou `bun`. Comandos como `uv pip install flask` são permitidos porque `uv` está na lista de permissões e é verificado primeiro. --- @@ -690,7 +696,7 @@ Detecta quando agentes ficam presos ou se comportam de forma inesperada. ### `warn-repeated-tool-calls` **Evento:** PreToolUse (todas as ferramentas) -**Padrão:** Instrui o Claude a reconsiderar quando a mesma ferramenta é chamada 3 ou mais vezes com parâmetros idênticos — um sinal comum de que o agente está preso em um loop. +**Padrão:** Instrui Claude a reconsiderar quando a mesma ferramenta é chamada 3 ou mais vezes com parâmetros idênticos — um sinal comum de que o agente está preso em um loop. Sem parâmetros. @@ -698,40 +704,39 @@ Sem parâmetros. ## Fluxo de trabalho -Impõe um fluxo de trabalho disciplinado ao fim da sessão. Estas políticas são acionadas no evento **Stop** e negam ao agente a possibilidade de parar até que cada condição seja atendida. Elas seguem uma cadeia de dependência natural: commit → push → PR → CI. Se uma política negar, as políticas posteriores na cadeia são ignoradas (deny provoca curto-circuito). +Impõe um fluxo de trabalho disciplinado ao final da sessão. Essas políticas são acionadas no evento **Stop** e impedem o agente de parar até que cada condição seja atendida. Elas seguem uma cadeia de dependência natural: commit → push → PR → CI. Se uma política negar, as políticas posteriores na cadeia são ignoradas (o deny causa um curto-circuito). Todas as políticas de fluxo de trabalho são **fail-open**: se a ferramenta necessária não estiver disponível (ex.: `gh` não instalado, sem remote git), a política permite com uma mensagem informativa explicando por que a verificação foi ignorada. ### Semântica de Stop por CLI -A aplicação de Stop funciona de forma ligeiramente diferente entre os sete CLIs suportados, pois cada um expõe um contrato de hook diferente para "agente finalizado". O **resultado** é o mesmo — o agente não consegue parar enquanto um gate de fluxo de trabalho estiver falhando — mas a **mecânica** difere. A tabela abaixo resume; apenas o Pi tem uma peculiaridade visível ao usuário que vale entender antes de habilitar uma política `require-*-before-stop`. +A aplicação do Stop tem uma aparência ligeiramente diferente entre os seis CLIs suportados, porque cada um expõe um contrato de hook diferente para "agente terminou". O **resultado** é o mesmo — o agente não consegue parar enquanto um gate de fluxo de trabalho estiver falhando — mas a **mecânica** é diferente. A tabela abaixo resume; apenas o Pi tem uma peculiaridade visível ao usuário que vale a pena entender antes de habilitar uma política `require-*-before-stop`. | CLI | Quando o gate é acionado | O que você vê | |---|---|---| -| Claude Code | No mesmo loop do agente, imediatamente | O Claude continua trabalhando — corrige o problema e então tenta finalizar novamente. Nenhuma interrupção visível para você. | -| Codex | No mesmo loop do agente, imediatamente | Igual ao Claude. | -| GitHub Copilot CLI | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal de retry `{decision:"block", reason}` do Copilot — verificado empiricamente no Copilot CLI 1.0.41). | -| Cursor Agent | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal `{followup_message}` do Cursor — limitado ao `loop_limit`, padrão 5 tentativas). | -| Gemini CLI | No mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal `{decision:"block", reason}` do Gemini em `AfterAgent`). | -| OpenCode | No mesmo loop do agente, imediatamente | Igual ao Claude (usa a chamada SDK `client.session.prompt(...)` do OpenCode roteada através de `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **Próximo turno do usuário** | **O Pi para visivelmente** quando o gate é acionado — seu loop de agente sai e você retorna ao prompt. O gate é então acionado na próxima vez que você enviar um prompt: o failproofai antepõe uma diretiva `MANDATORY ACTION REQUIRED` ao prompt do sistema daquele turno, instruindo o LLM a concluir a etapa do fluxo de trabalho (commit, push, etc.) antes de fazer o que você pediu. | +| Claude Code | Mesmo loop do agente, imediatamente | Claude continua trabalhando — corrige o problema e tenta terminar novamente. Nenhuma interrupção visível para você. | +| Codex | Mesmo loop do agente, imediatamente | Igual ao Claude. | +| GitHub Copilot CLI | Mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal de retry `{decision:"block", reason}` do Copilot — verificado empiricamente contra Copilot CLI 1.0.41). | +| Cursor Agent | Mesmo loop do agente, imediatamente | Igual ao Claude (usa o canal `{followup_message}` do Cursor — limitado por `loop_limit`, padrão 5 tentativas). | +| OpenCode | Mesmo loop do agente, imediatamente | Igual ao Claude (usa a chamada SDK `client.session.prompt(...)` do OpenCode roteada através de `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **Próximo turno do usuário** | **Pi para visivelmente** quando o gate é acionado — seu loop de agente sai e você retorna ao prompt. O gate então é acionado na próxima vez que você enviar um prompt: failproofai adiciona uma diretiva `MANDATORY ACTION REQUIRED` ao prompt de sistema desse turno, instruindo o LLM a concluir a etapa do fluxo de trabalho (commit, push etc.) antes de fazer o que você pediu. | -**Limitação do Pi.** O `AgentEndEvent` do Pi (o equivalente upstream do hook `Stop` do Claude) não tem tipo Result — quando ele é acionado, o loop do agente do Pi já saiu. O Pi não pode ser forçado a repetir o mesmo loop da forma que Claude / Copilot / Cursor / Gemini / OpenCode podem. O failproofai desloca o gate para o evento `before_agent_start` do Pi (que é acionado após o próximo prompt do usuário), para que a verificação do fluxo de trabalho ainda seja aplicada, apenas no próximo turno em vez do atual. +**Limitação do Pi.** O `AgentEndEvent` do Pi (equivalente upstream ao hook `Stop` do Claude) não tem tipo Result — no momento em que é acionado, o loop do agente do Pi já saiu. O Pi não pode ser forçado a repetir o mesmo loop da forma que Claude / Copilot / Cursor / OpenCode podem. failproofai desloca o gate para o evento `before_agent_start` do Pi (que é acionado após o próximo prompt do usuário) para que a verificação de fluxo de trabalho ainda seja aplicada, só que no próximo turno em vez do atual. **O que isso significa na prática:** -- Após o Pi parar, o motivo da negação é capturado na memória, indexado pelo ID de sessão do Pi. O próximo prompt que você enviar no mesmo processo do Pi o consome: o LLM vê a diretiva `MANDATORY ACTION REQUIRED` no topo de seu prompt de sistema, faz o commit (ou push / abre o PR / aguarda o CI), e só então continua com sua solicitação. O motivo de negação capturado é de uso único — uma vez consumido, o gate é liberado. -- O gate é limitado ao tempo de vida do processo do Pi. Se você der `Ctrl+C` no Pi ou sair entre turnos, a entrada na memória é descartada junto com o processo e o gate é perdido. Claude, Copilot, Cursor, Gemini e OpenCode têm o mesmo limite (matar o agente faz o gate ser perdido) — o Pi apenas torna isso mais visível porque o agente sai visivelmente antes do gate ser acionado. -- Uma negação pendente também é limpa no `session_shutdown` por qualquer motivo (`new` / `resume` / `fork` / `quit`), então um gate obsoleto de uma sessão anterior não pode vazar para uma nova sessão iniciada no mesmo processo do Pi. +- Após o Pi parar, o motivo de deny é capturado em memória com chave pelo ID de sessão do Pi. O próximo prompt que você enviar no mesmo processo Pi o drena: o LLM vê a diretiva `MANDATORY ACTION REQUIRED` no topo do seu prompt de sistema, faz commit (ou push / abre o PR / aguarda o CI) e só então continua com sua solicitação. O motivo de deny capturado é de uso único — uma vez drenado, o gate está limpo. +- O gate é limitado pelo tempo de vida do processo do Pi. Se você fizer `Ctrl+C` no Pi ou sair entre os turnos, a entrada em memória é descartada junto com o processo e o gate é perdido. Claude, Copilot, Cursor e OpenCode têm o mesmo limite (matar o agente faz o gate ser perdido) — o Pi apenas torna isso mais visível porque o agente sai visivelmente antes de o gate ser acionado. +- Um deny pendente também é limpo no `session_shutdown` por qualquer motivo (`new` / `resume` / `fork` / `quit`), portanto um gate desatualizado de uma sessão anterior não pode vazar para uma nova sessão iniciada no mesmo processo Pi. -Se você precisar do retry no mesmo loop no estilo Claude, execute suas políticas `Stop` em qualquer um dos outros seis CLIs suportados. Estamos acompanhando o upstream do Pi para um futuro tipo Result no `AgentEndEvent` que nos permitiria fechar essa lacuna. +Se você precisar de retry no mesmo loop ao estilo do Claude, execute suas políticas `Stop` em qualquer um dos outros cinco CLIs suportados. Estamos acompanhando o desenvolvimento upstream do Pi para um futuro tipo Result em `AgentEndEvent` que nos permitiria fechar essa lacuna. ### `require-commit-before-stop` **Evento:** Stop -**Padrão:** Nega a parada quando há alterações não commitadas (arquivos modificados, staged ou não rastreados). Retorna uma mensagem informativa quando o diretório de trabalho está limpo. +**Padrão:** Nega a parada quando há alterações sem commit (arquivos modificados, staged ou não rastreados). Retorna uma mensagem informativa quando o diretório de trabalho está limpo. Sem parâmetros. @@ -740,13 +745,13 @@ Sem parâmetros. ### `require-push-before-stop` **Evento:** Stop -**Padrão:** Nega a parada quando há commits não enviados ou quando o branch atual não tem um branch de rastreamento remoto. Sugere `git push -u` para criar um branch de rastreamento, se necessário. Falha de forma aberta se nenhum remote estiver configurado. +**Padrão:** Nega a parada quando há commits não enviados por push ou quando o branch atual não tem branch de rastreamento remoto. Sugere `git push -u` para criar um branch de rastreamento se necessário. Falha aberto se nenhum remote estiver configurado. **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | Nome do remote para o qual fazer push. | +| `remote` | `string` | `"origin"` | Nome do remote para fazer push. | **Exemplo:** @@ -765,13 +770,14 @@ Sem parâmetros. ### `require-pr-before-stop` **Evento:** Stop -**Padrão:** Nega a parada quando não existe pull request para o branch atual, ou quando o PR existente está fechado sem merge. Instrui o Claude a criar um PR com `gh pr create`. Quando o PR está **merged**, a política permite (o trabalho foi entregue) e a mensagem sugere sair do branch (`git checkout main && git pull`). +**Padrão:** Nega a parada quando não existe pull request para o branch atual, ou quando o PR existente está fechado sem merge. Instrui Claude a criar um PR com `gh pr create`. Quando o PR está **merged**, a política permite (o trabalho foi enviado) e a mensagem sugere sair do branch (`git checkout main && git pull`). Sem parâmetros. Esta política requer que o [GitHub CLI](https://cli.github.com/) (`gh`) esteja instalado e autenticado. -Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` para acesso de leitura a pull requests. Se `gh` não estiver instalado ou não estiver autenticado, a política falha de forma aberta e reporta o motivo ao Claude. +Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` para acesso de leitura a +pull requests. Se `gh` não estiver instalado ou autenticado, a política falha aberto e reporta o motivo a Claude. --- @@ -779,21 +785,24 @@ Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` ### `require-no-conflicts-before-stop` **Evento:** Stop -**Padrão:** Nega a parada quando o branch atual não pode ser mesclado de forma limpa no branch base. A política primeiro confirma se há um PR `OPEN` no GitHub para o branch — sem um, não há alvo de merge a aplicar, então toda a política provoca curto-circuito para allow. Uma vez confirmado um PR `OPEN`, duas sondagens independentes são executadas: +**Padrão:** Nega a parada quando o branch atual não pode ser mergeado de forma limpa no branch base. A política primeiro confirma se há um PR `OPEN` no GitHub para o branch — sem um, não há alvo de merge a impor, então toda a política causa curto-circuito para permitir. Uma vez confirmado um PR `OPEN`, duas verificações independentes são executadas: -1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. Em caso de conflito, a mensagem de deny nomeia os arquivos em conflito para que o Claude saiba exatamente o que resolver. -2. **GitHub** — reutiliza o resultado de `gh pr view --json mergeable,state` já obtido na verificação prévia. Detecta conflitos que um `origin/` local desatualizado perderia (ex.: alguém lançou um PR conflitante em `main` desde o último fetch). Um resultado `CONFLICTING` nega. Um resultado `UNKNOWN` também nega e instrui o Claude a aguardar ~10 segundos e verificar novamente antes de tentar parar — isso previne falsos negativos enquanto o GitHub recomputa. +1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. Em caso de conflito, a mensagem de deny lista os arquivos conflitantes para que Claude saiba exatamente o que resolver. +2. **GitHub** — reutiliza o resultado de `gh pr view --json mergeable,state` já obtido na pré-verificação. Detecta conflitos que um `origin/` local desatualizado perderia (ex.: alguém fez merge de um PR conflitante em `main` desde o último fetch). Um resultado `CONFLICTING` nega. Um resultado `UNKNOWN` também nega e instrui Claude a aguardar ~10 segundos e verificar novamente antes de tentar parar — isso evita falsos negativos enquanto o GitHub recalcula. -Ignora completamente (permite) quando: `gh` não está instalado, nenhum PR existe para o branch, o estado do PR não é `OPEN` (ex.: `MERGED`, `CLOSED`), ou `gh pr view` retorna saída não analisável. Também falha de forma aberta quando `origin/` está faltando localmente ou quando não há commits à frente do base — esses fall-throughs da Camada 1 ainda consultam a mesclabilidade do PR em cache antes de permitir. +Ignora completamente (permite) quando: `gh` não está instalado, não existe PR para o branch, o estado do PR não é `OPEN` (ex.: `MERGED`, `CLOSED`), ou `gh pr view` retorna saída não analisável. Também falha aberto quando `origin/` está ausente localmente ou quando não há commits à frente da base — esses fallbacks da Camada 1 ainda consultam a mergeabilidade do PR em cache antes de permitir. **Parâmetros:** | Parâmetro | Tipo | Padrão | Descrição | |-------|------|---------|-------------| -| `baseBranch` | `string` | `"main"` | Branch base para verificar conflitos. | +| `baseBranch` | `string` | `"main"` | Branch base contra o qual verificar conflitos. | -O GitHub CLI (`gh`) é necessário para esta política. A política usa `gh pr view` para confirmar que um PR `OPEN` existe antes de executar qualquer sondagem de conflito — sem `gh`, a política provoca curto-circuito para allow. Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` para acesso de leitura a pull requests. +O GitHub CLI (`gh`) é necessário para esta política. A política usa `gh pr view` para confirmar +que existe um PR `OPEN` antes de executar qualquer verificação de conflito — sem `gh`, a política +causa curto-circuito para permitir. Execute `gh auth login` com um token de acesso pessoal que tenha +o escopo `repo` para acesso de leitura a pull requests. --- @@ -801,13 +810,14 @@ O GitHub CLI (`gh`) é necessário para esta política. A política usa `gh pr v ### `require-ci-green-before-stop` **Evento:** Stop -**Padrão:** Nega a parada quando as verificações de CI estão falhando ou ainda em execução no branch atual. Verifica tanto execuções de workflow do GitHub Actions quanto verificações de bots de terceiros (ex.: CodeRabbit, SonarCloud, Codecov). Trata conclusões `skipped`, `cancelled` e `neutral` como não-falhando (o último cobre, por exemplo, alertas do Socket Security em PRs de contribuidores externos, onde o aplicativo intencionalmente reporta neutro em vez de sucesso/falha). Retorna uma mensagem informativa quando todas as verificações passam. +**Padrão:** Nega a parada quando as verificações de CI estão falhando ou ainda em execução no branch atual. Verifica tanto as execuções de workflow do GitHub Actions quanto as verificações de bots de terceiros (ex.: CodeRabbit, SonarCloud, Codecov). Trata conclusões `skipped`, `cancelled` e `neutral` como não-falhas (esta última cobre, por exemplo, alertas do Socket Security em PRs de colaboradores externos, onde o app intencionalmente reporta neutro em vez de sucesso/falha). Retorna uma mensagem informativa quando todas as verificações passam. Sem parâmetros. Esta política requer que o [GitHub CLI](https://cli.github.com/) (`gh`) esteja instalado e autenticado. -Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` para acesso de leitura a execuções de workflow do Actions e à API de Checks. Se `gh` não estiver instalado ou não estiver autenticado, a política falha de forma aberta e reporta o motivo ao Claude. +Execute `gh auth login` com um token de acesso pessoal que tenha o escopo `repo` para acesso de leitura a +execuções de workflow do Actions e à API de Checks. Se `gh` não estiver instalado ou autenticado, a política falha aberto e reporta o motivo a Claude. --- diff --git a/docs/pt-br/cli/audit.mdx b/docs/pt-br/cli/audit.mdx index 0886e980..da7aca55 100644 --- a/docs/pt-br/cli/audit.mdx +++ b/docs/pt-br/cli/audit.mdx @@ -1,22 +1,21 @@ --- title: Auditar sessões anteriores (beta) -description: "Conte quantas vezes o agente fez coisas desnecessárias ou arriscadas em transcrições anteriores" +description: "Conte com que frequência o agente fez coisas desnecessárias ou arriscadas em transcrições passadas" --- - **Recurso beta.** O audit é disponibilizado em beta enquanto coletamos feedback inicial. - O catálogo de detectores e o formato do relatório podem mudar antes do próximo corte estável. - Abra uma issue se algo parecer errado. + **Recurso beta.** O audit é lançado como beta enquanto coletamos feedback inicial. + O catálogo de detectores e o formato do relatório podem mudar antes do próximo + corte estável. Abra uma issue se algo parecer errado. -O audit reproduz suas transcrições anteriores do agente-CLI pelo motor de políticas do failproofai -e gera um relatório visual e compartilhável na **página `/audit` do dashboard** -— o arquétipo do seu agente, uma pontuação de 0 a 100, e exatamente quais políticas -teriam capturado o quê. +O audit reproduz suas transcrições anteriores do agent-CLI pelo mecanismo de políticas do failproofai +e gera um relatório visual e compartilhável na **página do dashboard `/audit`** — o arquétipo +do seu agente, uma pontuação de 0 a 100, e exatamente quais políticas teriam capturado o quê. -## Executar +## Execute -Três formas de iniciar — todas levam ao mesmo relatório `/audit`. +Três formas de iniciar — todas chegam ao mesmo relatório `/audit`. @@ -37,60 +36,60 @@ failproofai `npx -y failproofai audit` baixa o failproofai, executa a varredura e abre o - dashboard automaticamente — sem necessidade de instalação prévia. + dashboard pra você — sem precisar instalar nada antes. - `failproofai audit` executa a varredura no seu terminal e abre - `localhost:8020/audit` automaticamente ao terminar. + `failproofai audit` executa a varredura no seu terminal e depois abre + `localhost:8020/audit` automaticamente quando terminar. Execute `failproofai` e clique em **Audit** na barra de navegação (entre Policies e - Projects), ou acesse `/audit` diretamente. + Projects), ou abra `/audit` diretamente. - Execute `failproofai audit -h` (ou `--help`) para ver o uso. O audit roda **completamente - offline** — sem conta ou conexão à internet necessária — e o dashboard continua servindo - até você encerrá-lo com `Ctrl+C`. + Execute `failproofai audit -h` (ou `--help`) para ver o uso. O audit roda **totalmente + offline** — sem conta ou conexão com a internet — e o dashboard continua servindo + até você pará-lo com `Ctrl+C`. -O dashboard varre transcrições anteriores do agente CLI nesta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) e relata com que frequência o agente fez coisas que o failproofai foi criado para impedir — verificações de variáveis de ambiente, force pushes, prefixos redundantes `cd `, loops de polling com sleep, releitura de arquivos recém-editados, e mais. +O dashboard varre transcrições anteriores do agent CLI nesta máquina (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) e reporta com que frequência o agente fez coisas que o failproofai foi desenvolvido para impedir — verificações de variáveis de ambiente, force pushes, prefixos redundantes `cd `, loops de sleep-polling, releitura de arquivos recém-editados, e mais. -Para cada transcrição, cada evento de uso de ferramenta é reproduzido pelas 39 políticas integradas **e** pelos 8 detectores exclusivos do audit que capturam padrões ainda não cobertos pelas políticas em tempo real. As contagens são agregadas por política/detector em todas as sessões. +Para cada transcrição, cada evento de uso de ferramenta é reproduzido pelas 39 políticas integradas **e** por 8 detectores exclusivos do audit que identificam padrões ainda não cobertos pelas políticas de tempo de execução. As contagens são agregadas por política/detector em todas as sessões. ## O que você recebe -A página `/audit` é um **pôster** de tela única e compartilhável seguido por quatro seções abaixo da dobra: +A página `/audit` é um **poster** em tela única e compartilhável, seguido de quatro seções abaixo da dobra: -1. **Pôster** — a identidade do seu agente em um relance: seu **arquétipo** (um dos 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), suas palavras-chave de persona, o quão raro é esse arquétipo, e uma **pontuação de 0 a 100** com uma faixa de classificação (`S` até `bottom tier`). Criado para compartilhar — poste no X ou no LinkedIn, ou baixe como PNG. -2. **`// strengths`** — o que seu agente já faz bem, com números reais da varredura (ex.: % de chamadas de ferramenta limpas, `0` tentativas de push para main), exibido apenas onde a política relevante tem um histórico limpo. -3. **`// quirks`** — o que escapou: uma tabela classificada de comportamentos que o failproofai teria capturado — *quando* aconteceu pela última vez, *o que escapou* (e o integrado que teria bloqueado), sua *severidade*, e com que frequência foi *visto* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — a lista de correções prescrita: uma linha por política com um `failproofai policy add ` para copiar e colar, mais um botão **install all** que habilita todas as recomendações de uma vez e mostra sua **pontuação projetada** se você fizesse isso. -5. **`// come back better`** — crie o hábito: defina um **lembrete** de reauditoria por e-mail (`3d` / `7d` / `14d` / `30d`) ou reaudite agora, e **convide um amigo** para rodar a própria auditoria (enviado de failproof.ai, com Cc para você). Lembretes e convites exigem login — veja [`failproofai auth`](/pt-br/cli/auth). +1. **Poster** — a identidade do seu agente em um relance: seu **arquétipo** (um dos 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), suas palavras-chave de persona, o quão raro esse arquétipo é, e uma **pontuação de 0 a 100** com uma faixa de nível (de `S` até `bottom tier`). Feito para compartilhar — publique no X ou no LinkedIn, ou baixe como PNG. +2. **`// strengths`** — o que seu agente já faz bem, como números reais da varredura (ex: % de chamadas de ferramenta limpas, `0` tentativas de push para main), mostrado apenas onde a política relevante tem um histórico limpo. +3. **`// quirks`** — o que passou despercebido: uma tabela ranqueada de comportamentos que o failproofai teria capturado — *quando* aconteceu pela última vez, *o que escapou* (e a política integrada que teria bloqueado), sua *severidade*, e com que frequência foi *visto* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — a lista de correções recomendadas: uma linha por política com um `failproofai policy add ` para copiar e colar, além de um botão **install all** que ativa todas as recomendações de uma vez e mostra sua **pontuação projetada** caso você o faça. +5. **`// come back better`** — crie o hábito: defina um **lembrete** de re-audit por e-mail (`3d` / `7d` / `14d` / `30d`) ou faça um re-audit agora, e **convide um amigo** para rodar o próprio audit (enviado pelo failproof.ai, com cópia para você). Lembretes e convites requerem login — veja [`failproofai auth`](/pt-br/cli/auth). ## Detectores exclusivos do audit -Esses detectores capturam padrões de "comportamento ineficiente" ainda não aplicados em tempo real. Rodam apenas durante o audit e nunca bloqueiam uma chamada de ferramenta ao vivo. +Estes detectam padrões de "comportamento ineficiente" que não são (ainda) aplicados em tempo real. Eles rodam apenas durante o audit e nunca bloqueiam uma chamada de ferramenta ao vivo. | Detector | O que conta | |---|---| -| `redundant-cd-cwd` | Comandos Bash começando com `cd && …` mesmo que os comandos já rodem em `cwd`. | -| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` em um único arquivo fonte — use a ferramenta `Read`. | +| `redundant-cd-cwd` | Comandos Bash que começam com `cd && …` mesmo que os comandos já rodem no `cwd`. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` em um único arquivo-fonte — use a ferramenta `Read`. | | `prefer-edit-over-sed-awk` | Edições in-place com `sed -i` / `awk … > file` — use a ferramenta `Edit`. | | `prefer-write-over-heredoc` | Heredoc / `echo > file` multilinha para escrever arquivos — use a ferramenta `Write`. | | `sleep-polling-loop` | `sleep N` longo (≥ 30s) ou loops de polling `while …; sleep …; done`. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — limite ao escopo de `cwd`. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, pulando hooks. | -| `reread-after-edit` | `Read` de um arquivo que acabou de ser `Edit`/`Write` na mesma sessão. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, etc. — limite ao `cwd`. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, ignorando hooks. | +| `reread-after-edit` | `Read` de um arquivo que acabou de ser modificado por `Edit`/`Write` na mesma sessão. | ## Caches -- **Cache por transcrição** em `~/.failproofai/cache/audit/.json`, indexado por `(mtime, size, engineVersion, detectorVersion)` — invalida automaticamente quando a transcrição ou o código de política/detector muda. Cada entrada também armazena um timestamp `cachedAt` como **metadado de TTL** (não faz parte da chave do cache); entradas com mais de **7 dias** são rejeitadas na leitura para que resultados de longa duração não sobrevivam à evolução da intenção dos detectores. -- **Cache do resultado completo** em `~/.failproofai/audit-dashboard.json` (modo 0600). Permite que o dashboard renderize instantaneamente na navegação sem precisar rodar novamente. Também rejeitado na leitura após o **TTL de 7 dias** — `/audit` então cai em seu estado vazio e solicita uma nova execução. Clique em `[ re-audit now ]` perto do final do relatório para atualizar — o re-audit envia `noCache: true`, então ignora o cache por transcrição e reavarre todas as transcrições em vez de retornar o resultado em cache; a execução transmite o progresso via uma faixa fixa no topo e substitui o resultado no lugar ao ser concluída com sucesso (sem recarregamento de página; um re-audit com falha mantém o relatório anterior). +- **Cache por transcrição** em `~/.failproofai/cache/audit/.json` com chave em `(mtime, size, engineVersion, detectorVersion)` — invalida automaticamente quando a transcrição ou o código de política/detector muda. Cada entrada também armazena um timestamp `cachedAt` como **metadados de TTL** (não fazem parte da chave de cache); entradas com mais de **7 dias** são rejeitadas na leitura para que resultados duradouros não sobrevivam à evolução da intenção dos detectores. +- **Cache do resultado completo** em `~/.failproofai/audit-dashboard.json` (modo 0600). Permite que o dashboard renderize instantaneamente na navegação sem re-executar. Também rejeitado na leitura após o **TTL de 7 dias** — `/audit` então volta ao seu estado vazio e solicita uma nova execução. Clique em `[ re-audit now ]` perto do final do relatório para atualizar — o re-audit envia `noCache: true`, portanto ignora o cache por transcrição e varre todas as transcrições novamente em vez de retornar o resultado em cache; a execução transmite o progresso via uma faixa fixa no topo e substitui o resultado no lugar ao concluir com sucesso (sem recarregar a página; um re-audit com falha mantém o relatório anterior). -## Observações +## Notas -- **Sem mutação.** O audit é reproduzido em modo somente leitura. `warn-repeated-tool-calls` é ignorado porque seu sidecar por sessão seria modificado de outra forma. -- **Políticas de fluxo de trabalho ignoradas.** As políticas `require-*-before-stop` são acionadas apenas em eventos `Stop` e `execSync` contra o estado git atual — elas não têm uma interpretação significativa de "o que teria acontecido em 2025", portanto não aparecem nas contagens do audit. -- **Políticas personalizadas ignoradas.** Hooks customizados fornecidos pelo usuário não são reproduzidos (eles podem ter mudado desde a sessão original). \ No newline at end of file +- **Sem mutação.** O audit reproduz em modo somente leitura. `warn-repeated-tool-calls` é ignorado porque seu sidecar por sessão seria modificado de outra forma. +- **Políticas de fluxo de trabalho ignoradas.** As políticas `require-*-before-stop` disparam apenas em eventos `Stop` e executam `execSync` contra o estado git ao vivo — elas não têm uma interpretação significativa de "o que teria acontecido em 2025", por isso não aparecem nas contagens do audit. +- **Políticas customizadas ignoradas.** Hooks customizados fornecidos pelo usuário não são reproduzidos (eles podem ter mudado desde a sessão original). \ No newline at end of file diff --git a/docs/pt-br/configuration.mdx b/docs/pt-br/configuration.mdx index ba82f42c..e4f67943 100644 --- a/docs/pt-br/configuration.mdx +++ b/docs/pt-br/configuration.mdx @@ -4,7 +4,7 @@ description: "Formato do arquivo de configuração, sistema de três escopos e r icon: gear --- -failproofai usa arquivos de configuração JSON para controlar quais políticas estão ativas, como elas se comportam e de onde as políticas personalizadas são carregadas. A configuração foi projetada para ser fácil de compartilhar com sua equipe — faça o commit no seu repositório e todos os desenvolvedores terão a mesma rede de segurança para agentes. +failproofai usa arquivos de configuração JSON para controlar quais políticas estão ativas, como elas se comportam e de onde as políticas personalizadas são carregadas. A configuração é projetada para ser fácil de compartilhar com sua equipe — faça o commit no repositório e todos os desenvolvedores terão a mesma proteção para o agente. --- @@ -13,12 +13,12 @@ failproofai usa arquivos de configuração JSON para controlar quais políticas Existem três escopos de configuração, avaliados em ordem de prioridade: | Escopo | Caminho do arquivo | Finalidade | -|--------|--------------------|------------| -| **project** | `.failproofai/policies-config.json` | Configurações por repositório, commitadas no controle de versão | -| **local** | `.failproofai/policies-config.local.json` | Substituições pessoais por repositório, incluídas no gitignore | -| **global** | `~/.failproofai/policies-config.json` | Padrões do usuário aplicados em todos os projetos | +|--------|-------------------|-----------| +| **project** | `.failproofai/policies-config.json` | Configurações por repositório, versionadas no controle de versão | +| **local** | `.failproofai/policies-config.local.json` | Substituições pessoais por repositório, adicionadas ao .gitignore | +| **global** | `~/.failproofai/policies-config.json` | Padrões do usuário aplicados a todos os projetos | -Quando failproofai recebe um evento de hook, ele carrega e mescla os três arquivos que existirem para o diretório de trabalho atual. +Quando failproofai recebe um evento de hook, ele carrega e mescla todos os três arquivos que existem para o diretório de trabalho atual. ### Regras de mesclagem @@ -32,13 +32,13 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← união sem duplicatas ``` -**`policyParams`** — o primeiro escopo que define os parâmetros para uma política específica vence por completo. Não há mesclagem profunda de valores dentro dos parâmetros de uma política. +**`policyParams`** — o primeiro escopo que define parâmetros para uma determinada política vence por completo. Não há mesclagem profunda de valores dentro dos parâmetros de uma política. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project vence, global ignorado +resolved: { allowPatterns: ["sudo apt-get update"] } ← project vence, global é ignorado ``` ```text @@ -102,9 +102,9 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← cai para o global Tipo: `string[]` -Lista de nomes de políticas a serem habilitadas. Os nomes devem corresponder exatamente aos identificadores de política exibidos por `failproofai policies`. Consulte [Políticas Integradas](/pt-br/built-in-policies) para ver a lista completa. +Lista de nomes de políticas a serem habilitadas. Os nomes devem corresponder exatamente aos identificadores de política exibidos por `failproofai policies`. Consulte [Políticas Integradas](/pt-br/built-in-policies) para a lista completa. -Políticas que não estejam em `enabledPolicies` ficam inativas, mesmo que tenham entradas em `policyParams`. +Políticas que não estão em `enabledPolicies` ficam inativas, mesmo que possuam entradas em `policyParams`. ### `policyParams` @@ -112,17 +112,17 @@ Tipo: `Record>` Substituições de parâmetros por política. A chave externa é o nome da política; as chaves internas são específicas de cada política. Cada política documenta seus parâmetros disponíveis em [Políticas Integradas](/pt-br/built-in-policies). -Se uma política tiver parâmetros mas você não os especificar, os padrões internos da política serão usados. Usuários que não configurarem `policyParams` terão comportamento idêntico ao das versões anteriores. +Se uma política possui parâmetros, mas você não os especifica, os padrões integrados da política são utilizados. Usuários que não configuram `policyParams` têm comportamento idêntico às versões anteriores. -Chaves desconhecidas dentro do bloco de parâmetros de uma política são silenciosamente ignoradas no momento em que o hook é disparado, mas sinalizadas como avisos ao executar `failproofai policies`. +Chaves desconhecidas dentro do bloco de parâmetros de uma política são silenciosamente ignoradas no momento do disparo do hook, mas sinalizadas como avisos quando você executa `failproofai policies`. #### `hint` (transversal) Tipo: `string` (opcional) -Uma mensagem anexada ao motivo quando uma política retorna `deny` ou `instruct`. Use para fornecer orientações práticas a Claude sem modificar a própria política. +Uma mensagem adicionada ao motivo quando uma política retorna `deny` ou `instruct`. Use para fornecer orientações acionáveis ao Claude sem modificar a política em si. -Funciona com qualquer tipo de política — integradas, personalizadas (`custom/`), convenções de projeto (`.failproofai-project/`) ou convenções de usuário (`.failproofai-user/`). +Funciona com qualquer tipo de política — integrada, personalizada (`custom/`), convenção de projeto (`.failproofai-project/`) ou convenção do usuário (`.failproofai-user/`). ```json { @@ -143,15 +143,15 @@ Funciona com qualquer tipo de política — integradas, personalizadas (`custom/ Quando `block-force-push` nega, Claude vê: *"Force-pushing is blocked. Try creating a fresh branch instead."* -Valores não-string e strings vazias são silenciosamente ignorados. Se `hint` não estiver definido, o comportamento permanece inalterado (compatível com versões anteriores). +Valores não textuais e strings vazias são silenciosamente ignorados. Se `hint` não estiver definido, o comportamento não é alterado (compatível com versões anteriores). ### `customPoliciesPath` Tipo: `string` (caminho absoluto) -Caminho para um arquivo JavaScript contendo políticas de hook personalizadas. Esse campo é configurado automaticamente por `failproofai policies --install --custom ` (o caminho é resolvido para absoluto antes de ser armazenado). +Caminho para um arquivo JavaScript contendo políticas de hook personalizadas. Esse valor é definido automaticamente por `failproofai policies --install --custom ` (o caminho é resolvido para absoluto antes de ser armazenado). -O arquivo é carregado do zero a cada evento de hook — não há cache. Consulte [Políticas Personalizadas](/pt-br/custom-policies) para detalhes de autoria. +O arquivo é carregado novamente a cada evento de hook — não há cache. Consulte [Políticas Personalizadas](/pt-br/custom-policies) para detalhes de criação. ### Políticas baseadas em convenção @@ -162,11 +162,11 @@ Além do `customPoliciesPath` explícito, failproofai descobre e carrega automat | Projeto | `.failproofai/policies/` | Compartilhado com a equipe via controle de versão | | Usuário | `~/.failproofai/policies/` | Pessoal, aplicado a todos os projetos | -**Correspondência de arquivos:** Apenas arquivos que correspondam a `*policies.{js,mjs,ts}` são carregados (por exemplo, `security-policies.mjs`, `workflow-policies.js`). Outros arquivos no diretório são ignorados. +**Correspondência de arquivos:** Somente arquivos que correspondam a `*policies.{js,mjs,ts}` são carregados (ex.: `security-policies.mjs`, `workflow-policies.js`). Outros arquivos no diretório são ignorados. -**Sem configuração necessária:** Políticas de convenção não precisam de entradas em `policies-config.json`. Basta colocar os arquivos no diretório e eles serão detectados no próximo evento de hook. +**Sem necessidade de configuração:** Políticas de convenção não requerem entradas em `policies-config.json`. Basta colocar os arquivos no diretório e eles serão detectados no próximo evento de hook. -**Carregamento por união:** Os diretórios de convenção do projeto e do usuário são verificados. Todos os arquivos correspondentes de ambos os níveis são carregados (ao contrário de `customPoliciesPath`, que utiliza o primeiro escopo que vencer). +**Carregamento por união:** Ambos os diretórios de convenção — de projeto e de usuário — são verificados. Todos os arquivos correspondentes de ambos os níveis são carregados (diferente de `customPoliciesPath`, que utiliza o primeiro escopo vencedor). Consulte [Políticas Personalizadas](/pt-br/custom-policies) para mais detalhes e exemplos. @@ -189,20 +189,24 @@ Configuração do cliente LLM para políticas que fazem chamadas de IA. Não é ## Gerenciando a configuração pela CLI -Os comandos `policies --install` e `policies --uninstall` escrevem no arquivo de configurações de hook do seu agente CLI (os pontos de entrada dos hooks), enquanto `policies-config.json` é o arquivo que você gerencia diretamente. Os dois são independentes: +Os comandos `policies --install` e `policies --uninstall` escrevem no arquivo de configurações de hooks da CLI do seu agente (os pontos de entrada do hook), enquanto `policies-config.json` é o arquivo que você gerencia diretamente. Os dois são separados: -- **Configurações do agente CLI** — instrui o agente a chamar `failproofai --hook ` a cada uso de ferramenta: +- **Configurações da CLI do agente** — instrui o agente a chamar `failproofai --hook ` a cada uso de ferramenta: - **Claude Code**: `~/.claude/settings.json` (usuário), `/.claude/settings.json` (projeto), `/.claude/settings.local.json` (local) - - **OpenAI Codex**: `~/.codex/hooks.json` (usuário), `/.codex/hooks.json` (projeto) — o Codex não possui escopo `local` - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuário), `/.github/hooks/failproofai.json` (projeto) — o Copilot não possui escopo `local`. As entradas de hook usam os campos de comando `bash`/`powershell` com chave por SO do Copilot com `timeoutSec`; o arquivo carrega um marcador `version: 1` no nível superior. O suporte ao Copilot CLI está em **beta** enquanto verificamos o esquema de registros `events.jsonl` (não especificado na documentação pública) em mais sessões reais. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuário), `/.cursor/hooks.json` (projeto) — o Cursor não possui escopo `local`. As entradas de hook usam o formato Claude `{type, command, timeout}` (sem divisão `bash`/`powershell`), mas armazenadas sob chaves de evento em camelCase (`preToolUse`, `beforeSubmitPrompt`, …) em um array plano, conforme o [esquema de hooks](https://cursor.com/docs/hooks) do Cursor; o arquivo carrega um marcador `version: 1` no nível superior. O handler canonicaliza camelCase → PascalCase via `CURSOR_EVENT_MAP`, de modo que as políticas integradas existentes disparam sem alteração. O suporte ao Cursor Agent está em **beta** enquanto verificamos o formato em disco da transcrição do Cursor (não especificado na documentação pública) em mais instalações reais. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuário), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projeto) — o OpenCode não possui escopo `local`. Diferentemente dos outros seis CLIs, o OpenCode **não possui sistema de hooks para comandos externos**: ele carrega plugins JS/TS em processo, explicitamente registrados pelo array `plugin: []` no `opencode.json` (a autodescoberta a partir de `.opencode/plugins/` **não** é como os plugins são carregados no opencode v1.14.33). A instalação deposita um pequeno shim de plugin gerado que chama o binário failproofai em subprocesso e traduz a resposta JSON no formato Claude do binário para a semântica do plugin: `throw new Error()` para negação em eventos de ferramenta (cancela a chamada da ferramenta), `client.session.prompt(...)` para instruct E para negação de `Stop` / `SubagentStop` (envia o motivo da negação como a próxima mensagem do usuário — o único canal de força de nova tentativa, já que `session.idle` é apenas de notificação e lançar exceção a partir dele é um no-op), e no-op para allow. O shim canonicaliza nomes de ferramentas (minúsculas → PascalCase via `OPENCODE_TOOL_MAP`) e chaves de argumentos de entrada de ferramentas (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, por exemplo `filePath` → `file_path`, `oldString` → `old_string`) antes de encaminhar ao binário, de modo que políticas integradas de verificação de caminho como `block-read-outside-cwd`, `block-env-files` e `block-secrets-write` disparam sem alteração em chamadas de ferramentas do OpenCode. As sessões ficam no banco de dados SQLite do opencode em `~/.local/share/opencode/opencode.db`; o visualizador de sessões do dashboard as lê via `opencode db --format json` e `opencode export `. O suporte ao OpenCode está em **beta** enquanto verificamos o comportamento entre versões e em mais sessões reais. Consulte a [documentação de plugins do OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuário), `/.pi/settings.json` (projeto) — o Pi não possui escopo `local`. O Pi carrega pacotes de extensão TypeScript na inicialização; o arquivo de configurações é um array de strings plano `{"packages": ["./relative/path", …]}`. failproofai escreve uma única entrada no array de pacotes apontando para seu diretório `pi-extension/` empacotado. A extensão subscreve internamente aos eventos `tool_call` / `user_bash` / `input` / `session_start` do Pi e executa `failproofai --hook --cli pi` em shell; o handler canonicaliza eventos via `PI_EVENT_MAP` (underscore_lower_snake_case → PascalCase) para que as políticas integradas existentes disparem sem alteração. Os argumentos de entrada de ferramentas também são canonicalizados via `PI_TOOL_INPUT_MAP` (o Read / Write / Edit do Pi entregam `path` em vez de `file_path`; mapear a chave de nível superior permite que `block-env-files` e `block-secrets-write` disparem — `block-read-outside-cwd` já tinha um fallback para `path`). O suporte ao Pi está em **beta** enquanto a API de extensão do Pi e o layout do log de sessão se estabilizam. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (usuário), `/.gemini/settings.json` (projeto) — o Gemini não possui escopo `local` (ele documenta um escopo `system` em `/etc/gemini-cli/settings.json`, que failproofai não expõe). As entradas de hook usam o formato Claude `{type, command, timeout}` encapsulado no esquema de matcher do Gemini `{matcher, hooks: [...]}` com `matcher: "*"` por padrão. Os eventos são PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); o handler mapeia para nomes canônicos do Claude via `GEMINI_EVENT_MAP`. Os nomes de ferramentas são snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — o handler os canonicaliza via `GEMINI_TOOL_MAP` para que as políticas integradas existentes disparem sem alteração. O avaliador de políticas emite o formato plano `{decision: "deny", reason}` do Gemini (preferido conforme o contrato exit-0 da "Regra de Ouro" do Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` para injeção de contexto em BeforeAgent / AfterTool / SessionStart, e `{decision: "block", reason}` em AfterAgent para semântica de força de nova tentativa. O suporte ao Gemini CLI está em **beta** enquanto ampliamos a cobertura em situações reais. Consulte a [documentação de hooks do Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**somente escopo de usuário** — o Hermes não possui configuração de projeto/local). O Hermes é um **gateway** para Slack/Telegram, portanto uma única instalação intercepta chamadas de ferramentas de todas as plataformas (Slack/Telegram/cli/cron) **e** de subagentes internos. As entradas de hook são um par `{command, timeout}` (timeout em **segundos**) sob um mapa `hooks:` com chave pelos eventos snake_case do Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); o handler canonicaliza eventos via `HERMES_EVENT_MAP` e nomes de ferramentas via `HERMES_TOOL_MAP` para que as políticas integradas disparem sem alteração. A configuração é editada por meio de uma edição de ida e volta de `Document` YAML que preserva comentários, para que as outras configurações do operador sobrevivam, e a instalação define `hooks_auto_accept: true` para que o gateway headless (sem TTY) execute os hooks sem uma solicitação de consentimento. O avaliador emite o contrato stdout `{"decision":"block","reason"}` do Hermes (o Hermes ignora códigos de saída). **Limitações:** O Hermes não possui evento `Stop` de fim de turno, portanto as políticas integradas `require-*-before-stop` nunca disparam para ele (inaplicável, não quebrado); `instruct` é rebaixado para allow com nota registrada (sem canal de contexto adicional); e a redação de segredos na saída (`sanitize-*`) não pode reescrever a saída das ferramentas pelo contrato de hook de shell. O Hermes é **também** uma fonte de **auditoria** offline — o dashboard lê suas sessões de gateway diretamente de `~/.hermes/state.db`. -- **`policies-config.json`** — informa ao failproofai quais políticas avaliar e com quais parâmetros (compartilhado entre todos os agentes CLI) - -Passe `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` para direcionar um agente específico (separado por espaço ou repetido para qualquer subconjunto): + - **OpenAI Codex**: `~/.codex/hooks.json` (usuário), `/.codex/hooks.json` (projeto) — o Codex não tem escopo `local` + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (usuário), `/.github/hooks/failproofai.json` (projeto) — o Copilot não tem escopo `local`. As entradas de hook usam os campos de comando `bash`/`powershell` com chave por SO do Copilot com `timeoutSec`; o arquivo contém um marcador `version: 1` no nível superior. O suporte ao Copilot CLI está em **beta** enquanto verificamos o esquema de registros `events.jsonl` (não especificado na documentação pública) em mais sessões reais. **O modo de agente do VS Code Copilot Chat (Preview)** lê configurações de hooks em `.github/hooks/*.json`, `~/.copilot/hooks/*.json` e `~/.claude/settings.json` (controlado pela configuração `chat.hookFilesLocations`) usando o mesmo contrato no formato Claude `{hookSpecificOutput:{permissionDecision:"deny",…}}` — exatamente os caminhos que essa integração `copilot` e a integração `claude` (`~/.claude/settings.json`) já escrevem, portanto `failproofai policies --install --cli copilot` (ou `--cli claude`) **já aplica restrições no modo de agente do VS Code** sem necessidade de uma integração `vscode` separada (confirmado ao vivo pelos logs de descoberta do VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (usuário), `/.cursor/hooks.json` (projeto) — o Cursor não tem escopo `local`. As entradas de hook usam o formato Claude `{type, command, timeout}` (sem divisão `bash`/`powershell`), mas armazenados sob chaves de evento em camelCase (`preToolUse`, `beforeSubmitPrompt`, …) em um array plano conforme o [esquema de hooks](https://cursor.com/docs/hooks) do Cursor; o arquivo contém um marcador `version: 1` no nível superior. O handler canonicaliza camelCase → PascalCase via `CURSOR_EVENT_MAP`, para que as políticas integradas existentes sejam disparadas sem alterações. O suporte ao Cursor Agent está em **beta** enquanto verificamos o formato de transcrição em disco do Cursor (não especificado na documentação pública) em mais instalações reais. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (usuário), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (projeto) — o OpenCode não tem escopo `local`. Diferentemente das outras cinco CLIs, o OpenCode **não possui um sistema de hooks de comando externo**: ele carrega plugins JS/TS em processo explicitamente registrados via o array `plugin: []` em `opencode.json` (a descoberta automática em `.opencode/plugins/` **não** é como os plugins carregam no opencode v1.14.33). A instalação cria um pequeno shim de plugin gerado que chama o binário failproofai em subprocesso e traduz a resposta JSON no formato Claude de volta para a semântica do plugin: `throw new Error()` para deny de evento de ferramenta (cancela a chamada), `client.session.prompt(...)` para instruct E para deny de `Stop` / `SubagentStop` (envia o motivo do deny como a próxima mensagem do usuário — o único canal de força de nova tentativa, já que `session.idle` é somente notificação e lançar uma exceção nele é um no-op), e no-op para allow. O shim canonicaliza tanto os nomes de ferramentas (minúsculas → PascalCase via `OPENCODE_TOOL_MAP`) quanto as chaves de argumento de entrada de ferramenta (camelCase → snake_case via `OPENCODE_TOOL_INPUT_MAP` para `Read` / `Write` / `Edit`, ex.: `filePath` → `file_path`, `oldString` → `old_string`) antes de encaminhar ao binário, para que políticas integradas de verificação de caminho como `block-read-outside-cwd`, `block-env-files` e `block-secrets-write` sejam disparadas normalmente em chamadas de ferramenta do OpenCode. As sessões ficam no banco de dados SQLite do opencode em `~/.local/share/opencode/opencode.db`; o visualizador de sessões do dashboard as lê via `opencode db --format json` e `opencode export `. O suporte ao OpenCode está em **beta** enquanto verificamos o comportamento em diferentes versões e em mais sessões reais. Consulte a [documentação de plugins do OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (usuário), `/.pi/settings.json` (projeto) — o Pi não tem escopo `local`. O Pi carrega pacotes de extensão TypeScript na inicialização; o arquivo de configurações é um array de strings plano `{"packages": ["./relative/path", …]}`. failproofai escreve uma única entrada no array de pacotes apontando para seu diretório `pi-extension/` empacotado. A extensão internamente se inscreve nos eventos `tool_call` / `user_bash` / `input` / `session_start` do Pi e executa `failproofai --hook --cli pi` em um processo filho; o handler canonicaliza underscore_lower_snake_case → PascalCase via `PI_EVENT_MAP`, para que as políticas integradas existentes sejam disparadas sem alterações. Os argumentos de entrada de ferramentas também são canonicalizados via `PI_TOOL_INPUT_MAP` (as ferramentas Read / Write / Edit do Pi entregam `path` em vez de `file_path`; mapear a chave de nível superior faz `block-env-files` e `block-secrets-write` dispararem — `block-read-outside-cwd` já tinha um fallback para `path`). O suporte ao Pi está em **beta** enquanto a API de extensão e o layout de log de sessão do Pi se estabilizam. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**somente escopo de usuário** — o Hermes não tem configuração de projeto/local). O Hermes é um **gateway** Slack/Telegram, portanto uma única instalação intercepta chamadas de ferramentas de todas as plataformas (Slack/Telegram/cli/cron) **e** subagentes internos. As entradas de hook são um par `{command, timeout}` (timeout em **segundos**) sob um mapa `hooks:` com chave pelos eventos snake_case do Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); o handler canonicaliza eventos via `HERMES_EVENT_MAP` e nomes de ferramentas via `HERMES_TOOL_MAP`, para que as políticas integradas sejam disparadas sem alterações. A configuração é editada por meio de um round-trip YAML `Document` que preserva comentários, para que outras configurações do operador sobrevivam, e a instalação define `hooks_auto_accept: true` para que o gateway headless (sem TTY) execute os hooks sem um prompt de consentimento. O avaliador emite o contrato stdout `{"decision":"block","reason"}` do Hermes (o Hermes ignora códigos de saída). **Limitações:** o Hermes não tem um evento `Stop` de fim de turno, portanto os builtins `require-*-before-stop` nunca disparam para ele (inaplicável, não quebrado); `instruct` é rebaixado para allow-com-nota-registrada (sem canal de contexto adicional); e a redação de segredos na saída (`sanitize-*`) não consegue reescrever a saída de ferramentas pelo contrato de hook de shell. O Hermes também é uma fonte de **auditoria** offline — o dashboard lê suas sessões de gateway diretamente em `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**somente escopo de usuário** — o OpenClaw não tem configuração de projeto/local). Assim como o Hermes, o OpenClaw é um **gateway** multicanal auto-hospedado, portanto uma única instalação intercepta chamadas de ferramentas de todos os canais e seus subagentes internos. A aplicação ocorre por meio dos **hooks de plugin em processo** do OpenClaw (seus hooks internos baseados em arquivo são apenas de observação e não podem bloquear), portanto — assim como OpenCode/Pi — failproofai fornece um pacote estático `openclaw-plugin/` que executa o binário failproofai de forma assíncrona e traduz o veredicto. A instalação registra o diretório do plugin fornecido em `plugins.load.paths[]` do `openclaw.json` e o habilita em `plugins.entries.failproofai` (com `hooks.allowConversationAccess: true`, necessário para os hooks de conversa bruta). O avaliador emite um veredicto plano `{permission, reason}` e o shim o mapeia para o formato nativo de retorno de cada hook: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), e `before_agent_finalize → {action:"revise", reason}` (**Stop** — um portão de fim de turno real, portanto os builtins `require-*-before-stop` **se aplicam** no OpenClaw, ao contrário do Hermes). Eventos e nomes de ferramentas são canonicalizados no lado do binário via `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …), para que as políticas integradas sejam disparadas sem alterações; o shim falha de forma aberta em qualquer erro de spawn/parse/timeout. O OpenClaw também é uma fonte de **auditoria** offline — o dashboard lê suas sessões JSONL em `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (usuário), `/.factory/hooks.json` (projeto) — o Factory não tem escopo `local`. O droid fornece um sistema de hook de comando externo no estilo Claude, mas com duas peculiaridades verificadas ao vivo contra droid v0.171.0: (1) os nomes de eventos ficam no **nível superior** de `hooks.json` — **não há wrapper `"hooks"`** (o droid rejeita um); eventos de ferramenta (`PreToolUse`/`PostToolUse`) carregam `"matcher": "*"`, eventos não relacionados a ferramentas omitem isso. (2) O deny é controlado pelo **código de saída 2 + stderr** do hook, não por uma decisão JSON — o branch `factory` do avaliador retorna saída 2 para eventos de ferramenta/prompt e `{decision:"block", reason}` somente no evento de fim de turno `Stop` (único canal de força de nova tentativa do droid). Os eventos já estão em PascalCase (sem mapa de eventos) e o payload é snake_case Claude; somente os nomes de ferramentas são canonicalizados via `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). O Factory também é uma fonte de **auditoria** offline — o dashboard lê suas sessões JSONL em disco em `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (usuário), `/.devin/config.json` (projeto) — o Devin não tem escopo `local`. O Devin é um **clone puro do Claude** verificado ao vivo contra devin v3000.1.27: usa o esquema padrão Claude com wrapper `"hooks"` (as gravações preservam mesclagem para que outras chaves do arquivo de configuração — `org_id`, `theme_mode`, … — sobrevivam), nomes de eventos já em PascalCase (sem mapa de eventos, sem branch de handler) e payload stdin snake_case Claude (sem normalização). O branch `devin` do avaliador nega com JSON `{"decision":"block","reason"}` no stdout na saída 0 para **todos** os eventos (verificado — o bloco substituiu `--permission-mode dangerous`); no evento de fim de turno `Stop`, o motivo carrega o texto de força de nova tentativa MANDATORY-ACTION para que os builtins `require-*-before-stop` se apliquem. Somente os nomes de ferramentas são canonicalizados via `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` já é canônico). O Devin também é uma fonte de **auditoria** offline — o dashboard lê suas sessões SQLite em `~/.local/share/devin/cli/sessions.db` (cada linha de `sessions` contém um `working_directory` real, portanto as sessões são agrupadas por cwd do projeto como no Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (usuário), `/.agents/hooks.json` (projeto) — o Antigravity não tem escopo `local`. Diferentemente do Factory/Devin, o Antigravity tem seu **próprio** contrato (não é um clone do Claude), verificado ao vivo contra agy v1.1.2. O `hooks.json` usa um esquema de **hook nomeado**: a chave de nível superior é um *nome* de hook (`"failproofai"`) cujo valor é um mapa evento→handlers — eventos de ferramenta (`PreToolUse`/`PostToolUse`) encapsulam handlers em `{matcher:"*", hooks:[…]}`, enquanto `PreInvocation`/`Stop` são arrays de handler **planos** (outros hooks nomeados são preservados). O payload stdin é **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai o normaliza para snake_case antes de executar as políticas, e mapeia os args PascalCase de `run_command` (`CommandLine`/`Cwd`) via `ANTIGRAVITY_TOOL_INPUT_MAP`. O branch `antigravity` do avaliador usa as **próprias** formas de resposta do Antigravity: `{decision:"deny", reason}` bloqueia uma ferramenta/prompt (saída 0), `{decision:"continue", reason}` no evento de fim de turno `Stop` reingressa no loop (para que os builtins `require-*-before-stop` se apliquem), e `{injectSteps:[{ephemeralMessage}]}` injeta uma instrução em `PreInvocation` (→ `UserPromptSubmit`). Os nomes de ferramentas são canonicalizados via `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). O Antigravity também é uma fonte de **auditoria** offline — o dashboard lê suas transcrições JSONL em `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (índice de conversas em `conversation_summaries.db`). + - **Goose (codinome goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (usuário), `/.agents/plugins/failproofai/hooks/hooks.json` (projeto) — o Goose não tem escopo `local`. A aplicação usa o sistema de **hooks** do Goose, a especificação **Open Plugins** entre agentes: o instalador apenas cria o diretório do plugin `failproofai` e o Goose o descobre automaticamente na inicialização (auto-registrando-o em `~/.config/goose/config.yaml`). O `hooks.json` usa um esquema Open Plugins **com** wrapper `"hooks"` de nível superior, e o matcher é **omitido** em todos os eventos — um `"*"` puro é uma regex inválida que não corresponde a nada (verificado ao vivo contra goose v1.43.0). Os nomes de eventos já estão em PascalCase (sem mapa de eventos); o payload stdin usa `event`/`working_dir`, que o handler normaliza para `hook_event_name`/`cwd`. O branch `goose` do avaliador nega com JSON `{"decision":"block","reason"}` no stdout na saída 0, honrado apenas no evento **`PreToolUse`** (lançado no goose ≥ v1.37.0) — que dispara para a ferramenta de shell **e dentro de subagentes delegados**, tornando-o o único ponto de deny suficiente; qualquer outro erro de hook falha de forma **aberta**. O Goose **não tem evento `Stop`**, portanto os builtins `require-*-before-stop` não se aplicam (como no Hermes). Os nomes de ferramentas são canonicalizados via `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) e as chaves de caminho via `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). O Goose também é uma fonte de **auditoria** offline — o dashboard lê suas sessões SQLite em `~/.local/share/goose/sessions/sessions.db` (cada linha de `sessions` contém um `working_dir` real, portanto as sessões são agrupadas por cwd do projeto como no Devin; execuções avulsas com `--no-session` são filtradas). +- **`policies-config.json`** — instrui failproofai sobre quais políticas avaliar e com quais parâmetros (compartilhado entre todas as CLIs de agente) + +Passe `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` para selecionar um agente específico (separados por espaço ou repetidos para qualquer subconjunto): ```bash failproofai policies --install --cli codex --scope project @@ -210,23 +214,27 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Quando `--cli` é omitido, `failproofai` detecta quais agentes CLI estão instalados (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Quando `--cli` é omitido, `failproofai` detecta quais CLIs de agente estão instaladas (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Um CLI detectado** — seleciona automaticamente esse CLI sem solicitar confirmação. -- **Vários CLIs detectados** em um terminal interativo — exibe um prompt de seleção única com teclas de seta, agrupado em uma seção `Detected (N)` (com uma linha agregada `Install for all N detected` + cada CLI detectado individualmente) e uma seção `Not installed (M) · install hooks ahead of time` listando todos os CLIs suportados não detectados como opções de instalação antecipada (↑↓ para mover, Enter para selecionar, ^C para sair). O fluxo de desinstalação exibe apenas a seção Detected. -- **Vários CLIs detectados** em uma execução não interativa (CI, sem TTY) — instala para todos os CLIs detectados sem solicitar confirmação. -- **Nenhum detectado** — retorna para `claude`, com um aviso de que nenhum binário de agente foi encontrado no PATH; o comando de hook ainda é escrito para que seja ativado assim que você instalar um. +- **Uma CLI detectada** — seleciona automaticamente essa CLI sem solicitar confirmação. +- **Múltiplas CLIs detectadas** em um terminal interativo — exibe um prompt de seleção única por teclas de seta, agrupado em uma seção `Detected (N)` (com uma linha agregada `Install for all N detected` + cada CLI detectada individualmente) e uma seção `Not installed (M) · install hooks ahead of time` listando todas as CLIs suportadas não detectadas como opção de instalação antecipada (↑↓ para mover, Enter para selecionar, ^C para sair). O fluxo de desinstalação exibe somente a seção Detected. +- **Múltiplas CLIs detectadas** em uma execução não interativa (CI, sem TTY) — instala para todas as CLIs detectadas sem solicitar confirmação. +- **Nenhuma detectada** — retorna para `claude`, com um aviso de que nenhum binário de agente foi encontrado no PATH; o comando de hook ainda é escrito para ser ativado assim que você instalar um. Você pode editar `policies-config.json` diretamente a qualquer momento; as alterações entram em vigor imediatamente no próximo evento de hook, sem necessidade de reinicialização. --- -## Exemplo: configuração no nível de projeto com padrões da equipe +## Exemplo: configuração no nível do projeto com padrões da equipe Faça o commit de `.failproofai/policies-config.json` no seu repositório: @@ -247,4 +255,4 @@ Faça o commit de `.failproofai/policies-config.json` no seu repositório: } ``` -Cada desenvolvedor pode então criar `.failproofai/policies-config.local.json` (incluído no gitignore) para substituições pessoais sem afetar os colegas de equipe. \ No newline at end of file +Cada desenvolvedor pode então criar `.failproofai/policies-config.local.json` (adicionado ao .gitignore) para substituições pessoais sem afetar os colegas de equipe. \ No newline at end of file diff --git a/docs/pt-br/dashboard.mdx b/docs/pt-br/dashboard.mdx index 7b2ed4d0..76e6d126 100644 --- a/docs/pt-br/dashboard.mdx +++ b/docs/pt-br/dashboard.mdx @@ -24,12 +24,12 @@ O dashboard lê diretamente do sistema de arquivos — suas pastas de projetos d ### Projetos -Lista todos os projetos Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ e Hermes encontrados na sua máquina. Os projetos Claude são descobertos em `~/.claude/projects/` (ou no caminho definido por `CLAUDE_PROJECTS_PATH`); os projetos Codex são descobertos varrendo todas as transcrições em `~/.codex/sessions///
/*.jsonl` e agrupando pelo `cwd` registrado no primeiro registro de cada sessão; os projetos Copilot CLI são descobertos varrendo cada `~/.copilot/session-state//workspace.yaml` (configurável via `COPILOT_HOME`) e agrupando pelo campo `cwd`; os projetos Cursor Agent são descobertos varrendo metadados por sessão em `~/.cursor/agent-sessions//` (configurável via `CURSOR_HOME`, com `conversations/` e `sessions/` como alternativas) em busca de um escalar `cwd` em `meta.json` / `session.json` / `workspace.yaml`; os projetos OpenCode são descobertos consultando seu banco SQLite em `~/.local/share/opencode/opencode.db` via `opencode db --format json` (lemos as tabelas `session` e `project` e agrupamos por `project_id`); os projetos Pi são descobertos varrendo transcrições JSONL por sessão em `~/.pi/agent/sessions//_.jsonl` (configurável via `PI_SESSIONS_DIR`) e extraindo o `cwd` do primeiro registro de cada sessão; os projetos Gemini CLI são descobertos varrendo `~/.gemini/tmp//chats/session--.jsonl` (configurável via `GEMINI_SESSIONS_DIR`) e recuperando o cwd canônico a partir do marcador de texto `.project_root` adjacente; as sessões do gateway Hermes são lidas diretamente do seu armazenamento SQLite em `~/.hermes/state.db` (configurável via `HERMES_DB_PATH`) e agrupadas em projetos `hermes-` por `source` (Slack/Telegram/cli/cron — sessões do gateway não possuem cwd). Um projeto utilizado por múltiplos CLIs é exibido como uma única linha com todos os badges correspondentes. Use o menu suspenso **CLI** acima da tabela para filtrar por um agente CLI específico; a URL preserva sua seleção como `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Lista todos os projetos Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity e Goose encontrados na sua máquina. Projetos Claude são descobertos em `~/.claude/projects/` (ou no caminho definido por `CLAUDE_PROJECTS_PATH`); projetos Codex são descobertos varrendo todas as transcrições em `~/.codex/sessions///
/*.jsonl` e agrupando pelo `cwd` registrado no primeiro registro de cada sessão; projetos Copilot CLI são descobertos varrendo cada `~/.copilot/session-state//workspace.yaml` (configurável via `COPILOT_HOME`) e agrupando pelo campo `cwd`; projetos Cursor Agent são descobertos varrendo metadados por sessão em `~/.cursor/agent-sessions//` (configurável via `CURSOR_HOME`, com `conversations/` e `sessions/` como alternativas) por um escalar `cwd` em `meta.json` / `session.json` / `workspace.yaml`; projetos OpenCode são descobertos consultando seu banco SQLite em `~/.local/share/opencode/opencode.db` via `opencode db --format json` (lemos as tabelas `session` e `project` e agrupamos por `project_id`); projetos Pi são descobertos varrendo transcrições JSONL por sessão em `~/.pi/agent/sessions//_.jsonl` (configurável via `PI_SESSIONS_DIR`) e extraindo o `cwd` do primeiro registro de cada sessão; sessões do gateway Hermes são lidas diretamente do banco SQLite em `~/.hermes/state.db` (configurável via `HERMES_DB_PATH`) e agrupadas em projetos `hermes-` por `source` (Slack/Telegram/cli/cron — sessões do gateway não têm cwd); sessões do gateway OpenClaw são lidas de `~/.openclaw/agents//sessions/*.jsonl` e agrupadas em projetos `openclaw-` (também sem cwd); projetos Factory Droid são descobertos a partir das transcrições JSONL em `~/.factory/sessions//*.jsonl` e agrupados por cwd; projetos Devin a partir do banco SQLite em `~/.local/share/devin/cli/sessions.db` (agrupados pelo `working_directory` de cada sessão); projetos Antigravity a partir das transcrições JSONL em `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` e agrupados por cwd; e projetos Goose a partir do banco SQLite em `~/.local/share/goose/sessions/sessions.db` (agrupados pelo `working_dir` de cada sessão). Um projeto que foi utilizado por múltiplos CLIs é exibido como uma única linha com todos os badges correspondentes. Use o menu suspenso **CLI** acima da tabela para filtrar por um agente CLI específico; a URL preserva sua seleção como `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Cada projeto exibe: - Nome do projeto (derivado do caminho da pasta) -- Um badge de CLI — `Claude Code` (laranja), `OpenAI Codex` (roxo), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (âmbar), `Pi` (rosa), `Gemini CLI` (celeste) e/ou `Hermes` (índigo) -- Data da atividade mais recente da sessão +- Um badge de CLI — `Claude Code` (laranja), `OpenAI Codex` (roxo), `GitHub Copilot` (azul), `Cursor Agent` (esmeralda), `OpenCode` (âmbar), `Pi` (rosa) e/ou `Hermes` (índigo) +- Data da atividade de sessão mais recente Clique em um projeto para ver suas sessões. @@ -37,54 +37,54 @@ Clique em um projeto para ver suas sessões. Lista todas as sessões dentro de um projeto. Cada sessão exibe: - ID da sessão -- Timestamps de início e término +- Timestamps de início e fim - Número de chamadas de ferramentas - Contagem de atividade de hooks (políticas que foram acionadas) Use o filtro de intervalo de datas e a busca por ID de sessão para refinar a lista. As sessões são paginadas. -Clique em uma sessão para abrir o visualizador de sessão. +Clique em uma sessão para abrir o visualizador de sessões. -### Visualizador de sessão +### Visualizador de sessões -O visualizador de sessão responde à pergunta central dos agentes autônomos: o que o agente fez, e ele se manteve no curso? Um badge de CLI ao lado do cabeçalho indica se a sessão é uma transcrição do Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI ou Hermes. Ele exibe uma linha do tempo de tudo que aconteceu em uma sessão: +O visualizador de sessões responde à pergunta fundamental para agentes autônomos: o que o agente fez, e ele se manteve no caminho certo? Um badge de CLI ao lado do cabeçalho indica se a sessão é uma transcrição do Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity ou Goose. Ele exibe uma linha do tempo de tudo que aconteceu em uma sessão: - **Mensagens** — Respostas de texto do Claude e prompts do usuário - **Chamadas de ferramentas** — Cada ferramenta que o Claude invocou, com sua entrada e saída - **Atividade de políticas** — Para cada chamada de ferramenta, quais políticas foram acionadas e qual decisão retornaram -A barra de estatísticas no topo mostra a duração da sessão, total de chamadas de ferramentas e um resumo das decisões de hook (contagens de allow / deny / instruct). +A barra de estatísticas no topo exibe a duração da sessão, total de chamadas de ferramentas e um resumo das decisões de hooks (contagens de allow / deny / instruct). -Clique no botão **Download Logs** para exportar a sessão. Para sessões do Claude Code, Codex, Copilot, Cursor, Pi e Gemini, você recebe a transcrição JSONL original em disco byte a byte; para o OpenCode (cujas sessões ficam no SQLite, não em disco) você recebe um documento JSON espelhando as tabelas subjacentes `session` / `messages` / `parts`. +Clique no botão **Download Logs** para exportar a sessão. Para sessões Claude Code, Codex, Copilot, Cursor e Pi, você obtém a transcrição JSONL original em disco, byte a byte; para OpenCode (cujas sessões ficam no SQLite, não em disco) você obtém um documento JSON espelhando as tabelas subjacentes `session` / `messages` / `parts`. -### Auditoria +### Audit -Um relatório com personalidade sobre como seu agente tem se comportado ao longo das sessões anteriores. Executa a mesma varredura que o CLI `failproofai audit`, mas renderiza como um pôster de tela única compartilhável + quatro seções abaixo da dobra: +Um relatório orientado por personalidade de como seu agente tem se comportado nas sessões anteriores. Executa a mesma varredura que o CLI `failproofai audit`, mas renderiza como um pôster compartilhável de tela única + quatro seções abaixo da dobra: -1. **Pôster** — preenche o primeiro viewport. Região de captura PNG autocontida com a marca failproof_ai + rótulo de auditoria · índice de arquétipo (`№ NN de 08`) + data da auditoria · pontuação numérica (0–100) + pílula de percentil (`top 15%`) · o nome do arquétipo (um de `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + faixa de 3 palavras-chave · linha de raridade `// only N% of agents are this archetype` · tile de sigilo 8×8 pixels · rodapé `audit yours → failproof.ai`. Três botões de compartilhamento ficam logo fora da caixa de captura: `post your archetype` (X intent), `share on linkedin`, `download poster`. A captura é feita via `html-to-image`, então o PNG corresponde pixel a pixel ao render na tela (bordas tracejadas, máscara de logo SVG, gradientes, métricas de fonte — tudo preservado). -2. **Pontos fortes** — lista de linhas com ✓ tranquilo dos comportamentos que seu agente já faz corretamente, derivada dos dados de auditoria ao vivo (taxa limpa de chamadas de ferramentas, sem pushes diretos para main, zero vazamentos de credenciais, zero tempestades de retry) — cada item exibido apenas quando a política relevante tem um histórico limpo dentro da janela de auditoria. -3. **Peculiaridades** — tabela do que passou despercebido, ordenada por severidade: `when · what slipped + the policy that would've caught it · severity pill · seen`, onde a recorrência lê `new` (uma vez), `N× seen` (2–9 vezes), ou `recurring` (10+). -4. **Como melhorar** — lista de linhas tranquila, uma por política prescrita: nome da política em branco, descrição em uma linha, comando de instalação + botão de cópia à direita. O cabeçalho da seção lê `enable all N → projected · ` (a pontuação que você atingiria com todas as correções aplicadas), e seu botão `[install all]` copia o comando combinado `failproofai policy add a b c …` para cada política prescrita. -5. **Volte melhor** — dois cards lado a lado. Esquerdo: definir um lembrete (seletor de cadência `3d` / `7d` / `14d` / `30d`; persiste via `/api/auth/reminder` após autenticação). Direito: desbloquear benefícios failproof — `invite a friend` abre um modal que aceita uma lista de e-mails de amigos separados por vírgula/espaço/quebra de linha (máx. 10 por envio), faz POST para `/api/audit/invite`, que repassa para o `POST /v0/invite` do api-server. O api-server envia um e-mail por destinatário de `invite@failproof.ai` com o remetente em Cc e `Reply-To` definido, para que o destinatário veja quem o convidou e o remetente receba uma cópia em sua caixa de entrada. Usuários anônimos são redirecionados pelo `AuthDialog` primeiro, para que o e-mail do remetente seja conhecido antes de os convites serem enviados. Direitos / cumprimento de benefícios é uma etapa posterior. +1. **Pôster** — preenche o primeiro viewport. Região de captura PNG independente com o logotipo failproof_ai + label de auditoria · índice de arquétipo (`№ NN de 08`) + data da auditoria · pontuação numérica (0–100) + pílula de classificação percentil (`top 15%`) · o nome do arquétipo (um de `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + faixa de 3 palavras-chave · linha de raridade `// only N% of agents are this archetype` · tile de sigilo 8×8 pixels · rodapé `audit yours → failproof.ai`. Três botões de compartilhamento ficam logo fora da caixa de captura: `post your archetype` (X intent), `share on linkedin`, `download poster`. A captura é feita via `html-to-image`, portanto o PNG corresponde pixel a pixel ao que está na tela (bordas tracejadas, máscara de logo SVG, gradientes, métricas de fonte — tudo preservado). +2. **Pontos fortes** — lista calma de comportamentos que seu agente já faz corretamente, derivada dos dados de auditoria ao vivo (taxa limpa de chamadas de ferramentas, sem pushes diretos para a branch principal, zero vazamentos de credenciais, zero tempestades de retry) — cada item exibido apenas quando a política relevante tem um histórico limpo ao longo da janela de auditoria. +3. **Peculiaridades** — tabela do que passou despercebido, ordenada por gravidade: `quando · o que escapou + a política que teria detectado · pílula de gravidade · visto`, onde a recorrência é `new` (uma vez), `N× seen` (2–9 vezes) ou `recurring` (10+). +4. **Como melhorar** — lista calma de itens, um por política prescrita: nome da política em branco, descrição em uma linha, comando de instalação + botão de cópia à direita. O cabeçalho da seção exibe `enable all N → projected · ` (a pontuação que você alcançaria com todas as correções aplicadas), e seu botão `[install all]` copia o comando `failproofai policy add a b c …` combinado para cada política prescrita. +5. **Volte melhor** — dois cards lado a lado. Esquerda: definir um lembrete (seletor de cadência `3d` / `7d` / `14d` / `30d`; persiste via `/api/auth/reminder` após autenticação). Direita: desbloquear benefícios failproof — `invite a friend` abre um modal que aceita uma lista separada por vírgula/espaço/quebra de linha de e-mails de amigos (máx. 10 por envio), envia via POST para `/api/audit/invite`, que encaminha para o `POST /v0/invite` do api-server. O api-server envia um e-mail por destinatário a partir de `invite@failproof.ai` com o remetente em Cc e `Reply-To` definido, para que o destinatário veja quem o convidou e o remetente receba uma cópia em sua caixa de entrada. Usuários anônimos são redirecionados pelo `AuthDialog` primeiro, para que o e-mail do remetente seja conhecido antes de os convites serem enviados. Direitos / cumprimento de benefícios é uma etapa futura. -Alimentado pelo runtime `failproofai audit` — consulte [Audit CLI](/pt-br/cli/audit) para o mecanismo de varredura subjacente, flags suportadas e invariantes de cache por transcrição. O dashboard armazena em cache o resultado mais recente em `~/.failproofai/audit-dashboard.json` (modo `0600`, slot único, novas execuções sobrescrevem) para que revisitas sejam instantâneas; **tanto o cache por transcrição quanto o cache de resultado completo são rejeitados na leitura quando têm mais de 7 dias**, para que o dashboard nunca sirva silenciosamente um resultado de uma semana atrás — após o TTL, `/audit` cai no estado vazio e solicita uma nova execução. Clicar em `[ re-audit now ]` perto do final do relatório faz POST para `/api/audit/run` com `noCache: true` — a re-auditoria ignora o cache por transcrição e reanalisa todas as transcrições do zero em vez de retornar silenciosamente o resultado em cache — e o dashboard verifica `/api/audit/status` a 1Hz até a execução terminar; uma faixa de progresso rosa fixada no topo do viewport durante a execução exibe um timer decorrido, e o resultado atualizado substitui o anterior no lugar ao término com sucesso (sem recarregamento completo da página; uma re-auditoria com falha mantém o relatório anterior intacto). Em caso de falha, a faixa fica vermelha com texto baseado no `RerunError.kind` (`timeout` / `network` / `post_failed`). O estado vazio (sem cache ou expirado) e o estado de zero sessões (cache existe, mas a varredura não encontrou transcrições) são exibidos separadamente. +Impulsionado pelo runtime `failproofai audit` — veja [Audit CLI](/pt-br/cli/audit) para o mecanismo de varredura subjacente, flags suportadas e invariantes de cache por transcrição. O dashboard armazena em cache o resultado mais recente em `~/.failproofai/audit-dashboard.json` (modo `0600`, slot único, novas execuções sobrescrevem) para que revisitas sejam instantâneas; **tanto o cache por transcrição quanto o cache de resultado completo são rejeitados na leitura quando têm mais de 7 dias**, para que o dashboard nunca sirva silenciosamente um resultado de uma semana atrás — após o TTL, `/audit` retorna ao estado vazio e solicita uma nova execução. Clicar em `[ re-audit now ]` próximo ao final do relatório envia POST para `/api/audit/run` com `noCache: true` — o re-audit ignora o cache por transcrição e reescaneia cada transcrição do zero em vez de retornar silenciosamente o resultado em cache — e o dashboard consulta `/api/audit/status` a 1Hz até a execução terminar; uma faixa de progresso rosa fixa no topo do viewport durante a execução com um timer de tempo decorrido, e o resultado atualizado substitui o anterior ao concluir (sem recarregamento completo da página; um re-audit com falha mantém o relatório anterior intacto). Em caso de falha, a faixa fica vermelha com texto baseado no `RerunError.kind` (`timeout` / `network` / `post_failed`). O estado vazio (sem cache ou expirado) e o estado de zero sessões (cache existe, mas a varredura não encontrou transcrições) são exibidos separadamente. ### Políticas -Uma página com duas abas para gerenciar políticas e revisar atividade. +Uma página com duas abas para gerenciar políticas e revisar atividades. - - Selecione múltiplos CLIs de agentes que o failproofai protege em um único painel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI e Hermes têm uma linha com status de instalação (`Active` / `Detected` / `Inactive`), o caminho de configurações de escopo do usuário e um destaque com a cor da marca. Marque ou desmarque os CLIs desejados e clique em `Apply changes` para instalar/desinstalar as alterações em uma etapa. CLIs cujo binário é detectado no PATH são pré-selecionados. - - Ative ou desative políticas individuais com um único clique (escreve em `~/.failproofai/policies-config.json` — compartilhado entre todos os CLIs instalados) + - Selecione múltiplos CLIs de agentes que o failproofai protege a partir de um único painel — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi e Hermes têm uma linha com status de instalação (`Active` / `Detected` / `Inactive`), o caminho de configurações do escopo de usuário e um acento colorido por marca. Marque ou desmarque os CLIs desejados e clique em `Apply changes` para instalar/desinstalar a diferença em uma única etapa. CLIs cujo binário é detectado no PATH são pré-marcados. + - Ative ou desative políticas individuais com um único clique (grava em `~/.failproofai/policies-config.json` — compartilhado entre todos os CLIs instalados) - Expanda uma política para configurar seus parâmetros (para políticas que suportam `policyParams`) - Defina um caminho personalizado para o arquivo de políticas - - Histórico paginado completo de cada evento de hook que foi acionado em todas as sessões - - Filtre por decisão, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), nome da política ou ID de sessão - - Cada linha exibe: timestamp, nome da política, decisão, badge de CLI (laranja = Claude Code, roxo = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, âmbar = OpenCode, rosa = Pi, celeste = Gemini CLI, índigo = Hermes), nome da ferramenta, ID de sessão e o motivo das decisões deny/instruct - - Clique em um ID de sessão para abrir sua transcrição — o visualizador detecta automaticamente qual CLI acionou o hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) e renderiza o badge de CLI correspondente no cabeçalho + - Histórico paginado completo de cada evento de hook acionado em todas as sessões + - Filtre por decisão, tipo de evento, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), nome da política ou ID de sessão + - Cada linha exibe: timestamp, nome da política, decisão, badge de CLI (laranja = Claude Code, roxo = OpenAI Codex, azul = GitHub Copilot, esmeralda = Cursor Agent, âmbar = OpenCode, rosa = Pi, índigo = Hermes, teal = OpenClaw, rosa-escuro = Factory Droid, violeta = Devin, ciano = Antigravity, lima = Goose), nome da ferramenta, ID da sessão e o motivo para decisões de deny/instruct + - Clique em um ID de sessão para abrir sua transcrição — o visualizador detecta automaticamente qual CLI acionou o hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) e renderiza o badge de CLI correspondente no cabeçalho @@ -96,7 +96,7 @@ O dashboard possui um toggle de atualização automática na navegação superio --- -## Desativando páginas +## Desabilitando páginas Se você precisar apenas de algumas partes do dashboard, defina `FAILPROOFAI_DISABLE_PAGES` com uma lista separada por vírgulas de nomes de páginas: @@ -118,15 +118,15 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## Acessando a partir de um host diferente de localhost +## Acessando de um host diferente de localhost -Ao executar o dashboard em **modo dev** (`npm run dev`) e acessá-lo a partir de um hostname diferente de `localhost` — por exemplo, um domínio personalizado, um IP remoto ou uma URL tunelada — você pode ver um aviso como: +Ao executar o dashboard em **modo de desenvolvimento** (`npm run dev`) e acessá-lo a partir de um hostname diferente de `localhost` — por exemplo, um domínio personalizado, um IP remoto ou uma URL tunelada — você pode ver um aviso como: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Isso é o Next.js bloqueando o acesso cross-origin ao seu websocket HMR (hot module reload), que é um recurso exclusivo do modo dev. Para permitir seu host, use a flag `--allowed-origins`: +Isso é o Next.js bloqueando o acesso cross-origin ao seu websocket HMR (hot module reload), que é um recurso exclusivo de desenvolvimento. Para permitir seu host, use a flag `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com @@ -145,5 +145,5 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Isso se aplica apenas ao modo dev. Ao executar `failproofai` (modo produção), não há websocket HMR nem problema de recurso dev cross-origin. +Isso se aplica apenas ao modo de desenvolvimento. Ao executar `failproofai` (modo de produção), não há websocket HMR nem problema de recurso de desenvolvimento cross-origin. \ No newline at end of file diff --git a/docs/pt-br/getting-started.mdx b/docs/pt-br/getting-started.mdx index 133c5565..6c05402a 100644 --- a/docs/pt-br/getting-started.mdx +++ b/docs/pt-br/getting-started.mdx @@ -31,15 +31,15 @@ bun add -g failproofai - Políticas são regras que executam antes e depois de cada chamada de ferramenta do agente. Elas interceptam comandos destrutivos, vazamento de segredos e outros modos de falha antes que causem danos. + Políticas são regras executadas antes e depois de cada chamada de ferramenta do agente. Elas detectam comandos destrutivos, vazamento de segredos e outros modos de falha antes que causem danos. ```bash failproofai policies --install ``` - Isso registra entradas de hook nos CLIs de agente instalados (o `~/.claude/settings.json` do Claude Code, o `~/.codex/hooks.json` do OpenAI Codex, o `~/.copilot/hooks/failproofai.json` do GitHub Copilot CLI, o `~/.cursor/hooks.json` do Cursor Agent, o shim de plugin gerado pelo OpenCode em `~/.config/opencode/plugins/failproofai.mjs` mais uma entrada de registro no array `plugin` de `~/.config/opencode/opencode.json`, o `~/.pi/agent/settings.json` do Pi, o `~/.gemini/settings.json` do Gemini CLI ou o `~/.hermes/config.yaml` do Hermes). Se mais de um estiver presente, você será solicitado a escolher; passe `--cli claude codex copilot cursor opencode pi gemini hermes` (qualquer subconjunto) para pular a seleção. + Isso escreve entradas de hook nos CLIs de agente instalados (`~/.claude/settings.json` do Claude Code, `~/.codex/hooks.json` do OpenAI Codex, `~/.copilot/hooks/failproofai.json` do GitHub Copilot CLI, `~/.cursor/hooks.json` do Cursor Agent, o plugin shim gerado pelo OpenCode em `~/.config/opencode/plugins/failproofai.mjs` mais uma entrada de registro no array `plugin` de `~/.config/opencode/opencode.json`, `~/.pi/agent/settings.json` do Pi, `~/.hermes/config.yaml` do Hermes, `~/.openclaw/openclaw.json` do OpenClaw, `~/.factory/hooks.json` do Factory Droid, `~/.config/devin/config.json` do Devin CLI, `~/.gemini/config/hooks.json` do Antigravity CLI ou o diretório de plugins auto-descoberto do Goose em `~/.agents/plugins/failproofai/hooks/hooks.json`). Quando mais de um estiver presente, você será solicitado a escolher; passe `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (qualquer subconjunto) para pular o prompt. - O suporte ao GitHub Copilot CLI, Cursor Agent, OpenCode, Pi e Gemini CLI está em **beta** — instale com `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` ou `--cli gemini`. O Hermes (hermes-agent, um gateway Slack/Telegram) é instalado no escopo de usuário com `--cli hermes` e é **também** uma fonte de auditoria offline. + O suporte ao GitHub Copilot CLI, Cursor Agent, OpenCode e Pi está em **beta** — instale com `--cli copilot`, `--cli cursor`, `--cli opencode` ou `--cli pi`. O Hermes (hermes-agent, um gateway Slack/Telegram) é instalado com escopo de usuário via `--cli hermes` e é **também** uma fonte de auditoria offline. O OpenClaw (gateway openclaw, um assistente multicanal auto-hospedado) é instalado com escopo de usuário via `--cli openclaw` — a execução de políticas ocorre através dos hooks de plugin em processo (`before_agent_finalize` é um gate real de fim de turno, portanto os builtins `require-*-before-stop` são aplicados) — e é **também** uma fonte de auditoria offline. O Factory Droid (`droid`) é instalado com `--cli factory` (escopo de usuário + projeto) e é **também** uma fonte de auditoria offline. O Devin CLI (`devin`, Cognition) é instalado com `--cli devin` (escopo de usuário + projeto) e é **também** uma fonte de auditoria offline. O Antigravity CLI (`agy`) é instalado com `--cli antigravity` (escopo de usuário + projeto) e é **também** uma fonte de auditoria offline. O Goose (codinome goose, Block) é instalado com `--cli goose` (escopo de usuário + projeto) — o instalador apenas cria um diretório de plugin em `~/.agents/plugins/failproofai/` que o Goose descobre automaticamente, e é **também** uma fonte de auditoria offline. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,17 +62,17 @@ bun add -g failproofai failproofai policies ``` - Exibe todas as políticas, se estão ativadas e quaisquer parâmetros configurados. + Exibe todas as políticas, se estão ativas e quaisquer parâmetros configurados. ```bash failproofai ``` - Abre um painel local em `http://localhost:8020` onde você pode navegar pelas sessões, inspecionar chamadas de ferramentas e gerenciar políticas. + Abre um painel local em `http://localhost:8020` onde você pode navegar por sessões, inspecionar chamadas de ferramentas e gerenciar políticas. - Inicie o Claude Code normalmente. Se o agente tentar algo arriscado, o failproofai intercepta automaticamente. Deixe-o rodando sem supervisão e revise o que aconteceu no painel. + Inicie o Claude Code normalmente. Se o agente tentar algo arriscado, o failproofai o intercepta automaticamente. Deixe-o rodando sem supervisão e revise o que aconteceu no painel. @@ -88,17 +92,17 @@ Cada política retorna uma de três decisões: - **allow** - o agente prossegue normalmente - **deny** - a ação é bloqueada e o agente é informado do motivo -- **instruct** - contexto adicional é inserido no prompt do agente +- **instruct** - contexto adicional é adicionado ao prompt do agente -As políticas rodam no seu processo local. Nada é enviado para um serviço remoto. +As políticas são executadas no seu processo local. Nada é enviado para um serviço remoto. --- -## Configurar políticas de equipe com políticas baseadas em convenção +## Configure políticas de equipe com políticas baseadas em convenção -A maneira mais rápida de estabelecer padrões de qualidade em toda a sua equipe é a convenção `.failproofai/policies/`. Coloque arquivos de política nesse diretório e eles são carregados automaticamente — sem flags, sem alterações de configuração, sem comandos de instalação. +A maneira mais rápida de estabelecer padrões de qualidade em toda a equipe é a convenção `.failproofai/policies/`. Coloque arquivos de política nesse diretório e eles são carregados automaticamente — sem flags, sem alterações de configuração, sem comandos de instalação. @@ -138,27 +142,27 @@ A maneira mais rápida de estabelecer padrões de qualidade em toda a sua equipe git commit -m "Add team quality policies" ``` - Todo membro da equipe que tiver o failproofai instalado receberá essas políticas automaticamente. Sem configuração por desenvolvedor. + Todo membro da equipe que tem o failproofai instalado recebe essas políticas automaticamente. Nenhuma configuração individual por desenvolvedor é necessária. -Faça commit de `.failproofai/policies/` no seu repositório para que toda a equipe compartilhe os mesmos padrões. À medida que a equipe descobrir novos modos de falha, adicione políticas e faça push — todos recebem a atualização no próximo `git pull`. Com o tempo, essas políticas se tornam um padrão de qualidade vivo que continua melhorando. +Faça commit de `.failproofai/policies/` no seu repositório para que toda a equipe compartilhe os mesmos padrões. À medida que sua equipe descobre novos modos de falha, adicione políticas e faça push — todos recebem a atualização no próximo `git pull`. Com o tempo, essas políticas se tornam um padrão de qualidade vivo que continua melhorando. --- ## Armazenamento de dados -Todas as configurações e logs ficam na sua máquina: +Toda a configuração e os logs ficam armazenados na sua máquina: | Caminho | O que armazena | |---------|----------------| | `~/.failproofai/policies-config.json` | Configuração global de políticas | | `~/.failproofai/hook-activity.jsonl` | Histórico de execução de hooks | -| `~/.failproofai/hook.log` | Log de depuração para erros de hooks personalizados | -| `.failproofai/policies-config.json` | Configuração por projeto (versionada) | -| `.failproofai/policies-config.local.json` | Substituições pessoais (ignoradas pelo git) | +| `~/.failproofai/hook.log` | Log de depuração para erros de hooks customizados | +| `.failproofai/policies-config.json` | Configuração por projeto (commitada) | +| `.failproofai/policies-config.local.json` | Substituições pessoais (no gitignore) | --- @@ -168,7 +172,7 @@ Todas as configurações e logs ficam na sua máquina: failproofai policies --uninstall ``` -Remove as entradas de hook do `~/.claude/settings.json`. Os arquivos de configuração em `~/.failproofai/` são mantidos. +Remove as entradas de hook de `~/.claude/settings.json`. Os arquivos de configuração em `~/.failproofai/` são mantidos. --- @@ -184,11 +188,11 @@ Remove as entradas de hook do `~/.claude/settings.json`. Os arquivos de configur Todas as 26 políticas com seus parâmetros - + Escreva suas próprias políticas em JavaScript - + Monitore sessões e revise a atividade das políticas diff --git a/docs/pt-br/introduction.mdx b/docs/pt-br/introduction.mdx index aaf26213..1fcf1656 100644 --- a/docs/pt-br/introduction.mdx +++ b/docs/pt-br/introduction.mdx @@ -1,15 +1,15 @@ --- title: "Failproof AI" -description: "FailproofAI oferece 39 políticas de falha integradas para agentes de IA que detectam loops, vazamentos de segredos, chamadas de ferramentas destrutivas e muito mais em uma única instalação." +description: "FailproofAI oferece aos agentes de IA 39 políticas de falha integradas que detectam loops, vazamentos de segredos, chamadas de ferramentas destrutivas e muito mais em uma única instalação." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks e políticas para **tratamento de falhas de IA**, **recuperação de erros** e **confiabilidade de LLMs**. Mantenha seus agentes de IA confiáveis e funcionando de forma autônoma no **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** e no **Agents SDK**. +Hooks e políticas para **tratamento de falhas em IA**, **recuperação de erros** e **confiabilidade de LLMs**. Mantenha seus agentes de IA confiáveis e funcionando de forma autônoma no **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** e no **Agents SDK**. -Agentes de IA falham de maneiras previsíveis. Eles executam comandos destrutivos, vazam segredos, desviam da tarefa, ficam presos em loops ou fazem push direto para a branch principal. Sem supervisão, falhas pequenas evoluem para quedas de serviço, credenciais expostas e trabalho perdido. +Agentes de IA falham de formas previsíveis. Eles executam comandos destrutivos, vazam segredos, saem da tarefa, ficam presos em loops ou fazem push direto para a branch principal. Sem supervisão, pequenas falhas se transformam em interrupções, credenciais expostas e trabalho perdido. -O FailproofAI resolve isso com **políticas**. Essas regras se integram a cada chamada de ferramenta do agente para **detectar falhas**, **mitigá-las** (bloquear, instruir, sanitizar) e **alertar você** quando algo precisa de atenção. Um painel local permite revisar todas as chamadas de ferramenta, falhas do agente e ações de recuperação posteriormente. +FailproofAI resolve isso com **políticas**. Essas regras se conectam a cada chamada de ferramenta do agente para **detectar falhas**, **mitigá-las** (bloquear, instruir, sanitizar) e **alertar você** quando algo precisa de atenção. Um painel local permite revisar cada chamada de ferramenta, falha do agente e ação de recuperação depois do fato. Nenhum dado sai da sua máquina. @@ -18,7 +18,7 @@ Nenhum dado sai da sua máquina. - Bloqueie comandos destrutivos, evite vazamentos de segredos, mantenha os agentes dentro dos limites do projeto e muito mais. Tudo pronto para uso. + Bloqueie comandos destrutivos, evite vazamento de segredos, mantenha os agentes dentro dos limites do projeto e muito mais. Tudo pronto para uso. @@ -26,10 +26,10 @@ Nenhum dado sai da sua máquina. - Veja o que seus agentes fizeram enquanto você estava ausente. Navegue por sessões, inspecione chamadas de ferramentas e revise onde as políticas foram acionadas. + Veja o que seus agentes fizeram enquanto você estava ausente. Navegue pelas sessões, inspecione chamadas de ferramentas e revise onde as políticas foram acionadas. - + Ajuste qualquer política sem escrever código. Defina listas de permissões, branches protegidas ou limites por projeto ou globalmente. diff --git a/docs/ru/built-in-policies.mdx b/docs/ru/built-in-policies.mdx index 4a02f746..b8a1c3f0 100644 --- a/docs/ru/built-in-policies.mdx +++ b/docs/ru/built-in-policies.mdx @@ -1,39 +1,39 @@ --- title: Встроенные политики -description: "39 встроенных политик для предотвращения типичных сбоев агентов" +description: "Все 39 встроенных политик, которые перехватывают распространённые режимы отказа агентов" icon: shield --- -failproofai поставляется с 39 встроенными политиками, которые предотвращают типичные сбои агентов. Каждая политика срабатывает на определённый тип события хука и имя инструмента. Девятнадцать политик принимают параметры, позволяющие настраивать их поведение без написания кода. Пять рабочих политик обеспечивают соблюдение конвейера commit → push → PR → CI перед остановкой Claude. +failproofai поставляется с 39 встроенными политиками, которые перехватывают распространённые режимы отказа агентов. Каждая политика срабатывает на определённый тип события хука и имя инструмента. Девятнадцать политик принимают параметры, которые позволяют настроить их поведение без написания кода. Пять политик рабочего процесса обеспечивают конвейер commit → push → PR → CI перед остановкой Claude. --- ## Обзор -Политики разделены по категориям: +Политики сгруппированы по категориям: | Категория | Политики | Тип хука | |----------|----------|-----------| -| [Опасные команды](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | -| [Инфраструктурные команды](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [Секреты (санитайзеры)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | -| [Окружение](#environment) | block-env-files, protect-env-vars | PreToolUse | -| [Доступ к файлам](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | +| [Опасные команды](#опасные-команды) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | +| [Команды инфраструктуры](#команды-инфраструктуры) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | +| [Секреты (санитайзеры)](#секреты-санитайзеры) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [Окружение](#окружение) | block-env-files, protect-env-vars | PreToolUse | +| [Доступ к файлам](#доступ-к-файлам) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | -| [База данных](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | -| [Предупреждения](#warnings) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | -| [Менеджеры пакетов](#package-managers) | prefer-package-manager | PreToolUse | -| [Рабочий процесс](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | +| [База данных](#база-данных) | warn-destructive-sql, warn-schema-alteration | PreToolUse | +| [Предупреждения](#предупреждения) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | +| [Менеджеры пакетов](#менеджеры-пакетов) | prefer-package-manager | PreToolUse | +| [Рабочий процесс](#рабочий-процесс) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — остановить агента от продолжения. -- **`warn-`** — дать агенту дополнительный контекст для самокоррекции. -- **`sanitize-`** — удалить чувствительные данные из вывода инструмента перед отправкой агенту. +- **`block-`** — остановить агента от продолжения работы. +- **`warn-`** — дать агенту дополнительный контекст, чтобы он мог автоисправиться. +- **`sanitize-`** — удалить чувствительные данные из вывода инструмента перед тем, как агент их увидит. ### Пространства имён -Каждая политика находится в слоте `/`. Встроенные политики принадлежат пространству имён **`failproofai/`** — например, `failproofai/sanitize-jwt`. Пространство имён предотвращает коллизии при загрузке пользовательских или сторонних политик с похожими названиями. +Каждая политика находится в слоте `/`. Встроенные политики принадлежат пространству имён **`failproofai/`** — например, `failproofai/sanitize-jwt`. Пространство имён предотвращает коллизии при загрузке пользовательских или сторонних политик с похожими короткими именами. -В конфиге вы можете ссылаться на встроенную политику либо по краткому имени, либо по полному имени; обе формы разрешаются в одну политику: +В вашей конфигурации вы можете ссылаться на встроенную политику либо по её короткому имени, либо по полному имени; обе формы разрешаются в одну политику: ```json { @@ -44,27 +44,27 @@ failproofai поставляется с 39 встроенными политик } ``` -Если имя не содержит `/`, failproofai считает его принадлежащим пространству имён по умолчанию `failproofai`. Имена, уже содержащие `/` (например, `myorg/foo`, `custom/my-hook`), сохраняются как есть. -- **`require-`** — блокировать событие Stop до выполнения условий. +Если имя не содержит `/`, failproofai считает его принадлежащим пространству имён по умолчанию `failproofai`. Имена, которые уже содержат `/` (например `myorg/foo`, `custom/my-hook`), сохраняются как есть. +- **`require-`** — заблокировать событие Stop до выполнения условий. --- -Каждая политика поддерживает необязательное поле `hint` в `policyParams`. Подсказка добавляется к сообщению deny или instruct, которое видит Claude, предоставляя практичное руководство без изменения кода политики. Работает со встроенными, пользовательскими и условными политиками. Подробнее см. [Configuration → hint](/ru/configuration#hint-cross-cutting). +Каждая политика поддерживает необязательное поле `hint` в `policyParams`. Подсказка добавляется к сообщению deny или instruct, которое видит Claude, предоставляя практические советы без изменения кода политики. Работает со встроенными, пользовательскими и конвенционными политиками. Подробнее см. [Configuration → hint](/ru/configuration#hint-cross-cutting). --- ## Опасные команды -Предотвратите выполнение агентами операций, которые сложно отменить или которые могут повредить хост-систему. +Предотвратить запуск операций агентами, которые сложно отменить или которые могут повредить хост-систему. ### `block-sudo` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любую команду `sudo`. +**По умолчанию:** Блокирует любую команду `sudo`. -Блокирует вызовы, содержащие ключевое слово `sudo`. Сопоставление осуществляется для разобранных токенов команды, а не для сырой строки, что предотвращает обход через инъекции операторов оболочки. +Блокирует вызовы, которые включают ключевое слово `sudo`. Сопоставление паттернов выполняется на разобранных токенах команды, а не на исходной строке, чтобы предотвратить обход через инъекцию операторов оболочки. **Параметры:** @@ -84,10 +84,10 @@ failproofai поставляется с 39 встроенными политик } ``` -С такой конфигурацией `sudo systemctl status nginx` разрешена, но `sudo rm /etc/hosts` запрещена. +С этой конфигурацией `sudo systemctl status nginx` разрешена, но `sudo rm /etc/hosts` заблокирована. -Шаблоны сопоставляются с разобранными токенами, а не с сырой командной строкой. Это предотвращает обход через добавленные операторы оболочки (например, `sudo systemctl status x; rm -rf /` не совпадает с `sudo systemctl status *`). +Паттерны сопоставляются с разобранными токенами, а не с исходной строкой команды. Это предотвращает обход через добавленные операторы оболочки (например `sudo systemctl status x; rm -rf /` не совпадает с `sudo systemctl status *`). --- @@ -95,13 +95,13 @@ failproofai поставляется с 39 встроенными политик ### `block-rm-rf` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает `rm -rf`, `rm -fr` и аналогичные формы рекурсивного удаления. +**По умолчанию:** Блокирует `rm -rf`, `rm -fr` и аналогичные формы рекурсивного удаления. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Пути, которые безопасно удалять рекурсивно (например, `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Пути, безопасные для рекурсивного удаления (например `/tmp`). | **Пример:** @@ -120,37 +120,37 @@ failproofai поставляется с 39 встроенными политик ### `block-curl-pipe-sh` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает `curl | bash`, `curl | sh`, `wget | bash` и аналогичные шаблоны. +**По умолчанию:** Блокирует `curl | bash`, `curl | sh`, `wget | bash` и аналогичные паттерны. -Нет параметров. +Без параметров. --- ### `block-failproofai-commands` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает команды, которые деинсталлировали бы или отключили бы сам failproofai (например, `npm uninstall failproofai`, `failproofai policies --uninstall`). +**По умолчанию:** Блокирует команды, которые удалили бы или отключили бы сам failproofai (например `npm uninstall failproofai`, `failproofai policies --uninstall`). -Нет параметров. +Без параметров. --- -## Инфраструктурные команды +## Команды инфраструктуры -Предотвратите выполнение агентами инфраструктурных CLI или запуск конвейеров CI/CD. Все политики в этой категории **опциональны** (`defaultEnabled: false`) — агенты, которым действительно требуется вызывать `kubectl`, `terraform` и т. д., не будут нарушены, если только вы не включите политику. Если политика включена, любое использование подходящего CLI запрещено, если команда не совпадает с записью в `allowPatterns`. +Остановить кодирующих агентов от запуска CLI инфраструктуры или триггерирования конвейеров CI/CD. Все политики в этой категории **opt-in** (`defaultEnabled: false`) — агенты, которым действительно нужно вызывать `kubectl`, `terraform` и т. д., не будут нарушены, если вы не включите политику. При включении каждый вызов соответствующего CLI отклоняется, если только команда не совпадает с записью в `allowPatterns`. -Грамматика шаблонов совпадает с [`block-sudo`](#block-sudo): токены сопоставляются с разобранными argv, `*` — это подстановочный знак для одного токена, и любая команда, содержащая отдельный оператор оболочки (`&&`, `||`, `|`, `;`) или токен с внедрёнными метасимволами оболочки, отклоняется до проверки разрешённого списка, что предотвращает инъекции. +Грамматика паттернов та же, что и в [`block-sudo`](#block-sudo): токены сопоставляются с разобранным argv, `*` — подстановочный знак для одного токена, и любая команда, содержащая автономный оператор оболочки (`&&`, `||`, `|`, `;`) или токен со встроенными метасимволами оболочки, отклоняется перед сопоставлением со списком разрешённых, чтобы предотвратить обход инъекций. ### `block-kubectl` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование `kubectl`. +**По умолчанию:** Блокирует любой вызов `kubectl`. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы kubectl-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд kubectl, которые разрешены. | **Пример:** @@ -164,20 +164,20 @@ failproofai поставляется с 39 встроенными политик } ``` -С такой конфигурацией `kubectl get pods` разрешена, но `kubectl apply -f deploy.yaml` запрещена. +С этой конфигурацией `kubectl get pods` разрешена, но `kubectl apply -f deploy.yaml` заблокирована. --- ### `block-terraform` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование `terraform` или `tofu` (OpenTofu). +**По умолчанию:** Блокирует любой вызов `terraform` или `tofu` (OpenTofu). **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы terraform/tofu-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд terraform/tofu, которые разрешены. | **Пример:** @@ -196,13 +196,13 @@ failproofai поставляется с 39 встроенными политик ### `block-aws-cli` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование AWS CLI. +**По умолчанию:** Блокирует любой вызов CLI `aws`. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы aws-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд aws CLI, которые разрешены. | **Пример:** @@ -221,13 +221,13 @@ failproofai поставляется с 39 встроенными политик ### `block-gcloud` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование `gcloud` (Google Cloud CLI). +**По умолчанию:** Блокирует любой вызов CLI `gcloud` (Google Cloud). **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы gcloud-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд gcloud, которые разрешены. | **Пример:** @@ -246,13 +246,13 @@ failproofai поставляется с 39 встроенными политик ### `block-az-cli` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование `az` (Azure CLI). +**По умолчанию:** Блокирует любой вызов CLI `az` (Azure). **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы az-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд az CLI, которые разрешены. | **Пример:** @@ -271,13 +271,13 @@ failproofai поставляется с 39 встроенными политик ### `block-helm` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает любое использование `helm`. +**По умолчанию:** Блокирует любой вызов `helm`. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Префиксы helm-команд, которые разрешены. | +| `allowPatterns` | `string[]` | `[]` | Префиксы команд helm, которые разрешены. | **Пример:** @@ -296,7 +296,7 @@ failproofai поставляется с 39 встроенными политик ### `block-gh-pipeline` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает следующие подкоманды `gh` CLI, которые изменяют состояние или запускают конвейеры: +**По умолчанию:** Блокирует следующие подкоманды `gh` CLI, которые изменяют состояние или триггерируют конвейеры: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -305,13 +305,13 @@ failproofai поставляется с 39 встроенными политик - `gh cache delete` - `gh secret set`, `gh secret delete` -Только для чтения подкоманды `gh`, такие как `gh pr view`, `gh pr list`, `gh run list`, `gh release view` и `gh api repos/.../...` **не** совпадают с этой политикой — они регулярно требуются для проверок рабочего процесса (включая собственный `require-ci-green-before-stop` failproofai). +Доступные только для чтения подкоманды `gh`, такие как `gh pr view`, `gh pr list`, `gh run list`, `gh release view` и `gh api repos/.../...` **не** совпадают с этой политикой — они регулярно требуются для проверок рабочего процесса (включая собственное `require-ci-green-before-stop` failproofai). **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | Определённые скриптовые вызовы для разрешения, хотя они иначе были бы запрещены. | +| `allowPatterns` | `string[]` | `[]` | Специфические скриптовые вызовы, разрешённые несмотря на то, что они были бы заблокированы. | **Пример:** @@ -329,27 +329,27 @@ failproofai поставляется с 39 встроенными политик ## Секреты (санитайзеры) -Предотвратите утечку учётных данных в контекст или выход агента. Политики-санитайзеры срабатывают на событиях **PostToolUse**. Когда Claude выполняет bash-команду, читает файл или вызывает любой инструмент, эти политики проверяют вывод перед возвратом агенту. Если обнаружен шаблон секрета, политика возвращает решение deny, которое предотвращает передачу вывода обратно. +Остановить утечку учётных данных агентом в их контекст или вывод. Политики санитайзера срабатывают на событиях **PostToolUse**. Когда Claude запускает команду Bash, читает файл или вызывает любой инструмент, эти политики проверяют вывод перед тем, как он возвращается Claude. Если обнаружен паттерн секрета, политика возвращает решение deny, которое предотвращает передачу вывода обратно. ### `sanitize-jwt` **Событие:** PostToolUse (все инструменты) -**По умолчанию:** Скрывает JWT-токены (три сегмента base64url, разделённые `.`). +**По умолчанию:** Стирает JWT токены (три сегмента base64url, разделённые `.`). -Нет параметров. +Без параметров. --- ### `sanitize-api-keys` **Событие:** PostToolUse (все инструменты) -**По умолчанию:** Скрывает распространённые форматы API-ключей: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`) и Google API keys (`AIza`). +**По умолчанию:** Стирает распространённые форматы API ключей: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`), и Google API keys (`AIza`). **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Дополнительные regex-шаблоны для обработки как секретов. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Дополнительные regex паттерны, которые будут считаться секретами. | **Пример:** @@ -371,68 +371,68 @@ failproofai поставляется с 39 встроенными политик ### `sanitize-connection-strings` **Событие:** PostToolUse (все инструменты) -**По умолчанию:** Скрывает строки подключения к БД, содержащие внедрённые учётные данные (например, `postgresql://user:password@host/db`). +**По умолчанию:** Стирает строки подключения к базе данных, которые содержат встроенные учётные данные (например `postgresql://user:password@host/db`). -Нет параметров. +Без параметров. --- ### `sanitize-private-key-content` **Событие:** PostToolUse (все инструменты) -**По умолчанию:** Скрывает PEM-блоки (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` и т. д.). +**По умолчанию:** Стирает PEM блоки (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` и т. д.). -Нет параметров. +Без параметров. --- ### `sanitize-bearer-tokens` **Событие:** PostToolUse (все инструменты) -**По умолчанию:** Скрывает заголовки `Authorization: Bearer `, где токен содержит 20 или более символов. +**По умолчанию:** Стирает заголовки `Authorization: Bearer `, где токен состоит из 20 или более символов. -Нет параметров. +Без параметров. --- ## Окружение -Защитите чувствительную конфигурацию окружения от чтения или раскрытия агентами. +Защитить чувствительную конфигурацию окружения от чтения или разглашения агентом. ### `block-env-files` **Событие:** PreToolUse (Bash, Read) -**По умолчанию:** Запрещает чтение файлов `.env` через `cat .env`, вызовы инструмента Read с `.env` в качестве пути файла и т. д. +**По умолчанию:** Блокирует чтение `.env` файлов через `cat .env`, вызовы инструмента Read с `.env` в качестве пути файла и т. д. -Не блокирует `.envrc` или другие файлы окружения — только файлы с точным именем `.env`. +Не блокирует `.envrc` или другие связанные с окружением файлы — только файлы с названием `.env`. -Нет параметров. +Без параметров. --- ### `protect-env-vars` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает команды, которые выводят переменные окружения: `printenv`, `env`, `echo $VAR`. +**По умолчанию:** Блокирует команды, которые выводят переменные окружения: `printenv`, `env`, `echo $VAR`. -Нет параметров. +Без параметров. --- ## Доступ к файлам -Держите агентов в границах проекта и подальше от чувствительных файлов. +Держать агентов внутри границ проекта и вдали от чувствительных файлов. ### `block-read-outside-cwd` **Событие:** PreToolUse (Read, Bash) -**По умолчанию:** Запрещает чтение файлов вне корня проекта. Границей является `CLAUDE_PROJECT_DIR` (устанавливается один раз за сессию Claude Code) с откатом на текущий рабочий каталог сессии, когда переменная не задана. Использование корня проекта вместо текущего `cwd` означает, что граница остаётся стабильной даже после `cd` Claude в подкаталог. +**По умолчанию:** Блокирует чтение файлов вне корня проекта. Граница — это `CLAUDE_PROJECT_DIR` (установлена один раз за сеанс Claude Code), с fallback на текущий рабочий каталог сеанса, когда эта переменная не установлена. Использование корня проекта вместо живой `cwd` означает, что граница остаётся стабильной даже после того, как Claude переходит в подкаталог. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | Префиксы абсолютных путей, которые разрешены даже если находятся вне корня проекта. | +| `allowPaths` | `string[]` | `[]` | Абсолютные префиксы путей, разрешённые даже если вне корня проекта. | **Пример:** @@ -451,13 +451,13 @@ failproofai поставляется с 39 встроенными политик ### `block-secrets-write` **Событие:** PreToolUse (Write, Edit) -**По умолчанию:** Запрещает запись в файлы, обычно используемые для приватных ключей и сертификатов: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**По умолчанию:** Блокирует запись в файлы, обычно используемые для приватных ключей и сертификатов: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | Дополнительные шаблоны имён файлов (glob-стиль) для блокировки. | +| `additionalPatterns` | `string[]` | `[]` | Дополнительные глоб-стиль паттерны имён файлов для блокировки. | **Пример:** @@ -475,18 +475,18 @@ failproofai поставляется с 39 встроенными политик ## Git -Предотвратите случайные push, force-push и ошибки в ветках, которые сложно отменить. +Предотвратить случайные push'и, force-push'и и ошибки ветвей, которые сложно отменить. ### `block-push-master` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает `git push origin main` и `git push origin master`. +**По умолчанию:** Блокирует `git push origin main` и `git push origin master`. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Имена ветвей, в которые нельзя отправлять напрямую. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Имена ветвей, в которые нельзя push'ить напрямую. | **Пример:** @@ -501,7 +501,7 @@ failproofai поставляется с 39 встроенными политик ``` -Чтобы разрешить отправку во все ветви (эффективно отключить эту политику без удаления из `enabledPolicies`), установите `protectedBranches: []`. +Чтобы разрешить push'и во все ветви (фактически отключить эту политику без удаления из `enabledPolicies`), установите `protectedBranches: []`. --- @@ -509,28 +509,28 @@ failproofai поставляется с 39 встроенными политик ### `block-work-on-main` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает `git commit`, `git merge`, `git rebase` и `git cherry-pick` при работе дерева на `main` или `master`. Создание и переключение ветвей (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) не затронуты. +**По умолчанию:** Блокирует `git commit`, `git merge`, `git rebase` и `git cherry-pick`, пока рабочее дерево находится на `main` или `master`. Создание ветвей и переключение (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) не затронуты. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Имена ветвей, на которых commit/merge/rebase/cherry-pick запрещены. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Имена ветвей, на которых commit/merge/rebase/cherry-pick заблокирован. | --- ### `block-force-push` **Событие:** PreToolUse (Bash) -**По умолчанию:** Запрещает `git push --force` и `git push -f`. +**По умолчанию:** Блокирует `git push --force` и `git push -f`. -Нет специфичных для политики параметров. Используйте кросс-секционную [`hint`](/ru/configuration#hint-cross-cutting) для предложения альтернатив: +Нет специфичных для политики параметров. Используйте общий [`hint`](/ru/configuration#hint-cross-cutting), чтобы предложить альтернативы: ```json { "policyParams": { "block-force-push": { - "hint": "Create a new branch from your current HEAD (e.g. `git checkout -b `) and push that instead." + "hint": "Создайте новую ветвь из вашего текущего HEAD (например `git checkout -b `) и push'ьте её вместо этого." } } } @@ -541,66 +541,66 @@ failproofai поставляется с 39 встроенными политик ### `warn-git-amend` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude действовать осторожно при выполнении `git commit --amend`. Не блокирует команду. +**По умолчанию:** Инструктирует Claude осторожно продолжать при запуске `git commit --amend`. Не блокирует команду. -Нет параметров. +Без параметров. --- ### `warn-git-stash-drop` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude подтвердить перед выполнением `git stash drop`. Не блокирует команду. +**По умолчанию:** Инструктирует Claude подтвердить перед запуском `git stash drop`. Не блокирует команду. -Нет параметров. +Без параметров. --- ### `warn-all-files-staged` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude проверить, что он осуществляет индексирование при выполнении `git add -A` или `git add .`. Не блокирует команду. +**По умолчанию:** Инструктирует Claude проверить, что он ставит на сцену при запуске `git add -A` или `git add .`. Не блокирует команду. -Нет параметров. +Без параметров. --- ## База данных -Перехватите деструктивные SQL-операции перед их выполнением против БД. +Перехватить деструктивные SQL операции перед их выполнением на вашей базе данных. ### `warn-destructive-sql` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude подтвердить перед выполнением SQL, содержащего `DROP TABLE`, `DROP DATABASE` или `DELETE` без `WHERE`-предложения. +**По умолчанию:** Инструктирует Claude подтвердить перед запуском SQL, содержащего `DROP TABLE`, `DROP DATABASE` или `DELETE` без `WHERE` клаузы. -Нет параметров. +Без параметров. --- ### `warn-schema-alteration` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude подтвердить перед выполнением `ALTER TABLE`-операций. +**По умолчанию:** Инструктирует Claude подтвердить перед запуском `ALTER TABLE` утверждений. -Нет параметров. +Без параметров. --- ## Предупреждения -Дайте агентам дополнительный контекст перед потенциально рискованными, но не деструктивными операциями. +Дать агентам дополнительный контекст перед потенциально рискованными, но неразрушающими операциями. ### `warn-large-file-write` **Событие:** PreToolUse (Write) -**По умолчанию:** Инструктирует Claude подтвердить перед записью файлов больше 1024 KB. +**По умолчанию:** Инструктирует Claude подтвердить перед записью файлов размером более 1024 KB. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | Порог размера файла в килобайтах, выше которого выдаётся предупреждение. | +| `thresholdKb` | `number` | `1024` | Пороговое значение размера файла в килобайтах, выше которого выдаётся предупреждение. | **Пример:** @@ -615,7 +615,7 @@ failproofai поставляется с 39 встроенными политик ``` -Обработчик хука применяет ограничение stdin в 1 MB на полезные нагрузки. Для тестирования этой политики с малым содержимым установите `thresholdKb` на значение хорошо ниже 1024. +Обработчик хука обеспечивает лимит stdin в 1 MB для полезной нагрузки. Чтобы протестировать эту политику с небольшим содержимым, установите `thresholdKb` на значение хорошо ниже 1024. --- @@ -623,47 +623,47 @@ failproofai поставляется с 39 встроенными политик ### `warn-package-publish` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude подтвердить перед выполнением `npm publish`. +**По умолчанию:** Инструктирует Claude подтвердить перед запуском `npm publish`. -Нет параметров. +Без параметров. --- ### `warn-background-process` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude быть осторожным при запуске фоновых процессов через `nohup`, `&`, `disown` или `screen`. +**По умолчанию:** Инструктирует Claude осторожно относиться при запуске фоновых процессов через `nohup`, `&`, `disown` или `screen`. -Нет параметров. +Без параметров. --- ### `warn-global-package-install` **Событие:** PreToolUse (Bash) -**По умолчанию:** Инструктирует Claude подтвердить перед выполнением `npm install -g`, `yarn global add` или `pip install` без виртуального окружения. +**По умолчанию:** Инструктирует Claude подтвердить перед запуском `npm install -g`, `yarn global add` или `pip install` без виртуального окружения. -Нет параметров. +Без параметров. --- ## Менеджеры пакетов -Обеспечьте соблюдение правил о том, какие менеджеры пакетов разрешены агенту. +Обеспечить, какие менеджеры пакетов допущены для использования агентом. ### `prefer-package-manager` **Событие:** PreToolUse (Bash) -**По умолчанию:** Отключена. При включении блокирует любую команду менеджера пакетов не в списке `allowed` и говорит Claude переписать команду, используя разрешённый менеджер. +**По умолчанию:** Отключена. При включении блокирует любую команду менеджера пакетов, не входящую в список `allowed`, и указывает Claude переписать команду, используя допущенный менеджер. Обнаруживает: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | Параметр | Тип | По умолчанию | Описание | |-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | Разрешённые имена менеджеров пакетов. Любой обнаруженный менеджер не в этом списке блокируется. Если пусто, политика неактивна. | -| `blocked` | string[] | `[]` | Дополнительные имена менеджеров для блокировки помимо встроенного списка (например, `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Допущенные имена менеджеров пакетов. Любой обнаруженный менеджер, не входящий в этот список, блокируется. При пустом списке политика не действует. | +| `blocked` | string[] | `[]` | Дополнительные имена менеджеров для блокировки сверх встроенного списка (например `['pdm', 'pipx']`). | -Встроенный список блокировки включает: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Используйте `blocked` для добавления менеджеров не в этом списке. +Встроенный список блокировок охватывает: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Используйте `blocked` для добавления менеджеров, не входящих в этот список. **Пример конфигурации:** @@ -679,74 +679,73 @@ failproofai поставляется с 39 встроенными политик } ``` -С этой конфигурацией как `pip install flask`, так и `pdm install flask` запрещены с сообщением, говорящим Claude использовать `uv` или `bun` вместо этого. Команды вроде `uv pip install flask` разрешены, потому что `uv` в разрешённом списке и проверяется первым. +С этой конфигурацией `pip install flask` и `pdm install flask` оба отклонены с сообщением, указывающим Claude использовать `uv` или `bun` вместо этого. Команды типа `uv pip install flask` разрешены, потому что `uv` находится в списке разрешённых и проверяется в первую очередь. --- ## Поведение AI -Обнаруживайте, когда агенты застревают или ведут себя неожиданно. +Обнаружить, когда агенты застревают или ведут себя неожиданно. ### `warn-repeated-tool-calls` **Событие:** PreToolUse (все инструменты) -**По умолчанию:** Инструктирует Claude пересмотреть, когда один и тот же инструмент вызывается 3+ раза с идентичными параметрами — распространённый признак того, что агент застрял в цикле. +**По умолчанию:** Инструктирует Claude переосмыслить, когда один и тот же инструмент вызывается 3+ раза с идентичными параметрами — распространённый признак того, что агент застрял в цикле. -Нет параметров. +Без параметров. --- ## Рабочий процесс -Обеспечьте дисциплинированный рабочий процесс конца сессии. Эти политики срабатывают на событии **Stop** и запрещают агенту остановиться, пока не будут выполнены условия. Они следуют естественной цепочке зависимостей: commit → push → PR → CI. Если политика запрещает, последующие политики в цепи пропускаются (deny вызывает короткое замыкание). +Обеспечить дисциплинированный рабочий процесс конца сеанса. Эти политики срабатывают на событии **Stop** и отклоняют возможность агента остановиться, пока не будут выполнены все условия. Они следуют естественной цепочке зависимостей: commit → push → PR → CI. Если политика отклоняет, более поздние политики в цепочке пропускаются (отклонение прерывает). -Все рабочие политики **fail-open**: если требуемый инструмент недоступен (например, `gh` не установлена, нет удалённого репозитория), политика разрешает с информационным сообщением, объясняющим, почему проверка была пропущена. +Все политики рабочего процесса **fail-open**: если требуемый инструмент недоступен (например `gh` не установлен, нет git remote), политика разрешает с информационным сообщением, объясняющим причину пропуска проверки. -### Семантика Stop для каждого CLI +### Семантика Stop по CLI -Применение Stop выглядит немного по-разному в семи поддерживаемых CLI, потому что каждый предоставляет отличающийся контракт хука «агент завершил работу». **Результат** одинаков — агент не может остановиться, пока шлюз рабочего процесса не пройден — но **механика** отличается. Таблица ниже суммирует; только Pi имеет заметную для пользователя особенность, стоящую понимания перед включением политики `require-*-before-stop`. +Принудительное применение Stop выглядит немного по-разному в шести поддерживаемых CLI, потому что каждый предоставляет другой контракт хука завершения агента. **Результат** один и тот же — агент не избежит остановки, пока гейт рабочего процесса не будет неудачным — но **механика** отличается. Таблица ниже содержит сводку; только Pi имеет видимую пользователю причуду, которую стоит понять перед включением политики `require-*-before-stop`. -| CLI | Когда срабатывает шлюз | Что вы видите | +| CLI | Когда срабатывает гейт | Что вы видите | |---|---|---| -| Claude Code | Тот же цикл агента, сразу | Claude продолжает работать — исправляет проблему, затем пытается завершить снова. Нет видимого прерывания для вас. | -| Codex | Тот же цикл агента, сразу | То же самое, что Claude. | -| GitHub Copilot CLI | Тот же цикл агента, сразу | То же самое, что Claude (использует канал повтора `{decision:"block", reason}` Copilot — проверено эмпирически на Copilot CLI 1.0.41). | -| Cursor Agent | Тот же цикл агента, сразу | То же самое, что Claude (использует канал `{followup_message}` Cursor — ограничен `loop_limit`, по умолчанию 5 повторов). | -| Gemini CLI | Тот же цикл агента, сразу | То же самое, что Claude (использует канал `{decision:"block", reason}` Gemini на `AfterAgent`). | -| OpenCode | Тот же цикл агента, сразу | То же самое, что Claude (использует вызов SDK `client.session.prompt(...)` OpenCode, маршрутизированный через `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **Следующий ход пользователя** | **Pi видимо останавливается**, когда срабатывает шлюз — его цикл агента завершается и вы возвращаетесь к приглашению. Шлюз затем срабатывает при следующей отправке приглашения: failproofai добавляет директиву `MANDATORY ACTION REQUIRED` в системное приглашение того хода, инструктируя LLM завершить шаг рабочего процесса (commit, push и т. д.) перед выполнением запрашиваемого вами действия. | +| Claude Code | Тот же цикл агента, сразу же | Claude продолжает работать — исправляет проблему, затем пытается завершить снова. Без видимых вам перерывов. | +| Codex | Тот же цикл агента, сразу же | Так же, как Claude. | +| GitHub Copilot CLI | Тот же цикл агента, сразу же | Так же, как Claude (использует `{decision:"block", reason}` канал повтора Copilot — проверено эмпирически на Copilot CLI 1.0.41). | +| Cursor Agent | Тот же цикл агента, сразу же | Так же, как Claude (использует `{followup_message}` канал Cursor — ограничен `loop_limit`, по умолчанию 5 повторов). | +| OpenCode | Тот же цикл агента, сразу же | Так же, как Claude (использует вызов `client.session.prompt(...)` SDK, маршрутизируемый через `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **Следующий ход пользователя** | **Pi видимо останавливается**, когда срабатывает гейт — его цикл агента завершается и вы возвращаетесь в приглашение. Гейт затем срабатывает при следующем отправке приглашения: failproofai добавляет директиву `MANDATORY ACTION REQUIRED` в системный промпт этого хода, инструктируя LLM завершить шаг рабочего процесса (commit, push и т. д.) перед выполнением того, что вы запросили. | -**Ограничение Pi.** `AgentEndEvent` Pi (эквивалент `Stop` хука Claude) не имеет типа Result — по времени его срабатывания цикл агента Pi уже завершился. Pi не может быть принуждена повторить тот же цикл, как Claude / Copilot / Cursor / Gemini / OpenCode. failproofai смещает шлюз к событию `before_agent_start` Pi (которое срабатывает после следующего приглашения пользователя), чтобы проверка рабочего процесса всё ещё применялась, просто при следующем ходе вместо текущего. +**Ограничение Pi.** `AgentEndEvent` Pi (эквивалент upstream для хука Stop Claude) не имеет типа Result — к тому времени, когда он срабатывает, цикл агента Pi уже завершился. Pi не может быть заставлен повторить попытку того же цикла так, как Claude / Copilot / Cursor / OpenCode. failproofai переносит гейт на событие `before_agent_start` Pi (которое срабатывает после следующего приглашения пользователя), чтобы проверка рабочего процесса всё ещё обеспечивалась, просто на следующий ход вместо текущего. **Что это означает на практике:** -- После остановки Pi причина deny захватывается в памяти с ключом по id сессии Pi. Самое следующее приглашение, которое вы отправляете в той же сессии Pi, его извлекает: LLM видит директиву `MANDATORY ACTION REQUIRED` в верхней части своего системного приглашения, commit-ит (или push-ит / открывает PR / ждёт CI) и только затем продолжает с вашим запросом. Захваченная причина deny — одноразовая — после извлечения шлюз свободен. -- Шлюз ограничен временем жизни процесса Pi. Если вы `Ctrl+C` Pi или выход между ходами, запись в памяти удаляется вместе с процессом и шлюз пропускается. Claude, Copilot, Cursor, Gemini и OpenCode имеют то же самое ограничение (kill агента и шлюз пропускается) — Pi просто делает это более видимым, потому что агент видимо завершает работу перед срабатыванием шлюза. -- Ожидающий deny также очищается на `session_shutdown` по любой причине (`new` / `resume` / `fork` / `quit`), поэтому устаревший шлюз из предыдущей сессии не может утечь в свежую сессию, начатую в том же процессе Pi. +- После остановки Pi причина отклонения фиксируется в памяти ключом по ID сеанса Pi. Очень следующее приглашение, которое вы отправляете в том же процессе Pi, сливает его: LLM видит директиву `MANDATORY ACTION REQUIRED` в верхней части своего системного промпта, коммитит (или push'ит / открывает PR / ждёт CI) и только затем продолжает с вашим запросом. Зафиксированная причина отклонения одноразовая — после слива гейт чист. +- Гейт ограничен временем жизни процесса Pi. Если вы выполните `Ctrl+C` Pi или выключитесь между ходами, в памяти запись сбрасывается вместе с процессом и гейт пропущен. Claude, Copilot, Cursor и OpenCode имеют ту же границу (убейте агента и гейт пропущен) — Pi просто делает это более видимым, потому что агент видимо выходит перед срабатыванием гейта. +- Находящееся на рассмотрении отклонение также очищается на `session_shutdown` по любой причине (`new` / `resume` / `fork` / `quit`), поэтому устаревший гейт из предыдущего сеанса не может просочиться в свежий сеанс, запущенный в том же процессе Pi. -Если вам нужен повтор в том же цикле, как Claude, запустите ваши политики `Stop` в любом из шести других поддерживаемых CLI. Мы отслеживаем Pi upstream на предмет будущего типа Result на `AgentEndEvent`, который позволил бы нам закрыть этот пробел. +Если вам нужен повтор того же цикла в стиле Claude, запустите ваши политики Stop в любом из пяти других поддерживаемых CLI. Мы отслеживаем Pi upstream для будущего типа Result на `AgentEndEvent`, который позволил бы нам закрыть этот разрыв. ### `require-commit-before-stop` **Событие:** Stop -**По умолчанию:** Запрещает остановку при наличии незафиксированных изменений (изменённые, индексированные или неотслеживаемые файлы). Возвращает информационное сообщение, когда рабочий каталог чист. +**По умолчанию:** Отклоняет остановку, когда есть незакоммиченные изменения (изменённые, поставленные на сцену или отслеживаемые файлы). Возвращает информационное сообщение, когда рабочий каталог чист. -Нет параметров. +Без параметров. --- ### `require-push-before-stop` **Событие:** Stop -**По умолчанию:** Запрещает остановку при наличии неотправленных коммитов или когда текущая ветвь не имеет удалённой отслеживаемой ветви. Предлагает `git push -u` для создания отслеживаемой ветви при необходимости. Fail open, если удалённый репозиторий не настроен. +**По умолчанию:** Отклоняет остановку, когда есть непотолканные коммиты или когда текущая ветвь не имеет удалённой отслеживаемой ветви. Предлагает `git push -u` для создания отслеживаемой ветви, если требуется. Неудачно открывается, если удалённая ветвь не сконфигурирована. **Параметры:** | Параметр | Тип | По умолчанию | Описание | |-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | Имя удалённого репозитория для отправки. | +| `remote` | `string` | `"origin"` | Имя удалённой ветви для push'а. | **Пример:** @@ -765,14 +764,14 @@ failproofai поставляется с 39 встроенными политик ### `require-pr-before-stop` **Событие:** Stop -**По умолчанию:** Запрещает остановку при отсутствии pull request для текущей ветви или при закрытом существующем PR без мерджа. Инструктирует Claude создать PR с `gh pr create`. Когда PR **смёрджена**, политика разрешает (работа доставлена) и сообщение намекает переключиться с ветви (`git checkout main && git pull`). +**По умолчанию:** Отклоняет остановку, когда нет pull request для текущей ветви, или когда существующий PR закрыт без слияния. Инструктирует Claude создать PR с `gh pr create`. Когда PR **объединён**, политика разрешает (работа отправлена) и сообщение намекает на переключение с ветви (`git checkout main && git pull`). -Нет параметров. +Без параметров. -Эта политика требует установку и аутентификацию [GitHub CLI](https://cli.github.com/) (`gh`). -Выполните `gh auth login` с персональным токеном доступа, имеющим область `repo` для доступа на чтение к -pull request-ам. Если `gh` не установлена или не аутентифицирована, политика fail-open и сообщает причину Claude. +Эта политика требует установки [GitHub CLI](https://cli.github.com/) (`gh`) и аутентификации. +Запустите `gh auth login` с личным токеном доступа с областью `repo` для доступа на чтение к +pull requests. Если `gh` не установлен или не аутентифицирован, политика открывается неудачно и сообщает причину Claude. --- @@ -780,12 +779,12 @@ pull request-ам. Если `gh` не установлена или не аут ### `require-no-conflicts-before-stop` **Событие:** Stop -**По умолчанию:** Запрещает остановку, когда текущая ветвь не может чисто мержиться в базовую ветвь. Политика сначала подтверждает наличие `OPEN` PR на GitHub для ветви — без него нет целевого мерджа для применения, поэтому вся политика short-circuit в разрешение. После подтверждения `OPEN` PR выполняются два независимых зонда: +**По умолчанию:** Отклоняет остановку, когда текущая ветвь не может чисто слиться в базовую ветвь. Политика сначала подтверждает, что на GitHub есть `OPEN` PR для ветви — без него нет целевого слияния для обеспечения, поэтому вся политика сокращает путь до разрешения. После подтверждения `OPEN` PR запускаются два независимых зонда: -1. **Локальный** — `git merge-tree --write-tree --name-only origin/ HEAD`. При конфликте сообщение deny указывает конфликтные файлы, чтобы Claude знал ровно, что разрешить. -2. **GitHub** — повторно использует результат `gh pr view --json mergeable,state`, уже загруженный при предварительной проверке. Перехватывает конфликты, которые устаревший локальный `origin/` пропустил бы (например, кто-то посадил конфликтующий PR на `main` с последней fetch). Результат `CONFLICTING` запрещает. Результат `UNKNOWN` также запрещает и инструктирует Claude дождаться ~10 секунд и переповторить проверку перед попыткой остановки снова — это предотвращает ложные отрицания, пока GitHub пересчитывает. +1. **Локальный** — `git merge-tree --write-tree --name-only origin/ HEAD`. При конфликте сообщение отклонения называет файлы в конфликте, поэтому Claude знает точно, что разрешить. +2. **GitHub** — повторно использует результат `gh pr view --json mergeable,state`, уже загруженный в предварительную проверку. Перехватывает конфликты, которые устаревший локальный `origin/` пропустит бы (например кто-то призвал конфликтующий PR в `main` с последней выборки). Результат `CONFLICTING` отклоняет. Результат `UNKNOWN` также отклоняет и инструктирует Claude ждать ~10 секунд и переосмотреть перед попыткой остановки снова — это предотвращает ложные негативы, пока GitHub пересчитывает. -Пропускает полностью (разрешает) при: `gh` не установлена, нет PR для ветви, состояние PR не `OPEN` (например, `MERGED`, `CLOSED`), или `gh pr view` возвращает непарсируемый вывод. Также fail-open, когда `origin/` отсутствует локально или когда нет коммитов впереди базовой — те Layer 1 pass-through всё ещё консультируются с кэшированной слияемостью PR перед разрешением. +Пропускает полностью (разрешает), когда: `gh` не установлен, нет PR для ветви, состояние PR не `OPEN` (например `MERGED`, `CLOSED`), или `gh pr view` возвращает нераспиленный вывод. Также открывается неудачно, когда `origin/` отсутствует локально или когда нет коммитов впереди базовой — те Layer 1 сквозные проходы всё ещё консультируют кэшированную слиемость PR перед разрешением. **Параметры:** @@ -795,9 +794,9 @@ pull request-ам. Если `gh` не установлена или не аут GitHub CLI (`gh`) требуется для этой политики. Политика использует `gh pr view` для подтверждения -наличия `OPEN` PR перед запуском любого зонда конфликта — без `gh` политика -short-circuit в разрешение. Выполните `gh auth login` с персональным токеном доступа, имеющим -область `repo` для доступа на чтение к pull request-ам. +существования `OPEN` PR перед запуском любого зонда конфликта — без `gh` политика +сокращает путь до разрешения. Запустите `gh auth login` с личным токеном доступа с областью +`repo` для доступа на чтение к pull requests. --- @@ -805,14 +804,14 @@ short-circuit в разрешение. Выполните `gh auth login` с п ### `require-ci-green-before-stop` **Событие:** Stop -**По умолчанию:** Запрещает остановку, когда проверки CI не пройдены или всё ещё выполняются на текущей ветви. Проверяет как GitHub Actions workflow runs, так и сторонние bot checks (например, CodeRabbit, SonarCloud, Codecov). Обрабатывает `skipped`, `cancelled` и `neutral` результаты как не неудачные (последняя категория охватывает, например, Socket Security alerts на PR внешних контрибьюторов, где приложение намеренно сообщает neutral вместо success/failure). Возвращает информационное сообщение, когда все проверки пройдены. +**По умолчанию:** Отклоняет остановку, когда проверки CI не прошли или всё ещё выполняются на текущей ветви. Проверяет оба запуска рабочего процесса GitHub Actions и проверки сторонних ботов (например CodeRabbit, SonarCloud, Codecov). Рассматривает `skipped`, `cancelled` и `neutral` выводы как не неудачные (последний охватывает например Socket Security alerts на PR'х сторонних участников, где приложение намеренно сообщает neutral вместо успеха/неудачи). Возвращает информационное сообщение, когда все проверки проходят. -Нет параметров. +Без параметров. -Эта политика требует установку и аутентификацию [GitHub CLI](https://cli.github.com/) (`gh`). -Выполните `gh auth login` с персональным токеном доступа, имеющим область `repo` для доступа на чтение к -Actions workflow runs и Checks API. Если `gh` не установлена или не аутентифицирована, политика fail-open и сообщает причину Claude. +Эта политика требует установки [GitHub CLI](https://cli.github.com/) (`gh`) и аутентификации. +Запустите `gh auth login` с личным токеном доступа с областью `repo` для доступа на чтение к +запускам рабочего процесса Actions и API Checks. Если `gh` не установлен или не аутентифицирован, политика открывается неудачно и сообщает причину Claude. --- @@ -821,7 +820,7 @@ Actions workflow runs и Checks API. Если `gh` не установлена ## Отключение отдельных политик -Удалите определённую политику из `enabledPolicies` в вашей конфигурации или переключите её в таб Policies на дашборде. +Удалите специфичную политику из `enabledPolicies` в вашей конфигурации или переключите её в вкладке Policies приборной панели. ```json { @@ -832,4 +831,4 @@ Actions workflow runs и Checks API. Если `gh` не установлена } ``` -Политики не перечисленные в `enabledPolicies` не запускаются, даже если существуют записи `policyParams` для них. \ No newline at end of file +Политики, не перечисленные в `enabledPolicies`, не выполняются, даже если существуют записи `policyParams` для них. \ No newline at end of file diff --git a/docs/ru/cli/audit.mdx b/docs/ru/cli/audit.mdx index d3693eec..e430c1c2 100644 --- a/docs/ru/cli/audit.mdx +++ b/docs/ru/cli/audit.mdx @@ -1,19 +1,20 @@ --- -title: Проверка прошлых сеансов (бета) -description: "Подсчитайте, как часто агент выполнял неэффективные или рискованные операции в прошлых транскриптах" +title: Проверка прошлых сессий (beta) +description: "Подсчитайте, как часто агент делал неэффективные или рискованные действия в прошлых транскриптах" --- - **Бета-функция.** Аудит выпущен в бета-версии для сбора первых отзывов. - Каталог детекторов и формат отчета могут измениться перед следующим стабильным - релизом. Пожалуйста, откройте проблему, если что-то выглядит неправильно. + **Бета-функция.** Проверка поставляется в режиме beta, пока мы собираем + ранние отзывы. Каталог детекторов и формат отчёта могут измениться до + следующего стабильного релиза. Пожалуйста, откройте issue, если что-то + выглядит неправильно. -Аудит воспроизводит ваши прошлые транскрипты агента-CLI через механизм политик failproofai и рендеринге удобный для обмена визуальный отчет на **странице панели `/audit`** — архетип агента, оценка от 0 до 100 и ровно какие политики что бы перехватили. +Проверка воспроизводит ваши прошлые транскрипты agent-CLI через механизм политик failproofai и генерирует удобный для обмена визуальный отчёт на странице **`/audit` dashboard** — архетип вашего агента, оценка от 0 до 100 и точный список того, какие политики что перехватили бы. -## Запустить +## Запуск -Три способа — все ведут к одному отчету `/audit`. +Три способа — все ведут к одному отчёту `/audit`. @@ -25,7 +26,7 @@ npx -y failproofai audit failproofai audit ``` -```bash failproofai (панель) +```bash failproofai (dashboard) failproofai ``` @@ -33,61 +34,61 @@ failproofai - `npx -y failproofai audit` загружает failproofai, запускает сканирование и открывает - панель для вас — ничего не нужно устанавливать заранее. + `npx -y failproofai audit` загружает failproofai, запускает сканирование и + открывает dashboard для вас — ничего не нужно устанавливать заранее. - `failproofai audit` запускает сканирование в терминале, затем автоматически открывает - `localhost:8020/audit` по завершении. + `failproofai audit` запускает сканирование в терминале, затем автоматически + открывает `localhost:8020/audit` по завершении. - - Запустите `failproofai` и нажмите **Audit** в навигационной панели (между Policies и - Projects), или откройте `/audit` напрямую. + + Запустите `failproofai` и нажмите **Audit** в навигационной панели (между + Policies и Projects), или откройте `/audit` напрямую. - Запустите `failproofai audit -h` (или `--help`) для просмотра справки. Аудит работает **полностью - оффлайн** — аккаунт или сеть не требуются — и панель продолжает работать - до тех пор, пока вы не остановите её с помощью `Ctrl+C`. + Запустите `failproofai audit -h` (или `--help`) для просмотра справки. Проверка + работает **полностью офлайн** — аккаунт и интернет не требуются — и dashboard + продолжает работать до тех пор, пока вы не остановите его с помощью `Ctrl+C`. -Панель сканирует прошлые транскрипты агента CLI на этой машине (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) и сообщает, как часто агент выполнял операции, которые failproofai создан, чтобы остановить — проверки переменных окружения, force push, повторяющиеся префиксы `cd `, sleep-polling циклы, повторное чтение только что отредактированных файлов и многое другое. +Dashboard сканирует прошлые транскрипты agent CLI на этой машине (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) и сообщает, как часто агент делал то, что failproofai создана блокировать — проверки переменных окружения, force push'и, избыточные префиксы `cd `, циклы с sleep-polling'ом, повторное чтение только что отредактированных файлов и многое другое. -Для каждого транскрипта каждое событие использования инструмента воспроизводится через 39 встроенных политик **и** через 8 аудит-специфичных детекторов, которые выявляют паттерны, еще не покрытые политиками реального времени. Подсчеты агрегируются для каждой политики/детектора по всем сеансам. +Для каждого транскрипта каждое событие tool-use воспроизводится через 39 встроенных политик **и** через 8 детекторов, предназначенных только для проверки, которые ловят паттерны, ещё не охватанные политиками времени выполнения. Подсчёты агрегируются по политикам / детекторам по всем сессиям. ## Что вы получите -Страница `/audit` — это односкринный, готовый для обмена **постер**, за которым следуют четыре скрытых раздела: +Страница `/audit` — это одноэкранный, удобный для обмена **постер**, за которым следуют четыре раздела ниже сгиба: -1. **Постер** — идентичность вашего агента с первого взгляда: его **архетип** (один из 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), ключевые слова персоны, насколько редок этот архетип, и **оценка от 0 до 100** с полосой уровня (`S` до `bottom tier`). Создан для обмена — опубликуйте на X или LinkedIn, или загрузите как PNG. -2. **`// strengths`** — что ваш агент уже делает хорошо, как реальные числа из сканирования (например, clean-tool-call %, `0` попыток push-to-main), показано только там, где соответствующая политика имеет чистую историю. -3. **`// quirks`** — что прошло: таблица с рейтингом поведения, которое failproofai бы перехватил — *когда* это последний раз произошло, *что прошло* (и встроенная политика, которая бы это заблокировала), его *серьезность* и как часто это было *видно* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — предписанный список исправлений: одна строка для каждой политики с copy-paste `failproofai policy add `, плюс кнопка **install all**, которая включает каждую рекомендацию сразу и показывает вашу **projected score**, если бы вы это сделали. -5. **`// come back better`** — выработайте привычку: установите напоминание **reminder** по электронной почте для повторного аудита (`3d` / `7d` / `14d` / `30d`) или повторите аудит сейчас, и **пригласите друга** запустить свой собственный аудит (отправлено с failproof.ai, копия вам). Напоминания и приглашения требуют входа — см. [`failproofai auth`](/ru/cli/auth). +1. **Постер** — идентичность вашего агента с первого взгляда: его **архетип** (один из 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), его ключевые слова, насколько редкий этот архетип, и **оценка от 0 до 100** с уровнем (`S` до `bottom tier`). Разработан для обмена — выложите в X или LinkedIn, или загрузите как PNG. +2. **`// strengths`** — что ваш агент уже делает хорошо, в виде реальных цифр из сканирования (например, clean-tool-call %, `0` попыток push-to-main), показывается только там, где соответствующая политика имеет чистый рекорд. +3. **`// quirks`** — что прошло мимо: ранжированная таблица поведений, которые failproofai перехватила бы — *когда* это произошло в последний раз, *что прошло* (и встроенная политика, которая это заблокировала бы), его *серьёзность* и как часто это было *замечено* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — список рекомендуемых исправлений: по одной строке на политику с готовой к копированию `failproofai policy add `, плюс кнопка **install all**, которая включает все рекомендации сразу и показывает вашу **projected score**, если вы это сделаете. +5. **`// come back better`** — выработайте привычку: установите **reminder** для повторной проверки по почте (`3d` / `7d` / `14d` / `30d`) или проверьте сейчас, и **пригласите друга** запустить свою собственную проверку (отправляется с failproof.ai, Cc на вас). Напоминания и приглашения требуют входа — см. [`failproofai auth`](/ru/cli/auth). -## Аудит-специфичные детекторы +## Детекторы, предназначенные только для проверки -Они выявляют паттерны "глупого поведения", не (еще) принудительно применяемые в реальном времени. Они запускаются только во время аудита и никогда не блокируют вызов инструмента в реальном времени. +Они обнаруживают паттерны поведения "глупых ошибок", которые (ещё) не принудительно применяются в реальном времени. Они запускаются только во время проверки и никогда не блокируют живой вызов tool. -| Детектор | Что он подсчитывает | +| Детектор | Что он считает | |---|---| -| `redundant-cd-cwd` | Bash команды, начинающиеся с `cd && …` хотя команды уже выполняются в `cwd`. | -| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` на одном исходном файле — используйте инструмент `Read`. | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` редактирование на месте — используйте инструмент `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / многострочный `echo > file` запись файлов — используйте инструмент `Write`. | -| `sleep-polling-loop` | Длинный `sleep N` (≥ 30s) или `while …; sleep …; done` polling циклы. | -| `find-from-root` | `find /`, `find /home`, `find /usr` и т.д. — ограничьте областью `cwd`. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, пропуск хуков. | -| `reread-after-edit` | `Read` файла, который был только что `Edit`/`Write` в том же сеансе. | +| `redundant-cd-cwd` | Bash-команды, начинающиеся с `cd && …`, несмотря на то что команды уже запускаются в `cwd`. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` для одного исходного файла — используйте инструмент `Read`. | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` встроенные правки — используйте инструмент `Edit`. | +| `prefer-write-over-heredoc` | Heredoc / многострочный `echo > file` для записи файлов — используйте инструмент `Write`. | +| `sleep-polling-loop` | Длинный `sleep N` (≥ 30s) или `while …; sleep …; done` циклы polling'а. | +| `find-from-root` | `find /`, `find /home`, `find /usr` и т.д. — ограничьте поиск `cwd`. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, пропуск hooks'ов. | +| `reread-after-edit` | `Read` файла, который был только что `Edit`/`Write` в той же сессии. | ## Кэши -- **Кэш на транскрипт** в `~/.failproofai/cache/audit/.json` с ключом по `(mtime, size, engineVersion, detectorVersion)` — автоматически инвалидируется при изменении транскрипта или кода политики/детектора. Каждая запись также хранит временную метку `cachedAt` как **TTL метаданные** (не часть ключа кэша); записи старше **7 дней** отклоняются при чтении, чтобы долгоживущие результаты не пережили эволюцию намерения детектора. -- **Кэш полного результата** в `~/.failproofai/audit-dashboard.json` (режим 0600). Позволяет панели рендериться мгновенно при навигации без повторного запуска. Также отклоняется при чтении после **7-дневного TTL** — `/audit` затем переходит в пустое состояние и предлагает запустить заново. Нажмите `[ re-audit now ]` в нижней части отчета для обновления — повторный аудит отправляет `noCache: true`, поэтому он обходит кэш на транскрипт и повторно сканирует каждый транскрипт вместо возврата кэшированного результата; запуск выводит прогресс через липкую верхнюю полосу и заменяет результат на месте при успехе (без перезагрузки страницы; неудачный повторный аудит сохраняет предыдущий отчет). +- **Кэш для каждого транскрипта** в `~/.failproofai/cache/audit/.json`, индексируемый по `(mtime, size, engineVersion, detectorVersion)` — автоматически инвалидируется при изменении транскрипта или кода политики/детектора. Каждая запись также хранит `cachedAt` timestamp как **TTL metadata** (не часть ключа кэша); записи старше **7 дней** отклоняются при чтении, чтобы долгоживущие результаты не пережили эволюцию намерения детектора. +- **Кэш полного результата** в `~/.failproofai/audit-dashboard.json` (режим 0600). Позволяет dashboard отображаться мгновенно при навигации без повторного запуска. Также отклоняется при чтении после **7-дневного TTL** — `/audit` затем переходит в пустое состояние и предлагает запустить свежую проверку. Нажмите `[ re-audit now ]` в нижней части отчёта для обновления — повторная проверка отправляет `noCache: true`, так что она обходит кэш для каждого транскрипта и повторно сканирует каждый транскрипт вместо возврата кэшированного результата; запуск отправляет прогресс через липкую верхнюю полоску и заменяет результат на месте при успехе (без перезагрузки страницы; неудачная повторная проверка сохраняет предыдущий отчёт). ## Примечания -- **Без изменений.** Аудит воспроизводится в режиме только чтения. `warn-repeated-tool-calls` пропускается, так как его сопровождающий файл на сеанс иначе был бы изменен. -- **Пропущены политики рабочего процесса.** Политики `require-*-before-stop` срабатывают только на события `Stop` и `execSync` в реальном состоянии git — они не имеют значимого толкования "что бы произошло в 2025", поэтому они не появляются в подсчетах аудита. -- **Пользовательские политики пропущены.** Предоставляемые пользователем пользовательские хуки не воспроизводятся (они могли измениться с исходного сеанса). \ No newline at end of file +- **Без изменений.** Проверка воспроизводится в режиме только для чтения. `warn-repeated-tool-calls` пропускается, так как иначе её побочный файл для каждой сессии будет изменён. +- **Политики workflow пропущены.** Политики `require-*-before-stop` срабатывают только на событиях `Stop` и `execSync` против живого состояния git — они не имеют значимой интерпретации "что бы произошло в 2025 году", поэтому они не появляются в подсчётах проверки. +- **Пользовательские политики пропущены.** Пользовательские hooks не воспроизводятся (они могли измениться с момента исходной сессии). \ No newline at end of file diff --git a/docs/ru/configuration.mdx b/docs/ru/configuration.mdx index 8a9c41e9..c738f4bd 100644 --- a/docs/ru/configuration.mdx +++ b/docs/ru/configuration.mdx @@ -1,28 +1,28 @@ --- title: Конфигурация -description: "Формат конфига, трёхуровневая система и правила слияния" +description: "Формат файла конфигурации, система трёх областей видимости и правила слияния" icon: gear --- -failproofai использует JSON-файлы конфигурации для управления активными политиками, их поведением и источниками загрузки пользовательских политик. Конфигурация разработана так, чтобы легко делиться ею с командой — просто закоммитьте в репо, и каждый разработчик получит одну и ту же защиту агента. +failproofai использует JSON-файлы конфигурации для управления тем, какие политики активны, как они ведут себя и откуда загружаются пользовательские политики. Конфигурация разработана так, чтобы было легко делиться ей с командой — зафиксируйте её в репозитории, и каждый разработчик получит одинаковую защиту агента. --- -## Области конфигурации +## Области видимости конфигурации -Существуют три области конфигурации, оцениваемые в порядке приоритета: +Есть три области видимости, оценяемые по приоритету: | Область | Путь файла | Назначение | |---------|-----------|-----------| -| **project** | `.failproofai/policies-config.json` | Параметры репо, закоммичены в систему контроля версий | -| **local** | `.failproofai/policies-config.local.json` | Личные переопределения для репо, добавлены в .gitignore | -| **global** | `~/.failproofai/policies-config.json` | Пользовательские значения по умолчанию для всех проектов | +| **проект** | `.failproofai/policies-config.json` | Параметры для репозитория, зафиксированы в системе контроля версий | +| **локальная** | `.failproofai/policies-config.local.json` | Личные переопределения для репозитория, в .gitignore | +| **глобальная** | `~/.failproofai/policies-config.json` | Параметры пользователя по умолчанию для всех проектов | -Когда failproofai получает событие хука, он загружает и объединяет все три файла, существующие для текущей директории. +Когда failproofai получает событие хука, он загружает и объединяет все три файла, которые существуют для текущей директории. ### Правила слияния -**`enabledPolicies`** — объединение всех трёх областей. Политика, активированная на любом уровне, работает. +**`enabledPolicies`** — объединение всех трёх областей. Политика, включённая на любом уровне, активна. ```text project: ["block-sudo"] @@ -32,13 +32,13 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← дедублицированное объединение ``` -**`policyParams`** — первая область, которая определяет параметры для конкретной политики, побеждает полностью. Глубокого слияния значений внутри параметров политики не происходит. +**`policyParams`** — первая область, которая определяет параметры для данной политики, выигрывает полностью. Нет глубокого слияния значений внутри параметров политики. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project побеждает, global игнорируется +resolved: { allowPatterns: ["sudo apt-get update"] } ← побеждает project, global игнорируется ``` ```text @@ -49,9 +49,9 @@ global: block-sudo → { allowPatterns: ["sudo systemctl status"] } resolved: { allowPatterns: ["sudo systemctl status"] } ← переходит к global ``` -**`customPoliciesPath`** — первая область, которая её определяет, побеждает. +**`customPoliciesPath`** — первая область, которая её определяет, выигрывает. -**`llm`** — первая область, которая её определяет, побеждает. +**`llm`** — первая область, которая её определяет, выигрывает. --- @@ -102,27 +102,27 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← переходит Тип: `string[]` -Список имён политик для активации. Имена должны точно совпадать с идентификаторами политик, показываемыми `failproofai policies`. Полный список см. в разделе [Built-in Policies](/ru/built-in-policies). +Список имён политик для включения. Имена должны точно совпадать с идентификаторами политик, показанными `failproofai policies`. См. [Встроенные политики](/ru/built-in-policies) для полного списка. -Политики, не входящие в `enabledPolicies`, неактивны, даже если у них есть записи в `policyParams`. +Политики, не в `enabledPolicies`, неактивны, даже если у них есть записи в `policyParams`. ### `policyParams` Тип: `Record>` -Переопределения параметров для каждой политики. Внешний ключ — имя политики; внутренние ключи — специфичны для политики. Каждая политика документирует свои доступные параметры в разделе [Built-in Policies](/ru/built-in-policies). +Переопределения параметров для каждой политики. Внешний ключ — имя политики; внутренние ключи — специфичны для политики. Каждая политика документирует свои доступные параметры в разделе [Встроенные политики](/ru/built-in-policies). -Если у политики есть параметры, но вы их не указали, используются встроенные значения по умолчанию политики. Пользователи, которые вообще не настраивают `policyParams`, получают поведение, идентичное предыдущим версиям. +Если политика имеет параметры, но вы их не указываете, используются встроенные значения политики по умолчанию. Пользователи, которые вообще не настраивают `policyParams`, получают поведение, идентичное предыдущим версиям. -Неизвестные ключи внутри блока параметров политики молча игнорируются при срабатывании хука, но помечаются как предупреждения при запуске `failproofai policies`. +Неизвестные ключи внутри блока параметров политики молча игнорируются во время срабатывания хука, но помечаются как предупреждения при запуске `failproofai policies`. -#### `hint` (кросс-функциональный) +#### `hint` (сквозной) Тип: `string` (опционально) -Сообщение, добавляемое к причине, когда политика возвращает `deny` или `instruct`. Используйте его, чтобы дать Claude практические рекомендации без изменения самой политики. +Сообщение, добавляемое к причине, когда политика возвращает `deny` или `instruct`. Используйте его, чтобы дать Claude действенные указания без изменения самой политики. -Работает с любым типом политики — встроенной, пользовательской (`custom/`), конвенции проекта (`.failproofai-project/`) или конвенции пользователя (`.failproofai-user/`). +Работает с любым типом политики — встроенной, пользовательской (`custom/`), проектной конвенции (`.failproofai-project/`), или пользовательской конвенции (`.failproofai-user/`). ```json { @@ -141,40 +141,40 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← переходит } ``` -Когда `block-force-push` отклоняет, Claude видит: *Force-pushing is blocked. Try creating a fresh branch instead.* +Когда `block-force-push` отклоняет, Claude видит: *«Force-pushing is blocked. Try creating a fresh branch instead.»* -Значения не-строкового типа и пустые строки молча игнорируются. Если `hint` не установлен, поведение не изменяется (обратная совместимость). +Значения, которые не являются строками, и пустые строки молча игнорируются. Если `hint` не установлен, поведение не изменяется (обратная совместимость). ### `customPoliciesPath` Тип: `string` (абсолютный путь) -Путь к JavaScript-файлу, содержащему пользовательские политики хуков. Это автоматически устанавливается `failproofai policies --install --custom ` (путь разрешается в абсолютный перед сохранением). +Путь к JavaScript-файлу, содержащему пользовательские политики хука. Устанавливается автоматически `failproofai policies --install --custom ` (путь разрешается в абсолютный перед сохранением). -Файл загружается заново при каждом событии хука — кеширования нет. Подробности авторства см. в разделе [Custom Policies](/ru/custom-policies). +Файл загружается заново при каждом событии хука — кэширования нет. См. [Пользовательские политики](/ru/custom-policies) для деталей разработки. ### Политики на основе конвенций Помимо явного `customPoliciesPath`, failproofai автоматически обнаруживает и загружает файлы политик из директорий `.failproofai/policies/`: -| Уровень | Директория | Область | -|---------|-----------|--------| -| Project | `.failproofai/policies/` | Общее для команды через систему контроля версий | -| User | `~/.failproofai/policies/` | Личное, применяется ко всем проектам | +| Уровень | Директория | Область видимости | +|---------|-----------|---------| +| Проект | `.failproofai/policies/` | Общие с командой через систему контроля версий | +| Пользователь | `~/.failproofai/policies/` | Личные, применяются ко всем проектам | -**Соответствие файлов:** Загружаются только файлы, соответствующие `*policies.{js,mjs,ts}` (например `security-policies.mjs`, `workflow-policies.js`). Другие файлы в директории игнорируются. +**Подбор файлов:** Загружаются только файлы, совпадающие с `*policies.{js,mjs,ts}` (например `security-policies.mjs`, `workflow-policies.js`). Другие файлы в директории игнорируются. -**Не требуется конфиг:** Политики конвенций не требуют записей в `policies-config.json`. Просто поместите файлы в директорию, и они будут загружены при следующем событии хука. +**Конфигурация не требуется:** Политики конвенций не требуют записей в `policies-config.json`. Просто поместите файлы в директорию и они будут подхвачены при следующем событии хука. -**Объединённая загрузка:** Сканируются обе директории конвенций (проекта и пользователя). Все соответствующие файлы из обоих уровней загружаются (в отличие от `customPoliciesPath`, который использует правило первой побеждающей области). +**Объединённая загрузка:** Сканируются обе директории конвенций: проектная и пользовательская. Все совпадающие файлы обоих уровней загружаются (в отличие от `customPoliciesPath`, который использует правило first-scope-wins). -Подробности и примеры см. в разделе [Custom Policies](/ru/custom-policies). +См. [Пользовательские политики](/ru/custom-policies) для дополнительных деталей и примеров. ### `llm` Тип: `object` (опционально) -Конфигурация LLM-клиента для политик, которые делают AI-вызовы. Не требуется для большинства установок. +Конфигурация LLM-клиента для политик, которые делают вызовы AI. Не требуется для большинства установок. ```json { @@ -189,20 +189,24 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← переходит ## Управление конфигурацией из CLI -Команды `policies --install` и `policies --uninstall` пишут в файл параметров хука вашего CLI агента (точки входа хуков), а `policies-config.json` — это файл, которым вы управляете напрямую. Это раздельные сущности: - -- **Параметры CLI агента** — указывает агенту вызывать `failproofai --hook ` при каждом использовании инструмента: - - **Claude Code**: `~/.claude/settings.json` (пользователь), `/.claude/settings.json` (проект), `/.claude/settings.local.json` (локально) - - **OpenAI Codex**: `~/.codex/hooks.json` (пользователь), `/.codex/hooks.json` (проект) — Codex не имеет локальной области - - **GitHub Copilot CLI _(бета)_**: `~/.copilot/hooks/failproofai.json` (пользователь), `/.github/hooks/failproofai.json` (проект) — Copilot не имеет локальной области. Записи хуков используют поля команд `bash`/`powershell` с ключом ОС и `timeoutSec` Copilot; файл содержит маркер `version: 1` верхнего уровня. Поддержка Copilot CLI находится в **бета-версии**, пока мы проверяем схему записи `events.jsonl` (которую общедоступные документы не указывают) против дополнительных реальных сессий. - - **Cursor Agent _(бета)_**: `~/.cursor/hooks.json` (пользователь), `/.cursor/hooks.json` (проект) — Cursor не имеет локальной области. Записи хуков используют форму с Claude-подобной формой `{type, command, timeout}` (без разделения `bash`/`powershell`), но хранятся под camelCase ключами событий (`preToolUse`, `beforeSubmitPrompt`, …) в плоском массиве согласно [схеме хуков](https://cursor.com/docs/hooks) Cursor; файл содержит маркер `version: 1` верхнего уровня. Обработчик канонизирует camelCase → PascalCase через `CURSOR_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Поддержка Cursor Agent находится в **бета-версии**, пока мы проверяем транскрипт Cursor на диске (не указан в общедоступных документах) против дополнительных реальных установок. - - **OpenCode _(бета)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (пользователь), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (проект) — OpenCode не имеет локальной области. В отличие от остальных шести CLI, OpenCode **не имеет системы внешних команд для хуков**: он загружает в процессе плагины JS/TS, явно зарегистрированные через массив `plugin: []` в `opencode.json` (автообнаружение из `.opencode/plugins/` **не** это как загружаются плагины в opencode v1.14.33). Install помещает маленький сгенерированный шим плагина, который subprocess-вызывает бинарный файл failproofai и переводит JSON-ответ бинарного файла Claude-подобной формы обратно в семантику плагина: `throw new Error()` для отрицания tool-события (отменяет вызов инструмента), `client.session.prompt(...)` для instruct И для отрицания `Stop` / `SubagentStop` (отправляет причину отрицания как следующее пользовательское сообщение — единственный канал force-retry, так как `session.idle` только для уведомления и выброс из неё — это no-op), и no-op для allow. Шим канонизирует названия инструментов (lowercase → PascalCase через `OPENCODE_TOOL_MAP`) и ключи аргументов инструментов (camelCase → snake_case через `OPENCODE_TOOL_INPUT_MAP` для `Read` / `Write` / `Edit`, например `filePath` → `file_path`, `oldString` → `old_string`) перед отправкой в бинарный файл, поэтому встроенные проверки путей вроде `block-read-outside-cwd`, `block-env-files` и `block-secrets-write` срабатывают без изменений для вызовов инструментов OpenCode. Сессии живут в БД SQLite OpenCode в `~/.local/share/opencode/opencode.db`; средство просмотра сессий на панели инструментов читает их через `opencode db --format json` и `opencode export `. Поддержка OpenCode находится в **бета-версии**, пока мы проверяем поведение в разных версиях и против дополнительных реальных сессий. См. [документацию плагинов OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(бета)_**: `~/.pi/agent/settings.json` (пользователь), `/.pi/settings.json` (проект) — Pi не имеет локальной области. Pi загружает пакеты расширений TypeScript при запуске; файл параметров — это плоский массив строк `{"packages": ["./relative/path", …]}`. failproofai записывает одну запись packages-массива, указывающую на встроенную директорию `pi-extension/`. Расширение внутренне подписывается на события Pi `tool_call` / `user_bash` / `input` / `session_start` и shell-вызывает `failproofai --hook --cli pi`; обработчик канонизирует underscore_lower_snake_case → PascalCase через `PI_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Аргументы инструментов также канонизируются через `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit доставляют `path` вместо `file_path`; картирование верхнего уровня позволяет `block-env-files` и `block-secrets-write` срабатывать — `block-read-outside-cwd` уже имел fallback для `path`). Поддержка Pi находится в **бета-версии**, пока API расширений Pi и макет журнала сессий стабилизируются. - - **Gemini CLI _(бета)_**: `~/.gemini/settings.json` (пользователь), `/.gemini/settings.json` (проект) — Gemini не имеет локальной области (она документирует область `system` в `/etc/gemini-cli/settings.json`, которую failproofai не предоставляет). Записи хуков используют форму Claude's `{type, command, timeout}`, обёрнутую в схему matcher Gemini's `{matcher, hooks: [...]}` с `matcher: "*"` по умолчанию. События — PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); обработчик картирует на имена Claude canonical через `GEMINI_EVENT_MAP`. Названия инструментов — snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — обработчик канонизирует через `GEMINI_TOOL_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Оценщик политик выдаёт плоскую форму Gemini's `{decision: "deny", reason}` (предпочтено по Gemini's Golden Rule контракту exit-0), `{hookSpecificOutput: {hookEventName, additionalContext}}` для внедрения контекста в BeforeAgent / AfterTool / SessionStart, и `{decision: "block", reason}` на AfterAgent для семантики force-retry. Поддержка Gemini CLI находится в **бета-версии**, пока мы расширяем реальное покрытие. См. [документацию хуков Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**только область пользователя** — Hermes не имеет конфига проекта/локально). Hermes — это **шлюз** Slack/Telegram, поэтому одна установка перехватывает вызовы инструментов от каждой платформы (Slack/Telegram/cli/cron) **и** внутренние подагенты. Записи хуков — это пара `{command, timeout}` (timeout в **секундах**) под картой `hooks:` с ключами от snake_case событий Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); обработчик канонизирует события через `HERMES_EVENT_MAP` и названия инструментов через `HERMES_TOOL_MAP`, поэтому встроенные политики срабатывают без изменений. Конфиг редактируется через коммент-сохраняющий YAML round-trip `Document`, поэтому остальные параметры оператора выживают, и install устанавливает `hooks_auto_accept: true`, чтобы headless шлюз (без TTY) запускал хуки без промпта согласия. Оценщик выдаёт контракт `{"decision":"block","reason"}` stdout Hermes (Hermes игнорирует коды выхода). **Ограничения:** Hermes не имеет event end-turn `Stop`, поэтому встроенные `require-*-before-stop` никогда не срабатывают для него (неприменимо, не сломано); `instruct` деградирует до allow-with-logged-note (нет канала дополнительного контекста); и переписывание выходных секретов (`sanitize-*`) не может переписать вывод инструмента через shell-hook контракт. Hermes — **также** оффлайн **audit** источник — панель инструментов читает сессии шлюза напрямую из `~/.hermes/state.db`. -- **`policies-config.json`** — указывает failproofai, какие политики оценивать и с какими параметрами (общее для всех CLI агентов) - -Передайте `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` для выбора конкретного агента (разделённые пробелом или повторённые для подмножества): +Команды `policies --install` и `policies --uninstall` записывают в файл параметров хука вашего агента CLI (точки входа хука), а `policies-config.json` — это файл, который вы управляете напрямую. Они отделены: + +- **Параметры агента CLI** — указывает агенту вызывать `failproofai --hook ` при каждом использовании инструмента: + - **Claude Code**: `~/.claude/settings.json` (пользователь), `/.claude/settings.json` (проект), `/.claude/settings.local.json` (локальная) + - **OpenAI Codex**: `~/.codex/hooks.json` (пользователь), `/.codex/hooks.json` (проект) — Codex не имеет локальной области видимости + - **GitHub Copilot CLI _(бета)_**: `~/.copilot/hooks/failproofai.json` (пользователь), `/.github/hooks/failproofai.json` (проект) — Copilot не имеет локальной области видимости. Записи хуков используют Copilot поля команд `bash`/`powershell` с `timeoutSec` (ключи по ОС); файл содержит маркер `version: 1` на верхнем уровне. Поддержка Copilot CLI находится в **бета**, так как мы проверяем схему записей `events.jsonl` (которую публичные документы не указывают) на реальных сеансах. **VS Code Copilot Chat agent mode (Preview)** читает конфигурации хуков из `.github/hooks/*.json`, `~/.copilot/hooks/*.json` и `~/.claude/settings.json` (управляется параметром `chat.hookFilesLocations`) используя Claude-подобный контракт `{hookSpecificOutput:{permissionDecision:"deny",…}}` — это точные пути, которые интеграция `copilot` и интеграция `claude` (`~/.claude/settings.json`) уже записывают, поэтому `failproofai policies --install --cli copilot` (или `--cli claude`) **уже обеспечивают в режиме VS Code agent** без отдельной интеграции `vscode` (подтверждено из журналов обнаружения VS Code). + - **Cursor Agent _(бета)_**: `~/.cursor/hooks.json` (пользователь), `/.cursor/hooks.json` (проект) — Cursor не имеет локальной области видимости. Записи хуков используют Claude-подобную форму `{type, command, timeout}` (без разделения `bash`/`powershell`), но хранятся под camelCase ключами событий (`preToolUse`, `beforeSubmitPrompt`, …) в плоском массиве согласно [схеме хуков](https://cursor.com/docs/hooks) Cursor; файл содержит маркер `version: 1` на верхнем уровне. Обработчик канонизирует camelCase → PascalCase через `CURSOR_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Поддержка Cursor Agent находится в **бета**, так как мы проверяем формат расшифровок Cursor на диске (не указан в публичных документах) на большем числе реальных установок. + - **OpenCode _(бета)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (пользователь), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (проект) — OpenCode не имеет локальной области видимости. В отличие от остальных пяти CLI, OpenCode **не имеет внешней системы хуков команд**: он загружает встроенные JS/TS плагины, явно зарегистрированные через массив `plugin: []` в `opencode.json` (автообнаружение из `.opencode/plugins/` — **это не** то, как плагины загружаются в opencode v1.14.33). Установка добавляет небольшой сгенерированный shim плагина, который запускает бинарный файл failproofai как подпроцесс и переводит JSON-ответ бинарного файла Claude-подобной формы обратно в семантику плагина: `throw new Error()` для отклонения события инструмента (отменяет вызов инструмента), `client.session.prompt(...)` для instruct И для `Stop` / `SubagentStop` отклонения (отправляет причину отклонения как следующее сообщение пользователя — единственный канал retry, так как `session.idle` — это только уведомление и выброс из неё — это no-op), и no-op для allow. Shim канонизирует как имена инструментов (lowercase → PascalCase через `OPENCODE_TOOL_MAP`), так и ключи аргументов tool-input (camelCase → snake_case через `OPENCODE_TOOL_INPUT_MAP` для `Read` / `Write` / `Edit`, например `filePath` → `file_path`, `oldString` → `old_string`) перед отправкой в бинарный файл, поэтому встроенные проверки пути как `block-read-outside-cwd`, `block-env-files` и `block-secrets-write` срабатывают без изменений на вызовах инструментов OpenCode. Сеансы живут в SQLite БД opencode в `~/.local/share/opencode/opencode.db`; средство просмотра сеансов панели инструментов читает их через `opencode db --format json` и `opencode export `. Поддержка OpenCode находится в **бета**, так как мы проверяем поведение на разных версиях и большем числе реальных сеансов. См. [документацию плагинов OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(бета)_**: `~/.pi/agent/settings.json` (пользователь), `/.pi/settings.json` (проект) — Pi не имеет локальной области видимости. Pi загружает пакеты TypeScript-расширений при запуске; файл параметров — это плоский массив строк `{"packages": ["./relative/path", …]}`. failproofai записывает одну запись массива пакетов, указывающую на его собственную директорию `pi-extension/`. Расширение внутренне подписывается на события Pi `tool_call` / `user_bash` / `input` / `session_start` и вызывает `failproofai --hook --cli pi`; обработчик канонизирует underscore_lower_snake_case → PascalCase через `PI_EVENT_MAP`, поэтому существующие встроенные политики срабатывают без изменений. Аргументы tool input также канонизируются через `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit доставляют `path` вместо `file_path`; преобразование верхнего ключа позволяет срабатывать `block-env-files` и `block-secrets-write` — `block-read-outside-cwd` уже имел fallback для `path`). Поддержка Pi находится в **бета**, так как Pi's extension API и макет session-log стабилизируются. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**только область видимости пользователя** — Hermes не имеет конфигурации проекта/локальной). Hermes — это **шлюз** Slack/Telegram, поэтому одна установка перехватывает вызовы инструментов со всех платформ (Slack/Telegram/cli/cron) **и** внутренних подагентов. Записи хуков — это пара `{command, timeout}` (timeout в **секундах**) под картой `hooks:`, ключами которой являются события snake_case Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); обработчик канонизирует события через `HERMES_EVENT_MAP` и имена инструментов через `HERMES_TOOL_MAP`, поэтому встроенные политики срабатывают без изменений. Конфигурация редактируется через round-trip YAML `Document`, сохраняющий комментарии, поэтому другие параметры оператора сохраняются, и установка устанавливает `hooks_auto_accept: true`, так что безголовый шлюз (без TTY) запускает хуки без подсказки согласия. Оценивающий выводит контракт stdout Hermes `{"decision":"block","reason"}` (Hermes игнорирует коды выхода). **Ограничения:** Hermes не имеет события конца turn `Stop`, поэтому встроенные `require-*-before-stop` никогда не срабатывают для неё (неприменимо, не сломано); `instruct` деградирует до allow-with-logged-note (без канала дополнительного контекста); и редактирование output-secret (`sanitize-*`) не может переписать output инструмента через shell-hook контракт. Hermes — это **также** offline **audit** источник — панель инструментов читает её session шлюза непосредственно из `~/.hermes/state.db`. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**только область видимости пользователя** — OpenClaw не имеет конфигурации проекта/локальной). Как и Hermes, OpenClaw — это самостоятельно размещённый мультиканальный **шлюз**, поэтому одна установка перехватывает вызовы инструментов со всех каналов и его внутренних подагентов. Обеспечение работает через **встроенные в процесс plugin hooks** OpenClaw (его file-based internal hooks — это только observation и не могут блокировать), поэтому — как OpenCode/Pi — failproofai поставляется с статическим пакетом `openclaw-plugin/`, который асинхронно запускает бинарный файл failproofai и переводит вердикт. Установка регистрирует dir с поставляемым плагином в `openclaw.json`'s `plugins.load.paths[]` и включает его под `plugins.entries.failproofai` (с `hooks.allowConversationAccess: true`, требуется для raw-conversation hooks). Оценивающий выводит плоский вердикт `{permission, reason}` и shim преобразует его в родную форму возврата каждого хука: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), и `before_agent_finalize → {action:"revise", reason}` (**Stop** — реальные turn-end gate, поэтому встроенные `require-*-before-stop` **обеспечивают** на OpenClaw, в отличие от Hermes). События и имена инструментов канонизируют binary-side через `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …), поэтому встроенные политики срабатывают без изменений; shim открывается при любой ошибке spawn/parse/timeout. OpenClaw — это **также** offline **audit** источник — панель инструментов читает её JSONL-сеансы в `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (пользователь), `/.factory/hooks.json` (проект) — Factory не имеет локальной области видимости. droid поставляется с Claude-подобной системой external-command hooks, но с двумя особенностями, проверенными live на droid v0.171.0: (1) имена событий живут на **верхнем уровне** `hooks.json` — там **нет обёртки `"hooks"`** (droid её отклоняет); события инструментов (`PreToolUse`/`PostToolUse`) несут `"matcher": "*"`, события, не относящиеся к инструментам, его опускают. (2) Отклонение управляется **кодом выхода хука 2 + stderr**, не JSON-решением — ветка оценивающего `factory` возвращает выход 2 для событий инструмента/подсказки и `{decision:"block", reason}` только при turn-end событии `Stop` (единственный канал force-retry droid). События уже PascalCase (нет карты событий), и payload — Claude snake_case; только имена инструментов канонизируют через `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory — это **также** offline **audit** источник — панель инструментов читает её on-disk JSONL-сеансы в `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (пользователь), `/.devin/config.json` (проект) — Devin не имеет локальной области видимости. Devin — это **pure Claude-clone**, проверенный live на devin v3000.1.27: он использует стандартную Claude схему с обёрткой `"hooks"` (записи — это merge-preserving, поэтому другие ключи файла конфигурации — `org_id`, `theme_mode`, … — сохраняются), имена событий уже PascalCase (нет карты событий, нет ветки обработчика) и Claude snake_case stdin payload (нет нормализации). Ветка оценивающего `devin` отклоняет с `{"decision":"block","reason"}` JSON на stdout при выходе 0 для **каждого** события (проверено — блокирование переопределило `--permission-mode dangerous`); при turn-end событии `Stop` причина несёт обязательный текст force-retry, поэтому встроенные `require-*-before-stop` обеспечивают. Только имена инструментов канонизируют через `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` уже канонический). Devin — это **также** offline **audit** источник — панель инструментов читает его SQLite-сеансы в `~/.local/share/devin/cli/sessions.db` (каждая строка `sessions` несёт реальный `working_directory`, поэтому сеансы группируют по project cwd как Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (пользователь), `/.agents/hooks.json` (проект) — Antigravity не имеет локальной области видимости. В отличие от Factory/Devin, Antigravity имеет свой **собственный** контракт (не Claude-clone), проверенный live на agy v1.1.2. `hooks.json` использует **named-hook** схему: верхний ключ — это имя хука (*"failproofai"*), значение которого — карта событий → обработчиков — события инструментов (`PreToolUse`/`PostToolUse`) оборачивают обработчики в `{matcher:"*", hooks:[…]}`, в то время как `PreInvocation`/`Stop` — это **плоские** массивы обработчиков (другие named hooks сохраняются). Stdin payload — это **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai нормализует его в snake_case перед тем, как запустятся политики, и преобразует PascalCase аргументы `run_command` (`CommandLine`/`Cwd`) через `ANTIGRAVITY_TOOL_INPUT_MAP`. Ветка оценивающего `antigravity` использует **собственные** формы ответа Antigravity: `{decision:"deny", reason}` блокирует инструмент/подсказку (выход 0), `{decision:"continue", reason}` при turn-end событии `Stop` повторно входит в цикл (поэтому встроенные `require-*-before-stop` обеспечивают) и `{injectSteps:[{ephemeralMessage}]}` внедряет инструкцию на `PreInvocation` (→ `UserPromptSubmit`). Имена инструментов канонизируют через `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity — это **также** offline **audit** источник — панель инструментов читает её plain-JSONL-расшифровки в `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (индекс conversation в `conversation_summaries.db`). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (пользователь), `/.agents/plugins/failproofai/hooks/hooks.json` (проект) — Goose не имеет локальной области видимости. Обеспечение использует систему **hooks** Goose, кросс-агентную спецификацию **Open Plugins**: установщик просто добавляет dir плагина `failproofai`, и Goose автоматически обнаруживает его при запуске (самостоятельно регистрируя его в `~/.config/goose/config.yaml`). `hooks.json` использует схему Open Plugins **с** верхним уровнем обёртки `"hooks"`, и matcher — это **опущен** на каждом событии — bare `"*"` — это невалидный regex, который ничему не соответствует (проверено live на goose v1.43.0). Имена событий уже PascalCase (нет карты событий); stdin payload использует `event`/`working_dir`, которые обработчик нормализует в `hook_event_name`/`cwd`. Ветка оценивающего `goose` отклоняет с `{"decision":"block","reason"}` JSON на stdout при выходе 0, соблюдается на событии **`PreToolUse`** только (поставляется в goose ≥ v1.37.0) — которое срабатывает для shell tool **и внутри делегированных подагентов**, поэтому это единственная достаточная точка отклонения; любая другая ошибка хука открывается **открыто**. Goose **не имеет события `Stop`**, поэтому встроенные `require-*-before-stop` не применяются (как с Hermes). Имена инструментов канонизируют через `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) и ключи пути через `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose — это **также** offline **audit** источник — панель инструментов читает её SQLite-сеансы в `~/.local/share/goose/sessions/sessions.db` (каждая строка `sessions` несёт реальный `working_dir`, поэтому сеансы группируют по project cwd как Devin; `--no-session` scratch runs фильтруются). +- **`policies-config.json`** — указывает failproofai, какие политики оценивать и с какими параметрами (общие для всех agent CLI) + +Передайте `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` для целевого агента (разделённые пробелами или повторённые для любого подмножества): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Когда `--cli` опущен, `failproofai` обнаруживает, какие CLI агентов установлены (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Когда `--cli` опущен, `failproofai` определяет, какие agent CLI установлены (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Один CLI обнаружен** — автоматически выбирает тот CLI без запроса. -- **Несколько CLI обнаружено** в интерактивном терминале — показывает однострочный prompt выбора со стрелками, сгруппированный в раздел `Detected (N)` (с агрегированной строкой `Install for all N detected` + каждый обнаруженный CLI отдельно) и раздел `Not installed (M) · install hooks ahead of time`, перечисляющий каждый неподдерживаемый CLI как опцию forward-install (↑↓ для перемещения, Enter для выбора, ^C для выхода). Flow разустановки показывает только раздел Detected. -- **Несколько CLI обнаружено** в неинтерактивном запуске (CI, без TTY) — устанавливает для всех обнаруженных CLI без запроса. -- **Ничего не обнаружено** — возвращается к `claude` с предупреждением, что бинарный файл агента не найден в PATH; команда хука всё ещё записывается, поэтому она активируется, как только вы установите один. +- **Обнаружен один CLI** — автоматически выбирает этот CLI без подсказок. +- **Обнаружены несколько CLI** в интерактивном терминале — показывает prompt single-select с arrow-key, сгруппированный в секцию `Detected (N)` (с строкой агрегации `Install for all N detected` + каждый обнаруженный CLI отдельно) и секцию `Not installed (M) · install hooks ahead of time`, перечисляющую все необнаруженные поддерживаемые CLI как опцию forward-install (↑↓ для перемещения, Enter для выбора, ^C для выхода). Поток uninstall показывает только секцию Detected. +- **Несколько CLI обнаружены** в non-interactive run (CI, no TTY) — устанавливает для всех обнаруженных CLI без подсказок. +- **Ничего не обнаружено** — fallback на `claude`, с предупреждением о том, что бинарный файл агента не найден в PATH; команда хука всё ещё записана, так что она активируется, как только вы установите один. -Вы можете редактировать `policies-config.json` напрямую в любой момент; изменения вступают в силу немедленно при следующем событии хука без необходимости перезагрузки. +Вы можете редактировать `policies-config.json` напрямую в любой момент; изменения вступают в силу немедленно при следующем событии хука, без перезагрузки. --- -## Пример: конфиг уровня проекта с командными значениями по умолчанию +## Пример: конфигурация на уровне проекта с командными по умолчанию -Закоммитьте `.failproofai/policies-config.json` в ваш репо: +Зафиксируйте `.failproofai/policies-config.json` в своём репозитории: ```json { @@ -247,4 +255,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -Каждый разработчик может затем создать `.failproofai/policies-config.local.json` (добавлен в .gitignore) для личных переопределений без влияния на товарищей по команде. \ No newline at end of file +Каждый разработчик может затем создать `.failproofai/policies-config.local.json` (в .gitignore) для личных переопределений без влияния на коллег. \ No newline at end of file diff --git a/docs/ru/dashboard.mdx b/docs/ru/dashboard.mdx index 416ba866..27320e33 100644 --- a/docs/ru/dashboard.mdx +++ b/docs/ru/dashboard.mdx @@ -1,10 +1,10 @@ --- title: Dashboard -description: "Мониторьте сеансы агентов, проверяйте вызовы инструментов и управляйте политиками" +description: "Мониторьте сессии агентов, просматривайте вызовы инструментов и управляйте политиками" icon: chart-line --- -Панель управления failproofai — это локальное веб-приложение для мониторинга сеансов вашего AI-агента и управления политиками. Узнайте, что делал ваш агент, пока вас не было. +Панель управления failproofai — это локальное веб-приложение для мониторинга сессий ваших AI-агентов и управления политиками. Посмотрите, что делали ваши агенты в ваше отсутствие. --- @@ -14,9 +14,9 @@ icon: chart-line failproofai ``` -Открывается на `http://localhost:8020`. +Открывается по адресу `http://localhost:8020`. -Панель управления читает данные непосредственно из файловой системы — ваши папки проектов Claude Code и файлы конфигурации failproofai. Ничего не записывается в удалённый сервис. +Панель управления читает данные напрямую из файловой системы — папки проектов Claude Code и файлы конфигурации failproofai. Ничего не отправляется на удаленный сервис. --- @@ -24,67 +24,67 @@ failproofai ### Projects -Список всех найденных на вашем компьютере проектов Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ и Hermes. Проекты Claude обнаруживаются из `~/.claude/projects/` (или пути, установленного в `CLAUDE_PROJECTS_PATH`); проекты Codex обнаруживаются путём сканирования каждой транскрипции под `~/.codex/sessions///
/*.jsonl` и группировки по `cwd`, записанному в первой записи каждого сеанса; проекты Copilot CLI обнаруживаются путём сканирования каждого `~/.copilot/session-state//workspace.yaml` (настраивается через `COPILOT_HOME`) и группировки по полю `cwd`; проекты Cursor Agent обнаруживаются путём сканирования метаданных для каждого сеанса под `~/.cursor/agent-sessions//` (настраивается через `CURSOR_HOME`, со счётом `conversations/` и `sessions/` в качестве резервных вариантов) для скаляра `cwd` в `meta.json` / `session.json` / `workspace.yaml`; проекты OpenCode обнаруживаются путём запроса к его БД SQLite на `~/.local/share/opencode/opencode.db` через `opencode db --format json` (мы читаем таблицы `session` и `project` и группируем по `project_id`); проекты Pi обнаруживаются путём сканирования транскрипций JSONL для каждого сеанса под `~/.pi/agent/sessions//_.jsonl` (настраивается через `PI_SESSIONS_DIR`) и извлечения `cwd` из первой записи каждого сеанса; проекты Gemini CLI обнаруживаются путём сканирования `~/.gemini/tmp//chats/session--.jsonl` (настраивается через `GEMINI_SESSIONS_DIR`) и восстановления канонического cwd из текстового маркера `.project_root`; сеансы шлюза Hermes читаются непосредственно из его хранилища SQLite на `~/.hermes/state.db` (настраивается через `HERMES_DB_PATH`) и группируются в проекты `hermes-` по `source` (Slack/Telegram/cli/cron — сеансы шлюза не имеют cwd). Проект, который использовался несколькими CLI, отображается как одна строка со всеми соответствующими значками. Используйте выпадающее меню **CLI** над таблицей для фильтрации по конкретному агенту; URL сохраняет ваш выбор как `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Список всех проектов Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity и Goose, найденных на вашей машине. Проекты Claude обнаруживаются из `~/.claude/projects/` (или из пути, установленного `CLAUDE_PROJECTS_PATH`); проекты Codex обнаруживаются путем сканирования каждой стенограммы в `~/.codex/sessions///
/*.jsonl` и группировки по `cwd`, записанному в первой записи сессии; проекты Copilot CLI обнаруживаются путем сканирования каждого `~/.copilot/session-state//workspace.yaml` (настраивается через `COPILOT_HOME`) и группировки по его полю `cwd`; проекты Cursor Agent обнаруживаются путем сканирования метаданных для каждой сессии в `~/.cursor/agent-sessions//` (настраивается через `CURSOR_HOME`, с `conversations/` и `sessions/` как резервные варианты) для скалярного значения `cwd` в `meta.json` / `session.json` / `workspace.yaml`; проекты OpenCode обнаруживаются путем запроса его SQLite БД в `~/.local/share/opencode/opencode.db` через `opencode db --format json` (мы читаем таблицы `session` и `project` и группируем по `project_id`); проекты Pi обнаруживаются путем сканирования стенограмм JSONL для каждой сессии в `~/.pi/agent/sessions//_.jsonl` (настраивается через `PI_SESSIONS_DIR`) и извлечения `cwd` из первой записи каждой сессии; сессии шлюза Hermes читаются напрямую из его хранилища SQLite в `~/.hermes/state.db` (настраивается через `HERMES_DB_PATH`) и группируются в проекты `hermes-` по `source` (Slack/Telegram/cli/cron — сессии шлюза не имеют cwd); сессии шлюза OpenClaw читаются из `~/.openclaw/agents//sessions/*.jsonl` и группируются в проекты `openclaw-` (также без cwd); проекты Factory Droid обнаруживаются из стенограмм JSONL в `~/.factory/sessions//*.jsonl` и группируются по cwd; проекты Devin из его SQLite БД в `~/.local/share/devin/cli/sessions.db` (сгруппированы по `working_directory` каждой сессии); проекты Antigravity из стенограмм JSONL в `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` и сгруппированы по cwd; и проекты Goose из его SQLite БД в `~/.local/share/goose/sessions/sessions.db` (сгруппированы по `working_dir` каждой сессии). Проект, используемый несколькими CLI, отображается в виде одной строки со всеми соответствующими значками. Используйте раскрывающееся меню **CLI** над таблицей для фильтрации по конкретному CLI агента; URL сохраняет ваш выбор как `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. -Каждый проект показывает: -- Имя проекта (производное от пути папки) -- Значок CLI — `Claude Code` (оранжевый), `OpenAI Codex` (фиолетовый), `GitHub Copilot` (синий), `Cursor Agent` (изумруд), `OpenCode` (янтарь), `Pi` (розовый), `Gemini CLI` (небесно-голубой) и/или `Hermes` (индиго) -- Дата последней активности сеанса +Каждый проект отображает: +- Имя проекта (выведено из пути папки) +- Значок CLI — `Claude Code` (оранжевый), `OpenAI Codex` (фиолетовый), `GitHub Copilot` (синий), `Cursor Agent` (изумрудный), `OpenCode` (янтарный), `Pi` (розовый) и/или `Hermes` (индиго) +- Дата самой последней активности сессии -Щёлкните по проекту, чтобы просмотреть его сеансы. +Нажмите на проект, чтобы увидеть его сессии. ### Sessions -Список всех сеансов в проекте. Каждый сеанс показывает: -- ID сеанса +Список всех сессий в проекте. Каждая сессия отображает: +- ID сессии - Временные метки начала и конца - Количество вызовов инструментов -- Счётчик активности хуков (срабатывания политик) +- Количество активности хуков (политики, которые сработали) -Используйте фильтр диапазона дат и поиск по ID сеанса для уточнения списка. Сеансы постранично. +Используйте фильтр диапазона дат и поиск по ID сессии для сужения списка. Сессии разбиты на страницы. -Щёлкните по сеансу, чтобы открыть средство просмотра сеанса. +Нажмите на сессию, чтобы открыть просмотр сессии. ### Session viewer -Средство просмотра сеанса отвечает на ключевой вопрос для автономных агентов: что сделал агент и остался ли он на курсе? Значок CLI рядом с заголовком указывает, является ли сеанс транскрипцией Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI или Hermes. Он показывает временную шкалу всего, что произошло в сеансе: +Средство просмотра сессии отвечает на ключевой вопрос для автономных агентов: что делал агент и оставался ли он на курсе? Значок CLI рядом с заголовком указывает, является ли сессия стенограммой Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity или Goose. На нем показана шкала времени всего, что произошло в сессии: -- **Messages** — текстовые ответы Claude и подсказки пользователя +- **Messages** — текстовые ответы Claude и запросы пользователя - **Tool calls** — каждый инструмент, который вызвал Claude, с его входными и выходными данными -- **Policy activity** — для каждого вызова инструмента, какие политики срабатывали и какое решение они вернули +- **Policy activity** — для каждого вызова инструмента, какие политики сработали и какое решение они вернули -Панель статистики вверху показывает длительность сеанса, общее количество вызовов инструментов и сводку решений хуков (счётчики allow / deny / instruct). +Панель статистики в верхней части показывает продолжительность сессии, общее количество вызовов инструментов и сводку решений хуков (количество allow / deny / instruct). -Нажмите кнопку **Download Logs** для экспорта сеанса. Для сеансов Claude Code, Codex, Copilot, Cursor, Pi и Gemini вы получаете исходную транскрипцию JSONL на диске в исходном виде; для OpenCode (чьи сеансы хранятся в SQLite, а не на диске) вы получаете JSON-документ, отражающий основные таблицы `session` / `messages` / `parts`. +Нажмите кнопку **Download Logs** для экспорта сессии. Для сессий Claude Code, Codex, Copilot, Cursor и Pi вы получаете исходную стенограмму JSONL на диске байт в байт; для OpenCode (чьи сессии находятся в SQLite, а не на диске) вы получаете документ JSON, отражающий базовые таблицы `session` / `messages` / `parts`. ### Audit -Доклад, выстроенный с учётом особенностей вашего агента, о том, как он на самом деле вёл себя в прошлых сеансах. Выполняет то же сканирование, что и CLI `failproofai audit`, но отображает это как одноэкранный проверяемый постер + четыре раздела ниже видимой области: +Отчет, основанный на личности, о том, как ваш агент фактически себя вел во время прошлых сессий. Запускает то же сканирование, что и CLI `failproofai audit`, но отображает его как единую экранную общедоступный постер + четыре раздела ниже линии сгиба: -1. **Poster** — заполняет первый видимый экран. Автономный регион захвата PNG с логотипом failproof_ai + метка аудита · индекс архетипа (`№ NN из 08`) + дата аудита · числовой счёт (0–100) + таблетка рангового процентиля (`top 15%`) · имя архетипа (один из `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + полоса из 3 ключевых слов · строка редкости `// только N% агентов имеют этот архетип` · пиксельная плитка сигилла 8×8 · нижний колонтитул `audit yours → failproof.ai`. Три кнопки общего доступа находятся прямо за пределами поля захвата: `post your archetype` (намерение X), `share on linkedin`, `download poster`. Захват выполняется через `html-to-image`, поэтому PNG совпадает с отображением на экране пиксель в пиксель (пунктирные границы, маска логотипа SVG, градиенты, метрики шрифтов — всё сохраняется). -2. **Strengths** — спокойный ✓ список поведения, которое ваш агент уже выполняет правильно, полученный из данных живого аудита (чистая скорость вызовов инструментов, без прямых push на main, ноль утечек учётных данных, нет волн повторных попыток) — каждое появляется только когда соответствующая политика имеет чистый учёт во время окна аудита. -3. **Quirks** — таблица того, что прошло, ранжированная по степени серьёзности: `when · what slipped + the policy that would've caught it · severity pill · seen`, где повторяемость читается как `new` (один раз), `N× seen` (2–9 раз) или `recurring` (10+). -4. **How to improve** — спокойный список строк, по одной на каждую назначенную политику: имя политики белым, однострочное описание, команда установки + кнопка копирования на правой стороне. Заголовок раздела читает `enable all N → projected · ` (счёт, который вы достигли бы при каждом исправлении), и его кнопка `[install all]` копирует объединённую команду `failproofai policy add a b c …` для каждой назначенной политики. -5. **Come back better** — две карточки бок о бок. Слева: установить напоминание (выбор кадентности `3d` / `7d` / `14d` / `30d`; сохраняется через `/api/auth/reminder` после аутентификации). Справа: разблокировать привилегии failproof — `invite a friend` открывает модальное окно, которое принимает список электронных адресов друзей, разделённых запятой/пробелом/новой строкой (макс. 10 за отправку), публикует их на `/api/audit/invite`, которое пересылает на `POST /v0/invite` сервера API. Сервер API отправляет одно электронное письмо на одного получателя с адреса `invite@failproof.ai` с добавлением отправителя в Cc и установкой `Reply-To`, чтобы получатель видел, кто его пригласил, а отправитель получил копию в своём почтовом ящике. Анонимные пользователи сначала проходят через `AuthDialog`, чтобы электронный адрес отправителя был известен до отправки приглашений. Исполнение прав / привилегий — это дальнейшая работа. +1. **Poster** — заполняет первый видовой экран. Автономный регион PNG-захвата с логотипом failproof_ai + метка аудита · индекс архетипа (`№ NN of 08`) + дата аудита · числовой счет (0–100) + таблетка процентиля (`top 15%`) · название архетипа (один из `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + полоса 3 ключевых слов · строка редкости `// only N% of agents are this archetype` · плитка сигилов 8×8 пикселей · подвал `audit yours → failproof.ai`. Три кнопки для поделиться находятся за пределами области захвата: `post your archetype` (X intent), `share on linkedin`, `download poster`. Захват работает через `html-to-image`, поэтому PNG соответствует отображению на экране пиксель в пиксель (пунктирные границы, маска логотипа SVG, градиенты, метрики шрифтов — все сохранено). +2. **Strengths** — спокойный список ✓ поведения, которое ваш агент уже делает правильно, выведенный из данных аудита в реальном времени (чистая частота вызовов инструментов, нет прямых отправок на main, нулевые утечки учетных данных, нулевые штормы повторных попыток) — каждый видимый только когда соответствующая политика имеет чистую запись во всем окне аудита. +3. **Quirks** — таблица того, что прошло сквозь, ранжированная по серьезности: `when · what slipped + the policy that would've caught it · severity pill · seen`, где повторяемость читается `new` (один раз), `N× seen` (2–9 раз), или `recurring` (10+). +4. **How to improve** — спокойный список строк, одна на предписанную политику: имя политики белым, однострочное описание, команда установки + кнопка копирования на правой стороне. Заголовок раздела читается `enable all N → projected · ` (балл, который вы получите, если применить каждое исправление), и его кнопка `[install all]` копирует объединенную команду `failproofai policy add a b c …` для каждой предписанной политики. +5. **Come back better** — две карточки рядом. Слева: установить напоминание (средство выбора кадра `3d` / `7d` / `14d` / `30d`; сохраняется через `/api/auth/reminder` после аутентификации). Справа: разблокируйте преимущества failproof — `invite a friend` открывает модальное окно, которое принимает разделенный запятой/пробелом/новой строкой список писем друзей (макс. 10 за отправку), отправляет их в `/api/audit/invite`, который перенаправляет на `/v0/invite` api-сервера. API-сервер отправляет одно письмо на каждого получателя от `invite@failproof.ai` с добавлением отправителя в Cc и `Reply-To`, установленным, так что получатель видит, кто их пригласил, и отправитель получает копию в своем входящем. Анонимные пользователи перенаправляются через `AuthDialog` сначала, чтобы электронная почта отправителя была известна перед отправкой приглашений. Выполнение прав доступа / преимуществ — это дальнейший этап. -Работает с помощью среды выполнения `failproofai audit` — см. [Audit CLI](/ru/cli/audit) для основного механизма сканирования, поддерживаемых флагов и инвариантов кэша для каждой транскрипции. Панель управления кэширует последний результат на `~/.failproofai/audit-dashboard.json` (режим `0600`, одиночный слот, новые запуски переписывают) поэтому повторные посещения мгновенны; **кэш для каждой транскрипции и весь кэш результатов отклоняются при чтении один раз они старше 7 дней**, поэтому панель управления никогда молча не обслуживает неделю старого результата — прошлый TTL `/audit` падает в пустое состояние и подсказывает свежий запуск. Нажатие `[ re-audit now ]` рядом с нижней частью отчёта публикует `/api/audit/run` с `noCache: true` — перепроверка обходит кэш для каждой транскрипции и повторно сканирует каждую транскрипцию с нуля вместо молчаливого возврата кэшированного результата — и панель управления опрашивает `/api/audit/status` на частоте 1 Гц до завершения запуска; липкая розовая полоса прогресса закрепляется в верхней части видимой области во время запуска с истёкшим таймером, и свежий результат переставляется на место при успехе (нет полной перезагрузки страницы; неудачная перепроверка оставляет предыдущий отчёт неповреждённым). При отказе полоса становится красной с копией, предусмотренной из `RerunError.kind` (`timeout` / `network` / `post_failed`). Пустое состояние (отсутствие кэша или истекший) и состояние нулевых сеансов (кэш существует, но сканирование не нашло транскрипции) отображаются отдельно. +Управляется средой выполнения `failproofai audit` — см. [Audit CLI](/ru/cli/audit) для базового механизма сканирования, поддерживаемых флагов и инвариантов кэша для каждой стенограммы. Панель управления кэширует последний результат в `~/.failproofai/audit-dashboard.json` (режим `0600`, единый слот, новые запуски перезаписывают), поэтому повторные посещения мгновенны; **как кэш для каждой стенограммы, так и кэш всего результата отклоняются при чтении один раз они старше 7 дней**, поэтому панель управления никогда не служит результатом неделю назад — после TTL `/audit` переходит в пустое состояние и предлагает новый запуск. Нажатие `[ re-audit now ]` рядом с концом отчета отправляет POST на `/api/audit/run` с `noCache: true` — повторный аудит пропускает кэш для каждой стенограммы и пересканирует каждую стенограмму с нуля вместо того, чтобы молча возвращать кэшированный результат — и панель управления опрашивает `/api/audit/status` при 1 Гц до завершения запуска; липкая розовая полоса прогресса приклеивается к верхней части видовых окон во время запуска с истекшим таймером, и свежий результат заменяется на место при успехе (без полной перезагрузки страницы; неудачный повторный аудит оставляет предыдущий отчет нетронутым). При сбое полоса становится красной с копией, основанной на `RerunError.kind` (`timeout` / `network` / `post_failed`). Пустое состояние (нет кэша или истекло) и состояние нулевых сессий (кэш существует, но сканирование не нашло стенограмм) отображаются отдельно. ### Policies -Двухвкладочная страница для управления политиками и проверки активности. +Страница с двумя вкладками для управления политиками и просмотра активности. - - Выберите несколько агентов CLI, которых защищает failproofai, из одной панели — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI и Hermes все имеют строку со статусом установки (`Active` / `Detected` / `Inactive`), путём пользовательской области видимости и фирменный цветной акцент. Отметьте или снимите отметку с CLI, которые вы хотите, и нажмите `Apply changes` для установки/удаления разницы за один шаг. CLI, чьи двоичные файлы обнаружены в PATH, предварительно отмечены. - - Переключайте отдельные политики вкл/выкл одним щелчком (записывает в `~/.failproofai/policies-config.json` — общее для каждого установленного CLI) - - Разверните политику для настройки её параметров (для политик, поддерживающих `policyParams`) - - Установите путь пользовательского файла политик + - Выберите из единого панели, какие CLI агентов защищает failproofai — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi и Hermes имеют строку со статусом установки (`Active` / `Detected` / `Inactive`), пути настроек в области пользователя и цветным акцентом бренда. Отмечайте или снимайте отметки с CLI, которые вам нужны, и нажимайте `Apply changes` для установки/удаления diff за один шаг. CLI, чьи двоичные файлы обнаружены в PATH, предварительно отмечены. + - Включайте или отключайте отдельные политики одним щелчком (записывает в `~/.failproofai/policies-config.json` — общие для каждого установленного CLI) + - Разверните политику для настройки ее параметров (для политик, которые поддерживают `policyParams`) + - Установите пользовательский путь к файлу политик - - Полная постраничная история каждого события хука, срабатывающего во всех сеансах - - Фильтруйте по решению, типу события, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), имени политики или ID сеанса - - Каждая строка показывает: временную метку, имя политики, решение, значок CLI (оранжевый = Claude Code, фиолетовый = OpenAI Codex, синий = GitHub Copilot, изумруд = Cursor Agent, янтарь = OpenCode, розовый = Pi, небесно-голубой = Gemini CLI, индиго = Hermes), имя инструмента, ID сеанса и причину решений deny/instruct - - Щёлкните по ID сеанса, чтобы открыть его транскрипцию — средство просмотра автоматически обнаруживает, какой CLI срабатил хук (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) и отображает соответствующий значок CLI в заголовке + - Полная постраничная история каждого события хука, которое срабатывало во всех сессиях + - Фильтруйте по решению, типу события, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), имени политики или ID сессии + - Каждая строка отображает: временную метку, имя политики, решение, значок CLI (оранжевый = Claude Code, фиолетовый = OpenAI Codex, синий = GitHub Copilot, изумрудный = Cursor Agent, янтарный = OpenCode, розовый = Pi, индиго = Hermes, бирюзовый = OpenClaw, розовый = Factory Droid, фиолетовый = Devin, голубой = Antigravity, лайм = Goose), имя инструмента, ID сессии и причину решений deny/instruct + - Нажмите на ID сессии, чтобы открыть ее стенограмму — средство просмотра автоматически определяет, какой CLI сработал хук (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) и отображает соответствующий значок CLI в заголовке @@ -92,13 +92,13 @@ failproofai ## Auto-refresh -Панель управления имеет переключатель автоматического обновления в верхней навигации. Если он включен, текущая страница периодически обновляется, чтобы показывать новые сеансы и активность политик по мере их появления. Важно для мониторинга долгоживущих сеансов автономного агента. +Панель управления имеет переключатель автообновления в верхней навигации. При включении текущая страница периодически обновляется, чтобы показывать новые сессии и активность политик по мере их появления. Необходимо для мониторинга долгоживущих сессий автономных агентов. --- ## Отключение страниц -Если вам нужны только некоторые части панели управления, установите `FAILPROOFAI_DISABLE_PAGES` на список имён страниц, разделённых запятыми: +Если вам нужны только некоторые части панели управления, установите `FAILPROOFAI_DISABLE_PAGES` на разделенный запятой список имен страниц: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -108,9 +108,9 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai --- -## Настройка пути к проектам +## Настройка пути проектов -По умолчанию панель управления читает из стандартного каталога проектов Claude Code. Переопределите его для пользовательских установок: +По умолчанию панель управления читает из стандартного каталога проектов Claude Code. Переопределите его для пользовательских настроек: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,21 +118,21 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## Доступ с хоста, отличного от localhost +## Доступ с нелокального хоста -При запуске панели управления в **режиме разработки** (`npm run dev`) и её доступе с имени хоста, отличного от `localhost` — например, пользовательского домена, удалённого IP или туннелированного URL — вы можете увидеть предупреждение вроде: +При запуске панели управления в **режиме разработки** (`npm run dev`) и доступе к ней с имени хоста, отличного от `localhost` — например, с пользовательского домена, удаленного IP или туннелированного URL — вы можете увидеть предупреждение вроде: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Это Next.js блокирует кроссисточниковый доступ к его HMR (горячей перезагрузке модуля) веб-сокету, который является функцией только для разработки. Чтобы разрешить ваш хост, используйте флаг `--allowed-origins`: +Это Next.js блокирует кросс-происхождение доступ к его HMR (горячая перезагрузка модулей) вебсокету, что является функцией только для разработки. Чтобы разрешить ваш хост, используйте флаг `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -Для нескольких хостов или IP-адресов передайте список, разделённый запятыми: +Для нескольких хостов или IP передайте разделенный запятой список: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 @@ -145,5 +145,5 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Это применяется только к режиму разработки. При запуске `failproofai` (производственном режиме) нет веб-сокета HMR и нет проблемы с кроссисточниковым доступом к ресурсам разработки. +Это применяется только к режиму разработки. При запуске `failproofai` (режим производства) нет вебсокета HMR и нет проблемы с кросс-происхождением ресурсов разработки. \ No newline at end of file diff --git a/docs/ru/getting-started.mdx b/docs/ru/getting-started.mdx index 26e9d490..21126c8e 100644 --- a/docs/ru/getting-started.mdx +++ b/docs/ru/getting-started.mdx @@ -1,13 +1,13 @@ --- -title: Быстрый старт -description: "Установите failproofai, включите политики и дайте своим агентам работать надёжно" +title: Начало работы +description: "Установите failproofai, включите политики и позвольте вашим агентам работать надёжно" icon: rocket --- ## Требования - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (опционально - требуется только для сборки из исходного кода) +- **Bun** >= 1.3.0 (опционально — требуется только для сборки из исходников) --- @@ -31,15 +31,15 @@ bun add -g failproofai - Политики — это правила, которые выполняются перед и после каждого вызова инструмента агентом. Они перехватывают деструктивные команды, утечки секретов и другие сбои до того, как они нанесут ущерб. + Политики — это правила, которые выполняются до и после каждого вызова инструмента агентом. Они перехватывают деструктивные команды, утечки секретов и другие сценарии отказа до того, как они причинят вред. ```bash failproofai policies --install ``` - Эта команда записывает записи хуков в установленные CLI агентов (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, или Hermes's `~/.hermes/config.yaml`). Если присутствует несколько, вам будет предложено выбрать; передайте `--cli claude codex copilot cursor opencode pi gemini hermes` (любое подмножество), чтобы пропустить запрос. + Это добавляет записи hook в установленные CLI агентов (settings.json Claude Code в `~/.claude/settings.json`, hooks.json OpenAI Codex в `~/.codex/hooks.json`, failproofai.json GitHub Copilot CLI в `~/.copilot/hooks/failproofai.json`, hooks.json Cursor Agent в `~/.cursor/hooks.json`, сгенерированную подстановку плагина OpenCode в `~/.config/opencode/plugins/failproofai.mjs` плюс запись регистрации в массиве `plugin` файла `~/.config/opencode/opencode.json`, settings.json Pi в `~/.pi/agent/settings.json`, config.yaml Hermes в `~/.hermes/config.yaml`, openclaw.json OpenClaw в `~/.openclaw/openclaw.json`, hooks.json Factory Droid в `~/.factory/hooks.json`, config.json Devin CLI в `~/.config/devin/config.json`, hooks.json Antigravity CLI в `~/.gemini/config/hooks.json` или автоматически обнаруживаемую директорию плагина Goose в `~/.agents/plugins/failproofai/hooks/hooks.json`). Если присутствует более одного, вам будет предложено выбрать; передайте `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (любое подмножество), чтобы пропустить подсказку. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi и Gemini CLI поддерживаются в режиме **бета** — установите с помощью `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` или `--cli gemini`. Hermes (hermes-agent, шлюз Slack/Telegram) устанавливается в область пользователя с помощью `--cli hermes` и также является источником автономного аудита. + Поддержка GitHub Copilot CLI, Cursor Agent, OpenCode и Pi находится в статусе **beta** — установите с помощью `--cli copilot`, `--cli cursor`, `--cli opencode` или `--cli pi`. Hermes (hermes-agent, шлюз Slack/Telegram) устанавливается с областью пользователя с помощью `--cli hermes` и является **также** автономным источником аудита. OpenClaw (шлюз openclaw, многоканальный локальный ассистент) устанавливается с областью пользователя с помощью `--cli openclaw` — применение политик происходит через встроенные hook-и плагина (`before_agent_finalize` является реальным шлюзом конца хода, поэтому встроенные политики `require-*-before-stop` работают) — и является **также** автономным источником аудита. Factory Droid (`droid`) устанавливается с помощью `--cli factory` (область пользователя + проекта) и является **также** автономным источником аудита. Devin CLI (`devin`, Cognition) устанавливается с помощью `--cli devin` (область пользователя + проекта) и является **также** автономным источником аудита. Antigravity CLI (`agy`) устанавливается с помощью `--cli antigravity` (область пользователя + проекта) и является **также** автономным источником аудита. Goose (кодовое имя goose, Block) устанавливается с помощью `--cli goose` (область пользователя + проекта) — установщик просто помещает директорию плагина в `~/.agents/plugins/failproofai/`, которую Goose автоматически обнаруживает, и это **также** автономный источник аудита. ```bash failproofai policies --install --scope project @@ -48,27 +48,31 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` - + ```bash failproofai policies ``` - Показывает все политики, включены ли они и все настроенные параметры. + Показывает каждую политику, включена ли она, и любые настроенные параметры. - + ```bash failproofai ``` - Открывает локальную панель управления на `http://localhost:8020`, где вы можете просматривать сессии, инспектировать вызовы инструментов и управлять политиками. + Открывает локальную панель мониторинга по адресу `http://localhost:8020`, где вы можете просматривать сеансы, проверять вызовы инструментов и управлять политиками. - - Запустите Claude Code как обычно. Если агент попытается что-то рискованное, failproofai автоматически это перехватит. Оставьте его работать без присмотра и просмотрите результаты на панели управления. + + Запустите Claude Code как обычно. Если агент попытается что-то рискованное, failproofai автоматически его перехватит. Оставьте его работающим без присмотра и просмотрите произошедшее на панели мониторинга. @@ -86,19 +90,19 @@ Claude Code → failproofai --hook PreToolUse → читает JSON из std Каждая политика возвращает одно из трёх решений: -- **allow** — агент работает нормально -- **deny** — действие блокируется, агенту сообщается причина -- **instruct** — в запрос агента добавляется дополнительный контекст +- **allow** — агент действует нормально +- **deny** — действие блокируется, агенту объясняется почему +- **instruct** — дополнительный контекст добавляется в подсказку агента -Политики выполняются в вашем локальном процессе. Ничего не отправляется на удалённый сервис. +Политики выполняются в вашем локальном процессе. Ничто не отправляется на удалённый сервис. --- -## Установите командные политики с использованием соглашения о политиках +## Установите командные политики с помощью политик на основе соглашений -Самый быстрый способ установить стандарты качества в вашей команде — это соглашение `.failproofai/policies/`. Просто добавьте файлы политик в эту директорию, и они будут загружены автоматически — без флагов, без изменения конфигурации, без команд установки. +Быстрейший способ установить стандарты качества в вашей команде — это соглашение `.failproofai/policies/`. Положите файлы политик в эту директорию, и они будут загружены автоматически — без флагов, без изменения конфигурации, без команд установки. @@ -107,13 +111,13 @@ Claude Code → failproofai --hook PreToolUse → читает JSON из std ``` - Скопируйте примеры-шаблоны или напишите свои собственные: + Скопируйте примеры-стартеры или напишите свои собственные: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - Или создайте новый: + Или создайте новый файл: ```js // .failproofai/policies/team-policies.mjs @@ -125,25 +129,25 @@ Claude Code → failproofai --hook PreToolUse → читает JSON из std fn: async (ctx) => { if (ctx.toolName !== "Bash") return allow(); if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) { - return instruct("Run tests before committing."); + return instruct("Запустите тесты перед коммитом."); } return allow(); }, }); ``` - + ```bash git add .failproofai/policies/ git commit -m "Add team quality policies" ``` - Каждый член команды, у которого установлен failproofai, автоматически получит эти политики. Не требуется настройка для каждого разработчика. + Каждый участник команды, у которого установлен failproofai, автоматически получит эти политики. Никаких настроек для отдельных разработчиков не требуется. -Зафиксируйте `.failproofai/policies/` в вашем репозитории, чтобы вся команда следовала одним и тем же стандартам. По мере того, как ваша команда обнаруживает новые способы сбоев, добавляйте политики и публикуйте их — все получат обновление при следующем `git pull`. Со временем эти политики становятся живым стандартом качества, который постоянно улучшается. +Закоммитьте `.failproofai/policies/` в ваш репозиторий, чтобы вся команда придерживалась одних и тех же стандартов. По мере того как ваша команда обнаруживает новые сценарии отказа, добавляйте политики и отправляйте их — все получат обновление при следующем `git pull`. Со временем эти политики становятся живым стандартом качества, который постоянно улучшается. --- @@ -152,13 +156,13 @@ Claude Code → failproofai --hook PreToolUse → читает JSON из std Вся конфигурация и логи остаются на вашем компьютере: -| Путь | Что здесь хранится | -|------|---| +| Путь | Что хранится | +|------|--------------| | `~/.failproofai/policies-config.json` | Глобальная конфигурация политик | -| `~/.failproofai/hook-activity.jsonl` | История выполнения хуков | -| `~/.failproofai/hook.log` | Лог отладки для ошибок пользовательских хуков | -| `.failproofai/policies-config.json` | Конфигурация для конкретного проекта (зафиксирована в git) | -| `.failproofai/policies-config.local.json` | Личные переопределения (в .gitignore) | +| `~/.failproofai/hook-activity.jsonl` | История выполнения hook-ов | +| `~/.failproofai/hook.log` | Журнал отладки для ошибок пользовательских hook-ов | +| `.failproofai/policies-config.json` | Конфигурация для каждого проекта (коммитится) | +| `.failproofai/policies-config.local.json` | Личные переопределения (gitignored) | --- @@ -168,16 +172,16 @@ Claude Code → failproofai --hook PreToolUse → читает JSON из std failproofai policies --uninstall ``` -Удаляет записи хуков из `~/.claude/settings.json`. Файлы конфигурации в `~/.failproofai/` сохраняются. +Удаляет записи hook из `~/.claude/settings.json`. Файлы конфигурации в `~/.failproofai/` сохраняются. --- -## Следующие шаги +## Дальнейшие шаги - Области действия и формат файла конфигурации + Области и формат файла конфигурации @@ -185,11 +189,11 @@ failproofai policies --uninstall - Напишите свои политики на JavaScript + Напишите свои собственные политики на JavaScript - Мониторьте сессии и проверяйте активность политик + Мониторьте сеансы и проверяйте активность политик \ No newline at end of file diff --git a/docs/ru/introduction.mdx b/docs/ru/introduction.mdx index 4996d294..23186dfd 100644 --- a/docs/ru/introduction.mdx +++ b/docs/ru/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI предоставляет AI агентам 39 встроенных политик защиты, которые выявляют циклы, утечки секретов, деструктивные вызовы инструментов и многое другое в единой установке." +description: "FailproofAI предоставляет AI-агентам 39 встроенных политик отказоустойчивости, которые перехватывают циклы, утечки секретов, деструктивные вызовы инструментов и многое другое при однократной установке." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Хуки и политики для **обработки сбоев AI**, **восстановления после ошибок** и **надёжности LLM**. Держите ваших AI агентов надёжными и работающими автономно на **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** и **Agents SDK**. +Хуки и политики для **обработки отказов AI**, **восстановления после ошибок** и **надёжности LLM**. Держите ваших AI-агентов надёжными и работающими автономно в **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** и **Agents SDK**. -AI агенты падают предсказуемым образом. Они выполняют деструктивные команды, утекают секреты, отходят от задачи, застревают в циклах или пушат прямо в main. Без надзора, небольшие сбои каскадируют в отказы, утечки учётных данных и потерю работы. +AI-агенты отказывают предсказуемым образом. Они выполняют деструктивные команды, утекают секреты, отвлекаются от задачи, застревают в циклах или пушят напрямую в main. Без присмотра небольшие ошибки перерастают в сбои, утечки учётных данных и потерю работы. -FailproofAI решает эту проблему с помощью **политик**. Эти правила перехватывают каждый вызов инструмента агента, чтобы **обнаружить сбои**, **смягчить их** (блокировать, инструктировать, санитизировать) и **оповестить вас**, когда требуется внимание. Локальная панель позволяет вам просмотреть каждый вызов инструмента, сбой агента и действие восстановления впоследствии. +FailproofAI решает эту проблему с помощью **политик**. Эти правила интегрируются в каждый вызов инструмента агента, чтобы **обнаруживать отказы**, **смягчать их** (блокировать, инструктировать, санитизировать) и **уведомлять вас**, когда что-то требует внимания. Локальная панель инструментов позволяет вам позже просмотреть все вызовы инструментов, отказы агента и действия по восстановлению. Никакие данные не покидают вашу машину. -## Начните с этого +## Начало работы - Блокируйте деструктивные команды, предотвращайте утечки секретов, держите агентов внутри границ проекта и многое другое. Всё готово к использованию. + Блокируйте деструктивные команды, предотвращайте утечки секретов, держите агентов в границах проекта и многое другое. Всё готово к использованию. - Напишите свои правила на JavaScript с простым API allow / deny / instruct. + Напишите свои собственные правила на JavaScript с простым API allow / deny / instruct. - Смотрите, что делали ваши агенты, пока вас не было. Просматривайте сессии, проверяйте вызовы инструментов, смотрите, где срабатывали политики. + Посмотрите, что делали ваши агенты, пока вас не было. Просмотрите сессии, изучите вызовы инструментов, проверьте, где срабатывали политики. - Настраивайте любую политику без кода. Устанавливайте разрешённые списки, защищённые ветки или пороги для каждого проекта или глобально. + Настраивайте любую политику без кода. Установите списки разрешений, защищённые ветки или пороги для каждого проекта или глобально. @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # включить политики (или пропустить — `failproofai` предложит установить их при первом запуске) -failproofai # запустить панель +failproofai policies --install # включить политики (или пропустить — `failproofai` предложит их настроить при первом запуске) +failproofai # запустить панель инструментов ``` -Смотрите руководство [Начало работы](/ru/getting-started) для полного пошагового описания. \ No newline at end of file +Полный пошаговый процесс смотрите в руководстве [Getting started](/ru/getting-started). \ No newline at end of file diff --git a/docs/styles/config/vocabularies/Mintlify/accept.txt b/docs/styles/config/vocabularies/Mintlify/accept.txt index c7f9498d..c0668800 100644 --- a/docs/styles/config/vocabularies/Mintlify/accept.txt +++ b/docs/styles/config/vocabularies/Mintlify/accept.txt @@ -4,7 +4,6 @@ Anthropic Codex Copilot Cursor -Gemini OpenCode PreToolUse PostToolUse diff --git a/docs/tr/built-in-policies.mdx b/docs/tr/built-in-policies.mdx index 240ec79d..f63991d3 100644 --- a/docs/tr/built-in-policies.mdx +++ b/docs/tr/built-in-policies.mdx @@ -1,22 +1,22 @@ --- title: Yerleşik İlkeler -description: "Ajent başarısızlık modlarını yakalayan 39 yerleşik ilke" +description: "Yaygın ajan başarısızlık modlarını yakalayan 39 yerleşik ilke" icon: shield --- -failproofai, ortak ajent başarısızlık modlarını yakalayan 39 yerleşik ilke ile birlikte gelir. Her ilke belirli bir hook olay türü ve araç adında devreye girer. On dokuz ilke, kod yazmanıza gerek kalmadan davranışlarını ayarlamanıza izin veren parametreleri kabul eder. Beş iş akışı ilkesi, Claude'un durmadan önce commit → push → PR → CI ardışık düzenini uygular. +failproofai yaygın ajan başarısızlık modlarını yakalayan 39 yerleşik ilke ile birlikte gelir. Her ilke belirli bir hook olay türü ve araç adında tetiklenir. On dokuz ilke, kod yazmadan davranışlarını ayarlamanıza olanak veren parametreleri kabul eder. Beş iş akışı ilkesi Claude durdurmadan önce commit → push → PR → CI işlem hattını zorunlu kılar. --- -## Genel Bakış +## Özet -İlkeler kategorilere ayrılır: +İlkeler kategorilere göre gruplandırılır: | Kategori | İlkeler | Hook türü | |----------|---------|-----------| | [Tehlikeli komutlar](#tehlikeli-komutlar) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [Altyapı komutları](#altyapı-komutları) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [Sırlar (sanitizers)](#sırlar-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [Sırlar (sanitizer)](#sırlar-sanitizer) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | | [Ortam](#ortam) | block-env-files, protect-env-vars | PreToolUse | | [Dosya erişimi](#dosya-erişimi) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | @@ -25,15 +25,15 @@ failproofai, ortak ajent başarısızlık modlarını yakalayan 39 yerleşik ilk | [Paket yöneticileri](#paket-yöneticileri) | prefer-package-manager | PreToolUse | | [İş akışı](#iş-akışı) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — ajanı devam etmekten durdur. -- **`warn-`** — ajenta ek bağlam sağla, böylece kendini düzeltebilsin. -- **`sanitize-`** — ajent görmeden önce araç çıktısından hassas verileri temizle. +- **`block-`** — ajanın devam etmesini durdur. +- **`warn-`** — ajanın kendi kendini düzeltebilmesi için ek bağlam sağla. +- **`sanitize-`** — ajan görmeden önce araç çıktısından hassas verileri temizle. ### Ad Alanları -Her ilke bir `/` slotunda bulunur. Yerleşik ilkeler **`failproofai/`** ad alanına aittir — örneğin, `failproofai/sanitize-jwt`. Ad alanı, benzer kısa adlara sahip özel veya üçüncü taraf ilkeleri yüklerken çakışmaları önler. +Her ilke bir `/` konumunda yer alır. Yerleşik ilkeler **`failproofai/`** ad alanına aittir — örneğin, `failproofai/sanitize-jwt`. Ad alanı, benzer kısa adlara sahip özel veya üçüncü taraf ilkeler yüklediğinizde çakışmaları önler. -Yapılandırmanızda yerleşik bir ilkeye kısa adı veya tam adı ile başvurabilirsiniz; her iki form da aynı ilkeyi çözer: +Yapılandırmanızda yerleşik bir ilkeye kısa adıyla veya nitelenmiş adıyla başvurabilirsiniz; her iki form aynı ilkeyi çözer: ```json { @@ -44,33 +44,33 @@ Yapılandırmanızda yerleşik bir ilkeye kısa adı veya tam adı ile başvurab } ``` -Bir adda `/` yoksa, failproofai bunu varsayılan `failproofai` ad alanına ait olarak davranır. Zaten `/` içeren adlar (örneğin `myorg/foo`, `custom/my-hook`) olduğu gibi tutulur. -- **`require-`** — koşullar karşılanana kadar Stop olayını engelle. +Ad içinde `/` yoksa, failproofai bunu `failproofai` varsayılan ad alanına ait olarak davranır. Zaten `/` içeren adlar (örn. `myorg/foo`, `custom/my-hook`) olduğu gibi tutulur. +- **`require-`** — koşullar karşılanıncaya kadar Stop olayını engelle. --- -Her ilke `policyParams` içinde isteğe bağlı bir `hint` alanını destekler. İpucu, Claude'un gördüğü deny veya instruct iletisine eklenir; ilke kodunu değiştirmeden işlem yapılabilir rehberlik sağlar. Yerleşik, özel ve kural ilkeleriyle çalışır. Ayrıntılar için [Yapılandırma → hint](/tr/configuration#hint-cross-cutting) bölümüne bakın. +Her ilke `policyParams` içinde isteğe bağlı bir `hint` alanını destekler. İpucu, Claude'un gördüğü deny veya instruct mesajına eklenir ve ilke kodunu değiştirmeden işlem yapılabilir rehberlik sağlar. Yerleşik, özel ve sözleşme ilkeleriyle çalışır. Ayrıntılar için [Yapılandırma → hint](/tr/configuration#hint-cross-cutting) bölümüne bakın. --- ## Tehlikeli komutlar -Ajentlerin geri alınması zor olan veya ana bilgisayar sistemine zarar verebilecek işlemleri çalıştırmasını önleyin. +Ajanları geri almakta zor veya konak sistemine zarar verebilecek işlemleri çalıştırmasını önleyin. ### `block-sudo` **Olay:** PreToolUse (Bash) **Varsayılan:** Herhangi bir `sudo` komutunu reddeder. -`sudo` anahtar sözcüğünü içeren çağırışları engeller. Model eşleştirme ham dize yerine ayrıştırılmış komut jetonlarında yapılır; shell operatörü enjeksiyonu yoluyla atlatmayı önler. +`sudo` anahtar sözcüğünü içeren çağrıları engeller. Desen eşleştirmesi ham dizede değil, ayrıştırılmış komut belirteçleri üzerinde yapılır ve bu da shell operatörü enjeksiyonu yoluyla bypass'ı önler. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen tam komut önekleri. Her giriş ayrıştırılmış argv jetonlarına karşı eşleştirilir. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen tam komut ön ekleri. Her giriş, ayrıştırılmış argv belirteçlerine karşı eşleştirilir. | **Örnek:** @@ -84,10 +84,10 @@ Ajentlerin geri alınması zor olan veya ana bilgisayar sistemine zarar verebile } ``` -Bu yapılandırma ile `sudo systemctl status nginx` izin verilir, ancak `sudo rm /etc/hosts` reddedilir. +Bu yapılandırmayla `sudo systemctl status nginx` izin verilir, ancak `sudo rm /etc/hosts` reddedilir. -Desenler ham komut dizesi değil, ayrıştırılmış jetonlara karşı eşleştirilir. Bu, shell operatörleri yoluyla atlatmayı önler (örneğin `sudo systemctl status x; rm -rf /` kodu `sudo systemctl status *` ile eşleşmez). +Desenler ham komut dizesine değil, ayrıştırılmış belirteçlere karşı eşleştirilir. Bu, eklenen shell operatörleri yoluyla bypass'ı önler (örneğin `sudo systemctl status x; rm -rf /` `sudo systemctl status *` ile eşleşmez). --- @@ -95,13 +95,13 @@ Desenler ham komut dizesi değil, ayrıştırılmış jetonlara karşı eşleşt ### `block-rm-rf` **Olay:** PreToolUse (Bash) -**Varsayılan:** `rm -rf`, `rm -fr` ve benzer yinelemeli silme formlarını reddeder. +**Varsayılan:** `rm -rf`, `rm -fr` ve benzer özyinelemeli silme biçimlerini reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPaths` | `string[]` | `[]` | Yinelemeli olarak silinmesi güvenli olan yollar (örneğin `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Özyinelemeli olarak silinmesi güvenli olan yollar (örn. `/tmp`). | **Örnek:** @@ -122,35 +122,35 @@ Desenler ham komut dizesi değil, ayrıştırılmış jetonlara karşı eşleşt **Olay:** PreToolUse (Bash) **Varsayılan:** `curl | bash`, `curl | sh`, `wget | bash` ve benzer desenleri reddeder. -Parametresi yok. +Parametre yok. --- ### `block-failproofai-commands` **Olay:** PreToolUse (Bash) -**Varsayılan:** failproofai'nin kendisini kaldıracak veya devre dışı bırakacak komutları reddeder (örneğin `npm uninstall failproofai`, `failproofai policies --uninstall`). +**Varsayılan:** failproofai'nin kendisini kaldıracak veya devre dışı bırakacak komutları reddeder (örn. `npm uninstall failproofai`, `failproofai policies --uninstall`). -Parametresi yok. +Parametre yok. --- ## Altyapı komutları -Kodlama ajanlarının altyapı CLI'larını çalıştırmasını veya CI/CD ardışık düzenlerini tetiklemesini durdurun. Bu kategorideki tüm ilkeler **isteğe bağlı** (`defaultEnabled: false`) — `kubectl`, `terraform` vb. çağırması gereken ajanlar, ilkeyi etkinleştirmediğiniz sürece kesilmeyecektir. Etkinleştirildiğinde, eşleştirilen CLI'nın her çağırması `allowPatterns` içindeki bir giriş ile eşleşmediği sürece reddedilir. +Kodlama ajanlarının altyapı CLI'lerini çalıştırmasını veya CI/CD işlem hatlarını tetiklemesini durdurun. Bu kategorideki tüm ilkeler **opt-in** (`defaultEnabled: false`) — `kubectl`, `terraform` vb. çağrısı yapması gereken ajanlar, ilke etkinleştirilmediği sürece kesintiye uğramayacaktır. Etkinleştirildiğinde, eşleşen CLI'nin her çağrısı, komut `allowPatterns` içindeki bir girişle eşleşmediği sürece reddedilir. -Desen dilbilgisi [`block-sudo`](#block-sudo) ile aynıdır: jetonlar ayrıştırılmış argv'ye karşı eşleştirilir, `*` bir jeton için joker karakterdir ve herhangi bir shell operatörü (`&&`, `||`, `|`, `;`) içeren veya gömülü shell metakarakterleri olan komutlar, enjeksiyon atlatmalarını önlemek için beyaz liste eşleştirmesinden önce reddedilir. +Desen dilbilgisi [`block-sudo`](#block-sudo) ile aynıdır: belirteçler ayrıştırılmış argv'ye karşı eşleştirilir, `*` bir belirteç için joker kartıdır ve enjeksiyon bypass'ını önlemek için enjeksiyon eşleşmesinden önce reddedilir. ### `block-kubectl` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `kubectl` çağırışını reddeder. +**Varsayılan:** Herhangi bir `kubectl` çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen kubectl komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen kubectl komut ön ekleri. | **Örnek:** @@ -164,20 +164,20 @@ Desen dilbilgisi [`block-sudo`](#block-sudo) ile aynıdır: jetonlar ayrıştır } ``` -Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f deploy.yaml` reddedilir. +Bu yapılandırmayla `kubectl get pods` izin verilir, ancak `kubectl apply -f deploy.yaml` reddedilir. --- ### `block-terraform` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `terraform` veya `tofu` (OpenTofu) çağırışını reddeder. +**Varsayılan:** Herhangi bir `terraform` veya `tofu` (OpenTofu) çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen terraform/tofu komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen terraform/tofu komut ön ekleri. | **Örnek:** @@ -196,13 +196,13 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de ### `block-aws-cli` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `aws` CLI çağırışını reddeder. +**Varsayılan:** Herhangi bir `aws` CLI çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen aws CLI komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen aws CLI komut ön ekleri. | **Örnek:** @@ -221,13 +221,13 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de ### `block-gcloud` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `gcloud` (Google Cloud) CLI çağırışını reddeder. +**Varsayılan:** Herhangi bir `gcloud` (Google Cloud) CLI çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen gcloud komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen gcloud komut ön ekleri. | **Örnek:** @@ -246,13 +246,13 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de ### `block-az-cli` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `az` (Azure) CLI çağırışını reddeder. +**Varsayılan:** Herhangi bir `az` (Azure) CLI çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen az CLI komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen az CLI komut ön ekleri. | **Örnek:** @@ -271,13 +271,13 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de ### `block-helm` **Olay:** PreToolUse (Bash) -**Varsayılan:** Herhangi bir `helm` çağırışını reddeder. +**Varsayılan:** Herhangi bir `helm` çağrısını reddeder. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | İzin verilen helm komut önekleri. | +| `allowPatterns` | `string[]` | `[]` | İzin verilen helm komut ön ekleri. | **Örnek:** @@ -296,7 +296,7 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de ### `block-gh-pipeline` **Olay:** PreToolUse (Bash) -**Varsayılan:** Durumu değiştiren veya ardışık düzenler tetikleyen aşağıdaki `gh` CLI alt komutlarını reddeder: +**Varsayılan:** Durumu değiştiren veya işlem hatlarını tetikleyen aşağıdaki `gh` CLI alt komutlarını reddeder: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -305,13 +305,13 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de - `gh cache delete` - `gh secret set`, `gh secret delete` -`gh pr view`, `gh pr list`, `gh run list`, `gh release view` ve `gh api repos/.../...` gibi salt okunur `gh` alt komutları bu ilke tarafından eşleştirilmez — iş akışı denetimleri için rutinlik olarak gereklidir (failproofai'nin kendi `require-ci-green-before-stop` dahil). +`gh pr view`, `gh pr list`, `gh run list`, `gh release view` ve `gh api repos/.../...` gibi salt okunur `gh` alt komutları bu ilke tarafından eşleştirilmez — failproofai'nin kendi `require-ci-green-before-stop` de dahil olmak üzere iş akışı kontrolleri için rutin olarak gereklidir. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPatterns` | `string[]` | `[]` | Aksi takdirde reddedilecek olmasına rağmen izin verilebilecek belirli komut dosyası çağırışları. | +| `allowPatterns` | `string[]` | `[]` | Aksi takdirde reddedilecek belirli komut dosyası çağrılarını izin ver. | **Örnek:** @@ -327,29 +327,29 @@ Bu yapılandırma ile `kubectl get pods` izin verilir ancak `kubectl apply -f de --- -## Sırlar (sanitizers) +## Sırlar (sanitizer) -Ajentlerin kimlik bilgilerini kontekst veya çıktılarında sızmasını durdurun. Sanitizer ilkeleri **PostToolUse** olaylarında devreye girer. Claude bir Bash komutu çalıştırdığında, bir dosya okuduğunda veya herhangi bir aracı çağırdığında, bu ilkeler çıktı Claude'a döndürülmeden önce incelenir. Gizli bir desen algılanırsa, ilke çıktının geri dönmesini engelleyen bir reddetme kararı verir. +Ajanların kimlik bilgilerini bağlamlarına veya çıktılarına sızmasını durdurun. Sanitizer ilkeleri **PostToolUse** olaylarında tetiklenir. Claude bir Bash komutunu çalıştırdığında, bir dosyayı okuduğunda veya herhangi bir aracı çağırdığında, bu ilkeler çıktı, Claude'a döndürülmeden önce incelenir. Gizli bir desen algılanırsa, ilke çıktının geri dönüşünü önleyen bir deny kararı döndürür. ### `sanitize-jwt` **Olay:** PostToolUse (tüm araçlar) -**Varsayılan:** JWT jetonlarını (`.` ile ayrılmış üç base64url segmenti) gizler. +**Varsayılan:** JWT belirteçlerini (`.` ile ayrılmış üç base64url segmenti) maskeleyerek kaldırır. -Parametresi yok. +Parametre yok. --- ### `sanitize-api-keys` **Olay:** PostToolUse (tüm araçlar) -**Varsayılan:** Yaygın API anahtarı biçimlerini gizler: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PAT'ları (`ghp_`), AWS erişim anahtarları (`AKIA`), Stripe anahtarları (`sk_live_`, `sk_test_`) ve Google API anahtarları (`AIza`). +**Varsayılan:** Yaygın API anahtarı biçimlerini maskeleyerek kaldırır: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PAT'leri (`ghp_`), AWS erişim anahtarları (`AKIA`), Stripe anahtarları (`sk_live_`, `sk_test_`) ve Google API anahtarları (`AIza`). **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Sır olarak işlem görmesi gereken ek regex desenleri. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Sır olarak kabul edilecek ek regex desenleri. | **Örnek:** @@ -358,8 +358,8 @@ Parametresi yok. "policyParams": { "sanitize-api-keys": { "additionalPatterns": [ - { "regex": "myco_[A-Za-z0-9]{32}", "label": "MyCo internal API key" }, - { "regex": "pat_[0-9a-f]{40}", "label": "Internal PAT" } + { "regex": "myco_[A-Za-z0-9]{32}", "label": "MyCo iç API anahtarı" }, + { "regex": "pat_[0-9a-f]{40}", "label": "İç PAT" } ] } } @@ -371,42 +371,42 @@ Parametresi yok. ### `sanitize-connection-strings` **Olay:** PostToolUse (tüm araçlar) -**Varsayılan:** Gömülü kimlik bilgileri içeren veritabanı bağlantı dizelerini gizler (örneğin `postgresql://user:password@host/db`). +**Varsayılan:** Gömülü kimlik bilgileri içeren veritabanı bağlantı dizelerini maskeleyerek kaldırır (örn. `postgresql://user:password@host/db`). -Parametresi yok. +Parametre yok. --- ### `sanitize-private-key-content` **Olay:** PostToolUse (tüm araçlar) -**Varsayılan:** PEM bloklarını gizler (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` vb.). +**Varsayılan:** PEM bloklarını maskeleyerek kaldırır (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----` vb.). -Parametresi yok. +Parametre yok. --- ### `sanitize-bearer-tokens` **Olay:** PostToolUse (tüm araçlar) -**Varsayılan:** `Authorization: Bearer ` başlıklarını gizler; burada jeton 20 veya daha fazla karakterdir. +**Varsayılan:** Belirtecin 20 veya daha fazla karakter olduğu `Authorization: Bearer ` başlıklarını maskeleyerek kaldırır. -Parametresi yok. +Parametre yok. --- ## Ortam -Hassas ortam yapılandırmasını ajanlar tarafından okunmasından veya açığa çıkmasından koruyun. +Hassas ortam yapılandırmasını ajanlar tarafından okunmak veya açığa çıkmaktan koruyun. ### `block-env-files` **Olay:** PreToolUse (Bash, Read) -**Varsayılan:** `cat .env`, dosya yolu olarak `.env` ile Read araç çağrıları vb. aracılığıyla `.env` dosyalarını okumasını reddeder. +**Varsayılan:** `cat .env`, dosya yolu olarak `.env` ile Read araç çağrıları vb. aracılığıyla `.env` dosyalarının okunmasını reddeder. -`.envrc` veya diğer ortam-komşu dosyaları engelleme — yalnızca tam olarak `.env` adındaki dosyaları engelle. +`.envrc` veya diğer ortam ilişkili dosyaları engelleme — yalnızca `.env` olarak tam adlandırılan dosyalar. -Parametresi yok. +Parametre yok. --- @@ -415,24 +415,24 @@ Parametresi yok. **Olay:** PreToolUse (Bash) **Varsayılan:** Ortam değişkenlerini yazdıran komutları reddeder: `printenv`, `env`, `echo $VAR`. -Parametresi yok. +Parametre yok. --- ## Dosya erişimi -Ajentleri proje sınırları içinde ve hassas dosyalardan uzak tutun. +Ajanları proje sınırları içinde ve hassas dosyalardan uzakta tutun. ### `block-read-outside-cwd` **Olay:** PreToolUse (Read, Bash) -**Varsayılan:** Proje kökü dışındaki dosyaları okumasını reddeder. Sınır `CLAUDE_PROJECT_DIR` (Claude Code tarafından oturum başına bir kez ayarlanır) ve bu değişken ayarlanmadığında oturumun geçerli çalışma dizinine geri döner. Canlı `cwd` yerine proje kökünü kullanmak, Claude `cd` yaptıktan sonra bile sınırın kararlı kalmasını sağlar. +**Varsayılan:** Proje kökü dışındaki dosyaları okumasını reddeder. Sınır `CLAUDE_PROJECT_DIR` (Claude Code tarafından oturum başına bir kez ayarlanır) ile sınırlandırılır; bu değişken ayarlanmadığında oturum çalışma dizinine geri döner. Canlı `cwd` yerine proje kökü kullanmak, Claude `cd`'nin bir alt dizine gitmesi sonrasında bile sınırın sabit kalmasını sağlar. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `allowPaths` | `string[]` | `[]` | Proje kökü dışında olsa bile izin verilen mutlak yol önekleri. | +| `allowPaths` | `string[]` | `[]` | Proje kökü dışında olsa bile izin verilen mutlak yol ön ekleri. | **Örnek:** @@ -451,13 +451,13 @@ Ajentleri proje sınırları içinde ve hassas dosyalardan uzak tutun. ### `block-secrets-write` **Olay:** PreToolUse (Write, Edit) -**Varsayılan:** Özel anahtarlar ve sertifikalar için yaygın olarak kullanılan dosyalara yazılışı reddeder: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Varsayılan:** Özel anahtarlar ve sertifikalar için yaygın olarak kullanılan dosyalara yazımı reddeder: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `additionalPatterns` | `string[]` | `[]` | Engellenmesi gereken ek dosya adı desenleri (glob tarzı). | +| `additionalPatterns` | `string[]` | `[]` | Engellenecek ek dosya adı desenleri (glob stili). | **Örnek:** @@ -475,7 +475,7 @@ Ajentleri proje sınırları içinde ve hassas dosyalardan uzak tutun. ## Git -Geri alınması zor olan kazara itişleri, zorla-itişleri ve dal hatalarını önleyin. +Yanlışlıkla yapılan push'lar, force-push'lar ve geri almakta zor olan dal hatalarını önleyin. ### `block-push-master` @@ -486,7 +486,7 @@ Geri alınması zor olan kazara itişleri, zorla-itişleri ve dal hatalarını | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Doğrudan itilemeyen dal adları. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Doğrudan push yapılamayan dal adları. | **Örnek:** @@ -501,7 +501,7 @@ Geri alınması zor olan kazara itişleri, zorla-itişleri ve dal hatalarını ``` -Tüm dallara itişe izin vermek için (bu ilkeyi `enabledPolicies` öğesinden kaldırmadan etkili bir şekilde devre dışı bırakmak), `protectedBranches: []` ayarını yapın. +Tüm dallara push yapılmasına izin vermek için (bu ilkeyi `enabledPolicies` içinden kaldırmadan etkili şekilde devre dışı bırakmak), `protectedBranches: []` ayarlayın. --- @@ -509,7 +509,7 @@ Tüm dallara itişe izin vermek için (bu ilkeyi `enabledPolicies` öğesinden k ### `block-work-on-main` **Olay:** PreToolUse (Bash) -**Varsayılan:** Çalışma ağacı `main` veya `master` üzerindeyken `git commit`, `git merge`, `git rebase` ve `git cherry-pick` komutlarını reddeder. Dal oluşturma ve geçiş (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) etkilenmez. +**Varsayılan:** Çalışan ağaç `main` veya `master` üzerinde iken `git commit`, `git merge`, `git rebase` ve `git cherry-pick` komutlarını reddeder. Dal oluşturma ve değiştirme (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) etkilenmez. **Parametreler:** @@ -524,13 +524,13 @@ Tüm dallara itişe izin vermek için (bu ilkeyi `enabledPolicies` öğesinden k **Olay:** PreToolUse (Bash) **Varsayılan:** `git push --force` ve `git push -f` komutlarını reddeder. -İlke spesifik parametresi yok. Alternatifleri önermek için çapraz kesme [`hint`](/tr/configuration#hint-cross-cutting) kullanın: +İlkeye özgü parametre yok. Alternatif önerecek olan çapraz kesit [`hint`](/tr/configuration#hint-cross-cutting) kullanın: ```json { "policyParams": { "block-force-push": { - "hint": "Geçerli HEAD'inizden yeni bir dal oluşturun (örneğin `git checkout -b `) ve bunun yerine o dalı itin." + "hint": "Mevcut HEAD'den yeni bir dal oluşturun (örn. `git checkout -b `) ve bunun yerine bunu push edin." } } } @@ -541,66 +541,66 @@ Tüm dallara itişe izin vermek için (bu ilkeyi `enabledPolicies` öğesinden k ### `warn-git-amend` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `git commit --amend` çalıştırırken dikkatli ilerlemeye bilgilendirir. Komut engellenmez. +**Varsayılan:** Claude'u `git commit --amend` çalıştırırken dikkatli ilerlemeye talimat verir. Komutu engelleme. -Parametresi yok. +Parametre yok. --- ### `warn-git-stash-drop` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `git stash drop` çalıştırmadan önce onaylamaya bilgilendirir. Komut engellenmez. +**Varsayılan:** Claude'u `git stash drop` çalıştırmadan önce onaylamaya talimat verir. Komutu engelleme. -Parametresi yok. +Parametre yok. --- ### `warn-all-files-staged` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `git add -A` veya `git add .` çalıştırdığında sahneye koydukları şeyleri gözden geçirmeye bilgilendirir. Komut engellenmez. +**Varsayılan:** Claude'u `git add -A` veya `git add .` çalıştırdığında staging'e aldıklarını incelemeye talimat verir. Komutu engelleme. -Parametresi yok. +Parametre yok. --- ## Veritabanı -Yıkıcı SQL işlemlerini veritabanınıza yürütülmeden önce yakalayın. +Veritabanınıza karşı çalıştırılmadan önce yıkıcı SQL işlemlerini yakalayın. ### `warn-destructive-sql` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `DROP TABLE`, `DROP DATABASE` veya `WHERE` şartı olmayan `DELETE` içeren SQL çalıştırmadan önce onaylamaya bilgilendirir. +**Varsayılan:** Claude'u `DROP TABLE`, `DROP DATABASE` veya `WHERE` yan tümcesi olmayan `DELETE` içeren SQL'i çalıştırmadan önce onaylamaya talimat verir. -Parametresi yok. +Parametre yok. --- ### `warn-schema-alteration` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `ALTER TABLE` ifadeleri çalıştırmadan önce onaylamaya bilgilendirir. +**Varsayılan:** Claude'u `ALTER TABLE` ifadelerini çalıştırmadan önce onaylamaya talimat verir. -Parametresi yok. +Parametre yok. --- ## Uyarılar -Ajentlere potansiyel olarak riskli ancak yıkıcı olmayan işlemlerden önce ekstra bağlam sağlayın. +Ajanları potansiyel olarak riskli ancak yıkıcı olmayan işlemlerden önce ek bağlamla donatın. ### `warn-large-file-write` **Olay:** PreToolUse (Write) -**Varsayılan:** Claude'u 1024 KB'den büyük dosyaları yazmadan önce onaylamaya bilgilendirir. +**Varsayılan:** Claude'u 1024 KB'tan daha büyük dosyalar yazmadan önce onaylamaya talimat verir. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `thresholdKb` | `number` | `1024` | Uyarı verildiği dosya boyutu eşiği (kilobayt). | +| `thresholdKb` | `number` | `1024` | Uyarı verilen dosya boyutu eşiği (kilobayt cinsinden). | **Örnek:** @@ -615,7 +615,7 @@ Ajentlere potansiyel olarak riskli ancak yıkıcı olmayan işlemlerden önce ek ``` -Hook işleyicisi yükler üzerinde 1 MB stdin sınırı uygular. Bu ilkeyi küçük içerikle test etmek için `thresholdKb` değerini 1024'in altında bir değere ayarlayın. +Hook işleyicisi yüklemeler üzerinde 1 MB stdin sınırı uygular. Bu ilkeyi küçük içerikle test etmek için `thresholdKb` 1024'ün çok altında bir değere ayarlayın. --- @@ -623,47 +623,47 @@ Hook işleyicisi yükler üzerinde 1 MB stdin sınırı uygular. Bu ilkeyi küç ### `warn-package-publish` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `npm publish` çalıştırmadan önce onaylamaya bilgilendirir. +**Varsayılan:** Claude'u `npm publish` çalıştırmadan önce onaylamaya talimat verir. -Parametresi yok. +Parametre yok. --- ### `warn-background-process` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `nohup`, `&`, `disown` veya `screen` aracılığıyla arka plan işlemleri başlatırken dikkatli olmaya bilgilendirir. +**Varsayılan:** Claude'u `nohup`, `&`, `disown` veya `screen` aracılığıyla arka plan işlemleri başlatırken dikkatli olmaya talimat verir. -Parametresi yok. +Parametre yok. --- ### `warn-global-package-install` **Olay:** PreToolUse (Bash) -**Varsayılan:** Claude'u `npm install -g`, `yarn global add` veya sanal ortam olmadan `pip install` çalıştırmadan önce onaylamaya bilgilendirir. +**Varsayılan:** Claude'u `npm install -g`, `yarn global add` veya sanal ortam olmadan `pip install` çalıştırmadan önce onaylamaya talimat verir. -Parametresi yok. +Parametre yok. --- ## Paket yöneticileri -Ajanın hangi paket yöneticilerini kullanmasına izin verildiğini zorunlu kılın. +Ajanın kullanmasına izin verilen paket yöneticisini zorla. ### `prefer-package-manager` **Olay:** PreToolUse (Bash) -**Varsayılan:** Devre dışı. Etkinleştirildiğinde, `allowed` listesinde olmayan paket yöneticisi komutlarını engeller ve Claude'u komut yöneticisi kullanarak komutu yazmaya söyler. +**Varsayılan:** Devre dışı. Etkinleştirildiğinde, `allowed` listesinde olmayan herhangi bir paket yöneticisi komutunu engeller ve Claude'u komutu izin verilen bir yöneticiyi kullanarak yeniden yazmaya talimat verir. Algılar: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | Parametre | Tür | Varsayılan | Açıklama | |-----------|-----|-----------|---------| -| `allowed` | string[] | `[]` | İzin verilen paket yöneticisi adları. Bu listede olmayan herhangi bir algılanan yönetici engellenir. Boş olduğunda ilke işlemsiz kalır. | -| `blocked` | string[] | `[]` | Yerleşik listesinin ötesinde engellenmesi gereken ek yönetici adları (örneğin `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | İzin verilen paket yöneticisi adları. Bu listede olmayan algılanan herhangi bir yönetici engellenir. Boş olduğunda, ilke hiçbir işlem yapmaz. | +| `blocked` | string[] | `[]` | Yerleşik liste dışında englenecek ek yönetici adları (örn. `['pdm', 'pipx']`). | -Yerleşik engel listesi şunları kapsar: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Bu listede olmayan yöneticileri eklemek için `blocked` kullanın. +Yerleşik engelleme listesi şunları içerir: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Bu listede olmayan yöneticileri eklemek için `blocked` kullanın. **Örnek yapılandırma:** @@ -679,74 +679,73 @@ Yerleşik engel listesi şunları kapsar: pip, pip3, npm, npx, yarn, pnpm, pnpx, } ``` -Bu yapılandırma ile `pip install flask` ve `pdm install flask` her ikisi de reddedilir; Claude'a bunun yerine `uv` veya `bun` kullanması söylenir. `uv` beyaz listede olduğu ve önce kontrol edildiği için `uv pip install flask` gibi komutlar izin verilir. +Bu yapılandırmayla `pip install flask` ve `pdm install flask` her ikisi de reddedilir ve Claude'a `uv` veya `bun` kullanmasını söyleyen bir ileti görüntülenir. `uv pip install flask` gibi komutlar izin verilir çünkü `uv` izin listesinde ve ilk olarak kontrol edilir. --- ## AI davranışı -Ajanların sıkışıp kalması veya beklenmeyen davranması durumlarını algılayın. +Ajanlar takılıp kaldığında veya beklenmeyen davranış gösterdiğinde algılayın. ### `warn-repeated-tool-calls` **Olay:** PreToolUse (tüm araçlar) -**Varsayılan:** Aynı araç aynı parametrelerle 3+ kez çağrılırsa Claude'u yeniden düşünmeye bilgilendirir — ajanın bir döngüde sıkışmasının yaygın bir işaretidir. +**Varsayılan:** Aynı araç 3 veya daha fazla kez aynı parametrelerle çağrıldığında Claude'a yeniden düşünmeye talimat verir — bu yaygın olarak ajanın bir döngüye takılmış olduğunun işaretidir. -Parametresi yok. +Parametre yok. --- ## İş akışı -Disiplinli bir oturum sonu iş akışı uygulayın. Bu ilkeler **Stop** olayında devreye girer ve aynı ajan, her koşul karşılanana kadar durmaktan yoksun bırakılır. Doğal bir bağımlılık zinciri izlerler: commit → push → PR → CI. Bir ilke reddederse, zincirdeki sonraki ilkeler atlanır (reddetme kısa devre). +Disiplinli bir oturum sonu iş akışı zorla. Bu ilkeler **Stop** olayında tetiklenir ve her koşul karşılanıncaya kadar ajanın durmesini engeller. Doğal bir bağımlılık zincirini izlerler: commit → push → PR → CI. Bir ilke redderse, zincirdeki sonraki ilkeler atlanır (deny kısa devreler). -Tüm iş akışı ilkeleri **başarısız-açık** dur: gerekli araç kullanılamıyorsa (örneğin `gh` kurulu değil, git uzaktan yoktur), ilke bir bilgi iletisi ile izin verir; kontrol neden atlanmadığını açıklar. +Tüm iş akışı ilkeleri **fail-open** davranır: gerekli araç mevcut değilse (örn. `gh` yüklü değilse, git remote yoksa), ilke kontrolün neden atlandığını açıklayan bir bilgi mesajıyla izin verir. ### CLI başına Stop semantiği -Stop uygulaması yedi desteklenen CLI arasında biraz farklı görünür; çünkü her biri farklı bir "ajan bitişi" hook sözleşmesi ortaya koyar. **Sonuç** aynıdır — ajan bir iş akışı kapısı başarısız iken durmaktan kurtulmaz — ancak **mekanikler** farklıdır. Aşağıdaki tablo özetler; bir `require-*-before-stop` ilkesini etkinleştirmeden önce anlamanın değerine sahip Pi'de yalnızca kullanıcı tarafından görülebilir bir garip durum vardır. +Stop zorlaması, her biri farklı bir ajan bitişi hook sözleşmesi açığa çıkardığından altı desteklenen CLI arasında biraz farklı görünür. **Sonuç** aynıdır — ajan iş akışı kapısı başarısız olsa bile durmasından kurtulamamıştır — ancak **mekanizm** farklıdır. Aşağıdaki tablo özetler; bir `require-*-before-stop` ilkesini etkinleştirmeden önce anlamaya değer yalnızca Pi'nin kullanıcı tarafında görülen tuhaflığı vardır. -| CLI | Kapı ne zaman devreye girer | Ne görürsünüz | +| CLI | Kapının tetiklendiği zaman | Göreceğiniz şey | |---|---|---| -| Claude Code | Aynı ajan döngüsü, hemen | Claude çalışmaya devam eder — sorunu düzeltir, sonra tekrar bitirmeye çalışır. Size görünen kesinti yok. | -| Codex | Aynı ajan döngüsü, hemen | Claude ile aynı. | -| GitHub Copilot CLI | Aynı ajan döngüsü, hemen | Claude ile aynı (Copilot'un `{decision:"block", reason}` yeniden deneme kanalını kullanır — ampirik olarak Copilot CLI 1.0.41'e karşı doğrulanmıştır). | -| Cursor Agent | Aynı ajan döngüsü, hemen | Claude ile aynı (Cursor'un `{followup_message}` kanalını kullanır — `loop_limit`, varsayılan 5 yeniden denemeler ile sınırlandırılmış). | -| Gemini CLI | Aynı ajan döngüsü, hemen | Claude ile aynı (Gemini'nin `{decision:"block", reason}` kanalını kullanır; `AfterAgent` üzerinde). | -| OpenCode | Aynı ajan döngüsü, hemen | Claude ile aynı (OpenCode'un `client.session.prompt(...)` SDK çağrısını kullanır; `hookSpecificOutput.additionalContext` aracılığıyla yönlendirilmiş). | -| **Pi (pi-coding-agent)** | **Sonraki kullanıcı sırası** | **Kapı devreye girdiğinde Pi görünen şekilde durur** — ajan döngüsü çıkar ve komut isteminin başına dönersiniz. Kapı daha sonra bir sonraki iletişim gönderdiğinizde devreye girer: failproofai iş akışı adımını tamamlamadan önce (commit, push vb.) bir `MANDATORY ACTION REQUIRED` yönergesini o sıraya ait sistem komutunun başına ekler; ne istedinizi yapmadan önce. +| Claude Code | Aynı ajan döngüsü, anında | Claude çalışmaya devam eder — sorunu düzeltir, sonra bitmeyi tekrar dener. Size görünür hiçbir kesinti. | +| Codex | Aynı ajan döngüsü, anında | Claude ile aynı. | +| GitHub Copilot CLI | Aynı ajan döngüsü, anında | Claude ile aynı (Copilot'un `{decision:"block", reason}` yeniden deneme kanalını kullanır — Copilot CLI 1.0.41'e karşı deneysel olarak doğrulanmış). | +| Cursor Agent | Aynı ajan döngüsü, anında | Claude ile aynı (Cursor'un `{followup_message}` kanalını kullanır — `loop_limit` ile sınırlı, varsayılan 5 yeniden deneme). | +| OpenCode | Aynı ajan döngüsü, anında | Claude ile aynı (OpenCode'un `client.session.prompt(...)` SDK çağrısını `hookSpecificOutput.additionalContext` aracılığıyla yönlendirir). | +| **Pi (pi-coding-agent)** | **Sonraki kullanıcı turu** | **Pi görünür şekilde durur** — kapı tetiklendiğinde ajan döngüsü çıkar ve siz isteme dönersiniz. Kapı sonraki sefer bir istemi gönderdiğinizde tetiklenir: failproofai iş akışı adımını (commit, push vb.) tamamlamasını talimat veren bir `MANDATORY ACTION REQUIRED` direktifi o turun sistem istemiyle başına ekler. | -**Pi sınırlaması.** Pi'nin `AgentEndEvent` (Claude'un `Stop` hook'unun yukarı akış eşdeğeri) hiçbir Result türü yoktur — Pi'nin ajan döngüsü zaten çıkmış olduğu süredir. Pi, Claude / Copilot / Cursor / Gemini / OpenCode'un yapabildiği şekilde aynı döngüyü yeniden denemeye zorlanamazı. failproofai kapıyı Pi'nin `before_agent_start` olayına kaydırır (sonraki kullanıcı iletişim sonrasında devreye girer) — iş akışı kontrolü hala uygulanır, yalnızca mevcut sıra yerine sonraki sıra üzerinde. +**Pi sınırlaması.** Pi'nin `AgentEndEvent` (Claude'un `Stop` hook'una eşdeğeri), Result türüne sahip değildir — tetiklendikten sonra Pi'nin ajan döngüsü zaten çıkmıştır. Pi, Claude / Copilot / Cursor / OpenCode'in yaptığı şekilde aynı döngüyü yeniden denemek için zorlananamaz. failproofai, kapıyı Pi'nin `before_agent_start` olayına kaydırır (sonraki kullanıcı istemiyle tetiklenir) ve böylece iş akışı denetimi hala uygulanır, sadece mevcut sırada değil sonraki turda. -**Bunu pratikte ne anlama gelir:** +**Pratikte bu ne anlama gelir:** -- Pi durundan sonra, reddetme nedeni oturum kimliği tarafından bellek içinde anahtarlanmış şekilde yakalanır. Aynı Pi işlemi içinde gönderdiğiniz çok sonraki istişare bunu boşaltır: LLM sistem komutunun üstünde `MANDATORY ACTION REQUIRED` yönergesini görür, commits (veya pushes / açıklık PR / CI'yi bekler) ve ancak o zaman istediğiniz şeye devam eder. Yakalanan reddetme nedeni tek atış — bir kez boşaltıldıktan sonra kapı açıktır. -- Kapı Pi'nin işlem ömrü tarafından sınırlandırılır. Turlar arasında Pi'yi `Ctrl+C` yaparsanız veya çıkarsanız, bellek içi giriş işlemle birlikte bırakılır ve kapı kaçırılır. Claude, Copilot, Cursor, Gemini ve OpenCode'un aynı sınırı vardır (ajanı öldürün ve kapı kaçırılır) — Pi sadece bunu daha görünür hale getirir; çünkü ajan kapı devreye girmeden önce görünen şekilde çıkar. -- Beklemede olan bir reddetme herhangi bir nedenle `session_shutdown` üzerine de temizlenir (`new` / `resume` / `fork` / `quit`), bu nedenle önceki oturumdan eski bir kapı, aynı Pi işlemi içinde başlatılan yeni bir oturuma sızamaz. +- Pi durduğu sonra, deny nedeni Pi oturum kimliğiyle bellekte saklanır. Aynı Pi işleminde sunduğunuz çok sonraki istemi boşaltır: LLM sistem istemiyle `MANDATORY ACTION REQUIRED` direktifi görür, commit eder (veya push'lar / PR açar / CI'nin bekler) ve yalnızca o zaman isteminizle devam eder. Saklanan deny nedeni tek atışlıdır — boşaltıldıktan sonra kapı açıktır. +- Kapı Pi'nin işlem ömrü tarafından sınırlandırılır. Pi'yi `Ctrl+C` yaparsanız veya turlar arasında çıkarsanız, bellekte tutulan giriş işlemle birlikte atılır ve kapı kaçırılır. Claude, Copilot, Cursor ve OpenCode'un aynı sınırı vardır (ajanı öldürün ve kapı kaçırılır) — Pi bunu yalnızca daha görünür kılar çünkü ajan kapı tetiklenmeden önce görünür şekilde çıkar. +- Beklemede bir deny, `session_shutdown` sırasında herhangi bir nedenden dolayı temizlenir (`new` / `resume` / `fork` / `quit`), bu nedenle önceki oturumdan eski bir kapı aynı Pi işleminde başlatılan yeni bir oturuma sızamaz. -Claude tarzı aynı döngü yeniden denemesine ihtiyacınız varsa, `Stop` ilkelerinizi desteklenen diğer altı CLI'den birinin altında çalıştırın. Pi yukarı akışını gelecek bir Result türü ile izliyoruz; `AgentEndEvent` üzerinde bu boşluğu kapatmamıza izin verecektir. +Claude stili aynı döngü yeniden denemesine ihtiyacınız varsa, Stop ilkelerinizi desteklenen diğer beş CLI'den herhangi birinin altında çalıştırın. Pi upstream'de, bize bu boşluğu kapamaya izin verecek `AgentEndEvent` üzerinde bir Result türü için izliyoruz. ### `require-commit-before-stop` **Olay:** Stop -**Varsayılan:** Commit edilmemiş değişiklikler (değiştirilmiş, sahnelenmiş veya izlenmeyen dosyalar) olduğunda durmasını reddeder. Çalışma dizini temiz olduğunda bilgi iletisi döndürür. +**Varsayılan:** Taahhüt edilmemiş değişikliklerin olduğu durumlarda durmasını reddeder (değiştirilmiş, aşamalı veya izlenmemiş dosyalar). Çalışan dizini temiz olduğunda bilgi mesajı döndürür. -Parametresi yok. +Parametre yok. --- ### `require-push-before-stop` **Olay:** Stop -**Varsayılan:** Push edilmemiş commits olduğunda veya mevcut dal uzaktan izleme dalı olmadığında durmasını reddeder. Gerekirse izleme dalı oluşturmak için `git push -u` önerir. Yapılandırılmış uzaktan yoksa başarısız-açık. +**Varsayılan:** Push edilmemiş commit'lerin olduğu veya mevcut dal uzak izleme dalı olmadığında durmasını reddeder. Gerekirse bir izleme dalı oluşturmak için `git push -u` önerir. Uzak yapılandırılmadığında fail-open. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `remote` | `string` | `"origin"` | İtiş yapılacak uzaktan adı. | +| `remote` | `string` | `"origin"` | Push yapılacak uzak ad. | **Örnek:** @@ -765,13 +764,13 @@ Parametresi yok. ### `require-pr-before-stop` **Olay:** Stop -**Varsayılan:** Geçerli dal için çekme isteği yoksa veya mevcut PR birleştirilmeden kapatılmışsa durmasını reddeder. Claude'u `gh pr create` ile bir PR oluşturmaya bilgilendirir. PR **birleştirildiğinde**, ilke izin verir (çalışma gönderildi) ve ileti daldan geçmeye ipuç verir (`git checkout main && git pull`). +**Varsayılan:** Mevcut dal için pull request olmadığında veya mevcut PR birleştirilmeden kapatıldığında durmasını reddeder. Claude'a `gh pr create` ile PR oluşturmaya talimat verir. PR **birleştirildiğinde**, ilke izin verir (iş gönderilmiş) ve ileti dal kapatılmasını önerir (`git checkout main && git pull`). -Parametresi yok. +Parametre yok. -Bu ilke [GitHub CLI](https://cli.github.com/) (`gh`) kurulu ve doğrulanmış olmasını gerektirir. -Çekme isteklerine okuma erişimi için `repo` kapsamına sahip kişisel erişim belirteci ile `gh auth login` çalıştırın. `gh` kurulu değilse veya doğrulanmamışsa, ilke başarısız-açık ve nedeni Claude'a raporlar. +Bu ilke [GitHub CLI](https://cli.github.com/) (`gh`) yüklü ve kimliğinin doğrulanmış olması gerektirir. +`gh auth login` komutunu pull request'lere okuma erişimi için `repo` kapsamına sahip bir kişisel erişim belirteci ile çalıştırın. `gh` yüklü değilse veya kimliğinin doğrulanmamış ise, ilke fail-open olur ve nedenini Claude'a bildirir. --- @@ -779,21 +778,21 @@ Bu ilke [GitHub CLI](https://cli.github.com/) (`gh`) kurulu ve doğrulanmış ol ### `require-no-conflicts-before-stop` **Olay:** Stop -**Varsayılan:** Geçerli dal temel dala temiz şekilde birleştirilemezse durmasını reddeder. İlke önce dal için GitHub'da `OPEN` bir PR'ın olduğunu onaylar — biri olmadan, birleştirme hedefi yoktur; bu nedenle tüm ilke kısa devre ve izin verir. `OPEN` PR onaylandıktan sonra iki bağımsız sonda çalışır: +**Varsayılan:** Mevcut dal temiz bir şekilde temel dala birleştirilenemediğinde durmasını reddeder. İlke önce dal için GitHub'da `OPEN` PR var olduğunu doğrular — yoksa, birleştirme hedefi olmadığından, tüm ilke short-circuit'ler izin verir. Bir `OPEN` PR onaylandıktan sonra, iki bağımsız araştırma çalışır: -1. **Yerel** — `git merge-tree --write-tree --name-only origin/ HEAD`. Çatışmada, reddetme iletişi çatışmalı dosyaları adlandırır; böylece Claude tam olarak ne çözeceğini bilir. -2. **GitHub** — zaten ön kontrol içinde alınan `gh pr view --json mergeable,state` sonucunu yeniden kullanır. Eski yerel `origin/` kaçıracağı çatışmaları yakalar (örneğin, birisi son getirmeden bu yana `main` üzerinde çatışan bir PR indirdi). `CONFLICTING` sonuç reddeder. `UNKNOWN` sonuç da reddeder ve Claude'u tekrar kontrol etmeden ~10 saniye beklemesini bilgilendirir — durmaya tekrar denemeden önce bu yanlış negatifleri önler. +1. **Yerel** — `git merge-tree --write-tree --name-only origin/ HEAD`. Çakışma durumunda, deny mesajı çakışan dosyaları adlandırır; böylece Claude tam olarak ne çözeceğini bilir. +2. **GitHub** — önceden alınan `gh pr view --json mergeable,state` sonucunu yeniden kullanır. Eski yerel `origin/` kaçıracak çakışmaları yakalar (örn. son fetch'ten sonra `main` ile çakışan bir PR inişi). `CONFLICTING` sonucu reddeder. `UNKNOWN` sonuç da reddeder ve Claude'u ~10 saniye bekleyip yeniden kontrol etmeden önce durmasını denemeden önce talimat verir — bu sahte negatifleri önler; GitHub yeniden hesaplarken. -Şu durumlarda tamamen atlanır (izin verir): `gh` kurulu değil, dal için PR yoktur, PR'ın durumu `OPEN` değildir (örneğin `MERGED`, `CLOSED`) veya `gh pr view` ayrıştırılamayan çıktı döndürür. Ayrıca `origin/` yerel olarak eksik olduğunda veya hiçbir komit tabanın ilerisinde olmadığında da başarısız-açık — bu Katman 1 açılışları yine de izin vermeden önce önbelleğe alınan PR birleştirilebilirliğini danışır. +Atlanır ve şu durumlarda izin verir: `gh` yüklü değilse, dal için PR yoksa, PR'nin durumu `OPEN` değilse (örn. `MERGED`, `CLOSED`) veya `gh pr view` ayrıştırılamaz çıktı döndürse. Ayrıca yerel `origin/` eksikse veya taban'ın önü hiç commit olmadığında fail-open olur — bu Katman 1 fall-through'ları izin vermeden önce hala cache edilen PR birleştirilebilirliğini danışır. **Parametreler:** | Param | Tür | Varsayılan | Açıklama | |-------|-----|-----------|---------| -| `baseBranch` | `string` | `"main"` | Çatışmalar için kontrol edilmesi gereken temel dal. | +| `baseBranch` | `string` | `"main"` | Çakışmaları kontrol edilecek temel dal. | -Bu ilke için GitHub CLI (`gh`) gereklidir. İlke bir `OPEN` PR'ın var olduğunu doğrulamak için `gh pr view` kullanır — `gh` olmadan, ilke kısa devre ve izin verir. Çekme isteklerine okuma erişimi için `repo` kapsamına sahip kişisel erişim belirteci ile `gh auth login` çalıştırın. +Bu ilke GitHub CLI (`gh`) gerektirir. İlke bir `OPEN` PR var olduğunu doğrulamak için `gh pr view` kullanır — `gh` olmadan ilke allow'a kısa devreler. Bir kişisel erişim belirteci ile `gh auth login` çalıştırın ve pull request'lere okuma erişimi için `repo` kapsamı kullanın. --- @@ -801,13 +800,13 @@ Bu ilke için GitHub CLI (`gh`) gereklidir. İlke bir `OPEN` PR'ın var olduğun ### `require-ci-green-before-stop` **Olay:** Stop -**Varsayılan:** Geçerli daldaki CI kontrolleri başarısız veya hala çalışıyor olduğunda durmasını reddeder. GitHub Actions iş akışı çalıştırmalarını ve üçüncü taraf bot kontrollerini kontrol eder (örneğin CodeRabbit, SonarCloud, Codecov). `skipped`, `cancelled` ve `neutral` sonuçlarını başarısız olmayan olarak işler (sonuncusu örneğin dış katkıda bulunan PR'larında Socket Security uyarılarını kapsar; uygulama kasıtlı olarak başarı/başarısız yerine neutral raporlar). Tüm kontroller geçtiğinde bilgi iletişi döndürür. +**Varsayılan:** Mevcut dal üzerinde CI kontrolleri başarısız veya halen çalışıyor olduğunda durmasını reddeder. Hem GitHub Actions iş akışı çalıştırmaları hem de üçüncü taraf bot kontrolleri (örn. CodeRabbit, SonarCloud, Codecov) kontrol eder. `skipped`, `cancelled` ve `neutral` sonuçlarını başarısız olmayan olarak kabul eder (ikincisi, dış katkıda bulunan PR'lerinde Socket Security uyarıları için hesaba katılır; burada uygulama başarı/başarısızlık yerine kasıtlı olarak neutral raporlar). Tüm kontroller geçtiğinde bilgi mesajı döndürür. -Parametresi yok. +Parametre yok. -Bu ilke için [GitHub CLI](https://cli.github.com/) (`gh`) kurulu ve doğrulanmış olması gerekir. -Actions iş akışı çalıştırmalarına ve Kontroller API'sine okuma erişimi için `repo` kapsamına sahip kişisel erişim belirteci ile `gh auth login` çalıştırın. `gh` kurulu değilse veya doğrulanmamışsa, ilke başarısız-açık ve nedeni Claude'a raporlar. +Bu ilke [GitHub CLI](https://cli.github.com/) (`gh`) yüklü ve kimliğinin doğrulanmış olması gerektirir. +`gh auth login` komutunu Actions iş akışı çalıştırmaları ve Checks API'ye okuma erişimi için `repo` kapsamı ile çalıştırın. `gh` yüklü değilse veya kimliğinin doğrulanmamış ise, ilke fail-open olur ve nedenini Claude'a bildirir. --- @@ -816,7 +815,7 @@ Actions iş akışı çalıştırmalarına ve Kontroller API'sine okuma erişimi ## Bireysel ilkeleri devre dışı bırakma -Yapılandırmanızda `enabledPolicies` öğesinden belirli bir ilkeyi kaldırın veya panonun Politikalar sekmesinde kapatın. +Yapılandırmanızdaki `enabledPolicies` içinden belirli bir ilkeyi kaldırın veya panondaki İlkeler sekmesinde bunu kapatın. ```json { @@ -827,4 +826,4 @@ Yapılandırmanızda `enabledPolicies` öğesinden belirli bir ilkeyi kaldırın } ``` -`enabledPolicies` içinde listelenmemiş ilkeler, `policyParams` girdileri var olsa bile çalışmaz. \ No newline at end of file +`enabledPolicies` içinde listelenmemiş ilkeler, `policyParams` girişleri var olsa bile çalışmaz. \ No newline at end of file diff --git a/docs/tr/cli/audit.mdx b/docs/tr/cli/audit.mdx index 3615d41a..81930388 100644 --- a/docs/tr/cli/audit.mdx +++ b/docs/tr/cli/audit.mdx @@ -1,19 +1,19 @@ --- title: Geçmiş oturumları denetle (beta) -description: "Ajanın geçmiş transkriptlerde ne sıklıkla israf veya riskli şeyler yaptığını say" +description: "Aracının geçmiş transkriptler üzerinde ne sıklıkla boşa harcama veya riskli şeyler yaptığını say" --- **Beta özelliği.** Denetim, erken geri bildirim toplarken beta olarak sunulmaktadır. - Dedektör kataloğu ve rapor formatı, bir sonraki kararlı sürümden önce değişebilir. - Herhangi bir şey yanlış görünürse lütfen bir sorun açınız. + Dedektör kataloğu ve rapor formatı bir sonraki kararlı sürümden önce değişebilir. + Herhangi bir şey yanlış görünürse lütfen bir issue açınız. -Denetim, geçmiş ajan-CLI transkriptlerinizi failproofai'nin politika motoru üzerinden yeniden oynatır ve **`/audit` kontrol paneli sayfasında** paylaşılabilir, görsel bir rapor oluşturur — ajanınızın arketipi, 0–100 puanı ve tam olarak hangi politikaların neleri yakalayacağını gösterir. +Denetim, geçmiş aracı-CLI transkriptlerinizi failproofai'nin politika motorunda yeniden oynatır ve **`/audit` kontrol paneli sayfasında** paylaşılabilir, görsel bir rapor oluşturur — aracınızın arketipi, 0–100 puanı ve tam olarak hangi politikaların ne'yi yakalayacağı. ## Çalıştırın -Üç giriş yolu — tümü aynı `/audit` raporuna ulaşır. +Üç giriş yolu — hepsi aynı `/audit` raporuna ulaşır. @@ -33,56 +33,56 @@ failproofai - `npx -y failproofai audit` failproofai'yi getirir, taramayı çalıştırır ve kontrol panelini açar — önce herhangi bir şey kurmanıza gerek yok. + `npx -y failproofai audit`, failproofai'yi alır, taramayı çalıştırır ve kontrol panelini sizin için açar — öncesinde kurulması gereken hiçbir şey yoktur. - - `failproofai audit` taramayı terminalinizde çalıştırır, ardından bittikten sonra otomatik olarak `localhost:8020/audit` sayfasını açar. + + `failproofai audit`, taramayı terminalinizde çalıştırır, ardından bittiğinde otomatik olarak `localhost:8020/audit` açar. - `failproofai` komutunu çalıştırın ve gezinti çubuğunda (Politikalar ve Projeler arasında) **Audit** seçeneğine tıklayın veya doğrudan `/audit` sayfasını açın. + `failproofai` komutunu çalıştırın ve navbar'da **Audit** düğmesine tıklayın (Policies ve Projects arasında), ya da doğrudan `/audit` adresini açın. - Kullanımı görmek için `failproofai audit -h` (veya `--help`) komutunu çalıştırın. Denetim **tamamen çevrimdışı** çalışır — hesap veya ağ gerekmez — ve kontrol paneli `Ctrl+C` ile durdurana kadar sunulmaya devam eder. + Kullanım bilgisini görmek için `failproofai audit -h` (veya `--help`) çalıştırın. Denetim **tamamen çevrimdışı** çalışır — hesap veya ağ gerekmez — ve kontrol paneli `Ctrl+C` ile durdurana kadar sunulmaya devam eder. -Kontrol paneli bu makinedeki geçmiş ajan CLI transkriptlerini tarar (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) ve ajanın failproofai'nin durdurmak için tasarlandığı şeyleri ne sıklıkla yaptığını bildirir — ortam değişkeni kontrolleri, zorla göndermeler, gereksiz `cd ` önekleri, uyku-yoklama döngüleri, yeni düzenlenen dosyaları yeniden okuma ve daha fazlası. +Kontrol paneli bu makinedeki geçmiş aracı CLI transkriptlerini tarar (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) ve aracının failproofai'nin durdurmak için yapılandırıldığı şeyleri ne sıklıkla yaptığını bildirir — çevre değişkeni kontrolleri, force push'lar, gereksiz `cd ` önekleri, sleep-polling döngüleri, yeni düzenlenmiş dosyaları yeniden okuma ve daha fazlası. -Her transkript için, her araç-kullanım olayı 39 yerleşik politika **ve** henüz çalışma zamanı politikaları tarafından kapsanmayan desenleri yakalayan 8 denetim-yalnızca dedektörü aracılığıyla yeniden oynatılır. Sayılar tüm oturumlar arasında politika / dedektör başına toplanır. +Her transkript için, her araç-kullanım etkinliği 39 yerleşik politika **ve** henüz çalışma zamanı politikaları tarafından kapsanmayan desenleri yakalayan 8 yalnızca-denetim dedektörü aracılığıyla yeniden oynatılır. Sayılar tüm oturumlar arasında politika / dedektör başına toplanır. -## Neleri elde edersiniz +## Ne elde edersiniz -`/audit` sayfası, tek ekranlı, paylaşılabilir bir **poster** ve ardından aşağıya katlanmış dört bölümden oluşur: +`/audit` sayfası, tek ekranlı, paylaşılabilir bir **poster** ve ardından dört altın-kat bölümdür: -1. **Poster** — ajanınızın kimliğini bir bakışta: **arketipi** (8'den biri — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), kişi anahtar kelimeleri, o arketipin ne kadar nadir olduğu ve **0–100 puanı** bir kademe bandı (`S`'den `bottom tier`'a kadar). Paylaşılmak için tasarlanmış — X veya LinkedIn'e gönderin veya PNG olarak indirin. -2. **`// strengths`** — ajanınızın zaten iyi yaptıkları, taramadan gerçek sayılar olarak (örn. temiz araç çağrısı %, `0` ana şubaya itme denemesi), yalnızca ilgili politikanın temiz bir kaydı olduğu yerlerde gösterilir. -3. **`// quirks`** — sızan şeyler: failproofai'nin yakalayacağı davranışların sıralı tablosu — *son ne zaman* olduğu, *ne sızdı* (ve onu engelleyecek yerleşik), *ciddiyet* düzeyi ve *ne sıklıkla* görüldüğü (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — önerilen düzeltme listesi: her politika için bir satır, kopyala-yapıştır `failproofai policy add ` ile birlikte, artı tüm önerileri aynı anda etkinleştirip **tahmini puanı** gösteren bir **tümünü yükle** düğmesi. -5. **`// come back better`** — alışkanlığı oluşturun: yeniden denetim e-posta **hatırlatıcısı** ayarlayın (`3d` / `7d` / `14d` / `30d`) veya şimdi yeniden denetim yapın ve kendi denetimini çalıştırması için **bir arkadaşını davet edin** (failproof.ai'den gönderilir, size kcc yapılır). Hatırlatıcılar ve davetler oturum açma gerektirir — [`failproofai auth`](/tr/cli/auth) bölümüne bakınız. +1. **Poster** — aracınızın kimliği bir bakışta: **arketipi** (8'den biri — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), kişi anahtar kelimeleri, o arketipin ne kadar nadir olduğu ve bir tier bandı (`S` ile `bottom tier` arasında) içeren **0–100 puanı**. Paylaşım için tasarlandı — X veya LinkedIn'e gönderin ya da PNG olarak indirin. +2. **`// strengths`** — aracınızın zaten iyi yaptığı şeyler, taramadan gerçek sayılar olarak (örn. clean-tool-call %, `0` push-to-main denemeleri), yalnızca ilgili politika temiz bir rekora sahip olduğu yerlerde gösterilir. +3. **`// quirks`** — açığa çıkan şeyler: failproofai'nin yakalayacağı davranışların sıralanmış bir tablosu — *son ne zaman* olduğu, *ne açığa çıktığı* (ve bunu bloklamış olacak yerleşik), *şiddeti* ve ne sıklıkta *görüldüğü* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — önerilen düzeltme listesi: politika başına bir satır, kopya-yapıştır `failproofai policy add ` ile, artı **tümünü yükle** düğmesi, her tavsiyeyi bir kerede etkinleştiren ve bunu yapsanız **öngörülen puanınızı** gösteren. +5. **`// come back better`** — alışkanlık oluşturun: yeniden-denetim e-posta **hatırlatıcısını** ayarlayın (`3d` / `7d` / `14d` / `30d`) ya da şimdi yeniden-denetleyin ve bir arkadaşını kendi denetimini çalıştırmaya **davet edin** (failproof.ai'den gönderilen, size Cc'd). Hatırlatıcılar ve davetler oturum açma gerektirir — bkz. [`failproofai auth`](/tr/cli/auth). -## Denetim-yalnızca dedektörler +## Yalnızca-denetim dedektörleri -Bunlar gerçek zamanlı olarak (henüz) uygulanmayan "aptal davranış" desenleri algılarlar. Yalnızca denetim sırasında çalışırlar ve canlı bir araç çağrısını hiçbir zaman bloklamaz. +Bunlar gerçek zamanlı olarak (henüz) uygulanmayan "aptalca davranış" desenleri algılar. Yalnızca denetim sırasında çalışırlar ve hiçbir zaman canlı bir araç çağrısını bloklamaz. -| Dedektör | Ne saydığı | +| Dedektör | Ne sayar | |---|---| -| `redundant-cd-cwd` | `cd && …` ile başlayan Bash komutları, komutlar zaten `cwd`'de çalışmakta iken. | -| `prefer-edit-over-read-cat` | Tek bir kaynak dosyada `cat`/`head`/`tail`/`less`/`more` — `Read` aracını kullanın. | +| `redundant-cd-cwd` | `cd && …` ile başlayan Bash komutları, oysa komutlar zaten `cwd` içinde çalışır. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` tek bir kaynak dosyasında — `Read` aracını kullanın. | | `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` yerinde düzenlemeler — `Edit` aracını kullanın. | -| `prefer-write-over-heredoc` | Heredoc / çok satırlı `echo > file` dosya yazmaları — `Write` aracını kullanın. | -| `sleep-polling-loop` | Uzun `sleep N` (≥ 30s) veya `while …; sleep …; done` yoklama döngüleri. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, vb. — bunun yerine `cwd` kapsamında yapın. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, kancaları atlama. | -| `reread-after-edit` | Aynı oturumda yeni düzenlenen veya yazılan bir dosyanın `Read` işlemi. | +| `prefer-write-over-heredoc` | Heredoc / çok satırlı `echo > file` dosya yazma — `Write` aracını kullanın. | +| `sleep-polling-loop` | Uzun `sleep N` (≥ 30s) veya `while …; sleep …; done` polling döngüleri. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, vb. — bunun yerine `cwd` kapsamını alın. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, hook'ları atlayarak. | +| `reread-after-edit` | Aynı oturumda yeni `Edit`/`Write` yapılmış bir dosyanın `Read`'i. | ## Önbellekler -- **Transkript başına önbellek** `~/.failproofai/cache/audit/.json` dosyasında `(mtime, size, engineVersion, detectorVersion)` anahtarı ile — transkript veya politika/dedektör kodu değiştiğinde otomatik olarak geçersiz kılınır. Her giriş ayrıca **TTL meta verisi** olarak bir `cachedAt` zaman damgası depolar (önbellek anahtarının bir parçası değil); **7 günden** eski olan girişler okunurken reddedilir, böylece uzun ömürlü sonuçlar değişen dedektör niyetinden daha uzun ömürlü olmaz. -- **Tam sonuç önbelleği** `~/.failproofai/audit-dashboard.json` dosyasında (mod 0600). Kontrol panelinin yeniden çalıştırmadan gezintide anında işlenmesini sağlar. **7 günlük TTL**'den sonra da okunurken reddedilir — `/audit` boş durumuna düşer ve yeni bir çalışma istenir. Raporu sonuna yakın yeniden denetlemek için `[ re-audit now ]` öğesine tıklayın — yeniden denetim `noCache: true` gönderir, böylece transkript başına önbelleği atlar ve önbelleğe alınan sonucu döndürmek yerine her transkripti yeniden tarar; çalışma ilerlemeyi yapışkan bir üst şerit aracılığıyla akışa sokar ve başarılı durumda sonucu yerinde değiştirir (sayfa yeniden yüklenmesi yok; başarısız yeniden denetim önceki raporu tutar). +- **Transkript başına önbellek** `~/.failproofai/cache/audit/.json` konumunda, `(mtime, size, engineVersion, detectorVersion)` ile anahtarlanmış — transkript veya politika/dedektör kodu değiştiğinde otomatik olarak geçersiz kılınır. Her giriş ayrıca **TTL metaveri** olarak bir `cachedAt` zaman damgası saklar (önbellek anahtarının parçası değildir); **7 günden** eski girdiler, uzun ömürlü sonuçlar gelişen dedektör niyetini aşmayacak şekilde okunurken reddedilir. +- **Bütün sonuç önbelleği** `~/.failproofai/audit-dashboard.json` konumunda (mode 0600). Kontrol panelinin yeniden çalıştırmadan gezinti üzerinde anında oluşturulmasını sağlar. Ayrıca **7 günlük TTL** geçtikten sonra okunurken reddedilir — `/audit` daha sonra boş durumuna döner ve taze bir çalıştırma ister. Rapordaki alt kısmında bulunan `[ re-audit now ]` düğmesine tıklayarak yenilemek için — yeniden-denetim `noCache: true` gönderir, bu nedenle transkript başına önbelleği atlar ve her transkripti önbelleğe alınan sonucu döndürmek yerine yeniden tarar; çalıştırma yapışkan üst şerit aracılığıyla ilerlemeyi akıtır ve başarıda sonucu yerinde değiştirir (sayfa yeniden yüklenmesi yok; başarısız yeniden-denetim önceki raporu tutar). ## Notlar -- **Mutasyon yok.** Denetim salt okunur modda yeniden oynatılır. `warn-repeated-tool-calls`, oturum başına yan taraf arabası aksi halde değiştirileceği için atlanır. -- **İş akışı politikaları atlanır.** `require-*-before-stop` politikaları yalnızca `Stop` olaylarında ve canlı git durumuna karşı `execSync`'te devreye girer — "2025'te ne olurdu" yorumunun anlamı yoktur, bu nedenle denetim sayılarında görünmezler. -- **Özel politikalar atlanır.** Kullanıcı tarafından sağlanan özel kancalar yeniden oynatılmaz (bunlar orijinal oturumdan bu yana değişmiş olabilir). \ No newline at end of file +- **Mutasyon yok.** Denetim salt-okunur modda yeniden oynatılır. `warn-repeated-tool-calls`, oturum başına yan araca aksi takdirde değiştirilecek olduğundan atlanır. +- **İş akışı politikaları atlanır.** `require-*-before-stop` politikaları yalnızca `Stop` etkinlikleri ve canlı git durumuna karşı `execSync`'de ateşlenir — "2025'te ne olmuş olurdu" için anlamlı bir yorumu yoktur, bu nedenle denetim sayılarında görünmezler. +- **Özel politikalar atlanır.** Kullanıcı tarafından sağlanan özel hook'lar yeniden oynatılmaz (orijinal oturumdan itibaren değişmiş olabilirler). \ No newline at end of file diff --git a/docs/tr/configuration.mdx b/docs/tr/configuration.mdx index 245b7f07..c34c623e 100644 --- a/docs/tr/configuration.mdx +++ b/docs/tr/configuration.mdx @@ -1,52 +1,52 @@ --- title: Yapılandırma -description: "Yapılandırma dosyası formatı, üç kapsamlı sistem ve birleştirme kuralları" +description: "Yapılandırma dosyası biçimi, üç kapsam sistemi ve birleştirme kuralları" icon: gear --- -failproofai, hangi politikaların aktif olduğunu, nasıl davrandıklarını ve özel politikaların nereden yüklendiğini kontrol etmek için JSON yapılandırma dosyalarını kullanır. Yapılandırma, ekibinizle paylaşmak için tasarlanmıştır - bunu repo'nuza kaydedin ve her geliştirici aynı ajan güvenlik ağını alır. +failproofai, hangi politikaların etkin olduğunu, nasıl davrandıklarını ve özel politikaların nereye yüklendiğini kontrol etmek için JSON yapılandırma dosyalarını kullanır. Yapılandırma, takımınızla paylaşılması için tasarlanmıştır - bunu deponuza gönderin ve her geliştirici aynı ajan güvenlik ağını alır. --- ## Yapılandırma kapsamları -Üç yapılandırma kapsamı vardır ve öncelik sırasına göre değerlendirilir: +Üç yapılandırma kapsamı vardır ve bu kapsamlar öncelik sırasına göre değerlendirilir: | Kapsam | Dosya yolu | Amaç | -|--------|-----------|------| -| **proje** | `.failproofai/policies-config.json` | Her repo için ayarlar, sürüm kontrolüne kaydedilir | -| **yerel** | `.failproofai/policies-config.local.json` | Kişisel her repo geçersiz kılmaları, gitignore'da | -| **genel** | `~/.failproofai/policies-config.json` | Tüm projeler arasında kullanıcı düzeyinde varsayılanlar | +|--------|-----------|---------| +| **project** | `.failproofai/policies-config.json` | Depo başına ayarlar, sürüm kontrolüne gönderilen | +| **local** | `.failproofai/policies-config.local.json` | Kişisel depo başına geçersiz kılmalar, gitignore'da | +| **global** | `~/.failproofai/policies-config.json` | Tüm projeler arasında kullanıcı düzeyinde varsayılanlar | -failproofai bir hook olayı aldığında, mevcut çalışma dizini için mevcut olan üç dosyanın tümünü yükler ve birleştirir. +failproofai bir hook olayı aldığında, geçerli çalışma dizini için var olan üç dosyayı tümünü yükler ve birleştirir. ### Birleştirme kuralları -**`enabledPolicies`** - üç kapsamın tümünün birleşimi. Herhangi bir seviyede etkinleştirilen bir politika etkindir. +**`enabledPolicies`** - üç kapsam da birleştirilir. Herhangi bir düzeyde etkin olan politika aktiftir. ```text -proje: ["block-sudo"] -yerel: ["block-rm-rf"] -genel: ["block-sudo", "sanitize-api-keys"] +project: ["block-sudo"] +local: ["block-rm-rf"] +global: ["block-sudo", "sanitize-api-keys"] -çözüm: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← yinelenenden arındırılmış birleşim +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← yinelenenden arındırılmış birleşim ``` -**`policyParams`** - belirli bir politika için parametreleri tanımlayan ilk kapsam tamamen kazanır. Bir politikanın parametreleri içindeki değerlerin derin birleştirilmesi yoktur. +**`policyParams`** - belirli bir politika için parametreleri tanımlayan ilk kapsam tamamen kazanır. Bir politikanın parametreleri içinde derin birleştirme yapılmaz. ```text -proje: block-sudo → { allowPatterns: ["sudo apt-get update"] } -genel: block-sudo → { allowPatterns: ["sudo systemctl status"] } +project: block-sudo → { allowPatterns: ["sudo apt-get update"] } +global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -çözüm: { allowPatterns: ["sudo apt-get update"] } ← proje kazanır, genel yok sayılır +resolved: { allowPatterns: ["sudo apt-get update"] } ← project kazanır, global yoksayılır ``` ```text -proje: (block-sudo girişi yok) -yerel: (block-sudo girişi yok) -genel: block-sudo → { allowPatterns: ["sudo systemctl status"] } +project: (block-sudo girişi yok) +local: (block-sudo girişi yok) +global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -çözüm: { allowPatterns: ["sudo systemctl status"] } ← genel'e düşer +resolved: { allowPatterns: ["sudo systemctl status"] } ← global'e geri döner ``` **`customPoliciesPath`** - bunu tanımlayan ilk kapsam kazanır. @@ -55,7 +55,7 @@ genel: block-sudo → { allowPatterns: ["sudo systemctl status"] } --- -## Yapılandırma dosyası formatı +## Yapılandırma dosyası biçimi ```json { @@ -96,7 +96,7 @@ genel: block-sudo → { allowPatterns: ["sudo systemctl status"] } --- -## Alan referansı +## Alan başvurusu ### `enabledPolicies` @@ -104,31 +104,31 @@ Tür: `string[]` Etkinleştirilecek politika adlarının listesi. Adlar, `failproofai policies` tarafından gösterilen politika tanımlayıcılarıyla tam olarak eşleşmelidir. Tam liste için [Yerleşik Politikalar](/tr/built-in-policies) bölümüne bakın. -`enabledPolicies` içinde olmayan politikalar, `policyParams` içinde girdileri olsa bile etkindir değildir. +`enabledPolicies` içinde olmayan politikalar, `policyParams` içinde girdileri olsa bile etkin değildir. ### `policyParams` Tür: `Record>` -Politikaya özgü parametre geçersiz kılmaları. Dış anahtar politika adıdır; iç anahtarlar politikaya özgüdür. Her politika, [Yerleşik Politikalar](/tr/built-in-policies) içinde mevcut parametrelerini belgelendirmektedir. +Politika başına parametre geçersiz kılmalar. Dış anahtar politika adı; iç anahtarlar politikaya özgüdür. Her politika, [Yerleşik Politikalar](/tr/built-in-policies) bölümünde mevcut parametrelerini belgelendirir. -Bir politikanın parametreleri varsa ancak siz bunları belirtmezseniz, politikanın yerleşik varsayılanları kullanılır. `policyParams` hiç yapılandırmayan kullanıcılar önceki sürümlerle özdeş davranış alır. +Bir politikanın parametreleri varsa ancak bunları belirtmezseniz, politikanın yerleşik varsayılanları kullanılır. `policyParams` yapılandırmasını hiç yapmayan kullanıcılar, önceki sürümlerle özdeş davranış elde eder. -Bir politikanın params bloğu içindeki bilinmeyen anahtarlar hook çalıştırırken sessizce yok sayılır ancak `failproofai policies` çalıştırdığınızda uyarı olarak işaretlenir. +Politikanın parametreleri bloğunun içindeki bilinmeyen anahtarlar, hook ateşleme sırasında sessizce yoksayılır ancak `failproofai policies` çalıştırdığınızda uyarı olarak işaretlenir. -#### `hint` (çapraz kesme) +#### `hint` (tüm politikalar için geçerli) Tür: `string` (isteğe bağlı) -Bir politika `deny` veya `instruct` döndürdüğünde nedene eklenen mesaj. Politikanın kendisini değiştirmeden Claude'a uygulanabilir rehberlik vermek için kullanın. +Bir politika `deny` veya `instruct` döndürdüğünde nedene eklenen mesaj. Bunu, politikanın kendisini değiştirmeden Claude'a işlem yapılabilir rehberlik sağlamak için kullanın. -Herhangi bir politika türüyle çalışır — yerleşik, özel (`custom/`), proje kuralı (`.failproofai-project/`) veya kullanıcı kuralı (`.failproofai-user/`). +Tüm politika türleriyle çalışır — yerleşik, özel (`custom/`), proje kuralı (`.failproofai-project/`) veya kullanıcı kuralı (`.failproofai-user/`). ```json { "policyParams": { "block-force-push": { - "hint": "Bunun yerine yeni bir dal oluşturmayı deneyin." + "hint": "Bunun yerine yeni bir branch oluşturmayı deneyin." }, "block-sudo": { "allowPatterns": ["sudo apt-get"], @@ -141,32 +141,32 @@ Herhangi bir politika türüyle çalışır — yerleşik, özel (`custom/`), pr } ``` -`block-force-push` reddettiğinde, Claude şunu görür: *"Zorla itme engellendi. Bunun yerine yeni bir dal oluşturmayı deneyin."* +`block-force-push` reddettiğinde, Claude şu mesajı görür: *"Force-push engellendi. Bunun yerine yeni bir branch oluşturmayı deneyin."* -Dize olmayan değerler ve boş dizeler sessizce yok sayılır. `hint` ayarlanmadıysa, davranış değişmez (geriye dönük uyumlu). +String olmayan değerler ve boş stringler sessizce yoksayılır. `hint` ayarlanmamışsa, davranış değişmez (geriye dönük uyumlu). ### `customPoliciesPath` Tür: `string` (mutlak yol) -Özel hook politikaları içeren JavaScript dosyasının yolu. Bu, `failproofai policies --install --custom ` tarafından otomatik olarak ayarlanır (yol saklanmadan önce mutlak olarak çözümlenir). +Özel hook politikaları içeren JavaScript dosyasının yolu. Bu, `failproofai policies --install --custom ` tarafından otomatik olarak ayarlanır (yol depolanmadan önce mutlak olarak çözümlenir). -Dosya her hook olayında yeni yüklenir - hiçbir önbellek yoktur. Yazma ayrıntıları için [Özel Politikalar](/tr/custom-policies) bölümüne bakın. +Dosya her hook olayında yeniden yüklenir - önbelleğe alma yoktur. Yazma ayrıntıları için [Özel Politikalar](/tr/custom-policies) bölümüne bakın. ### Kural tabanlı politikalar -Açık `customPoliciesPath`'e ek olarak, failproofai `.failproofai/policies/` dizinlerinden politika dosyalarını otomatik olarak keşfeder ve yükler: +Açık `customPoliciesPath` öğesinin ek olarak, failproofai `.failproofai/policies/` dizinlerinden politika dosyalarını otomatik olarak keşfeder ve yükler: | Düzey | Dizin | Kapsam | -|------|-------|--------| -| Proje | `.failproofai/policies/` | Sürüm kontrolü aracılığıyla ekiple paylaşılır | -| Kullanıcı | `~/.failproofai/policies/` | Kişisel, tüm projelere uygulanır | +|-------|--------|--------| +| Project | `.failproofai/policies/` | Sürüm kontrolü aracılığıyla takımla paylaşılan | +| User | `~/.failproofai/policies/` | Kişisel, tüm projelere uygulanır | -**Dosya eşleşmesi:** Yalnızca `*policies.{js,mjs,ts}` ile eşleşen dosyalar yüklenir (örn. `security-policies.mjs`, `workflow-policies.js`). Dizindeki diğer dosyalar yok sayılır. +**Dosya eşleştirmesi:** Yalnızca `*policies.{js,mjs,ts}` ile eşleşen dosyalar yüklenir (ör. `security-policies.mjs`, `workflow-policies.js`). Dizindeki diğer dosyalar yoksayılır. -**Yapılandırma gerekmez:** Kural politikaları `policies-config.json` içinde giriş gerektirmez. Dosyaları dizine bırakın ve bir sonraki hook olayında seçilirler. +**Yapılandırma gerekli değil:** Kural politikaları `policies-config.json` içinde girdi gerektirmez. Dosyaları dizine koyun ve bir sonraki hook olayında alınırlar. -**Birleşim yükleme:** Hem proje hem de kullanıcı kural dizinleri taranır. Her iki seviyedeki tüm eşleşen dosyalar yüklenir (`customPoliciesPath` ilk kapsam kazanır'dan farklı olarak). +**Birleşim yüklemesi:** Hem proje hem de kullanıcı kural dizinleri taranır. Her iki düzeydeki tüm eşleşen dosyalar yüklenir (`customPoliciesPath` ilk-kapsam-kazanır kullanırken farklı olarak). Daha fazla ayrıntı ve örnekler için [Özel Politikalar](/tr/custom-policies) bölümüne bakın. @@ -187,22 +187,26 @@ AI çağrıları yapan politikalar için LLM istemci yapılandırması. Çoğu k --- -## CLI'dan yapılandırma yönetimi +## CLI'den yapılandırmayı yönetme -`policies --install` ve `policies --uninstall` komutları, ajan CLI'nizin hook ayarları dosyasına (hook giriş noktaları) yazarken `policies-config.json`, doğrudan yönettiğiniz dosyadır. İkisi ayrıdır: +`policies --install` ve `policies --uninstall` komutları, ajan CLI'niz için hook ayarları dosyasına yazarken (hook giriş noktaları), `policies-config.json` doğrudan yönettiğiniz dosyadır. İkisi ayrıdır: -- **Ajan CLI ayarları** — ajanı her araç kullanımında `failproofai --hook ` çağırması için söyler: - - **Claude Code**: `~/.claude/settings.json` (kullanıcı), `/.claude/settings.json` (proje), `/.claude/settings.local.json` (yerel) - - **OpenAI Codex**: `~/.codex/hooks.json` (kullanıcı), `/.codex/hooks.json` (proje) — Codex yerel kapsamı yok - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (kullanıcı), `/.github/hooks/failproofai.json` (proje) — Copilot yerel kapsamı yok. Hook girdileri Copilot'un OS anahtarlı `bash`/`powershell` komut alanlarını `timeoutSec` ile kullanır; dosya üst düzey `version: 1` işaretçisini taşır. Copilot CLI desteği **beta** durumundadır ve `events.jsonl` kayıt şemasını (halk belgeleri belirtmez) daha fazla gerçek dünya oturumuna karşı doğrularız. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (kullanıcı), `/.cursor/hooks.json` (proje) — Cursor yerel kapsamı yok. Hook girdileri Claude şeklinde `{type, command, timeout}` formunu kullanır (`bash`/`powershell` bölümü yok) ancak camelCase olay anahtarları (`preToolUse`, `beforeSubmitPrompt`, …) altında depolanır, Cursor'un [hooks şemasına](https://cursor.com/docs/hooks) göre düz dizi halinde; dosya üst düzey `version: 1` işaretçisini taşır. İşleyici, `CURSOR_EVENT_MAP` aracılığıyla camelCase → PascalCase'i kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Cursor Agent desteği **beta** durumundadır ve Cursor'un disk üzerindeki transkripti (açık belgelerde belirtilmez) daha fazla gerçek dünya kurulumuna karşı doğrularız. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (kullanıcı), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proje) — OpenCode yerel kapsamı yok. Diğer altı CLI'den farklı olarak, OpenCode **harici komut hook sistemi olmaz**: `plugin: []` dizisi aracılığıyla açıkça kaydedilen işlem içi JS/TS eklentilerini yükler (`opencode.json` içinde) (`.opencode/plugins/` dan otomatik keşif opencode v1.14.33'de eklentilerin nasıl yüklendiği **değildir**). Kurulum, ikili failproofai'yi subprocess olarak çağıran ve ikili'nin Claude şekli JSON yanıtını eklenti semantiğine geri çeviren küçük bir oluşturulan eklenti parçacığını bırakır: araç olayı reddi için `throw new Error()` (araç çağrısını iptal eder), `instruct` VE `Stop` / `SubagentStop` reddi için `client.session.prompt(...)` (reddi nedeni bir sonraki kullanıcı iletisi olarak gönderir — `session.idle` yalnızca bildirimdir ve bundan atmak no-op olduğundan tek zorla yeniden deneme kanalı), allow için no-op. Parçacık hem araç adlarını (küçük harf → PascalCase, `OPENCODE_TOOL_MAP` aracılığıyla) hem de araç giriş arg anahtarlarını (camelCase → snake_case, `OPENCODE_TOOL_INPUT_MAP` aracılığıyla `Read` / `Write` / `Edit` için, örn. `filePath` → `file_path`, `oldString` → `old_string`) kanonikleştirir, ikili'ye iletmeden önce, yol kontrol yerleşikleri gibi `block-read-outside-cwd`, `block-env-files` ve `block-secrets-write` OpenCode araç çağrılarında değişmeden çalışır. Oturumlar opencode'un SQLite DB'sinde yaşar `~/.local/share/opencode/opencode.db`; pano'nun oturum görüntüleyicisi onları `opencode db --format json` ve `opencode export ` aracılığıyla okur. OpenCode desteği **beta** durumundadır ve sürümler arasında ve daha fazla gerçek dünya oturumlarına karşı davranışı doğrularız. [OpenCode eklentileri belgeleri](https://opencode.ai/docs/plugins/) başlıklı sayfaya bakın. - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (kullanıcı), `/.pi/settings.json` (proje) — Pi yerel kapsamı yok. Pi başlangıçta TypeScript uzantı paketlerini yükler; ayarlar dosyası düz dize dizisidir `{"packages": ["./relative/path", …]}`. failproofai, paketlenmiş `pi-extension/` dizinine işaret eden tek bir packages-dizisi girişi yazar. Uzantı dahili olarak Pi'nin `tool_call` / `user_bash` / `input` / `session_start` olaylarına abone olur ve `failproofai --hook --cli pi`'ye shell çıkışı verir; işleyici underscore_lower_snake_case → PascalCase'i `PI_EVENT_MAP` aracılığıyla kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Araç giriş argları da `PI_TOOL_INPUT_MAP` aracılığıyla kanonikleştirilir (Pi'nin Read / Write / Edit `file_path` yerine `path` iletir; üst düzey anahtarı eşlemek `block-env-files` ve `block-secrets-write`'in çalışmasını sağlar — `block-read-outside-cwd` zaten bir `path` geri dönüşü içeriyordu). Pi desteği **beta** durumundadır, Pi'nin uzantı API'si ve oturum günlüğü düzeni stabilize olurken. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (kullanıcı), `/.gemini/settings.json` (proje) — Gemini yerel kapsamı yok (`/etc/gemini-cli/settings.json` içinde belgelenen bir `system` kapsamı vardır, failproofai bunu göstermez). Hook girdileri Claude'un `{type, command, timeout}` formunu Gemini'nin `{matcher, hooks: [...]}` eşleşme şemasında, varsayılan olarak `matcher: "*"` ile sarılı halde kullanır. Olaylar PascalCase'tir (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); işleyici `GEMINI_EVENT_MAP` aracılığıyla Claude kanonik adlarına eşlenir. Araç adları snake_case'tir (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — işleyici `GEMINI_TOOL_MAP` aracılığıyla kanonikleştirir, böylece mevcut yerleşik politikalar değişmeden çalışır. Politika değerlendirici Gemini'nin düz `{decision: "deny", reason}` şeklini yayar (Gemini'nin "Altın Kural" exit-0 sözleşmesine göre tercih edilen), `{hookSpecificOutput: {hookEventName, additionalContext}}` BeforeAgent / AfterTool / SessionStart'ta bağlam enjeksiyonu için ve AfterAgent'ta `{decision: "block", reason}` zorla yeniden deneme semantiği için. Gemini CLI desteği **beta** durumundadır ve gerçek dünya kapsamsını genişletirken. [Gemini CLI hooks belgeleri](https://geminicli.com/docs/hooks/) başlıklı sayfaya bakın. - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**yalnızca kullanıcı kapsamı** — Hermes proje/yerel yapılandırması yok). Hermes bir Slack/Telegram **ağ geçididir**, bu nedenle bir kurulum her platformdan (Slack/Telegram/cli/cron) araç çağrılarını **ve** iç alt ajanları yakalar. Hook girdileri, Hermes'in snake_case olayları (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) tarafından anahtarlanan `hooks:` eşlemesi altında `{command, timeout}` çiftidir; işleyici `HERMES_EVENT_MAP` aracılığıyla olayları ve `HERMES_TOOL_MAP` aracılığıyla araç adlarını kanonikleştirir, böylece yerleşik politikalar değişmeden çalışır. Yapılandırma, yorum koruyan YAML `Document` turuna göre düzenlendiğinden işletmenin diğer ayarları kalır ve kurulum, başsız ağ geçidinin (TTY yok) hookları onay istemi olmadan çalıştırması için `hooks_auto_accept: true` ayarlar. Değerlendirici Hermes'in `{"decision":"block","reason"}` stdout sözleşmesini yayar (Hermes çıkış kodlarını yok sayar). **Sınırlamalar:** Hermes'in bir `Stop` olay sonu yoktur, bu nedenle `require-*-before-stop` yerleşikleri bunun için hiçbir zaman çalışmaz (uygulanamaz, kırık değil); `instruct` izin-not-ile-günlüğe-kaydedil'e degrades (ek bağlam kanalı yok); ve çıkış gizli redaksiyonu (`sanitize-*`) shell-hook sözleşmesi üzerinde araç çıkışını yeniden yazamaz. Hermes aynı zamanda çevrimdışı bir **denetim** kaynağıdır — pano, ağ geçidi oturumlarını doğrudan `~/.hermes/state.db`'den okur. -- **`policies-config.json`** — failproofai'ye hangi politikaları değerlendireceğini ve hangi parametrelerle (tüm ajan CLI'ler arasında paylaşılan) söyler +- **Ajan CLI ayarları** — ajana her araç kullanımında `failproofai --hook ` çağırmasını söyler: + - **Claude Code**: `~/.claude/settings.json` (kullanıcı), `/.claude/settings.json` (proje), `/.claude/settings.local.json` (lokal) + - **OpenAI Codex**: `~/.codex/hooks.json` (kullanıcı), `/.codex/hooks.json` (proje) — Codex'in lokal kapsamı yoktur + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (kullanıcı), `/.github/hooks/failproofai.json` (proje) — Copilot'un lokal kapsamı yoktur. Hook girdileri Copilot'un işletim sistemi anahtarlanmış `bash`/`powershell` komut alanlarını `timeoutSec` ile kullanır; dosya üst düzey `version: 1` işaretçisi taşır. Copilot CLI desteği **beta**'dır çünkü `events.jsonl` kayıt şemasını (genel belgeler belirtmez) daha fazla gerçek dünya oturumuna karşı doğrulanıyoruz. **VS Code Copilot Chat ajan modu (Önizleme)**, `.github/hooks/*.json`, `~/.copilot/hooks/*.json` ve `~/.claude/settings.json` adreslerinden hook konfigürasyonlarını okur (` chat.hookFilesLocations` ayarı tarafından yönetilir) aynı Claude biçimli `{hookSpecificOutput:{permissionDecision:"deny",…}}` sözleşmesini kullanarak — bu `copilot` entegrasyonunun ve `claude` entegrasyonunun (`~/.claude/settings.json`) zaten yazdığı tam yollar, bu nedenle `failproofai policies --install --cli copilot` (veya `--cli claude`) **VS Code ajan modunda zaten uygular** ayrı `vscode` entegrasyonuna gerek kalmadan (VS Code keşif günlüklerinden canlı doğrulanmıştır). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (kullanıcı), `/.cursor/hooks.json` (proje) — Cursor'un lokal kapsamı yoktur. Hook girdileri Claude biçimli `{type, command, timeout}` formunu kullanır (`bash`/`powershell` bölümü yoktur) ancak Cursor'un [hooks şemasına](https://cursor.com/docs/hooks) göre camelCase olay anahtarları (`preToolUse`, `beforeSubmitPrompt`, …) altında düz bir dizi içinde saklanır; dosya üst düzey `version: 1` işaretçisi taşır. İşleyici camelCase → PascalCase'i `CURSOR_EVENT_MAP` aracılığıyla kanonikleştirir, bu nedenle mevcut yerleşik politikalar değişmeden ateşlenir. Cursor Agent desteği **beta**'dır çünkü Cursor'un disk üzerindeki transkript biçimini (genel belgeler belirtmez) daha fazla gerçek dünya kurulumuna karşı doğrulanıyoruz. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (kullanıcı), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (proje) — OpenCode'un lokal kapsamı yoktur. Diğer beş CLI'den farklı olarak, OpenCode **harici komut hook sistemi**ne sahip değildir: `opencode.json` içindeki `plugin: []` dizisi aracılığıyla açıkça kaydedilen işlem içi JS/TS eklentilerini yükler (`.opencode/plugins/` adresinden otomatik keşif, opencode v1.14.33'te **değildir**). Yükleme, failproofai ikilisini subprocess çağıran ve ikili dosyanın Claude biçimli JSON yanıtını eklenti semantiğine geri çeviren küçük bir oluşturulmuş eklenti parçacığı bırakır: araç olayı reddi için `throw new Error()` (araç çağrısını iptal eder), `instruct` ve `Stop` / `SubagentStop` reddi için `client.session.prompt(...)` (reddi nedeni sonraki kullanıcı mesajı olarak gönderilir — tek kuvvetli yeniden deneme kanalı çünkü `session.idle` yalnızca bildirimdir ve bundan atma işlemi yok-optur) ve izin ver için yok-op. Parçacık hem araç adlarını (küçük harf → PascalCase, `OPENCODE_TOOL_MAP` aracılığıyla) hem de araç girişi arg anahtarlarını (camelCase → snake_case, `OPENCODE_TOOL_INPUT_MAP` aracılığıyla `Read` / `Write` / `Edit` için, ör. `filePath` → `file_path`, `oldString` → `old_string`) kanonikleştirir, ardından ikiliye iletir, bu nedenle `block-read-outside-cwd`, `block-env-files` ve `block-secrets-write` gibi yol denetleyen yerleşik ögeler OpenCode araç çağrılarında değişmeden ateşlenir. Oturumlar opencode'un SQLite DB'sinde `~/.local/share/opencode/opencode.db` adresinde yaşar; pano oturumu görüntüleyicisi bunları `opencode db --format json` ve `opencode export ` aracılığıyla okur. OpenCode desteği **beta**'dır çünkü sürümler arasında davranışı ve daha fazla gerçek dünya oturumunu doğrulanıyoruz. [OpenCode eklentileri belgelerine](https://opencode.ai/docs/plugins/) bakın. + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (kullanıcı), `/.pi/settings.json` (proje) — Pi'nin lokal kapsamı yoktur. Pi başlangıçta TypeScript uzantı paketlerini yükler; ayarlar dosyası düz string dizisi `{"packages": ["./relative/path", …]}` yapısıdır. failproofai, paketlemenin `pi-extension/` dizinine işaret eden tek bir packages-dizi girdisi yazar. Uzantı dahili olarak Pi'nin `tool_call` / `user_bash` / `input` / `session_start` olaylarına abone olur ve `failproofai --hook --cli pi` komutu çalıştırır; işleyici underscore_lower_snake_case → PascalCase'i `PI_EVENT_MAP` aracılığıyla kanonikleştirir, bu nedenle mevcut yerleşik politikalar değişmeden ateşlenir. Araç girişi argları da `PI_TOOL_INPUT_MAP` aracılığıyla kanonikleştirilir (Pi'nin Read / Write / Edit, `file_path` yerine `path` ile teslim eder; üst düzey anahtarı eşleştirmek `block-env-files` ve `block-secrets-write` ateşlenmesine izin verir — `block-read-outside-cwd` zaten `path` geri dönüşüne sahipti). Pi desteği **beta**'dır çünkü Pi'nin uzantı API'si ve oturum-günlük düzeni stabilize oluyordu. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**yalnızca kullanıcı kapsamı** — Hermes'in proje/lokal konfigürasyonu yoktur). Hermes bir Slack/Telegram **ağ geçidi**sidir, bu nedenle bir yükleme, her platformdan (Slack/Telegram/cli/cron) **ve** dahili alt ajanlardan gelen araç çağrılarını engeller. Hook girdileri Hermes'in snake_case olayları tarafından anahtarlanan bir olay→işleyiciler haritasının altında bir `{command, timeout}` çiftidir (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`) (timeout **saniye**'dir); işleyici `HERMES_EVENT_MAP` aracılığıyla olayları ve `HERMES_TOOL_MAP` aracılığıyla araç adlarını kanonikleştirir, bu nedenle yerleşik politikalar değişmeden ateşlenir. Yapılandırma, yorumu koruyan YAML `Document` turunda değiştirilir, böylece operatörün diğer ayarları hayatta kalır ve yükleme `hooks_auto_accept: true` ayarlandığı için headless ağ geçidi (TTY yok) hookları izin isteminde çalıştırır. Değerlendirici Hermes'in `{"decision":"block","reason"}` stdout sözleşmesini yayınlar (Hermes çıkış kodlarını yoksayar). **Sınırlamalar:** Hermes'in turn-end `Stop` olayı yoktur, bu nedenle `require-*-before-stop` yerleşik ögeleri için asla ateşlenmez (uygulanamaz, bozuk değil); `instruct` izin ver-ile-günlüğe-alınan-nota haline gelir (ek-bağlam kanalı yok); ve çıktı-gizli redaksiyonu (`sanitize-*`) araç çıkışını shell-hook sözleşmesi üzerinde yeniden yazamaz. Hermes **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, ağ geçidi oturumlarını doğrudan `~/.hermes/state.db` adresinden okur. + - **OpenClaw (openclaw gateway)**: `~/.openclaw/openclaw.json` (**yalnızca kullanıcı kapsamı** — OpenClaw'un proje/lokal konfigürasyonu yoktur). Hermes gibi, OpenClaw kendi kendine barındırılan çok kanallı **ağ geçidi**sidir, bu nedenle bir yükleme, her kanaldan ve dahili alt ajanlardan gelen araç çağrılarını engeller. Uygulama OpenClaw'un **işlem içi eklenti kancaları** aracılığıyla çalışır (dosya tabanlı dahili kancaları yalnızca gözlemdir ve engellemeye katkıda bulunamaz), bu nedenle — OpenCode/Pi gibi — failproofai failproofai ikilisini eş zamansız olarak oluşturan ve karara çeviren statik `openclaw-plugin/` paketi sevk eder. Yükleme, sevk edilen eklenti dizinini `openclaw.json` adresinin `plugins.load.paths[]` içine kaydeder ve `plugins.entries.failproofai` altında etkinleştirir (`hooks.allowConversationAccess: true` ile, ham-konuşma kancaları için gerekli). Değerlendirici düz `{permission, reason}` kararını yayınlar ve parçacık bunu her kancaya yerel dönüş şekline eşler: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), ve `before_agent_finalize → {action:"revise", reason}` (**Stop** — gerçek turn-end geçidi, bu nedenle `require-*-before-stop` yerleşik ögeleri **uygular**, Hermes'ten farklı olarak). Olaylar ve araç adları `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) aracılığıyla binary tarafında kanonikleştirilir, bu nedenle yerleşik politikalar değişmeden ateşlenir; parçacık herhangi bir spawn/parse/timeout hatasında başarısız bir şekilde açılır. OpenClaw **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, JSONL oturumlarını `~/.openclaw/agents//sessions/.jsonl` adresinde okur. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (kullanıcı), `/.factory/hooks.json` (proje) — Factory'nin lokal kapsamı yoktur. droid, Claude biçimli harici komut hook sistemi sevk eder, ancak droid v0.171.0'a karşı canlı olarak doğrulanmış iki tuhaflık vardır: (1) olay adları `hooks.json` adresinin **üst düzeyinde** yaşar — bir **`"hooks"` sarmalayıcı yoktur** (droid bir taneyi reddeder); araç olayları (`PreToolUse`/`PostToolUse`) `"matcher": "*"` taşır, araç dışı olaylar bunu atlar. (2) Reddi, hook **çıkış kodu 2 + stderr** tarafından yönlendirilir, JSON kararına göre değil — değerlendirici'nin `factory` dalı araç/istem olayları için çıkış 2 döndürür ve turn-end `Stop` olayında `{decision:"block", reason}` yalnızca (droid'in tek kuvvetli yeniden deneme kanalı). Olaylar zaten PascalCase yapısında (olay haritası yok) ve yük Claude snake_case'idir; yalnızca araç adları `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …) aracılığıyla kanonikleştirilir. Factory **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, disk üzerinde JSONL oturumlarını `~/.factory/sessions//.jsonl` adresinde okur. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (kullanıcı), `/.devin/config.json` (proje) — Devin'in lokal kapsamı yoktur. Devin, devin v3000.1.27'ye karşı canlı olarak doğrulanmış **saf Claude klon**'tur: standart Claude `"hooks"`-sarmalayıcı şemasını kullanır (yazışlar birleştirme koruyucudur, bu nedenle yapılandırma dosyasının diğer anahtarları — `org_id`, `theme_mode`, … — hayatta kalır), zaten-PascalCase olay adları (olay haritası yok, işleyici dalı yok) ve Claude snake_case stdin yükü (normalleştirme yok). Değerlendirici'nin `devin` dalı **her** olay için çıkış 0'da `{"decision":"block","reason"}` JSON ile reddeder (doğrulanmıştır — `--permission-mode dangerous` açıklamadan sonra); turn-end `Stop` olayında neden, `require-*-before-stop` yerleşik ögeleri uygulama şekilde ZORUNLU-EYLEM kuvvetli yeniden deneme ifadeleri taşır. Yalnızca araç adları `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` zaten kurallıdır) aracılığıyla kanonikleştirilir. Devin **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, SQLite oturumlarını `~/.local/share/devin/cli/sessions.db` adresinde okur (her `sessions` satırı gerçek `working_directory` taşır, bu nedenle oturumlar Claude gibi proje cwd tarafından gruplandırılır). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (kullanıcı), `/.agents/hooks.json` (proje) — Antigravity'nin lokal kapsamı yoktur. Factory/Devin'den farklı olarak, Antigravity agy v1.1.2'ye karşı canlı olarak doğrulanmış **kendi** sözleşmesine sahiptir. `hooks.json` bir **adlandırılmış-kanca** şeması kullanır: üst düzey anahtar bir kanca *adı* (`"failproofai"`) olup değeri bir olay→işleyiciler haritasıdır — araç olayları (`PreToolUse`/`PostToolUse`) işleyicileri `{matcher:"*", hooks:[…]}` içinde sarmalar, `PreInvocation`/`Stop` ise **düz** işleyici dizileridir (diğer adlandırılmış kancalar korunur). stdin yükü **camelCase protojson**'dur (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai bunu politikalar çalıştırılmadan önce snake_case'e normalleştirir ve `run_command` adresinin PascalCase arglarını (`CommandLine`/`Cwd`) `ANTIGRAVITY_TOOL_INPUT_MAP` aracılığıyla eşler. Değerlendirici'nin `antigravity` dalı Antigravity'nin **kendi** yanıt şekillerini kullanır: `{decision:"deny", reason}` bir araç/istem bloğu (çıkış 0), `{decision:"continue", reason}` turn-end `Stop` adresinde yeniden giriş (bu nedenle `require-*-before-stop` yerleşik ögeleri uygular) ve `{injectSteps:[{ephemeralMessage}]}` `PreInvocation` adresinde bir talimatı enjekte eder (→ `UserPromptSubmit`). Araç adları `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …) aracılığıyla kanonikleştirilir. Antigravity **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, düz JSONL transkriptlerini `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` adresinde okur (konuşma dizini `conversation_summaries.db` içinde). + - **Goose (codename goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (kullanıcı), `/.agents/plugins/failproofai/hooks/hooks.json` (proje) — Goose'un lokal kapsamı yoktur. Uygulama Goose'un **kancaları** sistemini, çapraz-ajan **Açık Eklentiler** spesifikasyonunu kullanır: yükleyici sadece `failproofai` eklenti dizinini bırakır ve Goose bunu başlangıçta otomatik olarak keşfeder (kendi kendine `~/.config/goose/config.yaml` içinde kaydederek). `hooks.json` bir Open Plugins şeması ile bir üst düzey `"hooks"` sarmalayıcı **ile** kullanır ve eşleştirici **her olay üzerinde atlanır** — çıplak `"*"`, hiçbir şeyle eşleşmeyen geçersiz bir regexdir (goose v1.43.0'a karşı canlı olarak doğrulanmıştır). Olay adları zaten PascalCase yapısında (olay haritası yok); stdin yükü `event`/`working_dir` kullanır, işleyici bunu `hook_event_name`/`cwd` adresine normalleştirir. Değerlendirici'nin `goose` dalı çıkış 0'da `{"decision":"block","reason"}` JSON ile reddeder, **`PreToolUse`** olayında yalnızca onurlanır (goose ≥ v1.37.0 içinde sevk edilir) — hangi ateş kabuk aracında **ve temsilci alt ajanlar içinde**, bu nedenle tek yeterli reddi noktasıdır; başka bir kanca hatasında başarısız bir şekilde açılır. Goose'un **`Stop` olayı yoktur**, bu nedenle `require-*-before-stop` yerleşik ögeleri uygulanmaz (Hermes gibi). Araç adları `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) aracılığıyla ve yol anahtarları `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`) aracılığıyla kanonikleştirilir. Goose **ayrıca** çevrimdışı **denetim** kaynağıdır — pano, SQLite oturumlarını `~/.local/share/goose/sessions/sessions.db` adresinde okur (her `sessions` satırı gerçek `working_dir` taşır, bu nedenle oturumlar Devin gibi proje cwd tarafından gruplandırılır; `--no-session` karalama çalıştırmaları filtrelenir). +- **`policies-config.json`** — failproofai'ye hangi politikaları değerlendireceğini ve hangi parametrelerle değerlendireceğini söyler (tüm ajan CLI'leri arasında paylaşılan) -Belirli bir ajanı hedeflemek için `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` geçin (boşlukla ayrılmış veya herhangi bir altküme için tekrarlanan): +Belirli bir ajana hedef almak için `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` kullanın (boşluk veya tekrarlı olarak herhangi bir alt küme için): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -`--cli` atlandığında, `failproofai` hangi ajan CLI'lerin yüklendiğini algılar (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +`--cli` atlandığında, `failproofai` hangi ajan CLI'lerinin yüklendiğini algılar (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Bir CLI algılandı** — sor olmadan o CLI'yi otomatik seçer. -- **Etkileşimli bir terminalde birden fazla CLI algılandı** — `Detected (N)` bölümüne gruplandırılmış ok tuşu tek seçim istemi gösterir (algılanan tüm CLI'ler için bir `Tüm N tespit edileni yükle` toplu satırı + her algılanan CLI bireysel olarak) ve her desteklenen CLI'nin yüklenmemiş olan listesini gösteren `Yüklü olmayan (M) · hookları önceden kurma` bölümü (↑↓ taşımak, Enter seçmek, ^C bırakmak için). Kaldırma akışı yalnızca Algılanan bölümü gösterir. -- **Etkileşimli olmayan çalıştırmada birden fazla CLI algılandı** (CI, TTY yok) — sor olmadan tüm algılanan CLI'ler için yükler. -- **Hiçbiri algılanmadı** — `claude`'ye geri döner, PATH'de ajan ikili bulunamadığı konusunda bir uyarı ile; hook komutu hala yazılır, böylece biri yüklendiğin anda etkinleşir. +- **Bir CLI algılandı** — sormadan bu CLI'yi otomatik olarak seçer. +- **Etkileşimli terminalde birden fazla CLI algılandı** — bir `Detected (N)` bölümüne gruplanmış ok tuşu tek seçim istemi gösterir (bir `Install for all N detected` toplam satırı + her algılanan CLI ayrı ayrı) ve her desteklenen CLI'nin (↑↓ hareket etmek, Enter seçmek, ^C çıkmak için) listeleyen bir `Not installed (M) · install hooks ahead of time` bölümü. Kaldırma akışı yalnızca Algılanan bölümü gösterir. +- **Etkileşimli olmayan çalıştırmada birden fazla CLI algılandı** (CI, TTY yok) — sormadan tüm algılanan CLI'ler için yüklenir. +- **Hiçbiri algılanmadı** — `claude` adresine geri döner ve PATH'da hiçbir ajan ikilisinin bulunmadığına dair uyarı ile; hook komutu yine de yazılır, böylece bir taneyi yükler yüklemez etkinleşir. -`policies-config.json`'u doğrudan istediğiniz zaman düzenleyebilirsiniz; değişiklikler bir sonraki hook olayında yeniden başlatma gerekmeden hemen etkili olur. +`policies-config.json` öğesini istediğiniz zaman doğrudan düzenleyebilirsiniz; değişiklikler bir sonraki hook olayında yeniden başlatılmasına gerek kalmadan hemen etkinleşir. --- ## Örnek: takım varsayılanları ile proje düzeyinde yapılandırma -`.failproofai/policies-config.json`'u repo'nuza kaydedin: +`.failproofai/policies-config.json` öğesini deponuza gönderin: ```json { @@ -247,4 +255,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -Her geliştirici daha sonra, takım arkadaşlarını etkilemeden kişisel geçersiz kılmalar için `.failproofai/policies-config.local.json` (gitignore'da) oluşturabilir. \ No newline at end of file +Bundan sonra her geliştirici, takım arkadaşlarını etkilemeden kişisel geçersiz kılmalar için `.failproofai/policies-config.local.json` (gitignore) oluşturabilir. \ No newline at end of file diff --git a/docs/tr/dashboard.mdx b/docs/tr/dashboard.mdx index 6b865387..bd881a9c 100644 --- a/docs/tr/dashboard.mdx +++ b/docs/tr/dashboard.mdx @@ -1,14 +1,14 @@ --- -title: Pano +title: Kontrol Paneli description: "Agent oturumlarını izleyin, araç çağrılarını gözden geçirin ve politikaları yönetin" icon: chart-line --- -failproofai panosu, yapay zeka aracı oturumlarınızı izlemek ve politikaları yönetmek için yerel bir web uygulamasıdır. Aracılarınız sizi yokken neler yaptığını görün. +failproofai kontrol paneli, AI aracı oturumlarınızı izlemek ve politikaları yönetmek için yerel bir web uygulamasıdır. Aracılarınız yokken neler yaptığını görebilirsiniz. --- -## Panoyu başlatma +## Kontrol panelini başlatma ```bash failproofai @@ -16,7 +16,7 @@ failproofai `http://localhost:8020` adresinde açılır. -Pano, dosya sisteminden doğrudan okur — Claude Code proje klasörlerinizi ve failproofai yapılandırma dosyalarınızı. Uzak bir hizmete hiçbir şey yazılmaz. +Kontrol paneli dosya sisteminden doğrudan okur — Claude Code proje klasörleriniz ve failproofai yapılandırma dosyalarınız. Hiçbir şey uzak bir servise yazılmaz. --- @@ -24,67 +24,67 @@ Pano, dosya sisteminden doğrudan okur — Claude Code proje klasörlerinizi ve ### Projeler -Makinenizde bulunan tüm Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ ve Hermes projelerini listeler. Claude projeleri `~/.claude/projects/` adresinden keşfedilir (veya `CLAUDE_PROJECTS_PATH` tarafından ayarlanan yol); Codex projeleri `~/.codex/sessions///
/*.jsonl` altındaki her transkripti tarayarak ve her oturumun ilk kaydında kaydedilen `cwd` ye göre gruplandırılarak keşfedilir; Copilot CLI projeleri her `~/.copilot/session-state//workspace.yaml` tarayarak keşfedilir (`COPILOT_HOME` üzerinden yapılandırılabilir) ve `cwd` alanına göre gruplandırılır; Cursor Agent projeleri `~/.cursor/agent-sessions//` altındaki oturum başına meta verileri tarayarak keşfedilir (`CURSOR_HOME` üzerinden yapılandırılabilir, `conversations/` ve `sessions/` geri dönüş olarak problanır) `meta.json` / `session.json` / `workspace.yaml` içindeki `cwd` skaler değeri için; OpenCode projeleri `~/.local/share/opencode/opencode.db` adresindeki SQLite DB'sini `opencode db --format json` üzerinden sorgulayarak keşfedilir (`session` ve `project` tablolarını okuyuz ve `project_id` ye göre gruplandırırız); Pi projeleri `~/.pi/agent/sessions//_.jsonl` altındaki oturum başına JSONL transkriptlerini tarayarak keşfedilir (`PI_SESSIONS_DIR` üzerinden yapılandırılabilir) ve her oturumun ilk kaydından `cwd` yi çekeriz; Gemini CLI projeleri `~/.gemini/tmp//chats/session--.jsonl` tarayarak keşfedilir (`GEMINI_SESSIONS_DIR` üzerinden yapılandırılabilir) ve `.project_root` metin işaretçisinden kanonik cwd'yi kurtarırız; Hermes ağ geçidi oturumları doğrudan `~/.hermes/state.db` (`HERMES_DB_PATH` üzerinden yapılandırılabilir) adresindeki SQLite deposundan okunur ve `source` (Slack/Telegram/cli/cron — ağ geçidi oturumlarının cwd'si yoktur) tarafından `hermes-` projelerine gruplandırılır. Birden çok CLI tarafından kullanılan bir proje, tüm eşleşen rozetleriyle tek bir satır olarak işlenir. Belirli bir aracı CLI'ye göre filtrelemek için tablonun üstündeki **CLI** açılır menüsünü kullanın; URL seçiminizi `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes` olarak korur. +Makinenizde bulunan tüm Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity ve Goose projelerini listeler. Claude projeleri `~/.claude/projects/` adresinden keşfedilir (`CLAUDE_PROJECTS_PATH` tarafından ayarlanan yolu veya); Codex projeleri `~/.codex/sessions///
/*.jsonl` altındaki her transcript taranarak ve her oturumun ilk kaydında kayıtlı `cwd` ye göre gruplandırılarak keşfedilir; Copilot CLI projeleri `~/.copilot/session-state//workspace.yaml` dosyasının her biri taranarak (`COPILOT_HOME` aracılığıyla yapılandırılabilir) ve `cwd` alanı yoluyla gruplandırılarak keşfedilir; Cursor Agent projeleri `~/.cursor/agent-sessions//` altındaki oturum başına metaveri taranarak (`CURSOR_HOME` aracılığıyla yapılandırılabilir, `conversations/` ve `sessions/` yedek olarak araştırılır) ve `meta.json` / `session.json` / `workspace.yaml` içinde `cwd` skaleri aranarak keşfedilir; OpenCode projeleri SQLite DB'sini `~/.local/share/opencode/opencode.db` adresinde `opencode db --format json` aracılığıyla sorgulayarak keşfedilir (`session` ve `project` tablolarını okur ve `project_id` ye göre gruplandırırız); Pi projeleri `~/.pi/agent/sessions//_.jsonl` altında oturum başına JSONL transcript taranarak (`PI_SESSIONS_DIR` aracılığıyla yapılandırılabilir) ve her oturumun ilk kaydından `cwd` çekilerek keşfedilir; Hermes ağ geçidi oturumları doğrudan SQLite deposundan `~/.hermes/state.db` adresinde okunur (`HERMES_DB_PATH` aracılığıyla yapılandırılabilir) ve `source` ye göre `hermes-` projelerine gruplandırılır (Slack/Telegram/cli/cron — ağ geçidi oturumlarının cwd'si yoktur); OpenClaw ağ geçidi oturumları `~/.openclaw/agents//sessions/*.jsonl` adresinden okunur ve `openclaw-` projelerine gruplandırılır (ayrıca cwd'siz); Factory Droid projeleri `~/.factory/sessions//*.jsonl` adresindeki JSONL transcript'lerinden keşfedilir ve cwd ye göre gruplandırılır; Devin projeleri SQLite DB'sinden `~/.local/share/devin/cli/sessions.db` adresinde (her oturumun `working_directory` ye göre gruplandırılır); Antigravity projeleri `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` adresindeki JSONL transcript'lerinden ve cwd ye göre gruplandırılır; ve Goose projeleri SQLite DB'sinden `~/.local/share/goose/sessions/sessions.db` adresinde (her oturumun `working_dir` ye göre gruplandırılır). Birden fazla CLI tarafından kullanılan bir proje, tüm eşleşen rozetlerle tek bir satır olarak render edilir. Tablonun üzerindeki **CLI** açılır menüsünü kullanarak belirli bir aracı CLI'ye göre filtreleyin; URL seçiminizi `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` olarak korur. Her proje şunları gösterir: -- Proje adı (klasör yolundan türetilmiş) -- CLI rozeti — `Claude Code` (turuncu), `OpenAI Codex` (mor), `GitHub Copilot` (mavi), `Cursor Agent` (zümrüt), `OpenCode` (kehribar), `Pi` (pembe), `Gemini CLI` (gökyüzü), ve/veya `Hermes` (çivit) -- En son oturum etkinliğinin tarihi +- Proje adı (klasör yolundan türetilir) +- CLI rozeti — `Claude Code` (turuncu), `OpenAI Codex` (mor), `GitHub Copilot` (mavi), `Cursor Agent` (yeşilimsi), `OpenCode` (kehribar), `Pi` (pembe), ve/veya `Hermes` (indigo) +- En son oturum aktivitesinin tarihi -Oturumlarını görmek için bir projeyi tıklayın. +Oturumlarını görmek için bir projeye tıklayın. ### Oturumlar Bir proje içindeki tüm oturumları listeler. Her oturum şunları gösterir: -- Oturum ID'si +- Oturum kimliği - Başlangıç ve bitiş zaman damgaları -- Araç çağrılarının sayısı -- Kancı etkinliği sayısı (tetiklenen politikalar) +- Araç çağrı sayısı +- Hook aktivite sayısı (ateşlenen politikalar) -Listeyi daraltmak için tarih aralığı filtresini ve oturum ID aramasını kullanın. Oturumlar sayfalanır. +Listeyi daraltmak için tarih aralığı filtresini ve oturum kimliği aramasını kullanın. Oturumlar sayfalandırılır. -Oturum görüntüleyiciyi açmak için bir oturumu tıklayın. +Oturum görüntüleyiciyi açmak için bir oturuma tıklayın. -### Oturum görüntüleyici +### Oturum görüntüleyicisi -Oturum görüntüleyici, otonom aracılar için temel soruyu yanıtlar: aracı ne yaptı ve hız tuttu mu? Başlığın yanındaki CLI rozeti, oturumun Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI veya Hermes transkripti olup olmadığını gösterir. Bir oturumda gerçekleşen her şeyin bir zaman çizelgesini gösterir: +Oturum görüntüleyicisi, özerk aracılar için temel soruyu yanıtlar: aracı ne yaptı ve doğru yolda mı kaldı? Başlığın yanındaki bir CLI rozeti, oturumun Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity veya Goose transcript'i olup olmadığını gösterir. Bir oturumda olan her şeyin bir zaman çizelgesini gösterir: - **İletiler** - Claude'un metin yanıtları ve kullanıcı istemleri -- **Araç çağrıları** - Claude'un çağırdığı her araç, girişi ve çıktısıyla -- **Politika etkinliği** - Her araç çağrısı için, hangi politikalar tetiklendi ve ne kararı döndürdü +- **Araç çağrıları** - Claude'un çağırdığı her araç, girişi ve çıkışıyla +- **Politika aktivitesi** - Her araç çağrısı için hangi politikaların ateşlendiği ve ne kararı döndüğü -Üstteki istatistik çubuğu oturum süresini, toplam araç çağrılarını ve kanca kararlarının bir özetini gösterir (allow / deny / instruct sayıları). +Üstteki istatistik çubuğu, oturum süresini, toplam araç çağrı sayısını ve kanca kararlarının bir özetini (izin / reddet / talimat sayıları) gösterir. -Oturumu dışa aktarmak için **İndirme Günlükleri** düğmesini tıklayın. Claude Code, Codex, Copilot, Cursor, Pi ve Gemini oturumları için orijinal disk üzerindeki JSONL transkriptini bayt-bayt alırsınız; OpenCode (oturumları diskte değil SQLite'de yaşayan) için temel `session` / `messages` / `parts` tablolarını yansıtan bir JSON belgesi alırsınız. +Oturumu dışa aktarmak için **Günlükleri İndir** düğmesini tıklayın. Claude Code, Codex, Copilot, Cursor ve Pi oturumları için diskteki özgün JSONL transcript'ini bayt-bayt alırsınız; OpenCode için (oturumları diskte değil SQLite'de yaşar) temel `session` / `messages` / `parts` tablolarını yansıtan bir JSON belgesi alırsınız. ### Denetim -Aracınızın geçmiş oturumlar arasında gerçekten nasıl davrandığına dair kişilik odaklı bir rapor. `failproofai audit` CLI ile aynı taramasını çalıştırır ancak bunu tek ekran paylaşılabilir poster + aşağıya katlanmış dört bölüm olarak işler: +Aracınızın geçmiş oturumlar arasında gerçekten nasıl davrandığına ilişkin kişilikli bir rapor. `failproofai audit` CLI ile aynı taramayı çalıştırır ancak bunu tek ekranlı paylaşılabilir bir poster + aşağıya kıvrılan dört bölüm olarak render eder: -1. **Poster** — ilk görünüm penceresini doldurur. failproof_ai sözcüğü işareti + denetim etiketi ile kendi içinde PNG yakalama bölgesi · arketip indeksi (`№ NN of 08`) + denetim tarihi · sayısal puan (0–100) + yüzdelik sıra hapı (`top 15%`) · arketip adı (`the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost` arasından biri) + 3 anahtar kelime şeridi · `// only N% of agents are this archetype` nadir bulunma satırı · 8×8 piksel sigil döşemesi · `audit yours → failproof.ai` alt bilgisi. Üç paylaş düğmesi yakalama kutusunun hemen dışında yer alır: `post your archetype` (X niyeti), `share on linkedin`, `download poster`. Yakalama `html-to-image` üzerinden çalışır, bu nedenle PNG ekranda işlenen görüntüyle piksel-piksel eşleşir (kesik çizgili sınırlar, SVG logo maskesi, degradeler, yazı tipi ölçümleri — hepsi korunur). -2. **Güçlü Yönler** — sakin ✓ satır listeniz, aracınızın zaten doğru yaptığı davranışlardan, canlı denetim verilerinden türetilmiş (temiz araç çağrısı oranı, ana hala doğrudan itilme yok, kimlik bilgisi sızıntısı yok, yeniden deneme fırtınaları yok) — her biri yalnızca ilgili politika denetim penceresi arasında temiz bir kayda sahip olduğunda ortaya çıkar. -3. **Tuhaflıklar** — sızdı, ciddiyet ve sıralanmışlık tablosu: `when · what slipped + the policy that would've caught it · severity pill · seen`, burada yineleme `new` (bir kez), `N× seen` (2–9 kez) veya `recurring` (10+) olarak okunur. -4. **Nasıl iyileştirilir** — sakin satır listesi, önerilen her politika için bir tane: politika adı beyazda, tek satırlı açıklama, yükleme komutu + sağ tarafta kopyala düğmesi. Bölüm başlığı `enable all N → projected · ` (her onarım uygulandıktan sonra ulaşacağınız puan) olarak okunur ve `[install all]` düğmesi önerilen tüm politikalar için birleştirilmiş `failproofai policy add a b c …` komutunu kopyalar. -5. **Daha iyi dön** — yan yana iki kart. Sol: bir anımsatıcı ayarla (`3d` / `7d` / `14d` / `30d` cadence seçici; `/api/auth/reminder` üzerinden kimlik doğrulaması yapıldıktan sonra kalıcıdır). Sağ: failproof avantajlarının kilidini aç — `invite a friend` virgül/boşluk/satır sonu ile ayrılmış bir arkadaş e-posta listesini (gönderme başına maksimum 10) alan ve `/api/audit/invite` adresine POSTlayan bir modal açar, bu da api-sunucusunun `POST /v0/invite` adresine iletir. API sunucusu her alıcıya `invite@failproof.ai` adresinden bir e-posta gönderir, gönderici Cc'd ve `Reply-To` ayarlanmıştır, bu nedenle alıcı kimin kendilerini davet ettiğini görür ve gönderici gelen kutusuna bir kopya alır. Anonim kullanıcılar gönderenin e-postası bilinmeden önce davetler gönderilmeyecek şekilde `AuthDialog` üzerinden yönlendirilir. Hak/avantajlar karşılanması bir takip görevidir. +1. **Poster** — ilk viewport'u doldurur. failproof_ai sözcüğü işareti + denetim etiketi içeren bağımsız PNG yakalama bölgesi · arketip dizini (`№ NN of 08`) + denetim tarihi · sayısal puan (0–100) + yüzdelik sıra hapı (`top 15%`) · arketip adı (`the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost` içinden biri) + 3 anahtar kelime şeridi · `// only N% of agents are this archetype` nadirlik satırı · 8×8 piksel sigil döşeme · `audit yours → failproof.ai` altbilgisi. Üç paylaşım düğmesi yakalama kutusunun hemen dışında yer alır: `post your archetype` (X intent), `share on linkedin`, `download poster`. Yakalama `html-to-image` aracılığıyla çalışır, böylece PNG ekrandaki renderi piksel-için-piksel eşleştirir (kesikli kenarlıklar, SVG logo maskesi, degradeler, yazı tipi ölçümleri — tümü korunur). +2. **Güçlü Yönler** — sakin ✓ satır listesi aracınızın zaten iyi yaptığı davranışlar, canlı denetim verilerinden türetilir (temiz araç çağrı oranı, ana hatta doğrudan push yok, sıfır kimlik bilgisi sızıntısı, sıfır yeniden deneme fırtınaları) — her biri yalnızca ilgili politika denetim penceresinde temiz bir kayda sahip olduğunda sunulur. +3. **Tuhaflıklar** — kayıp olanların tablosu, önem derecesine göre sıralanmış: `when · what slipped + the policy that would've caught it · severity pill · seen`, burada yineleme `new` (bir kez), `N× seen` (2–9 kez) veya `recurring` (10+) olarak okunur. +4. **Nasıl İyileştirilir** — sakin satır listesi, önerilen her politika için birer tane: politika adı beyaz, tek satırlık açıklama, yükleme komutu + sağ tarafta kopyala düğmesi. Bölüm başlığı `enable all N → projected · ` olarak okunur (her düzeltme uygulandığında ulaşacağınız puan), ve `[install all]` düğmesi her önerilen politika için birleştirilmiş `failproofai policy add a b c …` komutunu kopyalar. +5. **Daha iyi geri dön** — yan yana iki kart. Sol: anımsatıcı ayarla (`3d` / `7d` / `14d` / `30d` cadence seçici; `/api/auth/reminder` aracılığıyla kimlik doğrulandıktan sonra devam eder). Sağ: failproof avantajlarının kilidini aç — `invite a friend` virgül/boşluk/satırsonu ayrılmış arkadaş e-postalarının bir listesini alan bir modal açar (gönderim başına en fazla 10), onları `/api/audit/invite` adresine POSTlar, bu da api-sunucusunun `POST /v0/invite` adresine iletilir. API sunucusu, `invite@failproof.ai` adresinden alıcı başına bir e-posta gönderir ve gönderici Cc'lenmiş ve `Reply-To` ayarlanmıştır, böylece alıcı kimi davet ettiğini ve gönderici gelen kutusunda bir kopya alır. Anonim kullanıcılar, davetler gönderilmeden önce gönderenin e-postası bilinebilmesi için `AuthDialog` aracılığıyla yönlendirilir. Hak / avantaj karşılanması takip edilecektir. -`failproofai audit` çalışma zamanı tarafından yönlendirilir — temel tarama motorunu, desteklenen bayrakları ve transkript başına önbellek değişmezlerini [Denetim CLI](/tr/cli/audit) adresinde görün. Pano en son sonucu `~/.failproofai/audit-dashboard.json` adresinde önbelleğe alır (mod `0600`, tek yuva, yeni çalıştırmalar üzerine yazar) böylece yeniden ziyaretler anlıktır; **hem transkript başına hem de bütün sonuç önbellekleri okuma sırasında 7 günden daha eski olduğunda reddedilir**, bu nedenle pano hiçbir zaman sessizce bir hafta eski sonuç sunmaz — TTL geçtikten sonra `/audit` boş durumuna düşer ve taze bir çalıştırma istenir. Raporun alt kısmına yakınında `[ re-audit now ]` öğesini tıklatmak `/api/audit/run` öğesine `noCache: true` ile POSTlar — yeniden denetim transkript başına önbelleği atlar ve her transkripti sessizce yapılan sonucu döndürmek yerine sıfırdan yeniden tarar — ve pano çalıştırma bitene kadar `/api/audit/status` adresini 1Hz'de yoklar; çalıştırma sırasında yapışkan pembe ilerleme şeridi görünüm penceresinin en üstüne sabitlenir ve geçen zamanlı sayaçla birlikte taze sonuç başarıda yerinde değişir (tam sayfa yeniden yüklemesi yok; başarısız yeniden denetim önceki raporu bozulmamış bırakır). Arızada şerit kırmızıya döner ve `RerunError.kind` kapalı kopya (`timeout` / `network` / `post_failed`). Boş durum (önbellek yok veya süresi dolmuş) ve sıfır oturum durumu (önbellek var ama tarama hiçbir transkript bulmadı) ayrı ayrı ortaya çıkarılır. +`failproofai audit` çalışma zamanı tarafından yürütülür — temel tarama motoru, desteklenen bayraklar ve transcript başına önbellek değişmezleri için [Audit CLI](/tr/cli/audit) adresine bakın. Kontrol paneli en son sonucu `~/.failproofai/audit-dashboard.json` adresinde önbelleğe alır (mod `0600`, tek yuva, yeni çalışmalar üzerine yazar), böylece yeniden ziyaretler anlıktır; **hem transcript başına hem de tam sonuç önbellekleri okumada 7 günden eski olduğunda reddedilir**, bu nedenle kontrol paneli asla sessizce bir haftalık önbelleğe alınmış sonuç sunmaz — TTL geçdikten sonra `/audit` boş durumuna düşer ve yeni bir çalışma ister. Rapordaki alt bölümün yakınında `[ re-audit now ]` öğesine tıklamak `/api/audit/run` adresine `noCache: true` ile POSTlar — yeniden denetim transcript başına önbelleği atlar ve her transcript'i sıfırdan yeniden tarar, sessizce önbelleğe alınan sonucu döndürmek yerine — ve kontrol paneli çalışma bitene kadar 1Hz'de `/api/audit/status` adresini yoklar; çalışma sırasında yapışkanlı bir pembe ilerleme şeridi viewport'un üstüne yapışırken geçen bir zamanlayıcı ile birlikte görüntülenir ve başarı sonrasında taze sonuç yerinde değiştirilir (tam sayfa yeniden yükleme yok; başarısız yeniden denetim önceki raporu bozulmamış halde bırakır). Başarısızlık durumunda şerit `RerunError.kind` (`timeout` / `network` / `post_failed`) anahtar alınan kopyayla kırmızı olur. Boş durum (önbellek yok veya süresi dolmuş) ve sıfır oturum durumu (önbellek var ancak tarama transcript bulamadı) ayrı olarak gösterilir. ### Politikalar -Politikaları yönetmek ve etkinliği gözden geçirmek için iki sekmeli bir sayfa. +Politikaları yönetmek ve aktiviteyi gözden geçirmek için iki sekmelik bir sayfa. - - Tek bir panelden hangi aracı CLI'lerin failproofai tarafından korunacağını çoklu seçim yapın — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI ve Hermes'in hepsinin yükleme durumu (`Active` / `Detected` / `Inactive`) olan bir satırı, kullanıcı kapsamı ayarları yolu ve marka renkli vurguyu vardır. İstediğiniz CLI'leri işaretleyin veya işareti kaldırın ve farkı bir adımda yüklemek/kaldırmak için `Apply changes` öğesine tıklayın. İkili PATH'de algılanan CLI'ler önceden işaretlenmiş. - - Tek tıklamayla bireysel politikaları açıp kapatın (`~/.failproofai/policies-config.json` adresine yazar — tüm yüklü CLI'ler arasında paylaşılır) - - Parametrelerini yapılandırmak için bir politikayı genişletin (`policyParams` destekleyen politikalar için) - - Özel politika dosyası yolunu ayarla + - Tek bir panelden failproofai'nin hangi aracı CLI'lerini koruduğunu çok seçili — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi ve Hermes'in her birinin yükleme durumlu bir satırı vardır (`Active` / `Detected` / `Inactive`), kullanıcı kapsamı ayarları yolu ve marka renkli vurgu. İstediğiniz CLI'leri işaretleyin veya işareti kaldırın ve `Apply changes` adına tıklayarak farklılığı tek adımda yükleyin/kaldırın. PATH'de ikili dosyası algılanan CLI'ler önceden işaretlenir. + - Bireysel politikaları tek tıklamada açın veya kapatın (yazma yapılır `~/.failproofai/policies-config.json` — yüklü tüm CLI'ler arasında paylaşılır) + - Bir politikayı genişleterek parametrelerini yapılandırın (`policyParams` destekleyen politikalar için) + - Özel politika dosya yolu ayarla - - - Tüm oturumlar arasında tetiklenen her kanca olayının tam sayfalı geçmişi - - Karar, olay türü, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), politika adı veya oturum ID'ye göre filtrele - - Her satır şunları gösterir: zaman damgası, politika adı, karar, CLI rozeti (turuncu = Claude Code, mor = OpenAI Codex, mavi = GitHub Copilot, zümrüt = Cursor Agent, kehribar = OpenCode, pembe = Pi, gökyüzü = Gemini CLI, çivit = Hermes), araç adı, oturum ID ve deny/instruct kararları için neden - - Transkripti açmak için bir oturum ID'sine tıklayın — görüntüleyici hangi CLI'nin kancayı tetiklediğini otomatik algılar (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) ve başlıkta eşleşen CLI rozetini işler + + - Tüm oturumlar arasında ateşlenen tüm kanca olaylarının tam sayfalandırılmış geçmişi + - Kararı, olay türü, CLI'yi (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), politika adını veya oturum kimliğini filtreleyin + - Her satır şunları gösterir: zaman damgası, politika adı, karar, CLI rozeti (turuncu = Claude Code, mor = OpenAI Codex, mavi = GitHub Copilot, yeşilimsi = Cursor Agent, kehribar = OpenCode, pembe = Pi, indigo = Hermes, deniz mavisi = OpenClaw, gül = Factory Droid, menekşe = Devin, cam = Antigravity, açık yeşil = Goose), araç adı, oturum kimliği ve reddet/talimat kararları için neden + - Transcript'i açmak için bir oturum kimliğine tıklayın — görüntüleyici kancayı ateşleyen CLI'yi otomatik olarak algılar (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) ve başlıkta eşleşen CLI rozetini render eder @@ -92,13 +92,13 @@ Politikaları yönetmek ve etkinliği gözden geçirmek için iki sekmeli bir sa ## Otomatik yenileme -Panonun üst gezinmesinde otomatik yenileme değiştirici vardır. Etkinleştirildiğinde, geçerli sayfa yeni oturumları ve politika etkinliğini göstermek için periyodik olarak yenilenir. Uzun süren otonom aracı oturumlarını izlemek için gereklidir. +Kontrol panelinin üst gezintisinde otomatik yenileme anahtarı vardır. Etkinleştirildiğinde, geçerli sayfa, yeni oturumlar ve politika aktivitesi göründüğünde periyodik olarak yenilenir. Uzun süreli özerk aracı oturumlarını izlemek için gereklidir. --- ## Sayfaları devre dışı bırakma -Panonun yalnızca bazı parçalarına ihtiyacınız varsa, `FAILPROOFAI_DISABLE_PAGES` öğesini virgülle ayrılmış sayfa adları listesine ayarlayın: +Kontrol panelinin yalnızca bazı kısımlarına ihtiyacınız varsa, `FAILPROOFAI_DISABLE_PAGES` adını virgülle ayrılmış sayfa adları listesine ayarlayın: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -108,9 +108,9 @@ Geçerli değerler: `policies`, `projects`, `audit`. --- -## Projeler yolunun yapılandırılması +## Proje yolunu yapılandırma -Varsayılan olarak, pano standart Claude Code projeleri dizininden okur. Özel kurulumlar için geçersiz kılın: +Varsayılan olarak, kontrol paneli standart Claude Code projeleri dizininden okur. Özel kurulumlar için bunu geçersiz kılın: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -118,21 +118,21 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai --- -## Localhost olmayan bir konaktan erişim +## Localhost olmayan bir ana bilgisayardan erişim -Panoyu **geliştirme modunda** (`npm run dev`) çalıştırırken ve `localhost` dışında bir ana bilgisayar adından erişirken — örneğin, özel bir etki alanı, uzak bir IP veya tünel oluşturulmuş bir URL — şöyle bir uyarı görebilirsiniz: +Kontrol panelini **dev modunda** (`npm run dev`) çalıştırırken ve örneğin özel bir alan adı, uzak bir IP veya tüneteli bir URL gibi `localhost` dışında bir ana bilgisayar adından erişirken, aşağıdaki gibi bir uyarı görebilirsiniz: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Bu, Next.js'nin HMR (sıcak modül yeniden yüklemesi) websocketine çapraz kökenli erişimi engeller, bu da sadece geliştirme özelliğidir. Konağınıza izin vermek için `--allowed-origins` bayrağını kullanın: +Bu, Next.js'nin HMR (sıcak modül yeniden yükleme) websocket'ine çapraz kaynaklı erişimi engellemesidir; bu, yalnızca dev özelliğidir. Ana bilgisayarınıza izin vermek için `--allowed-origins` bayrağını kullanın: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -Birden çok ana bilgisayar veya IP için virgülle ayrılmış bir liste geçirin: +Birden fazla ana bilgisayar veya IP için virgülle ayrılmış bir liste iletin: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 @@ -145,5 +145,5 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev ``` -Bu yalnızca geliştirme modunda geçerlidir. `failproofai` (üretim modu) çalıştırılırken HMR websocket'i ve çapraz kökenli geliştirme kaynağı sorunu yoktur. +Bu yalnızca dev moduna uygulanır. `failproofai` çalıştırırken (üretim modu), HMR websocket'i ve çapraz kaynaklı dev kaynak sorunu yoktur. \ No newline at end of file diff --git a/docs/tr/getting-started.mdx b/docs/tr/getting-started.mdx index 16429282..c060dd67 100644 --- a/docs/tr/getting-started.mdx +++ b/docs/tr/getting-started.mdx @@ -1,13 +1,13 @@ --- title: Başlarken -description: "failproofai'ı kurun, politikaları etkinleştirin ve ajanlarınızın güvenilir şekilde çalışmasını sağlayın" +description: "failproofai'ı kurun, politikaları etkinleştirin ve aracılarınızın güvenilir bir şekilde çalışmasını sağlayın" icon: rocket --- ## Gereksinimler - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (isteğe bağlı - yalnızca kaynaktan derlemek için gerekli) +- **Bun** >= 1.3.0 (isteğe bağlı - yalnızca kaynaktan derleme için gerekli) --- @@ -31,15 +31,15 @@ bun add -g failproofai - Politikalar, ajanın her araç çağrısından önce ve sonra çalışan kurallardır. Yıkıcı komutları, gizli bilgi sızıntılarını ve hasara neden olmadan diğer başarısızlık modlarını yakalar. + Politikalar, her aracı araç çağrısından önce ve sonra çalışan kurallardır. Yıkıcı komutları, gizli bilgi sızıntısını ve hasar oluşturmadan önce diğer arıza modlarını yakalarlar. ```bash failproofai policies --install ``` - Bu, yüklü ajan CLI'lerinize hook girişleri yazar (Claude Code'un `~/.claude/settings.json`, OpenAI Codex'in `~/.codex/hooks.json`, GitHub Copilot CLI'nin `~/.copilot/hooks/failproofai.json`, Cursor Agent'ın `~/.cursor/hooks.json`, OpenCode'un `~/.config/opencode/plugins/failproofai.mjs` konumundaki oluşturulmuş plugin shim'i ve `~/.config/opencode/opencode.json` dosyasındaki `plugin` dizisinde bir kayıt girişi, Pi'nin `~/.pi/agent/settings.json`, Gemini CLI'nin `~/.gemini/settings.json` veya Hermes'in `~/.hermes/config.yaml` dosyası). Birden fazla varsa size sorulacak; `--cli claude codex copilot cursor opencode pi gemini hermes` (herhangi bir alt küme) geçerek sorguyu atlayabilirsiniz. + Bu, kurulan aracı CLI'lerine kanca girdileri yazar (Claude Code'un `~/.claude/settings.json`, OpenAI Codex'in `~/.codex/hooks.json`, GitHub Copilot CLI'nin `~/.copilot/hooks/failproofai.json`, Cursor Agent'ın `~/.cursor/hooks.json`, OpenCode'un `~/.config/opencode/plugins/failproofai.mjs` konumundaki oluşturulan eklenti dolgusunu ve `~/.config/opencode/opencode.json` içindeki `plugin` dizisine kayıt girişini, Pi'nin `~/.pi/agent/settings.json`, Hermes'in `~/.hermes/config.yaml`, OpenClaw'un `~/.openclaw/openclaw.json`, Factory Droid'in `~/.factory/hooks.json`, Devin CLI'nin `~/.config/devin/config.json`, Antigravity CLI'nin `~/.gemini/config/hooks.json` veya Goose'un `~/.agents/plugins/failproofai/hooks/hooks.json` konumundaki otomatik keşfedilen eklenti dizinine). Birden fazlası mevcut olduğunda size sorulur; `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (herhangi bir alt küme) geçirerek soruyu atlatabilirsiniz. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi ve Gemini CLI desteği **beta** aşamasındadır — `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi` veya `--cli gemini` ile kurun. Hermes (hermes-agent, bir Slack/Telegram ağ geçidi) `--cli hermes` ile kullanıcı kapsamında yüklenir ve **ayrıca** çevrimdışı bir denetim kaynağıdır. + GitHub Copilot CLI, Cursor Agent, OpenCode ve Pi desteği **beta** sürümündedir — `--cli copilot`, `--cli cursor`, `--cli opencode` veya `--cli pi` ile kurun. Hermes (hermes-agent, bir Slack/Telegram ağ geçidi) `--cli hermes` ile kullanıcı kapsamında kuruluyor ve **aynı zamanda** çevrimdışı denetim kaynağıdır. OpenClaw (openclaw ağ geçidi, kendi kendine barındırılan çok kanallı asistan) `--cli openclaw` ile kullanıcı kapsamında kuruluyor — zorunlu kılma, işlem içi eklenti kancaları aracılığıyla gerçekleşiyor (`before_agent_finalize` gerçek bir tur sonu kapısıdır, bu nedenle `require-*-before-stop` yerleşik özellikleri zorunlu kılar) — ve **aynı zamanda** çevrimdışı denetim kaynağıdır. Factory Droid (`droid`) `--cli factory` ile kuruluyor (kullanıcı + proje kapsamı) ve **aynı zamanda** çevrimdışı denetim kaynağıdır. Devin CLI (`devin`, Cognition) `--cli devin` ile kuruluyor (kullanıcı + proje kapsamı) ve **aynı zamanda** çevrimdışı denetim kaynağıdır. Antigravity CLI (`agy`) `--cli antigravity` ile kuruluyor (kullanıcı + proje kapsamı) ve **aynı zamanda** çevrimdışı denetim kaynağıdır. Goose (kod adı goose, Block) `--cli goose` ile kuruluyor (kullanıcı + proje kapsamı) — yükleyici sadece `~/.agents/plugins/failproofai/` konumuna bir eklenti dizini bırakır, bu da Goose tarafından otomatik olarak keşfedilir ve **aynı zamanda** çevrimdışı denetim kaynağıdır. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -65,10 +69,10 @@ bun add -g failproofai failproofai ``` - Oturumları göz atabilir, araç çağrılarını inceleyebilir ve politikaları yönetebileceğiniz `http://localhost:8020` konumundaki yerel bir panoyu açar. + `http://localhost:8020` konumunda yerel bir pano açar; burada oturumları tarayabilir, araç çağrılarını inceleyebilir ve politikaları yönetebilirsiniz. - - Claude Code'u her zamanki gibi başlatın. Ajan riskli bir şey denerse, failproofai bunu otomatik olarak durdurur. Bunu çalıştırılır durumda bırakın ve panoda ne olduğunu gözden geçirin. + + Claude Code'u normal olarak başlatın. Aracı riskli bir şey denerse, failproofai bunu otomatik olarak engeller. Onu izlenmeyen bir şekilde çalıştırmaya devam edin ve panoda ne olduğunu gözden geçirin. @@ -76,19 +80,19 @@ bun add -g failproofai ## Politikalar nasıl çalışır -Ajan bir araç her çalıştırdığında, Claude Code failproofai'ı bir alt işlem olarak çağırır: +Aracı bir araç çalıştırırsa, Claude Code failproofai'ı bir alt işlem olarak çağırır: ```text Claude Code → failproofai --hook PreToolUse → stdin JSON'ı okur politikaları değerlendirir - kararı stdout'a yazar + stdout'a karar yazar ``` Her politika üç karardan birini döndürür: -- **allow** - ajan normal şekilde devam eder -- **deny** - eylem engellenir, ajanına neden engelleneceği söylenir -- **instruct** - ajanın isteminine ek bağlam eklenir +- **allow** - aracı normal olarak devam eder +- **deny** - eylem engellenir, aracıya neden olduğu söylenir +- **instruct** - aracının istemesine ek bağlam eklenir Politikalar yerel işleminizde çalışır. Hiçbir şey uzak bir hizmete gönderilmez. @@ -98,16 +102,16 @@ Politikalar yerel işleminizde çalışır. Hiçbir şey uzak bir hizmete gönde ## Kural tabanlı politikalarla ekip politikaları ayarlayın -Ekibiniz genelinde kalite standartları oluşturmanın en hızlı yolu `.failproofai/policies/` kuralıdır. Bu dizine politika dosyalarını bırakın ve otomatik olarak yüklenir — bayrak yok, yapılandırma değişikliği yok, kurulum komutu yok. +Ekibiniz genelinde kalite standartları oluşturmanın en hızlı yolu `.failproofai/policies/` kuralıdır. Politika dosyalarını bu dizine bırakın ve otomatik olarak yüklenir — bayrak yok, yapılandırma değişikliği yok, kurulum komutu yok. - + ```bash mkdir -p .failproofai/policies ``` - Başlangıç örneklerini kopyalayın veya kendi dosyalarınızı yazın: + Başlangıç örneklerini kopyalayın veya kendinizinkini yazın: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ @@ -125,25 +129,25 @@ Ekibiniz genelinde kalite standartları oluşturmanın en hızlı yolu `.failpro fn: async (ctx) => { if (ctx.toolName !== "Bash") return allow(); if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) { - return instruct("Run tests before committing."); + return instruct("Uygulamalı testler çalıştırın."); } return allow(); }, }); ``` - + ```bash git add .failproofai/policies/ - git commit -m "Add team quality policies" + git commit -m "Ekip kalite politikaları ekle" ``` - failproofai yüklü olan her ekip üyesi bu politikaları otomatik olarak alır. Geliştirici başına kurulum gerekmez. + failproofai'ın kurulu olduğu her ekip üyesi bu politikaları otomatik olarak alır. Geliştirici başına kurulum gerekmez. -Tüm ekibin aynı standartları paylaşması için `.failproofai/policies/` dizinini deponuza işleyin. Ekibiniz yeni başarısızlık modları keşfettikçe politika ekleyin ve gönderin — herkes bir sonraki `git pull` işleminde güncellemeyi alır. Zamanla bu politikalar, sürekli iyileşen ve ekibi güvende tutan canlı bir kalite standardı haline gelir. +`.failproofai/policies/` dizinini deponuza gönderin, böylece tüm ekip aynı standartları paylaşır. Ekibiniz yeni arıza modları keşfettikçe, politikalar ekleyin ve gönderin — herkes bir sonraki `git pull` konumunda güncellemeyi alır. Zamanla bu politikalar, gelişmeye devam eden ve ekibi güvenli tutan bir yaşayan kalite standardı haline gelir. --- @@ -152,13 +156,13 @@ Tüm ekibin aynı standartları paylaşması için `.failproofai/policies/` dizi Tüm yapılandırma ve günlükler makinenizde kalır: -| Yol | Ne depolar | -|------|------------| -| `~/.failproofai/policies-config.json` | Genel politika yapılandırması | -| `~/.failproofai/hook-activity.jsonl` | Hook yürütme geçmişi | -| `~/.failproofai/hook.log` | Özel hook hataları için hata ayıklama günlüğü | -| `.failproofai/policies-config.json` | Proje başına yapılandırma (işlenmiş) | -| `.failproofai/policies-config.local.json` | Kişisel geçersiz kılmalar (gitignore) | +| Yol | Ne depoladığı | +|------|----------------| +| `~/.failproofai/policies-config.json` | Global politika yapılandırması | +| `~/.failproofai/hook-activity.jsonl` | Kanca yürütme geçmişi | +| `~/.failproofai/hook.log` | Özel kanca hataları için hata ayıklama günlüğü | +| `.failproofai/policies-config.json` | Proje başına yapılandırma (kaydedildi) | +| `.failproofai/policies-config.local.json` | Kişisel geçersiz kılmalar (gitignored) | --- @@ -168,7 +172,7 @@ Tüm yapılandırma ve günlükler makinenizde kalır: failproofai policies --uninstall ``` -`~/.claude/settings.json` dosyasından hook girişlerini kaldırır. `~/.failproofai/` içindeki yapılandırma dosyaları korunur. +`~/.claude/settings.json` konumundan kanca girdilerini kaldırır. `~/.failproofai/` konumundaki yapılandırma dosyaları tutulur. --- @@ -181,14 +185,14 @@ failproofai policies --uninstall - Parameterlerle 26 politikanın tümü + Parametreleri olan tüm 26 politika JavaScript'te kendi politikalarınızı yazın - + Oturumları izleyin ve politika etkinliğini gözden geçirin diff --git a/docs/tr/introduction.mdx b/docs/tr/introduction.mdx index 526ec330..8441196d 100644 --- a/docs/tr/introduction.mdx +++ b/docs/tr/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI, AI ajanlarına döngüleri, gizli dizi sızıntılarını, yıkıcı araç çağrılarını ve daha fazlasını tek bir kurulumda yakalaması için 39 yerleşik başarısızlık politikası sağlar." +description: "FailproofAI, AI ajanlarına tek bir kurulumda döngüleri, gizli sızıntılarını, yıkıcı araç çağrılarını ve daha birçok şeyi yakalayan 39 yerleşik hata politikası sunar." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -**AI başarısızlık işleme**, **hata kurtarma** ve **LLM güvenilirliği** için hook'lar ve politikalar. AI ajanlarınızı **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes** ve **Agents SDK** arasında güvenilir ve otonom halde tutun. +**AI hata yönetimi**, **hata kurtarması** ve **LLM güvenilirliği** için kancalar ve politikalar. AI ajanlarınızı güvenilir tutun ve **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI** ve **Agents SDK** genelinde otonom olarak çalıştırın. -AI ajanları tahmin edilebilir şekillerde başarısız olur. Yıkıcı komutlar çalıştırırlar, sırları sızıntıya uğratırlar, görevlerinden saparlar, döngülere takılırlar ya da doğrudan ana dala push yaparlar. Gözetimsiz bırakıldığında, küçük başarısızlıklar kesintilere, sızıntıya uğramış kimlik bilgilerine ve kayıp işlere dönüşür. +AI ajanları tahmin edilebilir şekillerde başarısız olur. Yıkıcı komutlar çalıştırırlar, sırları sızdırırlar, görevden saparlar, döngülere takılırlar veya doğrudan ana dala gönderirler. Gözetimsiz bırakılırsa, küçük arızalar kesintilere, sızan kimlik bilgilerine ve kaybedilen çalışmalara dönüşebilir. -FailproofAI bunu **politikalar** ile çözer. Bu kurallar, her ajan araç çağrısına hook olarak **başarısızlıkları algılamak**, **onları hafifletmek** (engelle, talimat ver, temizle) ve **dikkat gereken bir şey olduğunda sizi uyarmak** için bağlanır. Yerel bir pano, daha sonra her araç çağrısını, ajan başarısızlığını ve kurtarma eylemini incelemenizi sağlar. +FailproofAI bunu **politikalar** ile çözer. Bu kurallar, her ajan araç çağrısına kanca kurarak **arızaları tespit eder**, **bunları azaltır** (engelle, talimata et, sterilize et) ve **dikkat gereken bir şey olduğunda sizi uyarır**. Yerel bir gösterge paneli, sonrasında her araç çağrısını, ajan arızasını ve kurtarma eylemini incelemenize olanak tanır. -Hiçbir veri makinenizi terk etmez. +Hiçbir veri makinenizden çıkmaz. ## Başlayın - Yıkıcı komutları engelle, gizli dizi sızıntılarını önle, ajanları proje sınırları içinde tut ve daha fazlasını yap. Hepsi hazır olarak. + Yıkıcı komutları engelle, gizli sızıntılarını önle, ajanları proje sınırları içinde tut ve daha birçok şey. Hepsi hazır olarak. - Basit allow / deny / instruct API'si ile JavaScript'te kendi kurallarını yaz. + Basit bir allow / deny / instruct API'sı ile JavaScript'te kendi kurallarını yaz. - Ajanlarınız yokken neler yaptığını gör. Oturumları gözat, araç çağrılarını incele, politikaların nereden tetiklendiğini incele. + Ajanlarınızın yokken ne yaptığını gör. Oturumları gezin, araç çağrılarını incele, politikaların nerede tetiklendiğini gözden geçir. - Herhangi bir politikayı kod yazmadan ayarla. İzin listelerini, korunan dalları ya da eşikleri proje başına veya genel olarak ayarla. + Herhangi bir politikayı kod yazmadan ayarla. İzin listeleri, korumalı dallar veya eşikleri proje başına veya global olarak belirle. @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # politikaları etkinleştir (ya da atla — failproofai ilk çalıştırmada kurulumu teklif edecektir) -failproofai # panoyu başlat +failproofai policies --install # politikaları etkinleştir (veya atla — `failproofai` ilk çalıştırmada bunları ayarlamayı teklif edecek) +failproofai # gösterge panelini başlat ``` -Tüm kılavuz için [Başlarken](/tr/getting-started) rehberine bakın. \ No newline at end of file +Tam açıklamayı için [Başlangıç](/tr/getting-started) kılavuzuna bakın. \ No newline at end of file diff --git a/docs/vi/built-in-policies.mdx b/docs/vi/built-in-policies.mdx index b7eb5873..bcbdc1f6 100644 --- a/docs/vi/built-in-policies.mdx +++ b/docs/vi/built-in-policies.mdx @@ -1,43 +1,39 @@ --- -title: Các chính sách tích hợp sẵn -description: "Tất cả 39 chính sách tích hợp sẵn bắt được các chế độ lỗi thông thường của agent" +title: Chính sách tích hợp sẵn +description: "Tất cả 39 chính sách tích hợp sẵn giúp bắt các lỗi phổ biến của agent" icon: shield --- -failproofai được trang bị 39 chính sách tích hợp sẵn bắt được các chế độ lỗi thông thường của agent. Mỗi chính sách được kích hoạt trên một loại sự kiện hook cụ thể và tên công cụ. Mười chín chính sách chấp nhận các tham số cho phép bạn tinh chỉnh hành vi của chúng mà không cần viết mã. Năm chính sách quy trình làm việc thực thi đường dẫn commit → push → PR → CI trước khi Claude dừng lại. +failproofai đi kèm với 39 chính sách tích hợp sẵn giúp bắt các lỗi phổ biến của agent. Mỗi chính sách kích hoạt trên một loại sự kiện hook cụ thể và tên công cụ. Mười chín chính sách chấp nhận các tham số cho phép bạn điều chỉnh hành vi mà không cần viết code. Năm chính sách quy trình làm việc thực thi một quy trình commit → push → PR → CI trước khi Claude dừng lại. --- ## Tổng quan -Các chính sách được nhóm vào các danh mục: +Các chính sách được nhóm thành các danh mục: -| Danh mục | Chính sách | Loại hook | +| Danh mục | Chính sách | Loại Hook | |----------|-----------|-----------| -| [Lệnh nguy hiểm](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | -| [Lệnh cơ sở hạ tầng](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [Bí mật (sanitizers)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | -| [Môi trường](#environment) | block-env-files, protect-env-vars | PreToolUse | -| [Truy cập tệp](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | +| [Lệnh nguy hiểm](#lệnh-nguy-hiểm) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | +| [Lệnh cơ sở hạ tầng](#lệnh-cơ-sở-hạ-tầng) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | +| [Bí mật (vệ sinh dữ liệu)](#bí-mật-vệ-sinh-dữ-liệu) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [Môi trường](#môi-trường) | block-env-files, protect-env-vars | PreToolUse | +| [Truy cập tệp](#truy-cập-tệp) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | -| [Cơ sở dữ liệu](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | -| [Cảnh báo](#warnings) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | -| [Trình quản lý gói](#package-managers) | prefer-package-manager | PreToolUse | -| [Quy trình làm việc](#workflow) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | +| [Cơ sở dữ liệu](#cơ-sở-dữ-liệu) | warn-destructive-sql, warn-schema-alteration | PreToolUse | +| [Cảnh báo](#cảnh-báo) | warn-large-file-write, warn-package-publish, warn-background-process, warn-global-package-install | PreToolUse | +| [Trình quản lý gói](#trình-quản-lý-gói) | prefer-package-manager | PreToolUse | +| [Quy trình làm việc](#quy-trình-làm-việc) | require-commit-before-stop, require-push-before-stop, require-pr-before-stop, require-no-conflicts-before-stop, require-ci-green-before-stop | Stop | -- **`block-`** — dừng agent không được tiếp tục. -- **`warn-`** — cung cấp ngữ cảnh bổ sung để agent có thể tự sửa chữa. -- **`sanitize-`** — loại bỏ dữ liệu nhạy cảm từ kết quả công cụ trước khi agent nhìn thấy. +- **`block-`** — ngăn agent tiếp tục. +- **`warn-`** — cung cấp cho agent ngữ cảnh bổ sung để nó có thể tự sửa lỗi. +- **`sanitize-`** — xóa dữ liệu nhạy cảm khỏi đầu ra công cụ trước khi agent thấy. ### Không gian tên -Mỗi chính sách sống trong một vị trí `/`. Các chính sách tích hợp sẵn thuộc về -không gian tên **`failproofai/`** — ví dụ: `failproofai/sanitize-jwt`. Không gian tên -ngăn chặn va chạm khi bạn cũng tải các chính sách tùy chỉnh hoặc của bên thứ ba -có tên ngắn tương tự. +Mỗi chính sách nằm trong một vị trí `/`. Các chính sách tích hợp sẵn thuộc về không gian tên **`failproofai/`** — ví dụ: `failproofai/sanitize-jwt`. Không gian tên này ngăn xung đột khi bạn cũng tải các chính sách tùy chỉnh hoặc của bên thứ ba với các tên rút gọn tương tự. -Trong cấu hình của bạn, bạn có thể tham chiếu đến một chính sách tích hợp sẵn bằng tên ngắn hoặc tên -đủ điều kiện; cả hai dạng đều giải quyết thành cùng một chính sách: +Trong cấu hình của bạn, bạn có thể tham chiếu một chính sách tích hợp sẵn bằng tên rút gọn hoặc tên đủ tiêu chí; cả hai dạng đều phân giải thành cùng một chính sách: ```json { @@ -48,35 +44,33 @@ Trong cấu hình của bạn, bạn có thể tham chiếu đến một chính } ``` -Nếu một tên không có `/`, failproofai coi nó thuộc về không gian tên mặc định -`failproofai`. Các tên đã chứa `/` (ví dụ: `myorg/foo`, -`custom/my-hook`) được giữ nguyên. +Nếu một tên không có `/`, failproofai coi nó thuộc về không gian tên mặc định `failproofai`. Tên chứa `/` (ví dụ: `myorg/foo`, `custom/my-hook`) được giữ nguyên. - **`require-`** — chặn sự kiện Stop cho đến khi các điều kiện được đáp ứng. --- -Mỗi chính sách hỗ trợ một trường `hint` tùy chọn trong `policyParams`. Hint được nối vào tin nhắn deny hoặc instruct mà Claude nhìn thấy, cung cấp hướng dẫn có thể hành động mà không sửa đổi mã chính sách. Hoạt động với các chính sách tích hợp sẵn, tùy chỉnh và theo quy ước. Xem [Configuration → hint](/vi/configuration#hint-cross-cutting) để biết chi tiết. +Mỗi chính sách hỗ trợ trường `hint` tùy chọn trong `policyParams`. Hint được nối thêm vào thông báo từ chối hoặc hướng dẫn mà Claude thấy, cung cấp hướng dẫn thực tế mà không cần sửa đổi code chính sách. Hoạt động với các chính sách tích hợp sẵn, tùy chỉnh và theo quy ước. Xem [Cấu hình → hint](/vi/configuration#hint-cross-cutting) để biết chi tiết. --- ## Lệnh nguy hiểm -Ngăn chặn agent chạy các thao tác khó hoàn tác hoặc có thể làm hỏng hệ thống chủ nhà. +Ngăn agent chạy các phép toán khó hoàn tác hoặc có thể làm hỏng hệ thống chủ. ### `block-sudo` **Sự kiện:** PreToolUse (Bash) **Mặc định:** Từ chối bất kỳ lệnh `sudo` nào. -Chặn các lần gọi bao gồm từ khóa `sudo`. Phối hợp mẫu được thực hiện trên các token lệnh được phân tích cú pháp, không phải chuỗi thô, để ngăn chặn bypass qua tiêm toán tử shell. +Chặn các lệnh gọi chứa từ khóa `sudo`. Khớp mẫu được thực hiện trên các token lệnh được phân tích cú pháp, không phải chuỗi thô, để ngăn vượt qua thông qua tiêm operator shell. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowPatterns` | `string[]` | `[]` | Tiền tố lệnh chính xác được phép. Mỗi mục được so khớp với các token argv được phân tích cú pháp. | +| `allowPatterns` | `string[]` | `[]` | Tiền tố lệnh chính xác được phép. Mỗi mục được so khớp với các token argv được phân tích. | **Ví dụ:** @@ -90,10 +84,10 @@ Chặn các lần gọi bao gồm từ khóa `sudo`. Phối hợp mẫu được } ``` -Với cấu hình này, `sudo systemctl status nginx` được phép, nhưng `sudo rm /etc/hosts` bị từ chối. +Với cấu hình này, `sudo systemctl status nginx` được cho phép, nhưng `sudo rm /etc/hosts` bị từ chối. -Các mẫu được so khớp với các token được phân tích cú pháp, không phải chuỗi lệnh thô. Điều này ngăn chặn bypass qua các toán tử shell được thêm vào (ví dụ: `sudo systemctl status x; rm -rf /` không khớp với `sudo systemctl status *`). +Các mẫu được so khớp với các token được phân tích, không phải chuỗi lệnh thô. Điều này ngăn vượt qua thông qua các operator shell được nối thêm (ví dụ: `sudo systemctl status x; rm -rf /` không khớp với `sudo systemctl status *`). --- @@ -107,7 +101,7 @@ Các mẫu được so khớp với các token được phân tích cú pháp, k | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowPaths` | `string[]` | `[]` | Đường dẫn an toàn để xóa đệ quy (ví dụ: `/tmp`). | +| `allowPaths` | `string[]` | `[]` | Các đường dẫn an toàn để xóa đệ quy (ví dụ: `/tmp`). | **Ví dụ:** @@ -143,9 +137,9 @@ Không có tham số. ## Lệnh cơ sở hạ tầng -Dừng các agent mã hóa chạy CLI cơ sở hạ tầng hoặc kích hoạt đường ống CI/CD. Tất cả các chính sách trong danh mục này là **opt-in** (`defaultEnabled: false`) — các agent hợp pháp cần gọi `kubectl`, `terraform`, v.v. sẽ không bị gián đoạn trừ khi bạn bật chính sách. Khi được bật, mỗi lần gọi CLI phù hợp bị từ chối trừ khi lệnh khớp với một mục trong `allowPatterns`. +Ngăn agent viết code chạy CLI cơ sở hạ tầng hoặc kích hoạt đường ống CI/CD. Tất cả các chính sách trong danh mục này là **tuỳ chọn** (`defaultEnabled: false`) — agent cần hợp pháp gọi `kubectl`, `terraform`, v.v. sẽ không bị gián đoạn trừ khi bạn bật chính sách. Khi bật, mỗi lệnh gọi của CLI phù hợp bị từ chối trừ khi lệnh khớp với một mục trong `allowPatterns`. -Ngữ pháp mẫu giống như [`block-sudo`](#block-sudo): các token được so khớp với argv được phân tích cú pháp, `*` là ký tự đại diện cho một token, và bất kỳ lệnh nào chứa toán tử shell độc lập (`&&`, `||`, `|`, `;`) hoặc token có ký tự siêu dữ liệu shell nhúng bị từ chối trước khi so khớp danh sách cho phép để ngăn chặn bypass tiêm. +Ngữ pháp mẫu giống như [`block-sudo`](#block-sudo): token được so khớp với argv được phân tích, `*` là ký tự đại diện cho một token, và bất kỳ lệnh nào chứa operator shell độc lập (`&&`, `||`, `|`, `;`) hoặc token có ký tự shell nhúng được từ chối trước khi khớp danh sách cho phép để ngăn vượt qua tiêm. ### `block-kubectl` @@ -170,7 +164,7 @@ Ngữ pháp mẫu giống như [`block-sudo`](#block-sudo): các token được } ``` -Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply -f deploy.yaml` bị từ chối. +Với cấu hình này, `kubectl get pods` được cho phép nhưng `kubectl apply -f deploy.yaml` bị từ chối. --- @@ -202,13 +196,13 @@ Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply ### `block-aws-cli` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Từ chối bất kỳ lệnh gọi CLI `aws` nào. +**Mặc định:** Từ chối bất kỳ lệnh gọi AWS CLI nào. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowPatterns` | `string[]` | `[]` | Tiền tố lệnh aws CLI được phép. | +| `allowPatterns` | `string[]` | `[]` | Tiền tố lệnh AWS CLI được phép. | **Ví dụ:** @@ -227,7 +221,7 @@ Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply ### `block-gcloud` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Từ chối bất kỳ lệnh gọi CLI `gcloud` (Google Cloud) nào. +**Mặc định:** Từ chối bất kỳ lệnh gọi `gcloud` (Google Cloud) CLI nào. **Tham số:** @@ -252,7 +246,7 @@ Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply ### `block-az-cli` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Từ chối bất kỳ lệnh gọi CLI `az` (Azure) nào. +**Mặc định:** Từ chối bất kỳ lệnh gọi `az` (Azure) CLI nào. **Tham số:** @@ -302,7 +296,7 @@ Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply ### `block-gh-pipeline` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Từ chối các lệnh phụ CLI `gh` sau đây gây ra thay đổi trạng thái hoặc kích hoạt đường ống: +**Mặc định:** Từ chối các lệnh con `gh` CLI sau đây thay đổi trạng thái hoặc kích hoạt đường ống: - `gh workflow run`, `gh workflow enable`, `gh workflow disable` - `gh run rerun`, `gh run cancel` @@ -311,13 +305,13 @@ Với cấu hình này, `kubectl get pods` được phép nhưng `kubectl apply - `gh cache delete` - `gh secret set`, `gh secret delete` -Các lệnh phụ `gh` chỉ đọc như `gh pr view`, `gh pr list`, `gh run list`, `gh release view` và `gh api repos/.../...` **không** được khớp bởi chính sách này — chúng thường cần thiết cho các kiểm tra quy trình làm việc (bao gồm cả chính sách `require-ci-green-before-stop` của failproofai). +Các lệnh con `gh` chỉ đọc như `gh pr view`, `gh pr list`, `gh run list`, `gh release view` và `gh api repos/.../...` **không** khớp với chính sách này — chúng thường cần thiết để kiểm tra quy trình làm việc (bao gồm cả `require-ci-green-before-stop` của failproofai). **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowPatterns` | `string[]` | `[]` | Các lệnh gọi được viết kịch bản cụ thể để cho phép ngay cả khi chúng sẽ bị từ chối. | +| `allowPatterns` | `string[]` | `[]` | Lệnh gọi kịch bản cụ thể để cho phép mặc dù chúng sẽ bị từ chối khác. | **Ví dụ:** @@ -333,14 +327,14 @@ Các lệnh phụ `gh` chỉ đọc như `gh pr view`, `gh pr list`, `gh run lis --- -## Bí mật (sanitizers) +## Bí mật (vệ sinh dữ liệu) -Dừng agent rò rỉ thông tin đăng nhập vào ngữ cảnh hoặc kết quả của chúng. Các chính sách sanitizer được kích hoạt trên các sự kiện **PostToolUse**. Khi Claude chạy lệnh Bash, đọc tệp hoặc gọi bất kỳ công cụ nào, các chính sách này kiểm tra kết quả trước khi nó được trả về Claude. Nếu phát hiện mẫu bí mật, chính sách trả về quyết định deny ngăn chặn kết quả được truyền lại. +Ngăn agent rò rỉ thông tin xác thực vào ngữ cảnh hoặc đầu ra của chúng. Các chính sách vệ sinh dữ liệu kích hoạt trên các sự kiện **PostToolUse**. Khi Claude chạy lệnh Bash, đọc tệp hoặc gọi bất kỳ công cụ nào, những chính sách này kiểm tra đầu ra trước khi được trả lại cho Claude. Nếu phát hiện một mẫu bí mật, chính sách trả lại quyết định từ chối ngăn đầu ra được truyền lại. ### `sanitize-jwt` **Sự kiện:** PostToolUse (tất cả công cụ) -**Mặc định:** Che khuất các token JWT (ba đoạn base64url được phân cách bằng `.`). +**Mặc định:** Redact token JWT (ba phân đoạn base64url được phân tách bằng `.`). Không có tham số. @@ -349,13 +343,13 @@ Không có tham số. ### `sanitize-api-keys` **Sự kiện:** PostToolUse (tất cả công cụ) -**Mặc định:** Che khuất các định dạng khóa API phổ biến: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PATs (`ghp_`), AWS access keys (`AKIA`), Stripe keys (`sk_live_`, `sk_test_`) và Google API keys (`AIza`). +**Mặc định:** Redact các định dạng khóa API phổ biến: Anthropic (`sk-ant-`), OpenAI (`sk-`), GitHub PAT (`ghp_`), Khóa truy cập AWS (`AKIA`), Khóa Stripe (`sk_live_`, `sk_test_`) và Khóa API Google (`AIza`). **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Các mẫu regex bổ sung để coi là bí mật. | +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | Các mẫu regex bổ sung để coi như bí mật. | **Ví dụ:** @@ -377,7 +371,7 @@ Không có tham số. ### `sanitize-connection-strings` **Sự kiện:** PostToolUse (tất cả công cụ) -**Mặc định:** Che khuất chuỗi kết nối cơ sở dữ liệu chứa thông tin đăng nhập nhúng (ví dụ: `postgresql://user:password@host/db`). +**Mặc định:** Redact chuỗi kết nối cơ sở dữ liệu chứa thông tin xác thực nhúng (ví dụ: `postgresql://user:password@host/db`). Không có tham số. @@ -386,7 +380,7 @@ Không có tham số. ### `sanitize-private-key-content` **Sự kiện:** PostToolUse (tất cả công cụ) -**Mặc định:** Che khuất các khối PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, v.v.). +**Mặc định:** Redact các khối PEM (`-----BEGIN PRIVATE KEY-----`, `-----BEGIN RSA PRIVATE KEY-----`, v.v.). Không có tham số. @@ -395,7 +389,7 @@ Không có tham số. ### `sanitize-bearer-tokens` **Sự kiện:** PostToolUse (tất cả công cụ) -**Mặc định:** Che khuất các tiêu đề `Authorization: Bearer ` nơi token là 20 hoặc nhiều ký tự hơn. +**Mặc định:** Redact các header `Authorization: Bearer ` trong đó token có 20 hoặc nhiều ký tự hơn. Không có tham số. @@ -403,14 +397,14 @@ Không có tham số. ## Môi trường -Bảo vệ cấu hình môi trường nhạy cảm khỏi việc agent đọc hoặc tiếp xúc. +Bảo vệ cấu hình môi trường nhạy cảm khỏi bị agent đọc hoặc tiếp xúc. ### `block-env-files` **Sự kiện:** PreToolUse (Bash, Read) -**Mặc định:** Từ chối đọc tệp `.env` qua `cat .env`, gọi công cụ `Read` với `.env` là đường dẫn tệp, v.v. +**Mặc định:** Từ chối đọc tệp `.env` qua `cat .env`, lệnh gọi công cụ Read với `.env` là đường dẫn tệp, v.v. -Không chặn `.envrc` hoặc các tệp liên quan môi trường khác - chỉ những tệp được đặt tên chính xác là `.env`. +Không chặn `.envrc` hoặc các tệp liên quan môi trường khác — chỉ các tệp được đặt tên chính xác là `.env`. Không có tham số. @@ -427,18 +421,18 @@ Không có tham số. ## Truy cập tệp -Giữ agent làm việc trong ranh giới dự án và tránh xa những tệp nhạy cảm. +Giữ agent làm việc trong ranh giới dự án và tránh xa các tệp nhạy cảm. ### `block-read-outside-cwd` **Sự kiện:** PreToolUse (Read, Bash) -**Mặc định:** Từ chối đọc tệp bên ngoài gốc dự án. Ranh giới là `CLAUDE_PROJECT_DIR` (được đặt một lần mỗi phiên bởi Claude Code), với dự phòng là thư mục làm việc hiện tại của phiên khi biến đó chưa được đặt. Sử dụng gốc dự án thay vì `cwd` trực tiếp có nghĩa là ranh giới vẫn ổn định ngay cả sau khi Claude `cd` vào thư mục con. +**Mặc định:** Từ chối đọc tệp bên ngoài thư mục dự án gốc. Ranh giới là `CLAUDE_PROJECT_DIR` (được đặt một lần mỗi phiên bởi Claude Code), với fallback đến thư mục làm việc hiện tại của phiên khi biến đó chưa được đặt. Sử dụng thư mục dự án gốc thay vì `cwd` trực tiếp có nghĩa là ranh giới vẫn ổn định ngay cả sau khi Claude `cd` vào thư mục con. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowPaths` | `string[]` | `[]` | Tiền tố đường dẫn tuyệt đối được phép ngay cả khi bên ngoài gốc dự án. | +| `allowPaths` | `string[]` | `[]` | Tiền tố đường dẫn tuyệt đối được phép ngay cả khi bên ngoài thư mục dự án gốc. | **Ví dụ:** @@ -457,7 +451,7 @@ Giữ agent làm việc trong ranh giới dự án và tránh xa những tệp n ### `block-secrets-write` **Sự kiện:** PreToolUse (Write, Edit) -**Mặc định:** Từ chối ghi vào các tệp thường được sử dụng cho các khóa riêng tư và chứng chỉ: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. +**Mặc định:** Từ chối ghi vào các tệp thường được sử dụng cho khóa riêng và chứng chỉ: `id_rsa`, `id_ed25519`, `*.key`, `*.pem`, `*.p12`, `*.pfx`. **Tham số:** @@ -481,7 +475,7 @@ Giữ agent làm việc trong ranh giới dự án và tránh xa những tệp n ## Git -Ngăn chặn các lần push tình cờ, force-push và các lỗi nhánh khó hoàn tác. +Ngăn push bất cẩn, force-push và lỗi branch khó hoàn tác. ### `block-push-master` @@ -492,7 +486,7 @@ Ngăn chặn các lần push tình cờ, force-push và các lỗi nhánh khó h | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Tên nhánh không thể được push trực tiếp. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Tên branch không thể được push trực tiếp. | **Ví dụ:** @@ -507,7 +501,7 @@ Ngăn chặn các lần push tình cờ, force-push và các lỗi nhánh khó h ``` -Để cho phép push đến tất cả các nhánh (có hiệu lực là vô hiệu hóa chính sách này mà không xóa nó khỏi `enabledPolicies`), đặt `protectedBranches: []`. +Để cho phép push đến tất cả các branch (có hiệu lực vô hiệu hóa chính sách này mà không loại bỏ nó khỏi `enabledPolicies`), hãy đặt `protectedBranches: []`. --- @@ -515,13 +509,13 @@ Ngăn chặn các lần push tình cờ, force-push và các lỗi nhánh khó h ### `block-work-on-main` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Từ chối `git commit`, `git merge`, `git rebase` và `git cherry-pick` khi cây làm việc nằm trên `main` hoặc `master`. Tạo nhánh và chuyển đổi (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) không bị ảnh hưởng. +**Mặc định:** Từ chối `git commit`, `git merge`, `git rebase` và `git cherry-pick` trong khi cây làm việc trên `main` hoặc `master`. Tạo branch và chuyển đổi (`git checkout`, `git checkout -b`, `git switch`, `git switch -c`) không bị ảnh hưởng. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `protectedBranches` | `string[]` | `["main", "master"]` | Tên nhánh trong đó commit/merge/rebase/cherry-pick bị từ chối. | +| `protectedBranches` | `string[]` | `["main", "master"]` | Tên branch mà commit/merge/rebase/cherry-pick bị từ chối. | --- @@ -530,13 +524,13 @@ Ngăn chặn các lần push tình cờ, force-push và các lỗi nhánh khó h **Sự kiện:** PreToolUse (Bash) **Mặc định:** Từ chối `git push --force` và `git push -f`. -Không có tham số cụ thể chính sách. Sử dụng [`hint`](/vi/configuration#hint-cross-cutting) cắt ngang để gợi ý các giải pháp thay thế: +Không có tham số cụ thể cho chính sách. Sử dụng [`hint`](/vi/configuration#hint-cross-cutting) xuyên suốt để gợi ý các lựa chọn thay thế: ```json { "policyParams": { "block-force-push": { - "hint": "Tạo một nhánh mới từ HEAD hiện tại của bạn (ví dụ: `git checkout -b `) và push nhánh đó thay vì." + "hint": "Create a new branch from your current HEAD (e.g. `git checkout -b `) and push that instead." } } } @@ -565,7 +559,7 @@ Không có tham số. ### `warn-all-files-staged` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Hướng dẫn Claude xem lại những gì nó sắp sàng lọc khi chạy `git add -A` hoặc `git add .`. Không chặn lệnh. +**Mặc định:** Hướng dẫn Claude xem xét những gì nó đang staging khi chạy `git add -A` hoặc `git add .`. Không chặn lệnh. Không có tham số. @@ -573,12 +567,12 @@ Không có tham số. ## Cơ sở dữ liệu -Bắt các thao tác SQL phá hủy trước khi chúng thực thi đối với cơ sở dữ liệu của bạn. +Bắt các thao tác SQL tàn phá trước khi chúng thực thi đối với cơ sở dữ liệu của bạn. ### `warn-destructive-sql` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Hướng dẫn Claude xác nhận trước khi chạy SQL chứa `DROP TABLE`, `DROP DATABASE` hoặc `DELETE` mà không có mệnh đề `WHERE`. +**Mặc định:** Hướng dẫn Claude xác nhận trước khi chạy SQL chứa `DROP TABLE`, `DROP DATABASE` hoặc `DELETE` không có mệnh đề `WHERE`. Không có tham số. @@ -595,7 +589,7 @@ Không có tham số. ## Cảnh báo -Cung cấp agent ngữ cảnh bổ sung trước các hoạt động tiềm ẩn rủi ro nhưng không phá hủy. +Cung cấp cho agent ngữ cảnh bổ sung trước các phép toán có rủi ro nhưng không tàn phá. ### `warn-large-file-write` @@ -621,7 +615,7 @@ Cung cấp agent ngữ cảnh bổ sung trước các hoạt động tiềm ẩn ``` -Xử lý hook thực thi giới hạn stdin 1 MB trên tải trọng. Để kiểm tra chính sách này với nội dung nhỏ, đặt `thresholdKb` thành giá trị tốt dưới 1024. +Trình xử lý hook thực thi giới hạn stdin 1 MB trên tải trọng. Để kiểm tra chính sách này với nội dung nhỏ, hãy đặt `thresholdKb` thành giá trị tốt dưới 1024. --- @@ -638,7 +632,7 @@ Không có tham số. ### `warn-background-process` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Hướng dẫn Claude cẩn thận khi khởi chạy các quy trình nền qua `nohup`, `&`, `disown` hoặc `screen`. +**Mặc định:** Hướng dẫn Claude cẩn thận khi khởi chạy các quá trình nền thông qua `nohup`, `&`, `disown` hoặc `screen`. Không có tham số. @@ -647,7 +641,7 @@ Không có tham số. ### `warn-global-package-install` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Hướng dẫn Claude xác nhận trước khi chạy `npm install -g`, `yarn global add` hoặc `pip install` mà không có môi trường ảo. +**Mặc định:** Hướng dẫn Claude xác nhận trước khi chạy `npm install -g`, `yarn global add` hoặc `pip install` không có môi trường ảo. Không có tham số. @@ -655,21 +649,21 @@ Không có tham số. ## Trình quản lý gói -Thực thi trình quản lý gói nào agent được phép sử dụng. +Thực thi những trình quản lý gói nào mà agent được phép sử dụng. ### `prefer-package-manager` **Sự kiện:** PreToolUse (Bash) -**Mặc định:** Bị vô hiệu hóa. Khi được bật, chặn bất kỳ lệnh trình quản lý gói nào không trong danh sách `allowed` và yêu cầu Claude viết lại lệnh bằng trình quản lý được phép. +**Mặc định:** Bị vô hiệu hóa. Khi bật, chặn bất kỳ lệnh trình quản lý gói nào không trong danh sách `allowed` và bảo Claude viết lại lệnh bằng trình quản lý được cho phép. Phát hiện: pip, pip3, python -m pip, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `allowed` | string[] | `[]` | Các tên trình quản lý gói được phép. Bất kỳ trình quản lý được phát hiện nào không có trong danh sách này bị chặn. Khi trống, chính sách là no-op. | -| `blocked` | string[] | `[]` | Các tên trình quản lý bổ sung để chặn ngoài danh sách tích hợp sẵn (ví dụ: `['pdm', 'pipx']`). | +| `allowed` | string[] | `[]` | Tên trình quản lý gói được phép. Bất kỳ trình quản lý được phát hiện nào không trong danh sách này bị chặn. Khi trống, chính sách là no-op. | +| `blocked` | string[] | `[]` | Tên trình quản lý bổ sung để chặn ngoài danh sách tích hợp sẵn (ví dụ: `['pdm', 'pipx']`). | -Danh sách chặn tích hợp sẵn bao gồm: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Sử dụng `blocked` để thêm các trình quản lý không có trong danh sách này. +Danh sách chặn tích hợp sẵn bao gồm: pip, pip3, npm, npx, yarn, pnpm, pnpx, bun, bunx, uv, poetry, pipenv, conda, cargo. Sử dụng `blocked` để thêm các trình quản lý không trong danh sách này. **Cấu hình ví dụ:** @@ -685,18 +679,18 @@ Danh sách chặn tích hợp sẵn bao gồm: pip, pip3, npm, npx, yarn, pnpm, } ``` -Với cấu hình này, `pip install flask` và `pdm install flask` đều bị từ chối với thông báo yêu cầu Claude sử dụng `uv` hoặc `bun` thay vì. Các lệnh như `uv pip install flask` được phép vì `uv` nằm trong danh sách cho phép và được kiểm tra trước tiên. +Với cấu hình này, `pip install flask` và `pdm install flask` đều bị từ chối với thông báo bảo Claude sử dụng `uv` hoặc `bun` thay thế. Các lệnh như `uv pip install flask` được cho phép vì `uv` trong danh sách cho phép và được kiểm tra trước. --- ## Hành vi AI -Phát hiện khi agent bị mắc kẹt hoặc có hành vi bất thường. +Phát hiện khi agent bị kẹt hoặc hành xử bất thường. ### `warn-repeated-tool-calls` **Sự kiện:** PreToolUse (tất cả công cụ) -**Mặc định:** Hướng dẫn Claude xem xét lại khi cùng một công cụ được gọi 3 lần trở lên với các tham số giống hệt nhau - dấu hiệu phổ biến của agent bị mắc vòng lặp. +**Mặc định:** Hướng dẫn Claude cân nhắc lại khi cùng một công cụ được gọi 3 lần trở lên với các tham số giống hệt nhau — dấu hiệu phổ biến của agent bị kẹt trong vòng lặp. Không có tham số. @@ -704,40 +698,39 @@ Không có tham số. ## Quy trình làm việc -Thực thi quy trình làm việc cuối phiên kỷ luật. Các chính sách này được kích hoạt trên sự kiện **Stop** và từ chối agent dừng lại cho đến khi mỗi điều kiện được đáp ứng. Chúng tuân theo chuỗi phụ thuộc tự nhiên: commit → push → PR → CI. Nếu chính sách từ chối, các chính sách sau trong chuỗi bị bỏ qua (deny short-circuits). +Thực thi một quy trình làm việc cuối phiên kỷ luật. Những chính sách này kích hoạt trên sự kiện **Stop** và từ chối agent dừng cho đến khi mỗi điều kiện được đáp ứng. Chúng theo một chuỗi phụ thuộc tự nhiên: commit → push → PR → CI. Nếu chính sách từ chối, các chính sách sau trong chuỗi bị bỏ qua (từ chối làm ngắt). -Tất cả các chính sách quy trình làm việc là **fail-open**: nếu công cụ được yêu cầu không có sẵn (ví dụ: `gh` không cài đặt, không có git remote), chính sách cho phép với thông báo thông tin giải thích lý do kiểm tra bị bỏ qua. +Tất cả các chính sách quy trình làm việc là **fail-open**: nếu công cụ bắt buộc không có sẵn (ví dụ: `gh` không được cài đặt, không có remote git), chính sách cho phép có thông báo thông tin giải thích lý do kiểm tra bị bỏ qua. -### Ngữ nghĩa Stop theo CLI +### Ngữ pháp Stop mỗi CLI -Thực thi Stop trông hơi khác nhau trên bảy CLI được hỗ trợ vì mỗi CLI tiếp xúc với hợp đồng hook "agent kết thúc" khác nhau. **Kết quả** là như nhau — agent không thoát khỏi việc dừng lại trong khi cổng quy trình làm việc đang thất bại — nhưng **cơ chế** khác nhau. Bảng dưới đây tóm tắt; chỉ Pi có một điểm kỳ lạ hiển thị cho người dùng đáng hiểu trước khi bạn bật chính sách `require-*-before-stop`. +Thực thi Stop trông hơi khác nhau trên sáu CLI được hỗ trợ vì mỗi CLI hiển thị một hợp đồng hook tương ứng với sự kiện hoàn tất khác nhau. **Kết quả** giống nhau — agent không thoát khỏi dừng lại trong khi cổng quy trình làm việc đang thất bại — nhưng **cơ chế** khác. Bảng dưới đây tóm tắt; chỉ Pi có một sự khác biệt đáng chú ý mà bạn nên hiểu trước khi bật chính sách `require-*-before-stop`. | CLI | Khi cổng kích hoạt | Những gì bạn thấy | |---|---|---| -| Claude Code | Cùng vòng lặp agent, ngay lập tức | Claude tiếp tục làm việc — sửa vấn đề, sau đó cố gắng hoàn thành lại. Không có sự gián đoạn hiển thị cho bạn. | -| Codex | Cùng vòng lặp agent, ngay lập tức | Giống như Claude. | -| GitHub Copilot CLI | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{decision:"block", reason}` retry của Copilot — đã xác minh theo kinh nghiệm đối với Copilot CLI 1.0.41). | -| Cursor Agent | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{followup_message}` của Cursor — bị giới hạn ở `loop_limit`, mặc định 5 lần thử lại). | -| Gemini CLI | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng kênh `{decision:"block", reason}` của Gemini trên `AfterAgent`). | -| OpenCode | Cùng vòng lặp agent, ngay lập tức | Giống như Claude (sử dụng lệnh gọi SDK `client.session.prompt(...)` của OpenCode được định tuyến qua `hookSpecificOutput.additionalContext`). | -| **Pi (pi-coding-agent)** | **Lần tới người dùng** | **Pi dừng lại rõ ràng** khi cổng kích hoạt — vòng lặp agent của nó thoát và bạn quay lại dấu nhắc. Cổng sau đó kích hoạt lần tiếp theo bạn gửi dấu nhắc: failproofai thêm tiền tố `MANDATORY ACTION REQUIRED` vào lời nhắc hệ thống của lần đó, hướng dẫn LLM hoàn thành bước quy trình làm việc (commit, push, v.v.) trước khi làm bất cứ điều gì bạn yêu cầu. | +| Claude Code | Cùng một vòng lặp agent, ngay lập tức | Claude tiếp tục làm việc — sửa vấn đề, rồi cố gắng kết thúc lại. Không có sự gián đoạn nhìn thấy được cho bạn. | +| Codex | Cùng một vòng lặp agent, ngay lập tức | Giống Claude. | +| GitHub Copilot CLI | Cùng một vòng lặp agent, ngay lập tức | Giống Claude (sử dụng kênh thử lại `{decision:"block", reason}` của Copilot — xác minh thực nghiệm dựa trên Copilot CLI 1.0.41). | +| Cursor Agent | Cùng một vòng lặp agent, ngay lập tức | Giống Claude (sử dụng kênh `{followup_message}` của Cursor — được giới hạn bởi `loop_limit`, mặc định 5 lần thử lại). | +| OpenCode | Cùng một vòng lặp agent, ngay lập tức | Giống Claude (sử dụng lệnh gọi `client.session.prompt(...)` SDK được định tuyến qua `hookSpecificOutput.additionalContext`). | +| **Pi (pi-coding-agent)** | **Lượt người dùng tiếp theo** | **Pi dừng một cách rõ ràng** khi cổng kích hoạt — vòng lặp agent của nó thoát và bạn được trả lại lời nhắc. Cổng sau đó kích hoạt vào lần tiếp theo bạn gửi lời nhắc: failproofai nối thêm một chỉ thị `MANDATORY ACTION REQUIRED` vào lời nhắc hệ thống của lượt đó, hướng dẫn LLM hoàn tất bước quy trình làm việc (commit, push, v.v.) trước khi làm bất kỳ điều gì bạn yêu cầu. | -**Giới hạn Pi.** `AgentEndEvent` của Pi (tương đương thượng nguồn của hook `Stop` của Claude) không có loại Result — khi nó kích hoạt, vòng lặp agent của Pi đã thoát. Pi không thể bị buộc thử lại cùng một vòng lặp theo cách Claude / Copilot / Cursor / Gemini / OpenCode. failproofai thay đổi cổng sang sự kiện `before_agent_start` của Pi (được kích hoạt sau dấu nhắc người dùng tiếp theo) để kiểm tra quy trình làm việc vẫn thực thi, chỉ trên lần tới thay vì lần hiện tại. +**Hạn chế Pi.** `AgentEndEvent` của Pi (tương đương hạ tầng của hook `Stop` của Claude) không có loại Result — vào thời điểm nó kích hoạt, vòng lặp agent của Pi đã thoát. Pi không thể bị ép buộc thử lại cùng một vòng lặp như Claude / Copilot / Cursor / OpenCode có thể. failproofai dịch chuyển cổng đến sự kiện `before_agent_start` của Pi (kích hoạt sau lời nhắc người dùng tiếp theo) để kiểm tra quy trình làm việc vẫn thực thi, chỉ là ở lượt tiếp theo thay vì ở lượt hiện tại. **Điều này có nghĩa gì trong thực tế:** -- Sau khi Pi dừng lại, lý do từ chối được ghi vào bộ nhớ trong bằng id phiên Pi. Dấu nhắc rất tiếp theo bạn gửi trong cùng quy trình Pi lấy ra nó: LLM nhìn thấy chỉ thị `MANDATORY ACTION REQUIRED` ở đầu lời nhắc hệ thống của nó, commit (hoặc push / mở PR / chờ CI) và chỉ khi đó tiếp tục với yêu cầu của bạn. Lý do từ chối được ghi lại là một lần — sau khi lấy ra, cổng rõ ràng. -- Cổng bị ràng buộc bởi vòng đời quá trình Pi. Nếu bạn `Ctrl+C` Pi hoặc thoát giữa các lần, mục bộ nhớ trong được loại bỏ cùng với quá trình và cổng bị bỏ lỡ. Claude, Copilot, Cursor, Gemini và OpenCode có cùng ranh giới (giết agent và cổng bị bỏ lỡ) — Pi chỉ làm cho nó rõ ràng hơn vì agent rõ ràng thoát trước khi cổng kích hoạt. -- Một từ chối đang chờ cũng bị xóa trên `session_shutdown` vì lý do gì đó (`new` / `resume` / `fork` / `quit`), vì vậy cổng cũ từ phiên trước không thể bị rò rỉ vào phiên mới được khởi động trong cùng quy trình Pi. +- Sau khi Pi dừng, lý do từ chối được giữ trong bộ nhớ được khóa theo id phiên Pi. Lời nhắc tiếp theo chính xác bạn gửi trong cùng một quá trình Pi sẽ thoát khỏi nó: LLM thấy chỉ thị `MANDATORY ACTION REQUIRED` ở đầu lời nhắc hệ thống của nó, commits (hoặc push / mở PR / chờ CI), và chỉ sau đó tiếp tục với yêu cầu của bạn. Lý do từ chối được ghi lại một lần — khi thoát khỏi, cổng sạch. +- Cổng bị ràng buộc bởi thời gian sống của quá trình Pi. Nếu bạn `Ctrl+C` Pi hoặc thoát giữa các lượt, mục trong bộ nhớ bị loại bỏ cùng với quá trình và cổng bị bỏ qua. Claude, Copilot, Cursor và OpenCode có cùng một ràng buộc (tắt agent và cổng bị bỏ qua) — Pi chỉ làm cho nó hiển thị rõ hơn vì agent rõ ràng thoát trước khi cổng kích hoạt. +- Một từ chối đang chờ xử lý cũng bị xóa trên `session_shutdown` vì bất kỳ lý do gì (`new` / `resume` / `fork` / `quit`), vì vậy cổng cũ từ phiên trước không thể rò rỉ vào phiên mới được bắt đầu trong cùng quá trình Pi. -Nếu bạn cần thử lại cùng vòng lặp kiểu Claude, hãy chạy các chính sách `Stop` của bạn dưới bất kỳ sáu CLI được hỗ trợ khác. Chúng tôi đang theo dõi Pi thượng nguồn để có loại Result trong tương lai trên `AgentEndEvent` sẽ cho phép chúng tôi đóng khoảng cách này. +Nếu bạn cần thử lại cùng vòng lặp kiểu Claude, hãy chạy chính sách `Stop` của bạn dưới một trong năm CLI được hỗ trợ khác. Chúng tôi đang theo dõi Pi hạ tầng để có loại Result trong tương lai trên `AgentEndEvent` để cho phép chúng tôi đóng khoảng trống này. ### `require-commit-before-stop` **Sự kiện:** Stop -**Mặc định:** Từ chối dừng lại khi có thay đổi chưa được xác nhận (tệp đã sửa đổi, được sắp xếp hoặc chưa theo dõi). Trả về thông báo thông tin khi thư mục làm việc sạch sẽ. +**Mặc định:** Từ chối dừng khi có những thay đổi chưa được commit (tệp đã sửa đổi, staged hoặc chưa theo dõi). Trả lại thông báo thông tin khi thư mục làm việc sạch. Không có tham số. @@ -746,13 +739,13 @@ Không có tham số. ### `require-push-before-stop` **Sự kiện:** Stop -**Mặc định:** Từ chối dừng lại khi có các lần commit chưa được push hoặc khi nhánh hiện tại không có nhánh theo dõi từ xa. Gợi ý `git push -u` để tạo nhánh theo dõi nếu cần. Thất bại mở nếu không có remote được cấu hình. +**Mặc định:** Từ chối dừng khi có commit chưa được push hoặc khi branch hiện tại không có remote tracking branch. Gợi ý `git push -u` để tạo tracking branch nếu cần. Thất bại mở nếu không có remote được cấu hình. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `remote` | `string` | `"origin"` | Tên remote để push đến. | +| `remote` | `string` | `"origin"` | Tên remote để push tới. | **Ví dụ:** @@ -771,14 +764,14 @@ Không có tham số. ### `require-pr-before-stop` **Sự kiện:** Stop -**Mặc định:** Từ chối dừng lại khi không có yêu cầu pull tồn tại cho nhánh hiện tại hoặc khi PR hiện có bị đóng mà không merge. Hướng dẫn Claude tạo PR với `gh pr create`. Khi PR được **merge**, chính sách cho phép (công việc đã được gửi) và thông báo gợi ý chuyển ra khỏi nhánh (`git checkout main && git pull`). +**Mặc định:** Từ chối dừng khi không có pull request cho branch hiện tại, hoặc khi PR hiện tại đóng mà không được merge. Hướng dẫn Claude tạo PR bằng `gh pr create`. Khi PR **được merge**, chính sách cho phép (công việc đã được gửi) và thông báo gợi ý chuyển ra khỏi branch (`git checkout main && git pull`). Không có tham số. Chính sách này yêu cầu [GitHub CLI](https://cli.github.com/) (`gh`) được cài đặt và xác thực. -Chạy `gh auth login` với token truy cập cá nhân có phạm vi `repo` để đọc -yêu cầu pull. Nếu `gh` không được cài đặt hoặc không xác thực, chính sách thất bại mở và báo cáo lý do cho Claude. +Chạy `gh auth login` với token truy cập cá nhân có phạm vi `repo` để truy cập đọc vào +pull request. Nếu `gh` không được cài đặt hoặc không được xác thực, chính sách thất bại mở và báo cáo lý do cho Claude. --- @@ -786,24 +779,24 @@ yêu cầu pull. Nếu `gh` không được cài đặt hoặc không xác thự ### `require-no-conflicts-before-stop` **Sự kiện:** Stop -**Mặc định:** Từ chối dừng lại khi nhánh hiện tại không thể merge sạch vào nhánh cơ sở. Chính sách trước tiên xác nhận có PR `OPEN` trên GitHub cho nhánh — nếu không có, không có mục tiêu merge để thực thi, vì vậy toàn bộ chính sách short-circuit cho phép. Khi PR `OPEN` được xác nhận, hai điều tra độc lập chạy: +**Mặc định:** Từ chối dừng khi branch hiện tại không thể merge sạch vào branch cơ sở. Chính sách trước tiên xác nhận có một PR `OPEN` trên GitHub cho branch — nếu không có, không có mục tiêu merge để thực thi, vì vậy toàn bộ chính sách ngắn mạch để cho phép. Khi PR `OPEN` được xác nhận, hai thăm dò độc lập chạy: -1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. Xung đột, thông báo từ chối đặt tên các tệp xung đột để Claude biết chính xác phải giải quyết cái gì. -2. **GitHub** — tái sử dụng kết quả `gh pr view --json mergeable,state` đã được tìm nạp trong kiểm tra trước. Bắt những xung đột mà `origin/` cũ cục bộ sẽ bỏ lỡ (ví dụ: ai đó đã hạ cánh PR xung đột trên `main` kể từ lần tìm nạp cuối cùng). Kết quả `CONFLICTING` từ chối. Kết quả `UNKNOWN` cũng từ chối và hướng dẫn Claude chờ ~10 giây và kiểm tra lại trước khi cố gắng dừng lại lại — điều này ngăn chặn dương tính giả trong khi GitHub tính toán lại. +1. **Local** — `git merge-tree --write-tree --name-only origin/ HEAD`. Trên xung đột, thông báo từ chối đặt tên các tệp xung đột để Claude biết chính xác những gì để giải quyết. +2. **GitHub** — tái sử dụng kết quả `gh pr view --json mergeable,state` đã được tìm nạp trước. Bắt các xung đột mà `origin/` cũ trên local sẽ bỏ lỡ (ví dụ: ai đó hạ cánh một PR xung đột trên `main` kể từ lần tìm nạp cuối cùng). Kết quả `CONFLICTING` từ chối. Kết quả `UNKNOWN` cũng từ chối và hướng dẫn Claude chờ ~10 giây và kiểm tra lại trước khi cố gắng dừng lại — điều này ngăn chặn các kết quả dương tính giả trong khi GitHub tính toán lại. -Bỏ qua hoàn toàn (cho phép) khi: `gh` không được cài đặt, không có PR nào cho nhánh, trạng thái PR không phải `OPEN` (ví dụ: `MERGED`, `CLOSED`), hoặc `gh pr view` trả về kết quả không thể phân tích. Cũng thất bại mở khi `origin/` bị thiếu cục bộ hoặc khi không có commit trước cơ sở — những lần rơi qua Layer 1 đó vẫn tham khảo kết quả PR mergeability được lưu trong bộ nhớ cache trước khi cho phép. +Bỏ qua hoàn toàn (cho phép) khi: `gh` không được cài đặt, không có PR cho branch, trạng thái PR không phải là `OPEN` (ví dụ: `MERGED`, `CLOSED`), hoặc `gh pr view` trả lại đầu ra không thể phân tích được. Cũng thất bại mở khi `origin/` bị thiếu cục bộ hoặc khi không có commit dẫn trước cơ sở — các fall-through Layer 1 đó vẫn tham khảo mergeability PR được lưu trong bộ nhớ cache trước khi cho phép. **Tham số:** | Tham số | Loại | Mặc định | Mô tả | |--------|------|---------|-------| -| `baseBranch` | `string` | `"main"` | Nhánh cơ sở để kiểm tra xung đột đối với. | +| `baseBranch` | `string` | `"main"` | Branch cơ sở để kiểm tra xung đột. | -GitHub CLI (`gh`) là bắt buộc cho chính sách này. Chính sách sử dụng `gh pr view` để xác nhận -một PR `OPEN` tồn tại trước khi chạy bất kỳ điều tra xung đột nào — nếu không có `gh`, chính sách -short-circuit cho phép. Chạy `gh auth login` với token truy cập cá nhân có -phạm vi `repo` để đọc yêu cầu pull. +GitHub CLI (`gh`) được yêu cầu cho chính sách này. Chính sách sử dụng `gh pr view` để xác nhận +một PR `OPEN` tồn tại trước khi chạy bất kỳ thăm dò xung đột nào — nếu không có `gh`, chính sách +ngắn mạch để cho phép. Chạy `gh auth login` với token truy cập cá nhân có phạm vi +`repo` để truy cập đọc vào pull request. --- @@ -811,14 +804,14 @@ phạm vi `repo` để đọc yêu cầu pull. ### `require-ci-green-before-stop` **Sự kiện:** Stop -**Mặc định:** Từ chối dừng lại khi các kiểm tra CI đang thất bại hoặc vẫn chạy trên nhánh hiện tại. Kiểm tra cả công việc GitHub Actions workflow và các kiểm tra bot của bên thứ ba (ví dụ: CodeRabbit, SonarCloud, Codecov). Coi `skipped`, `cancelled` và `neutral` kết luận là không thất bại (cái sau bao gồm ví dụ: Socket Security alerts trên PR của người đóng góp bên ngoài, nơi ứng dụng cố tình báo cáo neutral thay vì success/failure). Trả về thông báo thông tin khi tất cả các kiểm tra vượt qua. +**Mặc định:** Từ chối dừng khi các kiểm tra CI đang thất bại hoặc vẫn đang chạy trên branch hiện tại. Kiểm tra cả chạy quy trình làm việc GitHub Actions và kiểm tra bot của bên thứ ba (ví dụ: CodeRabbit, SonarCloud, Codecov). Coi các kết luận `skipped`, `cancelled` và `neutral` là không thất bại (kết luận cuối cùng bao gồm ví dụ như Socket Security alert trên PR của contributor bên ngoài, trong đó ứng dụng có ý định báo cáo neutral thay vì success/failure). Trả lại thông báo thông tin khi tất cả kiểm tra đều thành công. Không có tham số. Chính sách này yêu cầu [GitHub CLI](https://cli.github.com/) (`gh`) được cài đặt và xác thực. -Chạy `gh auth login` với token truy cập cá nhân có phạm vi `repo` để đọc -quy trình làm việc Actions và Checks API. Nếu `gh` không được cài đặt hoặc không xác thực, chính sách thất bại mở và báo cáo lý do cho Claude. +Chạy `gh auth login` với token truy cập cá nhân có phạm vi `repo` để truy cập đọc vào +chạy quy trình làm việc Actions và API Checks. Nếu `gh` không được cài đặt hoặc không được xác thực, chính sách thất bại mở và báo cáo lý do cho Claude. --- @@ -827,7 +820,7 @@ quy trình làm việc Actions và Checks API. Nếu `gh` không được cài ## Vô hiệu hóa các chính sách riêng lẻ -Xóa một chính sách cụ thể khỏi `enabledPolicies` trong cấu hình của bạn hoặc bật tắt nó trên tab Policies của bảng điều khiển. +Loại bỏ một chính sách cụ thể khỏi `enabledPolicies` trong cấu hình của bạn, hoặc chuyển nó tắt trong tab Chính sách của bảng điều khiển. ```json { @@ -838,4 +831,4 @@ Xóa một chính sách cụ thể khỏi `enabledPolicies` trong cấu hình c } ``` -Các chính sách không được liệt kê trong `enabledPolicies` không chạy, ngay cả khi các mục `policyParams` tồn tại cho chúng. \ No newline at end of file +Các chính sách không được liệt kê trong `enabledPolicies` không chạy, ngay cả khi tồn tại các mục `policyParams` cho chúng. \ No newline at end of file diff --git a/docs/vi/cli/audit.mdx b/docs/vi/cli/audit.mdx index e7fcf00a..48c9865d 100644 --- a/docs/vi/cli/audit.mdx +++ b/docs/vi/cli/audit.mdx @@ -1,19 +1,19 @@ --- -title: Kiểm toán các phiên trước (beta) -description: "Đếm xem agent đã làm những việc lãng phí hoặc rủi ro bao nhiêu lần trên các bản ghi quá khứ" +title: Kiểm toán các phiên trước đó (beta) +description: "Đếm xem agent đã làm những điều lãng phí hoặc rủi ro bao nhiêu lần trong các bảng ghi thoại trước đó" --- - **Tính năng beta.** Công cụ kiểm toán được phát hành dưới dạng beta trong khi chúng tôi thu thập phản hồi ban đầu. - Danh mục detector và định dạng báo cáo có thể thay đổi trước bản ổn định tiếp theo. - Vui lòng tạo issue nếu bạn thấy bất cứ điều gì sai sót. + **Tính năng beta.** Kiểm toán được phát hành dưới dạng beta trong khi chúng tôi thu thập phản hồi ban đầu. + Danh mục bộ phát hiện và định dạng báo cáo có thể thay đổi trước bản ổn định tiếp theo. + Vui lòng mở một issue nếu có gì không đúng. -Công cụ kiểm toán sẽ phát lại các bản ghi quá khứ của agent-CLI qua engine chính sách của failproofai và tạo ra một báo cáo trực quan có thể chia sẻ trên **trang dashboard `/audit`** — kiểu mẫu của agent, điểm từ 0–100, và chính xác những chính sách nào sẽ phát hiện được điều gì. +Kiểm toán sẽ phát lại các bảng ghi thoại agent-CLI trước đó thông qua engine chính sách của failproofai và hiển thị một báo cáo hình ảnh có thể chia sẻ trên **trang bảng điều khiển `/audit`** — kiểu mẫu của agent, điểm từ 0–100 và chính xác những chính sách nào sẽ phát hiện được gì. ## Chạy nó -Ba cách để bắt đầu — tất cả đều dẫn đến cùng một báo cáo `/audit`. +Ba cách vào — tất cả đều dẫn đến cùng một báo cáo `/audit`. @@ -25,7 +25,7 @@ npx -y failproofai audit failproofai audit ``` -```bash failproofai (dashboard) +```bash failproofai (bảng điều khiển) failproofai ``` @@ -33,56 +33,56 @@ failproofai - `npx -y failproofai audit` tải failproofai, chạy quét, và mở dashboard cho bạn — không cần cài đặt trước. + `npx -y failproofai audit` tải failproofai, chạy bước quét và mở bảng điều khiển cho bạn — không cần cài đặt gì trước. - `failproofai audit` chạy quét trong terminal của bạn, sau đó tự động mở `localhost:8020/audit` khi hoàn tất. + `failproofai audit` chạy bước quét trong terminal của bạn, sau đó tự động mở `localhost:8020/audit` khi hoàn thành. - - Chạy `failproofai` và nhấp **Audit** trong navbar (giữa Policies và Projects), hoặc mở `/audit` trực tiếp. + + Chạy `failproofai` và nhấp vào **Audit** trong thanh điều hướng (giữa Policies và Projects), hoặc mở `/audit` trực tiếp. - Chạy `failproofai audit -h` (hoặc `--help`) để xem cách sử dụng. Công cụ kiểm toán chạy **hoàn toàn ngoại tuyến** — không cần tài khoản hay mạng — và dashboard tiếp tục hoạt động cho đến khi bạn dừng nó bằng `Ctrl+C`. + Chạy `failproofai audit -h` (hoặc `--help`) để xem cách sử dụng. Kiểm toán chạy **hoàn toàn ngoại tuyến** — không cần tài khoản hoặc mạng — và bảng điều khiển tiếp tục phục vụ cho đến khi bạn dừng nó bằng `Ctrl+C`. -Dashboard quét các bản ghi agent CLI quá khứ trên máy này (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi, Gemini) và báo cáo tần suất agent làm những việc mà failproofai được xây dựng để ngăn chặn — kiểm tra biến môi trường, force push, tiền tố `cd ` dư thừa, vòng lặp sleep-polling, đọc lại tệp vừa chỉnh sửa, và nhiều hơn nữa. +Bảng điều khiển quét các bảng ghi thoại agent CLI trước đó trên máy này (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) và báo cáo xem agent đã làm những việc failproofai được xây dựng để dừng bao nhiêu lần — kiểm tra biến môi trường, force push, tiền tố `cd ` dư thừa, vòng lặp sleep-polling, đọc lại tệp vừa chỉnh sửa, và nhiều hơn nữa. -Đối với mỗi bản ghi, mỗi sự kiện tool-use được phát lại thông qua 39 chính sách tích hợp **và** thông qua 8 detector chỉ dùng cho kiểm toán để phát hiện các mẫu chưa được bao phủ bởi các chính sách thời gian chạy. Các số được tổng hợp theo chính sách/detector trên tất cả các phiên. +Đối với mỗi bảng ghi thoại, mọi sự kiện tool-use đều được phát lại thông qua 39 chính sách tích hợp **và** qua 8 bộ phát hiện chỉ dành cho kiểm toán bắt các mẫu chưa được bao phủ bởi chính sách thời gian chạy. Số lượng được tổng hợp theo chính sách / bộ phát hiện trên tất cả các phiên. -## Những gì bạn nhận được +## Bạn nhận được gì -Trang `/audit` là một **áp phích** toàn màn hình có thể chia sẻ, theo sau bởi bốn phần dưới nền trang: +Trang `/audit` là một **poster** trên màn hình duy nhất, có thể chia sẻ được theo sau là bốn phần dưới: -1. **Áp phích** — danh tính của agent một cách nhanh chóng: **kiểu mẫu** của nó (một trong 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), các từ khóa tính cách của nó, mức độ hiếm của kiểu mẫu đó, và **điểm 0–100** với dải hạng (`S` cho đến `bottom tier`). Được xây dựng để chia sẻ — đăng lên X hoặc LinkedIn, hoặc tải xuống dưới dạng PNG. -2. **`// strengths`** — những gì agent của bạn đã làm tốt, dưới dạng các số thực từ quét (ví dụ: clean-tool-call %, `0` lần push-to-main), chỉ hiển thị nơi chính sách liên quan có hồ sơ sạch sẽ. -3. **`// quirks`** — những gì đã trượt qua: một bảng xếp hạng các hành vi mà failproofai sẽ phát hiện — *khi* nó lần cuối cùng xảy ra, *những gì đã trượt* (và built-in sẽ chặn nó), *mức độ nghiêm trọng* của nó, và *tần suất* nó *được nhìn thấy* (`new` / `recurring` / `N× seen`). -4. **`// how to improve`** — danh sách sửa chữa được quy định: một hàng trên mỗi chính sách với `failproofai policy add ` sao chép-dán, cộng với nút **install all** cho phép mọi đề xuất cùng một lúc và hiển thị **projected score** của bạn nếu bạn làm vậy. -5. **`// come back better`** — hình thành thói quen: đặt **reminder** kiểm toán lại qua email (`3d` / `7d` / `14d` / `30d`) hoặc kiểm toán lại ngay bây giờ, và **invite a friend** để chạy kiểm toán của riêng họ (được gửi từ failproof.ai, được Cc cho bạn). Reminder và lời mời cần đăng nhập — xem [`failproofai auth`](/vi/cli/auth). +1. **Poster** — nhận dạng agent của bạn một cách thoáng qua: **kiểu mẫu** của nó (một trong 8 — `optimist`, `cowboy`, `explorer`, `goldfish`, `paranoid architect`, `precision builder`, `hammer`, `ghost`), các từ khóa nhân cách của nó, kiểu mẫu đó hiếm như thế nào, và điểm **0–100** với dải cấp (`S` xuống `bottom tier`). Được xây dựng để chia sẻ — đăng lên X hoặc LinkedIn, hoặc tải xuống dưới dạng PNG. +2. **`// strengths`** — những gì agent của bạn đã làm tốt, dưới dạng số thực từ bước quét (ví dụ: clean-tool-call %, `0` push-to-main attempts), chỉ hiển thị nơi chính sách liên quan có hồ sơ sạch sẽ. +3. **`// quirks`** — những gì đã lọt qua: bảng hạng các hành vi mà failproofai sẽ phát hiện — *khi nào* lần cuối cùng nó xảy ra, *cái gì đã lọt qua* (và hàng tích hợp sẽ chặn nó), **mức độ nghiêm trọng** của nó, và *bao nhiêu lần* nó được *nhìn thấy* (`new` / `recurring` / `N× seen`). +4. **`// how to improve`** — danh sách sửa chữa được quy định: một hàng cho mỗi chính sách với lệnh `failproofai policy add ` có thể sao chép dán, cộng với nút **install all** cho phép bộ công cụ khuyến nghị mọi cái cùng một lúc và hiển thị **projected score** của bạn nếu bạn làm vậy. +5. **`// come back better`** — xây dựng thói quen: đặt **reminder** tái kiểm toán email (`3d` / `7d` / `14d` / `30d`) hoặc tái kiểm toán ngay bây giờ, và **mời một bạn** để chạy kiểm toán của riêng họ (được gửi từ failproof.ai, Cc cho bạn). Reminders và invites yêu cầu đăng nhập — xem [`failproofai auth`](/vi/cli/auth). -## Detector chỉ dùng cho kiểm toán +## Bộ phát hiện chỉ dành cho kiểm toán -Những cái này phát hiện các mẫu hành vi "ngớ ngẩn" chưa được (thực thi) trong thời gian thực. Chúng chỉ chạy trong quá trình kiểm toán và không bao giờ chặn một lệnh tool gọi trực tiếp. +Những cái này phát hiện các mẫu "hành vi ngu ngốc" không (hoặc chưa) được thực thi trong thời gian thực. Chúng chỉ chạy trong quá trình kiểm toán và không bao giờ chặn lệnh gọi công cụ trực tiếp. -| Detector | Những gì nó đếm | +| Bộ phát hiện | Những gì nó đếm | |---|---| -| `redundant-cd-cwd` | Lệnh Bash bắt đầu với `cd && …` mặc dù các lệnh đã chạy trong `cwd`. | -| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` trên một tệp nguồn duy nhất — hãy sử dụng công cụ `Read`. | -| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` chỉnh sửa tại chỗ — hãy sử dụng công cụ `Edit`. | -| `prefer-write-over-heredoc` | Heredoc / `echo > file` đa dòng ghi tệp — hãy sử dụng công cụ `Write`. | -| `sleep-polling-loop` | Long `sleep N` (≥ 30s) hoặc `while …; sleep …; done` vòng lặp polling. | -| `find-from-root` | `find /`, `find /home`, `find /usr`, v.v. — phạm vi đến `cwd` thay thế. | -| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, bỏ qua hook. | +| `redundant-cd-cwd` | Các lệnh Bash bắt đầu bằng `cd && …` mặc dù các lệnh đã chạy trong `cwd`. | +| `prefer-edit-over-read-cat` | `cat`/`head`/`tail`/`less`/`more` trên một tệp nguồn duy nhất — sử dụng công cụ `Read`. | +| `prefer-edit-over-sed-awk` | `sed -i` / `awk … > file` chỉnh sửa tại chỗ — sử dụng công cụ `Edit`. | +| `prefer-write-over-heredoc` | Heredoc / multi-line `echo > file` ghi tệp — sử dụng công cụ `Write`. | +| `sleep-polling-loop` | `sleep N` dài (≥ 30s) hoặc `while …; sleep …; done` các vòng lặp polling. | +| `find-from-root` | `find /`, `find /home`, `find /usr`, v.v. — phạm vi để `cwd` thay thế. | +| `git-commit-no-verify` | `git commit … --no-verify` / `-n`, bỏ qua hooks. | | `reread-after-edit` | `Read` của một tệp vừa được `Edit`/`Write` trong cùng một phiên. | ## Bộ nhớ đệm -- **Bộ nhớ đệm trên mỗi bản ghi** tại `~/.failproofai/cache/audit/.json` được khóa bởi `(mtime, size, engineVersion, detectorVersion)` — tự động vô hiệu hóa khi bản ghi hoặc mã chính sách/detector thay đổi. Mỗi mục nhập cũng lưu trữ dấu thời gian `cachedAt` như **siêu dữ liệu TTL** (không phải là một phần của khóa bộ nhớ đệm); các mục nhập cũ hơn **7 ngày** bị từ chối khi đọc để các kết quả lâu dài không vượt quá ý định detector phát triển. -- **Bộ nhớ đệm toàn bộ kết quả** tại `~/.failproofai/audit-dashboard.json` (chế độ 0600). Cho phép dashboard hiển thị ngay lập tức khi điều hướng mà không cần chạy lại. Cũng bị từ chối khi đọc quá **7 ngày TTL** — `/audit` sau đó rơi vào trạng thái trống và nhắc chạy lại. Nhấp `[ re-audit now ]` gần phía dưới của báo cáo để làm mới — kiểm toán lại gửi `noCache: true`, vì vậy nó bỏ qua bộ nhớ đệm trên mỗi bản ghi và quét lại mỗi bản ghi thay vì trả về kết quả được lưu trong bộ nhớ đệm; chạy phát trực tuyến tiến trình qua một dải trên cùng dính và hoán đổi kết quả tại chỗ khi thành công (không tải lại trang; một lần kiểm toán lại không thành công sẽ giữ báo cáo trước đó). +- **Bộ nhớ đệm mỗi bảng ghi thoại** tại `~/.failproofai/cache/audit/.json` được khóa bởi `(mtime, size, engineVersion, detectorVersion)` — tự động vô hiệu hóa khi bảng ghi thoại hoặc mã chính sách/bộ phát hiện thay đổi. Mỗi mục cũng lưu trữ dấu thời gian `cachedAt` làm **metadata TTL** (không phải là một phần của khóa bộ nhớ đệm); các mục cũ hơn **7 ngày** bị từ chối khi đọc để kết quả dài hạn không vượt quá ý định bộ phát hiện phát triển. +- **Bộ nhớ đệm toàn bộ kết quả** tại `~/.failproofai/audit-dashboard.json` (chế độ 0600). Cho phép bảng điều khiển hiển thị tức thời khi điều hướng mà không cần chạy lại. Cũng bị từ chối khi đọc sau **TTL 7 ngày** — `/audit` sau đó rơi vào trạng thái trống rỗng của nó và nhắc bạn chạy lại. Nhấp vào `[ re-audit now ]` gần cuối báo cáo để làm mới — tái kiểm toán gửi `noCache: true`, vì vậy nó bỏ qua bộ nhớ đệm mỗi bảng ghi thoại và quét lại mọi bảng ghi thoại thay vì trả về kết quả được lưu trong bộ nhớ đệm; quá trình chạy truyền phát tiến trình thông qua một dải trên cùng dính và trao đổi kết quả tại chỗ khi thành công (không tải lại trang; một tái kiểm toán thất bại giữ báo cáo trước đó). ## Ghi chú -- **Không có đột biến.** Kiểm toán phát lại ở chế độ chỉ đọc. `warn-repeated-tool-calls` bị bỏ qua vì sidecar trên mỗi phiên của nó sẽ bị sửa đổi nếu không. -- **Chính sách workflow bị bỏ qua.** Các chính sách `require-*-before-stop` chỉ kích hoạt trên các sự kiện `Stop` và `execSync` đối với trạng thái git trực tiếp — chúng không có cách diễn giải có ý nghĩa "những gì sẽ xảy ra vào năm 2025", vì vậy chúng không xuất hiện trong số kiểm toán. -- **Chính sách tùy chỉnh bị bỏ qua.** Hook tùy chỉnh do người dùng cung cấp không được phát lại (chúng có thể đã thay đổi kể từ phiên gốc). \ No newline at end of file +- **Không có đột biến.** Kiểm toán phát lại ở chế độ chỉ đọc. `warn-repeated-tool-calls` bị bỏ qua vì sidecar mỗi phiên của nó sẽ bị sửa đổi. +- **Chính sách quy trình công việc bị bỏ qua.** Chính sách `require-*-before-stop` chỉ kích hoạt trên các sự kiện `Stop` và `execSync` so với trạng thái git trực tiếp — chúng không có giải thích "điều gì sẽ xảy ra vào năm 2025" có ý nghĩa, vì vậy chúng không xuất hiện trong số lượng kiểm toán. +- **Chính sách tùy chỉnh bị bỏ qua.** Các hook tùy chỉnh do người dùng cung cấp không được phát lại (chúng có thể đã thay đổi kể từ phiên gốc). \ No newline at end of file diff --git a/docs/vi/configuration.mdx b/docs/vi/configuration.mdx index d94dff4c..3fc78743 100644 --- a/docs/vi/configuration.mdx +++ b/docs/vi/configuration.mdx @@ -4,7 +4,7 @@ description: "Định dạng tệp cấu hình, hệ thống ba phạm vi và qu icon: gear --- -failproofai sử dụng các tệp cấu hình JSON để kiểm soát những chính sách nào đang hoạt động, cách chúng hoạt động như thế nào và nơi tải các chính sách tùy chỉnh. Cấu hình được thiết kế để dễ dàng chia sẻ với nhóm của bạn - cam kết nó vào kho lưu trữ của bạn và mỗi nhà phát triển đều nhận được cùng một lưới bảo vệ cho agent. +failproofai sử dụng tệp cấu hình JSON để kiểm soát những chính sách nào đang hoạt động, cách chúng hoạt động và nơi tải các chính sách tùy chỉnh. Cấu hình được thiết kế để dễ dàng chia sẻ với nhóm của bạn - cam kết nó vào repo của bạn và mỗi nhà phát triển sẽ nhận được cùng một lưới bảo vệ agent. --- @@ -14,31 +14,31 @@ Có ba phạm vi cấu hình, được đánh giá theo thứ tự ưu tiên: | Phạm vi | Đường dẫn tệp | Mục đích | |-------|-----------|---------| -| **project** | `.failproofai/policies-config.json` | Cài đặt theo kho lưu trữ, được cam kết vào kiểm soát phiên bản | -| **local** | `.failproofai/policies-config.local.json` | Ghi đè cá nhân cho mỗi kho lưu trữ, được gitignored | -| **global** | `~/.failproofai/policies-config.json` | Mặc định ở cấp người dùng trên tất cả các dự án | +| **project** | `.failproofai/policies-config.json` | Cài đặt theo repo, cam kết vào kiểm soát phiên bản | +| **local** | `.failproofai/policies-config.local.json` | Ghi đè cá nhân theo repo, gitignored | +| **global** | `~/.failproofai/policies-config.json` | Cài đặt mặc định cấp người dùng trên tất cả các dự án | -Khi failproofai nhận được sự kiện hook, nó sẽ tải và hợp nhất cả ba tệp tồn tại cho thư mục làm việc hiện tại. +Khi failproofai nhận sự kiện hook, nó tải và hợp nhất cả ba tệp tồn tại cho thư mục làm việc hiện tại. ### Quy tắc hợp nhất -**`enabledPolicies`** - hợp nhất tất cả ba phạm vi. Một chính sách được kích hoạt ở bất kỳ cấp độ nào đều hoạt động. +**`enabledPolicies`** - hợp nhất tất cả ba phạm vi. Một chính sách được bật ở bất kỳ cấp độ nào đều hoạt động. ```text project: ["block-sudo"] local: ["block-rm-rf"] global: ["block-sudo", "sanitize-api-keys"] -resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← loại bỏ trùng lặp +resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← hợp nhất loại bỏ trùng lặp ``` -**`policyParams`** - phạm vi đầu tiên xác định các tham số cho một chính sách nhất định sẽ thắng hoàn toàn. Không có hợp nhất sâu các giá trị trong các tham số của chính sách. +**`policyParams`** - phạm vi đầu tiên xác định tham số cho một chính sách nhất định chiến thắng hoàn toàn. Không có hợp nhất sâu các giá trị trong tham số của chính sách. ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project thắng, global bị bỏ qua +resolved: { allowPatterns: ["sudo apt-get update"] } ← project chiến thắng, global bị bỏ qua ``` ```text @@ -49,9 +49,9 @@ global: block-sudo → { allowPatterns: ["sudo systemctl status"] } resolved: { allowPatterns: ["sudo systemctl status"] } ← rơi xuống global ``` -**`customPoliciesPath`** - phạm vi đầu tiên xác định nó sẽ thắng. +**`customPoliciesPath`** - phạm vi đầu tiên xác định nó chiến thắng. -**`llm`** - phạm vi đầu tiên xác định nó sẽ thắng. +**`llm`** - phạm vi đầu tiên xác định nó chiến thắng. --- @@ -96,77 +96,77 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← rơi xuống global --- -## Tham chiếu trường +## Tham khảo trường ### `enabledPolicies` Loại: `string[]` -Danh sách tên chính sách cần kích hoạt. Tên phải khớp chính xác với các định danh chính sách được hiển thị bởi `failproofai policies`. Xem [Built-in Policies](/vi/built-in-policies) để có danh sách đầy đủ. +Danh sách tên chính sách cần bật. Tên phải khớp chính xác với các định danh chính sách được hiển thị bởi `failproofai policies`. Xem [Built-in Policies](/vi/built-in-policies) để biết danh sách đầy đủ. -Các chính sách không có trong `enabledPolicies` không hoạt động, ngay cả khi chúng có mục nhập trong `policyParams`. +Các chính sách không nằm trong `enabledPolicies` không hoạt động, ngay cả khi chúng có mục nhập trong `policyParams`. ### `policyParams` Loại: `Record>` -Ghi đè tham số cho từng chính sách. Khóa bên ngoài là tên chính sách; các khóa bên trong là riêng biệt cho chính sách. Mỗi chính sách ghi lại các tham số có sẵn của nó trong [Built-in Policies](/vi/built-in-policies). +Ghi đè tham số theo chính sách. Khóa bên ngoài là tên chính sách; các khóa bên trong là dành riêng cho chính sách. Mỗi chính sách ghi lại các tham số có sẵn của nó trong [Built-in Policies](/vi/built-in-policies). -Nếu một chính sách có các tham số nhưng bạn không chỉ định chúng, các giá trị mặc định được tích hợp của chính sách sẽ được sử dụng. Người dùng không cấu hình `policyParams` sẽ nhận được hành vi giống hệt với các phiên bản trước đó. +Nếu một chính sách có tham số nhưng bạn không chỉ định chúng, các giá trị mặc định tích hợp của chính sách sẽ được sử dụng. Người dùng không định cấu hình `policyParams` hoàn toàn sẽ nhận được hành vi giống hệt các phiên bản trước đó. -Các khóa không xác định trong khối tham số của một chính sách bị bỏ qua âm thầm khi hook kích hoạt nhưng được đánh dấu là cảnh báo khi bạn chạy `failproofai policies`. +Các khóa không xác định bên trong khối tham số của chính sách sẽ bị bỏ qua im lặng khi hook được kích hoạt nhưng được đánh dấu là cảnh báo khi bạn chạy `failproofai policies`. #### `hint` (cross-cutting) Loại: `string` (tùy chọn) -Một thông báo được thêm vào lý do khi một chính sách trả về `deny` hoặc `instruct`. Sử dụng nó để cung cấp cho Claude hướng dẫn có thể thực hiện được mà không cần sửa đổi chính sách. +Một tin nhắn được nối thêm vào lý do khi chính sách trả về `deny` hoặc `instruct`. Sử dụng nó để cung cấp cho Claude hướng dẫn có thể thực hiện được mà không cần sửa đổi chính sách. -Hoạt động với bất kỳ loại chính sách nào — built-in, custom (`custom/`), project convention (`.failproofai-project/`), hoặc user convention (`.failproofai-user/`). +Hoạt động với bất kỳ loại chính sách nào — tích hợp, tùy chỉnh (`custom/`), quy ước dự án (`.failproofai-project/`) hoặc quy ước người dùng (`.failproofai-user/`). ```json { "policyParams": { "block-force-push": { - "hint": "Try creating a fresh branch instead." + "hint": "Hãy thử tạo một nhánh mới thay thế." }, "block-sudo": { "allowPatterns": ["sudo apt-get"], - "hint": "Use apt-get directly without sudo." + "hint": "Sử dụng apt-get trực tiếp mà không cần sudo." }, "custom/my-policy": { - "hint": "Ask the user for approval first." + "hint": "Hãy yêu cầu phê duyệt của người dùng trước." } } } ``` -Khi `block-force-push` từ chối, Claude sẽ thấy: *"Force-pushing is blocked. Try creating a fresh branch instead."* +Khi `block-force-push` từ chối, Claude sẽ thấy: *"Force-pushing bị chặn. Hãy thử tạo một nhánh mới thay thế."* -Các giá trị không phải chuỗi và chuỗi trống bị bỏ qua âm thầm. Nếu `hint` không được đặt, hành vi không thay đổi (tương thích ngược). +Các giá trị không phải chuỗi và chuỗi trống sẽ bị bỏ qua im lặng. Nếu `hint` không được đặt, hành vi không thay đổi (tương thích ngược). ### `customPoliciesPath` Loại: `string` (đường dẫn tuyệt đối) -Đường dẫn đến tệp JavaScript chứa các chính sách hook tùy chỉnh. Điều này được đặt tự động bởi `failproofai policies --install --custom ` (đường dẫn được phân giải thành tuyệt đối trước khi được lưu trữ). +Đường dẫn đến tệp JavaScript chứa các chính sách hook tùy chỉnh. Điều này được đặt tự động bởi `failproofai policies --install --custom ` (đường dẫn được phân giải thành tuyệt đối trước khi lưu trữ). -Tệp được tải lại trên mỗi sự kiện hook - không có bộ nhớ cache. Xem [Custom Policies](/vi/custom-policies) để biết chi tiết về tác giả. +Tệp được tải mới trên mỗi sự kiện hook - không có bộ đệm. Xem [Custom Policies](/vi/custom-policies) để biết chi tiết tác giả. -### Các chính sách dựa trên quy ước +### Chính sách dựa trên quy ước -Ngoài `customPoliciesPath` rõ ràng, failproofai tự động phát hiện và tải các tệp chính sách từ các thư mục `.failproofai/policies/`: +Ngoài `customPoliciesPath` rõ ràng, failproofai tự động khám phá và tải các tệp chính sách từ các thư mục `.failproofai/policies/`: | Cấp độ | Thư mục | Phạm vi | |-------|-----------|-------| -| Project | `.failproofai/policies/` | Chia sẻ với nhóm thông qua kiểm soát phiên bản | -| User | `~/.failproofai/policies/` | Cá nhân, áp dụng cho tất cả các dự án | +| Dự án | `.failproofai/policies/` | Chia sẻ với nhóm thông qua kiểm soát phiên bản | +| Người dùng | `~/.failproofai/policies/` | Cá nhân, áp dụng cho tất cả các dự án | -**Khớp tệp:** Chỉ những tệp khớp với `*policies.{js,mjs,ts}` được tải (ví dụ: `security-policies.mjs`, `workflow-policies.js`). Các tệp khác trong thư mục bị bỏ qua. +**Khớp tệp:** Chỉ tệp khớp với `*policies.{js,mjs,ts}` được tải (ví dụ `security-policies.mjs`, `workflow-policies.js`). Các tệp khác trong thư mục sẽ bị bỏ qua. -**Không cần cấu hình:** Các chính sách quy ước không cần các mục nhập trong `policies-config.json`. Chỉ cần thả các tệp vào thư mục và chúng sẽ được chọn vào sự kiện hook tiếp theo. +**Không cần cấu hình:** Chính sách quy ước không cần mục nhập trong `policies-config.json`. Chỉ cần thả tệp vào thư mục và chúng sẽ được nhặt trên sự kiện hook tiếp theo. -**Tải hợp nhất:** Cả thư mục quy ước dự án và người dùng đều được quét. Tất cả các tệp phù hợp từ cả hai cấp độ được tải (không giống như `customPoliciesPath` sử dụng first-scope-wins). +**Tải hợp nhất:** Cả thư mục quy ước dự án và người dùng được quét. Tất cả tệp phù hợp từ cả hai cấp độ được tải (không giống như `customPoliciesPath` sử dụng first-scope-wins). Xem [Custom Policies](/vi/custom-policies) để biết thêm chi tiết và ví dụ. @@ -174,7 +174,7 @@ Xem [Custom Policies](/vi/custom-policies) để biết thêm chi tiết và ví Loại: `object` (tùy chọn) -Cấu hình máy khách LLM cho các chính sách thực hiện các cuộc gọi AI. Không bắt buộc cho hầu hết các bộ cài đặt. +Cấu hình máy khách LLM cho các chính sách thực hiện các cuộc gọi AI. Không bắt buộc cho hầu hết các thiết lập. ```json { @@ -189,20 +189,24 @@ Cấu hình máy khách LLM cho các chính sách thực hiện các cuộc gọ ## Quản lý cấu hình từ CLI -Các lệnh `policies --install` và `policies --uninstall` ghi vào tệp cài đặt hook của CLI agent của bạn (các điểm nhập hook), trong khi `policies-config.json` là tệp bạn quản lý trực tiếp. Hai loại này là riêng biệt: - -- **Cài đặt Agent CLI** — cho agent biết gọi `failproofai --hook ` trên mỗi tool use: - - **Claude Code**: `~/.claude/settings.json` (user), `/.claude/settings.json` (project), `/.claude/settings.local.json` (local) - - **OpenAI Codex**: `~/.codex/hooks.json` (user), `/.codex/hooks.json` (project) — Codex không có phạm vi `local` - - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (user), `/.github/hooks/failproofai.json` (project) — Copilot không có phạm vi `local`. Các mục nhập hook sử dụng các trường lệnh `bash`/`powershell` được khóa bằng OS của Copilot với `timeoutSec`; tệp có dấu hiệu `version: 1` ở cấp cao nhất. Hỗ trợ Copilot CLI đang ở **beta** khi chúng tôi xác minh lược đồ bản ghi `events.jsonl` (không được tài liệu công khai chỉ định) so với các phiên làm việc thực tế hơn. - - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (user), `/.cursor/hooks.json` (project) — Cursor không có phạm vi `local`. Các mục nhập hook sử dụng dạng `{type, command, timeout}` tương tự Claude (không chia tách `bash`/`powershell`), nhưng được lưu trữ dưới các khóa sự kiện camelCase (`preToolUse`, `beforeSubmitPrompt`, …) trong một mảng phẳng theo [schemas hooks](https://cursor.com/docs/hooks) của Cursor; tệp có dấu hiệu `version: 1` ở cấp cao nhất. Trình xử lý chuẩn hóa camelCase → PascalCase qua `CURSOR_EVENT_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Hỗ trợ Cursor Agent đang ở **beta** khi chúng tôi xác minh định dạng transcript trên đĩa của Cursor (không được chỉ định trong tài liệu công khai) so với các cài đặt thực tế hơn. - - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (user), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (project) — OpenCode không có phạm vi `local`. Không giống như sáu CLI khác, OpenCode **không có hệ thống hook lệnh bên ngoài**: nó tải các plugin JS/TS in-process được đăng ký rõ ràng qua mảng `plugin: []` trong `opencode.json` (tự động phát hiện từ `.opencode/plugins/` **không** là cách các plugin tải trên opencode v1.14.33). Cài đặt thả một shim plugin nhỏ được tạo ra gọi đến nhị phân failproofai qua subprocess và dịch phản hồi JSON hình dạng Claude của nhị phân trở lại ngữ nghĩa plugin: `throw new Error()` cho tool-event deny (hủy lệnh gọi công cụ), `client.session.prompt(...)` cho instruct VÀ cho `Stop` / `SubagentStop` deny (gửi lý do từ chối dưới dạng thông báo người dùng tiếp theo — kênh thử lại buộc duy nhất vì `session.idle` chỉ là thông báo và ném từ nó là no-op), và no-op cho allow. Shim chuẩn hóa cả tên công cụ (chữ thường → PascalCase qua `OPENCODE_TOOL_MAP`) và khóa đối số đầu vào công cụ (camelCase → snake_case qua `OPENCODE_TOOL_INPUT_MAP` cho `Read` / `Write` / `Edit`, ví dụ: `filePath` → `file_path`, `oldString` → `old_string`) trước khi chuyển tiếp đến nhị phân, vì vậy các built-in kiểm tra đường dẫn như `block-read-outside-cwd`, `block-env-files` và `block-secrets-write` kích hoạt không thay đổi trên các lệnh gọi công cụ OpenCode. Các phiên tồn tại trong cơ sở dữ liệu SQLite của opencode tại `~/.local/share/opencode/opencode.db`; người xem phiên của bảng điều khiển đọc chúng qua `opencode db --format json` và `opencode export `. Hỗ trợ OpenCode đang ở **beta** khi chúng tôi xác minh hành vi trên các phiên bản và so với các phiên làm việc thực tế hơn. Xem [tài liệu plugins OpenCode](https://opencode.ai/docs/plugins/). - - **Pi _(beta)_**: `~/.pi/agent/settings.json` (user), `/.pi/settings.json` (project) — Pi không có phạm vi `local`. Pi tải các gói mở rộng TypeScript khi khởi động; tệp cài đặt là một mảng chuỗi phẳng `{"packages": ["./relative/path", …]}`. failproofai viết một mục nhập mảng package duy nhất trỏ vào thư mục `pi-extension/` được đóng gói của nó. Tiện ích mở rộng bên trong đăng ký các sự kiện `tool_call` / `user_bash` / `input` / `session_start` của Pi và shell ra `failproofai --hook --cli pi`; trình xử lý chuẩn hóa underscore_lower_snake_case → PascalCase qua `PI_EVENT_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Các đối số đầu vào công cụ cũng được chuẩn hóa qua `PI_TOOL_INPUT_MAP` (Read / Write / Edit của Pi cung cấp `path` thay vì `file_path`; ánh xạ khóa cấp cao nhất cho phép `block-env-files` và `block-secrets-write` kích hoạt — `block-read-outside-cwd` đã có fallback `path`). Hỗ trợ Pi đang ở **beta** khi Pi's extension API và layout nhật ký phiên ổn định. - - **Gemini CLI _(beta)_**: `~/.gemini/settings.json` (user), `/.gemini/settings.json` (project) — Gemini không có phạm vi `local` (nó ghi lại phạm vi `system` tại `/etc/gemini-cli/settings.json` mà failproofai không tiếp xúc). Các mục nhập hook sử dụng dạng `{type, command, timeout}` của Claude được bao bọc trong lược đồ matcher `{matcher, hooks: [...]}` của Gemini với `matcher: "*"` theo mặc định. Các sự kiện là PascalCase (`SessionStart`, `BeforeAgent`, `AfterAgent`, `BeforeModel`, `AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`, `Notification`, `SessionEnd`); trình xử lý ánh xạ đến tên Claude canonical qua `GEMINI_EVENT_MAP`. Tên công cụ là snake_case (`run_shell_command`, `read_file`, `write_file`, `replace`, …) — trình xử lý chuẩn hóa qua `GEMINI_TOOL_MAP` vì vậy các chính sách built-in hiện có kích hoạt không thay đổi. Trình đánh giá chính sách phát hành hình dạng phẳng `{decision: "deny", reason}` của Gemini (ưu tiên theo Golden Rule exit-0 contract của Gemini), `{hookSpecificOutput: {hookEventName, additionalContext}}` cho tiêm ngữ cảnh trên BeforeAgent / AfterTool / SessionStart, và `{decision: "block", reason}` trên AfterTool cho ngữ nghĩa thử lại buộc. Hỗ trợ Gemini CLI đang ở **beta** khi chúng tôi mở rộng phạm vi thế giới thực. Xem [tài liệu hooks Gemini CLI](https://geminicli.com/docs/hooks/). - - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**phạm vi người dùng duy nhất** — Hermes không có cấu hình dự án/cục bộ). Hermes là một **cổng** Slack/Telegram, vì vậy một cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng (Slack/Telegram/cli/cron) **và** các subagent nội bộ. Các mục nhập hook là một cặp `{command, timeout}` (timeout tính bằng **giây**) dưới bản đồ `hooks:` được khóa bằng các sự kiện snake_case của Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); trình xử lý chuẩn hóa các sự kiện qua `HERMES_EVENT_MAP` và tên công cụ qua `HERMES_TOOL_MAP` vì vậy các chính sách built-in kích hoạt không thay đổi. Cấu hình được chỉnh sửa thông qua vòng quay YAML `Document` bảo tồn nhận xét vì vậy các cài đặt khác của nhà điều hành sống sót, và cài đặt đặt `hooks_auto_accept: true` vì vậy cổng headless (không TTY) chạy các hook mà không có lời nhắc đồng ý. Trình đánh giá phát hành hợp đồng stdout `{"decision":"block","reason"}` của Hermes (Hermes bỏ qua mã thoát). **Hạn chế:** Hermes không có sự kiện `Stop` kết thúc lượt, vì vậy các built-in `require-*-before-stop` không bao giờ kích hoạt cho nó (không áp dụng được, không bị hỏng); `instruct` suy giảm thành allow-with-logged-note (không có kênh ngữ cảnh bổ sung); và redaction bí mật đầu ra (`sanitize-*`) không thể viết lại đầu ra công cụ trên hợp đồng shell-hook. Hermes cũng là một nguồn **audit** **ngoại tuyến** — bảng điều khiển đọc các phiên cổng của nó trực tiếp từ `~/.hermes/state.db`. -- **`policies-config.json`** — cho failproofai biết những chính sách nào cần đánh giá và với những tham số nào (chia sẻ trên tất cả các CLI agent) - -Chuyển `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` để nhắm vào một agent cụ thể (cách nhau bằng dấu cách hoặc lặp lại cho bất kỳ tập con nào): +Các lệnh `policies --install` và `policies --uninstall` ghi vào tệp cài đặt hook của agent CLI của bạn (các điểm nhập hook), trong khi `policies-config.json` là tệp bạn quản lý trực tiếp. Hai cái này là riêng biệt: + +- **Cài đặt Agent CLI** — cho agent biết gọi `failproofai --hook ` trên mỗi lần sử dụng công cụ: + - **Claude Code**: `~/.claude/settings.json` (người dùng), `/.claude/settings.json` (dự án), `/.claude/settings.local.json` (cục bộ) + - **OpenAI Codex**: `~/.codex/hooks.json` (người dùng), `/.codex/hooks.json` (dự án) — Codex không có phạm vi `local` + - **GitHub Copilot CLI _(beta)_**: `~/.copilot/hooks/failproofai.json` (người dùng), `/.github/hooks/failproofai.json` (dự án) — Copilot không có phạm vi `local`. Mục nhập hook sử dụng trường lệnh `bash`/`powershell` được khóa hệ điều hành của Copilot với `timeoutSec`; tệp mang một đánh dấu `version: 1` cấp cao nhất. Hỗ trợ Copilot CLI là **beta** trong khi chúng tôi xác minh lược đồ bản ghi `events.jsonl` (các tài liệu công cộng không chỉ định) so với nhiều phiên bản thực tế hơn. **Chế độ agent VS Code Copilot Chat (Preview)** đọc cấu hình hook từ `.github/hooks/*.json`, `~/.copilot/hooks/*.json` và `~/.claude/settings.json` (được quản lý bởi cài đặt `chat.hookFilesLocations`) sử dụng hợp đồng `{hookSpecificOutput:{permissionDecision:"deny",…}}` hình dạng Claude giống nhau — những đường dẫn chính xác mà tích hợp `copilot` này và tích hợp `claude` (`~/.claude/settings.json`) đã ghi, vì vậy `failproofai policies --install --cli copilot` (hoặc `--cli claude`) **đã thực thi trong chế độ agent VS Code** mà không cần tích hợp `vscode` riêng (được xác nhận trực tiếp từ nhật ký khám phá VS Code). + - **Cursor Agent _(beta)_**: `~/.cursor/hooks.json` (người dùng), `/.cursor/hooks.json` (dự án) — Cursor không có phạm vi `local`. Mục nhập hook sử dụng biểu mẫu `{type, command, timeout}` hình dạng Claude (không chia `bash`/`powershell`), nhưng được lưu trữ dưới các khóa sự kiện camelCase (`preToolUse`, `beforeSubmitPrompt`, …) trong một mảng phẳng theo [lược đồ hook](https://cursor.com/docs/hooks) của Cursor. Tệp mang một đánh dấu `version: 1` cấp cao nhất. Trình xử lý sắp xếp lại camelCase → PascalCase thông qua `CURSOR_EVENT_MAP` để các chính sách tích hợp hiện có kích hoạt không thay đổi. Hỗ trợ Cursor Agent là **beta** trong khi chúng tôi xác minh định dạng bản ghi Cursor trên đĩa (không được chỉ định trong tài liệu công cộng) so với nhiều cài đặt thực tế hơn. + - **OpenCode _(beta)_**: `~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs` (người dùng), `/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs` (dự án) — OpenCode không có phạm vi `local`. Không giống năm CLI khác, OpenCode không có **hệ thống hook lệnh bên ngoài**: nó tải các plugin JS/TS trong quá trình được đăng ký rõ ràng thông qua mảng `plugin: []` trong `opencode.json` (tự động khám phá từ `.opencode/plugins/` **không phải** cách plugin tải trên opencode v1.14.33). Cài đặt thả một shim plugin nhỏ được tạo gọi subprocess lệnh nhị phân failproofai và dịch phản hồi JSON hình dạng Claude của nhị phân trở lại ngữ nghĩa plugin: `throw new Error()` cho tool-event deny (hủy lệnh công cụ), `client.session.prompt(...)` cho instruct VÀ cho `Stop` / `SubagentStop` deny (gửi lý do từ chối dưới dạng tin nhắn người dùng tiếp theo — kênh thử lại lực duy nhất vì `session.idle` chỉ dành cho thông báo và ném từ nó là no-op), và no-op cho allow. Shim sắp xếp lại cả tên công cụ (chữ thường → PascalCase thông qua `OPENCODE_TOOL_MAP`) và khóa arg đầu vào công cụ (camelCase → snake_case thông qua `OPENCODE_TOOL_INPUT_MAP` cho `Read` / `Write` / `Edit`, ví dụ `filePath` → `file_path`, `oldString` → `old_string`) trước khi chuyển tiếp đến nhị phân, vì vậy kiểm tra đường dẫn tích hợp như `block-read-outside-cwd`, `block-env-files` và `block-secrets-write` kích hoạt không thay đổi trên các lệnh gọi công cụ OpenCode. Phiên hoạt động trong DB SQLite của opencode tại `~/.local/share/opencode/opencode.db`; trình xem phiên bản của bảng điều khiển đọc chúng thông qua `opencode db --format json` và `opencode export `. Hỗ trợ OpenCode là **beta** trong khi chúng tôi xác minh hành vi trên các phiên bản và so với nhiều phiên bản thực tế hơn. Xem [tài liệu plugin OpenCode](https://opencode.ai/docs/plugins/). + - **Pi _(beta)_**: `~/.pi/agent/settings.json` (người dùng), `/.pi/settings.json` (dự án) — Pi không có phạm vi `local`. Pi tải các gói mở rộng TypeScript khi khởi động; tệp cài đặt là mảng chuỗi phẳng `{"packages": ["./relative/path", …]}`. failproofai ghi một mục mảng package duy nhất chỉ vào thư mục `pi-extension/` được gói của nó. Phần mở rộng bên trong đăng ký vào các sự kiện `tool_call` / `user_bash` / `input` / `session_start` của Pi và shell ra `failproofai --hook --cli pi`; trình xử lý sắp xếp lại underscore_lower_snake_case → PascalCase thông qua `PI_EVENT_MAP` để các chính sách tích hợp hiện có kích hoạt không thay đổi. Các arg đầu vào công cụ cũng được sắp xếp lại thông qua `PI_TOOL_INPUT_MAP` (Pi's Read / Write / Edit cung cấp `path` thay vì `file_path`; ánh xạ khóa cấp cao nhất cho phép `block-env-files` và `block-secrets-write` kích hoạt — `block-read-outside-cwd` đã có một fallback `path`). Hỗ trợ Pi là **beta** trong khi API mở rộng Pi và bố cục nhật ký phiên ổn định. + - **Hermes (hermes-agent)**: `~/.hermes/config.yaml` (**phạm vi người dùng chỉ** — Hermes không có cấu hình dự án/cục bộ). Hermes là một cổng **Slack/Telegram**, vì vậy một cài đặt chặn các lệnh gọi công cụ từ mọi nền tảng (Slack/Telegram/cli/cron) **và** các agent con nội bộ. Mục nhập hook là một cặp `{command, timeout}` (timeout tính bằng **giây**) dưới một bản đồ `hooks:` được khóa bởi các sự kiện snake_case của Hermes (`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`); trình xử lý sắp xếp lại các sự kiện thông qua `HERMES_EVENT_MAP` và tên công cụ thông qua `HERMES_TOOL_MAP` để các chính sách tích hợp kích hoạt không thay đổi. Cấu hình được chỉnh sửa thông qua vòng tròn YAML `Document` bảo tồn bình luận để cài đặt khác của nhà điều hành tồn tại, và cài đặt `hooks_auto_accept: true` để cổng không đầu (không TTY) chạy các hook mà không nhắc yêu cầu sự đồng ý. Trình đánh giá phát ra hợp đồng stdout Hermes `{"decision":"block","reason"}` (Hermes bỏ qua mã thoát). **Giới hạn:** Hermes không có sự kiện kết thúc lượt `Stop`, vì vậy các tích hợp `require-*-before-stop` không bao giờ kích hoạt cho nó (không áp dụng, không bị hỏng); `instruct` giảm xuống allow-with-logged-note (không kênh ngữ cảnh bổ sung); và redaction bí mật đầu ra (`sanitize-*`) không thể viết lại đầu ra công cụ trên hợp đồng shell-hook. Hermes cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các phiên cổng của nó trực tiếp từ `~/.hermes/state.db`. + - **OpenClaw (cổng openclaw)**: `~/.openclaw/openclaw.json` (**phạm vi người dùng chỉ** — OpenClaw không có cấu hình dự án/cục bộ). Giống như Hermes, OpenClaw là một cổng **đa kênh** tự lưu trữ, vì vậy một cài đặt chặn các lệnh gọi công cụ từ mọi kênh và các agent con nội bộ của nó. Thực thi chạy thông qua **hook trong quá trình của OpenClaw** (các hook dựa trên tệp nội bộ của nó chỉ dành cho quan sát và không thể chặn), vì vậy — giống như OpenCode/Pi — failproofai vận chuyển một gói `openclaw-plugin/` tĩnh spawns không đồng bộ lệnh nhị phân failproofai và dịch phán quyết. Cài đặt đăng ký thư mục plugin đã gửi trong `openclaw.json` của `plugins.load.paths[]` và cho phép nó dưới `plugins.entries.failproofai` (với `hooks.allowConversationAccess: true`, cần thiết cho các hook cuộc trò chuyện thô). Trình đánh giá phát ra phán quyết `{permission, reason}` phẳng và shim ánh xạ nó thành hình dạng trả về gốc của mỗi hook: `before_tool_call → {block:true, blockReason}` (**PreToolUse**), `before_agent_run → {outcome:"block", reason}` (**UserPromptSubmit**), và `before_agent_finalize → {action:"revise", reason}` (**Stop** — một cổng kết thúc lượt thực sự, vì vậy các tích hợp `require-*-before-stop` **thực thi** trên OpenClaw, không giống như Hermes). Các sự kiện và tên công cụ sắp xếp lại nhị phân bên phía thông qua `OPENCLAW_EVENT_MAP` / `OPENCLAW_TOOL_MAP` (`exec→Bash`, `read→Read`, …) vì vậy các chính sách tích hợp kích hoạt không thay đổi; shim không thành công mở trên bất kỳ lỗi spawn/parse/timeout nào. OpenClaw cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các phiên JSONL của nó tại `~/.openclaw/agents//sessions/.jsonl`. + - **Factory Droid (`droid`)**: `~/.factory/hooks.json` (người dùng), `/.factory/hooks.json` (dự án) — Factory không có phạm vi `local`. droid vận chuyển một hệ thống hook lệnh bên ngoài kiểu Claude, nhưng với hai điểm kỳ quặc được xác minh trực tiếp so với droid v0.171.0: (1) tên sự kiện sống ở **cấp cao nhất** của `hooks.json` — không có **bộ bao `"hooks"`** (droid từ chối một); các sự kiện công cụ (`PreToolUse`/`PostToolUse`) mang `"matcher": "*"`, các sự kiện không phải công cụ bỏ qua nó. (2) Deny được chạy bởi mã thoát hook **2 + stderr**, không phải quyết định JSON — nhánh `factory` của trình đánh giá trả về thoát 2 cho các sự kiện công cụ/nhắc nhở và `{decision:"block", reason}` chỉ trên sự kiện kết thúc lượt `Stop` (kênh thử lại lực duy nhất của droid). Các sự kiện đã là PascalCase (không có bản đồ sự kiện) và tải trọng là snake_case Claude; chỉ tên công cụ được sắp xếp lại thông qua `FACTORY_TOOL_MAP` (`Execute→Bash`, `Create→Write`, `FetchUrl→WebFetch`, …). Factory cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các phiên JSONL trên đĩa của nó tại `~/.factory/sessions//.jsonl`. + - **Devin CLI (`devin`, Cognition)**: `~/.config/devin/config.json` (người dùng), `/.devin/config.json` (dự án) — Devin không có phạm vi `local`. Devin là một **bản sao Claude thuần** được xác minh trực tiếp so với devin v3000.1.27: nó sử dụng lược đồ `"hooks"`-wrapper Claude tiêu chuẩn (các ghi sẽ bảo tồn hợp nhất để các khóa khác của tệp cấu hình — `org_id`, `theme_mode`, … — tồn tại), tên sự kiện đã là PascalCase (không có bản đồ sự kiện, không có nhánh trình xử lý) và tải trọng stdin PascalCase snake_case Claude (không có chuẩn hóa). Nhánh `devin` của trình đánh giá từ chối với JSON `{"decision":"block","reason"}` trên stdout tại exit 0 cho **mọi** sự kiện (được xác minh — khối ghi đè `--permission-mode dangerous`); trên sự kiện kết thúc lượt `Stop` lý do mang từ ngữ force-retry BẮT BUỘC-ACTION để các tích hợp `require-*-before-stop` thực thi. Chỉ tên công cụ được sắp xếp lại thông qua `DEVIN_TOOL_MAP` (`exec→Bash`; `tool_input.command` đã là chính tắc). Devin cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các phiên SQLite của nó tại `~/.local/share/devin/cli/sessions.db` (mỗi hàng `sessions` mang một `working_directory` thực sự, vì vậy các phiên nhóm theo dự án cwd như Claude). + - **Antigravity CLI (`agy`)**: `~/.gemini/config/hooks.json` (người dùng), `/.agents/hooks.json` (dự án) — Antigravity không có phạm vi `local`. Không giống Factory/Devin, Antigravity có **hợp đồng riêng của nó** (không phải bản sao Claude), được xác minh trực tiếp so với agy v1.1.2. `hooks.json` sử dụng **lược đồ hook được đặt tên**: khóa cấp cao nhất là tên hook *name* (`"failproofai"`) có giá trị là bản đồ sự kiện→trình xử lý — các sự kiện công cụ (`PreToolUse`/`PostToolUse`) bao trình xử lý trong `{matcher:"*", hooks:[…]}`, trong khi `PreInvocation`/`Stop` là **phẳng** mảng trình xử lý (các hook được đặt tên khác được bảo tồn). Tải trọng stdin là **camelCase protojson** (`toolCall:{name,args}`, `conversationId`, `workspacePaths`, `transcriptPath`) — failproofai chuẩn hóa nó thành snake_case trước khi các chính sách chạy, và ánh xạ arg PascalCase của `run_command` (`CommandLine`/`Cwd`) thông qua `ANTIGRAVITY_TOOL_INPUT_MAP`. Nhánh `antigravity` của trình đánh giá sử dụng hình dạng phản hồi **riêng** của Antigravity: `{decision:"deny", reason}` chặn một công cụ/nhắc nhở (exit 0), `{decision:"continue", reason}` trên sự kiện kết thúc lượt `Stop` nhập lại vòng lặp (vì vậy các tích hợp `require-*-before-stop` thực thi) và `{injectSteps:[{ephemeralMessage}]}` tiêm một hướng dẫn trên `PreInvocation` (→ `UserPromptSubmit`). Tên công cụ sắp xếp lại thông qua `ANTIGRAVITY_TOOL_MAP` (`run_command→Bash`, `view_file→Read`, …). Antigravity cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các bản ghi JSONL thuần túy của nó tại `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` (chỉ mục cuộc trò chuyện trong `conversation_summaries.db`). + - **Goose (tên mã goose, Block)**: `~/.agents/plugins/failproofai/hooks/hooks.json` (người dùng), `/.agents/plugins/failproofai/hooks/hooks.json` (dự án) — Goose không có phạm vi `local`. Thực thi sử dụng hệ thống **hook** của Goose, lệnh **Open Plugins** đa agent: trình cài đặt chỉ cần thả thư mục plugin `failproofai` và Goose tự động khám phá nó khi khởi động (tự đăng ký nó vào `~/.config/goose/config.yaml`). `hooks.json` sử dụng lược đồ Open Plugins **với** bộ bao `"hooks"` cấp cao nhất, và khớp bị **bỏ qua** trên mọi sự kiện — `"*"` trần là một regex không hợp lệ không khớp bất cứ điều gì (được xác minh trực tiếp so với goose v1.43.0). Tên sự kiện đã là PascalCase (không có bản đồ sự kiện); tải trọng stdin sử dụng `event`/`working_dir`, mà trình xử lý chuẩn hóa thành `hook_event_name`/`cwd`. Nhánh `goose` của trình đánh giá từ chối với JSON `{"decision":"block","reason"}` trên stdout tại exit 0, được tôn trọng trên sự kiện **`PreToolUse`** chỉ (được vận chuyển trong goose ≥ v1.37.0) — kích hoạt cho công cụ shell **và bên trong các agent con được ủy quyền**, vì vậy nó là điểm deny duy nhất đủ; bất kỳ lỗi hook khác nào **mở** không thành công. Goose không có **sự kiện `Stop`**, vì vậy các tích hợp `require-*-before-stop` không áp dụng (như với Hermes). Tên công cụ sắp xếp lại thông qua `GOOSE_TOOL_MAP` (`shell→Bash`, `write→Write`, `todo__todo_write→TodoWrite`, …) và khóa đường dẫn thông qua `GOOSE_TOOL_INPUT_MAP` (`path`/`source` → `file_path`). Goose cũng là một nguồn **kiểm toán** ngoại tuyến — bảng điều khiển đọc các phiên SQLite của nó tại `~/.local/share/goose/sessions/sessions.db` (mỗi hàng `sessions` mang một `working_dir` thực sự, vì vậy các phiên nhóm theo dự án cwd như Devin; các lần chạy scratch `--no-session` bị lọc). +- **`policies-config.json`** — cho failproofai biết những chính sách nào để đánh giá và với những tham số nào (chia sẻ trên tất cả các agent CLI) + +Chuyển `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` để nhắm mục tiêu một agent cụ thể (cách nhau bằng dấu cách hoặc lặp lại cho bất kỳ tập hợp con nào): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -Khi `--cli` bị bỏ qua, `failproofai` phát hiện những agent CLI nào được cài đặt (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +Khi `--cli` được bỏ qua, `failproofai` phát hiện những agent CLI nào được cài đặt (`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): -- **Một CLI được phát hiện** — tự động chọn CLI đó mà không cần nhắc. -- **Nhiều CLI được phát hiện** trong terminal tương tác — hiển thị lời nhắc lựa chọn đơn có mũi tên được nhóm thành phần Detected (N) (với hàng tổng hợp Cài đặt cho tất cả N detected + từng CLI được phát hiện riêng lẻ) và phần Not installed (M) · install hooks ahead of time liệt kê mỗi CLI được hỗ trợ không được phát hiện dưới dạng tùy chọn cài đặt trước (↑↓ để di chuyển, Enter để chọn, ^C để thoát). Dòng gỡ cài đặt chỉ hiển thị phần Detected. -- **Nhiều CLI được phát hiện** trong chạy không tương tác (CI, không TTY) — cài đặt cho tất cả các CLI được phát hiện mà không cần nhắc. -- **Không phát hiện được** — quay lại `claude`, có cảnh báo rằng không tìm thấy nhị phân agent nào trong PATH; lệnh hook vẫn được viết vì vậy nó kích hoạt ngay khi bạn cài đặt một. +- **Một CLI được phát hiện** — tự động chọn CLI đó mà không nhắc. +- **Nhiều CLI được phát hiện** trong một thiết bị đầu cuối tương tác — hiển thị dấu mũi tên lựa chọn đơn nhóm thành phần `Detected (N)` (có hàng tổng hợp `Install for all N detected` + từng CLI được phát hiện riêng lẻ) và phần `Not installed (M) · install hooks ahead of time` liệt kê mọi CLI không được phát hiện được hỗ trợ dưới dạng tùy chọn cài đặt trước (↑↓ để di chuyển, Enter để chọn, ^C để thoát). Luồng gỡ cài đặt hiển thị chỉ phần Detected. +- **Nhiều CLI được phát hiện** trong một lần chạy không tương tác (CI, không TTY) — cài đặt cho tất cả các CLI được phát hiện mà không nhắc. +- **Không có được phát hiện** — quay lại `claude`, với cảnh báo rằng không tìm thấy nhị phân agent nào trong PATH; lệnh hook vẫn được ghi để nó kích hoạt ngay khi bạn cài đặt một. -Bạn có thể chỉnh sửa `policies-config.json` trực tiếp bất kỳ lúc nào; những thay đổi có hiệu lực ngay lập tức vào sự kiện hook tiếp theo mà không cần khởi động lại. +Bạn có thể chỉnh sửa `policies-config.json` trực tiếp bất kỳ lúc nào; các thay đổi có hiệu lực ngay trên sự kiện hook tiếp theo mà không cần khởi động lại. --- -## Ví dụ: cấu hình cấp dự án với mặc định nhóm +## Ví dụ: cấu hình cấp dự án với các giá trị mặc định của nhóm -Cam kết `.failproofai/policies-config.json` vào kho lưu trữ của bạn: +Cam kết `.failproofai/policies-config.json` vào repo của bạn: ```json { @@ -247,4 +255,4 @@ Cam kết `.failproofai/policies-config.json` vào kho lưu trữ của bạn: } ``` -Mỗi nhà phát triển sau đó có thể tạo `.failproofai/policies-config.local.json` (gitignored) để ghi đè cá nhân mà không ảnh hưởng đến đồng đội. \ No newline at end of file +Mỗi nhà phát triển sau đó có thể tạo `.failproofai/policies-config.local.json` (gitignored) để ghi đè cá nhân mà không ảnh hưởng đến các đồng nghiệp. \ No newline at end of file diff --git a/docs/vi/dashboard.mdx b/docs/vi/dashboard.mdx index 219cbd9b..28dc8c15 100644 --- a/docs/vi/dashboard.mdx +++ b/docs/vi/dashboard.mdx @@ -1,11 +1,10 @@ --- ---- title: Bảng điều khiển description: "Giám sát các phiên làm việc của agent, xem xét các lệnh gọi công cụ và quản lý chính sách" icon: chart-line --- -Bảng điều khiển failproofai là một ứng dụng web cục bộ để giám sát các phiên làm việc của agent AI và quản lý chính sách. Xem những gì các agent của bạn đã làm khi bạn vắng mặt. +Bảng điều khiển failproofai là một ứng dụng web cục bộ để giám sát các phiên làm việc của agent AI và quản lý chính sách. Xem những gì các agent của bạn đã làm trong khi bạn vắng mặt. --- @@ -17,7 +16,7 @@ failproofai Mở tại `http://localhost:8020`. -Bảng điều khiển đọc trực tiếp từ hệ thống tệp - các thư mục dự án Claude Code và các tệp cấu hình failproofai. Không có gì được ghi vào dịch vụ từ xa. +Bảng điều khiển đọc trực tiếp từ hệ thống tệp - các thư mục dự án Claude Code của bạn và các tệp cấu hình failproofai. Không có gì được ghi vào dịch vụ từ xa. --- @@ -25,12 +24,12 @@ Bảng điều khiển đọc trực tiếp từ hệ thống tệp - các thư ### Dự án -Liệt kê tất cả các dự án Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Gemini CLI _(beta)_ và Hermes được tìm thấy trên máy của bạn. Các dự án Claude được phát hiện từ `~/.claude/projects/` (hoặc đường dẫn được đặt bởi `CLAUDE_PROJECTS_PATH`); các dự án Codex được phát hiện bằng cách quét mỗi bản ghi tạm dưới `~/.codex/sessions///
/*.jsonl` và nhóm theo `cwd` được ghi trong bản ghi đầu tiên của mỗi phiên; các dự án Copilot CLI được phát hiện bằng cách quét từng `~/.copilot/session-state//workspace.yaml` (có thể cấu hình qua `COPILOT_HOME`) và nhóm theo trường `cwd` của nó; các dự án Cursor Agent được phát hiện bằng cách quét siêu dữ liệu cho mỗi phiên dưới `~/.cursor/agent-sessions//` (có thể cấu hình qua `CURSOR_HOME`, với `conversations/` và `sessions/` được thử như giải pháp thay thế) cho một vô hướng `cwd` trong `meta.json` / `session.json` / `workspace.yaml`; các dự án OpenCode được phát hiện bằng cách truy vấn cơ sở dữ liệu SQLite của nó tại `~/.local/share/opencode/opencode.db` qua `opencode db --format json` (chúng tôi đọc các bảng `session` và `project` và nhóm theo `project_id`); các dự án Pi được phát hiện bằng cách quét bản ghi tạm JSONL cho mỗi phiên dưới `~/.pi/agent/sessions//_.jsonl` (có thể cấu hình qua `PI_SESSIONS_DIR`) và lấy `cwd` từ bản ghi đầu tiên của mỗi phiên; các dự án Gemini CLI được phát hiện bằng cách quét `~/.gemini/tmp//chats/session--.jsonl` (có thể cấu hình qua `GEMINI_SESSIONS_DIR`) và khôi phục cwd chính tắc từ dấu `.project_root` phía bên cạnh; các phiên cổng Hermes được đọc trực tiếp từ kho lưu trữ SQLite của nó tại `~/.hermes/state.db` (có thể cấu hình qua `HERMES_DB_PATH`) và được nhóm thành các dự án `hermes-` theo `source` (Slack/Telegram/cli/cron — các phiên cổng không có cwd). Một dự án đã được sử dụng bởi nhiều CLI được hiển thị dưới dạng một hàng duy nhất với tất cả các huy hiệu phù hợp. Sử dụng menu thả xuống **CLI** phía trên bảng để lọc theo một agent CLI cụ thể; URL lưu lựa chọn của bạn dưới dạng `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`. +Liệt kê tất cả các dự án Claude Code, OpenAI Codex, GitHub Copilot CLI _(beta)_, Cursor Agent _(beta)_, OpenCode _(beta)_, Pi _(beta)_, Hermes, OpenClaw, Factory Droid, Devin, Antigravity và Goose được tìm thấy trên máy của bạn. Các dự án Claude được khám phá từ `~/.claude/projects/` (hoặc đường dẫn được đặt bởi `CLAUDE_PROJECTS_PATH`); các dự án Codex được khám phá bằng cách quét mọi phiên ghi âm dưới `~/.codex/sessions///
/*.jsonl` và nhóm theo `cwd` được ghi lại trong bản ghi đầu tiên của mỗi phiên; các dự án Copilot CLI được khám phá bằng cách quét từng `~/.copilot/session-state//workspace.yaml` (có thể cấu hình qua `COPILOT_HOME`) và nhóm theo trường `cwd` của nó; các dự án Cursor Agent được khám phá bằng cách quét siêu dữ liệu cho mỗi phiên dưới `~/.cursor/agent-sessions//` (có thể cấu hình qua `CURSOR_HOME`, với `conversations/` và `sessions/` được thử làm dự phòng) để tìm một vô hướng `cwd` trong `meta.json` / `session.json` / `workspace.yaml`; các dự án OpenCode được khám phá bằng cách truy vấn DB SQLite của nó tại `~/.local/share/opencode/opencode.db` qua `opencode db --format json` (chúng tôi đọc các bảng `session` và `project` và nhóm theo `project_id`); các dự án Pi được khám phá bằng cách quét các phiên ghi âm JSONL dưới `~/.pi/agent/sessions//_.jsonl` (có thể cấu hình qua `PI_SESSIONS_DIR`) và lấy `cwd` từ bản ghi đầu tiên của mỗi phiên; các phiên gateway Hermes được đọc trực tiếp từ kho SQLite của nó tại `~/.hermes/state.db` (có thể cấu hình qua `HERMES_DB_PATH`) và nhóm thành các dự án `hermes-` theo `source` (Slack/Telegram/cli/cron — các phiên gateway không có cwd); các phiên gateway OpenClaw được đọc từ `~/.openclaw/agents//sessions/*.jsonl` và nhóm thành các dự án `openclaw-` (cũng không có cwd); các dự án Factory Droid được khám phá từ các phiên ghi âm JSONL tại `~/.factory/sessions//*.jsonl` và nhóm theo cwd; các dự án Devin từ DB SQLite của nó tại `~/.local/share/devin/cli/sessions.db` (nhóm theo `working_directory` của mỗi phiên); các dự án Antigravity từ các phiên ghi âm JSONL tại `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` và nhóm theo cwd; và các dự án Goose từ DB SQLite của nó tại `~/.local/share/goose/sessions/sessions.db` (nhóm theo `working_dir` của mỗi phiên). Một dự án đã được sử dụng bởi nhiều CLI hiển thị dưới dạng một hàng với tất cả các huy hiệu phù hợp. Sử dụng menu thả xuống **CLI** phía trên bảng để lọc theo một CLI agent cụ thể; URL giữ lựa chọn của bạn dưới dạng `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`. Mỗi dự án hiển thị: - Tên dự án (được lấy từ đường dẫn thư mục) -- Một huy hiệu CLI — `Claude Code` (cam), `OpenAI Codex` (tím), `GitHub Copilot` (xanh), `Cursor Agent` (lục bảo), `OpenCode` (hổ phách), `Pi` (hồng), `Gemini CLI` (xanh da trời) và/hoặc `Hermes` (chàm) -- Ngày của hoạt động phiên gần đây nhất +- Một huy hiệu CLI — `Claude Code` (cam), `OpenAI Codex` (tím), `GitHub Copilot` (xanh), `Cursor Agent` (xanh mộc), `OpenCode` (hổ phách), `Pi` (hồng) và/hoặc `Hermes` (chàm) +- Ngày hoạt động phiên gần nhất Nhấp vào một dự án để xem các phiên của nó. @@ -39,36 +38,36 @@ Nhấp vào một dự án để xem các phiên của nó. Liệt kê tất cả các phiên trong một dự án. Mỗi phiên hiển thị: - ID phiên - Dấu thời gian bắt đầu và kết thúc -- Số lượng cuộc gọi công cụ -- Số lượng hoạt động hook (chính sách được kích hoạt) +- Số lượng lệnh gọi công cụ +- Số lượng hoạt động hook (chính sách đã kích hoạt) -Sử dụng bộ lọc phạm vi ngày và tìm kiếm ID phiên để thu hẹp danh sách. Các phiên được phân trang. +Sử dụng bộ lọc khoảng ngày và tìm kiếm ID phiên để thu hẹp danh sách. Các phiên được phân trang. Nhấp vào một phiên để mở trình xem phiên. ### Trình xem phiên -Trình xem phiên trả lời câu hỏi quan trọng cho các agent tự động: agent đã làm gì, và nó có duy trì được theo dõi không? Một huy hiệu CLI bên cạnh tiêu đề cho biết phiên là bản ghi Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Gemini CLI hay Hermes. Nó hiển thị một dòng thời gian của mọi thứ đã xảy ra trong một phiên: +Trình xem phiên trả lời câu hỏi chính cho các agent tự trị: agent đã làm gì, và liệu nó có ở đúng đường hay không? Một huy hiệu CLI bên cạnh tiêu đề cho biết phiên có phải là bản ghi Claude Code, OpenAI Codex, GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, Hermes, OpenClaw, Factory Droid, Devin, Antigravity hay Goose. Nó hiển thị một dòng thời gian của mọi sự kiện đã xảy ra trong một phiên: -- **Tin nhắn** - Các phản hồi văn bản và lời nhắc của người dùng từ Claude -- **Cuộc gọi công cụ** - Mọi công cụ mà Claude gọi, cùng với đầu vào và đầu ra -- **Hoạt động chính sách** - Đối với mỗi lệnh gọi công cụ, các chính sách nào được kích hoạt và quyết định nào họ trả về +- **Tin nhắn** - Các phản hồi văn bản của Claude và các lời nhắc của người dùng +- **Lệnh gọi công cụ** - Mọi công cụ mà Claude đã gọi, kèm theo đầu vào và đầu ra của nó +- **Hoạt động chính sách** - Đối với mỗi lệnh gọi công cụ, những chính sách nào đã kích hoạt và quyết định nào mà chúng trả về -Thanh thống kê ở phía trên cùng hiển thị thời lượng phiên, tổng số lệnh gọi công cụ và tóm tắt các quyết định hook (số lượng allow / deny / instruct). +Thanh thống kê ở trên cùng hiển thị thời lượng phiên, tổng số lệnh gọi công cụ và tóm tắt các quyết định hook (số lượng allow / deny / instruct). -Nhấp vào nút **Download Logs** để xuất phiên. Đối với các phiên Claude Code, Codex, Copilot, Cursor, Pi và Gemini, bạn sẽ nhận được bản ghi JSONL trên đĩa nguyên gốc byte-for-byte; đối với OpenCode (các phiên của nó nằm trong SQLite, không phải trên đĩa), bạn sẽ nhận được một tài liệu JSON phản ánh các bảng `session` / `messages` / `parts` cơ bản. +Nhấp vào nút **Download Logs** để xuất phiên. Đối với các phiên Claude Code, Codex, Copilot, Cursor và Pi, bạn nhận được bản ghi âm JSONL trên đĩa gốc theo byte; đối với OpenCode (các phiên của nó nằm trong SQLite, không phải trên đĩa), bạn nhận được một tài liệu JSON phản chiếu các bảng `session` / `messages` / `parts` cơ bản. ### Kiểm toán -Một báo cáo được chạy bằng tính cách của cách agent của bạn thực sự hoạt động trên các phiên trong quá khứ. Chạy cùng một quá trình quét như CLI `failproofai audit` nhưng hiển thị nó dưới dạng một tấm poster có thể chia sẻ trên một màn hình duy nhất + bốn phần dưới ngữ cảnh: +Một báo cáo có tính cách về cách agent của bạn thực sự đã hành xử trong các phiên quá khứ. Chạy quét giống như CLI `failproofai audit` nhưng hiển thị nó dưới dạng một áp phích có thể chia sẻ trên toàn màn hình + bốn phần dưới nấu: -1. **Poster** — lấp đầy khung nhìn đầu tiên. Vùng chụp PNG độc lập với biểu tượng failproof_ai + nhãn kiểm toán · chỉ số kiến trúc (`№ NN of 08`) + ngày kiểm toán · điểm số (0–100) + xếp hạng phần trăm (`top 15%`) · tên kiến trúc (một trong `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + dải 3 từ khóa · `// only N% of agents are this archetype` dòng hiếm · ô sigil pixel 8×8 · chân trang `audit yours → failproof.ai`. Ba nút chia sẻ nằm ngay bên ngoài ô chụp: `post your archetype` (ý định X), `share on linkedin`, `download poster`. Chụp chạy qua `html-to-image` vì vậy PNG khớp với bản kết xuất trên màn hình pixel-for-pixel (đường viền đứt nét, mặt nạ logo SVG, gradient, số liệu phông chữ — tất cả đều được bảo toàn). -2. **Điểm mạnh** — dòng danh sách yên tĩnh ✓ các hành vi agent của bạn đã làm đúng, bắt nguồn từ dữ liệu kiểm toán trực tiếp (tỷ lệ gọi công cụ sạch, không có đẩy trực tiếp vào chính, không rò rỉ thông tin xác thực, không có cơn bão thử lại) — mỗi cái chỉ được hiển thị khi chính sách liên quan có bản ghi sạch trên cửa sổ kiểm toán. -3. **Những điều lạ lùng** — bảng những gì bị bỏ qua, được xếp hạng theo mức độ nghiêm trọng: `when · what slipped + the policy that would've caught it · severity pill · seen`, nơi sự tái diễn đọc `new` (một lần), `N× seen` (2–9 lần), hoặc `recurring` (10+). -4. **Cách cải thiện** — dòng danh sách yên tĩnh, một cho mỗi chính sách được quy định: tên chính sách bằng màu trắng, mô tả một dòng, lệnh cài đặt + nút sao chép ở phía bên phải. Tiêu đề phần đọc `enable all N → projected · ` (điểm bạn sẽ đạt được với mọi sửa chữa được áp dụng), và nó `[install all]` nút sao chép lệnh `failproofai policy add a b c …` kết hợp cho mỗi chính sách được quy định. -5. **Quay lại tốt hơn** — hai thẻ cạnh nhau. Bên trái: đặt nhắc nhở (`3d` / `7d` / `14d` / `30d` bộ chọn tần suất; được giữ qua `/api/auth/reminder` sau khi xác thực). Bên phải: mở khóa các đặc quyền failproof — `invite a friend` mở một modal nhận một danh sách các email bạn bè được phân tách bằng dấu phẩy/khoảng trắng/dòng mới (tối đa 10 lần gửi), POSTs chúng đến `/api/audit/invite`, được chuyển tiếp đến `/v0/invite` `POST` của api-server. Api-server gửi một email cho mỗi người nhận từ `invite@failproof.ai` với người gửi Cc và `Reply-To` được đặt, vì vậy người nhận thấy ai đã mời họ và người gửi nhận được bản sao trong hộp thư đến. Người dùng ẩn danh được định tuyến qua `AuthDialog` trước tiên để email của người gửi được biết trước khi lời mời được gửi. Quyền lợi / thực hiện đặc quyền là một bước tiếp theo. +1. **Áp phích** — lấp đầy khung nhìn đầu tiên. Vùng chụp PNG tự chứa với biểu tượng failproof_ai + nhãn kiểm toán · chỉ số nguyên mẫu (`№ NN của 08`) + ngày kiểm toán · điểm số (0–100) + dấu xếp hạng phần trăm (`top 15%`) · tên nguyên mẫu (một trong `the optimist`, `the cowboy`, `the explorer`, `the goldfish`, `the paranoid architect`, `the precision builder`, `the hammer`, `the ghost`) + dải 3 từ khóa · dòng `// chỉ N% agent là nguyên mẫu này` · ô sigil 8×8 pixel · chân trang `audit yours → failproof.ai`. Ba nút chia sẻ nằm ngay bên ngoài hộp chụp: `post your archetype` (ý định X), `share on linkedin`, `download poster`. Chụp chạy qua `html-to-image` vì vậy PNG khớp với kết xuất trên màn hình từng pixel (đường viền dashed, mặt nạ logo SVG, gradient, số liệu phông chữ — tất cả được bảo tồn). +2. **Điểm mạnh** — danh sách hàng ✓ yên tĩnh về những hành vi mà agent của bạn đã làm đúng, xuất phát từ dữ liệu kiểm toán trực tiếp (tỷ lệ lệnh gọi công cụ sạch, không đẩy trực tiếp tới main, không rò rỉ thông tin xác thực, không bão retry) — mỗi hàng chỉ xuất hiện khi chính sách liên quan có kỷ lục sạch trên cửa sổ kiểm toán. +3. **Những điều lạ lùng** — bảng của những gì lọt qua, được xếp hạng theo mức độ nghiêm trọng: `when · what slipped + the policy that would've caught it · severity pill · seen`, nơi sự tái diễn hiển thị `new` (một lần), `N× seen` (2–9 lần) hoặc `recurring` (10+). +4. **Cách cải thiện** — danh sách hàng yên tĩnh, một cho mỗi chính sách được quy định: tên chính sách màu trắng, mô tả một dòng, lệnh cài đặt + nút sao chép ở bên phải. Tiêu đề phần hiển thị `enable all N → projected · ` (điểm bạn sẽ đạt được với mọi bản sửa áp dụng), và nút `[install all]` của nó sao chép lệnh `failproofai policy add a b c …` kết hợp cho mọi chính sách được quy định. +5. **Quay lại tốt hơn** — hai thẻ cạnh nhau. Bên trái: đặt lời nhắc (`3d` / `7d` / `14d` / `30d` bộ chọn nhịp độ; vẫn tồn tại qua `/api/auth/reminder` sau khi xác thực). Bên phải: mở khóa các quyền lợi failproof — `invite a friend` mở một modal lấy danh sách email bạn bè được phân tách bằng dấu phẩy/khoảng cách/dòng mới (tối đa 10 mỗi lần gửi), POSTs chúng tới `/api/audit/invite`, chuyển tiếp tới `POST /v0/invite` của máy chủ api. Máy chủ api gửi một email cho mỗi người nhận từ `invite@failproof.ai` với người gửi Cc và `Reply-To` được đặt, vì vậy người nhận thấy ai mời họ và người gửi nhận được một bản sao trong hộp thư đến của họ. Người dùng ẩn danh được định tuyến thông qua `AuthDialog` trước để email của người gửi được biết trước khi lời mời được gửi đi. Thực hiện đặc quyền / quyền lợi là một phần tiếp theo. -Được điều khiển bởi thời gian chạy `failproofai audit` — xem [Audit CLI](/vi/cli/audit) cho công cụ quét cơ bản, các cờ được hỗ trợ và các bất biến bộ nhớ đệm trên mỗi bản ghi. Bảng điều khiển lưu vào bộ nhớ đệm kết quả mới nhất tại `~/.failproofai/audit-dashboard.json` (chế độ `0600`, một khe duy nhất, các lần chạy mới ghi đè) vì vậy các lần ghé thăm lại là tức thì; **cả bộ nhớ đệm trên mỗi bản ghi và toàn bộ kết quả sẽ bị từ chối khi đọc sau khi chúng cũ hơn 7 ngày** vì vậy bảng điều khiển không bao giờ âm thầm phục vụ kết quả một tuần tuổi — quá TTL `/audit` rơi vào trạng thái trống rỗng của nó và nhắc chạy lại. Nhấp `[ re-audit now ]` gần phía dưới của báo cáo POSTs `/api/audit/run` với `noCache: true` — kiểm toán lại bỏ qua bộ nhớ đệm trên mỗi bản ghi và quét lại mỗi bản ghi từ đầu thay vì âm thầm trả về kết quả được lưu vào bộ nhớ đệm — và bảng điều khiển bỏ phiếu `/api/audit/status` ở 1Hz cho đến khi chạy xong; một dải tiến trình hồng dính ghìm vào đầu trang khung nhìn trong lần chạy với bộ hẹn giờ đã trôi qua, và kết quả mới nhất hoán đổi vị trí khi thành công (không tải lại trang đầy đủ; một lần kiểm toán lại không thành công để báo cáo trước đó nguyên vẹn). Khi thất bại, dải chuyển sang màu đỏ với bản sao được khóa theo `RerunError.kind` (`timeout` / `network` / `post_failed`). Trạng thái trống (không có bộ nhớ đệm hoặc hết hạn) và trạng thái không có phiên (bộ nhớ đệm tồn tại nhưng quá trình quét không tìm thấy bản ghi) được hiển thị riêng biệt. +Được điều hành bởi thời gian chạy `failproofai audit` — xem [Audit CLI](/vi/cli/audit) cho công cụ quét cơ bản, các cờ được hỗ trợ và bất biến bộ nhớ đệm trên mỗi bản ghi âm. Bảng điều khiển lưu vào bộ nhớ đệm kết quả mới nhất tại `~/.failproofai/audit-dashboard.json` (chế độ `0600`, khe duy nhất, các lần chạy mới ghi đè) để revisits là tức thì; **cả bộ nhớ đệm trên mỗi bản ghi âm và toàn bộ kết quả đều bị từ chối khi đọc nếu chúng cũ hơn 7 ngày** vì vậy bảng điều khiển không bao giờ yên tĩnh phục vụ kết quả một tuần tuổi — vượt quá TTL `/audit` rơi vào trạng thái trống và nhắc chạy lại. Nhấp vào `[ re-audit now ]` gần dưới cùng của báo cáo POSTs `/api/audit/run` với `noCache: true` — tái kiểm toán bỏ qua bộ nhớ đệm trên mỗi bản ghi âm và quét lại mọi bản ghi âm từ đầu thay vì yên tĩnh trả về kết quả được lưu vào bộ nhớ đệm — và bảng điều khiển thăm dò `/api/audit/status` ở 1Hz cho đến khi lần chạy hoàn tất; một dải tiến trình hồng dính ở trên cùng của khung nhìn trong quá trình chạy với bộ hẹn giờ trôi qua, và kết quả tươi sẽ hoán đổi vị trí khi thành công (không tải lại toàn trang; tái kiểm toán không thành công để nguyên báo cáo trước). Khi thất bại, dải sẽ chuyển sang đỏ với bản sao được khóa trên `RerunError.kind` (`timeout` / `network` / `post_failed`). Trạng thái trống (không có bộ nhớ đệm hoặc hết hạn) và trạng thái không có phiên (bộ nhớ đệm tồn tại nhưng quét không tìm thấy bản ghi âm) được hiển thị riêng biệt. ### Chính sách @@ -76,30 +75,30 @@ Một trang hai tab để quản lý chính sách và xem xét hoạt động. - - Chọn nhiều agent CLI nào mà failproofai bảo vệ từ một bảng điều khiển duy nhất — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi, Gemini CLI và Hermes đều có một hàng với trạng thái cài đặt (`Active` / `Detected` / `Inactive`), đường dẫn cài đặt phạm vi người dùng và một điểm nhấn có thương hiệu. Chọn hoặc bỏ chọn các CLI bạn muốn và nhấp `Apply changes` để cài đặt/gỡ cài đặt chênh lệch trong một bước. Các CLI có tệp nhị phân được phát hiện trên PATH được tính sẵn. - - Bật hoặc tắt các chính sách riêng lẻ bằng một lần nhấp (ghi vào `~/.failproofai/policies-config.json` — được chia sẻ trên mọi CLI được cài đặt) + - Chọn đa lựa chọn agent CLI nào mà failproofai bảo vệ từ một bảng duy nhất — Claude Code, OpenAI Codex, GitHub Copilot, Cursor Agent, OpenCode, Pi và Hermes đều có một hàng với trạng thái cài đặt (`Active` / `Detected` / `Inactive`), đường dẫn cài đặt phạm vi người dùng và một điểm nhấn màu thương hiệu. Chọn hoặc bỏ chọn CLI bạn muốn và nhấp `Apply changes` để cài đặt/gỡ cài đặt sự khác biệt trong một bước. CLI có tệp nhị phân được phát hiện trên PATH được kiểm tra trước. + - Bật hoặc tắt các chính sách riêng lẻ bằng một cách nhấp (ghi vào `~/.failproofai/policies-config.json` — được chia sẻ trên mọi CLI được cài đặt) - Mở rộng một chính sách để cấu hình các tham số của nó (đối với các chính sách hỗ trợ `policyParams`) - - Đặt đường dẫn tệp chính sách tùy chỉnh + - Đặt một đường dẫn tệp chính sách tùy chỉnh - - Lịch sử được phân trang đầy đủ của mọi sự kiện hook đã được kích hoạt trên tất cả các phiên - - Lọc theo quyết định, loại sự kiện, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes), tên chính sách hoặc ID phiên - - Mỗi hàng hiển thị: dấu thời gian, tên chính sách, quyết định, huy hiệu CLI (cam = Claude Code, tím = OpenAI Codex, xanh = GitHub Copilot, lục bảo = Cursor Agent, hổ phách = OpenCode, hồng = Pi, xanh da trời = Gemini CLI, chàm = Hermes), tên công cụ, ID phiên và lý do cho các quyết định deny/instruct - - Nhấp vào ID phiên để mở bản ghi của nó — trình xem tự động phát hiện CLI nào được kích hoạt hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Gemini CLI `~/.gemini/tmp//chats/.jsonl`, Hermes `~/.hermes/state.db`) và hiển thị huy hiệu CLI phù hợp trong tiêu đề + - Lịch sử đầy đủ được phân trang của mọi sự kiện hook đã kích hoạt trên tất cả các phiên + - Lọc theo quyết định, loại sự kiện, CLI (Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose), tên chính sách hoặc ID phiên + - Mỗi hàng hiển thị: dấu thời gian, tên chính sách, quyết định, huy hiệu CLI (cam = Claude Code, tím = OpenAI Codex, xanh = GitHub Copilot, xanh mộc = Cursor Agent, hổ phách = OpenCode, hồng = Pi, chàm = Hermes, lục bảo = OpenClaw, hồng nhạt = Factory Droid, tím = Devin, lục lam = Antigravity, vôi = Goose), tên công cụ, ID phiên và lý do cho quyết định deny/instruct + - Nhấp vào ID phiên để mở phiên ghi âm của nó — trình xem tự động phát hiện CLI nào đã kích hoạt hook (Claude `~/.claude/projects/…`, Codex `~/.codex/sessions/…`, Copilot CLI `~/.copilot/session-state//events.jsonl`, Cursor Agent `~/.cursor/agent-sessions//events.jsonl`, OpenCode `~/.local/share/opencode/opencode.db`, Pi `~/.pi/agent/sessions//.jsonl`, Hermes `~/.hermes/state.db`, OpenClaw `~/.openclaw/agents//sessions/*.jsonl`, Factory Droid `~/.factory/sessions//.jsonl`, Devin `~/.local/share/devin/cli/sessions.db`, Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`, Goose `~/.local/share/goose/sessions/sessions.db`) và hiển thị huy hiệu CLI phù hợp trong tiêu đề --- -## Làm mới tự động +## Tự động làm mới -Bảng điều khiển có công tắc làm mới tự động trong điều hướng hàng trên cùng. Khi được bật, trang hiện tại sẽ được làm mới định kỳ để hiển thị các phiên mới và hoạt động chính sách khi chúng xuất hiện. Cần thiết để giám sát các phiên agent tự động chạy lâu dài. +Bảng điều khiển có bộ chuyển đổi tự động làm mới trong điều hướng trên cùng. Khi được bật, trang hiện tại sẽ làm mới định kỳ để hiển thị các phiên mới và hoạt động chính sách khi chúng xuất hiện. Cần thiết để giám sát các phiên agent tự trị chạy lâu dài. --- ## Vô hiệu hóa các trang -Nếu bạn chỉ cần một số phần của bảng điều khiển, hãy đặt `FAILPROOFAI_DISABLE_PAGES` thành danh sách tên trang được phân tách bằng dấu phẩy: +Nếu bạn chỉ cần một số phần của bảng điều khiển, hãy đặt `FAILPROOFAI_DISABLE_PAGES` thành danh sách các tên trang được phân tách bằng dấu phẩy: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -111,7 +110,7 @@ Các giá trị hợp lệ: `policies`, `projects`, `audit`. ## Cấu hình đường dẫn dự án -Theo mặc định, bảng điều khiển đọc từ thư mục dự án Claude Code tiêu chuẩn. Ghi đè nó cho các thiết lập tùy chỉnh: +Theo mặc định, bảng điều khiển đọc từ thư mục dự án Claude Code tiêu chuẩn. Ghi đè nó để thiết lập tùy chỉnh: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -121,25 +120,25 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ## Truy cập từ máy chủ không phải localhost -Khi chạy bảng điều khiển ở **chế độ dev** (`npm run dev`) và truy cập nó từ tên máy chủ khác `localhost` - ví dụ, một miền tùy chỉnh, một IP từ xa hoặc một URL được đường hầm — bạn có thể thấy một cảnh báo như: +Khi chạy bảng điều khiển ở **chế độ dev** (`npm run dev`) và truy cập nó từ tên máy chủ khác ngoài `localhost` - ví dụ, một miền tùy chỉnh, một IP từ xa hoặc một URL được tunnel - bạn có thể thấy một cảnh báo như: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -Đây là Next.js chặn quyền truy cập gốc chéo vào websocket HMR (làm mới mô-đun nóng) của nó, đây là một tính năng chỉ dev. Để cho phép máy chủ của bạn, hãy sử dụng cờ `--allowed-origins`: +Đây là Next.js chặn quyền truy cập gốc chéo vào websocket HMR (hot module reload) của nó, đây là tính năng chỉ cho dev. Để cho phép máy chủ của bạn, hãy sử dụng cờ `--allowed-origins`: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -Để có nhiều máy chủ hoặc IP, hãy chuyển một danh sách được phân tách bằng dấu phẩy: +Đối với nhiều máy chủ hoặc IP, hãy chuyển một danh sách được phân tách bằng dấu phẩy: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -Bạn cũng có thể đặt biến môi trường `FAILPROOFAI_ALLOWED_DEV_ORIGINS`: +Bạn cũng có thể đặt biến môi trường `FAILPROOFAI_ALLOWED_DEV_ORIGINS` thay thế: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev diff --git a/docs/vi/getting-started.mdx b/docs/vi/getting-started.mdx index f81b0633..86c0d32c 100644 --- a/docs/vi/getting-started.mdx +++ b/docs/vi/getting-started.mdx @@ -1,13 +1,13 @@ --- title: Bắt đầu -description: "Cài đặt failproofai, bật các chính sách, và để agents của bạn chạy một cách đáng tin cậy" +description: "Cài đặt failproofai, bật các chính sách, và để các agent của bạn chạy một cách đáng tin cậy" icon: rocket --- ## Yêu cầu - **Node.js** >= 20.9.0 -- **Bun** >= 1.3.0 (tùy chọn - chỉ cần thiết để build từ nguồn) +- **Bun** >= 1.3.0 (tùy chọn - chỉ cần thiết khi xây dựng từ mã nguồn) --- @@ -31,15 +31,15 @@ bun add -g failproofai - Chính sách là những quy tắc chạy trước và sau mỗi lần agent gọi tool. Chúng bắt các lệnh phá hủy, rò rỉ bí mật, và những chế độ lỗi khác trước khi chúng gây thiệt hại. + Chính sách là các quy tắc chạy trước và sau mỗi lần gọi công cụ của agent. Chúng bắt các lệnh phá hủy, rò rỉ bí mật, và các chế độ lỗi khác trước khi gây hại. ```bash failproofai policies --install ``` - Lệnh này ghi các hook entries vào CLI agents đã cài đặt của bạn (Claude Code's `~/.claude/settings.json`, OpenAI Codex's `~/.codex/hooks.json`, GitHub Copilot CLI's `~/.copilot/hooks/failproofai.json`, Cursor Agent's `~/.cursor/hooks.json`, OpenCode's generated plugin shim at `~/.config/opencode/plugins/failproofai.mjs` plus a registration entry in `~/.config/opencode/opencode.json`'s `plugin` array, Pi's `~/.pi/agent/settings.json`, Gemini CLI's `~/.gemini/settings.json`, or Hermes's `~/.hermes/config.yaml`). Khi có nhiều hơn một cái có mặt, bạn sẽ được nhắc; truyền `--cli claude codex copilot cursor opencode pi gemini hermes` (bất kỳ tập hợp con nào) để bỏ qua lời nhắc. + Điều này ghi các mục hook vào các CLI agent đã cài đặt của bạn (tệp `~/.claude/settings.json` của Claude Code, `~/.codex/hooks.json` của OpenAI Codex, `~/.copilot/hooks/failproofai.json` của GitHub Copilot CLI, `~/.cursor/hooks.json` của Cursor Agent, plugin shim được tạo tại `~/.config/opencode/plugins/failproofai.mjs` của OpenCode cộng với mục đăng ký trong mảng `plugin` của `~/.config/opencode/opencode.json`, `~/.pi/agent/settings.json` của Pi, `~/.hermes/config.yaml` của Hermes, `~/.openclaw/openclaw.json` của OpenClaw, `~/.factory/hooks.json` của Factory Droid, `~/.config/devin/config.json` của Devin CLI, `~/.gemini/config/hooks.json` của Antigravity CLI, hoặc thư mục plugin được khám phá tự động của Goose tại `~/.agents/plugins/failproofai/hooks/hooks.json`). Khi có nhiều hơn một được cài đặt, bạn sẽ được nhắc; truyền `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose` (bất kỳ tập con nào) để bỏ qua lời nhắc. - GitHub Copilot CLI, Cursor Agent, OpenCode, Pi, và Gemini CLI support là **beta** — cài đặt với `--cli copilot`, `--cli cursor`, `--cli opencode`, `--cli pi`, hoặc `--cli gemini`. Hermes (hermes-agent, một gateway Slack/Telegram) cài đặt user-scope với `--cli hermes` và là **cũng** một nguồn audit offline. + GitHub Copilot CLI, Cursor Agent, OpenCode, và hỗ trợ Pi là **beta** — cài đặt bằng `--cli copilot`, `--cli cursor`, `--cli opencode`, hoặc `--cli pi`. Hermes (hermes-agent, một gateway Slack/Telegram) cài đặt ở phạm vi người dùng với `--cli hermes` và cũng là **một** nguồn kiểm toán ngoại tuyến. OpenClaw (gateway openclaw, một trợ lý đa kênh tự lưu trữ) cài đặt ở phạm vi người dùng với `--cli openclaw` — thi hành chạy qua các hook plugin trong quy trình của nó (`before_agent_finalize` là một cổng kết thúc lượt thực sự, vì vậy các bộ sưu tập `require-*-before-stop` thi hành) — và cũng là **một** nguồn kiểm toán ngoại tuyến. Factory Droid (`droid`) cài đặt bằng `--cli factory` (phạm vi người dùng + dự án) và cũng là **một** nguồn kiểm toán ngoại tuyến. Devin CLI (`devin`, Cognition) cài đặt bằng `--cli devin` (phạm vi người dùng + dự án) và cũng là **một** nguồn kiểm toán ngoại tuyến. Antigravity CLI (`agy`) cài đặt bằng `--cli antigravity` (phạm vi người dùng + dự án) và cũng là **một** nguồn kiểm toán ngoại tuyến. Goose (tên mã goose, Block) cài đặt bằng `--cli goose` (phạm vi người dùng + dự án) — trình cài đặt chỉ cần loại thư mục plugin tại `~/.agents/plugins/failproofai/` mà Goose khám phá tự động, và nó cũng là **một** nguồn kiểm toán ngoại tuyến. ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,37 +62,37 @@ bun add -g failproofai failproofai policies ``` - Hiển thị mỗi chính sách, xem nó có được bật hay không, và bất kỳ tham số nào được cấu hình. + Hiển thị mọi chính sách, cho dù nó có được bật hay không, và bất kỳ tham số nào được cấu hình. - + ```bash failproofai ``` - Mở dashboard cục bộ tại `http://localhost:8020` nơi bạn có thể duyệt các phiên, kiểm tra các tool calls, và quản lý chính sách. + Mở bảng điều khiển cục bộ tại `http://localhost:8020` nơi bạn có thể duyệt các phiên, kiểm tra các lệnh gọi công cụ, và quản lý các chính sách. - Khởi động Claude Code như bình thường. Nếu agent thử một điều gì đó rủi ro, failproofai sẽ chặn nó tự động. Để nó chạy không cần giám sát và xem xét những gì đã xảy ra trong dashboard. + Khởi động Claude Code như bình thường. Nếu agent cố gắng làm điều gì đó rủi ro, failproofai sẽ chặn nó tự động. Để nó chạy mà không được chú ý và xem lại những gì đã xảy ra trong bảng điều khiển. --- -## Cách các chính sách hoạt động +## Chính sách hoạt động như thế nào -Mỗi khi một agent chạy một tool, Claude Code gọi failproofai như một subprocess: +Mỗi khi một agent chạy một công cụ, Claude Code gọi failproofai như một quy trình con: ```text -Claude Code → failproofai --hook PreToolUse → reads stdin JSON - evaluates policies - writes decision to stdout +Claude Code → failproofai --hook PreToolUse → đọc JSON từ stdin + đánh giá các chính sách + ghi quyết định vào stdout ``` Mỗi chính sách trả về một trong ba quyết định: -- **allow** - agent tiếp tục bình thường +- **allow** - agent tiến hành bình thường - **deny** - hành động bị chặn, agent được thông báo lý do -- **instruct** - ngữ cảnh bổ sung được thêm vào prompt của agent +- **instruct** - ngữ cảnh bổ sung được thêm vào lời nhắc của agent Các chính sách chạy trong quy trình cục bộ của bạn. Không có gì được gửi đến dịch vụ từ xa. @@ -98,7 +102,7 @@ Các chính sách chạy trong quy trình cục bộ của bạn. Không có gì ## Thiết lập chính sách nhóm với chính sách dựa trên quy ước -Cách nhanh nhất để thiết lập tiêu chuẩn chất lượng trên toàn nhóm của bạn là quy ước `.failproofai/policies/`. Thả các tệp chính sách vào thư mục này và chúng sẽ được tải tự động — không có flag, không có thay đổi config, không có lệnh cài đặt. +Cách nhanh nhất để thiết lập các tiêu chuẩn chất lượng trên toàn bộ nhóm của bạn là quy ước `.failproofai/policies/`. Thả các tệp chính sách vào thư mục này và chúng sẽ được tải tự động — không có cờ, không có thay đổi cấu hình, không có lệnh cài đặt. @@ -107,13 +111,13 @@ Cách nhanh nhất để thiết lập tiêu chuẩn chất lượng trên toàn ``` - Sao chép các ví dụ khởi động hoặc viết chính sách của riêng bạn: + Sao chép các ví dụ khởi động hoặc viết của riêng bạn: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - Hoặc tạo một cái mới: + Hoặc tạo một tệp mới: ```js // .failproofai/policies/team-policies.mjs @@ -125,39 +129,39 @@ Cách nhanh nhất để thiết lập tiêu chuẩn chất lượng trên toàn fn: async (ctx) => { if (ctx.toolName !== "Bash") return allow(); if (/git\s+commit/.test(ctx.toolInput?.command ?? "")) { - return instruct("Run tests before committing."); + return instruct("Chạy các bài kiểm tra trước khi cam kết."); } return allow(); }, }); ``` - + ```bash git add .failproofai/policies/ - git commit -m "Add team quality policies" + git commit -m "Thêm chính sách chất lượng nhóm" ``` - Mỗi thành viên nhóm có failproofai được cài đặt sẽ nhận các chính sách này tự động. Không cần thiết lập cho từng nhà phát triển. + Mỗi thành viên nhóm có failproofai được cài đặt sẽ tự động áp dụng các chính sách này. Không cần thiết lập cho từng nhà phát triển. -Commit `.failproofai/policies/` vào repo của bạn để toàn bộ nhóm chia sẻ các tiêu chuẩn giống nhau. Khi nhóm của bạn phát hiện ra các chế độ lỗi mới, hãy thêm chính sách và push — mọi người sẽ nhận được cập nhật trên lần `git pull` tiếp theo của họ. Theo thời gian, những chính sách này trở thành một tiêu chuẩn chất lượng sống động, liên tục cải thiện. +Cam kết `.failproofai/policies/` vào kho lưu trữ của bạn để toàn bộ nhóm chia sẻ các tiêu chuẩn tương tự. Khi nhóm của bạn phát hiện các chế độ lỗi mới, thêm các chính sách và đẩy — mọi người nhận được bản cập nhật trên `git pull` tiếp theo của họ. Theo thời gian, các chính sách này trở thành một tiêu chuẩn chất lượng sống động tiếp tục cải thiện. --- ## Lưu trữ dữ liệu -Tất cả cấu hình và log vẫn ở trên máy tính của bạn: +Tất cả cấu hình và nhật ký nằm trên máy của bạn: -| Đường dẫn | Lưu trữ những gì | +| Đường dẫn | Nội dung lưu trữ | |------|----------------| | `~/.failproofai/policies-config.json` | Cấu hình chính sách toàn cầu | | `~/.failproofai/hook-activity.jsonl` | Lịch sử thực thi hook | -| `~/.failproofai/hook.log` | Log gỡ lỗi cho lỗi hook tùy chỉnh | -| `.failproofai/policies-config.json` | Cấu hình trên mỗi dự án (được commit) | +| `~/.failproofai/hook.log` | Nhật ký gỡ lỗi cho lỗi hook tùy chỉnh | +| `.failproofai/policies-config.json` | Cấu hình cho từng dự án (được cam kết) | | `.failproofai/policies-config.local.json` | Ghi đè cá nhân (gitignored) | --- @@ -168,7 +172,7 @@ Tất cả cấu hình và log vẫn ở trên máy tính của bạn: failproofai policies --uninstall ``` -Xóa hook entries từ `~/.claude/settings.json`. Các tệp config trong `~/.failproofai/` được giữ lại. +Loại bỏ các mục hook từ `~/.claude/settings.json`. Các tệp cấu hình trong `~/.failproofai/` được giữ lại. --- @@ -176,20 +180,20 @@ Xóa hook entries từ `~/.claude/settings.json`. Các tệp config trong `~/.fa - - Phạm vi và định dạng tệp config + + Phạm vi và định dạng tệp cấu hình - - Tất cả 26 chính sách với tham số + + Tất cả 26 chính sách với các tham số - - Viết các chính sách riêng của bạn trong JavaScript + + Viết các chính sách của riêng bạn trong JavaScript - - Giám sát các phiên và xem xét hoạt động chính sách + + Theo dõi các phiên và xem lại hoạt động chính sách \ No newline at end of file diff --git a/docs/vi/introduction.mdx b/docs/vi/introduction.mdx index daaf6270..0d26a423 100644 --- a/docs/vi/introduction.mdx +++ b/docs/vi/introduction.mdx @@ -1,15 +1,15 @@ --- title: "Failproof AI" -description: "FailproofAI cung cấp 39 chính sách xử lý lỗi tích hợp sẵn giúp phát hiện vòng lặp, rò rỉ bí mật, lệnh gọi công cụ tàn phá, và nhiều hơn nữa chỉ với một lần cài đặt." +description: "FailproofAI cung cấp 39 chính sách xử lý sự cố tích hợp sẵn giúp bắt các vòng lặp, rò rỉ bí mật, các lệnh công cụ có tính chất phá hoại và nhiều hơn nữa chỉ trong một lần cài đặt." --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -Hooks và chính sách cho **xử lý lỗi AI**, **phục hồi lỗi**, và **độ tin cậy LLM**. Giữ cho các AI agents của bạn luôn đáng tin cậy và hoạt động tự trị trên **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Gemini CLI**, **Hermes**, và **Agents SDK**. +Hooks và chính sách cho **xử lý sự cố AI**, **phục hồi lỗi**, và **độ tin cậy của LLM**. Giữ cho các agent AI của bạn đáng tin cậy và chạy tự động trên **Claude Code**, **OpenAI Codex**, **GitHub Copilot**, **Cursor Agent**, **OpenCode**, **Pi**, **Hermes**, **OpenClaw**, **Factory Droid**, **Devin CLI**, **Antigravity CLI**, và **Agents SDK**. -Các AI agents thất bại theo những cách có thể dự đoán được. Chúng chạy các lệnh tàn phá, rò rỉ bí mật, lạc khỏi nhiệm vụ, mắc kẹt trong các vòng lặp, hoặc push trực tiếp lên main. Nếu không được giám sát, những lỗi nhỏ sẽ dẫn đến sự cố toàn hệ thống, rò rỉ thông tin xác thực, và mất công việc. +Các agent AI thất bại theo những cách dự đoán được. Chúng chạy các lệnh có tính chất phá hoại, rò rỉ bí mật, lệch khỏi nhiệm vụ, mắc kẹt trong vòng lặp, hoặc đẩy trực tiếp lên nhánh chính. Nếu không được giám sát, những sự cố nhỏ sẽ dẫn đến sự cố lớn, rò rỉ thông tin xác thực, và mất công việc. -FailproofAI giải quyết vấn đề này bằng **policies** (chính sách). Những quy tắc này kết nối vào mọi lệnh gọi công cụ của agent để **phát hiện lỗi**, **giảm nhẹ chúng** (chặn, hướng dẫn, làm sạch), và **cảnh báo cho bạn** khi có điều gì cần chú ý. Một bảng điều khiển cục bộ cho phép bạn xem lại mọi lệnh gọi công cụ, lỗi agent, và hành động phục hồi sau này. +FailproofAI giải quyết điều này bằng **chính sách**. Các quy tắc này kết nối vào mọi lệnh công cụ của agent để **phát hiện sự cố**, **giảm thiểu chúng** (chặn, hướng dẫn, vệ sinh), và **cảnh báo bạn** khi có điều gì đó cần chú ý. Bảng điều khiển cục bộ cho phép bạn xem lại mọi lệnh công cụ, sự cố agent, và hành động phục hồi sau đó. Không có dữ liệu nào rời khỏi máy của bạn. @@ -18,19 +18,19 @@ Không có dữ liệu nào rời khỏi máy của bạn. - Chặn các lệnh tàn phá, ngăn chặn rò rỉ bí mật, giữ agents trong ranh giới dự án, và nhiều hơn nữa. Tất cả đã sẵn sàng. + Chặn các lệnh có tính chất phá hoại, ngăn rò rỉ bí mật, giữ các agent trong ranh giới dự án, và nhiều hơn nữa. Tất cả đều sẵn có. - Viết các quy tắc của riêng bạn bằng JavaScript với API allow / deny / instruct đơn giản. + Viết các quy tắc của riêng bạn trong JavaScript bằng API allow / deny / instruct đơn giản. - - Xem những gì các agents của bạn đã làm trong khi bạn vắng mặt. Duyệt qua các phiên, kiểm tra các lệnh gọi công cụ, xem xét nơi các chính sách được kích hoạt. + + Xem agent của bạn đã làm gì khi bạn vắng mặt. Duyệt các phiên, kiểm tra các lệnh công cụ, xem lại nơi các chính sách được kích hoạt. - Điều chỉnh bất kỳ chính sách nào mà không cần code. Đặt danh sách cho phép, nhánh được bảo vệ, hoặc ngưỡng cho từng dự án hoặc toàn cục. + Điều chỉnh bất kỳ chính sách nào mà không cần mã. Đặt danh sách cho phép, nhánh được bảo vệ, hoặc ngưỡng cho từng dự án hoặc toàn cầu. @@ -50,8 +50,8 @@ bun add -g failproofai ```bash -failproofai policies --install # bật chính sách (hoặc bỏ qua — `failproofai` sẽ đề xuất thiết lập chúng khi chạy lần đầu tiên) -failproofai # khởi động bảng điều khiển +failproofai policies --install # enable policies (or skip — `failproofai` will offer to set them up on first run) +failproofai # launch the dashboard ``` -Xem hướng dẫn [Bắt đầu](/vi/getting-started) để tìm hiểu chi tiết đầy đủ. \ No newline at end of file +Xem hướng dẫn [Bắt đầu](/vi/getting-started) để có hướng dẫn đầy đủ. \ No newline at end of file diff --git a/docs/zh/built-in-policies.mdx b/docs/zh/built-in-policies.mdx index 8e2bd6da..08b0fc05 100644 --- a/docs/zh/built-in-policies.mdx +++ b/docs/zh/built-in-policies.mdx @@ -1,10 +1,10 @@ --- title: 内置策略 -description: "39 个内置策略,用于捕获常见的 Agent 故障模式" +description: "涵盖常见 Agent 失败模式的全部 39 条内置策略" icon: shield --- -failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。每个策略针对特定的 Hook 事件类型和工具名称触发。其中 19 个策略支持参数配置,让您无需编写代码即可调整其行为。5 个工作流策略会在 Claude 停止前强制执行提交 → 推送 → PR → CI 的流水线。 +failproofai 内置了 39 条策略,可捕获常见的 Agent 失败模式。每条策略针对特定的 hook 事件类型和工具名称触发。其中 19 条策略支持参数配置,无需编写代码即可调整行为。另有 5 条工作流策略,在 Claude 停止之前强制执行 commit → push → PR → CI 流水线。 --- @@ -13,11 +13,11 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 策略按类别分组: | 类别 | 策略 | Hook 类型 | -|----------|----------|-----------| +|------|------|-----------| | [危险命令](#dangerous-commands) | block-sudo, block-rm-rf, block-curl-pipe-sh, block-failproofai-commands | PreToolUse | | [基础设施命令](#infra-commands) | block-kubectl, block-terraform, block-aws-cli, block-gcloud, block-az-cli, block-helm, block-gh-pipeline | PreToolUse | -| [密钥(清洗器)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | -| [环境](#environment) | block-env-files, protect-env-vars | PreToolUse | +| [密钥(脱敏器)](#secrets-sanitizers) | sanitize-jwt, sanitize-api-keys, sanitize-connection-strings, sanitize-private-key-content, sanitize-bearer-tokens | PostToolUse | +| [环境变量](#environment) | block-env-files, protect-env-vars | PreToolUse | | [文件访问](#file-access) | block-read-outside-cwd, block-secrets-write | PreToolUse | | [Git](#git) | block-push-master, block-work-on-main, block-force-push, warn-git-amend, warn-git-stash-drop, warn-all-files-staged | PreToolUse | | [数据库](#database) | warn-destructive-sql, warn-schema-alteration | PreToolUse | @@ -27,13 +27,13 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 - **`block-`** — 阻止 Agent 继续执行。 - **`warn-`** — 为 Agent 提供额外上下文,使其能够自我纠正。 -- **`sanitize-`** — 在 Agent 看到工具输出之前清除其中的敏感数据。 +- **`sanitize-`** — 在 Agent 看到工具输出之前,清除其中的敏感数据。 ### 命名空间 -每个策略都位于 `/` 槽中。内置策略属于 **`failproofai/`** 命名空间,例如 `failproofai/sanitize-jwt`。命名空间可防止您同时加载具有相似短名称的自定义或第三方策略时发生冲突。 +每条策略都位于 `/` 插槽中。内置策略属于 **`failproofai/`** 命名空间,例如 `failproofai/sanitize-jwt`。当你同时加载名称相似的自定义或第三方策略时,命名空间可以防止冲突。 -在配置文件中,您可以使用短名称或完整限定名称来引用内置策略,两种形式解析到同一个策略: +在配置中,你可以使用短名称或完整限定名来引用内置策略,两种形式解析的是同一条策略: ```json { @@ -44,33 +44,33 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 } ``` -如果名称中不含 `/`,failproofai 会将其视为属于默认命名空间 `failproofai`。已包含 `/` 的名称(如 `myorg/foo`、`custom/my-hook`)则保持原样。 -- **`require-`** — 阻止 Stop 事件,直到满足条件为止。 +如果名称中不包含 `/`,failproofai 会将其视为属于默认命名空间 `failproofai`。已包含 `/` 的名称(例如 `myorg/foo`、`custom/my-hook`)则原样保留。 +- **`require-`** — 阻止 Stop 事件,直到满足指定条件。 --- -每个策略在 `policyParams` 中都支持可选的 `hint` 字段。该提示会附加到 Claude 收到的 deny 或 instruct 消息中,提供可操作的指导,无需修改策略代码。适用于内置策略、自定义策略和约定策略。详见[配置 → hint](/zh/configuration#hint-cross-cutting)。 +每条策略在 `policyParams` 中都支持可选的 `hint` 字段。该提示会附加到 Claude 看到的 deny 或 instruct 消息中,提供可操作的指导,无需修改策略代码。适用于内置策略、自定义策略和约定策略。详见[配置 → hint](/zh/configuration#hint-cross-cutting)。 --- -## 危险命令 +## 危险命令 {#dangerous-commands} -防止 Agent 运行难以撤销或可能损害宿主系统的操作。 +防止 Agent 执行难以撤销或可能损坏宿主系统的操作。 ### `block-sudo` **事件:** PreToolUse (Bash) **默认行为:** 拒绝任何包含 `sudo` 的命令。 -阻止包含 `sudo` 关键字的调用。模式匹配基于已解析的命令 token,而非原始字符串,以防止通过 Shell 运算符注入绕过。 +拦截包含 `sudo` 关键字的调用。模式匹配作用于解析后的命令 token,而非原始字符串,以防止通过 shell 运算符注入绕过检测。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的命令前缀。每个条目与已解析的 argv token 进行匹配。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的命令前缀。每条记录与解析后的 argv token 进行匹配。 | **示例:** @@ -84,10 +84,10 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 } ``` -使用此配置,`sudo systemctl status nginx` 将被允许,但 `sudo rm /etc/hosts` 将被拒绝。 +使用此配置,`sudo systemctl status nginx` 将被允许,但 `sudo rm /etc/hosts` 会被拒绝。 -模式匹配基于已解析的 token,而非原始命令字符串。这可防止通过附加 Shell 运算符绕过(例如 `sudo systemctl status x; rm -rf /` 不会匹配 `sudo systemctl status *`)。 +模式匹配作用于解析后的 token,而非原始命令字符串。这可以防止通过附加 shell 运算符绕过检测(例如,`sudo systemctl status x; rm -rf /` 不会匹配 `sudo systemctl status *`)。 --- @@ -99,8 +99,8 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| | `allowPaths` | `string[]` | `[]` | 允许递归删除的路径(如 `/tmp`)。 | **示例:** @@ -129,17 +129,17 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `block-failproofai-commands` **事件:** PreToolUse (Bash) -**默认行为:** 拒绝会卸载或禁用 failproofai 自身的命令(如 `npm uninstall failproofai`、`failproofai policies --uninstall`)。 +**默认行为:** 拒绝会卸载或禁用 failproofai 自身的命令(例如 `npm uninstall failproofai`、`failproofai policies --uninstall`)。 无参数。 --- -## 基础设施命令 +## 基础设施命令 {#infra-commands} -防止编码 Agent 运行基础设施 CLI 或触发 CI/CD 流水线。此类别中的所有策略均为**按需启用**(`defaultEnabled: false`)——合法需要调用 `kubectl`、`terraform` 等工具的 Agent 不会受到干扰,除非您主动启用相应策略。启用后,除非命令匹配 `allowPatterns` 中的条目,否则所有匹配 CLI 的调用均会被拒绝。 +防止编程 Agent 运行基础设施 CLI 或触发 CI/CD 流水线。此类别中的所有策略均为**按需启用**(`defaultEnabled: false`)——合法需要调用 `kubectl`、`terraform` 等工具的 Agent 不会受到影响,除非你手动启用该策略。启用后,除非命令匹配 `allowPatterns` 中的某条记录,否则所有匹配 CLI 的调用都会被拒绝。 -模式语法与 [`block-sudo`](#block-sudo) 相同:token 与已解析的 argv 进行匹配,`*` 为单个 token 的通配符,任何包含独立 Shell 运算符(`&&`、`||`、`|`、`;`)或内嵌 Shell 元字符的 token 都会在允许列表匹配之前被拒绝,以防注入绕过。 +模式语法与 [`block-sudo`](#block-sudo) 相同:token 与解析后的 argv 进行匹配,`*` 是单个 token 的通配符,任何包含独立 shell 运算符(`&&`、`||`、`|`、`;`)或含有内嵌 shell 元字符的 token 的命令,在进行白名单匹配之前就会被拒绝,以防止注入绕过。 ### `block-kubectl` @@ -148,9 +148,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 kubectl 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 kubectl 命令前缀。 | **示例:** @@ -164,7 +164,7 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 } ``` -使用此配置,`kubectl get pods` 将被允许,但 `kubectl apply -f deploy.yaml` 将被拒绝。 +使用此配置,`kubectl get pods` 将被允许,但 `kubectl apply -f deploy.yaml` 会被拒绝。 --- @@ -175,9 +175,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 terraform/tofu 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 terraform/tofu 命令前缀。 | **示例:** @@ -200,9 +200,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 aws CLI 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 aws CLI 命令前缀。 | **示例:** @@ -225,9 +225,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 gcloud 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 gcloud 命令前缀。 | **示例:** @@ -250,9 +250,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 az CLI 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 az CLI 命令前缀。 | **示例:** @@ -275,9 +275,9 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的 helm 命令前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 允许执行的 helm 命令前缀。 | **示例:** @@ -305,13 +305,13 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 - `gh cache delete` - `gh secret set`、`gh secret delete` -只读的 `gh` 子命令(如 `gh pr view`、`gh pr list`、`gh run list`、`gh release view` 和 `gh api repos/.../...`)**不**在此策略的拦截范围内——这些命令在工作流检查中经常用到(包括 failproofai 自身的 `require-ci-green-before-stop`)。 +只读的 `gh` 子命令(如 `gh pr view`、`gh pr list`、`gh run list`、`gh release view` 和 `gh api repos/.../...`)**不在**本策略的拦截范围内——这些命令在工作流检查中(包括 failproofai 自身的 `require-ci-green-before-stop`)是常规所需。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPatterns` | `string[]` | `[]` | 允许的特定脚本调用,即使它们本应被拒绝。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPatterns` | `string[]` | `[]` | 即使本应被拒绝,也允许执行的特定脚本化调用。 | **示例:** @@ -327,14 +327,14 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 --- -## 密钥(清洗器) +## 密钥(脱敏器) {#secrets-sanitizers} -防止 Agent 将凭据泄露到其上下文或输出中。清洗器策略在 **PostToolUse** 事件上触发。当 Claude 运行 Bash 命令、读取文件或调用任何工具时,这些策略会在输出返回给 Claude 之前对其进行检查。若检测到密钥模式,策略将返回拒绝决定,阻止输出被传回。 +防止 Agent 将凭据泄露到其上下文或输出中。脱敏策略在 **PostToolUse** 事件上触发。当 Claude 执行 Bash 命令、读取文件或调用任何工具时,这些策略会在输出返回给 Claude 之前对其进行检查。如果检测到密钥模式,策略将返回 deny 决策,阻止输出被传回。 ### `sanitize-jwt` **事件:** PostToolUse(所有工具) -**默认行为:** 清除 JWT token(由 `.` 分隔的三段 base64url 字符串)。 +**默认行为:** 脱敏 JWT token(由 `.` 分隔的三段 base64url 字符串)。 无参数。 @@ -343,13 +343,13 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `sanitize-api-keys` **事件:** PostToolUse(所有工具) -**默认行为:** 清除常见的 API 密钥格式:Anthropic(`sk-ant-`)、OpenAI(`sk-`)、GitHub PAT(`ghp_`)、AWS 访问密钥(`AKIA`)、Stripe 密钥(`sk_live_`、`sk_test_`)以及 Google API 密钥(`AIza`)。 +**默认行为:** 脱敏常见 API 密钥格式:Anthropic(`sk-ant-`)、OpenAI(`sk-`)、GitHub PAT(`ghp_`)、AWS 访问密钥(`AKIA`)、Stripe 密钥(`sk_live_`、`sk_test_`)以及 Google API 密钥(`AIza`)。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | 额外的正则表达式模式,用于识别自定义密钥。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `additionalPatterns` | `{ regex: string; label: string }[]` | `[]` | 需要作为密钥处理的额外正则表达式模式。 | **示例:** @@ -371,7 +371,7 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `sanitize-connection-strings` **事件:** PostToolUse(所有工具) -**默认行为:** 清除包含内嵌凭据的数据库连接字符串(如 `postgresql://user:password@host/db`)。 +**默认行为:** 脱敏包含内嵌凭据的数据库连接字符串(例如 `postgresql://user:password@host/db`)。 无参数。 @@ -380,7 +380,7 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `sanitize-private-key-content` **事件:** PostToolUse(所有工具) -**默认行为:** 清除 PEM 块(`-----BEGIN PRIVATE KEY-----`、`-----BEGIN RSA PRIVATE KEY-----` 等)。 +**默认行为:** 脱敏 PEM 块(`-----BEGIN PRIVATE KEY-----`、`-----BEGIN RSA PRIVATE KEY-----` 等)。 无参数。 @@ -389,22 +389,22 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `sanitize-bearer-tokens` **事件:** PostToolUse(所有工具) -**默认行为:** 清除 `Authorization: Bearer ` 请求头中 token 长度为 20 个或更多字符的内容。 +**默认行为:** 脱敏 `Authorization: Bearer ` 头中长度不少于 20 个字符的 token。 无参数。 --- -## 环境 +## 环境变量 {#environment} -保护敏感的环境配置,防止 Agent 读取或暴露它们。 +防止 Agent 读取或暴露敏感的环境配置。 ### `block-env-files` -**事件:** PreToolUse(Bash、Read) +**事件:** PreToolUse (Bash, Read) **默认行为:** 拒绝通过 `cat .env`、以 `.env` 为文件路径的 `Read` 工具调用等方式读取 `.env` 文件。 -不会阻止读取 `.envrc` 或其他与环境相关的文件——仅阻止名称恰好为 `.env` 的文件。 +不拦截 `.envrc` 或其他与环境相关的文件——仅拦截名称精确为 `.env` 的文件。 无参数。 @@ -412,27 +412,27 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `protect-env-vars` -**事件:** PreToolUse(Bash) +**事件:** PreToolUse (Bash) **默认行为:** 拒绝打印环境变量的命令:`printenv`、`env`、`echo $VAR`。 无参数。 --- -## 文件访问 +## 文件访问 {#file-access} -将 Agent 的工作范围限制在项目目录内,并使其远离敏感文件。 +将 Agent 的操作限制在项目边界内,并远离敏感文件。 ### `block-read-outside-cwd` -**事件:** PreToolUse(Read、Bash) -**默认行为:** 拒绝读取项目根目录以外的文件。边界为 `CLAUDE_PROJECT_DIR`(由 Claude Code 在每个会话开始时设置一次),当该变量未设置时回退到会话的当前工作目录。使用项目根目录而非实时的 `cwd`,意味着即使 Claude `cd` 进入子目录后,边界依然保持稳定。 +**事件:** PreToolUse (Read, Bash) +**默认行为:** 拒绝读取项目根目录之外的文件。边界由 `CLAUDE_PROJECT_DIR`(由 Claude Code 在每次会话开始时设置一次)确定,若该变量未设置,则回退到会话当前工作目录。使用项目根目录而非实时的 `cwd`,意味着即使 Claude `cd` 进入子目录,边界也保持稳定。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `allowPaths` | `string[]` | `[]` | 即使在项目根目录之外也允许访问的绝对路径前缀。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowPaths` | `string[]` | `[]` | 即使在项目根目录之外,也允许访问的绝对路径前缀。 | **示例:** @@ -450,14 +450,14 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `block-secrets-write` -**事件:** PreToolUse(Write、Edit) -**默认行为:** 拒绝写入通常用于私钥和证书的文件:`id_rsa`、`id_ed25519`、`*.key`、`*.pem`、`*.p12`、`*.pfx`。 +**事件:** PreToolUse (Write, Edit) +**默认行为:** 拒绝写入常用于私钥和证书的文件:`id_rsa`、`id_ed25519`、`*.key`、`*.pem`、`*.p12`、`*.pfx`。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `additionalPatterns` | `string[]` | `[]` | 额外的文件名模式(glob 风格)以阻止写入。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `additionalPatterns` | `string[]` | `[]` | 需要拦截的额外文件名模式(glob 风格)。 | **示例:** @@ -473,20 +473,20 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 --- -## Git +## Git {#git} -防止意外推送、强制推送以及难以撤销的分支错误操作。 +防止意外推送、强制推送以及难以撤销的分支操作失误。 ### `block-push-master` -**事件:** PreToolUse(Bash) +**事件:** PreToolUse (Bash) **默认行为:** 拒绝 `git push origin main` 和 `git push origin master`。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `protectedBranches` | `string[]` | `["main", "master"]` | 不允许直接推送的分支名称。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `protectedBranches` | `string[]` | `["main", "master"]` | 不能直接推送的分支名称。 | **示例:** @@ -501,27 +501,27 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ``` -如需允许推送到所有分支(即在不将此策略从 `enabledPolicies` 中移除的情况下将其实际禁用),可设置 `protectedBranches: []`。 +若要允许推送到所有分支(相当于在不从 `enabledPolicies` 中移除该策略的情况下将其禁用),请设置 `protectedBranches: []`。 --- ### `block-work-on-main` -**事件:** PreToolUse(Bash) -**默认行为:** 当工作树位于 `main` 或 `master` 分支时,拒绝 `git commit`、`git merge`、`git rebase` 和 `git cherry-pick`。分支创建和切换(`git checkout`、`git checkout -b`、`git switch`、`git switch -c`)不受影响。 +**事件:** PreToolUse (Bash) +**默认行为:** 当工作树位于 `main` 或 `master` 分支时,拒绝 `git commit`、`git merge`、`git rebase` 和 `git cherry-pick`。创建和切换分支(`git checkout`、`git checkout -b`、`git switch`、`git switch -c`)不受影响。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| | `protectedBranches` | `string[]` | `["main", "master"]` | 禁止执行 commit/merge/rebase/cherry-pick 的分支名称。 | --- ### `block-force-push` -**事件:** PreToolUse(Bash) +**事件:** PreToolUse (Bash) **默认行为:** 拒绝 `git push --force` 和 `git push -f`。 无策略专属参数。可使用通用的 [`hint`](/zh/configuration#hint-cross-cutting) 来建议替代方案: @@ -540,8 +540,8 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `warn-git-amend` -**事件:** PreToolUse(Bash) -**默认行为:** 当运行 `git commit --amend` 时,指示 Claude 谨慎操作。不会阻止该命令。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行 `git commit --amend` 时指示 Claude 谨慎操作。不阻止命令执行。 无参数。 @@ -549,8 +549,8 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `warn-git-stash-drop` -**事件:** PreToolUse(Bash) -**默认行为:** 在运行 `git stash drop` 之前,指示 Claude 进行确认。不会阻止该命令。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行 `git stash drop` 之前指示 Claude 确认操作。不阻止命令执行。 无参数。 @@ -558,21 +558,21 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `warn-all-files-staged` -**事件:** PreToolUse(Bash) -**默认行为:** 当运行 `git add -A` 或 `git add .` 时,指示 Claude 审查所暂存的内容。不会阻止该命令。 +**事件:** PreToolUse (Bash) +**默认行为:** 当 Claude 运行 `git add -A` 或 `git add .` 时,指示其检查正在暂存的内容。不阻止命令执行。 无参数。 --- -## 数据库 +## 数据库 {#database} -在破坏性 SQL 操作执行之前将其拦截。 +在破坏性 SQL 操作执行之前捕获它们。 ### `warn-destructive-sql` -**事件:** PreToolUse(Bash) -**默认行为:** 在运行包含 `DROP TABLE`、`DROP DATABASE` 或不带 `WHERE` 子句的 `DELETE` 的 SQL 之前,指示 Claude 进行确认。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行包含 `DROP TABLE`、`DROP DATABASE` 或不带 `WHERE` 子句的 `DELETE` 语句之前,指示 Claude 确认操作。 无参数。 @@ -580,27 +580,27 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ### `warn-schema-alteration` -**事件:** PreToolUse(Bash) -**默认行为:** 在运行 `ALTER TABLE` 语句之前,指示 Claude 进行确认。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行 `ALTER TABLE` 语句之前,指示 Claude 确认操作。 无参数。 --- -## 警告 +## 警告 {#warnings} -在潜在有风险但非破坏性的操作前,为 Agent 提供额外上下文。 +在执行可能有风险但非破坏性的操作之前,为 Agent 提供额外上下文。 ### `warn-large-file-write` -**事件:** PreToolUse(Write) -**默认行为:** 在写入大于 1024 KB 的文件之前,指示 Claude 进行确认。 +**事件:** PreToolUse (Write) +**默认行为:** 在写入大于 1024 KB 的文件之前,指示 Claude 确认操作。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `thresholdKb` | `number` | `1024` | 触发警告的文件大小阈值(单位:KB)。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `thresholdKb` | `number` | `1024` | 触发警告的文件大小阈值(KB)。 | **示例:** @@ -615,15 +615,15 @@ failproofai 内置了 39 个策略,用于捕获常见的 Agent 故障模式。 ``` -Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较小的内容测试此策略,请将 `thresholdKb` 设置为远低于 1024 的值。 +hook 处理器对 stdin 有效载荷强制限制为 1 MB。若要用较小内容测试此策略,请将 `thresholdKb` 设置为远低于 1024 的值。 --- ### `warn-package-publish` -**事件:** PreToolUse(Bash) -**默认行为:** 在运行 `npm publish` 之前,指示 Claude 进行确认。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行 `npm publish` 之前,指示 Claude 确认操作。 无参数。 @@ -631,8 +631,8 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `warn-background-process` -**事件:** PreToolUse(Bash) -**默认行为:** 当通过 `nohup`、`&`、`disown` 或 `screen` 启动后台进程时,指示 Claude 谨慎操作。 +**事件:** PreToolUse (Bash) +**默认行为:** 在通过 `nohup`、`&`、`disown` 或 `screen` 启动后台进程时,指示 Claude 谨慎操作。 无参数。 @@ -640,32 +640,32 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `warn-global-package-install` -**事件:** PreToolUse(Bash) -**默认行为:** 在运行 `npm install -g`、`yarn global add` 或在没有虚拟环境的情况下运行 `pip install` 之前,指示 Claude 进行确认。 +**事件:** PreToolUse (Bash) +**默认行为:** 在运行 `npm install -g`、`yarn global add` 或未在虚拟环境中运行 `pip install` 之前,指示 Claude 确认操作。 无参数。 --- -## 包管理器 +## 包管理器 {#package-managers} 强制规定 Agent 允许使用的包管理器。 ### `prefer-package-manager` -**事件:** PreToolUse(Bash) -**默认行为:** 禁用。启用后,阻止任何不在 `allowed` 列表中的包管理器命令,并告知 Claude 使用允许的包管理器重写该命令。 +**事件:** PreToolUse (Bash) +**默认行为:** 禁用状态。启用后,将拦截不在 `allowed` 列表中的任何包管理器命令,并告知 Claude 使用允许的包管理器重写该命令。 可检测:pip、pip3、python -m pip、npm、npx、yarn、pnpm、pnpx、bun、bunx、uv、poetry、pipenv、conda、cargo。 -| 参数 | 类型 | 默认值 | 描述 | -|-----------|------|---------|-------------| -| `allowed` | string[] | `[]` | 允许的包管理器名称。任何检测到的且不在此列表中的包管理器都将被阻止。为空时,策略不执行任何操作。 | -| `blocked` | string[] | `[]` | 除内置列表外额外需要阻止的包管理器名称(如 `['pdm', 'pipx']`)。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `allowed` | string[] | `[]` | 允许使用的包管理器名称。检测到的不在此列表中的包管理器将被拦截。列表为空时,策略不执行任何操作。 | +| `blocked` | string[] | `[]` | 除内置列表外,额外需要拦截的包管理器名称(例如 `['pdm', 'pipx']`)。 | -内置阻止列表包含:pip、pip3、npm、npx、yarn、pnpm、pnpx、bun、bunx、uv、poetry、pipenv、conda、cargo。使用 `blocked` 可追加不在此列表中的包管理器。 +内置拦截列表涵盖:pip、pip3、npm、npx、yarn、pnpm、pnpx、bun、bunx、uv、poetry、pipenv、conda、cargo。使用 `blocked` 可追加不在此列表中的包管理器。 -**示例配置:** +**配置示例:** ```json { @@ -679,59 +679,58 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 } ``` -使用此配置,`pip install flask` 和 `pdm install flask` 都会被拒绝,并提示 Claude 改用 `uv` 或 `bun`。而 `uv pip install flask` 则会被允许,因为 `uv` 在允许列表中且优先被检测。 +使用此配置,`pip install flask` 和 `pdm install flask` 都会被拒绝,并附带消息告知 Claude 改用 `uv` 或 `bun`。`uv pip install flask` 这样的命令则会被允许,因为 `uv` 在允许列表中,且优先进行检查。 --- -## AI 行为 +## AI 行为 {#ai-behavior} 检测 Agent 卡住或行为异常的情况。 ### `warn-repeated-tool-calls` **事件:** PreToolUse(所有工具) -**默认行为:** 当同一工具以相同参数被调用 3 次及以上时,指示 Claude 重新考虑——这是 Agent 陷入循环的常见信号。 +**默认行为:** 当同一工具以相同参数被调用 3 次或以上时,指示 Claude 重新考虑——这是 Agent 陷入循环的常见信号。 无参数。 --- -## 工作流 +## 工作流 {#workflow} -强制执行规范的会话结束工作流。这些策略在 **Stop** 事件上触发,阻止 Agent 停止,直到每个条件都得到满足。它们遵循自然的依赖链:提交 → 推送 → PR → CI。如果某个策略拒绝,链中后续策略将被跳过(拒绝会短路)。 +强制执行规范的会话结束工作流。这些策略在 **Stop** 事件上触发,阻止 Agent 停止,直到每个条件都满足。它们遵循自然的依赖链:commit → push → PR → CI。如果某条策略拒绝,链中后续策略将被跳过(deny 会短路执行)。 -所有工作流策略均为**失败开放**模式:如果所需工具不可用(如未安装 `gh`、无 git 远端),策略将允许通过并提供信息性消息,说明检查被跳过的原因。 +所有工作流策略均**失败放行(fail-open)**:如果所需工具不可用(例如未安装 `gh`、无 git 远程仓库),策略将放行并附带信息性消息,说明为何跳过检查。 ### 各 CLI 的 Stop 语义 -由于七种受支持的 CLI 各自暴露不同的"Agent 完成"Hook 合约,Stop 强制执行在各 CLI 上的表现略有不同。**结果**是相同的——Agent 在工作流门控未通过时无法停止——但**机制**有所差异。下表作出了总结;只有 Pi 存在一个值得您在启用 `require-*-before-stop` 策略前了解的用户可见差异。 +Stop 的执行方式在六种受支持的 CLI 中略有不同,因为每种 CLI 对外暴露的"Agent 完成"hook 契约各异。**最终效果**相同——Agent 不能在工作流关卡未通过的情况下停止——但**执行机制**有所差异。下表做了总结;其中只有 Pi 有一个值得在启用 `require-*-before-stop` 策略之前了解的用户可见特殊行为。 -| CLI | 门控触发时机 | 您看到的效果 | -|---|---|---| -| Claude Code | 同一 Agent 循环,立即触发 | Claude 继续工作——修复问题后再次尝试结束。对您无可见中断。 | +| CLI | 关卡触发时机 | 你看到的效果 | +|-----|------------|------------| +| Claude Code | 同一 Agent 循环,立即触发 | Claude 继续工作——修复问题后再次尝试结束。你不会感知到任何中断。 | | Codex | 同一 Agent 循环,立即触发 | 与 Claude 相同。 | -| GitHub Copilot CLI | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Copilot 的 `{decision:"block", reason}` 重试通道——已针对 Copilot CLI 1.0.41 实证验证)。 | +| GitHub Copilot CLI | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Copilot 的 `{decision:"block", reason}` 重试通道——已针对 Copilot CLI 1.0.41 实测验证)。 | | Cursor Agent | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Cursor 的 `{followup_message}` 通道——上限为 `loop_limit`,默认 5 次重试)。 | -| Gemini CLI | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 Gemini 的 `{decision:"block", reason}` 通道,位于 `AfterAgent`)。 | | OpenCode | 同一 Agent 循环,立即触发 | 与 Claude 相同(使用 OpenCode 的 `client.session.prompt(...)` SDK 调用,通过 `hookSpecificOutput.additionalContext` 路由)。 | -| **Pi (pi-coding-agent)** | **下一个用户轮次** | **Pi 会明显停止**——当门控触发时,其 Agent 循环退出,控制权回到提示符。下次您提交提示时门控才会触发:failproofai 会在该轮次的系统提示开头附加一条 `MANDATORY ACTION REQUIRED` 指令,要求 LLM 在执行您请求的操作之前先完成工作流步骤(提交、推送等)。 | +| **Pi (pi-coding-agent)** | **下一个用户轮次** | **Pi 会在关卡触发时明显停止**——其 Agent 循环退出,你回到提示符。关卡将在你下次提交提示时触发:failproofai 会在该轮次的系统提示开头预置一条 `MANDATORY ACTION REQUIRED` 指令,告知 LLM 在处理你的请求之前先完成工作流步骤(commit、push 等)。 | -**Pi 的限制。** Pi 的 `AgentEndEvent`(上游等效于 Claude 的 `Stop` Hook)没有 Result 类型——当它触发时,Pi 的 Agent 循环已经退出。Pi 无法像 Claude / Copilot / Cursor / Gemini / OpenCode 那样被强制重试同一循环。failproofai 将门控转移到 Pi 的 `before_agent_start` 事件(在下一个用户提示后触发),这样工作流检查依然会被执行,只是在下一轮而非当前轮次。 +**Pi 的限制。** Pi 的 `AgentEndEvent`(上游等价于 Claude 的 `Stop` hook)没有 Result 类型——当它触发时,Pi 的 Agent 循环已经退出。Pi 无法像 Claude / Copilot / Cursor / OpenCode 那样被强制重试同一循环。failproofai 将关卡移至 Pi 的 `before_agent_start` 事件(在下一个用户提示后触发),这样工作流检查仍然会执行,只是在下一轮次而非当前轮次。 **实际影响:** -- Pi 停止后,拒绝原因会以 Pi 会话 ID 为键存储在内存中。您在同一 Pi 进程中提交的下一个提示会消费它:LLM 在系统提示顶部看到 `MANDATORY ACTION REQUIRED` 指令,先完成提交(或推送/开 PR/等待 CI),然后才继续您的请求。该拒绝原因是一次性的——消费后门控即清除。 -- 门控的生命周期受 Pi 进程生命周期限制。如果您在两次轮次之间 `Ctrl+C` 或退出 Pi,内存中的条目会随进程一起丢失,门控也就错过了。Claude、Copilot、Cursor、Gemini 和 OpenCode 有相同的限制(杀掉 Agent 则门控错过)——只是 Pi 更为明显,因为 Agent 在门控触发之前就已可见地退出了。 -- 待处理的拒绝在任何原因导致的 `session_shutdown` 时也会被清除(`new` / `resume` / `fork` / `quit`),因此来自之前会话的过期门控不会泄漏到在同一 Pi 进程中启动的新会话中。 +- Pi 停止后,deny 原因会以 Pi 会话 ID 为键保存在内存中。你在同一 Pi 进程中提交的下一个提示会消耗它:LLM 在系统提示顶部看到 `MANDATORY ACTION REQUIRED` 指令,执行 commit(或 push / 创建 PR / 等待 CI),然后再继续处理你的请求。该 deny 原因是一次性的——消耗后关卡即清除。 +- 关卡受 Pi 进程生命周期约束。如果你在两个轮次之间 `Ctrl+C` 退出 Pi 或关闭程序,内存中的记录会随进程一起丢失,关卡也就被跳过了。Claude、Copilot、Cursor 和 OpenCode 有相同的约束(杀掉 Agent 则关卡被跳过)——Pi 只是因为 Agent 在关卡触发前明显退出而使这一点更加显眼。 +- 待处理的 deny 也会在任何原因(`new` / `resume` / `fork` / `quit`)触发 `session_shutdown` 时被清除,因此前一个会话遗留的关卡不会泄漏到同一 Pi 进程中启动的新会话。 -如果您需要类似 Claude 的同循环重试,请在其他六种受支持的 CLI 下运行您的 `Stop` 策略。我们正在跟踪 Pi 上游,等待 `AgentEndEvent` 上未来的 Result 类型以弥补这一差距。 +如果你需要类似 Claude 的同循环重试,请在其他五种受支持的 CLI 下运行 `Stop` 策略。我们正在跟进 Pi 上游,期待 `AgentEndEvent` 未来能够提供 Result 类型,以便弥合这一差距。 ### `require-commit-before-stop` **事件:** Stop -**默认行为:** 当存在未提交的更改(已修改、已暂存或未跟踪的文件)时,拒绝停止。工作目录干净时返回信息性消息。 +**默认行为:** 当存在未提交的更改(已修改、已暂存或未跟踪的文件)时,拒绝停止。当工作目录干净时,返回信息性消息。 无参数。 @@ -740,13 +739,13 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `require-push-before-stop` **事件:** Stop -**默认行为:** 当存在未推送的提交或当前分支没有远端跟踪分支时,拒绝停止。如需创建跟踪分支,建议使用 `git push -u`。若未配置远端,则失败开放。 +**默认行为:** 当存在未推送的提交,或当前分支没有远程跟踪分支时,拒绝停止。如有需要,建议使用 `git push -u` 创建跟踪分支。若未配置远程仓库,则失败放行。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| -| `remote` | `string` | `"origin"` | 要推送到的远端名称。 | +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `remote` | `string` | `"origin"` | 推送的目标远程仓库名称。 | **示例:** @@ -765,13 +764,13 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `require-pr-before-stop` **事件:** Stop -**默认行为:** 当当前分支不存在 Pull Request,或现有 PR 已关闭且未合并时,拒绝停止。指示 Claude 使用 `gh pr create` 创建 PR。当 PR 被**合并**后,策略允许通过(工作已交付),并提示切换离开该分支(`git checkout main && git pull`)。 +**默认行为:** 当当前分支不存在 Pull Request,或现有 PR 已关闭且未合并时,拒绝停止。指示 Claude 使用 `gh pr create` 创建 PR。当 PR **已合并**时,策略放行(工作已发布),并提示切换离开该分支(`git checkout main && git pull`)。 无参数。 -此策略需要安装并完成身份验证的 [GitHub CLI](https://cli.github.com/)(`gh`)。 -运行 `gh auth login`,使用具有 `repo` 作用域的个人访问令牌以获得对 Pull Request 的读取权限。如果未安装 `gh` 或未完成身份验证,策略将失败开放并向 Claude 报告原因。 +本策略需要安装并认证 [GitHub CLI](https://cli.github.com/)(`gh`)。 +请使用具有 `repo` 范围(用于读取 Pull Request)的个人访问 token 运行 `gh auth login`。若未安装 `gh` 或未认证,策略将失败放行,并向 Claude 报告原因。 --- @@ -779,21 +778,21 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `require-no-conflicts-before-stop` **事件:** Stop -**默认行为:** 当当前分支无法与基础分支干净合并时,拒绝停止。策略首先确认 GitHub 上该分支存在 `OPEN` 状态的 PR——没有 PR 则无合并目标可强制执行,整个策略短路为允许。确认存在 `OPEN` PR 后,将运行两个独立探测: +**默认行为:** 当当前分支无法干净地合并到基础分支时,拒绝停止。策略首先确认 GitHub 上该分支存在 `OPEN` 状态的 PR——若不存在,则没有可强制执行的合并目标,整个策略短路放行。确认存在 `OPEN` PR 后,将运行两项独立探测: -1. **本地检测** — `git merge-tree --write-tree --name-only origin/ HEAD`。发生冲突时,拒绝消息会列出冲突文件,使 Claude 知道确切需要解决的内容。 -2. **GitHub 检测** — 复用在预检中已获取的 `gh pr view --json mergeable,state` 结果。可捕获本地过期的 `origin/` 可能遗漏的冲突(例如自上次 fetch 以来,有人在 `main` 上合并了冲突 PR)。`CONFLICTING` 结果导致拒绝。`UNKNOWN` 结果也会拒绝,并指示 Claude 等待约 10 秒后重新检查,再尝试停止——这可防止 GitHub 重新计算期间出现误放。 +1. **本地检测** — `git merge-tree --write-tree --name-only origin/ HEAD`。发生冲突时,deny 消息会列出冲突文件,以便 Claude 准确知道需要解决什么。 +2. **GitHub 检测** — 复用预检阶段已获取的 `gh pr view --json mergeable,state` 结果。可捕获本地陈旧的 `origin/` 会遗漏的冲突(例如,自上次 fetch 以来有人向 `main` 合并了冲突 PR)。`CONFLICTING` 结果将触发 deny。`UNKNOWN` 结果同样触发 deny,并指示 Claude 等待约 10 秒后重新检查再尝试停止——这可防止在 GitHub 重新计算期间出现假阴性。 -以下情况策略将完全跳过(允许通过):未安装 `gh`、该分支无 PR、PR 状态非 `OPEN`(如 `MERGED`、`CLOSED`),或 `gh pr view` 返回无法解析的输出。当本地缺少 `origin/` 或 HEAD 相对于基础没有新提交时也失败开放——这些第一层回退在允许之前仍会查询缓存的 PR 可合并性。 +在以下情况下完全跳过(放行):未安装 `gh`、分支无 PR、PR 状态不是 `OPEN`(例如 `MERGED`、`CLOSED`),或 `gh pr view` 返回无法解析的输出。当本地缺少 `origin/`,或没有超前于基础分支的提交时,也会失败放行——这些第一层回退情况仍会在放行前查询缓存的 PR 可合并性。 **参数:** -| 参数 | 类型 | 默认值 | 描述 | -|-------|------|---------|-------------| +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| | `baseBranch` | `string` | `"main"` | 用于检查冲突的基础分支。 | -此策略需要 GitHub CLI(`gh`)。策略使用 `gh pr view` 在运行任何冲突探测之前确认存在 `OPEN` PR——没有 `gh` 则策略短路为允许。运行 `gh auth login`,使用具有 `repo` 作用域的个人访问令牌以获得对 Pull Request 的读取权限。 +本策略需要 GitHub CLI(`gh`)。策略使用 `gh pr view` 确认存在 `OPEN` PR 后,才会运行冲突探测——若未安装 `gh`,策略将短路放行。请使用具有 `repo` 范围(用于读取 Pull Request)的个人访问 token 运行 `gh auth login`。 --- @@ -801,22 +800,22 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 ### `require-ci-green-before-stop` **事件:** Stop -**默认行为:** 当 CI 检查在当前分支上失败或仍在运行时,拒绝停止。同时检查 GitHub Actions 工作流运行和第三方 Bot 检查(如 CodeRabbit、SonarCloud、Codecov)。将 `skipped`、`cancelled` 和 `neutral` 结论视为非失败(后者涵盖例如 Socket Security 对外部贡献者 PR 的警报,其中应用程序有意报告 neutral 而非 success/failure)。所有检查通过时返回信息性消息。 +**默认行为:** 当当前分支的 CI 检查失败或仍在运行时,拒绝停止。同时检查 GitHub Actions 工作流运行和第三方机器人检查(例如 CodeRabbit、SonarCloud、Codecov)。将 `skipped`、`cancelled` 和 `neutral` 结论视为非失败状态(最后一种涵盖例如外部贡献者 PR 上 Socket Security 告警的情况,该应用会故意报告 neutral 而非 success/failure)。所有检查通过时,返回信息性消息。 无参数。 -此策略需要安装并完成身份验证的 [GitHub CLI](https://cli.github.com/)(`gh`)。 -运行 `gh auth login`,使用具有 `repo` 作用域的个人访问令牌以获得对 Actions 工作流运行和 Checks API 的读取权限。如果未安装 `gh` 或未完成身份验证,策略将失败开放并向 Claude 报告原因。 +本策略需要安装并认证 [GitHub CLI](https://cli.github.com/)(`gh`)。 +请使用具有 `repo` 范围(用于读取 Actions 工作流运行和 Checks API)的个人访问 token 运行 `gh auth login`。若未安装 `gh` 或未认证,策略将失败放行,并向 Claude 报告原因。 --- --- -## 禁用单个策略 +## 禁用单条策略 -在配置文件的 `enabledPolicies` 中移除特定策略,或在控制台的策略标签页中将其关闭。 +从配置中的 `enabledPolicies` 移除特定策略,或在控制面板的 Policies 标签页中将其关闭。 ```json { @@ -827,4 +826,4 @@ Hook 处理程序对 stdin 的载荷大小有 1 MB 的限制。若要使用较 } ``` -未列在 `enabledPolicies` 中的策略不会运行,即使 `policyParams` 中存在对应条目。 \ No newline at end of file +未列入 `enabledPolicies` 的策略不会运行,即使 `policyParams` 中存在对应的配置项。 \ No newline at end of file diff --git a/docs/zh/cli/audit.mdx b/docs/zh/cli/audit.mdx index d6d90c87..9f9430da 100644 --- a/docs/zh/cli/audit.mdx +++ b/docs/zh/cli/audit.mdx @@ -1,19 +1,19 @@ --- -title: 审计历史会话(测试版) -description: "统计智能体在历史记录中执行浪费性或高风险操作的频率" +title: 审计过去的会话(测试版) +description: "统计智能体在过去记录中执行浪费性或高风险操作的频率" --- **测试版功能。** 审计功能目前以测试版形式发布,我们正在收集早期反馈。 - 检测器目录和报告格式可能在下一个稳定版本发布前有所变动。 - 如发现任何异常,请提交 issue。 + 在下一个稳定版本发布之前,检测器目录和报告格式可能会发生变化。 + 如有任何异常,请提交 issue。 -审计功能会将您过去的智能体 CLI 记录通过 failproofai 的策略引擎进行回放,并在 **`/audit` 仪表板页面**生成一份可分享的可视化报告——包括您的智能体原型、0 到 100 的评分,以及哪些策略会捕获哪些问题。 +审计功能会将您过去智能体 CLI 的记录重新通过 failproofai 的策略引擎进行回放,并在 **`/audit` 仪表盘页面**生成可分享的可视化报告——包括您智能体的原型、0–100 分的评分,以及哪些策略会拦截哪些行为的详细说明。 ## 运行方式 -有三种入口,最终都会进入同一份 `/audit` 报告。 +有三种入口——最终都会进入同一份 `/audit` 报告。 @@ -33,57 +33,57 @@ failproofai - `npx -y failproofai audit` 会自动获取 failproofai、执行扫描并为您打开仪表板——无需提前安装任何东西。 + `npx -y failproofai audit` 会自动获取 failproofai、执行扫描并为您打开仪表盘——无需预先安装任何内容。 - - `failproofai audit` 在终端中运行扫描,完成后自动打开 + + `failproofai audit` 在终端中执行扫描,完成后自动打开 `localhost:8020/audit`。 - - 运行 `failproofai`,点击导航栏中的 **Audit**(位于 Policies 和 Projects 之间),或直接打开 `/audit`。 + + 运行 `failproofai` 并点击导航栏中的 **Audit**(位于 Policies 和 Projects 之间),或直接访问 `/audit`。 - 运行 `failproofai audit -h`(或 `--help`)查看使用说明。审计**完全离线**运行——无需账号或网络——仪表板会持续运行,直到您按 `Ctrl+C` 停止。 + 运行 `failproofai audit -h`(或 `--help`)查看用法说明。审计**完全离线**运行——无需账号或网络——仪表盘将持续运行,直到您按 `Ctrl+C` 停止。 -仪表板会扫描本机上过去的智能体 CLI 记录(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi、Gemini),并报告智能体执行了哪些 failproofai 旨在阻止的操作——环境变量检查、强制推送、冗余的 `cd ` 前缀、轮询 sleep 循环、重复读取刚编辑的文件等。 +仪表盘会扫描本机上过去的智能体 CLI 记录(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi),并报告智能体执行过多少次 failproofai 旨在阻止的行为——环境变量检查、强制推送、多余的 `cd ` 前缀、sleep 轮询循环、重新读取刚刚编辑过的文件等。 -对于每条记录,每个工具调用事件都会通过 39 条内置策略以及 8 个仅限审计的检测器进行回放——这些检测器可识别运行时策略尚未覆盖的模式。计数按策略/检测器维度在所有会话中汇总。 +对于每条记录,所有工具调用事件都会通过 39 条内置策略**以及** 8 个仅用于审计的检测器进行回放,这些检测器可捕获运行时策略尚未覆盖的模式。统计结果按策略/检测器跨所有会话进行汇总。 ## 报告内容 -`/audit` 页面是一张单屏可分享的**海报**,后跟四个折叠下方的区块: +`/audit` 页面是一个单屏可分享的**海报**,下方包含四个部分: -1. **海报** — 一目了然地展示您的智能体身份:其**原型**(共 8 种——`optimist`、`cowboy`、`explorer`、`goldfish`、`paranoid architect`、`precision builder`、`hammer`、`ghost`)、人物关键词、该原型的稀有程度,以及带有层级标识的 **0 到 100 评分**(从 `S` 到 `bottom tier`)。专为分享而设计——可发布到 X 或 LinkedIn,也可下载为 PNG。 -2. **`// strengths`** — 您的智能体已经表现良好的方面,来自扫描的真实数据(例如干净工具调用率、`0` 次推送到主分支的尝试),仅在相关策略记录完全干净时显示。 -3. **`// quirks`** — 漏掉了什么:按优先级排列的行为表格,列出 failproofai 本可捕获的操作——*最近发生时间*、*泄漏内容*(以及会阻止它的内置规则)、*严重程度*,以及出现频率(`new` / `recurring` / `N× seen`)。 -4. **`// how to improve`** — 建议修复列表:每条策略对应一行可复制粘贴的 `failproofai policy add ` 命令,以及一个**一键安装全部**按钮,可同时启用所有建议,并显示执行后的**预期评分**。 -5. **`// come back better`** — 培养习惯:设置重新审计的邮件**提醒**(`3d` / `7d` / `14d` / `30d`)或立即重新审计,并**邀请好友**进行自己的审计(由 failproof.ai 发送,抄送给您)。提醒和邀请需要登录——请参阅 [`failproofai auth`](/zh/cli/auth)。 +1. **海报** — 一眼掌握您智能体的特征:其**原型**(共 8 种——`optimist`、`cowboy`、`explorer`、`goldfish`、`paranoid architect`、`precision builder`、`hammer`、`ghost`)、人设关键词、该原型的稀有程度,以及带等级区间的 **0–100 分**(从 `S` 到 `bottom tier`)。专为分享设计——可发布到 X 或 LinkedIn,或下载为 PNG。 +2. **`// strengths`** — 您的智能体已经做得好的方面,以扫描得出的真实数据呈现(例如工具调用干净率、`0` 次主分支推送尝试),仅在相关策略记录干净时才会显示。 +3. **`// quirks`** — 哪些行为漏网了:一张按优先级排列的表格,列出 failproofai 本可拦截的行为——*最近发生时间*、*漏网内容*(及对应的内置拦截规则)、*严重程度*,以及出现频率(`new`/`recurring`/`N× seen`)。 +4. **`// how to improve`** — 建议修复列表:每条策略对应一行,附带可复制粘贴的 `failproofai policy add ` 命令,另有**全部安装**按钮,可一次性启用所有建议,并显示执行后的**预期得分**。 +5. **`// come back better`** — 养成习惯:设置重新审计的邮件**提醒**(`3d`/`7d`/`14d`/`30d`)或立即重新审计,并**邀请朋友**进行自己的审计(由 failproof.ai 发送,抄送给您)。提醒和邀请需要登录——详见 [`failproofai auth`](/zh/cli/auth)。 -## 仅限审计的检测器 +## 仅审计检测器 -这些检测器用于识别尚未在实时环境中强制执行的"低效行为"模式。它们仅在审计期间运行,不会阻止实时工具调用。 +这些检测器用于检测目前尚未在实时运行中执行的"低效行为"模式。它们仅在审计期间运行,不会阻断任何实时工具调用。 | 检测器 | 统计内容 | |---|---| -| `redundant-cd-cwd` | 以 `cd && …` 开头的 Bash 命令,尽管命令已在 `cwd` 中运行。 | +| `redundant-cd-cwd` | 以 `cd && …` 开头的 Bash 命令,尽管命令本已在 `cwd` 中运行。 | | `prefer-edit-over-read-cat` | 对单个源文件使用 `cat`/`head`/`tail`/`less`/`more`——应使用 `Read` 工具。 | -| `prefer-edit-over-sed-awk` | 使用 `sed -i` / `awk … > file` 进行原地编辑——应使用 `Edit` 工具。 | -| `prefer-write-over-heredoc` | 使用 Heredoc / 多行 `echo > file` 写入文件——应使用 `Write` 工具。 | +| `prefer-edit-over-sed-awk` | 使用 `sed -i` / `awk … > file` 进行就地编辑——应使用 `Edit` 工具。 | +| `prefer-write-over-heredoc` | 使用 Heredoc / 多行 `echo > file` 写文件——应使用 `Write` 工具。 | | `sleep-polling-loop` | 长时间 `sleep N`(≥ 30 秒)或 `while …; sleep …; done` 轮询循环。 | -| `find-from-root` | `find /`、`find /home`、`find /usr` 等——应将范围限定在 `cwd`。 | +| `find-from-root` | `find /`、`find /home`、`find /usr` 等——应限定在 `cwd` 范围内。 | | `git-commit-no-verify` | `git commit … --no-verify` / `-n`,跳过钩子。 | -| `reread-after-edit` | 在同一会话中对刚刚 `Edit`/`Write` 的文件执行 `Read`。 | +| `reread-after-edit` | 在同一会话中,对刚刚经过 `Edit`/`Write` 的文件执行 `Read`。 | -## 缓存机制 +## 缓存 -- **逐记录缓存**位于 `~/.failproofai/cache/audit/.json`,以 `(mtime, size, engineVersion, detectorVersion)` 为键——当记录或策略/检测器代码发生变化时自动失效。每个条目还存储 `cachedAt` 时间戳作为 **TTL 元数据**(不作为缓存键的一部分);超过 **7 天**的条目在读取时会被拒绝,以防止长期存在的结果与不断演进的检测器意图产生偏差。 -- **整体结果缓存**位于 `~/.failproofai/audit-dashboard.json`(权限 0600)。允许仪表板在导航时即时渲染,无需重新运行。同样超过 **7 天 TTL** 后在读取时被拒绝——`/audit` 随后进入空状态并提示重新运行。点击报告底部的 `[ re-audit now ]` 刷新——重新审计会发送 `noCache: true`,绕过逐记录缓存并重新扫描所有记录,而非返回缓存结果;运行进度通过顶部固定条目流式显示,成功后在原位替换结果(无需重载页面;若重新审计失败,则保留上一份报告)。 +- **单条记录缓存**位于 `~/.failproofai/cache/audit/.json`,以 `(mtime, size, engineVersion, detectorVersion)` 为键——当记录或策略/检测器代码发生变化时自动失效。每个条目还存储了 `cachedAt` 时间戳作为 **TTL 元数据**(不属于缓存键);超过 **7 天**的条目在读取时会被拒绝,以防长期缓存结果与不断演进的检测器意图不符。 +- **整体结果缓存**位于 `~/.failproofai/audit-dashboard.json`(模式 0600)。允许仪表盘在导航时即时渲染,无需重新运行。同样在超过 **7 天 TTL** 后读取时被拒绝——`/audit` 会回退到空状态并提示重新运行。点击报告底部附近的 `[ re-audit now ]` 可刷新——重新审计会发送 `noCache: true`,绕过单条记录缓存并重新扫描所有记录,而非返回缓存结果;运行过程通过顶部固定提示条流式展示进度,成功后就地替换结果(无需刷新页面;若重新审计失败则保留之前的报告)。 ## 注意事项 -- **不做任何修改。** 审计以只读模式回放。`warn-repeated-tool-calls` 会被跳过,因为其每个会话的附属文件否则会被修改。 -- **跳过工作流策略。** `require-*-before-stop` 策略仅在 `Stop` 事件时触发,并对实时 git 状态执行 `execSync`——它们在审计场景中没有有意义的"2025 年会发生什么"解读,因此不出现在审计计数中。 -- **跳过自定义策略。** 用户提供的自定义钩子不会被回放(它们可能在原始会话之后发生了变化)。 \ No newline at end of file +- **不会修改任何内容。** 审计以只读模式回放。`warn-repeated-tool-calls` 会被跳过,否则其每会话附属文件将被修改。 +- **工作流策略跳过。** `require-*-before-stop` 策略仅在 `Stop` 事件时触发,并对当前 git 状态执行 `execSync`——这类策略没有有意义的"2025 年会发生什么"的解读,因此不会出现在审计统计中。 +- **自定义策略跳过。** 用户提供的自定义钩子不会被回放(它们可能在原始会话之后已发生变更)。 \ No newline at end of file diff --git a/docs/zh/configuration.mdx b/docs/zh/configuration.mdx index 21fbaf5f..48737d9a 100644 --- a/docs/zh/configuration.mdx +++ b/docs/zh/configuration.mdx @@ -1,24 +1,24 @@ --- title: 配置 -description: "配置文件格式、三级作用域系统与合并规则" +description: "配置文件格式、三级作用域系统及合并规则" icon: gear --- -failproofai 使用 JSON 配置文件来控制哪些策略处于启用状态、策略的行为方式,以及自定义策略的加载路径。配置设计上便于团队共享——将其提交到仓库,每位开发者都能获得相同的 AI 代理安全防护。 +failproofai 使用 JSON 配置文件来控制哪些策略处于激活状态、策略的行为方式以及自定义策略的加载路径。配置文件设计为易于与团队共享——提交到代码仓库后,所有开发者都能获得相同的 Agent 安全保障。 --- ## 配置作用域 -共有三个配置作用域,按优先级顺序评估: +共有三个配置作用域,按优先级顺序进行评估: | 作用域 | 文件路径 | 用途 | |-------|-----------|---------| -| **project** | `.failproofai/policies-config.json` | 每个仓库的配置,提交到版本控制 | -| **local** | `.failproofai/policies-config.local.json` | 个人的仓库级覆盖配置,已加入 gitignore | +| **project** | `.failproofai/policies-config.json` | 按仓库配置,提交至版本控制 | +| **local** | `.failproofai/policies-config.local.json` | 个人的按仓库覆盖配置,已加入 gitignore | | **global** | `~/.failproofai/policies-config.json` | 适用于所有项目的用户级默认配置 | -当 failproofai 收到 hook 事件时,会加载并合并当前工作目录下所有已存在的三个文件。 +当 failproofai 接收到 hook 事件时,会加载并合并当前工作目录下所有已存在的三个文件。 ### 合并规则 @@ -32,26 +32,26 @@ global: ["block-sudo", "sanitize-api-keys"] resolved: ["block-sudo", "block-rm-rf", "sanitize-api-keys"] ← 去重后的并集 ``` -**`policyParams`** — 对某个策略最先定义其参数的作用域完全胜出,不会对策略参数内的值进行深度合并。 +**`policyParams`** — 对于某个策略的参数,第一个定义该策略参数的作用域完全优先。策略参数内部不进行深度合并。 ```text project: block-sudo → { allowPatterns: ["sudo apt-get update"] } global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo apt-get update"] } ← project 胜出,global 被忽略 +resolved: { allowPatterns: ["sudo apt-get update"] } ← project 优先,global 被忽略 ``` ```text -project: (无 block-sudo 条目) -local: (无 block-sudo 条目) +project: (无 block-sudo 配置) +local: (无 block-sudo 配置) global: block-sudo → { allowPatterns: ["sudo systemctl status"] } -resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global +resolved: { allowPatterns: ["sudo systemctl status"] } ← 向下穿透至 global ``` -**`customPoliciesPath`** — 最先定义该字段的作用域胜出。 +**`customPoliciesPath`** — 第一个定义该字段的作用域优先。 -**`llm`** — 最先定义该字段的作用域胜出。 +**`llm`** — 第一个定义该字段的作用域优先。 --- @@ -102,27 +102,27 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global 类型:`string[]` -需要启用的策略名称列表。名称必须与 `failproofai policies` 显示的策略标识符完全匹配。完整列表请参见[内置策略](/zh/built-in-policies)。 +需要启用的策略名称列表。名称必须与 `failproofai policies` 命令所显示的策略标识符完全匹配。完整列表请参阅[内置策略](/zh/built-in-policies)。 -不在 `enabledPolicies` 中的策略将处于非活跃状态,即便在 `policyParams` 中为其配置了条目也不例外。 +不在 `enabledPolicies` 中的策略均为非激活状态,即使它们在 `policyParams` 中存在配置条目。 ### `policyParams` 类型:`Record>` -各策略的参数覆盖配置。外层键为策略名称,内层键为各策略专属的配置项。每个策略的可用参数请参见[内置策略](/zh/built-in-policies)。 +按策略的参数覆盖配置。外层键为策略名称,内层键为各策略专属配置项。每个策略的可用参数详见[内置策略](/zh/built-in-policies)。 -如果策略有参数但未指定,则使用策略的内置默认值。未配置 `policyParams` 的用户其行为与之前版本完全一致。 +若策略有参数但未指定,则使用该策略的内置默认值。未配置 `policyParams` 的用户与之前版本行为完全一致。 -策略参数块中未知的键在 hook 触发时会被静默忽略,但在运行 `failproofai policies` 时会作为警告标记出来。 +策略参数块中未知的键在 hook 触发时会被静默忽略,但执行 `failproofai policies` 时会以警告形式提示。 -#### `hint`(通用配置项) +#### `hint`(通用参数) 类型:`string`(可选) -当策略返回 `deny` 或 `instruct` 时,附加到原因后面的消息。可用于在不修改策略本身的情况下,向 Claude 提供可操作的指引。 +当策略返回 `deny` 或 `instruct` 时,追加到原因信息后面的提示文本。使用此字段可以在不修改策略本身的情况下,为 Claude 提供可操作的指导建议。 -适用于任何类型的策略——内置策略、自定义策略(`custom/`)、项目约定策略(`.failproofai-project/`)或用户约定策略(`.failproofai-user/`)。 +适用于所有策略类型——内置策略、自定义策略(`custom/`)、项目约定策略(`.failproofai-project/`)以及用户约定策略(`.failproofai-user/`)。 ```json { @@ -141,7 +141,7 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global } ``` -当 block-force-push 拒绝操作时,Claude 会看到:*"Force-pushing is blocked. Try creating a fresh branch instead."* +当 `block-force-push` 拒绝操作时,Claude 会看到:*"Force-pushing is blocked. Try creating a fresh branch instead."* 非字符串值和空字符串会被静默忽略。若未设置 `hint`,行为保持不变(向后兼容)。 @@ -149,32 +149,32 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global 类型:`string`(绝对路径) -包含自定义 hook 策略的 JavaScript 文件路径。该值由 `failproofai policies --install --custom ` 自动设置(路径在存储前会被解析为绝对路径)。 +包含自定义 hook 策略的 JavaScript 文件路径。此字段由 `failproofai policies --install --custom ` 自动设置(路径在存储前会被解析为绝对路径)。 -每次 hook 事件触发时都会重新加载该文件,不进行缓存。有关编写自定义策略的详情,请参见[自定义策略](/zh/custom-policies)。 +每次 hook 事件触发时都会重新加载该文件,不进行缓存。自定义策略的编写详情请参阅[自定义策略](/zh/custom-policies)。 ### 基于约定的策略 -除了显式的 `customPoliciesPath` 外,failproofai 还会自动发现并加载 `.failproofai/policies/` 目录中的策略文件: +除了显式的 `customPoliciesPath` 之外,failproofai 还会自动发现并加载 `.failproofai/policies/` 目录中的策略文件: | 级别 | 目录 | 作用域 | |-------|-----------|-------| | 项目级 | `.failproofai/policies/` | 通过版本控制与团队共享 | -| 用户级 | `~/.failproofai/policies/` | 个人使用,适用于所有项目 | +| 用户级 | `~/.failproofai/policies/` | 个人配置,适用于所有项目 | -**文件匹配:** 仅加载匹配 `*policies.{js,mjs,ts}` 的文件(例如 `security-policies.mjs`、`workflow-policies.js`),目录中的其他文件会被忽略。 +**文件匹配规则:** 仅加载匹配 `*policies.{js,mjs,ts}` 的文件(例如 `security-policies.mjs`、`workflow-policies.js`),目录中的其他文件会被忽略。 -**无需配置:** 约定策略无需在 `policies-config.json` 中添加任何条目,只需将文件放入对应目录,下次 hook 事件触发时即可自动生效。 +**无需配置:** 约定策略无需在 `policies-config.json` 中添加任何条目。只需将文件放入对应目录,下次 hook 事件触发时即可自动识别。 -**联合加载:** 项目和用户约定目录都会被扫描,两个级别中所有匹配的文件都会被加载(与 `customPoliciesPath` 采用首个作用域胜出的方式不同)。 +**合并加载:** 项目级和用户级约定目录都会被扫描,两个级别中所有匹配的文件都会被加载(与使用首个作用域优先规则的 `customPoliciesPath` 不同)。 -更多详情和示例请参见[自定义策略](/zh/custom-policies)。 +更多详情和示例请参阅[自定义策略](/zh/custom-policies)。 ### `llm` 类型:`object`(可选) -供策略进行 AI 调用的 LLM 客户端配置,大多数场景下无需配置。 +用于进行 AI 调用的策略所需的 LLM 客户端配置。大多数场景下无需配置。 ```json { @@ -189,20 +189,24 @@ resolved: { allowPatterns: ["sudo systemctl status"] } ← 回退到 global ## 通过 CLI 管理配置 -`policies --install` 和 `policies --uninstall` 命令会写入代理 CLI 的 hook 设置文件(hook 入口点),而 `policies-config.json` 是由你直接管理的文件,两者相互独立: +`policies --install` 和 `policies --uninstall` 命令负责写入 Agent CLI 的 hook 设置文件(hook 入口点),而 `policies-config.json` 则是由您直接管理的文件。两者相互独立: -- **代理 CLI 设置** — 告知代理在每次工具调用时执行 `failproofai --hook `: +- **Agent CLI 设置** — 指示 Agent 在每次工具调用时执行 `failproofai --hook `: - **Claude Code**:`~/.claude/settings.json`(用户级)、`/.claude/settings.json`(项目级)、`/.claude/settings.local.json`(本地级) - - **OpenAI Codex**:`~/.codex/hooks.json`(用户级)、`/.codex/hooks.json`(项目级)——Codex 没有 `local` 作用域 - - **GitHub Copilot CLI _(beta)_**:`~/.copilot/hooks/failproofai.json`(用户级)、`/.github/hooks/failproofai.json`(项目级)——Copilot 没有 `local` 作用域。Hook 条目使用 Copilot 基于操作系统的 `bash`/`powershell` 命令字段,并带有 `timeoutSec`;文件顶层包含 `version: 1` 标记。Copilot CLI 支持目前为 **beta** 版本,我们正在针对更多实际会话验证 `events.jsonl` 记录模式(公开文档中未作说明)。 - - **Cursor Agent _(beta)_**:`~/.cursor/hooks.json`(用户级)、`/.cursor/hooks.json`(项目级)——Cursor 没有 `local` 作用域。Hook 条目使用 Claude 风格的 `{type, command, timeout}` 格式(无 `bash`/`powershell` 拆分),但按照 Cursor 的 [hooks schema](https://cursor.com/docs/hooks) 以驼峰式事件键(`preToolUse`、`beforeSubmitPrompt` 等)存储在扁平数组中;文件顶层包含 `version: 1` 标记。处理器通过 `CURSOR_EVENT_MAP` 将驼峰式键规范化为帕斯卡式,使现有内置策略能够正常触发。Cursor Agent 支持目前为 **beta** 版本,我们正在针对更多实际安装验证 Cursor 的磁盘上转录格式(公开文档未作说明)。 - - **OpenCode _(beta)_**:`~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(用户级)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(项目级)——OpenCode 没有 `local` 作用域。与其他六种 CLI 不同,OpenCode **没有外部命令 hook 系统**:它通过 `opencode.json` 的 `plugin: []` 数组显式注册来加载进程内 JS/TS 插件(自动发现 `.opencode/plugins/` 目录**不是** opencode v1.14.33 插件的加载方式)。安装时会生成一个小型插件 shim,以子进程方式调用 failproofai 二进制文件,并将二进制文件的 Claude 风格 JSON 响应转换回插件语义:工具事件拒绝时 `throw new Error()`(取消工具调用);instruct 以及 `Stop` / `SubagentStop` 拒绝时调用 `client.session.prompt(...)`(将拒绝原因作为下一条用户消息提交——这是唯一的强制重试通道,因为 `session.idle` 仅用于通知,从中抛出异常无效);allow 时不执行任何操作。该 shim 在转发给二进制文件前会规范化工具名称(小写 → 帕斯卡式,通过 `OPENCODE_TOOL_MAP`)和工具输入参数键(驼峰式 → 下划线式,通过 `OPENCODE_TOOL_INPUT_MAP` 适用于 `Read` / `Write` / `Edit`,例如 `filePath` → `file_path`、`oldString` → `old_string`),从而使 `block-read-outside-cwd`、`block-env-files` 和 `block-secrets-write` 等路径检查内置策略在 OpenCode 工具调用中正常触发。会话存储在 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库中;仪表盘的会话查看器通过 `opencode db --format json` 和 `opencode export ` 读取它们。OpenCode 支持目前为 **beta** 版本,我们正在跨版本和更多实际会话中验证其行为。详见 [OpenCode plugins 文档](https://opencode.ai/docs/plugins/)。 - - **Pi _(beta)_**:`~/.pi/agent/settings.json`(用户级)、`/.pi/settings.json`(项目级)——Pi 没有 `local` 作用域。Pi 在启动时加载 TypeScript 扩展包;设置文件是一个扁平字符串数组 `{"packages": ["./relative/path", …]}`。failproofai 在 packages 数组中写入一个指向其捆绑的 `pi-extension/` 目录的条目。该扩展内部订阅 Pi 的 `tool_call` / `user_bash` / `input` / `session_start` 事件,并调用 `failproofai --hook --cli pi`;处理器通过 `PI_EVENT_MAP` 将下划线小写蛇形命名规范化为帕斯卡式,使现有内置策略正常触发。工具输入参数也通过 `PI_TOOL_INPUT_MAP` 规范化(Pi 的 Read / Write / Edit 使用 `path` 而非 `file_path`;映射顶层键后 `block-env-files` 和 `block-secrets-write` 可正常触发——`block-read-outside-cwd` 本身已有 `path` 的回退逻辑)。Pi 支持目前为 **beta** 版本,有待 Pi 的扩展 API 和会话日志格式稳定。 - - **Gemini CLI _(beta)_**:`~/.gemini/settings.json`(用户级)、`/.gemini/settings.json`(项目级)——Gemini 没有 `local` 作用域(其文档记录了 `/etc/gemini-cli/settings.json` 的 `system` 作用域,failproofai 未对外暴露该作用域)。Hook 条目使用 Claude 的 `{type, command, timeout}` 格式,包裹在 Gemini 的 `{matcher, hooks: [...]}` 匹配器模式中,默认 `matcher: "*"`。事件采用帕斯卡式(`SessionStart`、`BeforeAgent`、`AfterAgent`、`BeforeModel`、`AfterModel`、`BeforeToolSelection`、`BeforeTool`、`AfterTool`、`PreCompress`、`Notification`、`SessionEnd`);处理器通过 `GEMINI_EVENT_MAP` 映射到 Claude 规范名称。工具名称采用蛇形命名(`run_shell_command`、`read_file`、`write_file`、`replace` 等)——处理器通过 `GEMINI_TOOL_MAP` 规范化,使现有内置策略正常触发。策略评估器输出 Gemini 的扁平 `{decision: "deny", reason}` 格式(符合 Gemini 的"黄金规则"exit-0 约定),在 BeforeAgent / AfterTool / SessionStart 时输出 `{hookSpecificOutput: {hookEventName, additionalContext}}` 进行上下文注入,在 AfterAgent 时输出 `{decision: "block", reason}` 实现强制重试语义。Gemini CLI 支持目前为 **beta** 版本,我们正在扩大实际场景覆盖范围。详见 [Gemini CLI hooks 文档](https://geminicli.com/docs/hooks/)。 - - **Hermes (hermes-agent)**:`~/.hermes/config.yaml`(**仅用户作用域**——Hermes 没有项目/本地配置)。Hermes 是一个 Slack/Telegram **网关**,因此一次安装即可拦截来自所有平台(Slack/Telegram/cli/cron)**以及**内部子代理的工具调用。Hook 条目是 `hooks:` 映射下的 `{command, timeout}` 对(timeout 单位为**秒**),以 Hermes 的蛇形命名事件为键(`pre_tool_call` / `post_tool_call` / `on_session_start` / `on_session_end` / `subagent_stop`);处理器通过 `HERMES_EVENT_MAP` 规范化事件,通过 `HERMES_TOOL_MAP` 规范化工具名称,使内置策略正常触发。配置通过保留注释的 YAML `Document` 往返编辑,以确保操作者的其他设置不受影响;安装时将 `hooks_auto_accept: true` 设置为 true,以便无头网关(无 TTY)在无需确认提示的情况下运行 hook。评估器输出 Hermes 的 `{"decision":"block","reason"}` stdout 约定(Hermes 忽略退出码)。**限制:** Hermes 没有会话结束 `Stop` 事件,因此 `require-*-before-stop` 内置策略永远不会为其触发(不适用,并非故障);`instruct` 降级为允许并记录日志(无额外上下文通道);输出密钥清理(`sanitize-*`)无法通过 shell hook 约定重写工具输出。Hermes **同时**也是一个离线**审计**数据源——仪表盘直接从 `~/.hermes/state.db` 读取其网关会话。 -- **`policies-config.json`** — 告知 failproofai 评估哪些策略及其参数(在所有代理 CLI 之间共享) - -通过 `--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes` 指定目标代理(可用空格分隔或重复指定多个): + - **OpenAI Codex**:`~/.codex/hooks.json`(用户级)、`/.codex/hooks.json`(项目级)—— Codex 没有 `local` 作用域 + - **GitHub Copilot CLI _(beta)_**:`~/.copilot/hooks/failproofai.json`(用户级)、`/.github/hooks/failproofai.json`(项目级)—— Copilot 没有 `local` 作用域。Hook 条目使用 Copilot 的操作系统键控 `bash`/`powershell` 命令字段(含 `timeoutSec`);文件顶层携带 `version: 1` 标记。Copilot CLI 支持处于 **beta** 阶段,我们正在针对更多真实会话验证 `events.jsonl` 记录 schema(公开文档中未作说明)。**VS Code Copilot Chat Agent 模式(预览版)** 从 `.github/hooks/*.json`、`~/.copilot/hooks/*.json` 和 `~/.claude/settings.json`(受 `chat.hookFilesLocations` 设置管理)读取 hook 配置,使用与 Claude 相同的 `{hookSpecificOutput:{permissionDecision:"deny",…}}` 协议——这正是 `copilot` 集成和 `claude` 集成(`~/.claude/settings.json`)已写入的路径,因此 `failproofai policies --install --cli copilot`(或 `--cli claude`)**已在 VS Code Agent 模式下强制执行**,无需单独的 `vscode` 集成(已通过 VS Code 发现日志实时确认)。 + - **Cursor Agent _(beta)_**:`~/.cursor/hooks.json`(用户级)、`/.cursor/hooks.json`(项目级)—— Cursor 没有 `local` 作用域。Hook 条目使用 Claude 风格的 `{type, command, timeout}` 形式(无 `bash`/`powershell` 区分),但按照 Cursor 的 [hooks schema](https://cursor.com/docs/hooks) 以 camelCase 事件键(`preToolUse`、`beforeSubmitPrompt` 等)存储在平铺数组中;文件顶层携带 `version: 1` 标记。处理程序通过 `CURSOR_EVENT_MAP` 将 camelCase 规范化为 PascalCase,因此现有内置策略无需修改即可正常触发。Cursor Agent 支持处于 **beta** 阶段,我们正在针对更多真实安装验证 Cursor 的磁盘上 transcript 格式(公开文档中未作说明)。 + - **OpenCode _(beta)_**:`~/.config/opencode/opencode.json` + `~/.config/opencode/plugins/failproofai.mjs`(用户级)、`/.opencode/opencode.json` + `/.opencode/plugins/failproofai.mjs`(项目级)—— OpenCode 没有 `local` 作用域。与其他五个 CLI 不同,OpenCode **没有外部命令 hook 系统**:它通过 `opencode.json` 中 `plugin: []` 数组显式注册的进程内 JS/TS 插件加载(从 `.opencode/plugins/` 自动发现**不是** opencode v1.14.33 上插件的加载方式)。安装时会生成一个轻量插件 shim,以子进程方式调用 failproofai 二进制文件,并将二进制的 Claude 风格 JSON 响应转换回插件语义:工具事件拒绝时 `throw new Error()`(取消工具调用),instruct 以及 `Stop`/`SubagentStop` 拒绝时调用 `client.session.prompt(...)`(将拒绝原因作为下一条用户消息提交——这是唯一的强制重试通道,因为 `session.idle` 仅用于通知,从中抛出异常无效),allow 时为空操作。Shim 在转发给二进制之前,会规范化工具名称(小写 → PascalCase,通过 `OPENCODE_TOOL_MAP`)和工具输入参数键(camelCase → snake_case,通过 `OPENCODE_TOOL_INPUT_MAP`,适用于 `Read`/`Write`/`Edit`,例如 `filePath` → `file_path`、`oldString` → `old_string`),因此 `block-read-outside-cwd`、`block-env-files`、`block-secrets-write` 等路径检查内置策略在 OpenCode 工具调用时可正常触发。会话存储在 OpenCode 的 SQLite 数据库 `~/.local/share/opencode/opencode.db` 中;控制台的会话查看器通过 `opencode db --format json` 和 `opencode export ` 读取。OpenCode 支持处于 **beta** 阶段,我们正在跨版本和更多真实会话中验证其行为。详见 [OpenCode 插件文档](https://opencode.ai/docs/plugins/)。 + - **Pi _(beta)_**:`~/.pi/agent/settings.json`(用户级)、`/.pi/settings.json`(项目级)—— Pi 没有 `local` 作用域。Pi 在启动时加载 TypeScript 扩展包;settings 文件是一个平铺的字符串数组 `{"packages": ["./relative/path", …]}`。failproofai 写入单条 packages 数组条目,指向其捆绑的 `pi-extension/` 目录。该扩展内部订阅 Pi 的 `tool_call`/`user_bash`/`input`/`session_start` 事件,并调用 `failproofai --hook --cli pi`;处理程序通过 `PI_EVENT_MAP` 将 underscore_lower_snake_case 规范化为 PascalCase,因此现有内置策略无需修改即可正常触发。工具输入参数也通过 `PI_TOOL_INPUT_MAP` 进行规范化(Pi 的 Read/Write/Edit 使用 `path` 而非 `file_path`;映射顶层键后 `block-env-files` 和 `block-secrets-write` 可正常触发——`block-read-outside-cwd` 已有 `path` 回退逻辑)。Pi 支持处于 **beta** 阶段,等待 Pi 的扩展 API 和会话日志格式稳定。 + - **Hermes (hermes-agent)**:`~/.hermes/config.yaml`(**仅用户作用域** —— Hermes 没有项目/本地配置)。Hermes 是一个 Slack/Telegram **网关**,因此一次安装即可拦截来自所有平台(Slack/Telegram/cli/cron)**及**内部子 Agent 的工具调用。Hook 条目是 `{command, timeout}` 对(timeout 单位为**秒**),位于 `hooks:` 映射下,以 Hermes 的 snake_case 事件为键(`pre_tool_call`/`post_tool_call`/`on_session_start`/`on_session_end`/`subagent_stop`);处理程序通过 `HERMES_EVENT_MAP` 规范化事件,通过 `HERMES_TOOL_MAP` 规范化工具名称,因此内置策略无需修改即可正常触发。配置通过保留注释的 YAML `Document` 往返方式编辑,确保操作员的其他设置得以保留;安装时设置 `hooks_auto_accept: true`,使无头网关(无 TTY)无需确认提示即可运行 hook。评估器输出 Hermes 的 `{"decision":"block","reason"}` stdout 协议(Hermes 忽略退出码)。**限制:** Hermes 没有轮次结束的 `Stop` 事件,因此 `require-*-before-stop` 内置策略永远不会为其触发(不适用,并非故障);`instruct` 降级为允许并记录日志(无额外上下文通道);输出密钥脱敏(`sanitize-*`)无法通过 shell-hook 协议重写工具输出。Hermes **同时也是**一个离线**审计**数据源——控制台直接从 `~/.hermes/state.db` 读取其网关会话。 + - **OpenClaw (openclaw gateway)**:`~/.openclaw/openclaw.json`(**仅用户作用域** —— OpenClaw 没有项目/本地配置)。与 Hermes 类似,OpenClaw 是一个自托管的多通道**网关**,因此一次安装即可拦截所有通道及其内部子 Agent 的工具调用。强制执行通过 OpenClaw 的**进程内插件 hook**运行(其基于文件的内部 hook 仅供观察,无法阻止),因此——与 OpenCode/Pi 类似——failproofai 提供一个静态 `openclaw-plugin/` 包,以异步方式生成 failproofai 二进制文件并转换裁决结果。安装时在 `openclaw.json` 的 `plugins.load.paths[]` 中注册所提供的插件目录,并在 `plugins.entries.failproofai` 下启用(带有 `hooks.allowConversationAccess: true`,原始对话 hook 所必需)。评估器输出平铺的 `{permission, reason}` 裁决,shim 将其映射到每个 hook 的原生返回形式:`before_tool_call → {block:true, blockReason}`(**PreToolUse**)、`before_agent_run → {outcome:"block", reason}`(**UserPromptSubmit**)、`before_agent_finalize → {action:"revise", reason}`(**Stop** —— 这是真正的轮次结束关卡,因此 `require-*-before-stop` 内置策略**在 OpenClaw 上会强制执行**,与 Hermes 不同)。事件和工具名称在二进制侧通过 `OPENCLAW_EVENT_MAP`/`OPENCLAW_TOOL_MAP`(`exec→Bash`、`read→Read` 等)进行规范化,因此内置策略无需修改即可正常触发;shim 在任何生成/解析/超时错误时失败开放。OpenClaw **同时也是**一个离线**审计**数据源——控制台从 `~/.openclaw/agents//sessions/.jsonl` 读取其 JSONL 会话。 + - **Factory Droid (`droid`)**:`~/.factory/hooks.json`(用户级)、`/.factory/hooks.json`(项目级)—— Factory 没有 `local` 作用域。droid 提供类 Claude 风格的外部命令 hook 系统,但经 droid v0.171.0 实际验证存在两个特殊之处:(1) 事件名称位于 `hooks.json` 的**顶层**——**没有 `"hooks"` 包装层**(droid 会拒绝包装层);工具事件(`PreToolUse`/`PostToolUse`)携带 `"matcher": "*"`,非工具事件则省略。(2) 拒绝由 hook **退出码 2 + stderr** 驱动,而非 JSON 决策——评估器的 `factory` 分支对工具/提示事件返回退出码 2,仅在轮次结束的 `Stop` 事件(droid 的唯一强制重试通道)上返回 `{decision:"block", reason}`。事件已为 PascalCase(无事件映射),载荷为 Claude snake_case;仅通过 `FACTORY_TOOL_MAP` 规范化工具名称(`Execute→Bash`、`Create→Write`、`FetchUrl→WebFetch` 等)。Factory **同时也是**一个离线**审计**数据源——控制台从 `~/.factory/sessions//.jsonl` 读取其磁盘 JSONL 会话。 + - **Devin CLI (`devin`,Cognition)**:`~/.config/devin/config.json`(用户级)、`/.devin/config.json`(项目级)—— Devin 没有 `local` 作用域。经 devin v3000.1.27 实际验证,Devin 是**纯 Claude 克隆**:使用标准 Claude `"hooks"` 包装 schema(写入采用合并保留方式,配置文件中的其他键——`org_id`、`theme_mode` 等——得以保留),已为 PascalCase 的事件名称(无事件映射,无处理程序分支),以及 Claude snake_case stdin 载荷(无需规范化)。评估器的 `devin` 分支对**所有**事件均以退出码 0 在 stdout 上输出 `{"decision":"block","reason"}` JSON 进行拒绝(已验证——该阻断覆盖了 `--permission-mode dangerous`);在轮次结束的 `Stop` 事件上,原因携带 MANDATORY-ACTION 强制重试措辞,因此 `require-*-before-stop` 内置策略会强制执行。仅通过 `DEVIN_TOOL_MAP` 规范化工具名称(`exec→Bash`;`tool_input.command` 已为规范形式)。Devin **同时也是**一个离线**审计**数据源——控制台从 `~/.local/share/devin/cli/sessions.db` 读取其 SQLite 会话(每个 `sessions` 行携带真实的 `working_directory`,因此会话像 Claude 一样按项目 cwd 分组)。 + - **Antigravity CLI (`agy`)**:`~/.gemini/config/hooks.json`(用户级)、`/.agents/hooks.json`(项目级)—— Antigravity 没有 `local` 作用域。与 Factory/Devin 不同,Antigravity 有其**自有**协议(非 Claude 克隆),经 agy v1.1.2 实际验证。`hooks.json` 使用**命名 hook** schema:顶层键是 hook *名称*(`"failproofai"`),其值是事件→处理程序映射——工具事件(`PreToolUse`/`PostToolUse`)将处理程序包装在 `{matcher:"*", hooks:[…]}` 中,而 `PreInvocation`/`Stop` 是**平铺**的处理程序数组(其他命名 hook 得以保留)。stdin 载荷为 **camelCase protojson**(`toolCall:{name,args}`、`conversationId`、`workspacePaths`、`transcriptPath`)——failproofai 在策略运行前将其规范化为 snake_case,并通过 `ANTIGRAVITY_TOOL_INPUT_MAP` 映射 `run_command` 的 PascalCase 参数(`CommandLine`/`Cwd`)。评估器的 `antigravity` 分支使用 Antigravity **自有**的响应形式:`{decision:"deny", reason}` 阻断工具/提示(退出码 0),`{decision:"continue", reason}` 在轮次结束的 `Stop` 时重新进入循环(因此 `require-*-before-stop` 内置策略会强制执行),`{injectSteps:[{ephemeralMessage}]}` 在 `PreInvocation`(→ `UserPromptSubmit`)时注入指令。工具名称通过 `ANTIGRAVITY_TOOL_MAP` 规范化(`run_command→Bash`、`view_file→Read` 等)。Antigravity **同时也是**一个离线**审计**数据源——控制台从 `~/.gemini/antigravity-cli/brain//.system_generated/logs/transcript_full.jsonl` 读取其纯 JSONL transcript(对话索引位于 `conversation_summaries.db`)。 + - **Goose (代号 goose,Block)**:`~/.agents/plugins/failproofai/hooks/hooks.json`(用户级)、`/.agents/plugins/failproofai/hooks/hooks.json`(项目级)—— Goose 没有 `local` 作用域。强制执行使用 Goose 的 **hooks** 系统,即跨 Agent 的 **Open Plugins** 规范:安装程序只需放入 `failproofai` 插件目录,Goose 在启动时自动发现并将其自注册到 `~/.config/goose/config.yaml`。`hooks.json` 使用带有顶层 `"hooks"` 包装层的 Open Plugins schema,且每个事件均**省略** matcher——裸 `"*"` 是一个无效正则表达式,不匹配任何内容(经 goose v1.43.0 实际验证)。事件名称已为 PascalCase(无事件映射);stdin 载荷使用 `event`/`working_dir`,处理程序将其规范化为 `hook_event_name`/`cwd`。评估器的 `goose` 分支以退出码 0 在 stdout 上输出 `{"decision":"block","reason"}` JSON 进行拒绝,仅在 **`PreToolUse`** 事件上生效(goose ≥ v1.37.0 中提供)——该事件对 shell 工具**以及委托的子 Agent 内部**均会触发,因此是唯一充分的拒绝点;任何其他 hook 错误均**失败开放**。Goose **没有 `Stop` 事件**,因此 `require-*-before-stop` 内置策略不适用(与 Hermes 相同)。工具名称通过 `GOOSE_TOOL_MAP` 规范化(`shell→Bash`、`write→Write`、`todo__todo_write→TodoWrite` 等),路径键通过 `GOOSE_TOOL_INPUT_MAP` 规范化(`path`/`source` → `file_path`)。Goose **同时也是**一个离线**审计**数据源——控制台从 `~/.local/share/goose/sessions/sessions.db` 读取其 SQLite 会话(每个 `sessions` 行携带真实的 `working_dir`,因此会话像 Devin 一样按项目 cwd 分组;`--no-session` 临时运行会被过滤)。 +- **`policies-config.json`** — 告知 failproofai 需要评估哪些策略及其参数配置(在所有 Agent CLI 之间共享) + +通过 `--cli claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose` 指定目标 Agent(多个值以空格分隔或重复传入): ```bash failproofai policies --install --cli codex --scope project @@ -210,25 +214,29 @@ failproofai policies --install --cli copilot --scope project failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project -failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user -failproofai policies --install --cli claude codex copilot cursor opencode pi gemini +failproofai policies --install --cli openclaw --scope user +failproofai policies --install --cli factory --scope project +failproofai policies --install --cli devin --scope project +failproofai policies --install --cli antigravity --scope project +failproofai policies --install --cli goose --scope project +failproofai policies --install --cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose ``` -省略 `--cli` 时,`failproofai` 会自动检测已安装的代理 CLI(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which gemini` / `which hermes`): +省略 `--cli` 时,`failproofai` 会自动检测已安装的 Agent CLI(`which claude` / `which codex` / `which copilot` / `which cursor-agent` / `which opencode` / `which pi` / `which hermes` / `which openclaw` / `which droid` / `which devin` / `which agy` / `which goose`): - **检测到一个 CLI** — 自动选择该 CLI,无需提示。 -- **在交互式终端中检测到多个 CLI** — 显示方向键单选菜单,分为 `Detected (N)` 区域(包含一个"为所有 N 个已检测到的 CLI 安装"的聚合行及各个已检测 CLI)和 `Not installed (M) · install hooks ahead of time` 区域(列出所有未检测到的受支持 CLI 作为提前安装选项)(↑↓ 移动,回车选择,^C 退出)。卸载流程仅显示 Detected 区域。 -- **在非交互式运行中检测到多个 CLI**(CI、无 TTY)— 无需提示,为所有检测到的 CLI 安装。 -- **未检测到任何 CLI** — 回退到 `claude`,并显示在 PATH 中未找到代理二进制文件的警告;hook 命令仍会被写入,一旦安装代理即可生效。 +- **检测到多个 CLI**,且在交互式终端中 — 显示方向键单选提示,分为 `Detected (N)` 分组(含 `Install for all N detected` 聚合行和每个已检测 CLI 的独立选项)以及 `Not installed (M) · install hooks ahead of time` 分组(列出所有未检测到的支持 CLI 作为预安装选项;↑↓ 移动,Enter 确认,^C 退出)。卸载流程仅显示 Detected 分组。 +- **检测到多个 CLI**,且在非交互式环境(CI、无 TTY)中 — 直接为所有已检测 CLI 安装,无需提示。 +- **未检测到任何 CLI** — 回退至 `claude`,并提示 PATH 中未找到 Agent 二进制文件;hook 命令仍会被写入,待安装 Agent 后即可生效。 -你可以随时直接编辑 `policies-config.json`,修改将在下一次 hook 事件触发时立即生效,无需重启。 +您可以随时直接编辑 `policies-config.json`,更改会在下次 hook 事件触发时立即生效,无需重启。 --- -## 示例:带团队默认配置的项目级配置 +## 示例:包含团队默认配置的项目级配置 -将 `.failproofai/policies-config.json` 提交到你的仓库: +将 `.failproofai/policies-config.json` 提交到您的代码仓库: ```json { @@ -247,4 +255,4 @@ failproofai policies --install --cli claude codex copilot cursor opencode pi gem } ``` -每位开发者可以创建 `.failproofai/policies-config.local.json`(已加入 gitignore)进行个人覆盖配置,而不影响其他团队成员。 \ No newline at end of file +每位开发者可以在此基础上创建 `.failproofai/policies-config.local.json`(已加入 gitignore)进行个人覆盖配置,而不会影响到其他团队成员。 \ No newline at end of file diff --git a/docs/zh/dashboard.mdx b/docs/zh/dashboard.mdx index 721b39e2..87cf71ca 100644 --- a/docs/zh/dashboard.mdx +++ b/docs/zh/dashboard.mdx @@ -1,14 +1,14 @@ --- -title: 控制台 +title: 仪表盘 description: "监控 Agent 会话、查看工具调用并管理策略" icon: chart-line --- -failproofai 控制台是一个本地 Web 应用,用于监控 AI Agent 会话和管理策略。查看 Agent 在你离开期间的所有操作。 +failproofai 仪表盘是一个本地 Web 应用,用于监控您的 AI Agent 会话并管理策略。查看您不在时 Agent 做了什么。 --- -## 启动控制台 +## 启动仪表盘 ```bash failproofai @@ -16,58 +16,58 @@ failproofai 在 `http://localhost:8020` 打开。 -控制台直接从文件系统读取数据——包括你的 Claude Code 项目文件夹和 failproofai 配置文件。不会向任何远程服务写入数据。 +仪表盘直接从文件系统读取数据——包括您的 Claude Code 项目文件夹和 failproofai 配置文件。不会向远程服务写入任何内容。 --- -## 页面说明 +## 页面 ### 项目 -列出在你的机器上发现的所有 Claude Code、OpenAI Codex、GitHub Copilot CLI _(beta)_、Cursor Agent _(beta)_、OpenCode _(beta)_、Pi _(beta)_、Gemini CLI _(beta)_ 和 Hermes 项目。Claude 项目从 `~/.claude/projects/`(或由 `CLAUDE_PROJECTS_PATH` 设置的路径)中发现;Codex 项目通过扫描 `~/.codex/sessions///
/*.jsonl` 下的所有记录,并按每个会话第一条记录中的 `cwd` 字段分组发现;Copilot CLI 项目通过扫描 `~/.copilot/session-state//workspace.yaml`(可通过 `COPILOT_HOME` 配置),并按其 `cwd` 字段分组发现;Cursor Agent 项目通过扫描 `~/.cursor/agent-sessions//`(可通过 `CURSOR_HOME` 配置,并以 `conversations/` 和 `sessions/` 作为备选路径)下的逐会话元数据,从 `meta.json` / `session.json` / `workspace.yaml` 中的 `cwd` 标量发现;OpenCode 项目通过 `opencode db --format json` 查询位于 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库发现(读取 `session` 和 `project` 表并按 `project_id` 分组);Pi 项目通过扫描 `~/.pi/agent/sessions//_.jsonl`(可通过 `PI_SESSIONS_DIR` 配置)下的逐会话 JSONL 记录,并从每个会话的第一条记录中提取 `cwd` 发现;Gemini CLI 项目通过扫描 `~/.gemini/tmp//chats/session--.jsonl`(可通过 `GEMINI_SESSIONS_DIR` 配置),并从同级 `.project_root` 文本标记中恢复规范化 cwd 发现;Hermes 网关会话直接从 `~/.hermes/state.db`(可通过 `HERMES_DB_PATH` 配置)的 SQLite 存储中读取,并按 `source`(Slack/Telegram/cli/cron——网关会话没有 cwd)分组为 `hermes-` 项目。被多个 CLI 使用的项目在同一行显示,并附上所有匹配的徽章。使用表格上方的 **CLI** 下拉菜单按特定 Agent CLI 筛选;URL 会将你的选择保存为 `?cli=claude|codex|copilot|cursor|opencode|pi|gemini|hermes`。 +列出在您机器上发现的所有 Claude Code、OpenAI Codex、GitHub Copilot CLI _(测试版)_、Cursor Agent _(测试版)_、OpenCode _(测试版)_、Pi _(测试版)_、Hermes、OpenClaw、Factory Droid、Devin、Antigravity 和 Goose 项目。Claude 项目从 `~/.claude/projects/` 中发现(或由 `CLAUDE_PROJECTS_PATH` 设置的路径);Codex 项目通过扫描 `~/.codex/sessions///
/*.jsonl` 下的所有对话记录,并按每个会话第一条记录中的 `cwd` 分组发现;Copilot CLI 项目通过扫描每个 `~/.copilot/session-state//workspace.yaml`(可通过 `COPILOT_HOME` 配置)并按其 `cwd` 字段分组发现;Cursor Agent 项目通过扫描 `~/.cursor/agent-sessions//`(可通过 `CURSOR_HOME` 配置,并以 `conversations/` 和 `sessions/` 作为备选路径)下每个会话的元数据,从 `meta.json` / `session.json` / `workspace.yaml` 中获取 `cwd` 标量来发现;OpenCode 项目通过 `opencode db --format json` 查询位于 `~/.local/share/opencode/opencode.db` 的 SQLite 数据库(读取 `session` 和 `project` 表,并按 `project_id` 分组)来发现;Pi 项目通过扫描 `~/.pi/agent/sessions//_.jsonl`(可通过 `PI_SESSIONS_DIR` 配置)下每个会话的 JSONL 对话记录,并从每个会话的第一条记录中提取 `cwd` 来发现;Hermes 网关会话直接从位于 `~/.hermes/state.db`(可通过 `HERMES_DB_PATH` 配置)的 SQLite 存储中读取,并按 `source`(Slack/Telegram/cli/cron)分组为 `hermes-` 项目(网关会话没有 cwd);OpenClaw 网关会话从 `~/.openclaw/agents//sessions/*.jsonl` 读取,并分组为 `openclaw-` 项目(同样没有 cwd);Factory Droid 项目从 `~/.factory/sessions//*.jsonl` 的 JSONL 对话记录中发现,并按 cwd 分组;Devin 项目从位于 `~/.local/share/devin/cli/sessions.db` 的 SQLite 数据库中发现(按每个会话的 `working_directory` 分组);Antigravity 项目从 `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl` 的 JSONL 对话记录中发现,并按 cwd 分组;Goose 项目从位于 `~/.local/share/goose/sessions/sessions.db` 的 SQLite 数据库中发现(按每个会话的 `working_dir` 分组)。被多个 CLI 使用过的项目会渲染为单行,并显示所有匹配的徽章。使用表格上方的 **CLI** 下拉菜单按特定 Agent CLI 进行过滤;URL 会将您的选择保留为 `?cli=claude|codex|copilot|cursor|opencode|pi|hermes|openclaw|factory|devin|antigravity|goose`。 每个项目显示: - 项目名称(从文件夹路径派生) -- CLI 徽章——`Claude Code`(橙色)、`OpenAI Codex`(紫色)、`GitHub Copilot`(蓝色)、`Cursor Agent`(翠绿色)、`OpenCode`(琥珀色)、`Pi`(粉色)、`Gemini CLI`(天蓝色)和/或 `Hermes`(靛蓝色) -- 最近一次会话活动的日期 +- CLI 徽章——`Claude Code`(橙色)、`OpenAI Codex`(紫色)、`GitHub Copilot`(蓝色)、`Cursor Agent`(翠绿色)、`OpenCode`(琥珀色)、`Pi`(粉色)和/或 `Hermes`(靛蓝色) +- 最近会话活动的日期 -点击项目可查看其会话列表。 +点击项目可查看其会话。 ### 会话 -列出项目内的所有会话。每个会话显示: +列出项目中的所有会话。每个会话显示: - 会话 ID - 开始和结束时间戳 - 工具调用次数 -- Hook 活动计数(触发的策略数量) +- Hook 活动次数(触发的策略数量) -使用日期范围筛选和会话 ID 搜索来缩小列表范围。会话以分页形式显示。 +使用日期范围过滤器和会话 ID 搜索来缩小列表范围。会话支持分页。 点击会话可打开会话查看器。 ### 会话查看器 -会话查看器回答了自主 Agent 的核心问题:Agent 做了什么,是否保持在正轨上?页眉旁的 CLI 徽章指示该会话是 Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Gemini CLI 还是 Hermes 的记录。它以时间线形式展示会话中发生的所有事件: +会话查看器回答了自主 Agent 的关键问题:Agent 做了什么,它是否保持在正轨上?标题旁边的 CLI 徽章表示该会话是 Claude Code、OpenAI Codex、GitHub Copilot CLI、Cursor Agent、OpenCode、Pi、Hermes、OpenClaw、Factory Droid、Devin、Antigravity 还是 Goose 的对话记录。它显示会话中发生的所有事件的时间线: - **消息** - Claude 的文本回复和用户提示 - **工具调用** - Claude 调用的每个工具,包含其输入和输出 -- **策略活动** - 每次工具调用触发了哪些策略及其返回的决策 +- **策略活动** - 针对每个工具调用,显示哪些策略被触发以及它们返回了什么决策 -顶部的统计栏显示会话时长、工具调用总数,以及 Hook 决策摘要(allow / deny / instruct 计数)。 +顶部的统计栏显示会话时长、总工具调用次数以及 Hook 决策摘要(allow / deny / instruct 计数)。 -点击**下载日志**按钮可导出会话。对于 Claude Code、Codex、Copilot、Cursor、Pi 和 Gemini 会话,你将获得原始的磁盘 JSONL 记录文件(逐字节原样);对于 OpenCode(其会话存储在 SQLite 而非磁盘上),你将获得一个 JSON 文档,镜像底层的 `session` / `messages` / `parts` 表。 +点击 **下载日志** 按钮导出会话。对于 Claude Code、Codex、Copilot、Cursor 和 Pi 会话,您将获得磁盘上原始的 JSONL 对话记录(逐字节);对于 OpenCode(其会话存储在 SQLite 而非磁盘上),您将获得一个反映底层 `session` / `messages` / `parts` 表的 JSON 文档。 ### 审计 -一份具有个性化风格的报告,展示你的 Agent 在过去会话中的真实行为。运行与 `failproofai audit` CLI 相同的扫描,并将结果渲染为一个单屏可分享的海报,加上折叠区域下方的四个部分: +一份带有个性化风格的报告,展示您的 Agent 在过去会话中的实际行为。运行与 `failproofai audit` CLI 相同的扫描,但将结果渲染为单屏可分享海报及四个折叠下方的区块: -1. **海报** — 填满第一个视口。独立 PNG 捕获区域,包含 failproof_ai 文字标志 + 审计标签·原型索引(`№ NN of 08`)+ 审计日期·数值评分(0–100)+ 百分位等级标签(`top 15%`)·原型名称(`the optimist`、`the cowboy`、`the explorer`、`the goldfish`、`the paranoid architect`、`the precision builder`、`the hammer`、`the ghost` 之一)+ 3 关键词条·`// only N% of agents are this archetype` 稀有度说明·8×8 像素印记图块·`audit yours → failproof.ai` 页脚。捕获框外有三个分享按钮:`post your archetype`(X intent)、`share on linkedin`、`download poster`。捕获通过 `html-to-image` 实现,PNG 与屏幕渲染像素级一致(虚线边框、SVG logo 遮罩、渐变、字体度量——全部保留)。 -2. **优势** — 以平静的 ✓ 行列表形式,展示你的 Agent 已经做对的行为,来源于实时审计数据(干净的工具调用率、无直接推送到主分支、零凭据泄露、零重试风暴)——仅在相关策略在审计窗口内保持干净记录时才显示。 -3. **不足** — 按严重程度排序展示漏网之鱼的表格:`时间 · 漏网内容 + 可捕获该问题的策略 · 严重程度标签 · 出现次数`,其中出现次数读作 `new`(一次)、`N× seen`(2–9 次)或 `recurring`(10+ 次)。 -4. **改进建议** — 平静的行列表,每行对应一条建议策略:白色显示策略名称、一行描述,右侧是安装命令和复制按钮。该部分标题显示 `enable all N → projected · `(应用所有修复后可达到的分数),其 `[install all]` 按钮可复制包含所有建议策略的 `failproofai policy add a b c …` 组合命令。 -5. **下次更好** — 两张并排卡片。左侧:设置提醒(`3d` / `7d` / `14d` / `30d` 周期选择器;通过 `/api/auth/reminder` 在授权后持久保存)。右侧:解锁 failproof 福利——`invite a friend` 打开一个弹窗,接受逗号/空格/换行符分隔的好友邮箱列表(每次最多 10 个),通过 POST 发送到 `/api/audit/invite`,再转发到 api-server 的 `POST /v0/invite`。api-server 以 `invite@failproof.ai` 为每位收件人单独发送邮件,同时抄送发件人并设置 `Reply-To`,让收件人知道是谁邀请了他们,发件人也会在收件箱收到副本。匿名用户会先经过 `AuthDialog` 认证,确保在发送邀请前已知发件人邮箱。权限/福利兑现为后续功能。 +1. **海报** — 填满第一个视口。包含 failproof_ai 文字标志 + 审计标签 · 原型索引(`№ NN of 08`)+ 审计日期 · 数字评分(0–100)+ 百分位等级标签(`top 15%`)· 原型名称(`the optimist`、`the cowboy`、`the explorer`、`the goldfish`、`the paranoid architect`、`the precision builder`、`the hammer`、`the ghost` 之一)+ 3 个关键词条 · `// only N% of agents are this archetype` 稀有度说明 · 8×8 像素印记图块 · `audit yours → failproof.ai` 页脚。捕获框外侧有三个分享按钮:`post your archetype`(X 分享)、`share on linkedin`、`download poster`。捕获通过 `html-to-image` 运行,PNG 与屏幕渲染像素级一致(虚线边框、SVG 徽标遮罩、渐变、字体度量——全部保留)。 +2. **优势** — 平静的 ✓ 行列表,列出您的 Agent 已做到位的行为,从实时审计数据中派生(工具调用清洁率、未直接推送到主分支、零凭证泄露、零重试风暴)——仅当相关策略在审计窗口内记录清洁时才显示。 +3. **怪癖** — 按严重程度排序的漏网内容表格:`时间 · 漏网内容 + 本可捕获的策略 · 严重程度标签 · 出现次数`,其中重复次数显示为 `new`(1次)、`N× seen`(2–9次)或 `recurring`(10次以上)。 +4. **如何改进** — 平静的行列表,每行对应一个建议策略:策略名称以白色显示,一行描述,右侧为安装命令 + 复制按钮。区块标题显示 `enable all N → projected · `(应用所有修复后您将达到的评分),其 `[install all]` 按钮复制所有建议策略的组合 `failproofai policy add a b c …` 命令。 +5. **更好地回来** — 两张并排卡片。左侧:设置提醒(`3d` / `7d` / `14d` / `30d` 周期选择器;通过 `/api/auth/reminder` 在认证后持久化)。右侧:解锁 failproof 特权——`invite a friend` 打开一个模态框,接受逗号/空格/换行分隔的好友邮件列表(每次最多发送 10 封),通过 POST 提交到 `/api/audit/invite`,再转发到 api-server 的 `POST /v0/invite`。api-server 从 `invite@failproof.ai` 向每个收件人发送一封邮件,抄送发件人并设置 `Reply-To`,这样收件人可以看到邀请人是谁,发件人也会在收件箱收到一份副本。匿名用户会先通过 `AuthDialog` 流程,以便在发送邀请前知晓发件人邮箱。权益/特权履行将作为后续功能跟进。 -由 `failproofai audit` 运行时驱动——有关底层扫描引擎、支持的标志和逐记录缓存不变量,请参阅 [审计 CLI](/zh/cli/audit)。控制台在 `~/.failproofai/audit-dashboard.json`(权限 `0600`,单槽位,新运行覆盖旧结果)缓存最新结果,以便重访时即时加载;**逐记录缓存和整体结果缓存在超过 7 天后读取时均会被拒绝**,因此控制台永远不会静默地提供一周前的旧结果——超过 TTL 后,`/audit` 会回退到空白状态并提示重新运行。点击报告底部附近的 `[ re-audit now ]` 会向 `/api/audit/run` 发送带 `noCache: true` 的 POST 请求——重新审计会绕过逐记录缓存,从头重新扫描每条记录,而不是静默返回缓存结果——控制台以 1Hz 频率轮询 `/api/audit/status`,直到运行完成;运行期间,顶部视口会固定显示一个带有计时器的粉色进度条;运行成功后,新结果原地替换显示(无需整页刷新;重新审计失败时保留之前的报告)。失败时,进度条变为红色,并根据 `RerunError.kind`(`timeout` / `network` / `post_failed`)显示相应的提示文案。空白状态(无缓存或已过期)和零会话状态(缓存存在但扫描未找到记录)分别独立显示。 +由 `failproofai audit` 运行时驱动——请参阅 [审计 CLI](/zh/cli/audit) 了解底层扫描引擎、支持的标志和每个对话记录的缓存不变量。仪表盘将最新结果缓存于 `~/.failproofai/audit-dashboard.json`(权限 `0600`,单槽位,新运行覆盖旧结果),因此再次访问时速度极快;**每个对话记录缓存和整体结果缓存在读取时一旦超过 7 天即被拒绝**,仪表盘不会静默提供超过一周的旧结果——超过 TTL 后,`/audit` 将回落到空状态并提示进行新的运行。点击报告底部附近的 `[ re-audit now ]` 会向 `/api/audit/run` 发送带有 `noCache: true` 的 POST——重新审计会绕过每个对话记录的缓存,从头重新扫描每个对话记录,而不是静默返回缓存结果——仪表盘以 1Hz 频率轮询 `/api/audit/status` 直到运行完成;运行期间,视口顶部会固定显示一条粉色进度条和已用时间计时器,运行成功后新结果将就地替换(无需整页刷新;重新审计失败时保留之前的报告)。失败时,进度条变为红色,并根据 `RerunError.kind`(`timeout` / `network` / `post_failed`)显示相应的错误文案。空状态(无缓存或缓存已过期)和零会话状态(缓存存在但扫描未找到任何对话记录)会分别显示。 ### 策略 @@ -75,16 +75,16 @@ failproofai - - 在单一面板中多选 failproofai 保护哪些 Agent CLI——Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi、Gemini CLI 和 Hermes 各有一行,显示安装状态(`Active` / `Detected` / `Inactive`)、用户范围设置路径,以及品牌色强调。勾选或取消勾选你想要的 CLI,点击 `Apply changes` 一步完成安装/卸载差异。已在 PATH 中检测到二进制文件的 CLI 会被预先勾选。 - - 一键开启或关闭单个策略(写入 `~/.failproofai/policies-config.json`——所有已安装的 CLI 共享) + - 从单一面板多选 failproofai 保护哪些 Agent CLI——Claude Code、OpenAI Codex、GitHub Copilot、Cursor Agent、OpenCode、Pi 和 Hermes 各有一行,显示安装状态(`Active` / `Detected` / `Inactive`)、用户范围的设置路径和品牌色调强调。勾选或取消勾选您想要的 CLI,然后点击 `Apply changes` 一步完成安装/卸载差异。PATH 上检测到二进制文件的 CLI 会预先勾选。 + - 单击即可开启或关闭单个策略(写入 `~/.failproofai/policies-config.json`——在所有已安装的 CLI 之间共享) - 展开策略以配置其参数(适用于支持 `policyParams` 的策略) - 设置自定义策略文件路径 - 所有会话中触发的每个 Hook 事件的完整分页历史记录 - - 按决策、事件类型、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(beta)_ / Cursor Agent _(beta)_ / OpenCode _(beta)_ / Pi _(beta)_ / Gemini CLI _(beta)_ / Hermes)、策略名称或会话 ID 筛选 - - 每行显示:时间戳、策略名称、决策、CLI 徽章(橙色 = Claude Code,紫色 = OpenAI Codex,蓝色 = GitHub Copilot,翠绿色 = Cursor Agent,琥珀色 = OpenCode,粉色 = Pi,天蓝色 = Gemini CLI,靛蓝色 = Hermes)、工具名称、会话 ID,以及 deny/instruct 决策的原因 - - 点击会话 ID 可打开其记录——查看器自动检测触发 Hook 的 CLI(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Gemini CLI `~/.gemini/tmp//chats/.jsonl`、Hermes `~/.hermes/state.db`),并在页眉中渲染对应的 CLI 徽章 + - 按决策、事件类型、CLI(Claude Code / OpenAI Codex / GitHub Copilot _(测试版)_ / Cursor Agent _(测试版)_ / OpenCode _(测试版)_ / Pi _(测试版)_ / Hermes / OpenClaw / Factory Droid / Devin / Antigravity / Goose)、策略名称或会话 ID 进行过滤 + - 每行显示:时间戳、策略名称、决策、CLI 徽章(橙色 = Claude Code,紫色 = OpenAI Codex,蓝色 = GitHub Copilot,翠绿色 = Cursor Agent,琥珀色 = OpenCode,粉色 = Pi,靛蓝色 = Hermes,青色 = OpenClaw,玫瑰色 = Factory Droid,紫罗兰色 = Devin,青色 = Antigravity,青柠色 = Goose)、工具名称、会话 ID 以及 deny/instruct 决策的原因 + - 点击会话 ID 打开其对话记录——查看器会自动检测触发 Hook 的 CLI(Claude `~/.claude/projects/…`、Codex `~/.codex/sessions/…`、Copilot CLI `~/.copilot/session-state//events.jsonl`、Cursor Agent `~/.cursor/agent-sessions//events.jsonl`、OpenCode `~/.local/share/opencode/opencode.db`、Pi `~/.pi/agent/sessions//.jsonl`、Hermes `~/.hermes/state.db`、OpenClaw `~/.openclaw/agents//sessions/*.jsonl`、Factory Droid `~/.factory/sessions//.jsonl`、Devin `~/.local/share/devin/cli/sessions.db`、Antigravity `~/.gemini/antigravity-cli/brain//…/transcript_full.jsonl`、Goose `~/.local/share/goose/sessions/sessions.db`),并在标题中渲染匹配的 CLI 徽章 @@ -92,13 +92,13 @@ failproofai ## 自动刷新 -控制台顶部导航栏有一个自动刷新开关。启用后,当前页面会定期刷新,以显示新出现的会话和策略活动。这对于监控长时间运行的自主 Agent 会话至关重要。 +仪表盘顶部导航栏有一个自动刷新开关。启用后,当前页面会定期刷新,以实时显示新会话和策略活动。这对于监控长时间运行的自主 Agent 会话至关重要。 --- ## 禁用页面 -如果你只需要控制台的部分功能,可以将 `FAILPROOFAI_DISABLE_PAGES` 设置为逗号分隔的页面名称列表: +如果您只需要仪表盘的某些部分,可以将 `FAILPROOFAI_DISABLE_PAGES` 设置为逗号分隔的页面名称列表: ```bash FAILPROOFAI_DISABLE_PAGES=policies failproofai @@ -110,7 +110,7 @@ FAILPROOFAI_DISABLE_PAGES=policies failproofai ## 配置项目路径 -默认情况下,控制台从标准 Claude Code 项目目录读取。可以为自定义设置覆盖路径: +默认情况下,仪表盘从标准的 Claude Code 项目目录读取。对于自定义设置,可以覆盖该路径: ```bash CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai @@ -120,25 +120,25 @@ CLAUDE_PROJECTS_PATH=/custom/path/to/projects failproofai ## 从非 localhost 主机访问 -在**开发模式**(`npm run dev`)下运行控制台并从 `localhost` 以外的主机名访问时——例如自定义域名、远程 IP 或隧道 URL——你可能会看到如下警告: +在 **开发模式**(`npm run dev`)下运行仪表盘,并从 `localhost` 以外的主机名访问时——例如自定义域名、远程 IP 或隧道 URL——您可能会看到如下警告: ```text ⚠ Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr from "dashboard.example.com". ``` -这是 Next.js 阻止跨域访问其 HMR(热模块重载)WebSocket 的行为,该功能仅在开发模式下存在。要允许你的主机,请使用 `--allowed-origins` 标志: +这是 Next.js 阻止对其 HMR(热模块重载)WebSocket 的跨域访问,这是一个仅限开发模式的功能。要允许您的主机,请使用 `--allowed-origins` 标志: ```bash npm run dev -- --allowed-origins dashboard.example.com ``` -对于多个主机或 IP,传入逗号分隔的列表: +对于多个主机或 IP,传递逗号分隔的列表: ```bash npm run dev -- --allowed-origins dashboard.example.com,192.168.1.5 ``` -你也可以设置 `FAILPROOFAI_ALLOWED_DEV_ORIGINS` 环境变量来替代: +您也可以设置 `FAILPROOFAI_ALLOWED_DEV_ORIGINS` 环境变量: ```bash FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev diff --git a/docs/zh/getting-started.mdx b/docs/zh/getting-started.mdx index 92ed9c45..bad1180c 100644 --- a/docs/zh/getting-started.mdx +++ b/docs/zh/getting-started.mdx @@ -1,10 +1,10 @@ --- -title: 快速开始 -description: "安装 failproofai,启用策略,让你的 Agent 稳定可靠地运行" +title: 快速入门 +description: "安装 failproofai,启用策略,让你的智能体稳定运行" icon: rocket --- -## 环境要求 +## 系统要求 - **Node.js** >= 20.9.0 - **Bun** >= 1.3.0(可选 - 仅在从源码构建时需要) @@ -27,19 +27,19 @@ bun add -g failproofai --- -## 快速上手 +## 快速开始 - 策略是在每次 Agent 工具调用前后执行的规则。它们能在破坏性命令、密钥泄露及其他故障模式造成损害之前将其拦截。 + 策略是在每次智能体工具调用前后执行的规则。它们能在破坏性命令、密钥泄露及其他故障模式造成损害之前将其拦截。 ```bash failproofai policies --install ``` - 此命令会将 hook 条目写入已安装的 Agent CLI 配置文件中(Claude Code 的 `~/.claude/settings.json`、OpenAI Codex 的 `~/.codex/hooks.json`、GitHub Copilot CLI 的 `~/.copilot/hooks/failproofai.json`、Cursor Agent 的 `~/.cursor/hooks.json`、OpenCode 在 `~/.config/opencode/plugins/failproofai.mjs` 生成的插件 shim 及 `~/.config/opencode/opencode.json` 的 `plugin` 数组注册项、Pi 的 `~/.pi/agent/settings.json`、Gemini CLI 的 `~/.gemini/settings.json`,或 Hermes 的 `~/.hermes/config.yaml`)。若检测到多个 CLI,系统会提示你选择;也可以通过 `--cli claude codex copilot cursor opencode pi gemini hermes`(任意子集)跳过提示。 + 该命令会将 hook 条目写入你已安装的智能体 CLI(Claude Code 的 `~/.claude/settings.json`、OpenAI Codex 的 `~/.codex/hooks.json`、GitHub Copilot CLI 的 `~/.copilot/hooks/failproofai.json`、Cursor Agent 的 `~/.cursor/hooks.json`、OpenCode 生成的插件 shim 位于 `~/.config/opencode/plugins/failproofai.mjs` 并在 `~/.config/opencode/opencode.json` 的 `plugin` 数组中添加注册条目、Pi 的 `~/.pi/agent/settings.json`、Hermes 的 `~/.hermes/config.yaml`、OpenClaw 的 `~/.openclaw/openclaw.json`、Factory Droid 的 `~/.factory/hooks.json`、Devin CLI 的 `~/.config/devin/config.json`、Antigravity CLI 的 `~/.gemini/config/hooks.json`,以及 Goose 自动发现的插件目录 `~/.agents/plugins/failproofai/hooks/hooks.json`)。如果检测到多个 CLI,将提示你选择;传入 `--cli claude codex copilot cursor opencode pi hermes openclaw factory devin antigravity goose`(任意子集)可跳过提示。 - GitHub Copilot CLI、Cursor Agent、OpenCode、Pi 和 Gemini CLI 的支持目前处于 **beta** 阶段 — 请分别使用 `--cli copilot`、`--cli cursor`、`--cli opencode`、`--cli pi` 或 `--cli gemini` 进行安装。Hermes(hermes-agent,一个 Slack/Telegram 网关)使用 `--cli hermes` 安装用户级作用域,同时也是一个**离线**审计数据源。 + GitHub Copilot CLI、Cursor Agent、OpenCode 和 Pi 的支持处于 **测试阶段** —— 分别使用 `--cli copilot`、`--cli cursor`、`--cli opencode` 或 `--cli pi` 安装。Hermes(hermes-agent,一个 Slack/Telegram 网关)使用 `--cli hermes` 以用户范围安装,同时也是**离线审计源**。OpenClaw(openclaw 网关,一个自托管多渠道助手)使用 `--cli openclaw` 以用户范围安装 —— 通过其进程内插件 hook(`before_agent_finalize` 是真实的轮次结束关卡,因此内置的 `require-*-before-stop` 规则会强制执行)—— 同时也是**离线审计源**。Factory Droid(`droid`)使用 `--cli factory`(用户 + 项目范围)安装,同时也是**离线审计源**。Devin CLI(`devin`,Cognition)使用 `--cli devin`(用户 + 项目范围)安装,同时也是**离线审计源**。Antigravity CLI(`agy`)使用 `--cli antigravity`(用户 + 项目范围)安装,同时也是**离线审计源**。Goose(代号 goose,Block)使用 `--cli goose`(用户 + 项目范围)安装 —— 安装程序只需在 `~/.agents/plugins/failproofai/` 创建一个插件目录,Goose 会自动发现它,同时也是**离线审计源**。 ```bash failproofai policies --install --scope project @@ -48,8 +48,12 @@ bun add -g failproofai failproofai policies --install --cli cursor --scope project failproofai policies --install --cli opencode --scope project failproofai policies --install --cli pi --scope project - failproofai policies --install --cli gemini --scope project failproofai policies --install --cli hermes --scope user + failproofai policies --install --cli openclaw --scope user + failproofai policies --install --cli factory --scope project + failproofai policies --install --cli devin --scope project + failproofai policies --install --cli antigravity --scope project + failproofai policies --install --cli goose --scope project failproofai policies --install block-sudo block-rm-rf sanitize-api-keys ``` @@ -58,25 +62,25 @@ bun add -g failproofai failproofai policies ``` - 显示所有策略、各策略的启用状态及已配置的参数。 + 显示所有策略、是否已启用,以及已配置的参数。 - + ```bash failproofai ``` - 在 `http://localhost:8020` 打开本地控制台,你可以在此浏览会话记录、检查工具调用详情并管理策略。 + 在 `http://localhost:8020` 打开本地仪表盘,你可以在此浏览会话、检查工具调用并管理策略。 - - 像往常一样启动 Claude Code。如果 Agent 尝试执行危险操作,failproofai 会自动拦截。可以让它在无人值守的情况下运行,之后在控制台中查看执行情况。 + + 像往常一样启动 Claude Code。如果智能体尝试执行危险操作,failproofai 会自动拦截。让它在无人值守的情况下运行,然后在仪表盘中查看发生了什么。 --- -## 策略的工作原理 +## 策略工作原理 -每当 Agent 执行一个工具时,Claude Code 会将 failproofai 作为子进程调用: +每当智能体运行工具时,Claude Code 会将 failproofai 作为子进程调用: ```text Claude Code → failproofai --hook PreToolUse → reads stdin JSON @@ -84,21 +88,21 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON writes decision to stdout ``` -每条策略会返回以下三种决策之一: +每个策略返回以下三种决策之一: -- **allow** - Agent 正常继续执行 -- **deny** - 操作被拦截,Agent 会收到拦截原因说明 -- **instruct** - 向 Agent 的提示词中添加额外的上下文信息 +- **allow** - 智能体正常继续 +- **deny** - 操作被阻止,并告知智能体原因 +- **instruct** - 向智能体的提示词中添加额外上下文 -策略在你的本地进程中运行,不会向任何远程服务发送数据。 +策略在你的本地进程中运行,不会向远程服务发送任何数据。 --- -## 通过约定式策略建立团队规范 +## 使用约定式策略为团队建立规范 -在团队中快速统一质量标准的最佳方式是使用 `.failproofai/policies/` 约定。只需将策略文件放入该目录,它们便会自动加载 — 无需任何额外参数、配置修改或安装命令。 +在团队中快速建立质量标准的最佳方式是 `.failproofai/policies/` 约定。将策略文件放入该目录,它们会自动加载 —— 无需任何标志、配置变更或安装命令。 @@ -107,13 +111,13 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON ``` - 复制内置的示例文件,或自己编写: + 复制入门示例或自行编写: ```bash cp node_modules/failproofai/examples/convention-policies/*.mjs .failproofai/policies/ ``` - 或者创建一个新的策略文件: + 或者创建一个新的策略: ```js // .failproofai/policies/team-policies.mjs @@ -138,12 +142,12 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON git commit -m "Add team quality policies" ``` - 所有已安装 failproofai 的团队成员都会自动获取这些策略,无需每人单独配置。 + 所有已安装 failproofai 的团队成员都会自动获取这些策略,无需每位开发者单独配置。 -将 `.failproofai/policies/` 提交到代码仓库,让整个团队共享同一套标准。随着团队不断发现新的故障模式,持续添加策略并推送 — 所有人在下次 `git pull` 时便能自动获取更新。随着时间推移,这些策略将成为一套持续演进的活跃质量标准。 +将 `.failproofai/policies/` 提交到代码仓库,让整个团队共享相同的标准。随着团队发现新的故障模式,不断添加策略并推送 —— 所有人在下次 `git pull` 时即可获取更新。随着时间推移,这些策略将成为持续改进的活质量标准。 --- @@ -155,10 +159,10 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON | 路径 | 存储内容 | |------|----------------| | `~/.failproofai/policies-config.json` | 全局策略配置 | -| `~/.failproofai/hook-activity.jsonl` | Hook 执行历史记录 | -| `~/.failproofai/hook.log` | 自定义 hook 错误调试日志 | -| `.failproofai/policies-config.json` | 项目级配置(可提交至版本库) | -| `.failproofai/policies-config.local.json` | 个人本地覆盖配置(已加入 .gitignore) | +| `~/.failproofai/hook-activity.jsonl` | Hook 执行历史 | +| `~/.failproofai/hook.log` | 自定义 hook 错误的调试日志 | +| `.failproofai/policies-config.json` | 项目级配置(可提交) | +| `.failproofai/policies-config.local.json` | 个人覆盖配置(已加入 gitignore) | --- @@ -168,7 +172,7 @@ Claude Code → failproofai --hook PreToolUse → reads stdin JSON failproofai policies --uninstall ``` -从 `~/.claude/settings.json` 中移除 hook 条目。`~/.failproofai/` 中的配置文件将被保留。 +从 `~/.claude/settings.json` 中移除 hook 条目。`~/.failproofai/` 中的配置文件会被保留。 --- @@ -176,20 +180,20 @@ failproofai policies --uninstall - + 作用域与配置文件格式 - 全部 26 条策略及其参数说明 + 全部 26 条策略及其参数 使用 JavaScript 编写你自己的策略 - - 监控会话并查看策略活动记录 + + 监控会话并查看策略活动 \ No newline at end of file diff --git a/docs/zh/introduction.mdx b/docs/zh/introduction.mdx index b741ec58..f699da43 100644 --- a/docs/zh/introduction.mdx +++ b/docs/zh/introduction.mdx @@ -1,36 +1,36 @@ --- title: "Failproof AI" -description: "FailproofAI 为 AI 智能体提供 39 条内置故障策略,一次安装即可捕获循环、密钥泄露、破坏性工具调用等问题。" +description: "FailproofAI 为 AI 智能体提供 39 条内置故障策略,一次安装即可捕获循环、密钥泄漏、破坏性工具调用等问题。" --- [![npm weekly downloads](https://img.shields.io/npm/dw/failproofai?style=flat-square&color=2ea44f)](https://www.npmjs.com/package/failproofai) -专为 **AI 故障处理**、**错误恢复**和 **LLM 可靠性**设计的 Hooks 与策略系统。让你的 AI 智能体在 **Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Gemini CLI**、**Hermes** 以及 **Agents SDK** 上稳定运行、持续自主工作。 +专为 **AI 故障处理**、**错误恢复**和 **LLM 可靠性**设计的 Hooks 与策略。让您的 AI 智能体在 **Claude Code**、**OpenAI Codex**、**GitHub Copilot**、**Cursor Agent**、**OpenCode**、**Pi**、**Hermes**、**OpenClaw**、**Factory Droid**、**Devin CLI**、**Antigravity CLI** 以及 **Agents SDK** 上稳定运行、自主执行。 -AI 智能体的失败往往有迹可循:执行破坏性命令、泄露密钥、偏离任务、陷入死循环,或直接推送到主分支。一旦无人看管,小故障就会滚雪球般演变成服务中断、凭据泄露和数据丢失。 +AI 智能体的失败方式往往是可预见的:执行破坏性命令、泄露密钥、偏离任务、陷入循环,或直接推送到主分支。若无人监管,小问题会迅速演变为服务中断、凭据泄露和工作丢失。 -FailproofAI 通过**策略**来解决这些问题。这些规则挂载到每一次智能体工具调用中,负责**检测故障**、**采取应对措施**(阻止、指示、脱敏)并在需要人工介入时**及时告警**。本地仪表板让你事后可以回顾每一次工具调用、智能体故障及恢复操作的完整记录。 +FailproofAI 通过**策略**来解决这些问题。这些规则挂载到每一次智能体工具调用上,用于**检测故障**、**缓解故障**(阻断、指令纠正、内容清理),并在需要人工介入时**及时提醒您**。本地仪表盘让您可以事后审查每次工具调用、智能体故障及恢复操作的完整记录。 -所有数据均不离开你的本地机器。 +所有数据均不离开您的本地机器。 -## 快速开始 +## 快速上手 - 开箱即用:拦截破坏性命令、防止密钥泄露、将智能体限制在项目边界内,以及更多功能。 + 开箱即用。阻断破坏性命令、防止密钥泄漏、将智能体限制在项目边界内,以及更多防护能力。 - 使用 JavaScript 编写你自己的规则,配合简洁的 allow / deny / instruct API 轻松实现。 + 使用 JavaScript 编写您自己的规则,通过简洁的 allow / deny / instruct API 实现灵活控制。 - 查看智能体在你离开期间的所有操作。浏览会话记录、检查工具调用、回顾策略触发详情。 + 查看智能体在您离开期间的所有操作。浏览会话记录、检查工具调用详情、查看策略触发位置。 - - 无需编写代码即可调整任意策略。可按项目或全局设置允许列表、受保护分支或触发阈值。 + + 无需编写代码即可调整任意策略。按项目或全局设置允许列表、受保护分支或阈值参数。 @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -完整操作流程请参阅[入门指南](/zh/getting-started)。 \ No newline at end of file +完整流程请参阅[快速入门](/zh/getting-started)指南。 \ No newline at end of file From 4c67b9310d49ed6cfb0aaacf1fda3fdf1f06c215 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 02:42:40 +0000 Subject: [PATCH 6/8] fix(docs): restore AgentEye language navigation --- .github/workflows/translate-docs.yml | 26 +++++-- .../scripts/translate-docs/config.test.ts | 6 ++ .../translate-docs/mintlify-nav.test.ts | 7 ++ docs/docs.json | 4 +- scripts/translate-docs/config.ts | 70 +++++++++++++++---- scripts/translate-docs/mintlify-nav.ts | 7 +- scripts/translate-docs/types.ts | 3 + 7 files changed, 100 insertions(+), 23 deletions(-) diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 4da4e25f..7616fde2 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -4,19 +4,19 @@ on: push: branches: [main] paths: - - 'docs/*.mdx' - - 'docs/**/*.mdx' - - 'README.md' + - "docs/*.mdx" + - "docs/**/*.mdx" + - "README.md" workflow_dispatch: inputs: force: - description: 'Ignore cache and re-translate everything' + description: "Ignore cache and re-translate everything" type: boolean default: false languages: - description: 'Comma-separated language codes (leave empty for all)' + description: "Comma-separated language codes (leave empty for all)" type: string - default: '' + default: "" concurrency: group: translate-docs @@ -129,6 +129,20 @@ jobs: bun scripts/translate-docs/cli.ts --update-nav --languages zh,ja,ko,es,pt-br,de,fr,ru,hi,tr,vi,it,ar,he + - uses: actions/setup-node@v6 + with: + node-version: 22 + + - name: Install Mintlify CLI + run: npm install -g mintlify + + - name: Validate generated docs config + working-directory: docs + run: mintlify validate + + - name: Validate translated MDX pages + run: bun run validate:mdx + - name: Download cache fragments continue-on-error: true uses: actions/download-artifact@v8 diff --git a/__tests__/scripts/translate-docs/config.test.ts b/__tests__/scripts/translate-docs/config.test.ts index 6fbfbf35..cec14327 100644 --- a/__tests__/scripts/translate-docs/config.test.ts +++ b/__tests__/scripts/translate-docs/config.test.ts @@ -15,6 +15,12 @@ describe("LANGUAGES", () => { expect(LANGUAGES).toHaveLength(14); }); + it("uses Mintlify's canonical locale without changing the folder code", () => { + const portuguese = LANGUAGES.find((language) => language.code === "pt-br"); + + expect(portuguese?.mintlifyCode).toBe("pt-BR"); + }); + it("has unique codes", () => { const codes = LANGUAGES.map((l) => l.code); expect(new Set(codes).size).toBe(codes.length); diff --git a/__tests__/scripts/translate-docs/mintlify-nav.test.ts b/__tests__/scripts/translate-docs/mintlify-nav.test.ts index 025240ef..fbbea307 100644 --- a/__tests__/scripts/translate-docs/mintlify-nav.test.ts +++ b/__tests__/scripts/translate-docs/mintlify-nav.test.ts @@ -212,4 +212,11 @@ describe("localizeProductsNavigation", () => { "es/agenteye/overview", ]); }); + + it("uses Mintlify's canonical Portuguese locale with existing paths", () => { + const portuguese = buildLanguageNav(sampleEnglishTabs, "pt-br"); + + expect(portuguese.language).toBe("pt-BR"); + expect(portuguese.tabs[0].groups[0].pages[0]).toBe("pt-br/introduction"); + }); }); diff --git a/docs/docs.json b/docs/docs.json index 56e2c9da..07ba70d0 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -344,7 +344,7 @@ ] }, { - "language": "pt-br", + "language": "pt-BR", "tabs": [ { "tab": "Documentação", @@ -1275,7 +1275,7 @@ ] }, { - "language": "pt-br", + "language": "pt-BR", "tabs": [ { "tab": "Documentação", diff --git a/scripts/translate-docs/config.ts b/scripts/translate-docs/config.ts index 83819a92..fb15e0a8 100644 --- a/scripts/translate-docs/config.ts +++ b/scripts/translate-docs/config.ts @@ -2,22 +2,60 @@ import type { LanguageConfig } from "./types"; export const LANGUAGES: LanguageConfig[] = [ // Tier 1 — largest developer populations - { code: "zh", name: "Chinese (Simplified)", nativeName: "\u7b80\u4f53\u4e2d\u6587", tier: 1 }, + { + code: "zh", + name: "Chinese (Simplified)", + nativeName: "\u7b80\u4f53\u4e2d\u6587", + tier: 1, + }, { code: "ja", name: "Japanese", nativeName: "\u65e5\u672c\u8a9e", tier: 1 }, { code: "ko", name: "Korean", nativeName: "\ud55c\uad6d\uc5b4", tier: 1 }, { code: "es", name: "Spanish", nativeName: "Espa\u00f1ol", tier: 1 }, - { code: "pt-br", name: "Portuguese (Brazil)", nativeName: "Portugu\u00eas", tier: 1 }, + { + code: "pt-br", + mintlifyCode: "pt-BR", + name: "Portuguese (Brazil)", + nativeName: "Portugu\u00eas", + tier: 1, + }, { code: "de", name: "German", nativeName: "Deutsch", tier: 1 }, { code: "fr", name: "French", nativeName: "Fran\u00e7ais", tier: 1 }, // Tier 2 — strong tech communities - { code: "ru", name: "Russian", nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", tier: 2 }, - { code: "hi", name: "Hindi", nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940", tier: 2 }, + { + code: "ru", + name: "Russian", + nativeName: "\u0420\u0443\u0441\u0441\u043a\u0438\u0439", + tier: 2, + }, + { + code: "hi", + name: "Hindi", + nativeName: "\u0939\u093f\u0928\u094d\u0926\u0940", + tier: 2, + }, { code: "tr", name: "Turkish", nativeName: "T\u00fcrk\u00e7e", tier: 2 }, - { code: "vi", name: "Vietnamese", nativeName: "Ti\u1ebfng Vi\u1ec7t", tier: 2 }, + { + code: "vi", + name: "Vietnamese", + nativeName: "Ti\u1ebfng Vi\u1ec7t", + tier: 2, + }, { code: "it", name: "Italian", nativeName: "Italiano", tier: 2 }, // Tier 3 — RTL languages - { code: "ar", name: "Arabic", nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629", tier: 3, rtl: true }, - { code: "he", name: "Hebrew", nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea", tier: 3, rtl: true }, + { + code: "ar", + name: "Arabic", + nativeName: "\u0627\u0644\u0639\u0631\u0628\u064a\u0629", + tier: 3, + rtl: true, + }, + { + code: "he", + name: "Hebrew", + nativeName: "\u05e2\u05d1\u05e8\u05d9\u05ea", + tier: 3, + rtl: true, + }, ]; export function getLanguagesByTier(maxTier: number): LanguageConfig[] { @@ -184,17 +222,21 @@ export const NAV_TRANSLATIONS: Record< ru: { docs: "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f", examples: "\u041f\u0440\u0438\u043c\u0435\u0440\u044b", - gettingStarted: "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b", - coreConcepts: "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438", + gettingStarted: + "\u041d\u0430\u0447\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u044b", + coreConcepts: + "\u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043a\u043e\u043d\u0446\u0435\u043f\u0446\u0438\u0438", cli: "CLI", tools: "\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b", - advanced: "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439", + advanced: + "\u041f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0439", }, hi: { docs: "\u0926\u0938\u094d\u0924\u093e\u0935\u0947\u091c\u093c", examples: "\u0909\u0926\u093e\u0939\u0930\u0923", gettingStarted: "\u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902", - coreConcepts: "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901", + coreConcepts: + "\u092e\u0942\u0932 \u0905\u0935\u0927\u093e\u0930\u0923\u093e\u090f\u0901", cli: "CLI", tools: "\u0909\u092a\u0915\u0930\u0923", advanced: "\u0909\u0928\u094d\u0928\u0924", @@ -230,7 +272,8 @@ export const NAV_TRANSLATIONS: Record< docs: "\u0627\u0644\u0645\u0633\u062a\u0646\u062f\u0627\u062a", examples: "\u0623\u0645\u062b\u0644\u0629", gettingStarted: "\u0627\u0644\u0628\u062f\u0627\u064a\u0629", - coreConcepts: "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629", + coreConcepts: + "\u0627\u0644\u0645\u0641\u0627\u0647\u064a\u0645 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629", cli: "CLI", tools: "\u0627\u0644\u0623\u062f\u0648\u0627\u062a", advanced: "\u0645\u062a\u0642\u062f\u0645", @@ -238,7 +281,8 @@ export const NAV_TRANSLATIONS: Record< he: { docs: "\u05ea\u05d9\u05e2\u05d5\u05d3", examples: "\u05d3\u05d5\u05d2\u05de\u05d0\u05d5\u05ea", - gettingStarted: "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4", + gettingStarted: + "\u05ea\u05d7\u05d9\u05dc\u05ea \u05e2\u05d1\u05d5\u05d3\u05d4", coreConcepts: "\u05de\u05d5\u05e9\u05d2\u05d9 \u05d9\u05e1\u05d5\u05d3", cli: "CLI", tools: "\u05db\u05dc\u05d9\u05dd", diff --git a/scripts/translate-docs/mintlify-nav.ts b/scripts/translate-docs/mintlify-nav.ts index 854c4ff2..e003c6bf 100644 --- a/scripts/translate-docs/mintlify-nav.ts +++ b/scripts/translate-docs/mintlify-nav.ts @@ -1,7 +1,7 @@ import { readFileSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; -import { NAV_TRANSLATIONS, LANGUAGES } from "./config"; +import { getLanguageByCode, NAV_TRANSLATIONS, LANGUAGES } from "./config"; const __dirname = dirname(fileURLToPath(import.meta.url)); const DOCS_JSON_PATH = join(__dirname, "..", "..", "docs", "docs.json"); @@ -105,7 +105,10 @@ export function buildLanguageNav( })), })); - return { language: lang, tabs }; + return { + language: getLanguageByCode(lang)?.mintlifyCode ?? lang, + tabs, + }; } /** diff --git a/scripts/translate-docs/types.ts b/scripts/translate-docs/types.ts index b578a56a..22ea32f6 100644 --- a/scripts/translate-docs/types.ts +++ b/scripts/translate-docs/types.ts @@ -1,5 +1,8 @@ export interface LanguageConfig { + /** Internal code used for folders, cache keys, and translation routing. */ code: string; + /** Mintlify locale when its canonical casing differs from `code`. */ + mintlifyCode?: string; name: string; nativeName: string; tier: 1 | 2 | 3; From 32acf6edad42fb5d0a26053585e90d56787dacc4 Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 15 Jul 2026 02:50:30 +0000 Subject: [PATCH 7/8] fix(ci): make docs translation atomic --- .github/workflows/translate-docs.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 7616fde2..85bef4d0 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -67,7 +67,9 @@ jobs: restore-keys: bun-${{ runner.os }}- - name: Install dependencies - run: bun install --frozen-lockfile + # Translation only runs TypeScript tooling. Avoid the package prepare + # hook, which builds the full Next.js application once per language. + run: bun install --frozen-lockfile --ignore-scripts - name: Restore translation cache uses: actions/cache/restore@v6 @@ -100,7 +102,9 @@ jobs: consolidate: needs: [prepare, translate] - if: always() && needs.translate.result != 'cancelled' + # Never publish a partial translation set. A failed language produces no + # artifact and would otherwise leave that locale silently stale. + if: needs.translate.result == 'success' runs-on: ubuntu-latest permissions: contents: write @@ -114,10 +118,9 @@ jobs: bun-version: latest - name: Install dependencies - run: bun install --frozen-lockfile + run: bun install --frozen-lockfile --ignore-scripts - name: Download all translations - continue-on-error: true uses: actions/download-artifact@v8 with: pattern: translations-* @@ -144,7 +147,6 @@ jobs: run: bun run validate:mdx - name: Download cache fragments - continue-on-error: true uses: actions/download-artifact@v8 with: pattern: cache-* From 9cd4a087f0f82982c9cc4c904ebc37c06deb8e70 Mon Sep 17 00:00:00 2001 From: Nivedit Jain <40313233+NiveditJain@users.noreply.github.com> Date: Wed, 15 Jul 2026 08:01:17 +0000 Subject: [PATCH 8/8] fix(docs): address translation review findings --- .github/workflows/translate-docs.yml | 11 ++++++++--- CHANGELOG.md | 1 + docs/dashboard.mdx | 2 +- docs/fr/dashboard.mdx | 4 ++-- docs/hi/cli/audit.mdx | 4 ++-- docs/hi/dashboard.mdx | 4 ++-- docs/hi/introduction.mdx | 4 ++-- docs/introduction.mdx | 2 +- docs/it/dashboard.mdx | 4 ++-- docs/it/introduction.mdx | 4 ++-- docs/ja/cli/audit.mdx | 4 ++-- docs/ja/dashboard.mdx | 4 ++-- docs/ja/introduction.mdx | 4 ++-- docs/pt-br/introduction.mdx | 4 ++-- 14 files changed, 31 insertions(+), 25 deletions(-) diff --git a/.github/workflows/translate-docs.yml b/.github/workflows/translate-docs.yml index 85bef4d0..ff7c2fd8 100644 --- a/.github/workflows/translate-docs.yml +++ b/.github/workflows/translate-docs.yml @@ -89,7 +89,7 @@ jobs: docs/${{ matrix.lang }}/ docs/i18n/README.${{ matrix.lang }}.md retention-days: 1 - if-no-files-found: warn + if-no-files-found: error - name: Upload cache fragment uses: actions/upload-artifact@v7 @@ -97,7 +97,7 @@ jobs: name: cache-${{ matrix.lang }} path: scripts/translate-docs/.translation-cache.json retention-days: 1 - if-no-files-found: warn + if-no-files-found: error include-hidden-files: true consolidate: @@ -137,7 +137,7 @@ jobs: node-version: 22 - name: Install Mintlify CLI - run: npm install -g mintlify + run: npm install -g mintlify@4.2.680 - name: Validate generated docs config working-directory: docs @@ -243,6 +243,11 @@ jobs: git checkout -b "$BRANCH" fi + # Validate again after overlaying an existing translation branch so + # every file that will be committed is covered by both validators. + (cd docs && mintlify validate) + bun run validate:mdx + git add -A if git diff --cached --quiet; then echo "No new translation changes to push. Done." diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b43eb5e..f142953e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Surface OpenClaw sessions in the dashboard's audit + history browser: reads the real JSONL transcripts at `~/.openclaw/agents//sessions/.jsonl` (skipping the heavy `.trajectory.jsonl` OTel traces) via `lib/openclaw-sessions.ts` (a pure, unit-tested type-discriminated parser that pairs assistant `toolCall` blocks with their `toolResult` by `toolCallId`) and `lib/openclaw-projects.ts` (reads the `sessions.json` index, groups by agentId into `openclaw-` projects, parses channel metadata from the sessionKey). Wired through `src/audit/cli-adapters/openclaw.ts`, `lib/cli-registry.ts` (teal badge), `lib/projects.ts`, `lib/download-session.ts` (real-file download — no synthesis needed), and the `app/project/[name]` routes. (#489) ### Fixes +- Make documentation translation publishing atomic: require every locale and cache artifact, pin the Mintlify validator, validate the final overlaid PR tree, and emit the canonical `pt-BR` Mintlify locale while preserving `pt-br` paths. - Fix the Pi live `pi list` roundtrip e2e tests against pi-coding-agent ≥0.80: newer Pi no longer trusts project-local `.pi/settings.json` by default, so the tests now detect the installed Pi version and pass `pi list --approve` on ≥0.80 (older Pi trusts project settings without the flag and would reject it) to include the project-scope package failproofai's installer writes (previously `pi list` printed "No packages installed." — failing the install roundtrip and making the uninstall roundtrip pass vacuously). Gated behind `detectPiVersion()`, so it only runs where `pi` is installed. (#491) - Fix Antigravity file writes slipping past path/content policies. `ANTIGRAVITY_TOOL_MAP` had best-effort tool names; the real ones (verified against the `agy` binary + live transcripts) are `write_to_file` (not `write_file`), `list_dir` (not `list_directory`), and `find_by_name` (not `find_filepath`), and there was **no** input-key map for file tools — so `write_to_file`'s path (delivered as `TargetFile`) never became `file_path` and `block-env-files` / `block-secrets-write` silently allowed `.env` writes on Antigravity. Corrected the tool names and added `Write`/`Edit`/`Read` input maps (`TargetFile`→`file_path`, `CodeContent`→`content`). Verified live: `agy` now denies a `.env` write. (#508) - Keep informational allow-notes out of the agent-facing hook stdout on events with no additional-context channel (`Stop`, `SubagentStop`, `Session*`, `PreCompact`, …). Previously a *passing* `Stop` emitted its allow-reasons as `{reason}` on stdout, so agents like droid rendered a "…skipping commit check…skipping PR check…" wall on a perfectly fine turn. Those notes now go to stderr + the activity store only; stdout stays clean on channel-less events. (#508) diff --git a/docs/dashboard.mdx b/docs/dashboard.mdx index bfdee30d..43ea85f2 100644 --- a/docs/dashboard.mdx +++ b/docs/dashboard.mdx @@ -16,7 +16,7 @@ failproofai Opens at `http://localhost:8020`. -The dashboard reads directly from the filesystem - your Claude Code project folders and the failproofai config files. Nothing is written to a remote service. +The dashboard reads local project, session, and failproofai configuration data directly from the filesystem. Optional authenticated features, such as audit reminders and invitations, send the information needed for those requests (including email addresses) to remote APIs. --- diff --git a/docs/fr/dashboard.mdx b/docs/fr/dashboard.mdx index 1b463a02..4c13dca2 100644 --- a/docs/fr/dashboard.mdx +++ b/docs/fr/dashboard.mdx @@ -16,7 +16,7 @@ failproofai S'ouvre à l'adresse `http://localhost:8020`. -Le tableau de bord lit directement depuis le système de fichiers — vos dossiers de projets Claude Code et les fichiers de configuration failproofai. Rien n'est écrit vers un service distant. +Le tableau de bord lit les données locales des projets, des sessions et de la configuration failproofai directement depuis le système de fichiers. Les fonctionnalités authentifiées facultatives, telles que les rappels d'audit et les invitations, envoient aux API distantes les informations nécessaires à ces requêtes, notamment les adresses e-mail. --- @@ -146,4 +146,4 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev Ceci s'applique uniquement au mode développement. Lorsque vous exécutez `failproofai` (mode production), il n'y a pas de websocket HMR ni de problème de ressource de développement cross-origin. - \ No newline at end of file + diff --git a/docs/hi/cli/audit.mdx b/docs/hi/cli/audit.mdx index 1e2217bb..f5914a15 100644 --- a/docs/hi/cli/audit.mdx +++ b/docs/hi/cli/audit.mdx @@ -44,7 +44,7 @@ failproofai - उपयोग देखने के लिए `failproofai audit -h` (या `--help`) चलाएं। ऑडिट **पूरी तरह ऑफलाइन** चलता है — कोई खाता या नेटवर्क आवश्यक नहीं — और डैशबोर्ड तब तक सेवा देता रहता है जब तक आप इसे `Ctrl+C` से रोक न दें। + उपयोग देखने के लिए `failproofai audit -h` (या `--help`) चलाएं। मुख्य ऑडिट स्कैन और रिपोर्ट जनरेशन **पूरी तरह ऑफलाइन** चलते हैं — कोई खाता या नेटवर्क आवश्यक नहीं। वैकल्पिक प्रमाणित खाता सुविधाओं के लिए नेटवर्क की आवश्यकता होती है। डैशबोर्ड तब तक सेवा देता रहता है जब तक आप इसे `Ctrl+C` से रोक न दें। डैशबोर्ड इस मशीन पर पिछले एजेंट CLI ट्रांसक्रिप्ट्स को स्कैन करता है (Claude Code, Codex, Copilot, Cursor, OpenCode, Pi) और रिपोर्ट करता है कि एजेंट ने कितनी बार ऐसी चीजें कीं जिन्हें रोकने के लिए failproofai बनाया गया है — env-var चेक, force push, अनावश्यक `cd ` प्रिफिक्स, sleep-polling लूप, अभी-अभी edited फाइलें दोबारा पढ़ना, और अन्य। @@ -85,4 +85,4 @@ failproofai - **कोई mutation नहीं।** ऑडिट read-only mode में फिर से चलता है। `warn-repeated-tool-calls` को छोड़ दिया जाता है क्योंकि इसका per-session sidecar अन्यथा modify हो जाएगा। - **Workflow policies छोड़ दिए जाते हैं।** `require-*-before-stop` policies केवल `Stop` events और live git state के विरुद्ध `execSync` पर fire होती हैं — इनका meaningful "what would have happened in 2025" interpretation नहीं है, इसलिए वे audit counts में दिखाई नहीं देते हैं। -- **Custom policies छोड़ दिए जाते हैं।** User-supplied custom hooks को फिर से चलाया नहीं जाता (वे original session के बाद से बदल सकते हैं)। \ No newline at end of file +- **Custom policies छोड़ दिए जाते हैं।** User-supplied custom hooks को फिर से चलाया नहीं जाता (वे original session के बाद से बदल सकते हैं)। diff --git a/docs/hi/dashboard.mdx b/docs/hi/dashboard.mdx index 1297d046..41dac30c 100644 --- a/docs/hi/dashboard.mdx +++ b/docs/hi/dashboard.mdx @@ -16,7 +16,7 @@ failproofai `http://localhost:8020` पर खुलता है। -डैशबोर्ड फाइलसिस्टम से सीधे पढ़ता है - आपके Claude Code प्रोजेक्ट फोल्डर और failproofai कॉन्फ़िगरेशन फाइलें। किसी रिमोट सेवा में कुछ नहीं लिखा जाता है। +डैशबोर्ड स्थानीय प्रोजेक्ट, सेशन और failproofai कॉन्फ़िगरेशन डेटा को सीधे फाइलसिस्टम से पढ़ता है। ऑडिट रिमाइंडर और आमंत्रण जैसी वैकल्पिक प्रमाणित सुविधाएँ इन अनुरोधों के लिए आवश्यक जानकारी, जिसमें ईमेल पते शामिल हैं, रिमोट API को भेजती हैं। --- @@ -146,4 +146,4 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev यह केवल dev मोड पर लागू होता है। `failproofai` (उत्पादन मोड) चलाते समय, कोई HMR वेबसॉकेट नहीं है और कोई क्रॉस-ऑरिजिन dev संसाधन समस्या नहीं है। - \ No newline at end of file + diff --git a/docs/hi/introduction.mdx b/docs/hi/introduction.mdx index 3dc3ada1..b83299f0 100644 --- a/docs/hi/introduction.mdx +++ b/docs/hi/introduction.mdx @@ -12,7 +12,7 @@ AI एजेंट्स पूर्वानुमानित तरीको FailproofAI इसे **पॉलिसीज** से हल करता है। ये नियम प्रत्येक एजेंट टूल कॉल में हुक करते हैं ताकि **फेलियर्स को डिटेक्ट** करें, **उन्हें कम करें** (ब्लॉक, इंस्ट्रक्ट, सैनिटाइज), और **आपको अलर्ट** करें जब कुछ ध्यान देने की जरूरत हो। एक लोकल डैशबोर्ड आपको बाद में प्रत्येक टूल कॉल, एजेंट फेलियर और रिकवरी एक्शन की समीक्षा करने देता है। -कोई डेटा आपकी मशीन से बाहर नहीं जाता। +ट्रांसक्रिप्ट और पॉलिसी मूल्यांकन आपकी मशीन पर रहते हैं। डेटा केवल तब भेजा जाता है जब आप कोई ऑनलाइन सुविधा स्पष्ट रूप से उपयोग करते हैं, जैसे प्रमाणित ऑडिट रिमाइंडर या आमंत्रण। ## शुरुआत करें @@ -55,4 +55,4 @@ failproofai policies --install # enable policies (या स्किप क failproofai # डैशबोर्ड लॉन्च करें ``` -पूर्ण वॉकथ्रू के लिए [गेटिंग स्टार्टेड](/hi/getting-started) गाइड देखें। \ No newline at end of file +पूर्ण वॉकथ्रू के लिए [गेटिंग स्टार्टेड](/hi/getting-started) गाइड देखें। diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 71a591e4..d260daf5 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -11,7 +11,7 @@ AI agents fail in predictable ways. They run destructive commands, leak secrets, FailproofAI solves this with **policies**. These rules hook into every agent tool call to **detect failures**, **mitigate them** (block, instruct, sanitize), and **alert you** when something needs attention. A local dashboard lets you review every tool call, agent failure, and recovery action afterward. -No data leaves your machine. +Transcripts and policy evaluation stay on your machine. Data is sent only when you explicitly use an online feature, such as authenticated audit reminders or invitations. ## Get started diff --git a/docs/it/dashboard.mdx b/docs/it/dashboard.mdx index 7ee94550..8736ff77 100644 --- a/docs/it/dashboard.mdx +++ b/docs/it/dashboard.mdx @@ -16,7 +16,7 @@ failproofai Si apre su `http://localhost:8020`. -Il dashboard legge direttamente dal filesystem - le tue cartelle di progetti Claude Code e i file di configurazione failproofai. Nulla viene scritto su un servizio remoto. +Il dashboard legge i dati locali di progetti, sessioni e configurazione failproofai direttamente dal filesystem. Le funzionalità autenticate facoltative, come i promemoria di audit e gli inviti, inviano alle API remote le informazioni necessarie per tali richieste, inclusi gli indirizzi email. --- @@ -146,4 +146,4 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev Questo si applica solo alla modalità di sviluppo. Quando esegui `failproofai` (modalità di produzione), non c'è websocket HMR e nessun problema di risorsa di sviluppo cross-origin. - \ No newline at end of file + diff --git a/docs/it/introduction.mdx b/docs/it/introduction.mdx index 4ac02107..ea697485 100644 --- a/docs/it/introduction.mdx +++ b/docs/it/introduction.mdx @@ -11,7 +11,7 @@ Gli agenti AI falliscono in modi prevedibili. Eseguono comandi distruttivi, perd FailproofAI risolve questo con le **politiche**. Queste regole si intercettano in ogni chiamata di strumento dell'agente per **rilevare i fallimenti**, **mitigarli** (bloccare, istruire, pulire) e **avvisarti** quando qualcosa richiede attenzione. Un dashboard locale ti permette di esaminare ogni chiamata di strumento, fallimento dell'agente e azione di recupero in seguito. -Nessun dato lascia il tuo computer. +Le trascrizioni e la valutazione delle policy rimangono sul tuo computer. I dati vengono inviati solo quando utilizzi esplicitamente una funzionalità online, come promemoria di audit o inviti autenticati. ## Inizia subito @@ -54,4 +54,4 @@ failproofai policies --install # abilita le politiche (o salta — `failproofa failproofai # avvia il dashboard ``` -Vedi la guida [Inizia subito](/it/getting-started) per la procedura dettagliata completa. \ No newline at end of file +Vedi la guida [Inizia subito](/it/getting-started) per la procedura dettagliata completa. diff --git a/docs/ja/cli/audit.mdx b/docs/ja/cli/audit.mdx index 06d249d1..1f30cd28 100644 --- a/docs/ja/cli/audit.mdx +++ b/docs/ja/cli/audit.mdx @@ -44,7 +44,7 @@ failproofai - 使い方を確認するには `failproofai audit -h`(または `--help`)を実行してください。監査は**完全オフライン**で動作し、アカウントやネットワーク接続は不要です。`Ctrl+C` で停止するまでダッシュボードはサービスを継続します。 + 使い方を確認するには `failproofai audit -h`(または `--help`)を実行してください。中核となる監査スキャンとレポート生成は**完全オフライン**で動作し、アカウントやネットワーク接続は不要です。オプションの認証済みアカウント機能にはネットワーク接続が必要です。`Ctrl+C` で停止するまでダッシュボードはサービスを継続します。 ダッシュボードはこのマシン上の過去のエージェント CLI トランスクリプト(Claude Code、Codex、Copilot、Cursor、OpenCode、Pi)をスキャンし、failproofai が防止するように設計された操作の発生頻度を報告します。対象は環境変数チェック、フォースプッシュ、冗長な `cd ` プレフィックス、スリープポーリングループ、編集直後のファイル再読み込みなどです。 @@ -85,4 +85,4 @@ failproofai - **変更なし。** 監査は読み取り専用モードで再実行されます。`warn-repeated-tool-calls` はセッションごとのサイドカーが変更されてしまうためスキップされます。 - **ワークフローポリシーのスキップ。** `require-*-before-stop` ポリシーは `Stop` イベント時にのみ発火し、ライブの git 状態に対して `execSync` を実行します。「2025 年に何が起きたか」という文脈では意味のある解釈ができないため、監査カウントには含まれません。 -- **カスタムポリシーのスキップ。** ユーザーが定義したカスタムフックは再実行されません(元のセッション以降に変更された可能性があるため)。 \ No newline at end of file +- **カスタムポリシーのスキップ。** ユーザーが定義したカスタムフックは再実行されません(元のセッション以降に変更された可能性があるため)。 diff --git a/docs/ja/dashboard.mdx b/docs/ja/dashboard.mdx index e05c80fd..d2bbebf6 100644 --- a/docs/ja/dashboard.mdx +++ b/docs/ja/dashboard.mdx @@ -16,7 +16,7 @@ failproofai `http://localhost:8020` で開きます。 -ダッシュボードはファイルシステムから直接読み取ります — Claude Code のプロジェクトフォルダと failproofai の設定ファイルを参照します。リモートサービスへの書き込みは一切行われません。 +ダッシュボードはローカルのプロジェクト、セッション、failproofai 設定データをファイルシステムから直接読み取ります。監査リマインダーや招待などのオプションの認証済み機能は、そのリクエストに必要な情報(メールアドレスを含む)をリモート API に送信します。 --- @@ -146,4 +146,4 @@ FAILPROOFAI_ALLOWED_DEV_ORIGINS=dashboard.example.com npm run dev これは開発モードにのみ適用されます。`failproofai`(本番モード)を実行する場合、HMR WebSocket もクロスオリジン開発リソースの問題も発生しません。 - \ No newline at end of file + diff --git a/docs/ja/introduction.mdx b/docs/ja/introduction.mdx index e64e9beb..306e2b72 100644 --- a/docs/ja/introduction.mdx +++ b/docs/ja/introduction.mdx @@ -11,7 +11,7 @@ AI エージェントの障害は、予測可能なパターンで発生しま FailproofAI はこれを**ポリシー**で解決します。これらのルールはエージェントのすべてのツール呼び出しにフックし、**障害を検出**し、**軽減**(ブロック・指示・サニタイズ)し、対応が必要な場合に**アラートを通知**します。ローカルダッシュボードで、あとからすべてのツール呼び出し・エージェント障害・リカバリーアクションを確認できます。 -データはマシンの外に出ません。 +トランスクリプトとポリシー評価はマシン内に保持されます。認証済みの監査リマインダーや招待など、オンライン機能を明示的に使用した場合にのみデータが送信されます。 ## はじめに @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -詳細な手順については [Getting started](/ja/getting-started) ガイドをご覧ください。 \ No newline at end of file +詳細な手順については [Getting started](/ja/getting-started) ガイドをご覧ください。 diff --git a/docs/pt-br/introduction.mdx b/docs/pt-br/introduction.mdx index 911908e0..311dca85 100644 --- a/docs/pt-br/introduction.mdx +++ b/docs/pt-br/introduction.mdx @@ -11,7 +11,7 @@ Agentes de IA falham de maneiras previsíveis. Eles executam comandos destrutivo O FailproofAI resolve isso com **políticas**. Essas regras se integram a cada chamada de ferramenta do agente para **detectar falhas**, **mitigá-las** (bloquear, instruir, sanitizar) e **alertar você** quando algo precisa de atenção. Um painel local permite revisar todas as chamadas de ferramenta, falhas do agente e ações de recuperação posteriormente. -Nenhum dado sai da sua máquina. +As transcrições e a avaliação de políticas permanecem na sua máquina. Os dados só são enviados quando você usa explicitamente um recurso online, como lembretes de auditoria ou convites autenticados. ## Primeiros passos @@ -54,4 +54,4 @@ failproofai policies --install # enable policies (or skip — `failproofai` wi failproofai # launch the dashboard ``` -Consulte o guia de [Primeiros passos](/pt-br/getting-started) para o passo a passo completo. \ No newline at end of file +Consulte o guia de [Primeiros passos](/pt-br/getting-started) para o passo a passo completo.