@juspay/neurolink 8.32.0 → 8.34.0

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 (39) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +284 -75
  3. package/dist/action/actionExecutor.d.ts +29 -0
  4. package/dist/action/actionExecutor.js +290 -0
  5. package/dist/action/actionInputs.d.ts +25 -0
  6. package/dist/action/actionInputs.js +293 -0
  7. package/dist/action/githubIntegration.d.ts +21 -0
  8. package/dist/action/githubIntegration.js +187 -0
  9. package/dist/action/index.d.ts +8 -0
  10. package/dist/action/index.js +11 -0
  11. package/dist/index.d.ts +145 -13
  12. package/dist/index.js +145 -13
  13. package/dist/lib/action/actionExecutor.d.ts +29 -0
  14. package/dist/lib/action/actionExecutor.js +291 -0
  15. package/dist/lib/action/actionInputs.d.ts +25 -0
  16. package/dist/lib/action/actionInputs.js +294 -0
  17. package/dist/lib/action/githubIntegration.d.ts +21 -0
  18. package/dist/lib/action/githubIntegration.js +188 -0
  19. package/dist/lib/action/index.d.ts +8 -0
  20. package/dist/lib/action/index.js +12 -0
  21. package/dist/lib/index.d.ts +145 -13
  22. package/dist/lib/index.js +145 -13
  23. package/dist/lib/mcp/externalServerManager.js +41 -7
  24. package/dist/lib/neurolink.d.ts +172 -0
  25. package/dist/lib/neurolink.js +172 -0
  26. package/dist/lib/types/actionTypes.d.ts +205 -0
  27. package/dist/lib/types/actionTypes.js +7 -0
  28. package/dist/lib/types/index.d.ts +1 -0
  29. package/dist/lib/utils/errorHandling.d.ts +8 -0
  30. package/dist/lib/utils/errorHandling.js +29 -0
  31. package/dist/mcp/externalServerManager.js +41 -7
  32. package/dist/neurolink.d.ts +172 -0
  33. package/dist/neurolink.js +172 -0
  34. package/dist/types/actionTypes.d.ts +205 -0
  35. package/dist/types/actionTypes.js +6 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/utils/errorHandling.d.ts +8 -0
  38. package/dist/utils/errorHandling.js +29 -0
  39. package/package.json +11 -3
@@ -0,0 +1,291 @@
1
+ // src/lib/action/actionExecutor.ts
2
+ /**
3
+ * CLI execution for GitHub Action
4
+ * @module action/actionExecutor
5
+ */
6
+ import * as exec from "@actions/exec";
7
+ import * as core from "@actions/core";
8
+ import * as fs from "fs";
9
+ import * as path from "path";
10
+ import { buildEnvironmentVariables } from "./actionInputs.js";
11
+ import { withTimeout } from "../utils/errorHandling.js";
12
+ /** Default timeout for CLI execution (5 minutes) */
13
+ const DEFAULT_EXECUTION_TIMEOUT_MS = 300000;
14
+ /**
15
+ * Transform CLI token usage format to action format
16
+ */
17
+ function transformTokenUsage(cliUsage) {
18
+ if (!cliUsage) {
19
+ return undefined;
20
+ }
21
+ return {
22
+ promptTokens: cliUsage.input,
23
+ completionTokens: cliUsage.output,
24
+ totalTokens: cliUsage.total,
25
+ };
26
+ }
27
+ /**
28
+ * Transform CLI evaluation format to action format (scale 1-10 to 0-100)
29
+ */
30
+ function transformEvaluation(cliEval) {
31
+ if (!cliEval) {
32
+ return undefined;
33
+ }
34
+ return {
35
+ overallScore: cliEval.overall * 10, // Scale to 0-100
36
+ relevance: cliEval.relevance,
37
+ accuracy: cliEval.accuracy,
38
+ completeness: cliEval.completeness,
39
+ };
40
+ }
41
+ /**
42
+ * Transform CLI response to action result format
43
+ */
44
+ export function transformCliResponse(cliResponse) {
45
+ return {
46
+ response: cliResponse.content,
47
+ responseJson: cliResponse,
48
+ // Use top-level provider/model if available, otherwise fallback to analytics
49
+ provider: cliResponse.provider || cliResponse.analytics?.provider,
50
+ model: cliResponse.model || cliResponse.analytics?.model,
51
+ usage: transformTokenUsage(cliResponse.usage),
52
+ cost: cliResponse.analytics?.cost,
53
+ executionTime: cliResponse.responseTime,
54
+ evaluation: transformEvaluation(cliResponse.evaluation),
55
+ };
56
+ }
57
+ /**
58
+ * Build CLI arguments from action inputs (using verified camelCase flags)
59
+ */
60
+ export function buildCliArgs(inputs) {
61
+ const args = [inputs.command, inputs.prompt];
62
+ // Provider & Model
63
+ if (inputs.provider && inputs.provider !== "auto") {
64
+ args.push("--provider", inputs.provider);
65
+ }
66
+ if (inputs.model) {
67
+ args.push("--model", inputs.model);
68
+ }
69
+ // Generation parameters (camelCase flags!)
70
+ if (inputs.temperature !== undefined) {
71
+ args.push("--temperature", inputs.temperature.toString());
72
+ }
73
+ if (inputs.maxTokens !== undefined) {
74
+ args.push("--maxTokens", inputs.maxTokens.toString()); // NOT --max-tokens
75
+ }
76
+ if (inputs.systemPrompt) {
77
+ args.push("--system", inputs.systemPrompt);
78
+ }
79
+ // Output format (always JSON for parsing)
80
+ args.push("--format", "json");
81
+ args.push("--quiet");
82
+ args.push("--noColor");
83
+ // Multimodal inputs
84
+ const { multimodal } = inputs;
85
+ if (multimodal.imagePaths) {
86
+ for (const img of multimodal.imagePaths) {
87
+ args.push("--image", img);
88
+ }
89
+ }
90
+ if (multimodal.pdfPaths) {
91
+ for (const pdf of multimodal.pdfPaths) {
92
+ args.push("--pdf", pdf);
93
+ }
94
+ }
95
+ if (multimodal.csvPaths) {
96
+ for (const csv of multimodal.csvPaths) {
97
+ args.push("--csv", csv);
98
+ }
99
+ }
100
+ if (multimodal.videoPaths) {
101
+ for (const video of multimodal.videoPaths) {
102
+ args.push("--video", video);
103
+ }
104
+ }
105
+ // Extended thinking (camelCase flags!)
106
+ if (inputs.thinking.enabled) {
107
+ args.push("--thinking");
108
+ args.push("--thinkingLevel", inputs.thinking.level); // NOT --thinking-level
109
+ args.push("--thinkingBudget", inputs.thinking.budget.toString()); // NOT --thinking-budget
110
+ }
111
+ // Features (camelCase flags!)
112
+ if (inputs.enableAnalytics) {
113
+ args.push("--enableAnalytics"); // NOT --enable-analytics
114
+ }
115
+ if (inputs.enableEvaluation) {
116
+ args.push("--enableEvaluation"); // NOT --enable-evaluation
117
+ }
118
+ // Timeout
119
+ if (inputs.timeout) {
120
+ args.push("--timeout", inputs.timeout.toString());
121
+ }
122
+ // Output file
123
+ if (inputs.outputFile) {
124
+ args.push("--output", inputs.outputFile);
125
+ }
126
+ // Debug
127
+ if (inputs.debug) {
128
+ args.push("--debug");
129
+ }
130
+ return args;
131
+ }
132
+ /**
133
+ * Install NeuroLink CLI
134
+ */
135
+ export async function installNeurolink(version) {
136
+ core.info(`Installing @juspay/neurolink@${version}...`);
137
+ const installArgs = version === "latest"
138
+ ? ["install", "-g", "@juspay/neurolink"]
139
+ : ["install", "-g", `@juspay/neurolink@${version}`];
140
+ await exec.exec("npm", installArgs, {
141
+ silent: !core.isDebug(),
142
+ });
143
+ core.info("NeuroLink CLI installed successfully");
144
+ }
145
+ /**
146
+ * Execute NeuroLink CLI command
147
+ * @param args - CLI arguments
148
+ * @param env - Environment variables
149
+ * @param workingDirectory - Working directory for execution
150
+ * @param timeout - Timeout in milliseconds (defaults to 5 minutes)
151
+ */
152
+ export async function executeNeurolink(args, env, workingDirectory, timeout = DEFAULT_EXECUTION_TIMEOUT_MS) {
153
+ const startTime = Date.now();
154
+ try {
155
+ // Filter out undefined values from process.env
156
+ const processEnv = {};
157
+ for (const [key, value] of Object.entries(process.env)) {
158
+ if (value !== undefined) {
159
+ processEnv[key] = value;
160
+ }
161
+ }
162
+ const execPromise = exec.getExecOutput("neurolink", args, {
163
+ cwd: workingDirectory,
164
+ env: { ...processEnv, ...env },
165
+ silent: false,
166
+ ignoreReturnCode: true,
167
+ });
168
+ // Wrap execution with timeout protection
169
+ const { exitCode, stdout, stderr } = await withTimeout(execPromise, timeout, new Error(`CLI execution timed out after ${timeout}ms. Consider increasing the timeout parameter.`));
170
+ const executionTime = Date.now() - startTime;
171
+ if (exitCode !== 0) {
172
+ return {
173
+ success: false,
174
+ response: "",
175
+ error: stderr || `CLI exited with code ${exitCode}`,
176
+ executionTime,
177
+ };
178
+ }
179
+ // Parse JSON output
180
+ try {
181
+ // The CLI output may have log lines before the JSON
182
+ // The CLI JSON response always has "content" as the first key
183
+ // Find the line that contains '{"content"' or '{ "content"' to locate JSON start
184
+ const lines = stdout.split("\n");
185
+ let jsonStartIndex = -1;
186
+ // Find the line that starts the JSON response object
187
+ // Look for pattern: line is "{" and next non-empty line has "content"
188
+ for (let i = 0; i < lines.length; i++) {
189
+ const trimmedLine = lines[i].trim();
190
+ if (trimmedLine === "{") {
191
+ // Check if next non-empty line contains "content"
192
+ for (let j = i + 1; j < lines.length && j < i + 3; j++) {
193
+ const nextLine = lines[j].trim();
194
+ if (nextLine.includes('"content"')) {
195
+ jsonStartIndex = i;
196
+ break;
197
+ }
198
+ }
199
+ if (jsonStartIndex !== -1) {
200
+ break;
201
+ }
202
+ }
203
+ }
204
+ core.debug(`JSON start line index: ${jsonStartIndex}`);
205
+ if (jsonStartIndex === -1) {
206
+ core.debug("No JSON found, returning raw stdout");
207
+ return {
208
+ success: true,
209
+ response: stdout.trim(),
210
+ executionTime,
211
+ };
212
+ }
213
+ // Extract JSON from that line onwards
214
+ const jsonStr = lines.slice(jsonStartIndex).join("\n").trim();
215
+ core.debug(`JSON string starts with: ${jsonStr.substring(0, 50)}`);
216
+ const cliResponse = JSON.parse(jsonStr);
217
+ core.debug(`Parsed CLI response keys: ${Object.keys(cliResponse).join(", ")}`);
218
+ core.debug(`cliResponse.content: ${cliResponse.content?.substring(0, 50)}`);
219
+ core.debug(`cliResponse.provider: ${cliResponse.provider}`);
220
+ const transformed = transformCliResponse(cliResponse);
221
+ core.debug(`Transformed response: ${transformed.response?.substring(0, 50)}`);
222
+ core.debug(`Transformed provider: ${transformed.provider}`);
223
+ return {
224
+ success: true,
225
+ ...transformed,
226
+ executionTime: transformed.executionTime || executionTime,
227
+ };
228
+ }
229
+ catch (parseError) {
230
+ // If not JSON, return raw output
231
+ core.debug(`JSON parse error: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
232
+ return {
233
+ success: true,
234
+ response: stdout.trim(),
235
+ executionTime,
236
+ };
237
+ }
238
+ }
239
+ catch (error) {
240
+ return {
241
+ success: false,
242
+ response: "",
243
+ error: error instanceof Error ? error.message : String(error),
244
+ executionTime: Date.now() - startTime,
245
+ };
246
+ }
247
+ }
248
+ /**
249
+ * Run complete NeuroLink action
250
+ */
251
+ export async function runNeurolink(inputs) {
252
+ let credPath;
253
+ try {
254
+ // Install CLI
255
+ await installNeurolink(inputs.neurolinkVersion);
256
+ // Build environment
257
+ const env = buildEnvironmentVariables(inputs);
258
+ // Handle Google Cloud credentials (base64 decode)
259
+ if (inputs.googleCloudConfig.googleApplicationCredentials) {
260
+ const decoded = Buffer.from(inputs.googleCloudConfig.googleApplicationCredentials, "base64").toString("utf-8");
261
+ credPath = path.join(process.env.RUNNER_TEMP || "/tmp", `vertex-credentials-${process.pid}-${Date.now()}.json`);
262
+ fs.writeFileSync(credPath, decoded, { mode: 0o600 });
263
+ env.GOOGLE_APPLICATION_CREDENTIALS = credPath;
264
+ }
265
+ // Build CLI arguments
266
+ const args = buildCliArgs(inputs);
267
+ core.info(`Executing: neurolink ${args.join(" ")}`);
268
+ if (inputs.debug) {
269
+ core.debug(`Working directory: ${inputs.workingDirectory}`);
270
+ core.debug(`Environment keys: ${Object.keys(env)
271
+ .filter((k) => k.includes("API") || k.includes("KEY"))
272
+ .join(", ")}`);
273
+ }
274
+ // Execute with timeout (use input timeout or default)
275
+ const executionTimeout = inputs.timeout || DEFAULT_EXECUTION_TIMEOUT_MS;
276
+ return await executeNeurolink(args, env, inputs.workingDirectory, executionTimeout);
277
+ }
278
+ finally {
279
+ // Clean up credential file
280
+ if (credPath && fs.existsSync(credPath)) {
281
+ try {
282
+ fs.unlinkSync(credPath);
283
+ core.debug("Cleaned up temporary credentials file");
284
+ }
285
+ catch {
286
+ // Ignore cleanup errors
287
+ }
288
+ }
289
+ }
290
+ }
291
+ //# sourceMappingURL=actionExecutor.js.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * GitHub Action input parsing and validation
3
+ * @module action/actionInputs
4
+ */
5
+ import type { ActionInputs, ActionProviderKeys, ActionInputValidation, ActionAWSConfig, ActionGoogleCloudConfig } from "../types/actionTypes.js";
6
+ /**
7
+ * Mask all secrets in logs
8
+ */
9
+ export declare function maskSecrets(inputs: ActionInputs): void;
10
+ /**
11
+ * Validate that provider has required API key
12
+ */
13
+ export declare function validateProviderKey(provider: string, keys: Partial<ActionProviderKeys>, awsConfig?: Partial<ActionAWSConfig>, googleConfig?: Partial<ActionGoogleCloudConfig>): boolean;
14
+ /**
15
+ * Parse all action inputs from GitHub Action context
16
+ */
17
+ export declare function parseActionInputs(): ActionInputs;
18
+ /**
19
+ * Build environment variables from action inputs
20
+ */
21
+ export declare function buildEnvironmentVariables(inputs: ActionInputs): Record<string, string>;
22
+ /**
23
+ * Validate all action inputs
24
+ */
25
+ export declare function validateActionInputs(inputs: ActionInputs): ActionInputValidation;
@@ -0,0 +1,294 @@
1
+ // src/lib/action/actionInputs.ts
2
+ /**
3
+ * GitHub Action input parsing and validation
4
+ * @module action/actionInputs
5
+ */
6
+ import * as core from "@actions/core";
7
+ import { AIProviderName } from "../constants/enums.js";
8
+ import { ErrorFactory } from "../utils/errorHandling.js";
9
+ const PROVIDER_KEY_MAP = {
10
+ [AIProviderName.OPENAI]: ["openaiApiKey"],
11
+ [AIProviderName.ANTHROPIC]: ["anthropicApiKey"],
12
+ [AIProviderName.GOOGLE_AI]: ["googleAiApiKey"],
13
+ [AIProviderName.VERTEX]: ["googleVertexProject"],
14
+ [AIProviderName.BEDROCK]: ["awsAccessKeyId", "awsSecretAccessKey"],
15
+ [AIProviderName.AZURE]: ["azureOpenaiApiKey", "azureOpenaiEndpoint"],
16
+ [AIProviderName.MISTRAL]: ["mistralApiKey"],
17
+ [AIProviderName.HUGGINGFACE]: ["huggingfaceApiKey"],
18
+ [AIProviderName.OPENROUTER]: ["openrouterApiKey"],
19
+ [AIProviderName.LITELLM]: ["litellmApiKey", "litellmBaseUrl"],
20
+ [AIProviderName.SAGEMAKER]: ["awsAccessKeyId", "awsSecretAccessKey"],
21
+ [AIProviderName.OPENAI_COMPATIBLE]: [
22
+ "openaiCompatibleApiKey",
23
+ "openaiCompatibleBaseUrl",
24
+ ],
25
+ };
26
+ /**
27
+ * Parse comma-separated paths into array
28
+ */
29
+ function parsePathList(input) {
30
+ if (!input) {
31
+ return undefined;
32
+ }
33
+ return input
34
+ .split(",")
35
+ .map((p) => p.trim())
36
+ .filter(Boolean);
37
+ }
38
+ /**
39
+ * Parse and validate a numeric input, throwing if NaN
40
+ */
41
+ function parseNumericInput(inputName, rawValue, defaultValue, parseFunction, radix) {
42
+ if (!rawValue) {
43
+ return defaultValue;
44
+ }
45
+ const parsed = radix !== undefined
46
+ ? parseFunction(rawValue, radix)
47
+ : parseFunction(rawValue);
48
+ if (isNaN(parsed)) {
49
+ throw ErrorFactory.invalidConfiguration(inputName, `expected a valid number but received "${rawValue}"`);
50
+ }
51
+ return parsed;
52
+ }
53
+ /**
54
+ * Mask all secrets in logs
55
+ */
56
+ export function maskSecrets(inputs) {
57
+ const secrets = [
58
+ inputs.providerKeys.openaiApiKey,
59
+ inputs.providerKeys.anthropicApiKey,
60
+ inputs.providerKeys.googleAiApiKey,
61
+ inputs.providerKeys.azureOpenaiApiKey,
62
+ inputs.providerKeys.mistralApiKey,
63
+ inputs.providerKeys.huggingfaceApiKey,
64
+ inputs.providerKeys.openrouterApiKey,
65
+ inputs.providerKeys.litellmApiKey,
66
+ inputs.providerKeys.openaiCompatibleApiKey,
67
+ inputs.awsConfig.awsAccessKeyId,
68
+ inputs.awsConfig.awsSecretAccessKey,
69
+ inputs.awsConfig.awsSessionToken,
70
+ inputs.googleCloudConfig.googleApplicationCredentials,
71
+ inputs.githubToken,
72
+ ];
73
+ secrets
74
+ .filter((s) => Boolean(s))
75
+ .forEach((secret) => core.setSecret(secret));
76
+ }
77
+ /**
78
+ * Validate that provider has required API key
79
+ */
80
+ export function validateProviderKey(provider, keys, awsConfig, googleConfig) {
81
+ // These providers don't require API keys
82
+ if (provider === "auto" || provider === "ollama") {
83
+ return true;
84
+ }
85
+ const requiredKeys = PROVIDER_KEY_MAP[provider];
86
+ if (!requiredKeys) {
87
+ // Log warning for unknown provider, but don't fail (allows new providers)
88
+ core.warning(`Unknown provider "${provider}" - skipping key validation`);
89
+ return true;
90
+ }
91
+ // Check keys across all config objects
92
+ return requiredKeys.every((key) => {
93
+ const keyValue = keys[key] ||
94
+ awsConfig?.[key] ||
95
+ googleConfig?.[key];
96
+ return !!keyValue;
97
+ });
98
+ }
99
+ /**
100
+ * Parse all action inputs from GitHub Action context
101
+ */
102
+ export function parseActionInputs() {
103
+ const prompt = core.getInput("prompt", { required: true });
104
+ const provider = core.getInput("provider") || "auto";
105
+ // Parse provider keys (verified providers only)
106
+ const providerKeys = {
107
+ openaiApiKey: core.getInput("openai_api_key") || undefined,
108
+ anthropicApiKey: core.getInput("anthropic_api_key") || undefined,
109
+ googleAiApiKey: core.getInput("google_ai_api_key") || undefined,
110
+ azureOpenaiApiKey: core.getInput("azure_openai_api_key") || undefined,
111
+ azureOpenaiEndpoint: core.getInput("azure_openai_endpoint") || undefined,
112
+ azureOpenaiDeployment: core.getInput("azure_openai_deployment") || undefined,
113
+ mistralApiKey: core.getInput("mistral_api_key") || undefined,
114
+ huggingfaceApiKey: core.getInput("huggingface_api_key") || undefined,
115
+ openrouterApiKey: core.getInput("openrouter_api_key") || undefined,
116
+ litellmApiKey: core.getInput("litellm_api_key") || undefined,
117
+ litellmBaseUrl: core.getInput("litellm_base_url") || undefined,
118
+ openaiCompatibleApiKey: core.getInput("openai_compatible_api_key") || undefined,
119
+ openaiCompatibleBaseUrl: core.getInput("openai_compatible_base_url") || undefined,
120
+ };
121
+ // AWS config
122
+ const awsConfig = {
123
+ awsAccessKeyId: core.getInput("aws_access_key_id") || undefined,
124
+ awsSecretAccessKey: core.getInput("aws_secret_access_key") || undefined,
125
+ awsRegion: core.getInput("aws_region") || "us-east-1",
126
+ awsSessionToken: core.getInput("aws_session_token") || undefined,
127
+ bedrockModelId: core.getInput("bedrock_model_id") || undefined,
128
+ sagemakerEndpoint: core.getInput("sagemaker_endpoint") || undefined,
129
+ };
130
+ // Google Cloud config
131
+ const googleCloudConfig = {
132
+ googleVertexProject: core.getInput("google_vertex_project") || undefined,
133
+ googleVertexLocation: core.getInput("google_vertex_location") || "us-central1",
134
+ googleApplicationCredentials: core.getInput("google_application_credentials") || undefined,
135
+ };
136
+ // Validate provider has key
137
+ if (!validateProviderKey(provider, providerKeys, awsConfig, googleCloudConfig)) {
138
+ throw ErrorFactory.missingConfiguration(`API key for provider: ${provider}`);
139
+ }
140
+ return {
141
+ prompt,
142
+ provider: provider,
143
+ model: core.getInput("model") || undefined,
144
+ // Generation parameters
145
+ temperature: parseNumericInput("temperature", core.getInput("temperature"), 0.7, parseFloat),
146
+ maxTokens: parseNumericInput("max_tokens", core.getInput("max_tokens"), 4096, parseInt, 10),
147
+ systemPrompt: core.getInput("system_prompt") || undefined,
148
+ // Command
149
+ command: (core.getInput("command") || "generate"),
150
+ // Provider keys
151
+ providerKeys,
152
+ // AWS config
153
+ awsConfig,
154
+ // Google Cloud config
155
+ googleCloudConfig,
156
+ // Multimodal inputs
157
+ multimodal: {
158
+ imagePaths: parsePathList(core.getInput("image_paths")),
159
+ pdfPaths: parsePathList(core.getInput("pdf_paths")),
160
+ csvPaths: parsePathList(core.getInput("csv_paths")),
161
+ videoPaths: parsePathList(core.getInput("video_paths")),
162
+ },
163
+ // Extended thinking
164
+ thinking: {
165
+ enabled: core.getBooleanInput("thinking_enabled"),
166
+ level: (core.getInput("thinking_level") || "medium"),
167
+ budget: parseNumericInput("thinking_budget", core.getInput("thinking_budget"), 10000, parseInt, 10),
168
+ },
169
+ // Features (verified to exist in CLI)
170
+ enableAnalytics: core.getBooleanInput("enable_analytics"),
171
+ enableEvaluation: core.getBooleanInput("enable_evaluation"),
172
+ // Output
173
+ outputFormat: (core.getInput("output_format") || "text"),
174
+ outputFile: core.getInput("output_file") || undefined,
175
+ // MCP Tools
176
+ enableTools: core.getBooleanInput("enable_tools"),
177
+ mcpConfigPath: core.getInput("mcp_config_path") || undefined,
178
+ // GitHub Integration
179
+ postComment: core.getBooleanInput("post_comment"),
180
+ updateExistingComment: core.getBooleanInput("update_existing_comment"),
181
+ commentTag: core.getInput("comment_tag") || "neurolink-action",
182
+ githubToken: core.getInput("github_token") || process.env.GITHUB_TOKEN,
183
+ // Advanced
184
+ timeout: parseNumericInput("timeout", core.getInput("timeout"), 300, parseInt, 10),
185
+ debug: core.getBooleanInput("debug"),
186
+ neurolinkVersion: core.getInput("neurolink_version") || "latest",
187
+ workingDirectory: core.getInput("working_directory") || ".",
188
+ };
189
+ }
190
+ /**
191
+ * Build environment variables from action inputs
192
+ */
193
+ export function buildEnvironmentVariables(inputs) {
194
+ const env = {
195
+ CI: "true",
196
+ NEUROLINK_NON_INTERACTIVE: "true",
197
+ };
198
+ // Provider keys
199
+ const { providerKeys } = inputs;
200
+ if (providerKeys.openaiApiKey) {
201
+ env.OPENAI_API_KEY = providerKeys.openaiApiKey;
202
+ }
203
+ if (providerKeys.anthropicApiKey) {
204
+ env.ANTHROPIC_API_KEY = providerKeys.anthropicApiKey;
205
+ }
206
+ if (providerKeys.googleAiApiKey) {
207
+ env.GOOGLE_AI_API_KEY = providerKeys.googleAiApiKey;
208
+ }
209
+ if (providerKeys.azureOpenaiApiKey) {
210
+ env.AZURE_OPENAI_API_KEY = providerKeys.azureOpenaiApiKey;
211
+ }
212
+ if (providerKeys.azureOpenaiEndpoint) {
213
+ env.AZURE_OPENAI_ENDPOINT = providerKeys.azureOpenaiEndpoint;
214
+ }
215
+ if (providerKeys.azureOpenaiDeployment) {
216
+ env.AZURE_OPENAI_DEPLOYMENT = providerKeys.azureOpenaiDeployment;
217
+ }
218
+ if (providerKeys.mistralApiKey) {
219
+ env.MISTRAL_API_KEY = providerKeys.mistralApiKey;
220
+ }
221
+ if (providerKeys.huggingfaceApiKey) {
222
+ env.HUGGINGFACE_API_KEY = providerKeys.huggingfaceApiKey;
223
+ }
224
+ if (providerKeys.openrouterApiKey) {
225
+ env.OPENROUTER_API_KEY = providerKeys.openrouterApiKey;
226
+ }
227
+ if (providerKeys.litellmApiKey) {
228
+ env.LITELLM_API_KEY = providerKeys.litellmApiKey;
229
+ }
230
+ if (providerKeys.litellmBaseUrl) {
231
+ env.LITELLM_BASE_URL = providerKeys.litellmBaseUrl;
232
+ }
233
+ if (providerKeys.openaiCompatibleApiKey) {
234
+ env.OPENAI_COMPATIBLE_API_KEY = providerKeys.openaiCompatibleApiKey;
235
+ }
236
+ if (providerKeys.openaiCompatibleBaseUrl) {
237
+ env.OPENAI_COMPATIBLE_BASE_URL = providerKeys.openaiCompatibleBaseUrl;
238
+ }
239
+ // AWS
240
+ const { awsConfig } = inputs;
241
+ if (awsConfig.awsAccessKeyId) {
242
+ env.AWS_ACCESS_KEY_ID = awsConfig.awsAccessKeyId;
243
+ }
244
+ if (awsConfig.awsSecretAccessKey) {
245
+ env.AWS_SECRET_ACCESS_KEY = awsConfig.awsSecretAccessKey;
246
+ }
247
+ env.AWS_REGION = awsConfig.awsRegion;
248
+ if (awsConfig.awsSessionToken) {
249
+ env.AWS_SESSION_TOKEN = awsConfig.awsSessionToken;
250
+ }
251
+ if (awsConfig.bedrockModelId) {
252
+ env.BEDROCK_MODEL_ID = awsConfig.bedrockModelId;
253
+ }
254
+ if (awsConfig.sagemakerEndpoint) {
255
+ env.SAGEMAKER_DEFAULT_ENDPOINT = awsConfig.sagemakerEndpoint;
256
+ }
257
+ // Google Cloud
258
+ const { googleCloudConfig } = inputs;
259
+ if (googleCloudConfig.googleVertexProject) {
260
+ env.GOOGLE_VERTEX_PROJECT = googleCloudConfig.googleVertexProject;
261
+ }
262
+ env.GOOGLE_VERTEX_LOCATION = googleCloudConfig.googleVertexLocation;
263
+ // GitHub
264
+ if (inputs.githubToken) {
265
+ env.GITHUB_TOKEN = inputs.githubToken;
266
+ }
267
+ return env;
268
+ }
269
+ /**
270
+ * Validate all action inputs
271
+ */
272
+ export function validateActionInputs(inputs) {
273
+ const errors = [];
274
+ const warnings = [];
275
+ // Required fields
276
+ if (!inputs.prompt) {
277
+ errors.push("prompt is required");
278
+ }
279
+ // Temperature range
280
+ if (inputs.temperature < 0 || inputs.temperature > 2) {
281
+ warnings.push("temperature should be between 0 and 2");
282
+ }
283
+ // Thinking budget range
284
+ if (inputs.thinking.enabled &&
285
+ (inputs.thinking.budget < 5000 || inputs.thinking.budget > 100000)) {
286
+ warnings.push("thinking_budget should be between 5000 and 100000");
287
+ }
288
+ return {
289
+ valid: errors.length === 0,
290
+ errors,
291
+ warnings,
292
+ };
293
+ }
294
+ //# sourceMappingURL=actionInputs.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * GitHub API integration for comments, outputs, and job summary
3
+ * @module action/githubIntegration
4
+ */
5
+ import type { ActionInputs, ActionExecutionResult, ActionCommentResult, ActionOutput } from "../types/actionTypes.js";
6
+ /**
7
+ * Post result as comment on PR or issue
8
+ */
9
+ export declare function postResultComment(inputs: ActionInputs, result: ActionExecutionResult): Promise<ActionCommentResult>;
10
+ /**
11
+ * Write job summary
12
+ */
13
+ export declare function writeJobSummary(inputs: ActionInputs, result: ActionExecutionResult): Promise<void>;
14
+ /**
15
+ * Set all action outputs
16
+ */
17
+ export declare function setActionOutputs(result: ActionExecutionResult, commentResult?: ActionCommentResult): void;
18
+ /**
19
+ * Get all outputs as typed object (snake_case to match action.yml outputs)
20
+ */
21
+ export declare function getActionOutputs(result: ActionExecutionResult, commentResult?: ActionCommentResult): ActionOutput;