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.
- package/.babelrc +4 -0
- package/.claude/commands/commit-push-pr.md +19 -0
- package/.claude/commands/dedupe.md +38 -0
- package/.devcontainer/Dockerfile +91 -0
- package/.devcontainer/devcontainer.json +57 -0
- package/.devcontainer/init-firewall.sh +137 -0
- package/.gitattributes +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +188 -0
- package/.github/ISSUE_TEMPLATE/config.yml +17 -0
- package/.github/ISSUE_TEMPLATE/documentation.yml +117 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +132 -0
- package/.github/ISSUE_TEMPLATE/model_behavior.yml +220 -0
- package/.github/workflows/auto-close-duplicates.yml +31 -0
- package/.github/workflows/backfill-duplicate-comments.yml +44 -0
- package/.github/workflows/claude-dedupe-issues.yml +80 -0
- package/.github/workflows/claude-issue-triage.yml +106 -0
- package/.github/workflows/claude.yml +37 -0
- package/.github/workflows/issue-opened-dispatch.yml +28 -0
- package/.github/workflows/lock-closed-issues.yml +92 -0
- package/.github/workflows/log-issue-events.yml +40 -0
- package/CHANGELOG.md +646 -0
- package/KILO.md +1273 -0
- package/LICENSE.md +21 -0
- package/README.md +176 -0
- package/SECURITY.md +12 -0
- package/Script/run_devcontainer_claude_code.ps1 +152 -0
- package/api/githubApi.ts +144 -0
- package/babel.config.js +7 -0
- package/cli/.gitkeep +0 -0
- package/cli/auto-close-duplicates.ts +5 -0
- package/cli/configure.js +33 -0
- package/cli/list-models.js +48 -0
- package/cli/run.js +61 -0
- package/cli/set-api-key.js +26 -0
- package/config.json +4 -0
- package/demo.gif +0 -0
- package/examples/gpt-3.5-turbo.js +38 -0
- package/examples/gpt-4.js +38 -0
- package/examples/hooks/bash_command_validator_example.py +83 -0
- package/index.d.ts +3 -0
- package/index.js +62 -0
- package/jest.config.js +6 -0
- package/openapi.yaml +61 -0
- package/package.json +47 -0
- package/scripts/backfill-duplicate-comments.ts +213 -0
- package/tests/api-githubApi.test.ts +30 -0
- package/tests/auto-close-duplicates.test.ts +145 -0
- package/tests/cli-configure.test.ts +88 -0
- package/tests/cli-list-models.test.ts +44 -0
- package/tests/cli-run.test.ts +97 -0
- package/tests/cli-set-api-key.test.ts +54 -0
- package/tests/cli-validate-api-key.test.ts +52 -0
- 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 ---"
|
package/api/githubApi.ts
ADDED
|
@@ -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
|
+
}
|
package/babel.config.js
ADDED
package/cli/.gitkeep
ADDED
|
File without changes
|
package/cli/configure.js
ADDED
|
@@ -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
|
+
}
|