fix: address re-review findings — nil pointer, races, curl, clone error
Important: - Fix nil pointer dereference on resp.StatusCode when err!=nil (8 sites) - Replace curl shell-out with net/http in monitor inbox check - Handle clone failure in prep.go (was silently swallowed) - Use GitHubOrg() instead of hardcoded "dAppCore" Medium: - Fix JSONL append race (read+write → os.OpenFile O_APPEND) - Remove dead google/mcp/ directory Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
6d04c893b7
commit
e66ea0512b
12 changed files with 92 additions and 334 deletions
|
|
@ -1,67 +0,0 @@
|
||||||
# Core CLI MCP Server
|
|
||||||
|
|
||||||
This directory contains an MCP server that exposes the core CLI commands as tools for AI agents.
|
|
||||||
|
|
||||||
## Tools
|
|
||||||
|
|
||||||
### `core_go_test`
|
|
||||||
|
|
||||||
Run Go tests.
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
- `filter` (string, optional): Filter tests by name.
|
|
||||||
- `coverage` (boolean, optional): Enable code coverage. Defaults to `false`.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tool": "core_go_test",
|
|
||||||
"parameters": {
|
|
||||||
"filter": "TestMyFunction",
|
|
||||||
"coverage": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `core_dev_health`
|
|
||||||
|
|
||||||
Check the health of the monorepo.
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tool": "core_dev_health",
|
|
||||||
"parameters": {}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `core_dev_commit`
|
|
||||||
|
|
||||||
Commit changes across repositories.
|
|
||||||
|
|
||||||
**Parameters:**
|
|
||||||
|
|
||||||
- `message` (string, required): The commit message.
|
|
||||||
- `repos` (array of strings, optional): A list of repositories to commit to.
|
|
||||||
|
|
||||||
**Example:**
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"tool": "core_dev_commit",
|
|
||||||
"parameters": {
|
|
||||||
"message": "feat: Implement new feature",
|
|
||||||
"repos": [
|
|
||||||
"core-agent",
|
|
||||||
"another-repo"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GoTestRequest struct {
|
|
||||||
Filter string `json:"filter,omitempty"`
|
|
||||||
Coverage bool `json:"coverage,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GoTestResponse struct {
|
|
||||||
Output string `json:"output"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DevHealthResponse struct {
|
|
||||||
Output string `json:"output"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DevCommitRequest struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Repos []string `json:"repos,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type DevCommitResponse struct {
|
|
||||||
Output string `json:"output"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func goTestHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != http.MethodPost {
|
|
||||||
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var req GoTestRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"go", "test"}
|
|
||||||
if req.Filter != "" {
|
|
||||||
args = append(args, "-run", req.Filter)
|
|
||||||
}
|
|
||||||
if req.Coverage {
|
|
||||||
args = append(args, "-cover")
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("core", args...)
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
|
|
||||||
resp := GoTestResponse{
|
|
||||||
Output: string(output),
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
resp.Error = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func devHealthHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != http.MethodPost {
|
|
||||||
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cmd := exec.Command("core", "dev", "health")
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
|
|
||||||
resp := DevHealthResponse{
|
|
||||||
Output: string(output),
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
resp.Error = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func devCommitHandler(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method != http.MethodPost {
|
|
||||||
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var req DevCommitRequest
|
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
||||||
http.Error(w, "Invalid request body", http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{"dev", "commit", "-m", req.Message}
|
|
||||||
if len(req.Repos) > 0 {
|
|
||||||
args = append(args, "--repos", strings.Join(req.Repos, ","))
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command("core", args...)
|
|
||||||
output, err := cmd.CombinedOutput()
|
|
||||||
|
|
||||||
resp := DevCommitResponse{
|
|
||||||
Output: string(output),
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
resp.Error = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
json.NewEncoder(w).Encode(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
http.HandleFunc("/core_go_test", goTestHandler)
|
|
||||||
http.HandleFunc("/core_dev_health", devHealthHandler)
|
|
||||||
http.HandleFunc("/core_dev_commit", devCommitHandler)
|
|
||||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
fmt.Fprintf(w, "MCP Server is running")
|
|
||||||
})
|
|
||||||
|
|
||||||
log.Println("Starting MCP server on :8080")
|
|
||||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
|
||||||
log.Fatalf("could not start server: %s\n", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
|
||||||
// Get the absolute path to the testdata directory
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
testdataPath := filepath.Join(wd, "testdata")
|
|
||||||
|
|
||||||
// Add the absolute path to the PATH
|
|
||||||
os.Setenv("PATH", testdataPath+":"+os.Getenv("PATH"))
|
|
||||||
m.Run()
|
|
||||||
}
|
|
||||||
func TestGoTestHandler(t *testing.T) {
|
|
||||||
reqBody := GoTestRequest{
|
|
||||||
Filter: "TestMyFunction",
|
|
||||||
Coverage: true,
|
|
||||||
}
|
|
||||||
body, _ := json.Marshal(reqBody)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "/core_go_test", bytes.NewBuffer(body))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rr := httptest.NewRecorder()
|
|
||||||
handler := http.HandlerFunc(goTestHandler)
|
|
||||||
|
|
||||||
handler.ServeHTTP(rr, req)
|
|
||||||
|
|
||||||
if status := rr.Code; status != http.StatusOK {
|
|
||||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
|
||||||
status, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resp GoTestResponse
|
|
||||||
if err := json.NewDecoder(rr.Body).Decode(&resp); err != nil {
|
|
||||||
t.Fatalf("could not decode response: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Error != "" {
|
|
||||||
t.Errorf("handler returned an unexpected error: %v", resp.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDevHealthHandler(t *testing.T) {
|
|
||||||
req, err := http.NewRequest("POST", "/core_dev_health", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rr := httptest.NewRecorder()
|
|
||||||
handler := http.HandlerFunc(devHealthHandler)
|
|
||||||
|
|
||||||
handler.ServeHTTP(rr, req)
|
|
||||||
|
|
||||||
if status := rr.Code; status != http.StatusOK {
|
|
||||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
|
||||||
status, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resp DevHealthResponse
|
|
||||||
if err := json.NewDecoder(rr.Body).Decode(&resp); err != nil {
|
|
||||||
t.Fatalf("could not decode response: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Error != "" {
|
|
||||||
t.Errorf("handler returned an unexpected error: %v", resp.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDevCommitHandler(t *testing.T) {
|
|
||||||
reqBody := DevCommitRequest{
|
|
||||||
Message: "test commit",
|
|
||||||
}
|
|
||||||
body, _ := json.Marshal(reqBody)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", "/core_dev_commit", bytes.NewBuffer(body))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
rr := httptest.NewRecorder()
|
|
||||||
handler := http.HandlerFunc(devCommitHandler)
|
|
||||||
|
|
||||||
handler.ServeHTTP(rr, req)
|
|
||||||
|
|
||||||
if status := rr.Code; status != http.StatusOK {
|
|
||||||
t.Errorf("handler returned wrong status code: got %v want %v",
|
|
||||||
status, http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
var resp DevCommitResponse
|
|
||||||
if err := json.NewDecoder(rr.Body).Decode(&resp); err != nil {
|
|
||||||
t.Fatalf("could not decode response: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.Error != "" {
|
|
||||||
t.Errorf("handler returned an unexpected error: %v", resp.Error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
2
google/mcp/testdata/core
vendored
2
google/mcp/testdata/core
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
exit 0
|
|
||||||
|
|
@ -196,7 +196,12 @@ func (s *PrepSubsystem) resolveLabelIDs(ctx context.Context, org, repo string, n
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
@ -252,7 +257,12 @@ func (s *PrepSubsystem) createLabel(ctx context.Context, org, repo, name string)
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 201 {
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 201 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ package agentic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
coreio "forge.lthn.ai/core/go-io"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CompletionEvent is emitted when a dispatched agent finishes.
|
// CompletionEvent is emitted when a dispatched agent finishes.
|
||||||
|
|
@ -39,6 +40,10 @@ func emitCompletionEvent(agent, workspace string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append to events log
|
// Append to events log
|
||||||
existing, _ := coreio.Local.Read(eventsFile)
|
f, err := os.OpenFile(eventsFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
coreio.Local.Write(eventsFile, existing+string(data)+"\n")
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(append(data, '\n'))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,3 +42,11 @@ func AgentName() string {
|
||||||
}
|
}
|
||||||
return "charon"
|
return "charon"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitHubOrg returns the GitHub org for mirror operations.
|
||||||
|
func GitHubOrg() string {
|
||||||
|
if org := os.Getenv("GITHUB_ORG"); org != "" {
|
||||||
|
return org
|
||||||
|
}
|
||||||
|
return "dAppCore"
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,12 @@ func (s *PrepSubsystem) listRepoPRs(ctx context.Context, org, repo, state string
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return nil, coreerr.E("listRepoPRs", "failed to list PRs for "+repo, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return nil, coreerr.E("listRepoPRs", "failed to list PRs for "+repo, err)
|
return nil, coreerr.E("listRepoPRs", "failed to list PRs for "+repo, err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,9 @@ func (s *PrepSubsystem) prepWorkspace(ctx context.Context, _ *mcp.CallToolReques
|
||||||
// 1. Clone repo into src/ and create feature branch
|
// 1. Clone repo into src/ and create feature branch
|
||||||
srcDir := filepath.Join(wsDir, "src")
|
srcDir := filepath.Join(wsDir, "src")
|
||||||
cloneCmd := exec.CommandContext(ctx, "git", "clone", repoPath, srcDir)
|
cloneCmd := exec.CommandContext(ctx, "git", "clone", repoPath, srcDir)
|
||||||
cloneCmd.Run()
|
if err := cloneCmd.Run(); err != nil {
|
||||||
|
return nil, PrepOutput{}, coreerr.E("prep", "git clone failed for "+input.Repo, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Create feature branch
|
// Create feature branch
|
||||||
taskSlug := strings.Map(func(r rune) rune {
|
taskSlug := strings.Map(func(r rune) rune {
|
||||||
|
|
@ -459,7 +461,12 @@ func (s *PrepSubsystem) pullWiki(ctx context.Context, org, repo, wsDir string) i
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
@ -544,7 +551,12 @@ func (s *PrepSubsystem) generateContext(ctx context.Context, repo, wsDir string)
|
||||||
req.Header.Set("Authorization", "Bearer "+s.brainKey)
|
req.Header.Set("Authorization", "Bearer "+s.brainKey)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
@ -637,7 +649,12 @@ func (s *PrepSubsystem) generateTodo(ctx context.Context, org, repo string, issu
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
|
||||||
|
|
@ -242,7 +242,7 @@ func (s *PrepSubsystem) pushAndMerge(ctx context.Context, repoDir, repo string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark PR ready if draft
|
// Mark PR ready if draft
|
||||||
readyCmd := exec.CommandContext(ctx, "gh", "pr", "ready", "--repo", "dAppCore/"+repo)
|
readyCmd := exec.CommandContext(ctx, "gh", "pr", "ready", "--repo", GitHubOrg()+"/"+repo)
|
||||||
readyCmd.Dir = repoDir
|
readyCmd.Dir = repoDir
|
||||||
readyCmd.Run() // Ignore error — might already be ready
|
readyCmd.Run() // Ignore error — might already be ready
|
||||||
|
|
||||||
|
|
@ -339,8 +339,11 @@ func (s *PrepSubsystem) storeReviewOutput(repoDir, repo, reviewer, output string
|
||||||
jsonLine, _ := json.Marshal(entry)
|
jsonLine, _ := json.Marshal(entry)
|
||||||
|
|
||||||
jsonlPath := filepath.Join(dataDir, "reviews.jsonl")
|
jsonlPath := filepath.Join(dataDir, "reviews.jsonl")
|
||||||
existing, _ := coreio.Local.Read(jsonlPath)
|
f, err := os.OpenFile(jsonlPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||||
coreio.Local.Write(jsonlPath, existing+string(jsonLine)+"\n")
|
if err == nil {
|
||||||
|
defer f.Close()
|
||||||
|
f.Write(append(jsonLine, '\n'))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// saveRateLimitState persists rate limit info for cross-run awareness.
|
// saveRateLimitState persists rate limit info for cross-run awareness.
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,12 @@ func (s *PrepSubsystem) listOrgRepos(ctx context.Context, org string) ([]string,
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return nil, coreerr.E("scan.listOrgRepos", "failed to list repos", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return nil, coreerr.E("scan.listOrgRepos", "failed to list repos", err)
|
return nil, coreerr.E("scan.listOrgRepos", "failed to list repos", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
@ -129,7 +134,12 @@ func (s *PrepSubsystem) listRepoIssues(ctx context.Context, org, repo, label str
|
||||||
req.Header.Set("Authorization", "token "+s.forgeToken)
|
req.Header.Set("Authorization", "token "+s.forgeToken)
|
||||||
|
|
||||||
resp, err := s.client.Do(req)
|
resp, err := s.client.Do(req)
|
||||||
if err != nil || resp.StatusCode != 200 {
|
if err != nil {
|
||||||
|
return nil, coreerr.E("scan.listRepoIssues", "failed to list issues for "+repo, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != 200 {
|
||||||
return nil, coreerr.E("scan.listRepoIssues", "failed to list issues for "+repo, err)
|
return nil, coreerr.E("scan.listRepoIssues", "failed to list issues for "+repo, err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
@ -238,14 +238,26 @@ func (m *Subsystem) checkInbox() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the API to check inbox
|
// Call the API to check inbox
|
||||||
cmd := exec.Command("curl", "-sf",
|
apiURL := os.Getenv("CORE_API_URL")
|
||||||
"-H", "Authorization: Bearer "+strings.TrimSpace(apiKeyStr),
|
if apiURL == "" {
|
||||||
"https://api.lthn.sh/v1/messages/inbox?agent="+agentic.AgentName(),
|
apiURL = "https://api.lthn.sh"
|
||||||
)
|
}
|
||||||
out, err := cmd.Output()
|
req, err := http.NewRequest("GET", apiURL+"/v1/messages/inbox?agent="+agentic.AgentName(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+strings.TrimSpace(apiKeyStr))
|
||||||
|
|
||||||
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
httpResp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer httpResp.Body.Close()
|
||||||
|
|
||||||
|
if httpResp.StatusCode != 200 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var resp struct {
|
var resp struct {
|
||||||
Data []struct {
|
Data []struct {
|
||||||
|
|
@ -254,7 +266,7 @@ func (m *Subsystem) checkInbox() string {
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
}
|
}
|
||||||
if json.Unmarshal(out, &resp) != nil {
|
if json.NewDecoder(httpResp.Body).Decode(&resp) != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue