Files
envsitter-guard/AGENTS.md
T
David Ibia 7c8e1251a3
CI / Test (Node 22) (push) Has been skipped
CI / Test (Node 26) (push) Has been skipped
CI / Test (Node 24) (push) Has been skipped
CI / E2E (OpenCode 1.18.31 + 2.0.32) (push) Has been skipped
CI / E2E (OpenCode 1.19.3 + 2.1.0) (push) Has been skipped
chore: depend on the published envsitter 0.1.0
Refresh package-lock.json so npm ci resolves envsitter 0.1.0 from the registry (integrity matches the published tarball), which fixes CI's ETARGET failure.
2026-10-21 00:10:18 +01:00

150 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — envsitter-guard
This repository is a minimal TypeScript plugin for OpenCode 1 (`@opencode-ai/plugin`, 1.18.29+) and OpenCode 2 (`@opencode/plugin`, 2.0.32+), served from one default export.
## Repo layout
- `index.ts`: package entry. Exports only `EnvSitterGuard` = `{ id, setup, server }` (also the default export).
- `lib/tools.ts`: the 15 `envsitter_*` tools, defined once (zod args, JSON Schema for V2, `run(input, env)`).
- `lib/policy.ts`: pure blocking logic (protected paths, patch paths, shell scan, grep redaction, permission denial).
- `lib/scrub.ts`: finds the project's sensitive env files and scrubs secret values from tool output with envsitter's redactor.
- `lib/v1.ts` / `lib/v2.ts`: thin adapters (V1 hooks object; V2 `ctx.tool.transform`/`hook`, `ctx.permission.hook`).
- `lib/help.ts`: `envsitter_help` text.
- `test/`: `*.hook.test.ts` (V1 hooks), `*.tools.test.ts` (tools via V1), `*.v2.test.ts` (V2 setup with a fake ctx), `policy.test.ts`, `scrub.test.ts`.
- `scripts/e2e-opencode.mjs`: `npm run test:e2e`, real OpenCode 1 (`opencode`) and 2 (`opencode2`) CLIs vs a scripted model, isolated `HOME`.
- `.github/workflows/`: `ci.yml` (unit tests + pinned OpenCode e2e), `e2e-latest.yml` (weekly e2e vs newest OpenCode), `release.yml` (tag `vX.Y.Z` -> CI -> npm trusted publishing -> GitHub Release). Keep the `release.yml` name: npm's trusted-publisher config pins it. `origin` is Gitea (`git.boxpositron.dev`), mirrored to GitHub; jobs carry `if: github.server_url == 'https://github.com'` so Gitea's runner skips them.
- `tsconfig.json`: strict, `noEmit` (typecheck). `tsconfig.build.json` emits `dist/` (publish); `tsconfig.test.json` emits `dist-test/`.
- `.opencode/`: OpenCode packaging/runtime wrapper.
- `.opencode/plugin/envsitter-guard.ts` re-exports the plugin from `index.ts` (the only tracked file here).
- `.opencode/package.json` and `.opencode/bun.lock` are local-only (ignored by `.opencode/.gitignore`).
- `node_modules/`: npm-installed deps (do not edit); `envsitter` comes from npm, not the sibling checkout.
## Commands (build / lint / test)
### Install
- Root install (lockfile: `package-lock.json`): `npm ci` (preferred) or `npm install`
- `.opencode/` install (local-only Bun lockfile, untracked):
- If you need to refresh `.opencode/node_modules`, use Bun from `.opencode/`:
- `cd .opencode && bun install`
- If Bun is unavailable, do not guess; ask before changing `.opencode/` dependency management.
### Build / typecheck
Day-to-day work only typechecks. `npm run build` (`tsconfig.build.json` -> `dist/`) produces the published package and runs on `prepack`; `prepublishOnly` runs typecheck, test, then build.
- Typecheck (canonical): `npm run typecheck` (= `npx tsc -p tsconfig.json`)
### Lint / format
- No linting or formatting commands are configured in the root project.
- No `.eslintrc*`, `eslint.config.*`, `biome.json`, or Prettier config exists at repo root.
- Do not introduce new linters/formatters unless explicitly requested.
### Tests
Tests use Node’s built-in test runner, compiled via `tsc` into `dist-test/`.
- Run all tests (builds then runs): `npm test`
- Build test output only: `npm run build:test`
- Cross-version e2e (needs the CLIs installed; not part of `npm test`): `npm run test:e2e`
- Run a single test file:
- `npm run build:test && node --test dist-test/test/envsitter-guard.v2.test.js`
- To test against an unreleased `envsitter`: `npm pack` in `../envsitter`, then `npm install --no-save <tarball>` here (CI always uses the published version from the lockfile).
Pre-commit checks are enforced via Husky:
- `npm install` installs the git hook.
- `.husky/pre-commit` runs `npm run typecheck` and `npm test`.
## TypeScript / module conventions
- ESM project: `package.json` has `"type": "module"`.
- TS config: `module: "NodeNext"`, `moduleResolution: "NodeNext"`, `target: "ES2022"`, `strict: true`, `noEmit: true`.
- Prefer `import type { ... }` for type-only imports (see `index.ts`).
- Prefer `node:` specifier for Node built-ins (e.g. `import path from "node:path"`).
## Formatting conventions (match existing code)
- Indentation: 4 spaces.
- Quotes: double quotes.
- Semicolons: required.
- Trailing commas: used in multiline objects/args.
- Keep functions small and single-purpose (see `lib/policy.ts`).
## Naming conventions
- `camelCase`: functions, locals, parameters.
- `PascalCase`: exported plugin symbol (`EnvSitterGuard`).
- Booleans use `is*` / `has*` prefixes (e.g. `isProtectedPath`).
## Error handling & validation
This plugin is security-sensitive. Follow these patterns:
- Prefer early validation + `throw new Error("...")` with a clear, user-facing message.
- Avoid swallowing errors (no empty `catch` blocks).
- Avoid `any` and type suppression (`as any`, `@ts-ignore`, `@ts-expect-error`).
- When parsing unknown inputs, narrow types explicitly (e.g. `typeof args === "object"`, then access via `Record<string, unknown>`).
## Security & secrets
- Do not read or print `.env` values.
- Treat `.env.secure` as sensitive; never commit secrets.
- The plugin blocks protected env files and the pepper, and points agents to EnvSitter tools (keys, fingerprints, booleans; never values).
## Change discipline
- Prefer minimal diffs; avoid refactors during bugfixes.
- Keep behavior consistent with `lib/` patterns:
- normalize paths before matching; decide "protected" only via envsitter's `isSensitiveEnvFile` / `isEnvSitterPepperFile`
- ensure file paths stay within the project root (V1 `worktree`, V2 `ctx.location.project.directory`)
- block silently: throw an actionable `Error`, never show a toast (hook test asserts zero toasts)
- Never add non-plugin exports to `index.ts`: OpenCode 1 throws when a plugin module exports anything else.
- Add or change a tool once in `lib/tools.ts`; both adapters pick it up. Update `lib/help.ts` with it.
## Plugin behavior notes
- Tool surface (15 tools; every file-taking tool resolves paths via `resolveEnvFilePath` in `lib/tools.ts`):
- Read-only: `envsitter_keys`, `envsitter_fingerprint`, `envsitter_match`, `envsitter_match_by_key`, `envsitter_scan`, `envsitter_validate`.
- Mutating, dry-run unless `write: true`: `envsitter_copy`, `envsitter_format`, `envsitter_reorder`, `envsitter_annotate`, `envsitter_add`, `envsitter_set`, `envsitter_unset`, `envsitter_delete`.
- `envsitter_help`: agent-facing guide; update its topic text whenever a tool changes.
- V2 registers them with `codemode: false` so agents call them by name.
- Blocking (`findBlockedAccess`, used by V1 `tool.execute.before` and V2 `execute.before`):
- Any non-`envsitter_*` tool whose `filePath` / `path` / `file_path` / `paths` args hit a protected file.
- `patchText` envelopes (`patch`, V1.19 `apply_patch`) and unified diffs touching protected files.
- `command` strings naming protected files (best-effort shell scan; envsitter CLI segments allowed).
- `grep` output is redacted after execution and every non-envsitter tool's output is scrubbed of secret values (`lib/scrub.ts`); V2 also denies protected `read`/`edit`/`shell` permission checks.
- Protected = envsitter `isSensitiveEnvFile` (examples/templates stay readable) or `isEnvSitterPepperFile`.
## Path handling rules
- Treat all incoming tool args as untrusted.
- Normalize path separators before matching (Windows `\\` → `/`).
- Validate allowed paths before resolving to absolute paths.
- Ensure resolved paths stay within the project root using `path.relative()` checks.
## Output conventions
- Prefer returning structured JSON via `JSON.stringify(obj, null, 2)`.
- Never include secret values in output strings, prompts, or toast messages.
- Errors should be user-facing and actionable (what was blocked + safe alternative).
## Dependency & change policy
- Keep this repo minimalist: prefer existing dependencies over adding new ones.
- Do not change `.opencode/` dependency management unless you know the OpenCode packaging constraints.
- Never edit vendored `node_modules/` or `.opencode/node_modules/`.
## Repo hygiene
- When searching the codebase, exclude `node_modules/` and `.opencode/node_modules/` unless you are explicitly auditing dependency behavior.
- Do not add new config files (ESLint/Prettier/Biome/etc.) unless explicitly requested.
## Verification checklist
- `npm run typecheck` and `npm test` pass (V1 hook/tool tests and V2 tests).
- No tool path allows reading raw `.env*` values.
- `.opencode/plugin/envsitter-guard.ts` remains a re-export only.
- Error messages remain clear and do not leak file contents.