diff --git a/README.md b/README.md index beb31d8..9084d8c 100644 --- a/README.md +++ b/README.md @@ -66,20 +66,22 @@ Each example includes a complete workflow file that you can copy to your `.githu ### Inputs -| Input | Description | Required | Example | -| ---------------------- | ----------------------------------------------------- | -------- | ------------------------------------------- | -| `augment_session_auth` | Augment session authentication JSON (store as secret) | No\*\* | `${{ secrets.AUGMENT_SESSION_AUTH }}` | -| `augment_api_token` | API token for Augment services (store as secret) | No\*\* | `${{ secrets.AUGMENT_API_TOKEN }}` | -| `augment_api_url` | Augment API endpoint URL (store as variable) | No\*\* | `${{ vars.AUGMENT_API_URL }}` | -| `github_token` | GitHub token with `repo` and `user:email` scopes. | No | `${{ secrets.GITHUB_TOKEN }}` | -| `instruction` | Direct instruction text for simple commands | No\* | `"Generate PR description"` | -| `instruction_file` | Path to file with detailed instructions | No\* | `/tmp/instruction.txt` | -| `template_directory` | Path to template directory for dynamic instructions | No\* | `.github/templates` | -| `template_name` | Template file name (default: prompt.njk) | No | `pr-review.njk` | -| `pull_number` | PR number for template context extraction | No | `${{ github.event.pull_request.number }}` | -| `repo_name` | Repository name for template context | No | `${{ github.repository }}` | -| `custom_context` | Additional JSON context for templates | No | `'{"priority": "high"}'` | -| `model` | Model to use; passed through to auggie as --model | No | e.g. `sonnet4`, from `auggie --list-models` | +| Input | Description | Required | Example | +| ---------------------- | --------------------------------------------------------------------------------------- | -------- | ------------------------------------------- | +| `augment_session_auth` | Augment session authentication JSON (store as secret) | No\*\* | `${{ secrets.AUGMENT_SESSION_AUTH }}` | +| `augment_api_token` | API token for Augment services (store as secret) | No\*\* | `${{ secrets.AUGMENT_API_TOKEN }}` | +| `augment_api_url` | Augment API endpoint URL (store as variable) | No\*\* | `${{ vars.AUGMENT_API_URL }}` | +| `github_token` | GitHub token with `repo` and `user:email` scopes. | No | `${{ secrets.GITHUB_TOKEN }}` | +| `instruction` | Direct instruction text for simple commands | No\* | `"Generate PR description"` | +| `instruction_file` | Path to file with detailed instructions | No\* | `/tmp/instruction.txt` | +| `template_directory` | Path to template directory for dynamic instructions | No\* | `.github/templates` | +| `template_name` | Template file name (default: prompt.njk) | No | `pr-review.njk` | +| `pull_number` | PR number for template context extraction | No | `${{ github.event.pull_request.number }}` | +| `repo_name` | Repository name for template context | No | `${{ github.repository }}` | +| `custom_context` | Additional JSON context for templates | No | `'{"priority": "high"}'` | +| `model` | Model to use; passed through to auggie as --model | No | e.g. `sonnet4`, from `auggie --list-models` | +| `rules` | JSON array of rules file paths (each forwarded as individual `--rules` flags) | No | `'[".github/augment/rules.md"]'` | +| `mcp_configs` | JSON array of MCP config file paths (each forwarded as individual `--mcp-config` flags) | No | `'[".augment/mcp/config.json"]'` | \*Either `instruction`, `instruction_file`, or `template_directory` must be provided. diff --git a/action.yml b/action.yml index eca3b3e..46e9098 100644 --- a/action.yml +++ b/action.yml @@ -43,6 +43,12 @@ inputs: model: description: "Model to use; forwarded to auggie as --model" required: false + rules: + description: "JSON array of rules file paths. Each entry is forwarded to auggie as an individual --rules flag." + required: false + mcp_configs: + description: "JSON array of MCP config file paths. Each entry is forwarded to auggie as an individual --mcp-config flag." + required: false runs: using: "composite" @@ -74,3 +80,5 @@ runs: INPUT_REPO_NAME: ${{ inputs.repo_name }} INPUT_CUSTOM_CONTEXT: ${{ inputs.custom_context }} INPUT_MODEL: ${{ inputs.model }} + INPUT_RULES: ${{ inputs.rules }} + INPUT_MCP_CONFIGS: ${{ inputs.mcp_configs }} diff --git a/src/config/constants.ts b/src/config/constants.ts index 3776e3f..5a15bea 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -25,6 +25,8 @@ export const INPUT_FIELD_MAP: Record = { templateDirectory: { envVar: 'INPUT_TEMPLATE_DIRECTORY', required: false }, templateName: { envVar: 'INPUT_TEMPLATE_NAME', required: false }, model: { envVar: 'INPUT_MODEL', required: false }, + rules: { envVar: 'INPUT_RULES', required: false }, + mcpConfigs: { envVar: 'INPUT_MCP_CONFIGS', required: false }, }; export const TEMPLATE_CONFIG = { diff --git a/src/index.ts b/src/index.ts index ee639a0..94ed55f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -119,12 +119,32 @@ async function runAugmentScript(inputs: ActionInputs): Promise { } if (is_file) { logger.info(`📄 Using instruction file: ${instruction_value}`); - args.push('--instruction-file'); + args.push('--instruction-file', instruction_value); } else { logger.info('📝 Using direct instruction'); - args.push('--instruction'); + args.push('--instruction', instruction_value); } - args.push(instruction_value); + + const uniqueRules = Array.from(new Set(inputs.rules ?? [])).filter(rule => rule.length > 0); + if (uniqueRules.length > 0) { + logger.info(`🔧 Applying ${uniqueRules.length} rule file(s)`); + for (const rulePath of uniqueRules) { + logger.info(` - ${rulePath}`); + args.push('--rules', rulePath); + } + } + + const uniqueMcpConfigs = Array.from(new Set(inputs.mcpConfigs ?? [])).filter( + config => config.length > 0 + ); + if (uniqueMcpConfigs.length > 0) { + logger.info(`🧩 Applying ${uniqueMcpConfigs.length} MCP config file(s)`); + for (const configPath of uniqueMcpConfigs) { + logger.info(` - ${configPath}`); + args.push('--mcp-config', configPath); + } + } + await execCommand('auggie', args); logger.info('✅ Augment Agent completed successfully'); } diff --git a/src/types/inputs.ts b/src/types/inputs.ts index 07fec62..e237e1d 100644 --- a/src/types/inputs.ts +++ b/src/types/inputs.ts @@ -24,6 +24,10 @@ export interface ActionInputs { customContext?: string | undefined; pullNumber?: number | undefined; repoName?: string | undefined; + + // Additional configuration inputs + rules?: string[] | undefined; + mcpConfigs?: string[] | undefined; } export interface RepoInfo { diff --git a/src/utils/validation.ts b/src/utils/validation.ts index 742cb89..fcecf4e 100644 --- a/src/utils/validation.ts +++ b/src/utils/validation.ts @@ -7,6 +7,36 @@ import type { ActionInputs, RepoInfo } from '../types/inputs.js'; import { logger } from './logger.js'; import { ERROR, INPUT_FIELD_MAP } from '../config/constants.js'; +const createJsonStringArraySchema = (invalidTypeMessage: string, emptyEntryMessage: string) => + z.preprocess( + value => { + if (value === undefined || value === null) { + return undefined; + } + if (typeof value === 'string') { + const trimmed = value.trim(); + if (trimmed.length === 0) { + return undefined; + } + try { + return JSON.parse(trimmed); + } catch { + return value; + } + } + return value; + }, + z + .array( + z + .string() + .transform(val => val.trim()) + .refine(val => val.length > 0, { message: emptyEntryMessage }), + { invalid_type_error: invalidTypeMessage } + ) + .optional() + ); + /** * Zod schema for action inputs validation */ @@ -27,6 +57,14 @@ const ActionInputsSchema = z .string() .regex(/^[^\/]+\/[^\/]+$/, ERROR.INPUT.REPO_FORMAT) .optional(), + rules: createJsonStringArraySchema( + 'rules must be a JSON array of strings', + 'Rule file paths cannot be empty' + ), + mcpConfigs: createJsonStringArraySchema( + 'mcp_configs must be a JSON array of strings', + 'MCP config file paths cannot be empty' + ), }) .refine( data => {