Commit Graph
100 Commits
Author SHA1 Message Date
Vlad Mocanu 15ae31cd2f Merge pull request 'chore: merge 5 upstream commits from anthropics/claude-code-action' (#46) from chore/upstream-sync-20260305 into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/46
2026-03-05 12:35:16 +00:00
Vlad Mocanu 7f4c72d944 Merge pull request 'chore: merge 1 upstream commits from anthropics/claude-code-action' (#42) from chore/upstream-sync-20260302 into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/42
2026-03-03 20:55:21 +00:00
Vlad Mocanu 2f9e75cbf5 Merge pull request 'chore: merge 1 upstream commits from anthropics/claude-code-action' (#40) from chore/upstream-sync-20260228 into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/40
2026-02-28 07:13:16 +00:00
Vlad Mocanu 66654a1a19 docs: document Alpine/musl CLI install fallback 2026-02-28 09:11:41 +02:00
Vlad Mocanu b8cb56d204 fix: use npm install for Claude Code CLI on musl/Alpine systems
The native binary (install.sh) requires posix_getdents which is only
available in Alpine edge (musl 1.2.5-r21+), not in any stable Alpine
release. Detect musl upfront via ldd and skip straight to npm install,
avoiding 15+ seconds of wasted retries on deterministic failures.

On glibc systems the native install path is unchanged with npm as a
fallback if it fails.
2026-02-28 09:08:26 +02:00
Vlad MocanuandClaude Opus 4.6 f9c9754a16 docs: add Forgejo Support section to README with blog post link
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 18:06:23 +02:00
Vlad MocanuandClaude Opus 4.6 b4fa3bbd24 chore: bump kcl-ci to v1.40.2
Use generic email for mirror commits (noreply@forgejo-actions)
to avoid exposing internal domain on Codeberg.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:00:25 +02:00
Vlad MocanuandClaude Opus 4.6 90a9904e9f feat: mirror to Codeberg via SSH deploy key
Push clean copy (without .forgejo/ and prds/) to Codeberg on
each push to main. Uses SSH deploy key for authentication.

Also bumps kcl-ci to v1.40.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:52:39 +02:00
Vlad MocanuandClaude Opus 4.6 0e082695c9 chore: bump kcl-ci to v1.38.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:39:26 +02:00
Vlad MocanuandClaude Opus 4.6 f7e1e41b49 feat: add mirror branch workflow for Codeberg sync
Adds a mirror-branch workflow that copies main to a `codeberg` branch
excluding .forgejo/ and prds/ directories. Configure Forgejo push mirror
on this branch to sync a clean copy to Codeberg.

Also picks up updated allowed_tools from kcl-ci (adds bunx/npx patterns).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:36:34 +02:00
Vlad MocanuandClaude Opus 4.6 fba53fc8a0 chore: anonymize internal URLs for public release
Replace git.wxs.ro with forgejo.example.com in tests and docs.
Add public repo guidelines to CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:36:34 +02:00
Vlad MocanuandClaude Opus 4.6 b01c498dd9 docs: add Forgejo link and strikethrough GitHub-only quickstart note
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:36:34 +02:00
Vlad MocanuandClaude Opus 4.6 1dea90ac49 docs: update actor validation docs to reflect event-based guard
Self-trigger guard now only blocks comment/review events, not all
events. Updated CLAUDE.md, docs/forgejo.md API table, and known
limitations section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 14:03:39 +02:00
Vlad Mocanu 348db11fe6 Merge pull request 'chore: merge 1 upstream commits from anthropics/claude-code-action' (#37) from chore/upstream-sync-20260227 into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/37
2026-02-27 12:01:24 +00:00
Vlad MocanuandClaude Opus 4.6 c97c9765c3 fix: allow Forgejo bot actor on non-comment events
The self-trigger guard blocked the claude bot on all events. Loop risk
only exists for comment/review events (tag mode). PR, workflow_dispatch,
and schedule events are safe — refined the guard to only block on
issue_comment, issues, pull_request_review, and
pull_request_review_comment events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:57:59 +02:00
Vlad MocanuandClaude Opus 4.6 307af41a7f fix: allow test-action agent mode to run on claude bot PRs
The actor guard (github.actor != 'claude') was skipping test-agent-mode
on upstream-sync PRs. Refined the condition to only skip on non-PR events
(where tag mode loop risk exists) while allowing PR events through.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:52:28 +02:00
Vlad MocanuandClaude Opus 4.6 80082fbe8f fix: use label ID for Forgejo issue search and prevent duplicate labels
Forgejo's /issues?labels= filter requires integer IDs, not label names.
The workflow was searching by name (returning 0 results) then creating
a new issue every run.

Fix: look up label first, only create if missing, then use the ID for
both issue search and issue creation. This prevents both duplicate
issues and duplicate labels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:38:41 +02:00
Vlad MocanuandClaude Opus 4.6 841717842f fix: improve upstream-sync Claude prompt and permissions
- Add command execution rules to prompt (no env prefixes, no 2>&1)
- Document pre-existing test failures so Claude doesn't waste turns
- Add Bash(echo:*) and Bash(cat:*) to allowed_tools
- Delete stale remote branches before creating new ones

Addresses 24 permission denials in last run where Claude spent
~15 of 47 turns on blocked commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:34:19 +02:00
Vlad MocanuandClaude Opus 4.6 f3e800e254 fix: use integer label IDs for Forgejo issue creation
Forgejo's create-issue API expects `labels` as `[int64]` (label IDs),
not `[{"name": "..."}]` like GitHub. The previous format caused a JSON
unmarshal error, silently returning null instead of creating the issue.

Changes:
- Split label step to create-if-missing then look up the ID
- Pass label ID as integer to issue creation: `labels: [169]`
- Add error handling: log API response if issue creation returns null
- Also cleaned up another duplicate upstream-sync label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:21:52 +02:00
Vlad MocanuandClaude Opus 4.6 d1c8fd0946 chore: ignore root package.json/bun.lock in Renovate
These are managed by upstream — our fork syncs deps via the
upstream-sync workflow. Keep Renovate active for .forgejo/kcl-ci/
dependencies (kcl.mod git tags).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:19:17 +02:00
Vlad MocanuandClaude Opus 4.6 432243def1 fix: skip test-action for PRs created by claude bot
When Claude creates a PR (e.g. upstream-sync), the pull_request event
fires with actor=claude. The self-trigger guard in actor.ts blocks
this because actor 'claude' matches bot_name 'claude[bot]', causing
test-action to fail with "Blocking self-trigger" error.

Add `if: github.actor != 'claude'` to the test-agent-mode job.
Claude-created PRs (upstream syncs) don't need the integration test
since they're merge commits, not action code changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:17:19 +02:00
Vlad MocanuandClaude Opus 4.6 b1524d7857 fix: handle existing sync PRs in upstream-sync workflow
Add idempotency to the merge-upstream job:

1. Check for existing open PR from chore/upstream-sync-* branch
2. If PR exists and branch is up to date with upstream → skip
3. If PR exists but upstream has new commits → checkout existing
   branch, merge new upstream commits, run Claude to review/test
4. If no PR exists → create new branch (existing behavior)

Also update Claude's prompt to handle both create and update PR
cases, so it knows to push to the existing PR branch instead of
creating a duplicate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:15:50 +02:00
Vlad MocanuandClaude Opus 4.6 88e7747d2f fix: use bot token for issue creation and link PRs to tracking issues
Three fixes in the upstream-sync workflow:

1. Replace github.token with CLAUDE_BOT_TOKEN in the check-upstream
   job. The default runner token on Forgejo doesn't have issue-write
   permissions, so issues were silently failing to create.

2. Output the tracking issue number from check-upstream and pass it
   to the merge-upstream job. Claude's prompt now includes the issue
   reference and instructs it to add "Closes #N" in the PR body.

3. Capture the issue number from both create and update paths so
   the merge job always has it available.

Also cleaned up 6 duplicate upstream-sync labels created by previous
runs that used the unprivileged token.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:12:35 +02:00
Vlad MocanuandClaude Opus 4.6 bc063f62f0 fix: add bun install step and bunx/npx tool patterns to upstream-sync
Two fixes for the upstream-sync Claude workflow:

1. Add Bun install + bun install (deps) steps before Claude runs,
   so tsc, prettier, and other devDependencies are available.
   Previously node_modules/.bin/ didn't exist and typecheck/format
   commands failed with "command not found".

2. Add Bash(bunx:*), Bash(npx:*), Bash(./node_modules/.bin/*:*)
   to allowed_tools. The existing Bash(bun:*) only covers the `bun`
   binary, not `bunx` which is a separate binary.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:07:37 +02:00
Vlad MocanuandClaude Opus 4.6 073ef1e934 docs: document Bash sub-patterns and agent mode allowed_tools fix
- CLAUDE.md: add "Things That Will Bite You" entry about bare Bash
  requiring interactive approval and needing sub-patterns in CI
- docs/forgejo.md: update allowed_tools section with sub-pattern
  examples, agent mode fix note, and common patterns reference

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:59:38 +02:00
Vlad MocanuandClaude Opus 4.6 2978878d82 fix: pass allowed_tools to SDK in agent mode
Agent mode never passed ALLOWED_TOOLS_INPUT to the Claude SDK —
only tag mode did (via --allowedTools in claudeArgs). This meant
the allowed_tools action input was silently ignored in agent mode,
causing all Bash commands to require interactive approval in CI.

Pass ALLOWED_TOOLS_INPUT directly as options.allowedTools, which
the SDK merges with any tools from claudeArgs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:58:09 +02:00
Vlad MocanuandClaude Opus 4.6 ed536bb8a3 feat: add human-readable CI log output for show_full_output mode
Replace raw JSON dumps with concise, scannable log lines when
show_full_output is enabled. Adds an onMessage callback to the SDK
runner that formats each message type into 1-2 line summaries with
emoji prefixes, tool-specific parameter display, result correlation
for parallel tool calls, and subagent progress tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:50:49 +02:00
Vlad MocanuandClaude Opus 4.6 ec1a718b2e chore: bump kcl-ci to v1.37.1 (Bash sub-patterns for claude.yml)
Picks up the allowed_tools fix from kcl-ci — claude.yml tag-mode
workflow now uses Bash(git:*),Bash(bun:*),Bash(curl:*) sub-patterns
instead of bare Bash, enabling auto-approval in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:49:01 +02:00
Vlad MocanuandClaude Opus 4.6 b308697d5e fix: use Bash sub-patterns in upstream-sync for CI auto-approval
Bare `Bash` in allowed_tools makes the tool available but individual
commands still require interactive approval. In CI there's nobody to
approve, so git push, bun test, and curl all fail with
"Error: This command requires approval".

Changes:
- Switch to Bash(git:*), Bash(bun:*), Bash(curl:*) sub-patterns
- Add GITHUB_SERVER_URL env var so Claude doesn't need `export`
- Update prompt to reflect env var is pre-set

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:48:21 +02:00
Vlad MocanuandClaude Opus 4.6 ec92cf4c28 fix: enable verbose output and full tool access for Claude workflows
- Add show_full_output: true to both claude.yml and upstream-sync.yml
- Add allowed_tools (Bash, Read, Write, etc.) to upstream-sync merge step
- Upgrade kcl-ci to v1.37.0 (defaults show_full_output and full tools)

Fixes: Claude was burning 38 turns hitting sandbox permission denials
trying to run bun test and git push during upstream sync.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 12:25:13 +02:00
Vlad MocanuandClaude Opus 4.6 c47fc002c6 fix: simplify kcl-ci-build and exclude generated workflows from Prettier
Remove wait-for-checks from kcl-ci-build (not needed for this repo).
Add .forgejo/workflows/ to .prettierignore since KCL controls formatting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:59:42 +02:00
Vlad MocanuandClaude Opus 4.6 4954e96cc5 feat: add Claude auto-merge to upstream-sync workflow
- New merge-upstream job: creates branch, merges upstream, runs Claude
  agent mode to review, resolve conflicts, run tests, and create a PR
- Dynamic fork impact analysis: computes overlap between fork-modified
  files and upstream-changed files to assess conflict risk
- Claude reviews ALL upstream changes for fork compatibility (renamed
  imports, changed APIs, GitHub-only assumptions) not just conflicts
- Maintainability principle: minimize fork divergence, prefer adapters
- Remove ANTHROPIC_API_KEY (using OAuth token only)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:55:51 +02:00
Vlad MocanuandClaude Opus 4.6 5c014823e0 feat: migrate workflows to kcl-ci standard
- Add .forgejo/kcl-ci/ with kcl.mod, main.k, Taskfile.yaml
- claude.yml: use claude.k module (fixes #comment YAML validation error,
  removes duplicate pull_request_comment trigger)
- ci.yml: add paths-ignore for kcl-ci paths, named jobs for check constants
- test-action.yml: regenerated from KCL (functionally identical)
- upstream-sync.yml: regenerated from KCL (functionally identical)
- kcl-ci-build.yml: new auto-regeneration workflow (waits for CI checks)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:40:47 +02:00
Vlad MocanuandClaude Opus 4.6 8125818e24 chore: ignore upstream paths in Renovate config
Ignore .github/, base-action/, and node_modules/ — these are
upstream-owned and managed via upstream-sync, not Renovate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:28:33 +02:00
Vlad Mocanu 4c69c3b8b4 Merge pull request 'Configure Renovate' (#25) from renovate/configure into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/25
2026-02-27 09:25:51 +00:00
Vlad MocanuandClaude Opus 4.6 df7afc08d4 fix: wire allowed_tools/disallowed_tools inputs through to Claude SDK
The disallowed tools env var read in run.ts was DISALLOWED_TOOLS_INPUT
(raw user input) instead of DISALLOWED_TOOLS (computed value including
WebSearch/WebFetch defaults). This meant default tool disallowance was
never enforced. Also removes orphaned ALLOWED_TOOLS env var export from
createPrompt() (tag mode passes allowed tools via claudeArgs instead),
extracts shared parseToolsInput utility to eliminate duplication, and
adds tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 11:16:38 +02:00
Vlad MocanuandClaude Opus 4.6 29a1032aa6 fix: normalize Forgejo PR/issue state to uppercase
Forgejo REST API returns state as lowercase ("closed"/"open") but
branch.ts compares against GraphQL-style uppercase ("CLOSED"/"MERGED").
This caused @claude on closed/merged PRs to take the open-PR checkout
path, failing with "fatal: invalid reference: refs/pull/N/head".

Normalize state to uppercase in the Forgejo data fetcher, matching the
existing pattern used for review state (line 153).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:19:53 +02:00
Vlad MocanuandClaude Opus 4.6 2e1165ed90 fix: handle Forgejo pull_request_comment payload missing pull_request field
Forgejo's pull_request_comment event uses an issue_comment-like payload
with issue.number instead of pull_request.number. Add fallback to
extract entity number from issue field when pull_request is absent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:31:40 +02:00
Vlad Mocanu 01c9c503c3 Merge pull request 'fix(prd-7): Senior developer review of Forgejo platform support' (#24) from feature/prd-7-senior-review-forgejo into main 2026-02-26 11:20:38 +00:00
Vlad MocanuandClaude Opus 4.6 87a323593d chore(prd-7): archive completed PRD to prds/done/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:19:19 +02:00
Vlad MocanuandClaude Opus 4.6 58677b91f4 fix(prd-7): M6 documentation accuracy review — 10 corrections across docs/forgejo.md and CLAUDE.md
- Fix actor validation: "skipped entirely" → "bot-type check skipped; self-trigger guard active"
- Fix permission check: document getCollaboratorPermissionLevel() primary with repos.get() fallback
- Add platform detection cross-validation security note (rejects Forgejo override on github.com)
- Fix update-with-branch.ts description: "PR compare URL" → "branch link" (URL is in update-comment-link.ts)
- Add missing update-comment-link.ts to key integration points in CLAUDE.md
- Fix test-action.yml description to match actual validation checks
- Nuance troubleshooting guidance for # in workflow if: expressions
- Verify all Known Limitations still accurate

Progress: 100% complete — all 6 milestones done

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:18:34 +02:00
Vlad MocanuandClaude Opus 4.6 741f12afaf fix(prd-7): M5 code quality review — remove dead re-exports, verify type safety
- Removed unused re-exports (CommentUpdateInput, ExecutionDetails,
  ensureProperlyEncodedUrl) from forgejo/comment-logic.ts
- Verified no `any` type escapes in Forgejo-specific code
- Confirmed naming conventions consistent with upstream
- No dead code, unused imports, or unreachable branches
- All complex decisions documented with comments
- Typecheck, format, and 834 tests pass clean

Progress: 83% complete — M6 (documentation accuracy) remaining

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:57:25 +02:00
Vlad MocanuandClaude Opus 4.6 bbfd630fc5 fix(prd-7): M4 test coverage review — 28 new tests for comment operations and branch setup
- test/create-initial-comment.test.ts: 15 tests covering GitHub/Forgejo
  platform branches, sticky comment matching, review comment fallback,
  error handling with GITHUB_OUTPUT verification
- test/update-tracking-comment.test.ts: 11 tests covering body construction,
  branch link logic (issue vs PR), comment type routing, Forgejo URLs
- test/setup-branch-forgejo.test.ts: 2 tests verifying Forgejo uses
  repos.getBranch() while GitHub uses git.getRef() for source branch SHA
- test/COVERAGE-NOTES.md: documents all coverage status and accepted gaps
  (tag mode orchestrator, entrypoint) with rationale
- Notable finding: CLAUDE_APP_BOT_ID discrepancy flagged for M5

Progress: 67% complete (4/6 milestones) — M5 code quality next

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:51:08 +02:00
Vlad MocanuandClaude Opus 4.6 6b0302d226 fix(prd-7): M3 security review — self-trigger guard, actor permissions, trigger bypass, platform validation
- Add self-mention/bot loop prevention in actor.ts (blocks actor matching bot_name)
- Switch Forgejo permission check to actor-level via getCollaboratorPermissionLevel
  with fallback to token-level repos.get() when collaborator API returns 403
- Close empty-body PR review comment trigger bypass (now returns false instead of true)
- Add platform detection cross-validation (reject PLATFORM=forgejo on github.com)
- Document URL builder defense-in-depth rationale in comment-logic.ts
- Update/add tests across 6 test files (actor, permissions, trigger, platform, mcp, m7)

Progress: 50% complete (3/6 milestones) — next: M4 test coverage review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:31:12 +02:00
Vlad MocanuandClaude Opus 4.6 cefc229199 fix(prd-7): M2 error handling review — fix process.exit bypasses, TOCTOU gap, URL consistency
- F1: Replace process.exit(1) with throw in branch.ts (cleanup was bypassed)
- F2: Replace process.exit(1) with throw in install-mcp-server.ts (same issue)
- F2b: Replace process.exit(1) with throw in create-prompt/index.ts (same issue)
- F3: Use getServerUrl() instead of GITHUB_SERVER_URL constant in branch-cleanup.ts
- F4: Use updated_at for review TOCTOU filtering in Forgejo data fetcher
- Accepted notes: no pagination >100, no retry, unconditional trigger, image no-op

Progress: 33% complete — M2 done, M3 (security review) next

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:16:22 +02:00
Vlad MocanuandClaude Opus 4.6 ac58fb6c14 fix(prd-7): M1 architecture review — consolidate duplication, fix bugs, memoize detection
- F1: Consolidated updateForgejoCommentBody into unified updateCommentBody (~150 lines removed)
- F2: Fixed wrong run identifier in update-with-branch.ts (context.runId → getForgejoRunIndex())
- F3: Memoized detectPlatform() with _resetPlatformCache() for tests
- F4: Added getServerUrl() runtime helper to resolve constant-vs-function inconsistency
- F5: Fixed sticky comment bot matching on Forgejo via context.inputs.botName
- F6: Documented GHES heuristic misidentification in docs/forgejo.md
- Updated PRD M1 checkbox to complete

Progress: 17% complete — M1 done, M2 (error handling review) next

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:09:02 +02:00
Vlad Mocanu ae326659b1 Merge remote-tracking branch 'upstream/main' 2026-02-26 11:36:32 +02:00
Vlad Mocanu eee75baa45 Merge pull request 'feat(prd-6): E2E test and fix all untested Forgejo trigger scenarios' (#15) from feature/prd-6-m2-test-pr-review-comment into main 2026-02-26 09:33:15 +00:00
Vlad MocanuandClaude Opus 4.6 57353f9eb9 docs(prd-6): archive completed PRD to prds/done/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:53 +02:00
Vlad MocanuandClaude Opus 4.6 4a30b9819e docs(prd-6): mark M7 complete — documentation updated with full E2E results
- Updated docs/forgejo.md E2E table with all 5 validated trigger scenarios
- Added "Webhook & Event Differences" section (12-row comparison table)
- Added 4 new Known Limitations and 5 new Troubleshooting entries
- Removed "Not Yet E2E Tested" section — all triggers validated
- PRD #6 is 100% complete (all 7 milestones done)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:53 +02:00
Vlad MocanuandClaude Opus 4.6 ccac5aff1e docs(prd-6): mark M6 complete — tag mode with code changes validated
- Branch creation, commit push, bot attribution all verified (run #198)
- 1 bug found: prompt template used quick_pull=1 instead of expand=1
- Fix committed in f08b1b4, validates after merge to main

Progress: 87% complete — M7 (docs update) remaining

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:53 +02:00
Vlad MocanuandClaude Opus 4.6 2acaece6ae fix: use expand=1 instead of quick_pull=1 in PR URL on Forgejo
The prompt template hardcoded quick_pull=1 (GitHub-specific) in the
"Create a PR" URL. On Forgejo, this parameter is ignored so the
compare page doesn't auto-expand the PR creation form. Forgejo uses
expand=1 for this purpose.

Since Claude writes the PR URL into the comment body, and
updateForgejoCommentBody() extracts it (prLinkFromContent) with
priority over the URL generated by update-comment-link.ts, the
prompt template is the correct place to fix this.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:53 +02:00
Vlad MocanuandClaude Opus 4.6 f83eed97de docs: document Forgejo event behavior in workflow and trigger.ts
Add inline comments explaining:
- Forgejo never fires pull_request_review (sends pull_request_comment)
- Why workflow if-condition cannot gate on @claude for these events
  (payload fields are empty, confirmed by run 12084 being skipped)
- The @claude check is handled in trigger.ts via payload inspection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:36 +02:00
Vlad MocanuandClaude Opus 4.6 a033ec873e revert: undo workflow if-condition gating for pull_request_comment
Forgejo's pull_request_comment payload does not populate
github.event.comment.body or github.event.review.body in a way
the workflow contains() expression can read, causing legitimate
@claude reviews to be skipped (run 12084).

Revert to unconditional pass at the workflow level. The @claude
check is handled properly in trigger.ts which inspects the actual
payload fields with fallback logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:36 +02:00
Vlad MocanuandClaude Opus 4.6 42f6508d49 fix: gate Forgejo review/comment triggers on @claude mention
Previously, all pull_request_comment events on Forgejo triggered the
full Claude pipeline unconditionally — both in the workflow if-condition
and in trigger.ts. This wasted CI resources and API credits on reviews
without @claude mentions (e.g. plain "LGTM" reviews).

Workflow: add @claude check via contains() on comment.body and review.body.
Trigger validation: replace blind auto-trigger with payload-aware check
that inspects available body fields, falling back only when no body exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:32:36 +02:00
Vlad MocanuandClaude Opus 4.6 8754cc0181 docs(prd-6): mark M5 complete — assignee trigger validated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:49:39 +02:00
Vlad MocanuandClaude Opus 4.6 99624efacc fix: fall back to issue.assignee on Forgejo for assignee trigger
Forgejo's issues/assigned webhook payload doesn't include a top-level
assignee object. The assignee is only available under issue.assignee.
Fall back to that field when payload.assignee is missing.

Also removes M5 debug logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:47:30 +02:00
Vlad MocanuandClaude Opus 4.6 001072c05c debug: add issue.assignee/assignees logging for M5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:46:25 +02:00
Vlad MocanuandClaude Opus 4.6 9efd06cc26 debug: add M5 debug logging for assignee trigger
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:15 +02:00
Vlad MocanuandClaude Opus 4.6 efddd08f5c docs(prd-6): mark M4 complete — label trigger validated
3 bugs found and fixed:
- Workflow if: expression parser rejects # comments
- Forgejo doesn't populate github.event.action in if: context
- Forgejo sends 'label_updated' instead of 'labeled'

Key learning: normalize Forgejo event action names in context.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:15 +02:00
Vlad MocanuandClaude Opus 4.6 f3c92a2821 fix: move comments out of workflow if: expression block
Forgejo runner's expression parser rejects '#' characters inside
if: | blocks (run 52778: "unexpected character '#' while lexing
expression"). Move all comments above the if: key and switch from
block scalar (|) to folded scalar (>-) to avoid multiline issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:15 +02:00
Vlad MocanuandClaude Opus 4.6 1748a2c3df docs(prd-6): mark M3 complete — PR review trigger validated
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 401c35fdd2 docs: document Forgejo event behavior in workflow and trigger.ts
Add inline comments explaining:
- Forgejo never fires pull_request_review (sends pull_request_comment)
- Why workflow if-condition cannot gate on @claude for these events
  (payload fields are empty, confirmed by run 12084 being skipped)
- The @claude check is handled in trigger.ts via payload inspection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 231a31ca39 revert: undo workflow if-condition gating for pull_request_comment
Forgejo's pull_request_comment payload does not populate
github.event.comment.body or github.event.review.body in a way
the workflow contains() expression can read, causing legitimate
@claude reviews to be skipped (run 12084).

Revert to unconditional pass at the workflow level. The @claude
check is handled properly in trigger.ts which inspects the actual
payload fields with fallback logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 71fb686885 fix: gate Forgejo review/comment triggers on @claude mention
Previously, all pull_request_comment events on Forgejo triggered the
full Claude pipeline unconditionally — both in the workflow if-condition
and in trigger.ts. This wasted CI resources and API credits on reviews
without @claude mentions (e.g. plain "LGTM" reviews).

Workflow: add @claude check via contains() on comment.body and review.body.
Trigger validation: replace blind auto-trigger with payload-aware check
that inspects available body fields, falling back only when no body exists.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 d9c22ffe50 docs(prd-6): mark M2 complete — PR review comment trigger validated
E2E test confirmed: Claude correctly responds to @claude mentions in
PR review comments on Forgejo (run #12075, PR #15). Three bugs were
found and fixed during validation:
1. Missing comment object in Forgejo webhook payload
2. Event name mismatch (pull_request_comment vs pull_request_review_comment)
3. MCP server routing updates to wrong API (critical — silently dropped responses)

Progress: 3/8 milestones complete (37.5%)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 84cf34ff1f fix: route Forgejo review comment updates to issue comment API
On Forgejo, the tracking comment for pull_request_review_comment events
is always created as a regular issue comment (because Forgejo's webhook
payload lacks the top-level comment object). The MCP server was
incorrectly setting isPullRequestReviewComment=true based on the event
name, causing every update to try pulls.updateReviewComment first —
which 404'd and silently swallowed Claude's responses.

Three fixes:
- MCP server: detect Forgejo and always use issue comment path
- update-comment-link: skip pulls.getReviewComment on Forgejo (saves
  one wasted 404 API call)
- update-claude-comment: expand fallback to also catch 422 (defense
  in depth for Forgejo edge cases)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 821cc86c6e docs(prd-6): mark M1.5 resolved — CI confirmed green
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 2f44e40942 fix: remove all image-downloader mocking from forgejo-data-fetcher test
Both mock.module and spyOn cause cross-file test pollution in Bun's
single-process runner — mock.module poisons the module registry permanently,
and spyOn doesn't correctly restore ESM live bindings across files on Linux.

The real downloadCommentImages is safe to call because test comment bodies
contain no GitHub image URLs, so the function finds zero images and returns
an empty Map naturally. The only side effect is mkdir("/tmp/github-images")
which is harmless on CI runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 ede18897b0 docs(prd-6): mark M1.5 resolved, document root cause and fix
Root cause was mock.module cross-file pollution in Bun's test runner,
not Linux-specific mock tracking bugs as previously theorized.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 ac9e9cddff fix: replace mock.module with spyOn to stop cross-file test pollution
mock.module("image-downloader") in forgejo-data-fetcher.test.ts replaced
the module in Bun's registry globally for the entire process. When Bun's
non-deterministic file ordering ran this file BEFORE image-downloader.test.ts,
the image-downloader tests imported a stubbed module instead of the real one,
breaking all 18 tests. This was the root cause of the CI failures that
persisted through 5 previous fix attempts.

spyOn patches the live module export per-test and is auto-restored by Bun
after each test — no cross-file pollution regardless of execution order.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 a544d710e5 test: remove diagnostic file that broke typecheck
The DI fix for image-downloader tests passed on CI (all 18 tests
green). Removing the temporary mock tracking diagnostic file whose
type errors caused the typecheck job to fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 7011b0f71a test: add mock tracking diagnostics for Forgejo CI debugging
DI fix passes locally in grunt-runner Docker but still fails on
actual Forgejo runner. Adding diagnostic tests to isolate whether
mock() tracking itself is broken, or something else in the runner
environment causes it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:09 +02:00
Vlad MocanuandClaude Opus 4.6 a6b3c94004 fix: use dependency injection for image-downloader fs mocks
mock.module("fs/promises") on Linux Bun poisons the entire mock
tracking system — not just fs mocks, but ALL mock/spy assertions
(octokit mocks, spyOn(global, "fetch"), etc.) stop recording calls.

Replace with dependency injection: downloadCommentImages() now accepts
an optional fsDeps parameter. Tests pass mock mkdir/writeFile directly.
Production callers omit it and get real fs. No mock.module anywhere.

Fixes 18 test failures blocking CI on Forgejo Linux runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:45:08 +02:00
Vlad Mocanu 6113a4ef2d test: add M2 E2E test marker for PR review comment trigger 2026-02-26 10:45:08 +02:00
Vlad MocanuandClaude Opus 4.6 3cd73bccde revert: remove label check from opened events to prevent duplicates
Forgejo fires both issues/opened AND issues/label_updated when an
issue is created with a label. Having the label check on opened
caused duplicate Claude runs. Remove it — the label_updated event
handles label triggers correctly now that the workflow gate and
action normalization are fixed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:30:47 +02:00
Vlad MocanuandClaude Opus 4.6 1feec26c2e feat: check trigger label on issue opened events
When an issue is created with the trigger label already applied,
Forgejo only fires issues/opened (not a separate labeled event).
Check payload.issue.labels for the trigger label during opened
events so creating an issue with the claude label works in one step.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:29:05 +02:00
Vlad MocanuandClaude Opus 4.6 b37009b766 cleanup: remove M4 debug logging from run.ts
Debug logging confirmed Forgejo sends 'label_updated' as eventAction
for issues/labeled events. Normalization fix in context.ts handles it.
Remove temporary debug lines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:27:59 +02:00
Vlad MocanuandClaude Opus 4.6 baa007a3ec fix: normalize Forgejo 'label_updated' to 'labeled' in context
Forgejo sends eventAction 'label_updated' instead of 'labeled' for
issue label events. Add FORGEJO_EVENT_ACTION_MAP in context.ts to
normalize at parse time (same pattern as event name normalization),
so all downstream code (trigger.ts, create-prompt) works unchanged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:25:58 +02:00
Vlad MocanuandClaude Opus 4.6 fa0070ddcc fix: accept Forgejo 'label_updated' action for label triggers
Forgejo sends eventAction 'label_updated' instead of 'labeled'
for issue label events (discovered via debug logging, run 52786).
Accept both values in trigger.ts label check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:24:01 +02:00
Vlad MocanuandClaude Opus 4.6 b020426956 debug: add issues event payload logging for M4 label trigger
Temporary debug logging to inspect eventAction and payload.label
on Forgejo for issues/labeled events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:22:57 +02:00
Vlad MocanuandClaude Opus 4.6 a864b1636f fix: move comments out of workflow if: expression block
Forgejo runner's expression parser rejects '#' characters inside
if: | blocks (run 52778: "unexpected character '#' while lexing
expression"). Move all comments above the if: key and switch from
block scalar (|) to folded scalar (>-) to avoid multiline issues.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:21:23 +02:00
Vlad MocanuandClaude Opus 4.6 414c7053eb fix: let all issues events through workflow gate on Forgejo
Forgejo does not populate github.event.action in the workflow if:
context for issues events (run 12061 was skipped despite action
being 'labeled'). Same pattern as pull_request_comment (M3).

Remove the action/body/title gating from the workflow condition
and let trigger.ts handle all validation (label, assignee, mention).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 10:19:39 +02:00
Vlad MocanuandClaude Opus 4.6 dab92ef0eb fix: use mock.module for image-downloader tests
Replace the _fsForTest/DI patterns with Bun's native mock.module() API.
This mocks fs/promises at the module loader level, which works reliably
on Linux where jest.fn() call tracking fails cross-module. The source
code is now clean with no testing artifacts.

Also switches from jest.fn() to mock() (Bun's native API) for Octokit
mocks in these tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 09:05:39 +02:00
Vlad MocanuandClaude Opus 4.6 cff360d00a fix: use dependency injection for image-downloader fs mocks
The _fsForTest mutable object pattern fails on Linux Bun because
test and source files get different module instances. Switch to
passing fs operations as an optional parameter with defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:54:58 +02:00
Vlad MocanuandClaude Opus 4.6 ac8e22e2f8 fix: fall through to issue comment when PR review comment fetch 404s
On Forgejo, pull_request_review_comment events create the tracking
comment as a regular issue comment (because the payload lacks
comment.id for reply-to-review). The update-comment-link step then
tried pulls.getReviewComment() first, which 404'd and threw before
reaching the issues.getComment() fallback.

Wrap the PR review comment fetch in its own try/catch so it falls
through to the issue comment fetch on failure.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:49:26 +02:00
Vlad MocanuandClaude Opus 4.6 910c843122 chore: remove debug-event job, merge into failure step
The separate debug-event job ran on every event, wasting a runner.
Merged the event payload dump into the existing "Debug on failure"
step so it only runs when the claude job actually fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:43:57 +02:00
Vlad MocanuandClaude Opus 4.6 e73c881c64 fix: skip commentBody validation for Forgejo review comment events
Forgejo's pull_request_review_comment payload doesn't include the
comment body. The Forgejo data fetcher retrieves it via REST instead.
Skip the COMMENT_BODY required check on Forgejo to avoid crashing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:42:22 +02:00
Vlad MocanuandClaude Opus 4.6 9d8c96f01e fix: handle missing comment payload in Forgejo pull_request_review_comment
Forgejo's pull_request_review_comment event does NOT include a top-level
`comment` object in the webhook payload. This caused crashes at:
- create-initial.ts: context.payload.comment.id (for reply-to-review)
- fetcher.ts: context.payload.comment.created_at (for trigger timestamp)

Fix: use optional chaining and fall back gracefully — reply-to-review
becomes a regular issue comment, trigger timestamp returns undefined.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 08:39:48 +02:00
Vlad MocanuandClaude Opus 4.6 a10b0475c0 fix: handle missing comment payload in Forgejo review comment events
Forgejo's pull_request_review_comment event does not include a
top-level `comment` object in the payload (it's undefined), causing
a crash: "undefined is not an object (evaluating 'context.payload.comment.body')".

- trigger.ts: On Forgejo, always trigger for pull_request_review_comment
  events since the workflow already gates on event name alone
- create-prompt/index.ts: Use optional chaining for comment fields,
  fall back to actor/empty values (data fetcher provides full data)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:53:19 +02:00
Vlad MocanuandClaude Opus 4.6 b4bc36810d fix: let pull_request_review_comment events through unconditionally
Forgejo's pull_request_review_comment event does not populate
github.event.comment.body in the workflow context (it's always
empty), so the contains() check never matches. The action code
does its own trigger phrase validation, so it's safe to let these
events through based on event name alone.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 23:49:19 +02:00
Vlad Mocanu 2ff7e35b48 chore: trigger workflow cache refresh for debug job 2026-02-25 23:48:10 +02:00
Vlad Mocanu 97dd0863c7 chore: improve debug-event job payload dump [skip ci] 2026-02-25 23:47:04 +02:00
Vlad Mocanu a129a15f61 feat(prd-6): verify workflow triggers and add assignee_trigger (#13) 2026-02-25 21:43:37 +00:00
Vlad Mocanu 095c2c2429 Merge pull request 'docs: rename bot from claude-bot to claude in CI and docs' (#12) from claude/issue-11-20260225-2020 into main
Reviewed-on: https://git.wxs.ro/actions/claude-code-action/pulls/12
2026-02-25 20:37:35 +00:00
Vlad Mocanu 3bab2edc41 fix: build image URL regexes at call time, not module load time 2026-02-25 19:26:18 +00:00
Vlad MocanuandClaude Opus 4.6 2f7d0a7fb2 docs(prd-5): mark complete and archive to prds/done/ [skip ci]
- All milestones delivered, E2E validated on PR #8
- Deferred: commit authorship E2E, cross-repo test

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:11:20 +02:00
Vlad Mocanu 40731a0f5d Merge pull request 'feat: add dedicated claude-bot user for Forgejo (PRD #5)' (#8) from feature/prd-5-dedicated-forgejo-user into main 2026-02-25 19:07:49 +00:00
Vlad MocanuandClaude Opus 4.6 23f15aecb9 fix: use GITHUB_RUN_NUMBER for Forgejo job URLs and pin Bun version in CI
Forgejo uses the per-repo sequential run index (GITHUB_RUN_NUMBER) in
action URLs, not the internal DB run ID (GITHUB_RUN_ID). This caused
"View job" links to return 404. Fixed in all 4 URL construction sites:
create-initial comment, update-comment-link, and both prompt generators.

Also pins Bun to 1.2.21 in CI — Bun 1.3.9 broke spyOn(fs, ...) which
failed 18 upstream image-downloader tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:07:40 +02:00
Vlad MocanuandClaude Opus 4.6 6ebfb4914f docs: replace instance-specific values with placeholders in forgejo.md
Replace hardcoded bot_id "48" and bot_email "claude@wxs.ro" with
generic placeholders in Quick Start and setup examples so readers
don't copy instance-specific values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:56:55 +02:00