diff --git a/AGENTS.md b/AGENTS.md index fb6d9bd..ae7a1c1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ **Generated:** 2025-01-20T00:00:00Z **Branch:** main -**Refresh:** reconciled against actual file tree and `plans/*`; verified scheduled event routing, config loader, handler symbols, manual `/zai update-agents` command, action.yml inputs, and test coverage. Fixed stale workflow filenames (replaced nonexistent `code-review.yml` with actual `zai-code-bot.yml`, `zai-agents-init-example.yml`). Confirmed: scheduled test coverage exists (`tests/handlers/scheduled.test.js`, `tests/scheduled-config.test.js`, `tests/repository-context.test.js`, `tests/agents-validation.test.js`); `docs/scheduled-tasks.md` present; README updated with scheduled-tasks section and `/zai update-agents` command. +**Refresh:** reconciled against actual file tree, source files, `plans/*`, and test coverage. Verified three event flows (PR auto-review, `/zai` commands, scheduled tasks), handler registry, config loader, agents-validation guardrail, action.yml inputs, workflow filenames, code-scope.js exports, and auth.js permissive policy. Fixed stale `calculateTokenBudget` reference (function does not exist in `code-scope.js`; actual exports are `extractWindow`, `extractTargetBlock`, `extractEnclosingBlock`). Confirmed workflow filenames (`zai-code-bot.yml`, `zai-agents-update.yml`, `zai-agents-init-example.yml`). ## OVERVIEW JavaScript GitHub Action with three event flows: (1) PR auto-review, (2) collaborator-gated `/zai` PR comment commands, and (3) cron-triggered scheduled tasks (`.zai-scheduled.yml`) that regenerate AGENTS.md files and open PRs. Runtime executes bundled `dist/index.js`; maintained logic lives in `src/index.js` plus modular services in `src/lib/*`. @@ -14,15 +14,16 @@ zai-code-bot/ ├── src/lib/ # Commands/auth/context/comments/api/services ├── src/lib/events.js # Event-type detection incl. `schedule` (cron) routing ├── src/lib/commands.js # `/zai` parser + allowlist (incl. `update-agents`) +├── src/lib/auth.js # Collaborator/fork authorization (currently permissive) ├── src/lib/auto-review.js # Large PR batching and synthesis ├── src/lib/changed-files.js # Paginated changed-files fetch (3000 file limit) ├── src/lib/pr-context.js # Shared PR context fetch (files, content at ref, refs) -├── src/lib/code-scope.js # Token-budget calculation for prompt sizing +├── src/lib/code-scope.js # Window/block extraction for prompt scoping ├── src/lib/context.js # Changed-file fetch + truncation/range helpers ├── src/lib/config/scheduled-config.js # Scheduled-task config loader (.zai-scheduled.yml) ├── src/lib/repository-context.js # Real repo context collection (tree + AGENTS.md discovery + key files) ├── src/lib/agents-validation.js # Hallucination guard: validates generated AGENTS.md vs real repo -├── src/lib/handlers/ # Command + scheduled handlers (ask/review/explain/describe/impact/help/scheduled) +├── src/lib/handlers/ # Command + scheduled handlers (see child AGENTS.md) ├── tests/ # Unit and integration coverage (Vitest v3) ├── dist/index.js # Generated ncc bundle executed by GitHub ├── dist/licenses.txt # Generated third-party licenses @@ -49,13 +50,13 @@ zai-code-bot/ | Route events and command execution | `src/index.js` | `run()`, pull_request path, issue_comment command path, schedule path | | Schedule event detection | `src/lib/events.js` | `getEventType` returns `schedule`; `shouldProcessEvent` always processes cron events | | Parse commands and enforce allowlist | `src/lib/commands.js` | `/zai` parser, command normalization, help fallback; `update-agents` in allowlist | -| Authorization and fork policy | `src/lib/auth.js` | Collaborator checks and fork-safe behavior | +| Authorization and fork policy | `src/lib/auth.js` | Collaborator checks and fork-safe behavior; currently permissive (authorizes any identifiable user) | | Comment/reaction behavior | `src/lib/comments.js` | Marker-based upsert, threaded reply (`replyToId`), reactions | | API retry/error handling | `src/lib/api.js`, `src/lib/logging.js` | Retry policy, categorized safe errors | | Large PR batching and synthesis | `src/lib/auto-review.js` | Batch creation, context limit handling, synthesis prompt | | Paginated changed-files fetch | `src/lib/changed-files.js` | Handles GitHub's 3000 file API limit | | Shared PR context fetch | `src/lib/pr-context.js` | `fetchPrFiles`, `fetchFileAtRef`, `resolvePrRefs`; user-safe fallbacks, size limits | -| Token budget calculation | `src/lib/code-scope.js` | Window extraction, enclosing block detection for prompt sizing | +| Code scope extraction | `src/lib/code-scope.js` | `extractWindow`, `extractTargetBlock`, `extractEnclosingBlock` for prompt scoping | | Scheduled-task config loading | `src/lib/config/scheduled-config.js` | `loadScheduledConfig`, `getTasksToRun`, `validateAndNormalizeConfig`, `validateAgentsConfig`, `getGistUrl`; scoping fields (`context_paths`/`target_paths`/`exclude_paths`/budgets) | | Scheduled-task execution | `src/lib/handlers/scheduled.js` | `handleScheduledEvent`, `handleUpdateAgentsTask` (grounded flow: context→prompt→validate→PR), `SCHEDULED_HANDLERS`; see child `src/lib/handlers/AGENTS.md` | | Repository context for AGENTS.md gen | `src/lib/repository-context.js` | `collectRepositoryContext` (git tree + existing AGENTS.md discovery + key files, budgeted), `renderRepositoryContext` | @@ -91,7 +92,9 @@ zai-code-bot/ | `fetchFileAtRef` | function | `src/lib/pr-context.js` | medium | File content at base/head ref, sliding-window scoping | | `resolvePrRefs` | function | `src/lib/pr-context.js` | low | Resolves base/head refs for diff context | | `MAX_PR_FILES_API_LIMIT` | constant | `src/lib/changed-files.js` | low | GitHub API ceiling (3000) | -| `calculateTokenBudget` | function | `src/lib/code-scope.js` | medium | Token/char budget sizing for prompts | +| `extractEnclosingBlock` | function | `src/lib/code-scope.js` | medium | Enclosing function/class block selection for prompt scoping | +| `extractWindow` | function | `src/lib/code-scope.js` | low | Target lines + surrounding window extraction | +| `extractTargetBlock` | function | `src/lib/code-scope.js` | low | Exact line range extraction | | `getEventType` | function | `src/lib/events.js` | low | Event-type detection for routing (incl. `schedule`) | | `shouldProcessEvent` | function | `src/lib/events.js` | low | Event filter; always-process gate for cron events | | `loadScheduledConfig` | function | `src/lib/config/scheduled-config.js` | low | Parses `.zai-scheduled.yml` task config | @@ -115,37 +118,52 @@ zai-code-bot/ ## CONVENTIONS - Edit maintained code in `src/`; do not hand-edit generated `dist/index.js`. - After source changes, run `npm run build` and commit `dist/index.js` + `dist/licenses.txt`. -- Use marker-based idempotent comments; preserve marker constants and update semantics. -- Command responses should stay threaded to the invoking comment via `replyToId`. -- Keep security posture strict: collaborator/fork checks before command execution, no secret leakage. +- Use marker-based idempotent comments; preserve marker constants (`COMMENT_MARKER`, `PROGRESS_MARKER`, `GUIDANCE_MARKER`, `AUTH_MARKER`) and update semantics. +- Command responses must stay threaded to the invoking comment (`replyToId`); never post top-level comments for command replies. +- Authorization (`enforceCommandAuthorization`) must precede all command handler execution; fork PRs follow silent-block policy for non-identifiable users. +- Keep prompts bounded via `src/lib/code-scope.js` and `src/lib/context.js` truncation helpers; never pass raw unbounded patches into Z.ai prompts. +- Return user-safe errors via `src/lib/logging.js`; never surface raw exception internals or secrets in PR comments. +- External I/O (Z.ai, GitHub API) goes through `src/lib/api.js` and `src/lib/pr-context.js`, not ad-hoc calls in handlers. +- Scheduled AGENTS.md generation must pass through `validateGeneratedAgentFiles` before any PR is created (hallucination guard). +- Reaction lifecycle: `eyes` (acknowledge) → `eyes` (working — `REACTIONS.THINKING` maps to `'eyes'`) → `rocket` (success) / `-1` (failure). -## ANTI-PATTERNS (THIS PROJECT) -- Bypassing authorization/fork checks for command handlers. -- Executing command logic for non-PR issue comments. -- Allowing unbounded context payloads into prompts. -- Asking an LLM to "scan the repo" without providing real repo context (causes hallucinated AGENTS.md — PR #15 bug). -- Committing AGENTS.md output that references files/languages not present in the repo. -- Editing `dist/` manually or shipping source changes without rebuilt artifacts. -- Confusing consumer-facing workflow examples (README snippet) with this repo's own `.github/workflows/` runtime logic. +## ANTI-PATTERNS +- Running handler logic before auth/fork checks. +- Hand-editing `dist/index.js` instead of `src/` then rebuilding. +- Returning raw exception details to PR comments. +- Unbounded diff/context payloads in prompts. +- Bypassing `validateGeneratedAgentFiles` for AGENTS.md updates. +- Introducing hidden coupling between unrelated service modules. +- Posting top-level comments instead of threaded replies for command responses. +- Deleting integration assertions to make behavior changes pass. -## UNIQUE STYLES -- Event-first architecture: `src/index.js` orchestrates; `src/lib/*` isolates concerns. -- Reactions communicate command lifecycle (`eyes`/`thinking`/`rocket`/`x`). -- Continuity is encoded with hidden markers in comments, not external storage. +## TESTING +- Framework: Vitest v3 (globals: `describe`/`test`/`expect`); configured via `vitest.config.js`. +- Run: `npm test` → `vitest run --coverage`. +- Coverage uploaded to Codecov. +- Unit tests: `tests/*.test.js` and `tests/handlers/*.test.js`. +- Integration tests: `tests/integration/*.test.js` (command pipeline + PR auto-review lifecycle). +- When changing comment markers or command UX, update integration assertions immediately. +- See `tests/AGENTS.md` for the full test map. -## COMMANDS -```bash -npm install -npm test # vitest run --coverage -npm run build # ncc build src/index.js -o dist --license licenses.txt -npm audit --audit-level=moderate # security audit gate (CI) -``` -After source changes: run `npm run build` and commit `dist/index.js` + `dist/licenses.txt` (CI fails on dist drift). +## KEY DOCS +| Document | Purpose | +|----------|---------| +| `ARCHITECTURE.md` | Layered architecture, dependency direction, life-of-request flows, invariant catalog | +| `CONTRIBUTING.md` | Contribution guide, build/release process, senior review checklists | +| `RUNBOOK.md` | Operational procedures, rollback steps, incident response | +| `SECURITY.md` | Authorization rules, fork policy, permission model | +| `docs/scheduled-tasks.md` | Scheduled-task configuration reference, cron syntax, troubleshooting | +| `README.md` | User-facing inputs, commands, quickstart, consumer workflow example | +| `src/lib/AGENTS.md` | Services-layer module guide | +| `src/lib/handlers/AGENTS.md` | Per-command handler guide | +| `tests/AGENTS.md` | Test strategy and suite layout | +| `tests/integration/AGENTS.md` | End-to-end pipeline test guide | -## NOTES -- CI (`.github/workflows/ci.yml`) enforces tests, build, dist drift, and security audit across Node 20 + 22. -- No linting/formatting configs (ESLint, Prettier) — rely on code review and CI gates. -- 7 command handlers + scheduled pipeline: `ask`, `review`, `explain`, `describe`, `impact`, `help`, plus `scheduled` (largest handler, drives cron tasks via `.zai-scheduled.yml`). -- Scheduled test coverage: `tests/handlers/scheduled.test.js`, `tests/scheduled-config.test.js`, `tests/repository-context.test.js`, `tests/agents-validation.test.js` (unit-level); end-to-end schedule integration test is still a gap. -- Scheduled-tasks configuration reference: `docs/scheduled-tasks.md`. -- Architecture and invariants catalog: `ARCHITECTURE.md`. +## GOTCHAS +- `dist/index.js` is the only artifact GitHub executes; CI `dist-drift` job fails on uncommitted `dist/` changes. +- GitHub's changed-files API caps at 3000 files (`MAX_PR_FILES_API_LIMIT`); coverage notes flag incomplete review beyond that ceiling. +- `REACTIONS.THINKING` maps to `'eyes'` (not a distinct emoji) — see `src/lib/comments.js`. +- Auth module (`src/lib/auth.js`) currently authorizes any identifiable user (permissive policy); fork non-identifiable users are silently blocked. +- `scheduled` handler is imported directly in `src/index.js`, not through the `/zai` HANDLERS map in `handlers/index.js`. +- The `handleUpdateAgentsTask` flow embeds a strict no-live-repo-access constraint in its prompt; the model receives only the collected context snapshot. diff --git a/src/lib/handlers/AGENTS.md b/src/lib/handlers/AGENTS.md index da2dbf9..d5c2340 100644 --- a/src/lib/handlers/AGENTS.md +++ b/src/lib/handlers/AGENTS.md @@ -12,9 +12,9 @@ Command handlers implement `/zai` behavior only after parsing + authorization; e | `/zai describe` | `src/lib/handlers/describe.js` | File/directory description | | `/zai impact` | `src/lib/handlers/impact.js` | Change impact analysis | | `/zai help` | `src/lib/handlers/help.js` | Static help output with auth gate | -| `/zai update-agents` | `src/index.js` (`dispatchCommand`) | Manual AGENTS.md regen; reuses `handleUpdateAgentsTask` | +| `/zai update-agents` | `src/index.js` (`dispatchCommand`) | Manual AGENTS.md regen; reuses `handleUpdateAgentsTask` from `scheduled.js` | | scheduled tasks | `src/lib/handlers/scheduled.js` | Largest module; cron-driven `.zai-scheduled.yml` tasks; grounded + validated AGENTS.md upgrades | -| Handler registry | `src/lib/handlers/index.js` | Dispatcher map consumed by runtime (note: `scheduled` is exported but not in the `/zai` HANDLERS map) | +| Handler registry | `src/lib/handlers/index.js` | Dispatcher map consumed by runtime (note: `scheduled` is exported but not in the `/zai` HANDLERS map; imported directly in `src/index.js`) | ## SCHEDULED MODULE (`scheduled.js`) KEY SYMBOLS - `handleScheduledEvent` (entry) → `executeScheduledTask` (per-task) → `buildExecutionContext` → `getScheduledHandler` (registry lookup). @@ -27,7 +27,7 @@ Command handlers implement `/zai` behavior only after parsing + authorization; e ## CONVENTIONS - Keep command argument parsing explicit and reject invalid formats early. - Always use threaded replies (`replyToId`) for command results. -- Reactions should reflect lifecycle: acknowledge -> work -> success/failure. +- Reactions should reflect lifecycle: acknowledge → work → success/failure. - Keep prompts bounded via context truncation helpers; never pass raw unbounded patches. - Return user-safe failures; log internal details through shared logging helpers. @@ -46,3 +46,4 @@ Command handlers implement `/zai` behavior only after parsing + authorization; e ## NOTES - Prefer adding helper functions within a handler module before introducing cross-handler coupling. - Keep marker constants stable once tests depend on them. +- `handleUpdateAgentsTask` is testable via the `__callZaiForTest` injection seam (see `tests/handlers/scheduled.test.js`); use this to mock Z.ai responses without network calls. diff --git a/tests/AGENTS.md b/tests/AGENTS.md index 4fb56f8..e25c5eb 100644 --- a/tests/AGENTS.md +++ b/tests/AGENTS.md @@ -8,8 +8,8 @@ Repository test coverage mixes module-focused tests in `tests/*.test.js` and sce tests/ ├── *.test.js # Module-level tests for lib/runtime units ├── handlers/ # Handler-focused test cases (ask, explain, impact, review, scheduled) -├── helpers/ # Shared mocks and fixtures utilities -├── lib/ # Shared test helpers + code-scope tests +├── helpers/ # Shared mocks and fixtures utilities (mocks.js) +├── lib/ # Code-scope tests (code-scope.test.js) ├── fixtures/ # Static test payloads (issue-comment-event.json, pr-event.json) └── integration/ # End-to-end command/review pipeline checks ``` @@ -22,11 +22,11 @@ tests/ | API and logging resilience | `tests/api.test.js`, `tests/logging.test.js` | Retry/error categorization | | Context, PR fetch, and batching | `tests/context.test.js`, `tests/pr-context.test.js`, `tests/changed-files.test.js`, `tests/auto-review.test.js` | Diff scoping, file-at-ref fetch, paginated/batched review | | Continuity and events | `tests/continuity.test.js`, `tests/events.test.js` | Hidden-marker state, event-type detection | -| Code scope and window extraction | `tests/lib/code-scope.test.js` | Token budget, enclosing block, window extraction | +| Code scope and window extraction | `tests/lib/code-scope.test.js` | Window extraction, enclosing block, target block | | Describe handler | `tests/describe.test.js` | PR description generation | -| Scheduled pipeline | `tests/handlers/scheduled.test.js`, `tests/scheduled-config.test.js`, `tests/repository-context.test.js`, `tests/agents-validation.test.js` | Config load + `validateAgentsConfig` scoping; `parseFileUpdatesFromResponse`; grounded `handleUpdateAgentsTask` flow incl. hallucination rejection; repo-context collection (tree/budgets/globs); validation guards incl. PR #15 regression | +| Scheduled pipeline | `tests/handlers/scheduled.test.js`, `tests/scheduled-config.test.js`, `tests/repository-context.test.js`, `tests/agents-validation.test.js` | Config load + `validateAgentsConfig` scoping; `parseFileUpdatesFromResponse`; grounded `handleUpdateAgentsTask` flow incl. hallucination rejection (via `__callZaiForTest` seam); repo-context collection (tree/budgets/globs); validation guards incl. PR #15 regression | | Scheduled pipeline (integration) | (pending) | End-to-end schedule event → context → Z.ai mock → validated PR is still a gap; unit coverage of the grounded flow exists via the `handleUpdateAgentsTask` seam (`__callZaiForTest`). | -| Full command pipeline | `tests/integration/command-pipeline.test.js` | Parse -> auth -> handler -> output contract | +| Full command pipeline | `tests/integration/command-pipeline.test.js` | Parse → auth → handler → output contract | | PR auto-review behavior | `tests/integration/pr-auto-review.test.js` | Marker upsert and PR event lifecycle | ## CONVENTIONS @@ -34,11 +34,12 @@ tests/ - Keep tests deterministic with explicit mock payloads and marker assertions. - Prefer scenario names that encode trigger + expected visible outcome. - When changing comment markers or command UX, update integration snapshots/assertions immediately. +- Shared mock utilities live in `tests/helpers/mocks.js`; reuse rather than duplicating inline. ## ANTI-PATTERNS - Deleting integration assertions to make behavior changes pass. - Asserting only internal calls without validating user-visible output. -- Duplicating large fixtures inline when reusable fixtures already exist. +- Duplicating large fixtures inline when reusable fixtures already exist in `tests/fixtures/`. ## NOTES - Test command: `npm test` → `vitest run --coverage`. diff --git a/tests/integration/AGENTS.md b/tests/integration/AGENTS.md index 3f8f542..9007a46 100644 --- a/tests/integration/AGENTS.md +++ b/tests/integration/AGENTS.md @@ -14,6 +14,7 @@ Integration tests verify end-to-end GitHub event pipelines and visible bot behav - Test the public behavior chain from event input to final comment/reaction outcome. - Cover both happy paths and safety gates (non-PR comments, unauthorized users, empty diffs). - Keep marker expectations explicit so idempotent update regressions are caught quickly. +- Shared event payloads in `tests/integration/fixtures/events.js` should be extended rather than duplicating inline JSON. ## ANTI-PATTERNS - Replacing integration assertions with unit-level mocks only.