- Use allowlist for issue view (numeric issue numbers only)
- Enforce zero positional args for issue list / label list
- Pin GH_HOST and GH_REPO explicitly to avoid ambient state
- Add descriptive error messages with usage examples
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.
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
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>
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>
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>