@dependabit/action 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +225 -0
  4. package/action.yml +85 -0
  5. package/dist/actions/check.d.ts +33 -0
  6. package/dist/actions/check.d.ts.map +1 -0
  7. package/dist/actions/check.js +162 -0
  8. package/dist/actions/check.js.map +1 -0
  9. package/dist/actions/generate.d.ts +9 -0
  10. package/dist/actions/generate.d.ts.map +1 -0
  11. package/dist/actions/generate.js +152 -0
  12. package/dist/actions/generate.js.map +1 -0
  13. package/dist/actions/update.d.ts +9 -0
  14. package/dist/actions/update.d.ts.map +1 -0
  15. package/dist/actions/update.js +246 -0
  16. package/dist/actions/update.js.map +1 -0
  17. package/dist/actions/validate.d.ts +33 -0
  18. package/dist/actions/validate.d.ts.map +1 -0
  19. package/dist/actions/validate.js +226 -0
  20. package/dist/actions/validate.js.map +1 -0
  21. package/dist/index.d.ts +8 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +35 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/logger.d.ts +114 -0
  26. package/dist/logger.d.ts.map +1 -0
  27. package/dist/logger.js +154 -0
  28. package/dist/logger.js.map +1 -0
  29. package/dist/utils/agent-config.d.ts +31 -0
  30. package/dist/utils/agent-config.d.ts.map +1 -0
  31. package/dist/utils/agent-config.js +42 -0
  32. package/dist/utils/agent-config.js.map +1 -0
  33. package/dist/utils/agent-router.d.ts +33 -0
  34. package/dist/utils/agent-router.d.ts.map +1 -0
  35. package/dist/utils/agent-router.js +57 -0
  36. package/dist/utils/agent-router.js.map +1 -0
  37. package/dist/utils/errors.d.ts +51 -0
  38. package/dist/utils/errors.d.ts.map +1 -0
  39. package/dist/utils/errors.js +219 -0
  40. package/dist/utils/errors.js.map +1 -0
  41. package/dist/utils/inputs.d.ts +35 -0
  42. package/dist/utils/inputs.d.ts.map +1 -0
  43. package/dist/utils/inputs.js +47 -0
  44. package/dist/utils/inputs.js.map +1 -0
  45. package/dist/utils/metrics.d.ts +66 -0
  46. package/dist/utils/metrics.d.ts.map +1 -0
  47. package/dist/utils/metrics.js +116 -0
  48. package/dist/utils/metrics.js.map +1 -0
  49. package/dist/utils/outputs.d.ts +43 -0
  50. package/dist/utils/outputs.d.ts.map +1 -0
  51. package/dist/utils/outputs.js +146 -0
  52. package/dist/utils/outputs.js.map +1 -0
  53. package/dist/utils/performance.d.ts +100 -0
  54. package/dist/utils/performance.d.ts.map +1 -0
  55. package/dist/utils/performance.js +185 -0
  56. package/dist/utils/performance.js.map +1 -0
  57. package/dist/utils/reporter.d.ts +43 -0
  58. package/dist/utils/reporter.d.ts.map +1 -0
  59. package/dist/utils/reporter.js +122 -0
  60. package/dist/utils/reporter.js.map +1 -0
  61. package/dist/utils/secrets.d.ts +45 -0
  62. package/dist/utils/secrets.d.ts.map +1 -0
  63. package/dist/utils/secrets.js +94 -0
  64. package/dist/utils/secrets.js.map +1 -0
  65. package/package.json +45 -0
  66. package/src/actions/check.ts +223 -0
  67. package/src/actions/generate.ts +181 -0
  68. package/src/actions/update.ts +284 -0
  69. package/src/actions/validate.ts +292 -0
  70. package/src/index.ts +43 -0
  71. package/src/logger.test.ts +200 -0
  72. package/src/logger.ts +210 -0
  73. package/src/utils/agent-config.ts +61 -0
  74. package/src/utils/agent-router.ts +67 -0
  75. package/src/utils/errors.ts +251 -0
  76. package/src/utils/inputs.ts +75 -0
  77. package/src/utils/metrics.ts +169 -0
  78. package/src/utils/outputs.ts +202 -0
  79. package/src/utils/performance.ts +248 -0
  80. package/src/utils/reporter.ts +169 -0
  81. package/src/utils/secrets.ts +124 -0
  82. package/test/actions/check.test.ts +216 -0
  83. package/test/actions/generate.test.ts +82 -0
  84. package/test/actions/update.test.ts +70 -0
  85. package/test/actions/validate.test.ts +257 -0
  86. package/test/utils/agent-config.test.ts +112 -0
  87. package/test/utils/agent-router.test.ts +129 -0
  88. package/test/utils/metrics.test.ts +221 -0
  89. package/test/utils/reporter.test.ts +196 -0
  90. package/test/utils/secrets.test.ts +217 -0
  91. package/tsconfig.json +15 -0
  92. package/tsconfig.tsbuildinfo +1 -0
package/src/logger.ts ADDED
@@ -0,0 +1,210 @@
1
+ import * as core from '@actions/core';
2
+
3
+ /**
4
+ * Log level enumeration
5
+ */
6
+ export enum LogLevel {
7
+ DEBUG = 'debug',
8
+ INFO = 'info',
9
+ WARNING = 'warning',
10
+ ERROR = 'error'
11
+ }
12
+
13
+ /**
14
+ * Structured log entry
15
+ */
16
+ export interface LogEntry {
17
+ timestamp: string;
18
+ level: LogLevel;
19
+ message: string;
20
+ correlationId?: string;
21
+ [key: string]: unknown;
22
+ }
23
+
24
+ /**
25
+ * Logger configuration
26
+ */
27
+ export interface LoggerConfig {
28
+ correlationId?: string;
29
+ enableDebug?: boolean;
30
+ context?: Record<string, unknown>;
31
+ }
32
+
33
+ /**
34
+ * Structured JSON logger for GitHub Actions
35
+ */
36
+ export class Logger {
37
+ private correlationId: string;
38
+ private enableDebug: boolean;
39
+ private context: Record<string, unknown>;
40
+
41
+ constructor(config: LoggerConfig = {}) {
42
+ this.correlationId = config.correlationId || this.generateCorrelationId();
43
+ this.enableDebug = config.enableDebug ?? false;
44
+ this.context = config.context || {};
45
+ }
46
+
47
+ /**
48
+ * Generate a unique correlation ID for operation tracing
49
+ */
50
+ private generateCorrelationId(): string {
51
+ return `${Date.now()}-${Math.random().toString(36).substring(7)}`;
52
+ }
53
+
54
+ /**
55
+ * Format log entry as JSON
56
+ */
57
+ private formatEntry(level: LogLevel, message: string, data?: Record<string, unknown>): string {
58
+ const entry: LogEntry = {
59
+ timestamp: new Date().toISOString(),
60
+ level,
61
+ message,
62
+ correlationId: this.correlationId,
63
+ ...this.context,
64
+ ...data
65
+ };
66
+
67
+ return JSON.stringify(entry);
68
+ }
69
+
70
+ /**
71
+ * Log debug message
72
+ */
73
+ debug(message: string, data?: Record<string, unknown>): void {
74
+ if (this.enableDebug) {
75
+ core.debug(this.formatEntry(LogLevel.DEBUG, message, data));
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Log info message
81
+ */
82
+ info(message: string, data?: Record<string, unknown>): void {
83
+ core.info(this.formatEntry(LogLevel.INFO, message, data));
84
+ }
85
+
86
+ /**
87
+ * Log warning message
88
+ */
89
+ warning(message: string, data?: Record<string, unknown>): void {
90
+ core.warning(this.formatEntry(LogLevel.WARNING, message, data));
91
+ }
92
+
93
+ /**
94
+ * Log error message
95
+ */
96
+ error(message: string, data?: Record<string, unknown>): void {
97
+ core.error(this.formatEntry(LogLevel.ERROR, message, data));
98
+ }
99
+
100
+ /**
101
+ * Start a log group
102
+ */
103
+ startGroup(name: string): void {
104
+ core.startGroup(name);
105
+ }
106
+
107
+ /**
108
+ * End a log group
109
+ */
110
+ endGroup(): void {
111
+ core.endGroup();
112
+ }
113
+
114
+ /**
115
+ * Get correlation ID
116
+ */
117
+ getCorrelationId(): string {
118
+ return this.correlationId;
119
+ }
120
+
121
+ /**
122
+ * Create a child logger with the same correlation ID
123
+ */
124
+ child(context?: Record<string, unknown>): Logger {
125
+ return new Logger({
126
+ correlationId: this.correlationId,
127
+ enableDebug: this.enableDebug,
128
+ context: { ...this.context, ...context }
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Log LLM interaction
134
+ */
135
+ logLLMInteraction(data: {
136
+ provider: string;
137
+ model?: string;
138
+ prompt: string;
139
+ response: string;
140
+ tokens?: number;
141
+ latencyMs?: number;
142
+ }): void {
143
+ this.info('LLM interaction', {
144
+ type: 'llm_interaction',
145
+ ...data
146
+ });
147
+ }
148
+
149
+ /**
150
+ * Log API call
151
+ */
152
+ logAPICall(data: {
153
+ endpoint: string;
154
+ method: string;
155
+ statusCode?: number;
156
+ latencyMs?: number;
157
+ rateLimit?: {
158
+ remaining: number;
159
+ limit: number;
160
+ reset: number;
161
+ };
162
+ }): void {
163
+ this.info('API call', {
164
+ type: 'api_call',
165
+ ...data
166
+ });
167
+ }
168
+
169
+ /**
170
+ * Log operation duration
171
+ */
172
+ logDuration(operation: string, durationMs: number, data?: Record<string, unknown>): void {
173
+ this.info(`Operation completed: ${operation}`, {
174
+ type: 'operation_duration',
175
+ operation,
176
+ durationMs,
177
+ ...data
178
+ });
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Create a new logger instance
184
+ */
185
+ export function createLogger(config?: LoggerConfig): Logger {
186
+ return new Logger(config);
187
+ }
188
+
189
+ /**
190
+ * Measure and log operation duration
191
+ */
192
+ export async function withTiming<T>(
193
+ logger: Logger,
194
+ operation: string,
195
+ fn: () => Promise<T>
196
+ ): Promise<T> {
197
+ const start = Date.now();
198
+ try {
199
+ const result = await fn();
200
+ const duration = Date.now() - start;
201
+ logger.logDuration(operation, duration);
202
+ return result;
203
+ } catch (error) {
204
+ const duration = Date.now() - start;
205
+ logger.logDuration(operation, duration, {
206
+ error: error instanceof Error ? error.message : String(error)
207
+ });
208
+ throw error;
209
+ }
210
+ }
@@ -0,0 +1,61 @@
1
+ import type { DependabitConfig, Severity } from '@dependabit/manifest';
2
+
3
+ /**
4
+ * Agent assignment configuration
5
+ */
6
+ export interface AgentAssignmentConfig {
7
+ enabled: boolean;
8
+ severityMapping: {
9
+ breaking?: string;
10
+ major?: string;
11
+ minor?: string;
12
+ };
13
+ }
14
+
15
+ /**
16
+ * Parse AI agent assignment configuration from config
17
+ *
18
+ * Extracts severity-to-agent mapping from config.yml:
19
+ *
20
+ * ```yaml
21
+ * issues:
22
+ * aiAgentAssignment:
23
+ * enabled: true
24
+ * breaking: copilot
25
+ * major: claude
26
+ * minor: copilot
27
+ * ```
28
+ *
29
+ * @param config Dependabit configuration
30
+ * @returns Agent assignment configuration
31
+ */
32
+ export function parseAgentConfig(config: DependabitConfig): AgentAssignmentConfig {
33
+ const aiAgentAssignment = config.issues?.aiAgentAssignment;
34
+
35
+ if (!aiAgentAssignment || !aiAgentAssignment.enabled) {
36
+ return {
37
+ enabled: false,
38
+ severityMapping: {}
39
+ };
40
+ }
41
+
42
+ // Normalize agent names to lowercase
43
+ const severityMapping: Record<string, string> = {};
44
+
45
+ if (aiAgentAssignment.breaking) {
46
+ severityMapping['breaking'] = aiAgentAssignment.breaking.toLowerCase();
47
+ }
48
+
49
+ if (aiAgentAssignment.major) {
50
+ severityMapping['major'] = aiAgentAssignment.major.toLowerCase();
51
+ }
52
+
53
+ if (aiAgentAssignment.minor) {
54
+ severityMapping['minor'] = aiAgentAssignment.minor.toLowerCase();
55
+ }
56
+
57
+ return {
58
+ enabled: true,
59
+ severityMapping
60
+ };
61
+ }
@@ -0,0 +1,67 @@
1
+ import type { Severity } from '@dependabit/manifest';
2
+ import type { AgentAssignmentConfig } from './agent-config';
3
+ /**
4
+ * Route issue to appropriate AI agent based on severity
5
+ *
6
+ * Uses severity-to-agent mapping from configuration to determine
7
+ * which AI agent should be assigned to handle the issue.
8
+ *
9
+ * @param severity Change severity (breaking, major, minor)
10
+ * @param config Agent assignment configuration
11
+ * @returns Agent name (e.g., 'copilot', 'claude') or null if not configured
12
+ */
13
+ export function routeToAgent(severity: Severity, config: AgentAssignmentConfig): string | null {
14
+ if (!config.enabled) {
15
+ return null;
16
+ }
17
+
18
+ const agent = config.severityMapping[severity];
19
+ return agent || null;
20
+ }
21
+
22
+ /**
23
+ * Generate assignee label for issue
24
+ *
25
+ * Creates a label in format "assigned:agent" that can be used
26
+ * to trigger agent-specific workflows or assign the issue.
27
+ *
28
+ * @param agent Agent name or null
29
+ * @returns Label string or null
30
+ */
31
+ export function getAssigneeLabel(agent: string | null): string | null {
32
+ if (!agent) {
33
+ return null;
34
+ }
35
+
36
+ return `assigned:${agent}`;
37
+ }
38
+
39
+ /**
40
+ * Get all configured agents
41
+ *
42
+ * Returns list of unique agent names configured in the severity mapping
43
+ *
44
+ * @param config Agent assignment configuration
45
+ * @returns Array of agent names
46
+ */
47
+ export function getConfiguredAgents(config: AgentAssignmentConfig): string[] {
48
+ if (!config.enabled) {
49
+ return [];
50
+ }
51
+
52
+ const agents = new Set<string>();
53
+
54
+ if (config.severityMapping.breaking) {
55
+ agents.add(config.severityMapping.breaking);
56
+ }
57
+
58
+ if (config.severityMapping.major) {
59
+ agents.add(config.severityMapping.major);
60
+ }
61
+
62
+ if (config.severityMapping.minor) {
63
+ agents.add(config.severityMapping.minor);
64
+ }
65
+
66
+ return Array.from(agents);
67
+ }
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Error categorization and remediation messages
3
+ * Provides actionable error messages with remediation steps
4
+ */
5
+
6
+ export enum ErrorCategory {
7
+ AUTHENTICATION = 'authentication',
8
+ RATE_LIMIT = 'rate_limit',
9
+ NETWORK = 'network',
10
+ VALIDATION = 'validation',
11
+ NOT_FOUND = 'not_found',
12
+ PERMISSION = 'permission',
13
+ CONFIGURATION = 'configuration',
14
+ INTERNAL = 'internal'
15
+ }
16
+
17
+ export interface CategorizedError {
18
+ category: ErrorCategory;
19
+ message: string;
20
+ originalError: Error;
21
+ remediation: string[];
22
+ context?: Record<string, unknown> | undefined;
23
+ }
24
+
25
+ /**
26
+ * Error categorizer with remediation suggestions
27
+ */
28
+ export class ErrorCategorizer {
29
+ /**
30
+ * Categorize an error and provide remediation steps
31
+ */
32
+ categorize(error: Error, context?: Record<string, unknown>): CategorizedError {
33
+ const message = error.message.toLowerCase();
34
+
35
+ // Authentication errors
36
+ if (
37
+ message.includes('authentication') ||
38
+ message.includes('unauthorized') ||
39
+ message.includes('invalid token') ||
40
+ message.includes('bad credentials')
41
+ ) {
42
+ return {
43
+ category: ErrorCategory.AUTHENTICATION,
44
+ message: error.message,
45
+ originalError: error,
46
+ remediation: [
47
+ 'Verify that GITHUB_TOKEN is set correctly',
48
+ 'Check token has required permissions (repo, issues, contents)',
49
+ 'Ensure token has not expired',
50
+ 'For fine-grained tokens, verify repository access is granted',
51
+ 'Try regenerating the token if issues persist'
52
+ ],
53
+ context
54
+ };
55
+ }
56
+
57
+ // Rate limit errors
58
+ if (
59
+ message.includes('rate limit') ||
60
+ message.includes('api rate limit exceeded') ||
61
+ message.includes('secondary rate limit')
62
+ ) {
63
+ return {
64
+ category: ErrorCategory.RATE_LIMIT,
65
+ message: error.message,
66
+ originalError: error,
67
+ remediation: [
68
+ 'Wait for rate limit to reset (check X-RateLimit-Reset header)',
69
+ 'Consider using authenticated requests (higher rate limits)',
70
+ 'Implement request batching or caching',
71
+ 'Review API usage patterns to reduce calls',
72
+ 'For GitHub Actions, consider using GITHUB_TOKEN instead of PAT'
73
+ ],
74
+ context
75
+ };
76
+ }
77
+
78
+ // Network errors
79
+ if (
80
+ message.includes('econnrefused') ||
81
+ message.includes('enotfound') ||
82
+ message.includes('timeout') ||
83
+ message.includes('network')
84
+ ) {
85
+ return {
86
+ category: ErrorCategory.NETWORK,
87
+ message: error.message,
88
+ originalError: error,
89
+ remediation: [
90
+ 'Check internet connectivity',
91
+ 'Verify API endpoint is accessible',
92
+ 'Check for firewall or proxy blocking requests',
93
+ 'Retry the operation after a short delay',
94
+ 'Verify DNS resolution is working'
95
+ ],
96
+ context
97
+ };
98
+ }
99
+
100
+ // Not found errors
101
+ if (message.includes('not found') || message.includes('404')) {
102
+ return {
103
+ category: ErrorCategory.NOT_FOUND,
104
+ message: error.message,
105
+ originalError: error,
106
+ remediation: [
107
+ 'Verify the repository owner and name are correct',
108
+ 'Check if the resource exists (branch, file, issue)',
109
+ 'Ensure you have access to the repository (private repos)',
110
+ 'Verify the URL or path is correct',
111
+ 'Check if the resource was recently deleted'
112
+ ],
113
+ context
114
+ };
115
+ }
116
+
117
+ // Permission errors
118
+ if (
119
+ message.includes('permission') ||
120
+ message.includes('forbidden') ||
121
+ message.includes('403')
122
+ ) {
123
+ return {
124
+ category: ErrorCategory.PERMISSION,
125
+ message: error.message,
126
+ originalError: error,
127
+ remediation: [
128
+ 'Verify token has required scopes (repo, admin:org, etc.)',
129
+ 'Check repository access permissions',
130
+ 'For organization repos, verify org membership',
131
+ 'Ensure not attempting to modify protected branches',
132
+ 'Review repository settings and branch protection rules'
133
+ ],
134
+ context
135
+ };
136
+ }
137
+
138
+ // Validation errors
139
+ if (
140
+ message.includes('validation') ||
141
+ message.includes('invalid') ||
142
+ message.includes('malformed')
143
+ ) {
144
+ return {
145
+ category: ErrorCategory.VALIDATION,
146
+ message: error.message,
147
+ originalError: error,
148
+ remediation: [
149
+ 'Check input data format and structure',
150
+ 'Verify required fields are provided',
151
+ 'Validate data types match API expectations',
152
+ 'Review API documentation for correct format',
153
+ 'Check for special characters that need escaping'
154
+ ],
155
+ context
156
+ };
157
+ }
158
+
159
+ // Configuration errors
160
+ if (message.includes('config') || message.includes('missing')) {
161
+ return {
162
+ category: ErrorCategory.CONFIGURATION,
163
+ message: error.message,
164
+ originalError: error,
165
+ remediation: [
166
+ 'Verify all required configuration values are set',
167
+ 'Check .dependabit/config.yml exists and is valid',
168
+ 'Validate configuration schema',
169
+ 'Review example configuration in documentation',
170
+ 'Ensure environment variables are properly set'
171
+ ],
172
+ context
173
+ };
174
+ }
175
+
176
+ // Default to internal error
177
+ return {
178
+ category: ErrorCategory.INTERNAL,
179
+ message: error.message,
180
+ originalError: error,
181
+ remediation: [
182
+ 'This may be an internal error or unexpected condition',
183
+ 'Check error details for more information',
184
+ 'Try running the operation again',
185
+ 'If issue persists, report it with error details',
186
+ 'Check GitHub status page for service issues'
187
+ ],
188
+ context
189
+ };
190
+ }
191
+
192
+ /**
193
+ * Format error with remediation for display
194
+ */
195
+ format(categorizedError: CategorizedError): string {
196
+ const lines = [
197
+ `Error [${categorizedError.category}]: ${categorizedError.message}`,
198
+ '',
199
+ 'Remediation steps:',
200
+ ...categorizedError.remediation.map((step, i) => ` ${i + 1}. ${step}`)
201
+ ];
202
+
203
+ if (categorizedError.context && Object.keys(categorizedError.context).length > 0) {
204
+ lines.push('');
205
+ lines.push('Context:');
206
+ for (const [key, value] of Object.entries(categorizedError.context)) {
207
+ lines.push(` ${key}: ${JSON.stringify(value)}`);
208
+ }
209
+ }
210
+
211
+ return lines.join('\n');
212
+ }
213
+
214
+ /**
215
+ * Check if error is retryable
216
+ */
217
+ isRetryable(categorizedError: CategorizedError): boolean {
218
+ return [ErrorCategory.NETWORK, ErrorCategory.RATE_LIMIT].includes(categorizedError.category);
219
+ }
220
+
221
+ /**
222
+ * Get recommended retry delay in milliseconds
223
+ */
224
+ getRetryDelay(categorizedError: CategorizedError): number {
225
+ switch (categorizedError.category) {
226
+ case ErrorCategory.RATE_LIMIT:
227
+ return 60000; // 1 minute
228
+ case ErrorCategory.NETWORK:
229
+ return 5000; // 5 seconds
230
+ default:
231
+ return 0; // Not retryable
232
+ }
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Create a categorized error from an exception
238
+ */
239
+ export function categorizeError(error: Error, context?: Record<string, unknown>): CategorizedError {
240
+ const categorizer = new ErrorCategorizer();
241
+ return categorizer.categorize(error, context);
242
+ }
243
+
244
+ /**
245
+ * Format error with remediation steps
246
+ */
247
+ export function formatError(error: Error, context?: Record<string, unknown>): string {
248
+ const categorizer = new ErrorCategorizer();
249
+ const categorized = categorizer.categorize(error, context);
250
+ return categorizer.format(categorized);
251
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Action Input Parsing
3
+ * Handles parsing and validation of GitHub Action inputs
4
+ */
5
+
6
+ import * as core from '@actions/core';
7
+
8
+ export interface GenerateActionInputs {
9
+ repoPath: string;
10
+ llmProvider: 'github-copilot' | 'claude' | 'openai';
11
+ llmModel?: string;
12
+ llmApiKey?: string;
13
+ manifestPath: string;
14
+ enableDebug: boolean;
15
+ }
16
+
17
+ export interface UpdateActionInputs {
18
+ repoPath: string;
19
+ manifestPath: string;
20
+ commits: string[]; // Commit SHAs to analyze
21
+ }
22
+
23
+ export interface CheckActionInputs {
24
+ manifestPath: string;
25
+ createIssues: boolean;
26
+ issueLabels: string[];
27
+ }
28
+
29
+ /**
30
+ * Parse inputs for the generate action
31
+ */
32
+ export function parseGenerateInputs(): GenerateActionInputs {
33
+ const llmModelInput = core.getInput('llm_model');
34
+ const llmApiKeyInput =
35
+ core.getInput('llm_api_key') || process.env['GITHUB_TOKEN'] || process.env['OPENAI_API_KEY'];
36
+
37
+ return {
38
+ repoPath: core.getInput('repo_path') || process.cwd(),
39
+ llmProvider: (core.getInput('llm_provider') || 'github-copilot') as 'github-copilot',
40
+ ...(llmModelInput && { llmModel: llmModelInput }),
41
+ ...(llmApiKeyInput && { llmApiKey: llmApiKeyInput }),
42
+ manifestPath: core.getInput('manifest_path') || '.dependabit/manifest.json',
43
+ enableDebug: core.getInput('debug') === 'true'
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Parse inputs for the update action
49
+ */
50
+ export function parseUpdateInputs(): UpdateActionInputs {
51
+ const commitsInput = core.getInput('commits');
52
+ const commits = commitsInput ? commitsInput.split(',').map((c) => c.trim()) : [];
53
+
54
+ return {
55
+ repoPath: core.getInput('repo_path') || process.cwd(),
56
+ manifestPath: core.getInput('manifest_path') || '.dependabit/manifest.json',
57
+ commits
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Parse inputs for the check action
63
+ */
64
+ export function parseCheckInputs(): CheckActionInputs {
65
+ const labelsInput = core.getInput('issue_labels');
66
+ const labels = labelsInput
67
+ ? labelsInput.split(',').map((l) => l.trim())
68
+ : ['dependabit', 'dependency-update'];
69
+
70
+ return {
71
+ manifestPath: core.getInput('manifest_path') || '.dependabit/manifest.json',
72
+ createIssues: core.getBooleanInput('create_issues') !== false,
73
+ issueLabels: labels
74
+ };
75
+ }