From 4404fdf735978e287fa1fb7dd5501f1c1bc59cce Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 09:44:11 +0000 Subject: [PATCH 1/2] docs: update AGENTS.md from scheduled task --- AGENTS.md | 122 +++++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 56 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index fb6d9bd..0ed6e01 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 and source code. Verified: all `src/lib/` modules present in tree including `agents-validation.js`, `repository-context.js`; auth module (`src/lib/auth.js`) currently uses a permissive policy (authorizes any identifiable user); API client uses native `https` with progressive timeout and exponential backoff; scheduled pipeline validated against `handlers/scheduled.js` exports; comment markers defined in `src/index.js`; REACTIONS map verified in `src/lib/comments.js`. ## 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,6 +14,7 @@ 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 # Authorization (currently permissive: any identifiable user) ├── 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) @@ -48,18 +49,18 @@ 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 | -| 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 | +| Parse commands and enforce allowlist | `src/lib/commands.js` | `/zai` parser, `@zai-bot`/`@zai` prefix normalization, help fallback; `update-agents` in allowlist | +| Authorization and fork policy | `src/lib/auth.js` | Currently permissive: authorizes any identifiable user; `checkForkAuthorization` silently blocks only unidentified users on fork PRs | +| Comment/reaction behavior | `src/lib/comments.js` | Marker-based upsert, threaded reply (`replyToId`), reactions (`REACTIONS` map) | +| API retry/error handling | `src/lib/api.js`, `src/lib/logging.js` | `createApiClient` with progressive timeout, exponential backoff, fallback prompts; `callWithRetry` | +| Large PR batching and synthesis | `src/lib/auto-review.js` | `createReviewBatches`, batch creation, context limit handling, synthesis prompt | +| Paginated changed-files fetch | `src/lib/changed-files.js` | `fetchAllChangedFiles` returns `{ files, pageCount, limitReached }`; 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 | -| 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` | +| Token budget calculation | `src/lib/code-scope.js` | `extractWindow` (15-line default), `extractEnclosingBlock`, `extractTargetBlock` | +| Scheduled-task config loading | `src/lib/config/scheduled-config.js` | `loadScheduledConfig`, `getTasksToRun`, `validateAndNormalizeConfig`, `validateAgentsConfig`, `getGistUrl`; scoping fields | +| Scheduled-task execution | `src/lib/handlers/scheduled.js` | `handleScheduledEvent`, `handleUpdateAgentsTask` (grounded flow: context→prompt→validate→PR), `SCHEDULED_HANDLERS` | | Repository context for AGENTS.md gen | `src/lib/repository-context.js` | `collectRepositoryContext` (git tree + existing AGENTS.md discovery + key files, budgeted), `renderRepositoryContext` | -| AGENTS.md output validation | `src/lib/agents-validation.js` | `validateGeneratedAgentFiles` — rejects non-AGENTS paths, out-of-scope writes, and hallucinated content referencing non-existent files | +| AGENTS.md output validation | `src/lib/agents-validation.js` | `validateGeneratedAgentFiles` — rejects non-AGENTS paths, out-of-scope writes, and hallucinated content | | Manual `/zai update-agents` | `src/index.js` (`dispatchCommand`) | Reuses `handleUpdateAgentsTask` for ad-hoc AGENTS.md updates | | Command-specific behavior | `src/lib/handlers/AGENTS.md` | Local guide for each handler module | | Test strategy and fixtures | `tests/AGENTS.md` | Test map and suite conventions | @@ -79,19 +80,33 @@ zai-code-bot/ | `handlePullRequestReviewCommentEvent` | function | `src/index.js` | high | Inline review comment command flow | | `dispatchCommand` | function | `src/index.js` | high | Handler selection and response management | | `enforceCommandAuthorization` | function | `src/index.js` | medium | Auth gate before command dispatch | +| `callZaiApi` | function | `src/index.js` | medium | Direct Z.ai HTTP call (native `node:https`) for auto-review | +| `buildPrompt` | function | `src/index.js` | low | Auto-review prompt builder (non-batched) | +| `getReviewConfig` | function | `src/index.js` | low | Reads auto-review input thresholds from action inputs | +| `executeReviewBatch` | function | `src/index.js` | medium | Single-batch review with context-limit sub-splitting | +| `runLargePrReview` | function | `src/index.js` | medium | Batched review loop + synthesis | | `parseCommand` | function | `src/lib/commands.js` | high | Command extraction and validation | -| `checkForkAuthorization` | function | `src/lib/auth.js` | medium | Fork-aware security policy | -| `buildHandlerContext` | function | `src/lib/context.js` | medium | Shared context for handlers | +| `normalizeInput` | function | `src/lib/commands.js` | medium | `@zai-bot`/`@zai` → `/zai` prefix normalization | +| `checkForkAuthorization` | function | `src/lib/auth.js` | medium | Fork-aware authorization (currently permissive) | +| `getCommenter` | function | `src/lib/auth.js` | low | Extracts commenter from payload | | `upsertComment` | function | `src/lib/comments.js` | high | Marker idempotency + threaded reply support | -| `callWithRetry` | function | `src/lib/api.js` | medium | API retry/backoff wrapper | +| `REACTIONS` | constant | `src/lib/comments.js` | low | `EYES`/`THINKING`→`'eyes'`, `ROCKET`→`'rocket'`, `X`→`'-1'` | +| `createApiClient` | function | `src/lib/api.js` | medium | API client factory with timeout/retry/fallback config | +| `callWithRetry` | function | `src/lib/api.js` | medium | Exponential backoff + progressive timeout + fallback prompt | +| `categorizeError` | function | `src/lib/api.js` | low | Error classification: auth/validation/provider/rate-limit/timeout/internal | | `saveContinuityState` | function | `src/lib/continuity.js` | medium | Hidden state persistence across turns | | `createReviewBatches` | function | `src/lib/auto-review.js` | medium | Large PR file chunking | +| `buildSynthesisPrompt` | function | `src/lib/auto-review.js` | low | Final synthesis prompt for batched reviews | +| `isLargePr` | function | `src/lib/auto-review.js` | low | Threshold check for batched mode | +| `isContextLimitError` | function | `src/lib/auto-review.js` | low | Detects 413/context-length API errors | | `fetchAllChangedFiles` | function | `src/lib/changed-files.js` | medium | Paginated file list (3000 limit) | +| `MAX_PR_FILES_API_LIMIT` | constant | `src/lib/changed-files.js` | low | GitHub API ceiling (3000) | | `fetchPrFiles` | function | `src/lib/pr-context.js` | medium | PR file list with size limits + fallbacks | | `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 | +| `extractWindow` | function | `src/lib/code-scope.js` | medium | Target + surrounding window extraction (15-line default) | +| `extractEnclosingBlock` | function | `src/lib/code-scope.js` | medium | Nearest function/class block detection | +| `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 | @@ -99,53 +114,48 @@ zai-code-bot/ | `getTasksToRun` | function | `src/lib/config/scheduled-config.js` | low | Filters tasks whose schedule matches the event | | `getGistUrl` | function | `src/lib/config/scheduled-config.js` | low | Resolves gist URL priority: task > defaults > env | | `handleScheduledEvent` | function | `src/lib/handlers/scheduled.js` | medium | Scheduled pipeline entry: load config, run matching tasks | -| `executeScheduledTask` | function | `src/lib/handlers/scheduled.js` | medium | Per-task executor; builds context, dispatches via registry | | `handleUpdateAgentsTask` | function | `src/lib/handlers/scheduled.js` | medium | AGENTS.md regeneration: gist → collect repo context → grounded Z.ai prompt → validate → JSON diff → PR | -| `SCHEDULED_HANDLERS` | constant | `src/lib/handlers/scheduled.js` | low | Command→handler registry; `getScheduledHandler`/`registerScheduledHandler` extend it | -| `buildAgentsUpgradePrompt` | function | `src/lib/handlers/scheduled.js` | low | Grounded prompt: embeds real tree + existing AGENTS.md + key files; tells model it has NO live repo access | -| `parseFileUpdatesFromResponse` | function | `src/lib/handlers/scheduled.js` | low | Multi-format JSON extraction from Z.ai output | -| `callZaiApiWithRetry` | function | `src/lib/handlers/scheduled.js` | low | Z.ai HTTP client (native https) with retry for scheduled tasks | -| `fetchFromUrl` | function | `src/lib/handlers/scheduled.js` | low | HTTP GET for gist command text (30s timeout) | -| `createPR` | function | `src/lib/handlers/scheduled.js` | low | Branch + multi-file commit + PR open for scheduled changes | -| `collectRepositoryContext` | function | `src/lib/repository-context.js` | medium | git.getTree → existing AGENTS.md discovery + key-file contents, budgeted + glob-excluded | +| `SCHEDULED_HANDLERS` | constant | `src/lib/handlers/scheduled.js` | low | Command→handler registry | +| `collectRepositoryContext` | function | `src/lib/repository-context.js` | medium | git.getTree → existing AGENTS.md discovery + key-file contents, budgeted | | `renderRepositoryContext` | function | `src/lib/repository-context.js` | low | Renders collected context into a compact prompt block | -| `validateGeneratedAgentFiles` | function | `src/lib/agents-validation.js` | medium | Pre-PR guard: rejects non-AGENTS paths, out-of-scope/target writes, and hallucinated content | -| `validateAgentsConfig` | function | `src/lib/config/scheduled-config.js` | low | Validates scoping/budget config fields (`context_paths`, `target_paths`, etc.) | +| `validateGeneratedAgentFiles` | function | `src/lib/agents-validation.js` | medium | Pre-PR guard: rejects non-AGENTS paths, out-of-scope writes, hallucinated content | +| `validateFileEntry` | function | `src/lib/agents-validation.js` | low | Per-file validation with structured reasons | ## 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. +- 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. +- Reactions indicate lifecycle: `eyes` (acknowledge) → `eyes` (thinking) → `rocket` (success) / `-1` (failure). +- Authorization is currently permissive (any identifiable user is authorized); fork PRs from unidentified users are silently blocked. +- Keep prompts bounded via context truncation helpers; never pass raw unbounded patches. +- Return user-safe failure messages; log internal details through `src/lib/logging.js`. +- External I/O (Z.ai, GitHub) should flow through `src/lib/api.js` and `src/lib/pr-context.js`, not ad-hoc calls in handlers. +- `@zai-bot` and `@zai` prefixes are normalized to `/zai` before command parsing. -## 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. +- Returning raw exception details to PR comments. +- Unbounded diff/context payloads in prompts. +- Hand-editing `dist/index.js` instead of rebuilding from `src/`. +- Introducing cross-layer coupling (handlers calling Octokit directly instead of through shared context). +- Bypassing `validateGeneratedAgentFiles` before creating a PR from scheduled task output. -## 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. - -## 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). +## GOTCHAS +- `src/index.js` uses `require('node:https')` for its direct `callZaiApi`, while `src/lib/api.js` uses `require('https')` — both are native Node HTTPS modules but the import style differs. +- `REACTIONS.THINKING` maps to `'eyes'`, not a distinct reaction — GitHub does not support a "thinking" reaction type. +- The `dist/` drift CI gate will fail if `dist/index.js` is not rebuilt after `src/` changes. +- `MAX_PR_FILES_API_LIMIT` (3000) is GitHub's platform ceiling, not a configurable threshold. +- The auth module (`src/lib/auth.js`) contains legacy collaborator-check code (`AUTHORIZED_PERMISSIONS`, `AUTHORIZED_ASSOCIATIONS`) that is currently bypassed by an early `return { authorized: true }` in `checkAuthorization` — these constants are defined but unused in the active code path. -## 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`. +## KEY DOCS +- `ARCHITECTURE.md` — layered architecture, dependency direction, invariants, life-of-request flows +- `CONTRIBUTING.md` — development setup, PR process, review checklists, release steps +- `RUNBOOK.md` — operational procedures, rollback steps +- `SECURITY.md` — authorization rules and permission model +- `docs/scheduled-tasks.md` — scheduled-tasks configuration reference +- `README.md` — user-facing inputs, commands, quickstart +- `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 From f2d5d954e48e302529dcc553ea0c5c1d84be74b0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 9 Jul 2026 09:44:13 +0000 Subject: [PATCH 2/2] docs: update AGENTS.md from scheduled task --- tests/AGENTS.md | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/tests/AGENTS.md b/tests/AGENTS.md index 4fb56f8..bf00221 100644 --- a/tests/AGENTS.md +++ b/tests/AGENTS.md @@ -6,12 +6,26 @@ Repository test coverage mixes module-focused tests in `tests/*.test.js` and sce ## STRUCTURE ```text 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 -├── fixtures/ # Static test payloads (issue-comment-event.json, pr-event.json) -└── integration/ # End-to-end command/review pipeline checks +├── *.test.js # Module-level tests for lib/runtime units +├── handlers/ # Handler-focused test cases +│ ├── ask.test.js +│ ├── explain.test.js +│ ├── impact.test.js +│ ├── review.test.js +│ └── scheduled.test.js +├── helpers/ # Shared mocks and fixtures utilities +│ └── mocks.js +├── lib/ # Shared test helpers + 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 + ├── AGENTS.md + ├── command-pipeline.test.js + ├── pr-auto-review.test.js + └── fixtures/ + └── events.js ``` ## WHERE TO LOOK @@ -19,21 +33,22 @@ tests/ |------|----------|-------| | Parser/auth/comment unit behavior | `tests/commands.test.js`, `tests/auth.test.js`, `tests/comments.test.js` | Fast regression checks | | Runtime orchestration checks | `tests/action.test.js`, `tests/handlers.test.js`, `tests/index.test.js` | Entry flow and dispatch behavior | -| API and logging resilience | `tests/api.test.js`, `tests/logging.test.js` | Retry/error categorization | +| API and logging resilience | `tests/api.test.js`, `tests/logging.test.js` | Retry/error categorization, progressive timeout | | 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 | | 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 (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 | +| 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; validation guards incl. PR #15 regression | +| 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 -- Test framework: Vitest v3 (uses vitest globals: describe/test/expect); configured via `vitest.config.js`. +- Test framework: Vitest v3 (uses vitest globals: `describe`/`test`/`expect`); configured via `vitest.config.js`. - 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. +- Test command: `npm test` → `vitest run --coverage`. +- Coverage uploaded to Codecov. ## ANTI-PATTERNS - Deleting integration assertions to make behavior changes pass. @@ -41,6 +56,5 @@ tests/ - Duplicating large fixtures inline when reusable fixtures already exist. ## NOTES -- Test command: `npm test` → `vitest run --coverage`. -- Coverage uploaded to Codecov. - Integration tests are the safety net for command threading and marker idempotency. +- 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`).