Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb7de776e4 | |||
| 108b8243a9 | |||
| 59f1e72dec | |||
| 46d95853ae | |||
| e6374a952c |
@@ -1,2 +0,0 @@
|
|||||||
!examples
|
|
||||||
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
name: Auto-tag Action Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main]
|
|
||||||
paths:
|
|
||||||
- 'package.json'
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
auto-tag:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v4
|
|
||||||
with:
|
|
||||||
node-version: '20'
|
|
||||||
|
|
||||||
- name: Setup pnpm
|
|
||||||
uses: pnpm/action-setup@v4
|
|
||||||
with:
|
|
||||||
version: latest
|
|
||||||
|
|
||||||
- name: Get package version
|
|
||||||
id: version
|
|
||||||
run: |
|
|
||||||
VERSION=$(node -p "require('./package.json').version")
|
|
||||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
# Extract major version (e.g., "0" from "0.0.1")
|
|
||||||
MAJOR_VERSION=$(echo $VERSION | cut -d. -f1)
|
|
||||||
echo "major_tag=v$MAJOR_VERSION" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Check if tag already exists
|
|
||||||
id: check_tag
|
|
||||||
run: |
|
|
||||||
if git rev-parse "refs/tags/${{ steps.version.outputs.tag }}" >/dev/null 2>&1; then
|
|
||||||
echo "exists=true" >> $GITHUB_OUTPUT
|
|
||||||
echo "Tag ${{ steps.version.outputs.tag }} already exists"
|
|
||||||
else
|
|
||||||
echo "exists=false" >> $GITHUB_OUTPUT
|
|
||||||
echo "Tag ${{ steps.version.outputs.tag }} does not exist"
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Verify built files are up to date
|
|
||||||
if: steps.check_tag.outputs.exists == 'false'
|
|
||||||
run: |
|
|
||||||
# Check if there are any uncommitted changes (built files should already be committed via pre-commit hook)
|
|
||||||
if [[ -n $(git status --porcelain) ]]; then
|
|
||||||
echo "❌ Error: There are uncommitted changes. Built files should be committed via pre-commit hook."
|
|
||||||
git status
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo "✅ All built files are up to date"
|
|
||||||
|
|
||||||
- name: Create and push tags
|
|
||||||
if: steps.check_tag.outputs.exists == 'false'
|
|
||||||
run: |
|
|
||||||
# Create specific version tag
|
|
||||||
git tag ${{ steps.version.outputs.tag }}
|
|
||||||
git push origin ${{ steps.version.outputs.tag }}
|
|
||||||
|
|
||||||
# Create/update major version tag (moving tag)
|
|
||||||
git tag -f ${{ steps.version.outputs.major_tag }}
|
|
||||||
git push origin ${{ steps.version.outputs.major_tag }} --force
|
|
||||||
|
|
||||||
- name: Create GitHub Release
|
|
||||||
if: steps.check_tag.outputs.exists == 'false'
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ steps.version.outputs.tag }}
|
|
||||||
release_name: ${{ steps.version.outputs.tag }}
|
|
||||||
body: |
|
|
||||||
Automated release for action version ${{ steps.version.outputs.version }}
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- uses: pullfrog/pullfrog@${{ steps.version.outputs.major_tag }}
|
|
||||||
with:
|
|
||||||
message: "Your message here"
|
|
||||||
```
|
|
||||||
|
|
||||||
Or use the specific version:
|
|
||||||
```yaml
|
|
||||||
- uses: pullfrog/pullfrog@${{ steps.version.outputs.tag }}
|
|
||||||
with:
|
|
||||||
message: "Your message here"
|
|
||||||
```
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
+25
-28
@@ -1,37 +1,34 @@
|
|||||||
# macOS settings file
|
# dependencies (bun install)
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Contains all your dependencies
|
|
||||||
node_modules
|
node_modules
|
||||||
|
|
||||||
# Replace as required with your build location
|
# output
|
||||||
/build
|
out
|
||||||
|
dist
|
||||||
|
*.tgz
|
||||||
|
|
||||||
# Deal with environment files
|
# code coverage
|
||||||
.env
|
|
||||||
.env.*
|
|
||||||
|
|
||||||
# We'll allow an example .env file which can be copied
|
|
||||||
!.env.example
|
|
||||||
|
|
||||||
# Coverage directory used by testing tools
|
|
||||||
coverage
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
# Visual Studio Code configuration
|
# logs
|
||||||
.vscode/
|
logs
|
||||||
|
_.log
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
# npm and yarn debug logs
|
# caches
|
||||||
npm-debug.log*
|
.eslintcache
|
||||||
yarn-debug.log*
|
.cache
|
||||||
yarn-error.log*
|
*.tsbuildinfo
|
||||||
|
|
||||||
# next.js
|
# IntelliJ based IDEs
|
||||||
.next
|
.idea
|
||||||
|
|
||||||
# sveltekit
|
# Finder (MacOS) folder config
|
||||||
/.svelte-kit
|
.DS_Store
|
||||||
vite.config.js.timestamp-*
|
|
||||||
vite.config.ts.timestamp-*
|
|
||||||
|
|
||||||
examples
|
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
# Build the action before committing
|
|
||||||
echo "🔨 Building action..."
|
|
||||||
npm run build
|
|
||||||
|
|
||||||
# Add the built files to the commit
|
|
||||||
git add index.cjs dist/
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# Pullfrog
|
|
||||||
|
|
||||||
A simple GitHub Action that prints a customizable message to the console.
|
|
||||||
|
|
||||||
+21
-13
@@ -1,20 +1,28 @@
|
|||||||
name: 'Pullfrog Claude Code Action'
|
name: shockbot
|
||||||
description: 'Execute Claude Code with a prompt using Anthropic API'
|
description: Ollama-powered code review bot for Gitea
|
||||||
author: 'Pullfrog'
|
author: ShockVPN
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
prompt:
|
prompt:
|
||||||
description: 'Prompt to send to Claude Code'
|
description: Review instruction sent to the model
|
||||||
required: true
|
|
||||||
default: 'Hello from Claude Code!'
|
|
||||||
anthropic_api_key:
|
|
||||||
description: 'Anthropic API key for Claude Code authentication'
|
|
||||||
required: false
|
required: false
|
||||||
|
default: "Review this pull request"
|
||||||
|
model:
|
||||||
|
description: Ollama model to use
|
||||||
|
required: false
|
||||||
|
default: "qwen3.6:35b"
|
||||||
|
context_window:
|
||||||
|
description: Max tokens per diff chunk
|
||||||
|
required: false
|
||||||
|
default: "4096"
|
||||||
|
max_tool_calls:
|
||||||
|
description: Max MCP tool calls the model can make per chunk
|
||||||
|
required: false
|
||||||
|
default: "10"
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: 'node20'
|
using: "node24"
|
||||||
main: 'index.cjs'
|
main: "bootstrap.ts"
|
||||||
|
|
||||||
branding:
|
# BOT_TOKEN, OLLAMA_HOST, and GITEA_URL must be set as env vars by the consuming workflow.
|
||||||
icon: 'code'
|
# GITHUB_EVENT_NAME, GITHUB_EVENT_PATH, and GITHUB_REPOSITORY are set by the runner.
|
||||||
color: 'orange'
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
import * as core from "@actions/core";
|
|
||||||
import { executeCommand } from "../utils/exec";
|
|
||||||
import { createTempFile } from "../utils/files";
|
|
||||||
import type { Agent, AgentConfig, AgentResult } from "./types";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Claude Code agent implementation
|
|
||||||
*/
|
|
||||||
export class ClaudeAgent implements Agent {
|
|
||||||
private apiKey: string;
|
|
||||||
|
|
||||||
constructor(config: AgentConfig) {
|
|
||||||
if (!config.apiKey) {
|
|
||||||
throw new Error("Claude agent requires an API key");
|
|
||||||
}
|
|
||||||
this.apiKey = config.apiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Install Claude Code CLI
|
|
||||||
*/
|
|
||||||
async install(): Promise<void> {
|
|
||||||
core.info("Installing Claude Code...");
|
|
||||||
try {
|
|
||||||
await executeCommand("curl -fsSL https://claude.ai/install.sh | bash -s 1.0.93");
|
|
||||||
core.info("Claude Code installed successfully");
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error(`Failed to install Claude Code: ${error}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute Claude Code with the given prompt
|
|
||||||
*/
|
|
||||||
async execute(prompt: string): Promise<AgentResult> {
|
|
||||||
core.info("Executing Claude Code...");
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Create a temporary file for the prompt
|
|
||||||
const promptFile = createTempFile(prompt, "prompt.txt");
|
|
||||||
|
|
||||||
// Execute Claude Code with the prompt
|
|
||||||
const command = `$HOME/.local/bin/claude --dangerously-skip-permissions "${promptFile}"`;
|
|
||||||
core.info(`Executing: ${command}`);
|
|
||||||
|
|
||||||
const { stdout, stderr } = await executeCommand(command, {
|
|
||||||
ANTHROPIC_API_KEY: this.apiKey,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (stderr) {
|
|
||||||
core.warning(`Claude Code stderr: ${stderr}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stdout) {
|
|
||||||
core.info("Claude Code output:");
|
|
||||||
console.log(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info("Claude Code executed successfully");
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
output: stdout,
|
|
||||||
error: stderr || undefined,
|
|
||||||
metadata: {
|
|
||||||
promptFile,
|
|
||||||
command,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: `Failed to execute Claude Code: ${errorMessage}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import { ClaudeAgent } from "./claude";
|
|
||||||
import type { Agent, AgentConfig } from "./types";
|
|
||||||
|
|
||||||
export type AgentType = "claude";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory for creating agent instances
|
|
||||||
*/
|
|
||||||
export function createAgent(type: AgentType, config: AgentConfig): Agent {
|
|
||||||
switch (type) {
|
|
||||||
case "claude":
|
|
||||||
return new ClaudeAgent(config);
|
|
||||||
default:
|
|
||||||
throw new Error(`Unsupported agent type: ${type}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
export * from "./claude";
|
|
||||||
export * from "./factory";
|
|
||||||
export * from "./types";
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Standard interface for all Pullfrog agents
|
|
||||||
*/
|
|
||||||
export interface Agent {
|
|
||||||
/**
|
|
||||||
* Install the agent and any required dependencies
|
|
||||||
*/
|
|
||||||
install(): Promise<void>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the agent with the given prompt
|
|
||||||
* @param prompt The prompt to send to the agent
|
|
||||||
* @param options Additional options specific to the agent
|
|
||||||
*/
|
|
||||||
execute(prompt: string, options?: Record<string, any>): Promise<AgentResult>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result returned by agent execution
|
|
||||||
*/
|
|
||||||
export interface AgentResult {
|
|
||||||
success: boolean;
|
|
||||||
output?: string;
|
|
||||||
error?: string;
|
|
||||||
metadata?: Record<string, any>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration for agent creation
|
|
||||||
*/
|
|
||||||
export interface AgentConfig {
|
|
||||||
apiKey?: string;
|
|
||||||
[key: string]: any;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { existsSync } from "node:fs";
|
||||||
|
import { execSync } from "node:child_process";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname } from "node:path";
|
||||||
|
|
||||||
|
const dir = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
|
if (!existsSync(`${dir}/node_modules`)) {
|
||||||
|
console.log("node_modules not found, installing dependencies...");
|
||||||
|
try {
|
||||||
|
execSync("bun install --frozen-lockfile", { stdio: "inherit", cwd: dir, timeout: 120_000 });
|
||||||
|
} catch {
|
||||||
|
console.log("bun unavailable, falling back to npm...");
|
||||||
|
execSync("npm install --no-fund --no-audit", { stdio: "inherit", cwd: dir, timeout: 120_000 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await import("./entry.ts");
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
{
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"configVersion": 1,
|
||||||
|
"workspaces": {
|
||||||
|
"": {
|
||||||
|
"name": "shockbot",
|
||||||
|
"devDependencies": {
|
||||||
|
"@go-gitea/sdk.js": "^0.2.1",
|
||||||
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"ollama": "^0.6.3",
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"@go-gitea/sdk.js": ["@go-gitea/sdk.js@0.2.1", "", { "dependencies": { "@octokit/core": "^7.0.2", "@octokit/plugin-paginate-rest": "^13.0.0", "@octokit/plugin-retry": "^8.0.1", "@octokit/request-error": "^7.0.0", "@octokit/types": "^15.0.0" } }, "sha512-8H3ci55MHUk8LtS8T4rlkpjNagAWCpBin3J0VhSNobh+XXbLR7kXplwH4ZxXRMqZOi1+gBv3XEk8azicW8zt3g=="],
|
||||||
|
|
||||||
|
"@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="],
|
||||||
|
|
||||||
|
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
|
||||||
|
|
||||||
|
"@octokit/auth-token": ["@octokit/auth-token@6.0.0", "", {}, "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w=="],
|
||||||
|
|
||||||
|
"@octokit/core": ["@octokit/core@7.0.6", "", { "dependencies": { "@octokit/auth-token": "^6.0.0", "@octokit/graphql": "^9.0.3", "@octokit/request": "^10.0.6", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "before-after-hook": "^4.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q=="],
|
||||||
|
|
||||||
|
"@octokit/endpoint": ["@octokit/endpoint@11.0.3", "", { "dependencies": { "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.2" } }, "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag=="],
|
||||||
|
|
||||||
|
"@octokit/graphql": ["@octokit/graphql@9.0.3", "", { "dependencies": { "@octokit/request": "^10.0.6", "@octokit/types": "^16.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA=="],
|
||||||
|
|
||||||
|
"@octokit/openapi-types": ["@octokit/openapi-types@26.0.0", "", {}, "sha512-7AtcfKtpo77j7Ts73b4OWhOZHTKo/gGY8bB3bNBQz4H+GRSWqx2yvj8TXRsbdTE0eRmYmXOEY66jM7mJ7LzfsA=="],
|
||||||
|
|
||||||
|
"@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@13.2.1", "", { "dependencies": { "@octokit/types": "^15.0.1" }, "peerDependencies": { "@octokit/core": ">=6" } }, "sha512-Tj4PkZyIL6eBMYcG/76QGsedF0+dWVeLhYprTmuFVVxzDW7PQh23tM0TP0z+1MvSkxB29YFZwnUX+cXfTiSdyw=="],
|
||||||
|
|
||||||
|
"@octokit/plugin-retry": ["@octokit/plugin-retry@8.1.0", "", { "dependencies": { "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "bottleneck": "^2.15.3" }, "peerDependencies": { "@octokit/core": ">=7" } }, "sha512-O1FZgXeiGb2sowEr/hYTr6YunGdSAFWnr2fyW39Ah85H8O33ELASQxcvOFF5LE6Tjekcyu2ms4qAzJVhSaJxTw=="],
|
||||||
|
|
||||||
|
"@octokit/request": ["@octokit/request@10.0.10", "", { "dependencies": { "@octokit/endpoint": "^11.0.3", "@octokit/request-error": "^7.0.2", "@octokit/types": "^16.0.0", "content-type": "^2.0.0", "json-with-bigint": "^3.5.3", "universal-user-agent": "^7.0.2" } }, "sha512-KxNC2pTqqhszMNrf12ZRd4PonRgyJdsM4F/jySiddQK+DsRcfBtUvqn8t7UsyZhnRJHvX46OohDt5N3VqIWC2w=="],
|
||||||
|
|
||||||
|
"@octokit/request-error": ["@octokit/request-error@7.1.0", "", { "dependencies": { "@octokit/types": "^16.0.0" } }, "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw=="],
|
||||||
|
|
||||||
|
"@octokit/types": ["@octokit/types@15.0.2", "", { "dependencies": { "@octokit/openapi-types": "^26.0.0" } }, "sha512-rR+5VRjhYSer7sC51krfCctQhVTmjyUMAaShfPB8mscVa8tSoLyon3coxQmXu0ahJoLVWl8dSGD/3OGZlFV44Q=="],
|
||||||
|
|
||||||
|
"@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="],
|
||||||
|
|
||||||
|
"@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
|
||||||
|
|
||||||
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
||||||
|
|
||||||
|
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||||
|
|
||||||
|
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
|
||||||
|
|
||||||
|
"before-after-hook": ["before-after-hook@4.0.0", "", {}, "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ=="],
|
||||||
|
|
||||||
|
"body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
||||||
|
|
||||||
|
"bottleneck": ["bottleneck@2.19.5", "", {}, "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw=="],
|
||||||
|
|
||||||
|
"bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="],
|
||||||
|
|
||||||
|
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
||||||
|
|
||||||
|
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
||||||
|
|
||||||
|
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
||||||
|
|
||||||
|
"content-disposition": ["content-disposition@1.1.0", "", {}, "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g=="],
|
||||||
|
|
||||||
|
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
||||||
|
|
||||||
|
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
||||||
|
|
||||||
|
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
||||||
|
|
||||||
|
"cors": ["cors@2.8.6", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw=="],
|
||||||
|
|
||||||
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||||
|
|
||||||
|
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||||
|
|
||||||
|
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
||||||
|
|
||||||
|
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||||
|
|
||||||
|
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
||||||
|
|
||||||
|
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
||||||
|
|
||||||
|
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
||||||
|
|
||||||
|
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
||||||
|
|
||||||
|
"es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="],
|
||||||
|
|
||||||
|
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
||||||
|
|
||||||
|
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
||||||
|
|
||||||
|
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
|
||||||
|
|
||||||
|
"eventsource-parser": ["eventsource-parser@3.1.0", "", {}, "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg=="],
|
||||||
|
|
||||||
|
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
||||||
|
|
||||||
|
"express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="],
|
||||||
|
|
||||||
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
|
"fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="],
|
||||||
|
|
||||||
|
"finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
|
||||||
|
|
||||||
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
||||||
|
|
||||||
|
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
||||||
|
|
||||||
|
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
||||||
|
|
||||||
|
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
||||||
|
|
||||||
|
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
||||||
|
|
||||||
|
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
||||||
|
|
||||||
|
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
||||||
|
|
||||||
|
"hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="],
|
||||||
|
|
||||||
|
"hono": ["hono@4.12.23", "", {}, "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA=="],
|
||||||
|
|
||||||
|
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
|
||||||
|
|
||||||
|
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||||
|
|
||||||
|
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||||
|
|
||||||
|
"ip-address": ["ip-address@10.2.0", "", {}, "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA=="],
|
||||||
|
|
||||||
|
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
||||||
|
|
||||||
|
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
||||||
|
|
||||||
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
||||||
|
|
||||||
|
"jose": ["jose@6.2.3", "", {}, "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw=="],
|
||||||
|
|
||||||
|
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
||||||
|
|
||||||
|
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
|
||||||
|
|
||||||
|
"json-with-bigint": ["json-with-bigint@3.5.8", "", {}, "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw=="],
|
||||||
|
|
||||||
|
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
||||||
|
|
||||||
|
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
||||||
|
|
||||||
|
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
||||||
|
|
||||||
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
||||||
|
|
||||||
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||||
|
|
||||||
|
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
||||||
|
|
||||||
|
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||||
|
|
||||||
|
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
||||||
|
|
||||||
|
"ollama": ["ollama@0.6.3", "", { "dependencies": { "whatwg-fetch": "^3.6.20" } }, "sha512-KEWEhIqE5wtfzEIZbDCLH51VFZ6Z3ZSa6sIOg/E/tBV8S51flyqBOXi+bRxlOYKDf8i327zG9eSTb8IJxvm3Zg=="],
|
||||||
|
|
||||||
|
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
||||||
|
|
||||||
|
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
||||||
|
|
||||||
|
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||||
|
|
||||||
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||||
|
|
||||||
|
"path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
|
||||||
|
|
||||||
|
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
|
||||||
|
|
||||||
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
||||||
|
|
||||||
|
"qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="],
|
||||||
|
|
||||||
|
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
||||||
|
|
||||||
|
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
||||||
|
|
||||||
|
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
||||||
|
|
||||||
|
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
||||||
|
|
||||||
|
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||||
|
|
||||||
|
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
||||||
|
|
||||||
|
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
|
||||||
|
|
||||||
|
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
||||||
|
|
||||||
|
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||||
|
|
||||||
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
||||||
|
|
||||||
|
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
||||||
|
|
||||||
|
"side-channel-list": ["side-channel-list@1.0.1", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.4" } }, "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w=="],
|
||||||
|
|
||||||
|
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
||||||
|
|
||||||
|
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
||||||
|
|
||||||
|
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
||||||
|
|
||||||
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
||||||
|
|
||||||
|
"type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="],
|
||||||
|
|
||||||
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||||
|
|
||||||
|
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
|
||||||
|
|
||||||
|
"universal-user-agent": ["universal-user-agent@7.0.3", "", {}, "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A=="],
|
||||||
|
|
||||||
|
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
||||||
|
|
||||||
|
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
||||||
|
|
||||||
|
"whatwg-fetch": ["whatwg-fetch@3.6.20", "", {}, "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg=="],
|
||||||
|
|
||||||
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||||
|
|
||||||
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
||||||
|
|
||||||
|
"zod": ["zod@4.4.3", "", {}, "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ=="],
|
||||||
|
|
||||||
|
"zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="],
|
||||||
|
|
||||||
|
"@octokit/core/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"@octokit/endpoint/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"@octokit/graphql/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"@octokit/plugin-retry/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"@octokit/request/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"@octokit/request/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
||||||
|
|
||||||
|
"@octokit/request-error/@octokit/types": ["@octokit/types@16.0.0", "", { "dependencies": { "@octokit/openapi-types": "^27.0.0" } }, "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg=="],
|
||||||
|
|
||||||
|
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
||||||
|
|
||||||
|
"@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@octokit/endpoint/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@octokit/graphql/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@octokit/plugin-retry/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
|
||||||
|
"@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@27.0.0", "", {}, "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA=="],
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
import type { AggregatedReview, Finding, ReviewSeverity } from "./types.ts";
|
||||||
|
|
||||||
|
const SEVERITY_ORDER: ReviewSeverity[] = ["error", "warning", "nit"];
|
||||||
|
|
||||||
|
const SEVERITY_LABEL: Record<ReviewSeverity, string> = {
|
||||||
|
error: "Errors",
|
||||||
|
warning: "Warnings",
|
||||||
|
nit: "Nits",
|
||||||
|
};
|
||||||
|
|
||||||
|
const SEVERITY_EMOJI: Record<ReviewSeverity, string> = {
|
||||||
|
error: "🔴",
|
||||||
|
warning: "🟡",
|
||||||
|
nit: "🔵",
|
||||||
|
};
|
||||||
|
|
||||||
|
function renderGroup(severity: ReviewSeverity, findings: Finding[]): string {
|
||||||
|
const items = findings.map(
|
||||||
|
(f) => `**\`${f.filename}\`** line ${f.line}\n> ${f.comment}`,
|
||||||
|
);
|
||||||
|
return `### ${SEVERITY_EMOJI[severity]} ${SEVERITY_LABEL[severity]} (${findings.length})\n\n${items.join("\n\n")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatReview(
|
||||||
|
review: AggregatedReview,
|
||||||
|
files: string[],
|
||||||
|
model: string,
|
||||||
|
): string {
|
||||||
|
console.log(
|
||||||
|
`Formatting review for ${files.length} file${files.length === 1 ? "" : "s"} with model ${model}...`,
|
||||||
|
);
|
||||||
|
const parts: string[] = [];
|
||||||
|
|
||||||
|
parts.push(
|
||||||
|
`## 🤖 shockbot review\n\n> Reviewed ${files.length} file${files.length === 1 ? "" : "s"} using \`${model}\``,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Summary section — join per-chunk summaries
|
||||||
|
const summaries = review.summaries.filter(Boolean);
|
||||||
|
if (summaries.length > 0) {
|
||||||
|
parts.push(`**Summary**\n\n${summaries.join("\n\n")}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group findings by severity
|
||||||
|
const grouped = new Map<ReviewSeverity, Finding[]>();
|
||||||
|
for (const severity of SEVERITY_ORDER) grouped.set(severity, []);
|
||||||
|
for (const finding of review.findings) {
|
||||||
|
grouped.get(finding.severity)?.push(finding);
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasFindings = review.findings.length > 0;
|
||||||
|
if (hasFindings) {
|
||||||
|
for (const severity of SEVERITY_ORDER) {
|
||||||
|
const group = grouped.get(severity)!;
|
||||||
|
if (group.length > 0) parts.push(renderGroup(severity, group));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parts.push("No issues found. ✅");
|
||||||
|
}
|
||||||
|
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
parts.push(`---\n\n<sub>shockbot · \`${model}\` · ${timestamp}</sub>`);
|
||||||
|
|
||||||
|
return parts.join("\n\n---\n\n");
|
||||||
|
}
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
import type { DiffChunk } from "./types.ts";
|
||||||
|
|
||||||
|
// ~4 chars per token is a reasonable rough estimate for code
|
||||||
|
function estimateTokens(text: string): number {
|
||||||
|
return Math.ceil(text.length / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SKIP_EXTENSIONS = new Set([
|
||||||
|
"lock",
|
||||||
|
"sum",
|
||||||
|
"map",
|
||||||
|
"png",
|
||||||
|
"jpg",
|
||||||
|
"jpeg",
|
||||||
|
"gif",
|
||||||
|
"svg",
|
||||||
|
"ico",
|
||||||
|
"webp",
|
||||||
|
"woff",
|
||||||
|
"woff2",
|
||||||
|
"ttf",
|
||||||
|
"eot",
|
||||||
|
"pdf",
|
||||||
|
"zip",
|
||||||
|
"tar",
|
||||||
|
"gz",
|
||||||
|
"bin",
|
||||||
|
"exe",
|
||||||
|
"dll",
|
||||||
|
"so",
|
||||||
|
"dylib",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const SKIP_PATTERNS = [
|
||||||
|
/^node_modules\//,
|
||||||
|
/^\.git\//,
|
||||||
|
/\/generated\//,
|
||||||
|
/\.pb\.\w+$/,
|
||||||
|
/\.min\.[jt]s$/,
|
||||||
|
];
|
||||||
|
|
||||||
|
function shouldSkip(filename: string): boolean {
|
||||||
|
if (!filename.includes(".")) return true; // no extension = likely binary
|
||||||
|
const ext = filename.split(".").pop()!.toLowerCase();
|
||||||
|
return (
|
||||||
|
SKIP_EXTENSIONS.has(ext) || SKIP_PATTERNS.some((p) => p.test(filename))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const EXT_TO_LANG: Record<string, string> = {
|
||||||
|
ts: "TypeScript",
|
||||||
|
tsx: "TypeScript",
|
||||||
|
js: "JavaScript",
|
||||||
|
jsx: "JavaScript",
|
||||||
|
mjs: "JavaScript",
|
||||||
|
cjs: "JavaScript",
|
||||||
|
py: "Python",
|
||||||
|
go: "Go",
|
||||||
|
rs: "Rust",
|
||||||
|
rb: "Ruby",
|
||||||
|
java: "Java",
|
||||||
|
kt: "Kotlin",
|
||||||
|
kts: "Kotlin",
|
||||||
|
swift: "Swift",
|
||||||
|
cs: "C#",
|
||||||
|
cpp: "C++",
|
||||||
|
cc: "C++",
|
||||||
|
cxx: "C++",
|
||||||
|
hpp: "C++",
|
||||||
|
c: "C",
|
||||||
|
php: "PHP",
|
||||||
|
sh: "Shell",
|
||||||
|
bash: "Shell",
|
||||||
|
zsh: "Shell",
|
||||||
|
yaml: "YAML",
|
||||||
|
yml: "YAML",
|
||||||
|
json: "JSON",
|
||||||
|
md: "Markdown",
|
||||||
|
sql: "SQL",
|
||||||
|
html: "HTML",
|
||||||
|
htm: "HTML",
|
||||||
|
css: "CSS",
|
||||||
|
scss: "CSS",
|
||||||
|
sass: "CSS",
|
||||||
|
less: "CSS",
|
||||||
|
vue: "Vue",
|
||||||
|
svelte: "Svelte",
|
||||||
|
toml: "TOML",
|
||||||
|
xml: "XML",
|
||||||
|
tf: "Terraform",
|
||||||
|
hcl: "HCL",
|
||||||
|
};
|
||||||
|
|
||||||
|
function detectLanguage(filename: string): string {
|
||||||
|
const ext = filename.split(".").pop()?.toLowerCase() ?? "";
|
||||||
|
return EXT_TO_LANG[ext] ?? "plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiffFile {
|
||||||
|
filename: string;
|
||||||
|
language: string;
|
||||||
|
hunks: Array<{ header: string; body: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseDiff(rawDiff: string): DiffFile[] {
|
||||||
|
console.log("Parsing diff...");
|
||||||
|
const files: DiffFile[] = [];
|
||||||
|
|
||||||
|
const sections = rawDiff.split(/^diff --git /m).filter((s) => s.trim());
|
||||||
|
|
||||||
|
for (const section of sections) {
|
||||||
|
const lines = section.split("\n");
|
||||||
|
|
||||||
|
// Use +++ / --- lines — more reliable than first line for renames and paths with spaces
|
||||||
|
const plusLine = lines.find((l) => l.startsWith("+++ "));
|
||||||
|
const minusLine = lines.find((l) => l.startsWith("--- "));
|
||||||
|
|
||||||
|
let filename: string;
|
||||||
|
if (plusLine?.startsWith("+++ b/")) {
|
||||||
|
filename = plusLine.slice(6);
|
||||||
|
} else if (
|
||||||
|
plusLine === "+++ /dev/null" &&
|
||||||
|
minusLine?.startsWith("--- a/")
|
||||||
|
) {
|
||||||
|
filename = minusLine.slice(6); // deleted file — use old path
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSkip(filename)) continue;
|
||||||
|
|
||||||
|
const language = detectLanguage(filename);
|
||||||
|
const hunks: DiffFile["hunks"] = [];
|
||||||
|
let header = "";
|
||||||
|
let bodyLines: string[] = [];
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
if (line.startsWith("@@")) {
|
||||||
|
if (header) hunks.push({ header, body: bodyLines.join("\n") });
|
||||||
|
header = line;
|
||||||
|
bodyLines = [];
|
||||||
|
} else if (header) {
|
||||||
|
bodyLines.push(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (header) hunks.push({ header, body: bodyLines.join("\n") });
|
||||||
|
|
||||||
|
if (hunks.length > 0) files.push({ filename, language, hunks });
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function chunkFile(file: DiffFile, maxTokens: number): DiffChunk[] {
|
||||||
|
console.log(
|
||||||
|
`Chunking file ${file.filename} with ${file.hunks.length} hunks...`,
|
||||||
|
);
|
||||||
|
return file.hunks.map(({ header, body }) => {
|
||||||
|
let hunk = body;
|
||||||
|
|
||||||
|
if (estimateTokens(body) > maxTokens) {
|
||||||
|
// Truncate from bottom — top of the hunk has the most useful context
|
||||||
|
const lines = body.split("\n");
|
||||||
|
const charBudget = maxTokens * 4;
|
||||||
|
let chars = 0;
|
||||||
|
let i = 0;
|
||||||
|
while (
|
||||||
|
i < lines.length &&
|
||||||
|
chars + (lines[i]?.length ?? 0) + 1 <= charBudget
|
||||||
|
) {
|
||||||
|
chars += (lines[i]?.length ?? 0) + 1;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
hunk = lines.slice(0, i).join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
filename: file.filename,
|
||||||
|
language: file.language,
|
||||||
|
hunk,
|
||||||
|
context: header,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
Vendored
-17731
File diff suppressed because one or more lines are too long
@@ -0,0 +1,122 @@
|
|||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import type { ActionConfig, PRContext, ChunkReview } from "./types.ts";
|
||||||
|
import { getPR, getPRDiff, addReaction, removeReaction, postReviewComment } from "./gitea.ts";
|
||||||
|
import { parseDiff, chunkFile } from "./diff.ts";
|
||||||
|
import { createMcpServer } from "./mcp.ts";
|
||||||
|
import { reviewChunk, aggregateFindings } from "./review.ts";
|
||||||
|
import { formatReview } from "./comment.ts";
|
||||||
|
|
||||||
|
function readConfig(): ActionConfig {
|
||||||
|
return {
|
||||||
|
prompt: process.env.INPUT_PROMPT ?? "Review this pull request",
|
||||||
|
model: process.env.INPUT_MODEL ?? "qwen3.6:35b",
|
||||||
|
contextWindow: parseInt(process.env.INPUT_CONTEXT_WINDOW ?? "4096", 10),
|
||||||
|
maxToolCalls: parseInt(process.env.INPUT_MAX_TOOL_CALLS ?? "10", 10),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function readEvent(): Record<string, unknown> {
|
||||||
|
const path = process.env.GITHUB_EVENT_PATH;
|
||||||
|
if (!path) return {};
|
||||||
|
try {
|
||||||
|
return JSON.parse(readFileSync(path, "utf8")) as Record<string, unknown>;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
const config = readConfig();
|
||||||
|
const eventName = process.env.GITHUB_EVENT_NAME ?? "";
|
||||||
|
const event = readEvent();
|
||||||
|
|
||||||
|
const repository = process.env.GITHUB_REPOSITORY ?? "";
|
||||||
|
const slashIdx = repository.indexOf("/");
|
||||||
|
if (slashIdx === -1) throw new Error(`Invalid GITHUB_REPOSITORY: ${repository}`);
|
||||||
|
const owner = repository.slice(0, slashIdx);
|
||||||
|
const repo = repository.slice(slashIdx + 1);
|
||||||
|
|
||||||
|
let prNumber: number;
|
||||||
|
let prompt: string;
|
||||||
|
let triggerCommentId: number | null = null;
|
||||||
|
|
||||||
|
if (eventName === "pull_request") {
|
||||||
|
prNumber = event.number as number;
|
||||||
|
prompt = config.prompt;
|
||||||
|
} else if (eventName === "issue_comment") {
|
||||||
|
const issue = event.issue as Record<string, unknown>;
|
||||||
|
if (!issue?.pull_request) {
|
||||||
|
console.log("issue_comment on non-PR issue, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const comment = event.comment as Record<string, unknown>;
|
||||||
|
const commentBody = String(comment?.body ?? "");
|
||||||
|
if (!commentBody.toLowerCase().includes("@shockbot")) {
|
||||||
|
console.log("comment does not mention @shockbot, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
prNumber = issue.number as number;
|
||||||
|
triggerCommentId = comment.id as number;
|
||||||
|
prompt = commentBody.replace(/@shockbot\s*/gi, "").trim() || config.prompt;
|
||||||
|
} else {
|
||||||
|
console.log(`Unsupported event: ${eventName}, skipping`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prData = await getPR(owner, repo, prNumber);
|
||||||
|
const headSha = prData.head?.sha;
|
||||||
|
if (!headSha) throw new Error(`Could not get head SHA for PR #${prNumber}`);
|
||||||
|
|
||||||
|
const pr: PRContext = { owner, repo, prNumber, headSha };
|
||||||
|
|
||||||
|
if (triggerCommentId !== null) {
|
||||||
|
await addReaction(pr, triggerCommentId, "eyes").catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rawDiff = await getPRDiff(pr);
|
||||||
|
if (!rawDiff.trim()) {
|
||||||
|
await postReviewComment(pr, "shockbot: no diff found for this PR.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const files = parseDiff(rawDiff);
|
||||||
|
if (files.length === 0) {
|
||||||
|
await postReviewComment(pr, "shockbot: no reviewable files in this PR (all files skipped).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const chunks = files.flatMap((f) => chunkFile(f, config.contextWindow));
|
||||||
|
const mcpServer = createMcpServer(pr, config.maxToolCalls);
|
||||||
|
|
||||||
|
const results: ChunkReview[] = [];
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
const result = await reviewChunk(
|
||||||
|
chunk,
|
||||||
|
prompt,
|
||||||
|
config.model,
|
||||||
|
config.contextWindow,
|
||||||
|
mcpServer,
|
||||||
|
);
|
||||||
|
results.push(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
const aggregated = aggregateFindings(results);
|
||||||
|
const body = formatReview(aggregated, files.map((f) => f.filename), config.model);
|
||||||
|
await postReviewComment(pr, body);
|
||||||
|
|
||||||
|
if (triggerCommentId !== null) {
|
||||||
|
await removeReaction(pr, triggerCommentId, "eyes").catch(() => {});
|
||||||
|
await addReaction(pr, triggerCommentId, "+1").catch(() => {});
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Review failed:", err);
|
||||||
|
if (triggerCommentId !== null) {
|
||||||
|
await removeReaction(pr, triggerCommentId, "eyes").catch(() => {});
|
||||||
|
await addReaction(pr, triggerCommentId, "-1").catch(() => {});
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { build } from 'esbuild';
|
|
||||||
|
|
||||||
await build({
|
|
||||||
entryPoints: ['./index.ts'],
|
|
||||||
bundle: true,
|
|
||||||
outfile: './index.cjs',
|
|
||||||
format: 'cjs',
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node20',
|
|
||||||
minify: false,
|
|
||||||
sourcemap: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('✅ Build completed successfully!');
|
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import { Gitea } from "@go-gitea/sdk.js";
|
||||||
|
import type {
|
||||||
|
Comment,
|
||||||
|
ChangedFile,
|
||||||
|
PullReview,
|
||||||
|
Reaction,
|
||||||
|
} from "@go-gitea/sdk.js";
|
||||||
|
import type { PRContext } from "./types.ts";
|
||||||
|
|
||||||
|
const client = new Gitea({
|
||||||
|
baseUrl: process.env.GITEA_URL,
|
||||||
|
auth: process.env.BOT_TOKEN,
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function getPRDiff(pr: PRContext): Promise<string> {
|
||||||
|
console.log(`Fetching PR #${pr.prNumber} diff for ${pr.owner}/${pr.repo}`);
|
||||||
|
const res = await client.rest.repository.repoDownloadPullDiffOrPatch({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
index: pr.prNumber,
|
||||||
|
diffType: "diff",
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPRFiles(pr: PRContext): Promise<ChangedFile[]> {
|
||||||
|
console.log(
|
||||||
|
`Fetching PR #${pr.prNumber} changed files for ${pr.owner}/${pr.repo}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.repository.repoGetPullRequestFiles({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
index: pr.prNumber,
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postReviewComment(
|
||||||
|
pr: PRContext,
|
||||||
|
body: string,
|
||||||
|
): Promise<Comment> {
|
||||||
|
console.log(
|
||||||
|
`Posting review comment on PR #${pr.prNumber} for ${pr.owner}/${pr.repo}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.issue.issueCreateComment({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
index: pr.prNumber,
|
||||||
|
body: { body },
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postInlineComment(
|
||||||
|
pr: PRContext,
|
||||||
|
file: string,
|
||||||
|
line: number,
|
||||||
|
body: string,
|
||||||
|
): Promise<PullReview> {
|
||||||
|
console.log(
|
||||||
|
`Posting inline review comment on PR #${pr.prNumber} for ${pr.owner}/${pr.repo} at ${file}:${line}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.repository.repoCreatePullReview({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
index: pr.prNumber,
|
||||||
|
body: {
|
||||||
|
event: "COMMENT",
|
||||||
|
commit_id: pr.headSha,
|
||||||
|
comments: [{ path: file, new_position: line, body }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addReaction(
|
||||||
|
pr: PRContext,
|
||||||
|
commentId: number,
|
||||||
|
reaction: string,
|
||||||
|
): Promise<Reaction> {
|
||||||
|
const res = await client.rest.issue.issuePostCommentReaction({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
id: commentId,
|
||||||
|
content: { content: reaction },
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function removeReaction(
|
||||||
|
pr: PRContext,
|
||||||
|
commentId: number,
|
||||||
|
reaction: string,
|
||||||
|
): Promise<void> {
|
||||||
|
await client.rest.issue.issueDeleteCommentReaction({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
id: commentId,
|
||||||
|
content: { content: reaction },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPR(owner: string, repo: string, prNumber: number) {
|
||||||
|
console.log(`Fetching PR #${prNumber} data for ${owner}/${repo}`);
|
||||||
|
const res = await client.rest.repository.repoGetPullRequest({
|
||||||
|
owner,
|
||||||
|
repo,
|
||||||
|
index: prNumber,
|
||||||
|
});
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getFileContents(
|
||||||
|
pr: PRContext,
|
||||||
|
filePath: string,
|
||||||
|
): Promise<string> {
|
||||||
|
console.log(
|
||||||
|
`Fetching contents of ${filePath} at PR #${pr.prNumber} head for ${pr.owner}/${pr.repo}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.repository.repoGetContents({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
filepath: filePath,
|
||||||
|
ref: pr.headSha,
|
||||||
|
});
|
||||||
|
const entry = Array.isArray(res.data) ? res.data[0] : res.data;
|
||||||
|
if (!entry?.content || entry.type !== "file") return "";
|
||||||
|
// content is base64-encoded; Buffer handles embedded newlines
|
||||||
|
return Buffer.from(entry.content, "base64").toString("utf8");
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function listDir(
|
||||||
|
pr: PRContext,
|
||||||
|
dirPath: string,
|
||||||
|
): Promise<string[]> {
|
||||||
|
console.log(
|
||||||
|
`Listing directory ${dirPath} at PR #${pr.prNumber} head for ${pr.owner}/${pr.repo}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.repository.repoGetContents({
|
||||||
|
owner: pr.owner,
|
||||||
|
repo: pr.repo,
|
||||||
|
filepath: dirPath,
|
||||||
|
ref: pr.headSha,
|
||||||
|
});
|
||||||
|
const entries = Array.isArray(res.data) ? res.data : [res.data];
|
||||||
|
return entries.map((e) => e.name ?? "").filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gitea REST API v1 has no code search endpoint — returns repo names matching the query.
|
||||||
|
// mcp.ts should strongly prefer disk grep (find_symbol) when workspace is available.
|
||||||
|
export async function searchCode(
|
||||||
|
pr: PRContext,
|
||||||
|
query: string,
|
||||||
|
): Promise<string[]> {
|
||||||
|
console.log(
|
||||||
|
`Searching code for "${query}" at PR #${pr.prNumber} head for ${pr.owner}/${pr.repo}`,
|
||||||
|
);
|
||||||
|
const res = await client.rest.repository.repoSearch({
|
||||||
|
q: query,
|
||||||
|
limit: 20,
|
||||||
|
});
|
||||||
|
return (res.data.data ?? []).map((r) => r.full_name ?? "").filter(Boolean);
|
||||||
|
}
|
||||||
@@ -1,39 +1 @@
|
|||||||
import * as core from "@actions/core";
|
console.log("Hello via Bun!");
|
||||||
import { createAgent } from "./agents/factory";
|
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
|
||||||
try {
|
|
||||||
// Get inputs
|
|
||||||
const prompt = core.getInput("prompt", { required: true });
|
|
||||||
const anthropicApiKey = core.getInput("anthropic_api_key", { required: true });
|
|
||||||
|
|
||||||
if (!anthropicApiKey) {
|
|
||||||
throw new Error("anthropic_api_key is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
core.info(`🐸 Pullfrog Claude Code Action starting...`);
|
|
||||||
core.info(`Prompt: ${prompt}`);
|
|
||||||
|
|
||||||
// Create and install the Claude agent
|
|
||||||
const agent = createAgent("claude", { apiKey: anthropicApiKey });
|
|
||||||
await agent.install();
|
|
||||||
|
|
||||||
// Execute the agent with the prompt
|
|
||||||
const result = await agent.execute(prompt);
|
|
||||||
|
|
||||||
if (!result.success) {
|
|
||||||
throw new Error(result.error || "Agent execution failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set outputs
|
|
||||||
core.setOutput("status", "success");
|
|
||||||
core.setOutput("prompt", prompt);
|
|
||||||
core.setOutput("output", result.output || "");
|
|
||||||
} catch (error) {
|
|
||||||
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
||||||
core.setFailed(`Action failed: ${errorMessage}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute main function
|
|
||||||
main();
|
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
||||||
|
import { execFileSync } from "node:child_process";
|
||||||
|
import { join, resolve, relative } from "node:path";
|
||||||
|
import type { Tool } from "ollama";
|
||||||
|
import {
|
||||||
|
getFileContents,
|
||||||
|
listDir as giteaListDir,
|
||||||
|
searchCode,
|
||||||
|
} from "./gitea.ts";
|
||||||
|
import type { PRContext } from "./types.ts";
|
||||||
|
|
||||||
|
const MAX_FILE_LINES = 200;
|
||||||
|
const MAX_GREP_RESULTS = 50;
|
||||||
|
|
||||||
|
export const TOOLS: Tool[] = [
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "read_file",
|
||||||
|
description: "Read the contents of a file in the repository.",
|
||||||
|
parameters: {
|
||||||
|
type: "object",
|
||||||
|
required: ["path"],
|
||||||
|
properties: {
|
||||||
|
path: {
|
||||||
|
type: "string",
|
||||||
|
description: "Repo-relative path to the file",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "list_dir",
|
||||||
|
description: "List files and directories at a path in the repository.",
|
||||||
|
parameters: {
|
||||||
|
type: "object",
|
||||||
|
required: ["path"],
|
||||||
|
properties: {
|
||||||
|
path: { type: "string", description: "Repo-relative directory path" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "find_symbol",
|
||||||
|
description:
|
||||||
|
"Search for a symbol, function, or pattern across the repository.",
|
||||||
|
parameters: {
|
||||||
|
type: "object",
|
||||||
|
required: ["symbol"],
|
||||||
|
properties: {
|
||||||
|
symbol: {
|
||||||
|
type: "string",
|
||||||
|
description: "Symbol name or regex pattern to search for",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export class ToolServer {
|
||||||
|
private _callCount = 0;
|
||||||
|
private readonly pr: PRContext;
|
||||||
|
private readonly workspace: string | null;
|
||||||
|
private readonly maxToolCalls: number;
|
||||||
|
|
||||||
|
constructor(pr: PRContext, workspace: string | null, maxToolCalls: number) {
|
||||||
|
this.pr = pr;
|
||||||
|
this.workspace = workspace;
|
||||||
|
this.maxToolCalls = maxToolCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
get tools(): Tool[] {
|
||||||
|
return TOOLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
get callCount(): number {
|
||||||
|
return this._callCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
get atLimit(): boolean {
|
||||||
|
return this._callCount >= this.maxToolCalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetCallCount(): void {
|
||||||
|
this._callCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async execute(name: string, args: Record<string, unknown>): Promise<string> {
|
||||||
|
if (this._callCount >= this.maxToolCalls) {
|
||||||
|
return "[tool call limit reached — conclude your review now]";
|
||||||
|
}
|
||||||
|
this._callCount++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (name) {
|
||||||
|
case "read_file":
|
||||||
|
return await this.readFile(String(args["path"] ?? ""));
|
||||||
|
case "list_dir":
|
||||||
|
return await this.listDir(String(args["path"] ?? ""));
|
||||||
|
case "find_symbol":
|
||||||
|
return await this.findSymbol(String(args["symbol"] ?? ""));
|
||||||
|
default:
|
||||||
|
return `[unknown tool: ${name}]`;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return `[error: ${err instanceof Error ? err.message : String(err)}]`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates path is repo-relative with no traversal or absolute prefix.
|
||||||
|
private safePath(path: string): string | null {
|
||||||
|
if (!path) return null;
|
||||||
|
if (path.startsWith("/") || path.includes("..")) return null;
|
||||||
|
return path.replace(/\/+/g, "/").replace(/\/$/, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async readFile(path: string): Promise<string> {
|
||||||
|
const safe = this.safePath(path);
|
||||||
|
if (!safe) return "[invalid path]";
|
||||||
|
|
||||||
|
if (this.workspace) {
|
||||||
|
const full = join(this.workspace, safe);
|
||||||
|
// Verify resolved path stays inside workspace
|
||||||
|
if (!resolve(full).startsWith(resolve(this.workspace)))
|
||||||
|
return "[invalid path]";
|
||||||
|
if (!existsSync(full)) return "[file not found]";
|
||||||
|
const content = readFileSync(full, "utf8");
|
||||||
|
const lines = content.split("\n");
|
||||||
|
const truncated = lines.slice(0, MAX_FILE_LINES).join("\n");
|
||||||
|
return lines.length > MAX_FILE_LINES
|
||||||
|
? `${truncated}\n... (truncated, ${lines.length - MAX_FILE_LINES} lines omitted)`
|
||||||
|
: truncated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await getFileContents(this.pr, safe);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async listDir(path: string): Promise<string> {
|
||||||
|
const safe = this.safePath(path || ".");
|
||||||
|
if (!safe) return "[invalid path]";
|
||||||
|
|
||||||
|
if (this.workspace) {
|
||||||
|
const full = join(this.workspace, safe);
|
||||||
|
if (!resolve(full).startsWith(resolve(this.workspace)))
|
||||||
|
return "[invalid path]";
|
||||||
|
if (!existsSync(full)) return "[directory not found]";
|
||||||
|
const entries = readdirSync(full, { withFileTypes: true });
|
||||||
|
return entries
|
||||||
|
.map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`)
|
||||||
|
.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
const entries = await giteaListDir(this.pr, safe);
|
||||||
|
return entries.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findSymbol(symbol: string): Promise<string> {
|
||||||
|
if (!symbol) return "[no symbol provided]";
|
||||||
|
|
||||||
|
if (this.workspace) {
|
||||||
|
try {
|
||||||
|
// execFileSync avoids shell injection — symbol is passed as an argument, not interpolated
|
||||||
|
const out = execFileSync(
|
||||||
|
"grep",
|
||||||
|
[
|
||||||
|
"-r",
|
||||||
|
"-n",
|
||||||
|
"--include=*.ts",
|
||||||
|
"--include=*.tsx",
|
||||||
|
"--include=*.js",
|
||||||
|
"--include=*.jsx",
|
||||||
|
"--include=*.py",
|
||||||
|
"--include=*.go",
|
||||||
|
"--include=*.rs",
|
||||||
|
"--include=*.rb",
|
||||||
|
"--include=*.java",
|
||||||
|
"--include=*.kt",
|
||||||
|
symbol,
|
||||||
|
this.workspace,
|
||||||
|
],
|
||||||
|
{ encoding: "utf8", timeout: 5000, maxBuffer: 256 * 1024 },
|
||||||
|
);
|
||||||
|
const lines = out
|
||||||
|
.split("\n")
|
||||||
|
.filter(Boolean)
|
||||||
|
.slice(0, MAX_GREP_RESULTS);
|
||||||
|
// Strip workspace prefix so paths are repo-relative
|
||||||
|
return (
|
||||||
|
lines.map((l) => l.replace(this.workspace! + "/", "")).join("\n") ||
|
||||||
|
"[not found]"
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
return "[not found]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await searchCode(this.pr, symbol);
|
||||||
|
return results.join("\n") || "[not found]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createMcpServer(
|
||||||
|
pr: PRContext,
|
||||||
|
maxToolCalls: number,
|
||||||
|
): ToolServer {
|
||||||
|
console.log("Initializing tool server...");
|
||||||
|
const ws =
|
||||||
|
process.env.GITEA_WORKSPACE ?? process.env.GITHUB_WORKSPACE ?? null;
|
||||||
|
const workspace = ws && existsSync(ws) ? ws : null;
|
||||||
|
return new ToolServer(pr, workspace, maxToolCalls);
|
||||||
|
}
|
||||||
Generated
-601
@@ -1,601 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "action",
|
|
||||||
"version": "0.0.2",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {
|
|
||||||
"": {
|
|
||||||
"name": "action",
|
|
||||||
"version": "0.0.2",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/core": "^1.10.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^20.10.0",
|
|
||||||
"esbuild": "^0.25.9",
|
|
||||||
"typescript": "^5.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/core": {
|
|
||||||
"version": "1.11.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
|
|
||||||
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/exec": "^1.1.1",
|
|
||||||
"@actions/http-client": "^2.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/exec": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/io": "^1.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/http-client": {
|
|
||||||
"version": "2.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
|
|
||||||
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"tunnel": "^0.0.6",
|
|
||||||
"undici": "^5.25.4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@actions/io": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/aix-ppc64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"aix"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-arm": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/android-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"android"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/darwin-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/darwin-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/freebsd-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/freebsd-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-arm": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-ia32": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-loong64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==",
|
|
||||||
"cpu": [
|
|
||||||
"loong64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-mips64el": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==",
|
|
||||||
"cpu": [
|
|
||||||
"mips64el"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-ppc64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==",
|
|
||||||
"cpu": [
|
|
||||||
"ppc64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-riscv64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==",
|
|
||||||
"cpu": [
|
|
||||||
"riscv64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-s390x": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==",
|
|
||||||
"cpu": [
|
|
||||||
"s390x"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/linux-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/netbsd-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"netbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/netbsd-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"netbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/openbsd-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/openbsd-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openbsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/openharmony-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"openharmony"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/sunos-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"sunos"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-arm64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-ia32": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==",
|
|
||||||
"cpu": [
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@esbuild/win32-x64": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@fastify/busboy": {
|
|
||||||
"version": "2.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
|
||||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
|
||||||
"version": "20.19.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.11.tgz",
|
|
||||||
"integrity": "sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"undici-types": "~6.21.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/esbuild": {
|
|
||||||
"version": "0.25.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz",
|
|
||||||
"integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==",
|
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"esbuild": "bin/esbuild"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=18"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@esbuild/aix-ppc64": "0.25.9",
|
|
||||||
"@esbuild/android-arm": "0.25.9",
|
|
||||||
"@esbuild/android-arm64": "0.25.9",
|
|
||||||
"@esbuild/android-x64": "0.25.9",
|
|
||||||
"@esbuild/darwin-arm64": "0.25.9",
|
|
||||||
"@esbuild/darwin-x64": "0.25.9",
|
|
||||||
"@esbuild/freebsd-arm64": "0.25.9",
|
|
||||||
"@esbuild/freebsd-x64": "0.25.9",
|
|
||||||
"@esbuild/linux-arm": "0.25.9",
|
|
||||||
"@esbuild/linux-arm64": "0.25.9",
|
|
||||||
"@esbuild/linux-ia32": "0.25.9",
|
|
||||||
"@esbuild/linux-loong64": "0.25.9",
|
|
||||||
"@esbuild/linux-mips64el": "0.25.9",
|
|
||||||
"@esbuild/linux-ppc64": "0.25.9",
|
|
||||||
"@esbuild/linux-riscv64": "0.25.9",
|
|
||||||
"@esbuild/linux-s390x": "0.25.9",
|
|
||||||
"@esbuild/linux-x64": "0.25.9",
|
|
||||||
"@esbuild/netbsd-arm64": "0.25.9",
|
|
||||||
"@esbuild/netbsd-x64": "0.25.9",
|
|
||||||
"@esbuild/openbsd-arm64": "0.25.9",
|
|
||||||
"@esbuild/openbsd-x64": "0.25.9",
|
|
||||||
"@esbuild/openharmony-arm64": "0.25.9",
|
|
||||||
"@esbuild/sunos-x64": "0.25.9",
|
|
||||||
"@esbuild/win32-arm64": "0.25.9",
|
|
||||||
"@esbuild/win32-ia32": "0.25.9",
|
|
||||||
"@esbuild/win32-x64": "0.25.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tunnel": {
|
|
||||||
"version": "0.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
|
||||||
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/typescript": {
|
|
||||||
"version": "5.9.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
|
|
||||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"bin": {
|
|
||||||
"tsc": "bin/tsc",
|
|
||||||
"tsserver": "bin/tsserver"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.17"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici": {
|
|
||||||
"version": "5.29.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
|
||||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@fastify/busboy": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=14.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/undici-types": {
|
|
||||||
"version": "6.21.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
|
||||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+11
-32
@@ -1,36 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "action",
|
"name": "shockbot",
|
||||||
"version": "0.0.5",
|
"module": "index.ts",
|
||||||
"main": "index.js",
|
|
||||||
"directories": {
|
|
||||||
"example": "examples"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
|
||||||
|
|
||||||
"build": "node esbuild.config.js",
|
|
||||||
"dev": "node esbuild.config.js --watch",
|
|
||||||
"prepare": "husky"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/core": "^1.10.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^20.10.0",
|
|
||||||
"esbuild": "^0.25.9",
|
|
||||||
"husky": "^9.0.0",
|
|
||||||
"typescript": "^5.3.0"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/pullfrog/pullfrog.git"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bugs": {
|
"private": true,
|
||||||
"url": "https://github.com/pullfrog/pullfrog/issues"
|
"devDependencies": {
|
||||||
|
"@go-gitea/sdk.js": "^0.2.1",
|
||||||
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||||
|
"@types/bun": "latest",
|
||||||
|
"ollama": "^0.6.3"
|
||||||
},
|
},
|
||||||
"homepage": "https://github.com/pullfrog/pullfrog#readme"
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
-372
@@ -1,372 +0,0 @@
|
|||||||
lockfileVersion: '9.0'
|
|
||||||
|
|
||||||
settings:
|
|
||||||
autoInstallPeers: true
|
|
||||||
excludeLinksFromLockfile: false
|
|
||||||
|
|
||||||
importers:
|
|
||||||
|
|
||||||
.:
|
|
||||||
dependencies:
|
|
||||||
'@actions/core':
|
|
||||||
specifier: ^1.10.1
|
|
||||||
version: 1.11.1
|
|
||||||
devDependencies:
|
|
||||||
'@types/node':
|
|
||||||
specifier: ^20.10.0
|
|
||||||
version: 20.19.11
|
|
||||||
esbuild:
|
|
||||||
specifier: ^0.25.9
|
|
||||||
version: 0.25.9
|
|
||||||
husky:
|
|
||||||
specifier: ^9.0.0
|
|
||||||
version: 9.1.7
|
|
||||||
typescript:
|
|
||||||
specifier: ^5.3.0
|
|
||||||
version: 5.9.2
|
|
||||||
|
|
||||||
packages:
|
|
||||||
|
|
||||||
'@actions/core@1.11.1':
|
|
||||||
resolution: {integrity: sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==}
|
|
||||||
|
|
||||||
'@actions/exec@1.1.1':
|
|
||||||
resolution: {integrity: sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==}
|
|
||||||
|
|
||||||
'@actions/http-client@2.2.3':
|
|
||||||
resolution: {integrity: sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==}
|
|
||||||
|
|
||||||
'@actions/io@1.1.3':
|
|
||||||
resolution: {integrity: sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==}
|
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [aix]
|
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.9':
|
|
||||||
resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [android]
|
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [freebsd]
|
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.9':
|
|
||||||
resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.9':
|
|
||||||
resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ia32]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [loong64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.9':
|
|
||||||
resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [mips64el]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ppc64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [riscv64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.9':
|
|
||||||
resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [s390x]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [linux]
|
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [netbsd]
|
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [openbsd]
|
|
||||||
|
|
||||||
'@esbuild/openharmony-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [openharmony]
|
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [sunos]
|
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [arm64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.9':
|
|
||||||
resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [ia32]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.9':
|
|
||||||
resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
cpu: [x64]
|
|
||||||
os: [win32]
|
|
||||||
|
|
||||||
'@fastify/busboy@2.1.1':
|
|
||||||
resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==}
|
|
||||||
engines: {node: '>=14'}
|
|
||||||
|
|
||||||
'@types/node@20.19.11':
|
|
||||||
resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==}
|
|
||||||
|
|
||||||
esbuild@0.25.9:
|
|
||||||
resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
husky@9.1.7:
|
|
||||||
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
tunnel@0.0.6:
|
|
||||||
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}
|
|
||||||
engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'}
|
|
||||||
|
|
||||||
typescript@5.9.2:
|
|
||||||
resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
|
|
||||||
engines: {node: '>=14.17'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
undici-types@6.21.0:
|
|
||||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
|
||||||
|
|
||||||
undici@5.29.0:
|
|
||||||
resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==}
|
|
||||||
engines: {node: '>=14.0'}
|
|
||||||
|
|
||||||
snapshots:
|
|
||||||
|
|
||||||
'@actions/core@1.11.1':
|
|
||||||
dependencies:
|
|
||||||
'@actions/exec': 1.1.1
|
|
||||||
'@actions/http-client': 2.2.3
|
|
||||||
|
|
||||||
'@actions/exec@1.1.1':
|
|
||||||
dependencies:
|
|
||||||
'@actions/io': 1.1.3
|
|
||||||
|
|
||||||
'@actions/http-client@2.2.3':
|
|
||||||
dependencies:
|
|
||||||
tunnel: 0.0.6
|
|
||||||
undici: 5.29.0
|
|
||||||
|
|
||||||
'@actions/io@1.1.3': {}
|
|
||||||
|
|
||||||
'@esbuild/aix-ppc64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-arm@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/android-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/darwin-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/darwin-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/freebsd-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/freebsd-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-arm@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-ia32@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-loong64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-mips64el@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-ppc64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-riscv64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-s390x@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/linux-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/netbsd-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/netbsd-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/openbsd-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/openbsd-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/openharmony-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/sunos-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-arm64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-ia32@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@esbuild/win32-x64@0.25.9':
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
'@fastify/busboy@2.1.1': {}
|
|
||||||
|
|
||||||
'@types/node@20.19.11':
|
|
||||||
dependencies:
|
|
||||||
undici-types: 6.21.0
|
|
||||||
|
|
||||||
esbuild@0.25.9:
|
|
||||||
optionalDependencies:
|
|
||||||
'@esbuild/aix-ppc64': 0.25.9
|
|
||||||
'@esbuild/android-arm': 0.25.9
|
|
||||||
'@esbuild/android-arm64': 0.25.9
|
|
||||||
'@esbuild/android-x64': 0.25.9
|
|
||||||
'@esbuild/darwin-arm64': 0.25.9
|
|
||||||
'@esbuild/darwin-x64': 0.25.9
|
|
||||||
'@esbuild/freebsd-arm64': 0.25.9
|
|
||||||
'@esbuild/freebsd-x64': 0.25.9
|
|
||||||
'@esbuild/linux-arm': 0.25.9
|
|
||||||
'@esbuild/linux-arm64': 0.25.9
|
|
||||||
'@esbuild/linux-ia32': 0.25.9
|
|
||||||
'@esbuild/linux-loong64': 0.25.9
|
|
||||||
'@esbuild/linux-mips64el': 0.25.9
|
|
||||||
'@esbuild/linux-ppc64': 0.25.9
|
|
||||||
'@esbuild/linux-riscv64': 0.25.9
|
|
||||||
'@esbuild/linux-s390x': 0.25.9
|
|
||||||
'@esbuild/linux-x64': 0.25.9
|
|
||||||
'@esbuild/netbsd-arm64': 0.25.9
|
|
||||||
'@esbuild/netbsd-x64': 0.25.9
|
|
||||||
'@esbuild/openbsd-arm64': 0.25.9
|
|
||||||
'@esbuild/openbsd-x64': 0.25.9
|
|
||||||
'@esbuild/openharmony-arm64': 0.25.9
|
|
||||||
'@esbuild/sunos-x64': 0.25.9
|
|
||||||
'@esbuild/win32-arm64': 0.25.9
|
|
||||||
'@esbuild/win32-ia32': 0.25.9
|
|
||||||
'@esbuild/win32-x64': 0.25.9
|
|
||||||
|
|
||||||
husky@9.1.7: {}
|
|
||||||
|
|
||||||
tunnel@0.0.6: {}
|
|
||||||
|
|
||||||
typescript@5.9.2: {}
|
|
||||||
|
|
||||||
undici-types@6.21.0: {}
|
|
||||||
|
|
||||||
undici@5.29.0:
|
|
||||||
dependencies:
|
|
||||||
'@fastify/busboy': 2.1.1
|
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
import { Ollama } from "ollama";
|
||||||
|
import type { Message } from "ollama";
|
||||||
|
import type {
|
||||||
|
DiffChunk,
|
||||||
|
ChunkReview,
|
||||||
|
ReviewResult,
|
||||||
|
AggregatedReview,
|
||||||
|
Finding,
|
||||||
|
} from "./types.ts";
|
||||||
|
import type { ToolServer } from "./mcp.ts";
|
||||||
|
|
||||||
|
const ollama = new Ollama({ host: process.env.OLLAMA_HOST });
|
||||||
|
|
||||||
|
const SYSTEM_PROMPT = `You are a code reviewer. Your job is to find real bugs, security issues, and significant problems in the changed lines below. Do not comment on style, formatting, or personal preference unless they cause functional problems.
|
||||||
|
|
||||||
|
Be concise. Each comment should say what the problem is and why it matters.
|
||||||
|
|
||||||
|
You have tools available to read files, list directories, and search for symbols in the repository. Use them when you need more context to understand the code being reviewed.
|
||||||
|
|
||||||
|
When you are done gathering context and ready to report your findings, you MUST respond with ONLY a valid JSON object in this exact shape:
|
||||||
|
{
|
||||||
|
"issues": [
|
||||||
|
{ "line": <line number>, "severity": "<error|warning|nit>", "comment": "<your comment>" }
|
||||||
|
],
|
||||||
|
"summary": "<one paragraph overall summary>"
|
||||||
|
}
|
||||||
|
|
||||||
|
Do not include any text outside the JSON object.`;
|
||||||
|
|
||||||
|
export function buildReviewPrompt(
|
||||||
|
chunk: DiffChunk,
|
||||||
|
userPrompt: string,
|
||||||
|
): string {
|
||||||
|
return `${userPrompt}
|
||||||
|
|
||||||
|
File: ${chunk.filename} (${chunk.language})
|
||||||
|
Hunk: ${chunk.context}
|
||||||
|
|
||||||
|
${chunk.hunk}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseReviewResult(content: string): ReviewResult | null {
|
||||||
|
// Strip markdown code fences the model may have added despite instructions
|
||||||
|
const stripped = content
|
||||||
|
.replace(/^```(?:json)?\s*/m, "")
|
||||||
|
.replace(/\s*```\s*$/m, "")
|
||||||
|
.trim();
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(stripped);
|
||||||
|
if (!Array.isArray(parsed.issues) || typeof parsed.summary !== "string")
|
||||||
|
return null;
|
||||||
|
return parsed as ReviewResult;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function reviewChunk(
|
||||||
|
chunk: DiffChunk,
|
||||||
|
userPrompt: string,
|
||||||
|
model: string,
|
||||||
|
contextWindow: number,
|
||||||
|
mcpServer: ToolServer,
|
||||||
|
): Promise<ChunkReview> {
|
||||||
|
console.log(`Reviewing chunk from ${chunk.filename} with model ${model}...`);
|
||||||
|
mcpServer.resetCallCount();
|
||||||
|
|
||||||
|
const messages: Message[] = [
|
||||||
|
{ role: "system", content: SYSTEM_PROMPT },
|
||||||
|
{ role: "user", content: buildReviewPrompt(chunk, userPrompt) },
|
||||||
|
];
|
||||||
|
|
||||||
|
let forceConclusion = false;
|
||||||
|
let parseFailures = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const response = await ollama.chat({
|
||||||
|
model,
|
||||||
|
messages,
|
||||||
|
tools: forceConclusion ? undefined : mcpServer.tools,
|
||||||
|
format: "json",
|
||||||
|
stream: false,
|
||||||
|
keep_alive: -1,
|
||||||
|
options: { num_ctx: contextWindow, temperature: 0.2 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const msg = response.message;
|
||||||
|
|
||||||
|
// Model called one or more tools
|
||||||
|
if (msg.tool_calls && msg.tool_calls.length > 0) {
|
||||||
|
messages.push({
|
||||||
|
role: "assistant",
|
||||||
|
content: msg.content ?? "",
|
||||||
|
tool_calls: msg.tool_calls,
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const call of msg.tool_calls) {
|
||||||
|
const result = await mcpServer.execute(
|
||||||
|
call.function.name,
|
||||||
|
call.function.arguments as Record<string, unknown>,
|
||||||
|
);
|
||||||
|
messages.push({
|
||||||
|
role: "tool",
|
||||||
|
content: result,
|
||||||
|
tool_name: call.function.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcpServer.atLimit) {
|
||||||
|
forceConclusion = true;
|
||||||
|
messages.push({
|
||||||
|
role: "user",
|
||||||
|
content:
|
||||||
|
"You have reached the tool call limit. Respond now with your final JSON review.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Model produced content — try to parse as final JSON review
|
||||||
|
const content = (msg.content ?? "").trim();
|
||||||
|
|
||||||
|
if (content) {
|
||||||
|
const result = parseReviewResult(content);
|
||||||
|
if (result) return { chunk, result };
|
||||||
|
|
||||||
|
// Parse failed — give the model one chance to fix it
|
||||||
|
parseFailures++;
|
||||||
|
if (parseFailures <= 1) {
|
||||||
|
messages.push(
|
||||||
|
{ role: "assistant", content },
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content:
|
||||||
|
"Your response was not valid JSON. Respond with ONLY the JSON review object, no other text.",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
forceConclusion = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second failure — return raw content as summary rather than crash
|
||||||
|
return {
|
||||||
|
chunk,
|
||||||
|
result: {
|
||||||
|
issues: [],
|
||||||
|
summary: `[parse error] ${content.slice(0, 500)}`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty response — shouldn't happen, but bail rather than loop forever
|
||||||
|
return {
|
||||||
|
chunk,
|
||||||
|
result: { issues: [], summary: "[empty response from model]" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function aggregateFindings(results: ChunkReview[]): AggregatedReview {
|
||||||
|
console.log(`Aggregating findings from ${results.length} reviewed chunks...`);
|
||||||
|
const findings: Finding[] = results.flatMap(({ chunk, result }) =>
|
||||||
|
result.issues.map((issue) => ({ ...issue, filename: chunk.filename })),
|
||||||
|
);
|
||||||
|
const summaries = results.map((r) => r.result.summary).filter(Boolean);
|
||||||
|
return { findings, summaries };
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"action": "opened",
|
||||||
|
"number": 4,
|
||||||
|
"pull_request": {
|
||||||
|
"number": 4,
|
||||||
|
"title": "Add devices section",
|
||||||
|
"draft": false,
|
||||||
|
"head": {
|
||||||
|
"sha": "94f4a680369ab07b076ba5679f05cc157e8c9a9c",
|
||||||
|
"ref": "AddDevicesSection"
|
||||||
|
},
|
||||||
|
"base": {
|
||||||
|
"ref": "master"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"name": "test-repo",
|
||||||
|
"owner": {
|
||||||
|
"login": "ShockVPN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"action": "opened",
|
||||||
|
"number": 4,
|
||||||
|
"pull_request": {
|
||||||
|
"number": 4,
|
||||||
|
"head": {
|
||||||
|
"sha": "94f4a680369ab07b076ba5679f05cc157e8c9a9c"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"name": "test-repo",
|
||||||
|
"owner": {
|
||||||
|
"login": "ShockVPN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
-12
@@ -1,17 +1,29 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ES2020",
|
// Environment setup & latest features
|
||||||
"module": "commonjs",
|
"lib": ["ESNext"],
|
||||||
"lib": ["ES2020"],
|
"target": "ESNext",
|
||||||
"outDir": "./",
|
"module": "Preserve",
|
||||||
"rootDir": "./",
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"esModuleInterop": true,
|
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"declaration": false,
|
"noUncheckedIndexedAccess": true,
|
||||||
"sourceMap": false
|
"noImplicitOverride": true,
|
||||||
},
|
|
||||||
"include": ["*.ts"],
|
// Some stricter flags (disabled by default)
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
export interface ActionConfig {
|
||||||
|
prompt: string;
|
||||||
|
model: string;
|
||||||
|
contextWindow: number;
|
||||||
|
maxToolCalls: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EnvConfig {
|
||||||
|
botToken: string;
|
||||||
|
ollamaHost: string;
|
||||||
|
giteaUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PRContext {
|
||||||
|
owner: string;
|
||||||
|
repo: string;
|
||||||
|
prNumber: number;
|
||||||
|
headSha: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TriggerType = "pr_open" | "issue_comment";
|
||||||
|
|
||||||
|
export interface DiffChunk {
|
||||||
|
filename: string;
|
||||||
|
language: string;
|
||||||
|
hunk: string;
|
||||||
|
context: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type MCPToolName = "read_file" | "list_dir" | "find_symbol";
|
||||||
|
|
||||||
|
export type ReviewSeverity = "error" | "warning" | "nit";
|
||||||
|
|
||||||
|
export interface ReviewIssue {
|
||||||
|
line: number;
|
||||||
|
severity: ReviewSeverity;
|
||||||
|
comment: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ReviewResult {
|
||||||
|
issues: ReviewIssue[];
|
||||||
|
summary: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ChunkReview {
|
||||||
|
chunk: DiffChunk;
|
||||||
|
result: ReviewResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Finding extends ReviewIssue {
|
||||||
|
filename: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AggregatedReview {
|
||||||
|
findings: Finding[];
|
||||||
|
summaries: string[];
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import { exec } from "node:child_process";
|
|
||||||
import { promisify } from "node:util";
|
|
||||||
|
|
||||||
export const execAsync = promisify(exec);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a shell command with optional environment variables
|
|
||||||
*/
|
|
||||||
export async function executeCommand(
|
|
||||||
command: string,
|
|
||||||
env?: Record<string, string>
|
|
||||||
): Promise<{ stdout: string; stderr: string }> {
|
|
||||||
const execEnv = env ? { ...process.env, ...env } : process.env;
|
|
||||||
return execAsync(command, { env: execEnv });
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { mkdtempSync, writeFileSync } from "node:fs";
|
|
||||||
import { tmpdir } from "node:os";
|
|
||||||
import { join } from "node:path";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a temporary file with the given content
|
|
||||||
*/
|
|
||||||
export function createTempFile(content: string, filename = "temp.txt"): string {
|
|
||||||
const tempDir = mkdtempSync(join(tmpdir(), "pullfrog-"));
|
|
||||||
const filePath = join(tempDir, filename);
|
|
||||||
writeFileSync(filePath, content);
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user