fix: workaround GitHub Actions composite action output limitation

GitHub Actions composite actions cannot have dynamic outputs - all outputs
must be explicitly declared in action.yml. This is a known limitation.

Changes:
- Add structured_output JSON output to base-action/action.yml
  (contains all structured fields as single JSON string)
- Update run-claude.ts to set structured_output output
- Update tests to parse structured_output JSON with jq
- Add structured_output to RESERVED_OUTPUTS list

Users can now access structured outputs via:
  steps.<id>.outputs.structured_output | jq '.field_name'

Or in GitHub Actions expressions:
  fromJSON(steps.<id>.outputs.structured_output).field_name

Individual field outputs are still set for direct usage contexts,
but only the structured_output JSON is accessible via composite action.

Fixes #683 test failures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
inigo
2025-11-18 12:08:41 -08:00
parent e93583852d
commit dcee434ef2
3 changed files with 71 additions and 34 deletions

View File

@@ -92,6 +92,9 @@ outputs:
execution_file:
description: "Path to the JSON file containing Claude Code execution log"
value: ${{ steps.run_claude.outputs.execution_file }}
structured_output:
description: "JSON string containing all structured output fields (use fromJSON() or jq to parse)"
value: ${{ steps.run_claude.outputs.structured_output }}
runs:
using: "composite"

View File

@@ -139,7 +139,11 @@ export function sanitizeOutputName(name: string): string {
}
// Reserved output names that cannot be used by structured outputs
const RESERVED_OUTPUTS = ["conclusion", "execution_file"] as const;
const RESERVED_OUTPUTS = [
"conclusion",
"execution_file",
"structured_output",
] as const;
/**
* Converts values to string format for GitHub Actions outputs
@@ -191,9 +195,17 @@ async function parseAndSetStructuredOutputs(
);
}
// Set GitHub Action output for each field
// Set the complete structured output as a single JSON string
// This works around GitHub Actions limitation that composite actions can't have dynamic outputs
const structuredOutputJson = JSON.stringify(result.structured_output);
core.setOutput("structured_output", structuredOutputJson);
core.info(
`Set structured_output with ${Object.keys(result.structured_output).length} field(s)`,
);
// Also set individual field outputs for direct usage (when not using composite action)
const entries = Object.entries(result.structured_output);
core.info(`Setting ${entries.length} structured output(s)`);
core.info(`Setting ${entries.length} individual structured output(s)`);
for (const [key, value] of entries) {
// Validate key before sanitization