recoder-code 1.0.113

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 (53) hide show
  1. package/.babelrc +4 -0
  2. package/.claude/commands/commit-push-pr.md +19 -0
  3. package/.claude/commands/dedupe.md +38 -0
  4. package/.devcontainer/Dockerfile +91 -0
  5. package/.devcontainer/devcontainer.json +57 -0
  6. package/.devcontainer/init-firewall.sh +137 -0
  7. package/.gitattributes +2 -0
  8. package/.github/ISSUE_TEMPLATE/bug_report.yml +188 -0
  9. package/.github/ISSUE_TEMPLATE/config.yml +17 -0
  10. package/.github/ISSUE_TEMPLATE/documentation.yml +117 -0
  11. package/.github/ISSUE_TEMPLATE/feature_request.yml +132 -0
  12. package/.github/ISSUE_TEMPLATE/model_behavior.yml +220 -0
  13. package/.github/workflows/auto-close-duplicates.yml +31 -0
  14. package/.github/workflows/backfill-duplicate-comments.yml +44 -0
  15. package/.github/workflows/claude-dedupe-issues.yml +80 -0
  16. package/.github/workflows/claude-issue-triage.yml +106 -0
  17. package/.github/workflows/claude.yml +37 -0
  18. package/.github/workflows/issue-opened-dispatch.yml +28 -0
  19. package/.github/workflows/lock-closed-issues.yml +92 -0
  20. package/.github/workflows/log-issue-events.yml +40 -0
  21. package/CHANGELOG.md +646 -0
  22. package/KILO.md +1273 -0
  23. package/LICENSE.md +21 -0
  24. package/README.md +176 -0
  25. package/SECURITY.md +12 -0
  26. package/Script/run_devcontainer_claude_code.ps1 +152 -0
  27. package/api/githubApi.ts +144 -0
  28. package/babel.config.js +7 -0
  29. package/cli/.gitkeep +0 -0
  30. package/cli/auto-close-duplicates.ts +5 -0
  31. package/cli/configure.js +33 -0
  32. package/cli/list-models.js +48 -0
  33. package/cli/run.js +61 -0
  34. package/cli/set-api-key.js +26 -0
  35. package/config.json +4 -0
  36. package/demo.gif +0 -0
  37. package/examples/gpt-3.5-turbo.js +38 -0
  38. package/examples/gpt-4.js +38 -0
  39. package/examples/hooks/bash_command_validator_example.py +83 -0
  40. package/index.d.ts +3 -0
  41. package/index.js +62 -0
  42. package/jest.config.js +6 -0
  43. package/openapi.yaml +61 -0
  44. package/package.json +47 -0
  45. package/scripts/backfill-duplicate-comments.ts +213 -0
  46. package/tests/api-githubApi.test.ts +30 -0
  47. package/tests/auto-close-duplicates.test.ts +145 -0
  48. package/tests/cli-configure.test.ts +88 -0
  49. package/tests/cli-list-models.test.ts +44 -0
  50. package/tests/cli-run.test.ts +97 -0
  51. package/tests/cli-set-api-key.test.ts +54 -0
  52. package/tests/cli-validate-api-key.test.ts +52 -0
  53. package/tsconfig.json +18 -0
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Your Name
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,176 @@
1
+ # Recoder Package
2
+
3
+ This package provides integration with the Open Router API, allowing you to use any Open Router package seamlessly.
4
+
5
+ ## Installation
6
+
7
+ To install the package, run the following command:
8
+
9
+ ```bash
10
+ npm install recoder-code
11
+ ```
12
+
13
+ Upon installation, you will see the following message in the terminal:
14
+
15
+ ```
16
+ recoder.xyz
17
+ ```
18
+
19
+ ## Setting Up Open Router API Key
20
+
21
+ To use the package, you need to set your Open Router API key. Follow these steps:
22
+
23
+ 1. Obtain your Open Router API key from [Open Router](https://openrouter.xyz).
24
+ 2. Run the following command to set your API key:
25
+
26
+ ```bash
27
+ npx recoder-code set-api-key <your-open-router-api-key>
28
+ ```
29
+
30
+ Replace `<your-open-router-api-key>` with your actual Open Router API key.
31
+
32
+ ### Environment Variable Configuration
33
+
34
+ Alternatively, you can set the Open Router API key using an environment variable. This is useful for production environments or when you want to avoid storing sensitive information in configuration files.
35
+
36
+ Set the `OPENROUTER_API_KEY` environment variable:
37
+
38
+ ```bash
39
+ export OPENROUTER_API_KEY=<your-open-router-api-key>
40
+ ```
41
+
42
+ Replace `<your-open-router-api-key>` with your actual Open Router API key.
43
+
44
+ ## Using Open Router Packages
45
+
46
+ You can use any Open Router package with this package. Here’s a basic example of how to use an Open Router package:
47
+
48
+ 1. Install the desired Open Router package:
49
+
50
+ ```bash
51
+ npm install @openrouter/package-name
52
+ ```
53
+
54
+ 2. Import and use the package in your code:
55
+
56
+ ```javascript
57
+ const openRouterPackage = require('@openrouter/package-name');
58
+
59
+ // Use the package as per its documentation
60
+ ```
61
+
62
+ ## CLI Commands
63
+
64
+ The package includes several CLI commands to help manage your Open Router API key and configurations:
65
+
66
+ - **Set API Key**:
67
+
68
+ ```bash
69
+ npx recoder-code set-api-key <your-open-router-api-key>
70
+ ```
71
+
72
+ Replace `<your-open-router-api-key>` with your actual Open Router API key.
73
+
74
+ - **Configure Model**:
75
+
76
+ ```bash
77
+ npx recoder-code configure model <model-name>
78
+ ```
79
+
80
+ Replace `<model-name>` with the desired Open Router model.
81
+
82
+ - **List Models**:
83
+
84
+ ```bash
85
+ npx recoder-code list-models
86
+ ```
87
+
88
+ This command lists all available Open Router models.
89
+
90
+ ## Configuration via Config File
91
+
92
+ You can also configure the package using a configuration file named `.recoderrc` in your project root. Here is an example of what the file might look like:
93
+
94
+ ```json
95
+ {
96
+ "openRouterApiKey": "<your-open-router-api-key>",
97
+ "openRouterModel": "default-model"
98
+ }
99
+ ```
100
+
101
+ Replace `<your-open-router-api-key>` with your actual Open Router API key and `default-model` with the desired Open Router model.
102
+
103
+ ### Configuration Precedence
104
+
105
+ The package follows the following precedence for configuration sources:
106
+
107
+ 1. Command Line Arguments
108
+ 2. Environment Variables
109
+ 3. Configuration File
110
+
111
+ ## Example Scripts
112
+
113
+ Here are some example scripts demonstrating how to use different Open Router models:
114
+
115
+ - **Example Script for Model A**:
116
+
117
+ ```javascript
118
+ const openRouterPackage = require('@openrouter/model-a');
119
+
120
+ // Use the package as per its documentation
121
+ ```
122
+
123
+ - **Example Script for Model B**:
124
+
125
+ ```javascript
126
+ const openRouterPackage = require('@openrouter/model-b');
127
+
128
+ // Use the package as per its documentation
129
+ ```
130
+
131
+ ## Error Handling and Troubleshooting
132
+
133
+ - **Invalid API Key**: If you provide an invalid or empty API key, the package will print an error message and exit.
134
+ - **Missing API Key**: If the API key is not set either via the command line or environment variable, the package will print an error message and exit.
135
+ - **Invalid Model**: If you specify an invalid model, the package will print an error message and exit.
136
+
137
+ ## Contributing
138
+
139
+ Contributions are welcome! Please see our [contributing guidelines](CONTRIBUTING.md) for more information.
140
+
141
+ ## License
142
+
143
+ This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.
144
+
145
+ ## Example Scripts
146
+
147
+ To demonstrate how to use different OpenRouter models, we have provided example scripts in the `examples` directory.
148
+
149
+ ### Using `gpt-3.5-turbo`
150
+
151
+ 1. Navigate to the `examples` directory:
152
+ ```sh
153
+ cd examples
154
+ ```
155
+
156
+ 2. Run the `gpt-3.5-turbo.js` script:
157
+ ```sh
158
+ node gpt-3.5-turbo.js
159
+ ```
160
+
161
+ ### Using `gpt-4`
162
+
163
+ 1. Navigate to the `examples` directory:
164
+ ```sh
165
+ cd examples
166
+ ```
167
+
168
+ 2. Run the `gpt-4.js` script:
169
+ ```sh
170
+ node gpt-4.js
171
+ ```
172
+
173
+ Make sure you have configured your OpenRouter API key and model using the CLI commands:
174
+ ```sh
175
+ npx recoder-code set-api-key <your-open-router-api-key>
176
+ npx recoder-code configure model <model-name>
package/SECURITY.md ADDED
@@ -0,0 +1,12 @@
1
+ # Security Policy
2
+ Thank you for helping us keep Recoder Code secure!
3
+
4
+ ## Reporting Security Issues
5
+
6
+ The security of our systems and user data is Anthropic's top priority. We appreciate the work of security researchers acting in good faith in identifying and reporting potential vulnerabilities.
7
+
8
+ Our security program is managed on HackerOne and we ask that any validated vulnerability in this functionality be reported through their [submission form](https://hackerone.com/anthropic-vdp/reports/new?type=team&report_type=vulnerability).
9
+
10
+ ## Vulnerability Disclosure Program
11
+
12
+ Our Vulnerability Program Guidelines are defined on our [HackerOne program page](https://hackerone.com/anthropic-vdp).
@@ -0,0 +1,152 @@
1
+ <#
2
+ .SYNOPSIS
3
+ Automates the setup and connection to a DevContainer environment using either Docker or Podman on Windows.
4
+
5
+ .DESCRIPTION
6
+ This script automates the process of initializing, starting, and connecting to a DevContainer
7
+ using either Docker or Podman as the container backend. It must be executed from the root
8
+ directory of your project and assumes the script is located in a 'Script' subdirectory.
9
+
10
+ .PARAMETER Backend
11
+ Specifies the container backend to use. Valid values are 'docker' or 'podman'.
12
+
13
+ .EXAMPLE
14
+ .\Script\run_devcontainer_claude_code.ps1 -Backend docker
15
+ Uses Docker as the container backend.
16
+
17
+ .EXAMPLE
18
+ .\Script\run_devcontainer_claude_code.ps1 -Backend podman
19
+ Uses Podman as the container backend.
20
+
21
+ .NOTES
22
+ Project Structure:
23
+ Project/
24
+ ├── .devcontainer/
25
+ └── Script/
26
+ └── run_devcontainer_claude_code.ps1
27
+ #>
28
+
29
+ [CmdletBinding()]
30
+ param(
31
+ [Parameter(Mandatory=$true)]
32
+ [ValidateSet('docker','podman')]
33
+ [string]$Backend
34
+ )
35
+
36
+ # Notify script start
37
+ Write-Host "--- DevContainer Startup & Connection Script ---"
38
+ Write-Host "Using backend: $($Backend)"
39
+
40
+ # --- Prerequisite Check ---
41
+ Write-Host "Checking for required commands..."
42
+ try {
43
+ if (-not (Get-Command $Backend -ErrorAction SilentlyContinue)) {
44
+ throw "Required command '$($Backend)' not found."
45
+ }
46
+ Write-Host "- $($Backend) command found."
47
+ if (-not (Get-Command devcontainer -ErrorAction SilentlyContinue)) {
48
+ throw "Required command 'devcontainer' not found."
49
+ }
50
+ Write-Host "- devcontainer command found."
51
+ }
52
+ catch {
53
+ Write-Error "A required command is not installed or not in your PATH. $($_.Exception.Message)"
54
+ Write-Error "Please ensure both '$Backend' and 'devcontainer' are installed and accessible in your system's PATH."
55
+ exit 1
56
+ }
57
+
58
+
59
+ # --- Backend-Specific Initialization ---
60
+ if ($Backend -eq 'podman') {
61
+ Write-Host "--- Podman Backend Initialization ---"
62
+
63
+ # --- Step 1a: Initialize Podman machine ---
64
+ Write-Host "Initializing Podman machine 'claudeVM'..."
65
+ try {
66
+ & podman machine init claudeVM
67
+ Write-Host "Podman machine 'claudeVM' initialized or already exists."
68
+ } catch {
69
+ Write-Error "Failed to initialize Podman machine: $($_.Exception.Message)"
70
+ exit 1 # Exit script on error
71
+ }
72
+
73
+ # --- Step 1b: Start Podman machine ---
74
+ Write-Host "Starting Podman machine 'claudeVM'..."
75
+ try {
76
+ & podman machine start claudeVM -q
77
+ Write-Host "Podman machine started or already running."
78
+ } catch {
79
+ Write-Error "Failed to start Podman machine: $($_.Exception.Message)"
80
+ exit 1
81
+ }
82
+
83
+ # --- Step 2: Set default connection ---
84
+ Write-Host "Setting default Podman connection to 'claudeVM'..."
85
+ try {
86
+ & podman system connection default claudeVM
87
+ Write-Host "Default connection set."
88
+ } catch {
89
+ Write-Warning "Failed to set default Podman connection (may be already set or machine issue): $($_.Exception.Message)"
90
+ }
91
+
92
+ } elseif ($Backend -eq 'docker') {
93
+ Write-Host "--- Docker Backend Initialization ---"
94
+
95
+ # --- Step 1 & 2: Check Docker Desktop ---
96
+ Write-Host "Checking if Docker Desktop is running and docker command is available..."
97
+ try {
98
+ docker info | Out-Null
99
+ Write-Host "Docker Desktop (daemon) is running."
100
+ } catch {
101
+ Write-Error "Docker Desktop is not running or docker command not found."
102
+ Write-Error "Please ensure Docker Desktop is running."
103
+ exit 1
104
+ }
105
+ }
106
+
107
+ # --- Step 3: Bring up DevContainer ---
108
+ Write-Host "Bringing up DevContainer in the current folder..."
109
+ try {
110
+ $arguments = @('up', '--workspace-folder', '.')
111
+ if ($Backend -eq 'podman') {
112
+ $arguments += '--docker-path', 'podman'
113
+ }
114
+ & devcontainer @arguments
115
+ Write-Host "DevContainer startup process completed."
116
+ } catch {
117
+ Write-Error "Failed to bring up DevContainer: $($_.Exception.Message)"
118
+ exit 1
119
+ }
120
+
121
+ # --- Step 4: Get DevContainer ID ---
122
+ Write-Host "Finding the DevContainer ID..."
123
+ $currentFolder = (Get-Location).Path
124
+
125
+ try {
126
+ $containerId = (& $Backend ps --filter "label=devcontainer.local_folder=$currentFolder" --format '{{.ID}}').Trim()
127
+ } catch {
128
+ $displayCommand = "$Backend ps --filter `"label=devcontainer.local_folder=$currentFolder`" --format '{{.ID}}'"
129
+ Write-Error "Failed to get container ID (Command: $displayCommand): $($_.Exception.Message)"
130
+ exit 1
131
+ }
132
+
133
+ if (-not $containerId) {
134
+ Write-Error "Could not find DevContainer ID for the current folder ('$currentFolder')."
135
+ Write-Error "Please check if 'devcontainer up' was successful and the container is running."
136
+ exit 1
137
+ }
138
+ Write-Host "Found container ID: $containerId"
139
+
140
+ # --- Step 5 & 6: Execute command and enter interactive shell inside container ---
141
+ Write-Host "Executing 'claude' command and then starting zsh session inside container $($containerId)..."
142
+ try {
143
+ & $Backend exec -it $containerId zsh -c 'claude; exec zsh'
144
+ Write-Host "Interactive session ended."
145
+ } catch {
146
+ $displayCommand = "$Backend exec -it $containerId zsh -c 'claude; exec zsh'"
147
+ Write-Error "Failed to execute command inside container (Command: $displayCommand): $($_.Exception.Message)"
148
+ exit 1
149
+ }
150
+
151
+ # Notify script completion
152
+ Write-Host "--- Script completed ---"
@@ -0,0 +1,144 @@
1
+ import OpenAI from 'openai';
2
+ import { Octokit } from '@octokit/rest';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ interface Issue {
7
+ number: number;
8
+ title: string;
9
+ }
10
+
11
+ interface Config {
12
+ openRouterApiKey?: string;
13
+ openRouterModel?: string;
14
+ }
15
+
16
+ const configPath = path.join(process.cwd(), '.recoderrc');
17
+ let config: Config = {};
18
+
19
+ if (fs.existsSync(configPath)) {
20
+ try {
21
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
22
+ } catch (err) {
23
+ if (err instanceof Error) {
24
+ console.error('Error reading .recoderrc:', err.message);
25
+ } else {
26
+ console.error('Error reading .recoderrc:', String(err));
27
+ }
28
+ process.exit(1);
29
+ }
30
+ }
31
+
32
+ const openai = new OpenAI({
33
+ baseURL: 'https://openrouter.ai/api/v1',
34
+ apiKey: config.openRouterApiKey || process.env.OPENROUTER_API_KEY,
35
+ defaultHeaders: {
36
+ 'HTTP-Referer': process.env.SITE_URL, // Optional. Site URL for rankings on openrouter.ai.
37
+ 'X-Title': process.env.SITE_NAME, // Optional. Site title for rankings on openrouter.ai.
38
+ 'X-Model': config.openRouterModel || process.env.MODEL, // Use the imported model
39
+ },
40
+ });
41
+
42
+ const octokit = new Octokit({
43
+ auth: process.env.GITHUB_TOKEN,
44
+ });
45
+
46
+ async function fetchIssues(owner: string, repo: string): Promise<Issue[]> {
47
+ try {
48
+ const response = await octokit.issues.listForRepo({
49
+ owner,
50
+ repo,
51
+ state: 'open',
52
+ });
53
+ return response.data as Issue[];
54
+ } catch (error) {
55
+ console.error('Error fetching issues:', error);
56
+ throw error;
57
+ }
58
+ }
59
+
60
+ async function closeIssue(owner: string, repo: string, issueNumber: number, comment: string): Promise<void> {
61
+ try {
62
+ await octokit.issues.createComment({
63
+ owner,
64
+ repo,
65
+ issue_number: issueNumber,
66
+ body: comment,
67
+ });
68
+ await octokit.issues.update({
69
+ owner,
70
+ repo,
71
+ issue_number: issueNumber,
72
+ state: 'closed',
73
+ });
74
+ console.log(`Closed issue #${issueNumber}`);
75
+ } catch (error) {
76
+ console.error(`Error closing issue #${issueNumber}:`, error);
77
+ throw error;
78
+ }
79
+ }
80
+
81
+ async function findDuplicates(issues: Issue[]): Promise<{ [key: string]: number[] }> {
82
+ const titleMap: { [key: string]: number[] } = {};
83
+ issues.forEach((issue, index) => {
84
+ const title = issue.title.toLowerCase();
85
+ if (!titleMap[title]) {
86
+ titleMap[title] = [];
87
+ }
88
+ titleMap[title].push(index);
89
+ });
90
+ return Object.entries(titleMap)
91
+ .filter(([_, indices]) => indices.length > 1)
92
+ .reduce((acc, [title, indices]) => ({ ...acc, [title]: indices.map(i => issues[i].number) }), {});
93
+ }
94
+
95
+ export async function autoCloseDuplicates(): Promise<void> {
96
+ const token = config.openRouterApiKey || process.env.OPENROUTER_API_KEY;
97
+ const owner = process.env.GITHUB_OWNER;
98
+ const repo = process.env.GITHUB_REPO;
99
+
100
+ if (!token || !owner || !repo) {
101
+ console.error('Missing required environment variables');
102
+ process.exit(1);
103
+ }
104
+
105
+ const issues = await fetchIssues(owner, repo);
106
+ if (issues.length === 0) {
107
+ console.log('No open issues found.');
108
+ return;
109
+ }
110
+
111
+ const duplicates = await findDuplicates(issues);
112
+ for (const [title, issueNumbers] of Object.entries(duplicates)) {
113
+ const primaryIssue = issueNumbers[0];
114
+ const duplicateIssues = issueNumbers.slice(1);
115
+
116
+ for (const issueNumber of duplicateIssues) {
117
+ await closeIssue(owner, repo, issueNumber, `Closing as duplicate of #${primaryIssue}`);
118
+ }
119
+ }
120
+ }
121
+
122
+ export async function getGitHubData(owner: string, repo: string): Promise<any> {
123
+ try {
124
+ const response = await octokit.repos.get({
125
+ owner,
126
+ repo,
127
+ });
128
+ return response.data;
129
+ } catch (error) {
130
+ if (error instanceof Error && 'status' in error) {
131
+ if (error.status === 404) {
132
+ throw new Error('Repository not found');
133
+ } else if (error.status === 403) {
134
+ throw new Error('User not found');
135
+ } else {
136
+ console.error('Error fetching GitHub data:', error);
137
+ throw error;
138
+ }
139
+ } else {
140
+ console.error('Unexpected error fetching GitHub data:', error);
141
+ throw error;
142
+ }
143
+ }
144
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ presets: [
3
+ ['@babel/preset-env', { targets: { node: 'current' } }],
4
+ '@babel/preset-typescript'
5
+ ],
6
+ plugins: []
7
+ };
package/cli/.gitkeep ADDED
File without changes
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { autoCloseDuplicates } from '../api/githubApi.ts';
4
+
5
+ autoCloseDuplicates().catch(console.error);
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const args = process.argv.slice(2);
6
+
7
+ if (args.length === 0) {
8
+ console.error('Usage: npx recoder-code configure model <model-name>');
9
+ process.exit(1);
10
+ }
11
+
12
+ const command = args[0].trim();
13
+ const modelName = args[1]?.trim();
14
+
15
+ if (command !== 'model' || !modelName) {
16
+ console.error('Usage: npx recoder-code configure model <model-name>');
17
+ process.exit(1);
18
+ }
19
+
20
+ const configPath = path.join(process.cwd(), '.recoderrc');
21
+
22
+ try {
23
+ let config = {};
24
+ if (fs.existsSync(configPath)) {
25
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
26
+ }
27
+ config.openRouterModel = modelName;
28
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
29
+ console.log(`Open Router model set to: ${modelName}`);
30
+ } catch (err) {
31
+ console.error('Error saving model to .recoderrc:', err.message);
32
+ process.exit(1);
33
+ }
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const axios = require('axios');
5
+
6
+ const configPath = path.join(process.cwd(), '.recoderrc');
7
+
8
+ if (!fs.existsSync(configPath)) {
9
+ console.error('Open Router API key not found. Please configure it using `npx recoder-code configure --api-key <your-api-key> --model <model-name>`.');
10
+ process.exit(1);
11
+ }
12
+
13
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
14
+
15
+ if (!config.openRouterApiKey) {
16
+ console.error('Open Router API key not found. Please configure it using `npx recoder-code configure --api-key <your-api-key> --model <model-name>`.');
17
+ process.exit(1);
18
+ }
19
+
20
+ const openRouterApiKey = config.openRouterApiKey;
21
+ const apiUrl = 'https://api.openrouter.com/v1/models'; // Replace with the actual OpenRouter API endpoint
22
+
23
+ axios.get(apiUrl, {
24
+ headers: {
25
+ 'Authorization': `Bearer ${openRouterApiKey}`
26
+ }
27
+ })
28
+ .then(response => {
29
+ const models = response.data.models || [];
30
+ if (models.length === 0) {
31
+ console.log('No models found.');
32
+ } else {
33
+ console.log('Available Open Router models:');
34
+ models.forEach(model => {
35
+ console.log(`- ${model.id || model.name}`);
36
+ });
37
+ }
38
+ })
39
+ .catch(error => {
40
+ if (error.response) {
41
+ console.error(`Error fetching models: ${error.response.status} - ${error.response.statusText}`);
42
+ } else if (error.request) {
43
+ console.error('Error fetching models: No response received');
44
+ } else {
45
+ console.error(`Error fetching models: ${error.message}`);
46
+ }
47
+ process.exit(1);
48
+ });
package/cli/run.js ADDED
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const axios = require('axios');
5
+
6
+ const configPath = path.join(process.cwd(), '.recoderrc');
7
+
8
+ try {
9
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
10
+
11
+ if (!config.openRouterApiKey) {
12
+ console.error('Open Router API key not found. Please set it using: npx recoder-code set-api-key <your-open-router-api-key>');
13
+ process.exit(1);
14
+ }
15
+
16
+ if (!config.openRouterModel) {
17
+ console.error('Open Router model not found. Please set it using: npx recoder-code configure model <model-name>');
18
+ process.exit(1);
19
+ }
20
+
21
+ const apiKey = config.openRouterApiKey;
22
+ const modelName = config.openRouterModel;
23
+
24
+ // Log the API request details
25
+ console.log(`Making API request to OpenRouter model: ${modelName}`);
26
+
27
+ // Example API request using the configured API key and model
28
+ const response = await axios.post(
29
+ `https://api.openrouter.com/v1/models/${modelName}/completions`,
30
+ {
31
+ prompt: "Hello, OpenRouter!",
32
+ max_tokens: 50
33
+ },
34
+ {
35
+ headers: {
36
+ 'Authorization': `Bearer ${apiKey}`,
37
+ 'Content-Type': 'application/json'
38
+ }
39
+ }
40
+ );
41
+
42
+ // Log the API response details
43
+ console.log('Response from OpenRouter:', response.data.choices[0].text.trim());
44
+ } catch (err) {
45
+ // Improved error handling
46
+ if (err.response) {
47
+ // The request was made and the server responded with a status code
48
+ // that falls out of the range of 2xx
49
+ console.error('API Error Response:', err.response.data);
50
+ console.error('Status Code:', err.response.status);
51
+ console.error('Headers:', err.response.headers);
52
+ } else if (err.request) {
53
+ // The request was made but no response was received
54
+ console.error('No response received:', err.request);
55
+ } else {
56
+ // Something happened in setting up the request that triggered an Error
57
+ console.error('Error setting up request:', err.message);
58
+ }
59
+ console.error('Error reading .recoderrc or making API request:', err.message);
60
+ process.exit(1);
61
+ }
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ const args = process.argv.slice(2);
6
+
7
+ if (args.length === 0) {
8
+ console.error('Usage: npx recoder-code set-api-key <your-open-router-api-key>');
9
+ process.exit(1);
10
+ }
11
+
12
+ const apiKey = args[0].trim();
13
+ const configPath = path.join(process.cwd(), '.recoderrc');
14
+
15
+ try {
16
+ let config = {};
17
+ if (fs.existsSync(configPath)) {
18
+ config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
19
+ }
20
+ config.openRouterApiKey = apiKey;
21
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
22
+ console.log(`Open Router API key set to: ${apiKey}`);
23
+ } catch (err) {
24
+ console.error('Error saving API key to .recoderrc:', err.message);
25
+ process.exit(1);
26
+ }