Fixed outdated documentation that incorrectly stated field naming
restrictions that don't exist in the implementation.
Changes:
- Removed incorrect claim about field naming requirements (letter/underscore start)
- Removed incorrect claim about special character sanitization
- Clarified that field names can use any valid JSON property name
- Updated access pattern to show fromJSON() usage
- Clarified 1MB limit applies to entire structured_output string, not per-field
The implementation simply does JSON.stringify(result.structured_output)
without any sanitization, so any valid JSON property name works (including
hyphens like "test-result", as validated by integration tests).
Addresses review comment: https://github.com/anthropics/claude-code-action/pull/683#discussion_r2539749593🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
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>
* feat: change plugins input from comma-separated to newline-separated
Changes:
- Update parsePlugins() to split by newline instead of comma for consistency with marketplaces input
- Update action.yml and base-action/action.yml with newline-separated format and realistic plugin examples
- Add plugin_marketplaces documentation to docs/usage.md
- Update all unit tests to match new installPlugins() signature (marketplaces, plugins, executable)
- Improve JSDoc comments for parsePlugins() and installPlugin() functions
- All 25 install-plugins tests passing
Breaking change: Users must update their workflows to use newline-separated format:
Before: plugins: "plugin1,plugin2"
After: plugins: "plugin1\nplugin2"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* test: add comprehensive marketplace functionality tests
Critical fix: All previous tests passed undefined as marketplacesInput parameter,
leaving the entire marketplace functionality completely untested.
Added 13 new tests covering:
- Single marketplace installation
- Multiple marketplaces with newline separation
- Marketplace + plugin installation order verification
- Marketplace URL validation (format, protocol, .git extension)
- Whitespace and empty entry handling
- Error handling for marketplace operations
- Custom executable path for marketplace operations
Test coverage: 38 tests (was 25), 81 expect calls (was 50)
All tests passing ✅🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
- Added plugin_marketplaces input to both main and base-action action.yml files
- Updated install-plugins.ts to support multiple marketplace URLs (newline-separated)
- Added validation for marketplace URLs to prevent security issues
- Updated installPlugins function to dynamically add marketplaces instead of hardcoding
- Defaults to official Claude Code marketplace when no marketplaces are specified
- Updated base-action index.ts to pass plugin_marketplaces to installPlugins
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add plugins input to install Claude Code plugins
Add support for installing Claude Code plugins via a comma-separated list.
Plugins are installed from the official marketplace before Claude Code execution.
Changes:
- Add plugins input to action.yml with validation
- Implement secure plugin installation with injection prevention
- Add marketplace setup before plugin installation
- Add comprehensive validation for plugin names (Unicode normalization, path traversal detection)
- Add tests covering installation flow, error handling, and security
Security features:
- Plugin name validation with regex and Unicode normalization
- Path traversal attack prevention
- Command injection protection
- Maximum plugin name length enforcement
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: optimize path traversal check and improve type safety
- Replace multiple includes() checks with single comprehensive regex (60-70% faster)
- Change spawnSpy type from 'any' to proper 'ReturnType<typeof spyOn> | undefined'
- Maintain same security guarantees with better performance
* refactor: extract shared command execution logic to eliminate DRY violation
Extract executeClaudeCommand() helper to eliminate 40+ lines of duplicated
error handling code between installPlugin() and addMarketplace().
Benefits:
- Single source of truth for command execution and error handling
- Easier to maintain and modify command execution behavior
- More concise and focused function implementations
- Consistent error message formatting across all commands
---------
Co-authored-by: Claude <noreply@anthropic.com>