feat: add claude_args passthrough and structured_output (closes #1)

Bring the upstream v1 `claude_args` input and `structured_output` output
into this Gitea fork so downstream workflows can run the agent with
arbitrary Claude CLI flags (notably `--json-schema`) and read the
schema-validated verdict back as an action output, without an
agent-written file.

Approach (issue Option B, ported rather than bumped): the production
"Run Claude Code" step previously delegated to the external
anthropics/claude-code-base-action@v0.0.63, which has neither input.
Upstream base-action main has them but has migrated to the Claude Agent
SDK — a wholesale divergence that would change v0.0.63 behavior every
downstream step relies on. Instead this invokes the vendored base-action
directly via `bun run ${github.action_path}/base-action/src/index.ts`
(the same github.action_path pattern prepare.ts already uses, reliable
on Gitea), and ports only the two features onto the v0.0.63 process-spawn
engine.

- base-action/src/run-claude.ts: tokenize claude_args with shell-quote
  (comment-line stripping; quoted/file-path schemas survive intact) and
  append after the byte-identical BASE_ARGS, so empty claude_args yields
  an unchanged arg list; extract structured_output from the stream-json
  result event when --json-schema is present, failing loudly if absent.
- base-action/src/index.ts: forward INPUT_CLAUDE_ARGS.
- base-action/action.yml: add claude_args input + structured_output output.
- action.yml: add claude_args input + structured_output output; replace
  the external base-action delegation with a direct bun-run of the
  vendored copy (full INPUT_*/provider env contract derived from the
  vendored validate-env/index); bump the default Claude CLI install to
  2.1.160 (--json-schema requires a newer CLI than 1.0.117).
- shell-quote added to both package.json files; root bun.lock reconciled
  (it was stale vs package.json — non-frozen installs already resolved
  the newer tree).
- Tests for tokenizer, hasJsonSchema, and structured-output extraction.
- README: inputs/outputs tables, "Structured output" + "Version pins".
- examples/gitea-structured-output.yml.

Follow-up (cannot be done from this repo): consumers using a pre-baked
runner image (path_to_claude_code_executable) must rebuild that image
with a --json-schema-capable Claude CLI and restart the runner.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 22:22:51 +10:00
parent 92631f4d12
commit 52882e1d74
11 changed files with 482 additions and 97 deletions
+47
View File
@@ -67,6 +67,7 @@ jobs:
| `use_vertex` | Use Google Vertex AI with OIDC authentication instead of direct Anthropic API | No | `false` |
| `allowed_tools` | Additional tools for Claude to use (the base GitHub tools will always be included) | No | "" |
| `disallowed_tools` | Tools that Claude should never use | No | "" |
| `claude_args` | Additional arguments forwarded verbatim to the Claude CLI (e.g. `--json-schema /path/to/schema.json`). See [Structured output](#structured-output). Requires a Claude CLI new enough to support the flags used. | No | "" |
| `custom_instructions` | Additional custom instructions to include in the prompt for Claude | No | "" |
| `assignee_trigger` | The assignee username that triggers the action (e.g. @claude). Only used for issue and PR assignment | No | - |
| `trigger_phrase` | The trigger phrase to look for in comments, issue/PR bodies, and issue titles | No | `@claude` |
@@ -77,6 +78,52 @@ jobs:
> **Note**: This action is currently in beta. Features and APIs may change as we continue to improve the integration.
## Outputs
| Output | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `execution_file` | Path to the JSON file containing the Claude Code execution log |
| `structured_output` | JSON string of the schema-validated result, set only when `--json-schema` is passed via `claude_args`. Parse with `fromJSON()` or `jq`. |
| `branch_name` | The branch created by Claude Code for this execution (issue flows) |
## Structured output
`claude_args` forwards arbitrary flags straight to the Claude CLI. The primary use case is asking the model for a **schema-validated result** instead of having the agent write it to a file. When you pass `--json-schema`, the action surfaces the validated object as the `structured_output` action output (no agent-written file required).
```yaml
- uses: ryan/claude-code-gitea-action@gitea
id: review
with:
gitea_token: ${{ secrets.GITHUB_TOKEN }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
direct_prompt: "Review this PR and return a verdict that matches the schema."
# Prefer the file-path form — it has no spaces or `$` for the shell
# tokenizer to mangle, so a schema containing $ref/$defs round-trips safely.
claude_args: --json-schema ${{ github.workspace }}/.gitea/review-schema.json
- name: Use the verdict
shell: bash
run: |
echo '${{ steps.review.outputs.structured_output }}' | jq -r '.decision'
```
Notes:
- **Use the file-path form** (`--json-schema /path/to/schema.json`). An inline schema also works if single-quoted (`--json-schema '{"type":"object"}'`), but the schema must be single-quoted so the shell tokenizer treats it as one literal token and does not expand `$` (e.g. `$ref`).
- If `--json-schema` is supplied but the model returns no structured result, the run **fails loudly** rather than emitting an empty output.
- **Claude CLI version.** `--json-schema` requires a recent CLI. This action installs `2.1.160` by default. If you pin `path_to_claude_code_executable` (e.g. a pre-baked runner image), that baked CLI must be `--json-schema`-capable — bump it independently. See [Version pins](#version-pins).
### Version pins
This fork runs Claude via the vendored `base-action/` (invoked directly, not the external `anthropics/claude-code-base-action`). The moving pieces:
| Component | Where it's pinned | Current value |
| -------------------------------------- | -------------------------------------------------- | ------------- |
| Claude CLI (default install) | `action.yml` → "Install Claude" step | `2.1.160` |
| Claude CLI (pre-baked runner image) | the runner image's Dockerfile (`CLAUDE_CLI_VERSION`) | set by you |
If you consume this action through a pre-baked runner image that sets `path_to_claude_code_executable`, the action's own install step is skipped — so enabling `--json-schema` there requires **rebuilding that runner image** with a `--json-schema`-capable CLI and restarting the runner. That is outside this repository.
## Gitea Configuration
This action has been enhanced to work with Gitea installations. The main differences from GitHub are: