mirror of
https://github.com/alibaba/open-code-review.git
synced 2026-07-09 17:28:58 +00:00
feat: argus 改名 opencodereview
This commit is contained in:
parent
9e449d5a24
commit
3d2029dbfa
32 changed files with 507 additions and 160 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -10,7 +10,7 @@ temp/
|
|||
|
||||
bin/
|
||||
|
||||
/argus
|
||||
/opencodereview
|
||||
|
||||
# Mac OS X
|
||||
.DS_Store
|
||||
|
|
|
|||
6
Makefile
6
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
build-all dist sha256sum version-info \
|
||||
build-linux-amd64 build-linux-arm64 build-darwin-amd64 build-darwin-arm64
|
||||
|
||||
BINARY_NAME := argus
|
||||
BINARY_NAME := opencodereview
|
||||
GO := go
|
||||
DIST_DIR := ./dist
|
||||
|
||||
|
|
@ -21,12 +21,12 @@ LD_FLAGS := -s -w \
|
|||
define BUILD_PLATFORM
|
||||
GOOS=$(1) GOARCH=$(2) CGO_ENABLED=0 $(GO) build -ldflags "$(LD_FLAGS)" \
|
||||
-o $(DIST_DIR)/$(BINARY_NAME)-$(VERSION)-$(1)-$(2) \
|
||||
./cmd/argus
|
||||
./cmd/opencodereview
|
||||
endef
|
||||
|
||||
# ── Development targets ──────────────────────────────────────────────────────
|
||||
build:
|
||||
$(GO) build -ldflags "$(LD_FLAGS)" -o $(DIST_DIR)/$(BINARY_NAME) ./cmd/argus
|
||||
$(GO) build -ldflags "$(LD_FLAGS)" -o $(DIST_DIR)/$(BINARY_NAME) ./cmd/opencodereview
|
||||
|
||||
test:
|
||||
$(GO) test -v -race -count=1 ./...
|
||||
|
|
|
|||
50
README.md
50
README.md
|
|
@ -1,6 +1,6 @@
|
|||
# Argus
|
||||
# OpenCodeReview
|
||||
|
||||
AI-powered code review CLI tool built in Go. Argus reads git diffs, sends changed files to a configurable LLM (via OpenAI-compatible API), and generates structured code review comments — acting as an autonomous AI reviewer that can read your full project context, not just the diff.
|
||||
AI-powered code review CLI tool built in Go. OpenCodeReview reads git diffs, sends changed files to a configurable LLM (via OpenAI-compatible API), and generates structured code review comments — acting as an autonomous AI reviewer that can read your full project context, not just the diff.
|
||||
|
||||
## Features
|
||||
|
||||
|
|
@ -20,15 +20,15 @@ AI-powered code review CLI tool built in Go. Argus reads git diffs, sends change
|
|||
Requires [Go](https://go.dev/) 1.24+.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/argus-review/argus.git
|
||||
cd argus
|
||||
make # builds binary at ./bin/argus
|
||||
git clone https://github.com/open-code-review/open-code-review.git
|
||||
cd open-code-review
|
||||
make # builds binary at ./bin/opencodereview
|
||||
```
|
||||
|
||||
Or build directly:
|
||||
|
||||
```bash
|
||||
go build -o bin/argus ./cmd/argus
|
||||
go build -o bin/opencodereview ./cmd/opencodereview
|
||||
```
|
||||
|
||||
Add `bin/` to your `$PATH` or copy the binary somewhere accessible.
|
||||
|
|
@ -37,20 +37,20 @@ Add `bin/` to your `$PATH` or copy the binary somewhere accessible.
|
|||
|
||||
### 1. Configure your LLM
|
||||
|
||||
Argus connects to any OpenAI-compatible API endpoint. Set up your credentials:
|
||||
OpenCodeReview connects to any OpenAI-compatible API endpoint. Set up your credentials:
|
||||
|
||||
```bash
|
||||
argus config set llm.url https://your-api-endpoint/v1/chat/completions
|
||||
argus config set llm.auth_token your-api-key-here
|
||||
argus config set llm.model claude-opus-4-6
|
||||
ocr config set llm.url https://your-api-endpoint/v1/chat/completions
|
||||
ocr config set llm.auth_token your-api-key-here
|
||||
ocr config set llm.model claude-opus-4-6
|
||||
```
|
||||
|
||||
Configuration is stored at `~/.argus/config.json`.
|
||||
Configuration is stored at `~/.open-code-review/config.json`.
|
||||
|
||||
### 2. Test connectivity
|
||||
|
||||
```bash
|
||||
argus llm test
|
||||
ocr llm test
|
||||
```
|
||||
|
||||
### 3. Run a review
|
||||
|
|
@ -59,13 +59,13 @@ Navigate to any git repository and run:
|
|||
|
||||
```bash
|
||||
# Review all staged, unstaged, and untracked changes
|
||||
argus review
|
||||
ocr review
|
||||
|
||||
# Review differences between two branches
|
||||
argus review --from main --to feature-branch
|
||||
ocr review --from main --to feature-branch
|
||||
|
||||
# Review a specific commit
|
||||
argus review --commit abc123
|
||||
ocr review --commit abc123
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
|
@ -74,10 +74,10 @@ argus review --commit abc123
|
|||
|
||||
| Command | Description |
|
||||
|---------|-------------|
|
||||
| `argus review` / `argus r` | Start a code review session |
|
||||
| `argus config set <key> <value>` | Manage user configuration |
|
||||
| `argus llm test` | Test LLM connectivity |
|
||||
| `argus version` | Show version information |
|
||||
| `ocr review` / `ocr r` | Start a code review session |
|
||||
| `ocr config set <key> <value>` | Manage user configuration |
|
||||
| `ocr llm test` | Test LLM connectivity |
|
||||
| `ocr version` | Show version information |
|
||||
|
||||
### Review Flags
|
||||
|
||||
|
|
@ -98,24 +98,24 @@ argus review --commit abc123
|
|||
**Workspace mode** (no flags): reviews all staged, unstaged, and untracked changes in the current working directory.
|
||||
|
||||
```bash
|
||||
argus review
|
||||
ocr review
|
||||
```
|
||||
|
||||
**Branch range mode**: reviews changes between two git refs using merge-base.
|
||||
|
||||
```bash
|
||||
argus review --from main --to dev
|
||||
ocr review --from main --to dev
|
||||
```
|
||||
|
||||
**Single commit mode**: reviews a specific commit against its parent.
|
||||
|
||||
```bash
|
||||
argus review --commit abc123
|
||||
ocr review --commit abc123
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
User config lives at `~/.argus/config.json`. Supported keys:
|
||||
User config lives at `~/.open-code-review/config.json`. Supported keys:
|
||||
|
||||
| Key | Description | Example |
|
||||
|-----|-------------|---------|
|
||||
|
|
@ -166,7 +166,7 @@ Example config:
|
|||
└─────────────┘
|
||||
```
|
||||
|
||||
Each changed file is reviewed as an independent subtask running concurrently (configurable semaphore). Full session history (requests, responses, tool calls, durations, token estimates) is saved to `<repo>/temp/argus-session-*.json` for debugging.
|
||||
Each changed file is reviewed as an independent subtask running concurrently (configurable semaphore). Full session history (requests, responses, tool calls, durations, token estimates) is saved to `<repo>/temp/ocr-session-*.json` for debugging.
|
||||
|
||||
### LLM Agent Tools
|
||||
|
||||
|
|
@ -184,7 +184,7 @@ During a review, the AI agent has access to these tools:
|
|||
## Project Structure
|
||||
|
||||
```
|
||||
├── cmd/argus/ # CLI entry point and command dispatch
|
||||
├── cmd/opencodereview/ # CLI entry point and command dispatch
|
||||
│ ├── main.go # Application entry point
|
||||
│ ├── review_cmd.go # Core review orchestration
|
||||
│ ├── flags.go # Flag parsing
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ import (
|
|||
"strconv"
|
||||
)
|
||||
|
||||
// Default config file location: ~/.argus/config.json
|
||||
// Default config file location: ~/.open-code-review/config.json
|
||||
func defaultConfigPath() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "argus.json"
|
||||
return "open-code-review.json"
|
||||
}
|
||||
return filepath.Join(home, ".argus", "config.json")
|
||||
return filepath.Join(home, ".open-code-review", "config.json")
|
||||
}
|
||||
|
||||
func runConfig(args []string) error {
|
||||
|
|
@ -66,7 +66,7 @@ func runConfigSet(key, value string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Config represents the user-level configuration file (~/.argus/config.json).
|
||||
// Config represents the user-level configuration file (~/.open-code-review/config.json).
|
||||
type Config struct {
|
||||
Llm LlmConfig `json:"llm,omitempty"`
|
||||
Language string `json:"language,omitempty"` // Output language, defaults to Chinese when empty
|
||||
|
|
@ -8,21 +8,21 @@ import (
|
|||
|
||||
// --- custom flag set that supports short flags (-c, -f etc.) ---
|
||||
|
||||
type argusFlagSet struct {
|
||||
type ocrFlagSet struct {
|
||||
fs *flag.FlagSet
|
||||
shortMap map[string]string // maps short key "c" -> full name "commit"
|
||||
showHelp bool
|
||||
}
|
||||
|
||||
func newArgusFlagSet(name string) *argusFlagSet {
|
||||
return &argusFlagSet{
|
||||
func newOcrFlagSet(name string) *ocrFlagSet {
|
||||
return &ocrFlagSet{
|
||||
fs: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||
shortMap: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// StringVarP registers --name with optional short form -s.
|
||||
func (a *argusFlagSet) StringVarP(p *string, name, shorthand string, value, usage string) {
|
||||
func (a *ocrFlagSet) StringVarP(p *string, name, shorthand string, value, usage string) {
|
||||
suffix := ""
|
||||
if shorthand != "" {
|
||||
a.shortMap[shorthand] = name
|
||||
|
|
@ -32,7 +32,7 @@ func (a *argusFlagSet) StringVarP(p *string, name, shorthand string, value, usag
|
|||
}
|
||||
|
||||
// BoolVarP registers --name with optional short form -s.
|
||||
func (a *argusFlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
||||
func (a *ocrFlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usage string) {
|
||||
suffix := ""
|
||||
if shorthand != "" {
|
||||
a.shortMap[shorthand] = name
|
||||
|
|
@ -41,27 +41,27 @@ func (a *argusFlagSet) BoolVarP(p *bool, name, shorthand string, value bool, usa
|
|||
a.fs.BoolVar(p, name, value, usage+suffix)
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) StringVar(p *string, name string, value string, usage string) {
|
||||
func (a *ocrFlagSet) StringVar(p *string, name string, value string, usage string) {
|
||||
a.fs.StringVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||
func (a *ocrFlagSet) BoolVar(p *bool, name string, value bool, usage string) {
|
||||
a.fs.BoolVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||
func (a *ocrFlagSet) IntVar(p *int, name string, value int, usage string) {
|
||||
a.fs.IntVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
func (a *ocrFlagSet) DurationVar(p *time.Duration, name string, value time.Duration, usage string) {
|
||||
a.fs.DurationVar(p, name, value, usage)
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) PrintDefaults() {
|
||||
func (a *ocrFlagSet) PrintDefaults() {
|
||||
a.fs.PrintDefaults()
|
||||
}
|
||||
|
||||
func (a *argusFlagSet) Parse(arguments []string) error {
|
||||
func (a *ocrFlagSet) Parse(arguments []string) error {
|
||||
expanded := expandShortFlags(arguments, a.shortMap)
|
||||
|
||||
for _, arg := range expanded {
|
||||
|
|
@ -107,7 +107,7 @@ type reviewOptions struct {
|
|||
}
|
||||
|
||||
func parseReviewFlags(args []string) (reviewOptions, error) {
|
||||
a := newArgusFlagSet("argus review")
|
||||
a := newOcrFlagSet("ocr review")
|
||||
|
||||
opts := reviewOptions{}
|
||||
|
||||
|
|
@ -149,26 +149,26 @@ func parseReviewFlags(args []string) (reviewOptions, error) {
|
|||
}
|
||||
|
||||
func printReviewUsage() {
|
||||
fmt.Println(`Argus - Code Review Agent CLI
|
||||
fmt.Println(`OpenCodeReview - AI-Powered Code Review CLI
|
||||
|
||||
Usage:
|
||||
argus review [flags]
|
||||
argus r [flags] (alias)
|
||||
ocr review [flags]
|
||||
ocr r [flags] (alias)
|
||||
|
||||
Examples:
|
||||
# Review staged + unstaged + untracked changes in current workspace
|
||||
argus review
|
||||
ocr review
|
||||
|
||||
# Review a branch against its base (merge-base mode)
|
||||
argus review --from master --to dev-ref
|
||||
ocr review --from master --to dev-ref
|
||||
|
||||
# Review a specific commit
|
||||
argus review --commit abc123
|
||||
argus review -c abc123
|
||||
ocr review --commit abc123
|
||||
ocr review -c abc123
|
||||
|
||||
# Output JSON format
|
||||
argus review --format json
|
||||
argus review -f json
|
||||
ocr review --format json
|
||||
ocr review -f json
|
||||
|
||||
Flags:`)
|
||||
fs := flag.NewFlagSet("print", flag.ContinueOnError)
|
||||
|
|
@ -193,14 +193,14 @@ type configAction struct {
|
|||
|
||||
func parseConfigArgs(args []string) (configAction, error) {
|
||||
if len(args) == 0 {
|
||||
return configAction{}, fmt.Errorf("usage: argus config set <key> <value>\ne.g., argus config set llm.provider idealab")
|
||||
return configAction{}, fmt.Errorf("usage: ocr config set <key> <value>\ne.g., ocr config set llm.provider idealab")
|
||||
}
|
||||
|
||||
subCmd := args[0]
|
||||
switch subCmd {
|
||||
case "set":
|
||||
if len(args) < 3 {
|
||||
return configAction{}, fmt.Errorf("usage: argus config set <key> <value>\ne.g., argus config set llm.model claude-opus-4-6")
|
||||
return configAction{}, fmt.Errorf("usage: ocr config set <key> <value>\ne.g., ocr config set llm.model claude-opus-4-6")
|
||||
}
|
||||
return configAction{
|
||||
subCmd: "set",
|
||||
|
|
@ -216,13 +216,13 @@ func printConfigUsage() {
|
|||
fmt.Println(`Configuration management.
|
||||
|
||||
Usage:
|
||||
argus config set <key> <value>
|
||||
ocr config set <key> <value>
|
||||
|
||||
Examples:
|
||||
argus config set llm.provider idealab
|
||||
argus config set llm.url https://xx/v1/openai/chat/completions
|
||||
argus config set llm.auth_token xxxxxxxxxx
|
||||
argus config set llm.model claude-opus-4-6
|
||||
ocr config set llm.provider idealab
|
||||
ocr config set llm.url https://xx/v1/openai/chat/completions
|
||||
ocr config set llm.auth_token xxxxxxxxxx
|
||||
ocr config set llm.model claude-opus-4-6
|
||||
|
||||
Supported keys: llm.provider, llm.url, llm.auth_token, llm.model`)
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/argus-review/argus/internal/config/testconnection"
|
||||
"github.com/argus-review/argus/internal/llm"
|
||||
"github.com/open-code-review/open-code-review/internal/config/testconnection"
|
||||
"github.com/open-code-review/open-code-review/internal/llm"
|
||||
)
|
||||
|
||||
func runLLM(args []string) error {
|
||||
|
|
@ -18,7 +18,7 @@ func runLLM(args []string) error {
|
|||
case "test":
|
||||
return runLLMTest()
|
||||
default:
|
||||
return fmt.Errorf("unknown llm sub-command: %s\nRun 'argus llm' for usage", args[0])
|
||||
return fmt.Errorf("unknown llm sub-command: %s\nRun 'ocr llm' for usage", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -72,11 +72,11 @@ func printLLMUsage() {
|
|||
fmt.Println(`LLM utility commands.
|
||||
|
||||
Usage:
|
||||
argus llm <sub-command>
|
||||
ocr llm <sub-command>
|
||||
|
||||
Sub-commands:
|
||||
test Send a test conversation to the configured LLM model
|
||||
|
||||
Examples:
|
||||
argus llm test Verify LLM connectivity and configuration`)
|
||||
ocr llm test Verify LLM connectivity and configuration`)
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Argus is an AI-powered code review CLI tool.
|
||||
// OpenCodeReview is an AI-powered code review CLI tool.
|
||||
// It reads git diffs, sends them to a configurable LLM service, and generates review comments.
|
||||
package main
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/argus-review/argus/internal/telemetry"
|
||||
"github.com/open-code-review/open-code-review/internal/telemetry"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -50,15 +50,15 @@ func dispatch() error {
|
|||
printTopLevelUsage()
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown command: %s\nRun 'argus' for usage", args[0])
|
||||
return fmt.Errorf("unknown command: %s\nRun 'ocr' for usage", args[0])
|
||||
}
|
||||
}
|
||||
|
||||
func printTopLevelUsage() {
|
||||
fmt.Println(`Argus - Code Review Agent CLI
|
||||
fmt.Println(`OpenCodeReview - AI-Powered Code Review CLI
|
||||
|
||||
Usage:
|
||||
argus [command]
|
||||
ocr [command]
|
||||
|
||||
Commands:
|
||||
review, r Start a code review
|
||||
|
|
@ -67,13 +67,13 @@ Commands:
|
|||
version Show version information
|
||||
|
||||
Examples:
|
||||
argus review --from dev --to master Review diff range
|
||||
argus review --commit abc123 Review a single commit
|
||||
argus config set llm.model opus-4-6 Set a config value
|
||||
argus llm test Test LLM connectivity
|
||||
argus version Show version info
|
||||
ocr review --from dev --to master Review diff range
|
||||
ocr review --commit abc123 Review a single commit
|
||||
ocr config set llm.model opus-4-6 Set a config value
|
||||
ocr llm test Test LLM connectivity
|
||||
ocr version Show version info
|
||||
|
||||
Use "argus review -h" for more information about review.
|
||||
Use "argus config" for more information about config.
|
||||
Use "argus llm" for more information about LLM utilities.`)
|
||||
Use "ocr review -h" for more information about review.
|
||||
Use "ocr config" for more information about config.
|
||||
Use "ocr llm" for more information about LLM utilities.`)
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
func outputText(comments []model.LlmComment) {
|
||||
|
|
@ -7,13 +7,13 @@ import (
|
|||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/argus-review/argus/internal/agent"
|
||||
"github.com/argus-review/argus/internal/config/rules"
|
||||
"github.com/argus-review/argus/internal/config/template"
|
||||
"github.com/argus-review/argus/internal/config/toolsconfig"
|
||||
"github.com/argus-review/argus/internal/llm"
|
||||
"github.com/argus-review/argus/internal/telemetry"
|
||||
"github.com/argus-review/argus/internal/tool"
|
||||
"github.com/open-code-review/open-code-review/internal/agent"
|
||||
"github.com/open-code-review/open-code-review/internal/config/rules"
|
||||
"github.com/open-code-review/open-code-review/internal/config/template"
|
||||
"github.com/open-code-review/open-code-review/internal/config/toolsconfig"
|
||||
"github.com/open-code-review/open-code-review/internal/llm"
|
||||
"github.com/open-code-review/open-code-review/internal/telemetry"
|
||||
"github.com/open-code-review/open-code-review/internal/tool"
|
||||
)
|
||||
|
||||
func runReview(args []string) error {
|
||||
|
|
@ -62,7 +62,7 @@ func runReview(args []string) error {
|
|||
return fmt.Errorf("load app config: %w", err)
|
||||
}
|
||||
if cfg == nil || cfg.Llm.URL == "" || cfg.Llm.AuthToken == "" {
|
||||
return fmt.Errorf("llm.url and llm.auth_token are required in $HOME/.argus/config.json")
|
||||
return fmt.Errorf("llm.url and llm.auth_token are required in $HOME/.open-code-review/config.json")
|
||||
}
|
||||
model := cfg.Llm.Model
|
||||
tpl.ApplyLanguage(cfg.Language)
|
||||
|
|
@ -13,7 +13,7 @@ var (
|
|||
)
|
||||
|
||||
func printVersion() {
|
||||
fmt.Printf("argus %s", Version)
|
||||
fmt.Printf("opencodereview %s", Version)
|
||||
if GitCommit != "" {
|
||||
fmt.Printf(" (%s)", GitCommit)
|
||||
}
|
||||
|
|
@ -10,8 +10,8 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/argus-review/argus/internal/diff"
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/diff"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
1
dist/VERSION
vendored
Normal file
1
dist/VERSION
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
v0.0.1
|
||||
BIN
dist/opencodereview
vendored
Executable file
BIN
dist/opencodereview
vendored
Executable file
Binary file not shown.
2
go.mod
2
go.mod
|
|
@ -1,4 +1,4 @@
|
|||
module github.com/argus-review/argus
|
||||
module github.com/open-code-review/open-code-review
|
||||
|
||||
go 1.25.0
|
||||
|
||||
|
|
|
|||
|
|
@ -9,15 +9,15 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/argus-review/argus/internal/config/rules"
|
||||
"github.com/argus-review/argus/internal/config/template"
|
||||
"github.com/argus-review/argus/internal/config/toolsconfig"
|
||||
"github.com/argus-review/argus/internal/diff"
|
||||
"github.com/argus-review/argus/internal/llm"
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/argus-review/argus/internal/session"
|
||||
"github.com/argus-review/argus/internal/telemetry"
|
||||
"github.com/argus-review/argus/internal/tool"
|
||||
"github.com/open-code-review/open-code-review/internal/config/rules"
|
||||
"github.com/open-code-review/open-code-review/internal/config/template"
|
||||
"github.com/open-code-review/open-code-review/internal/config/toolsconfig"
|
||||
"github.com/open-code-review/open-code-review/internal/diff"
|
||||
"github.com/open-code-review/open-code-review/internal/llm"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/session"
|
||||
"github.com/open-code-review/open-code-review/internal/telemetry"
|
||||
"github.com/open-code-review/open-code-review/internal/tool"
|
||||
)
|
||||
|
||||
// Args holds all dependencies and configuration needed to run a review session.
|
||||
|
|
@ -175,7 +175,7 @@ func (a *Agent) Run(ctx context.Context) ([]model.LlmComment, error) {
|
|||
diffSpan.End()
|
||||
|
||||
if len(a.diffs) == 0 {
|
||||
fmt.Println("[argus] No files changed. Skipping review.")
|
||||
fmt.Println("[ocr] No files changed. Skipping review.")
|
||||
telemetry.Event(ctx, "no.files.changed")
|
||||
a.session.Finalize()
|
||||
return nil, nil
|
||||
|
|
@ -183,7 +183,7 @@ func (a *Agent) Run(ctx context.Context) ([]model.LlmComment, error) {
|
|||
|
||||
a.currentDate = time.Now().Format("2006-01-02 15:04")
|
||||
|
||||
fmt.Printf("[argus] Reviewing %d file(s) in %s\n", len(a.diffs), a.args.RepoDir)
|
||||
fmt.Printf("[ocr] Reviewing %d file(s) in %s\n", len(a.diffs), a.args.RepoDir)
|
||||
telemetry.Event(ctx, "review.started",
|
||||
telemetry.AnyToAttr("file.count", len(a.diffs)),
|
||||
telemetry.AnyToAttr("repo.dir", a.args.RepoDir))
|
||||
|
|
@ -295,7 +295,7 @@ func (a *Agent) dispatchSubtasks(ctx context.Context) ([]model.LlmComment, error
|
|||
|
||||
fileComments, err := a.executeSubtask(fileCtx, d)
|
||||
if err != nil {
|
||||
fmt.Printf("[argus] Subtask error for %s: %v\n", d.NewPath, err)
|
||||
fmt.Printf("[ocr] Subtask error for %s: %v\n", d.NewPath, err)
|
||||
telemetry.ErrorEvent(fileCtx, "subtask.error", err,
|
||||
telemetry.AnyToAttr("file.path", d.NewPath))
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ func (a *Agent) executeSubtask(ctx context.Context, d model.Diff) ([]model.LlmCo
|
|||
// Phase 1: Plan (skip when changes are below threshold)
|
||||
var planResult string
|
||||
if a.args.Template.PlanTask != nil && len(a.args.Template.PlanTask.Messages) > 0 && threshold > 0 && changeLines < int64(threshold) {
|
||||
fmt.Printf("[argus] Skipping plan phase for %s (%d lines < threshold %d)\n", newPath, changeLines, threshold)
|
||||
fmt.Printf("[ocr] Skipping plan phase for %s (%d lines < threshold %d)\n", newPath, changeLines, threshold)
|
||||
telemetry.Event(ctx, "plan.skipped",
|
||||
telemetry.AnyToAttr("file.path", newPath),
|
||||
telemetry.AnyToAttr("lines.changed", changeLines),
|
||||
|
|
@ -344,7 +344,7 @@ func (a *Agent) executeSubtask(ctx context.Context, d model.Diff) ([]model.LlmCo
|
|||
var err error
|
||||
planResult, err = a.executePlanPhase(ctx, newPath, d.Diff, changeFilesExcludingCurrent, rule)
|
||||
if err != nil {
|
||||
fmt.Printf("[argus] Plan phase failed for %s: %v (continuing without plan)\n", newPath, err)
|
||||
fmt.Printf("[ocr] Plan phase failed for %s: %v (continuing without plan)\n", newPath, err)
|
||||
telemetry.Eventf(ctx, "plan.failed", err.Error(),
|
||||
telemetry.AnyToAttr("file.path", newPath))
|
||||
planResult = ""
|
||||
|
|
@ -375,7 +375,7 @@ func (a *Agent) executeSubtask(ctx context.Context, d model.Diff) ([]model.LlmCo
|
|||
|
||||
tokenCount := countMessagesTokens(messages)
|
||||
if tokenCount > a.args.Template.TokenWarningThreshold {
|
||||
fmt.Printf("[argus] WARNING: prompt tokens (%d) exceed threshold (%d) for %s\n",
|
||||
fmt.Printf("[ocr] WARNING: prompt tokens (%d) exceed threshold (%d) for %s\n",
|
||||
tokenCount, a.args.Template.TokenWarningThreshold, newPath)
|
||||
telemetry.Event(ctx, "token.threshold.exceeded",
|
||||
telemetry.AnyToAttr("file.path", newPath),
|
||||
|
|
@ -454,7 +454,7 @@ func (a *Agent) executePlanPhase(_ context.Context, newPath, rawDiff, changeFile
|
|||
if resp.Usage != nil {
|
||||
atomic.AddInt64(&a.totalTokensUsed, int64(resp.Usage.TotalTokens))
|
||||
}
|
||||
fmt.Printf("[argus] Plan completed for %s\n", newPath)
|
||||
fmt.Printf("[ocr] Plan completed for %s\n", newPath)
|
||||
return resp.Content(), nil
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +540,7 @@ func (a *Agent) performLlmCodeReview(ctx context.Context, messages []llm.Message
|
|||
|
||||
if len(calls) == 0 {
|
||||
// No tool calls - remind the model
|
||||
fmt.Printf("[argus] No tool calls parsed for %s, retrying...\n", newPath)
|
||||
fmt.Printf("[ocr] No tool calls parsed for %s, retrying...\n", newPath)
|
||||
messages = append(messages, llm.NewTextMessage("user", "You did not successfully call any tools. Please try again or use task_done if finished."))
|
||||
if content != "" {
|
||||
messages = append(messages[:len(messages)-1], llm.NewTextMessage("assistant", content), messages[len(messages)-1])
|
||||
|
|
@ -581,19 +581,19 @@ func (a *Agent) performLlmCodeReview(ctx context.Context, messages []llm.Message
|
|||
break
|
||||
}
|
||||
if !hasValidResult {
|
||||
fmt.Printf("[argus] No valid tool results for %s, stopping.\n", newPath)
|
||||
fmt.Printf("[ocr] No valid tool results for %s, stopping.\n", newPath)
|
||||
break
|
||||
}
|
||||
|
||||
succeed := a.addNextMessage(content, calls, results, &messages, newPath)
|
||||
if !succeed {
|
||||
fmt.Printf("[argus] Context compression exceeded threshold for %s, stopping.\n", newPath)
|
||||
fmt.Printf("[ocr] Context compression exceeded threshold for %s, stopping.\n", newPath)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if toolReqCount <= 0 {
|
||||
fmt.Printf("[argus] Max tool requests reached for %s.\n", newPath)
|
||||
fmt.Printf("[ocr] Max tool requests reached for %s.\n", newPath)
|
||||
}
|
||||
|
||||
comments := a.args.CommentCollector.Comments()
|
||||
|
|
@ -720,7 +720,7 @@ func BuildToolDefs(entries []toolsconfig.ToolConfigEntry, planOnly bool) []llm.T
|
|||
}
|
||||
var fn llm.FunctionDef
|
||||
if err := json.Unmarshal(defRaw, &fn); err != nil {
|
||||
fmt.Printf("[argus] WARNING: failed to parse tool definition %q: %v\n", e.Name, err)
|
||||
fmt.Printf("[ocr] WARNING: failed to parse tool definition %q: %v\n", e.Name, err)
|
||||
continue
|
||||
}
|
||||
defs = append(defs, llm.ToolDef{
|
||||
|
|
@ -752,7 +752,7 @@ func (a *Agent) compressAndRecord(msgs []llm.Message, filePath string) []llm.Mes
|
|||
rec := fs.AppendTaskRecord(session.MemoryCompressionTask, compressionMsgs)
|
||||
if err != nil {
|
||||
rec.SetError(err, duration)
|
||||
fmt.Printf("[argus] Memory compression failed: %v\n", err)
|
||||
fmt.Printf("[ocr] Memory compression failed: %v\n", err)
|
||||
return msgs[:2]
|
||||
}
|
||||
rec.SetResponse(resp, duration)
|
||||
|
|
@ -788,7 +788,7 @@ func compressMessages(msgs []llm.Message, compTask template.LlmConversation, cli
|
|||
|
||||
resp, err := client.GeneralRequest(compressionMsgs, model, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("[argus] Memory compression failed: %v\n", err)
|
||||
fmt.Printf("[ocr] Memory compression failed: %v\n", err)
|
||||
return msgs[:2]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
// DiffContextLines defines the number of context lines around each changed hunk.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package diff
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
// ResolveLineNumbers populates StartLine/EndLine on each comment by matching
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package diff
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
const testDiff = `diff --git a/pkg/example/handler.go b/pkg/example/handler.go
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// Package llm provides an OpenAI-compatible LLM client interface.
|
||||
// Argus supports any service that implements the OpenAI Chat Completion API schema,
|
||||
// OpenCodeReview supports any service that implements the OpenAI Chat Completion API schema,
|
||||
// including OpenAI, Claude (via Anthropic's OpenAI-compatible endpoint), local models, etc.
|
||||
package llm
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/argus-review/argus/internal/llm"
|
||||
"github.com/open-code-review/open-code-review/internal/llm"
|
||||
)
|
||||
|
||||
// TaskType identifies the kind of LLM request within a file subtask.
|
||||
|
|
@ -176,20 +176,20 @@ func (sh *SessionHistory) writeDebugDump() {
|
|||
|
||||
data, err := json.MarshalIndent(snap, "", " ")
|
||||
if err != nil {
|
||||
fmt.Printf("[argus debug] Failed to marshal session history: %v\n", err)
|
||||
fmt.Printf("[ocr debug] Failed to marshal session history: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
debugDir := filepath.Join(sh.RepoDir, "temp")
|
||||
if err := os.MkdirAll(debugDir, 0755); err != nil {
|
||||
fmt.Printf("[argus debug] Failed to create debug dir %s: %v\n", debugDir, err)
|
||||
fmt.Printf("[ocr debug] Failed to create debug dir %s: %v\n", debugDir, err)
|
||||
return
|
||||
}
|
||||
filename := filepath.Join(debugDir, fmt.Sprintf("argus-session-%s.json", sessionName))
|
||||
filename := filepath.Join(debugDir, fmt.Sprintf("ocr-session-%s.json", sessionName))
|
||||
if err := os.WriteFile(filename, data, 0644); err != nil {
|
||||
fmt.Printf("[argus debug] Failed to write session dump to %s: %v\n", filename, err)
|
||||
fmt.Printf("[ocr debug] Failed to write session dump to %s: %v\n", filename, err)
|
||||
} else {
|
||||
fmt.Printf("[argus debug] Session history written to %s\n", filename)
|
||||
fmt.Printf("[ocr debug] Session history written to %s\n", filename)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Package telemetry provides OpenTelemetry-based observability for Argus CLI.
|
||||
// Package telemetry provides OpenTelemetry-based observability for OpenCodeReview CLI.
|
||||
// It supports console output (for personal use) and OTLP export (for system integration).
|
||||
package telemetry
|
||||
|
||||
|
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
defaultServiceName = "argus"
|
||||
defaultServiceName = "open-code-review"
|
||||
defaultOTLPEndpoint = ""
|
||||
defaultExporter = "console"
|
||||
defaultContentLogging = false
|
||||
|
|
@ -17,7 +17,7 @@ const (
|
|||
|
||||
// Config holds resolved telemetry configuration.
|
||||
type Config struct {
|
||||
Enabled bool // Master switch; false when ARGUS_ENABLE_TELEMETRY is unset
|
||||
Enabled bool // Master switch; false when OCR_ENABLE_TELEMETRY is unset
|
||||
ServiceName string // Service name in traces/metrics
|
||||
Exporter string // "console" or "otlp"
|
||||
OTLPEndpoint string // OTLP collector address (grpc/http)
|
||||
|
|
@ -40,7 +40,7 @@ func DefaultConfig() Config {
|
|||
// resolveEnv reads environment variables to override defaults.
|
||||
// Environment takes highest priority.
|
||||
func resolveEnv(cfg *Config) {
|
||||
if os.Getenv("ARGUS_ENABLE_TELEMETRY") == "1" {
|
||||
if os.Getenv("OCR_ENABLE_TELEMETRY") == "1" {
|
||||
cfg.Enabled = true
|
||||
}
|
||||
if v := os.Getenv("OTEL_SERVICE_NAME"); v != "" {
|
||||
|
|
@ -53,12 +53,12 @@ func resolveEnv(cfg *Config) {
|
|||
if v := os.Getenv("OTEL_EXPORTER_OTLP_PROTOCOL"); v != "" {
|
||||
cfg.OTLPProtocol = v
|
||||
}
|
||||
if os.Getenv("ARGUS_CONTENT_LOGGING") == "1" {
|
||||
if os.Getenv("OCR_CONTENT_LOGGING") == "1" {
|
||||
cfg.ContentLog = true
|
||||
}
|
||||
}
|
||||
|
||||
// telemetrySection matches the telemetry key in ~/.argus/config.json.
|
||||
// telemetrySection matches the telemetry key in ~/.open-code-review/config.json.
|
||||
type telemetrySection struct {
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
Exporter *string `json:"exporter,omitempty"`
|
||||
|
|
@ -121,11 +121,11 @@ func ResolveConfig(configPath string) Config {
|
|||
return cfg
|
||||
}
|
||||
|
||||
// HomeConfigPath returns the default path to ~/.argus/config.json.
|
||||
// HomeConfigPath returns the default path to ~/.open-code-review/config.json.
|
||||
func HomeConfigPath() string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return filepath.Join(home, ".argus", "config.json")
|
||||
return filepath.Join(home, ".open-code-review", "config.json")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,32 +61,32 @@ func FormatDuration(dur time.Duration) string {
|
|||
|
||||
// PrintTraceSummary prints a one-line summary of the review to stdout.
|
||||
func PrintTraceSummary(filesReviewed, commentsGenerated int64, totalTokens int64, duration time.Duration) {
|
||||
fmt.Printf("[argus] Summary: %d file(s) reviewed, %d comment(s), ~%d token(s) used, %s elapsed\n",
|
||||
fmt.Printf("[ocr] Summary: %d file(s) reviewed, %d comment(s), ~%d token(s) used, %s elapsed\n",
|
||||
filesReviewed, commentsGenerated, totalTokens, FormatDuration(duration))
|
||||
}
|
||||
|
||||
// PrintToolCallStarted prints a line when a tool begins execution.
|
||||
// Args are summarized as key-value pairs (path, search terms, etc.).
|
||||
// Example: [argus] ▶ file_read "internal/config/rules/loader.go"
|
||||
// Example: [ocr] ▶ file_read "internal/config/rules/loader.go"
|
||||
func PrintToolCallStarted(toolName string, args map[string]any) {
|
||||
summary := summarizeArgs(args)
|
||||
if summary != "" {
|
||||
fmt.Printf("[argus] ▶ %s %s\n", toolName, summary)
|
||||
fmt.Printf("[ocr] ▶ %s %s\n", toolName, summary)
|
||||
} else {
|
||||
fmt.Printf("[argus] ▶ %s\n", toolName)
|
||||
fmt.Printf("[ocr] ▶ %s\n", toolName)
|
||||
}
|
||||
}
|
||||
|
||||
// PrintToolCallFinished prints a line when a tool finishes successfully.
|
||||
// Example: [argus] ✔ file_read "internal/config/rules/loader.go" (12ms)
|
||||
// Example: [ocr] ✔ file_read "internal/config/rules/loader.go" (12ms)
|
||||
func PrintToolCallFinished(toolName string, dur time.Duration) {
|
||||
fmt.Printf("[argus] ✔ %s (%s)\n", toolName, FormatDuration(dur))
|
||||
fmt.Printf("[ocr] ✔ %s (%s)\n", toolName, FormatDuration(dur))
|
||||
}
|
||||
|
||||
// PrintToolCallError prints a line when a tool fails.
|
||||
// Example: [argus] ✘ file_read "internal/config/rules/loader.go" failed: permission denied
|
||||
// Example: [ocr] ✘ file_read "internal/config/rules/loader.go" failed: permission denied
|
||||
func PrintToolCallError(toolName string, err error) {
|
||||
fmt.Fprintf(os.Stderr, "[argus] ✘ %s failed: %v\n", toolName, err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] ✘ %s failed: %v\n", toolName, err)
|
||||
}
|
||||
|
||||
// summarizeArgs extracts a concise key=value summary from tool arguments for console display.
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ func initOTLPProviders(ctx context.Context, res *resource.Resource, cfg Config)
|
|||
otlptracegrpc.WithEndpoint(cfg.OTLPEndpoint),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: failed to create OTLP trace exporter: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: failed to create OTLP trace exporter: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ func initOTLPProviders(ctx context.Context, res *resource.Resource, cfg Config)
|
|||
otlpmetricgrpc.WithEndpoint(cfg.OTLPEndpoint),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: failed to create OTLP metric exporter: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: failed to create OTLP metric exporter: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +62,7 @@ func initOTLPProviders(ctx context.Context, res *resource.Resource, cfg Config)
|
|||
func initConsoleProviders(res *resource.Resource) {
|
||||
traceExp, err := newStdoutTraceExporter()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: failed to create console trace exporter: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: failed to create console trace exporter: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ func initConsoleProviders(res *resource.Resource) {
|
|||
|
||||
metricExp, err := newStdoutMetricExporter()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: failed to create console metric exporter: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: failed to create console metric exporter: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,35 +34,35 @@ func ensureMetrics() {
|
|||
m := getMeter()
|
||||
|
||||
var err error
|
||||
mReviewDuration, err = m.Int64Histogram("argus.review.duration_seconds",
|
||||
mReviewDuration, err = m.Int64Histogram("ocr.review.duration_seconds",
|
||||
metric.WithUnit("s"), metric.WithDescription("Total duration of a code review run"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mFilesReviewed, err = m.Int64Counter("argus.files_reviewed_total",
|
||||
mFilesReviewed, err = m.Int64Counter("ocr.files_reviewed_total",
|
||||
metric.WithDescription("Number of files reviewed in this session"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mCommentsGenerated, err = m.Int64Counter("argus.comments_generated_total",
|
||||
mCommentsGenerated, err = m.Int64Counter("ocr.comments_generated_total",
|
||||
metric.WithDescription("Number of review comments generated"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mLLMRequests, err = m.Int64Counter("argus.llm.requests_total",
|
||||
mLLMRequests, err = m.Int64Counter("ocr.llm.requests_total",
|
||||
metric.WithDescription("Total LLM API requests made"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mLLMTokens, err = m.Int64Counter("argus.llm.tokens_used",
|
||||
mLLMTokens, err = m.Int64Counter("ocr.llm.tokens_used",
|
||||
metric.WithDescription("Tokens consumed by LLM requests"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mLLMDuration, err = m.Float64Histogram("argus.llm.request_duration_seconds",
|
||||
mLLMDuration, err = m.Float64Histogram("ocr.llm.request_duration_seconds",
|
||||
metric.WithUnit("s"), metric.WithDescription("Duration of individual LLM API requests"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mToolCalls, err = m.Int64Counter("argus.tool.calls_total",
|
||||
mToolCalls, err = m.Int64Counter("ocr.tool.calls_total",
|
||||
metric.WithDescription("Total tool calls made"))
|
||||
checkMetricErr(err)
|
||||
|
||||
mToolExecutionTime, err = m.Float64Histogram("argus.tool.execution_duration_seconds",
|
||||
mToolExecutionTime, err = m.Float64Histogram("ocr.tool.execution_duration_seconds",
|
||||
metric.WithUnit("s"), metric.WithDescription("Duration of tool executions"))
|
||||
checkMetricErr(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ var (
|
|||
)
|
||||
|
||||
// serviceName holds the name set during Init.
|
||||
var serviceName = "argus"
|
||||
var serviceName = "open-code-review"
|
||||
|
||||
// Init initializes global TracerProvider and MeterProvider based on
|
||||
// environment variables and optional config file. Returns true when enabled.
|
||||
|
|
@ -44,7 +44,7 @@ func Init(ctx context.Context) bool {
|
|||
resource.WithHost(),
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: failed to create OTel resource: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: failed to create OTel resource: %v\n", err)
|
||||
res = resource.Default()
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ func IsEnabled() bool {
|
|||
return initialized && len(shutdownFuncs) > 0
|
||||
}
|
||||
|
||||
// ContentLogging returns true when content logging is enabled via ARGUS_CONTENT_LOGGING.
|
||||
// ContentLogging returns true when content logging is enabled via OCR_CONTENT_LOGGING.
|
||||
func ContentLogging() bool {
|
||||
if !IsEnabled() {
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -34,6 +34,6 @@ func ShutdownWithTimeout(ctx context.Context, timeout time.Duration) {
|
|||
cctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
if err := Shutdown(cctx); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "[argus] WARNING: telemetry shutdown error: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "[ocr] WARNING: telemetry shutdown error: %v\n", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
// CodeCommentProvider submits review comments to the per-Agent CommentCollector.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package tool
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/argus-review/argus/internal/model"
|
||||
"github.com/open-code-review/open-code-review/internal/model"
|
||||
)
|
||||
|
||||
// CommentCollector is a thread-safe, per-Agent comment store.
|
||||
|
|
|
|||
198
scripts/install.sh
Executable file
198
scripts/install.sh
Executable file
|
|
@ -0,0 +1,198 @@
|
|||
#!/usr/bin/env sh
|
||||
# install.sh — Install or upgrade argus CLI
|
||||
#
|
||||
# Usage (pipelined):
|
||||
# curl -fsSL https://git.cn-hangzhou.oss-cdn.aliyun-inc.com/opencodereview-cli/install.sh | sh
|
||||
# OCR_VERSION=v0.1.0 curl -fsSL ... | sh
|
||||
#
|
||||
# Usage (standalone):
|
||||
# sh install.sh
|
||||
# OCR_VERSION=v0.1.0 sh install.sh
|
||||
#
|
||||
# Environment variables:
|
||||
# OCR_VERSION Pin a specific version (e.g., v0.1.0). Defaults to "latest".
|
||||
# INSTALL_DIR Override install destination (default: /usr/local/bin).
|
||||
|
||||
set -eu
|
||||
|
||||
# ── Configuration ────────────────────────────────────────────────────────────
|
||||
BASE_URL="https://code.alibaba-inc.com/lizhengfeng.lzf/opencodereview-cli/raw/master/dist"
|
||||
BINARY_NAME="opencodereview"
|
||||
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
|
||||
|
||||
# ── Logging ──────────────────────────────────────────────────────────────────
|
||||
info() { printf "[INFO] %s\n" "$*" >&2; }
|
||||
warn() { printf "[WARN] %s\n" "$*" >&2; }
|
||||
error() { printf "[ERROR] %s\n" "$*" >&2; }
|
||||
die() { error "$@"; exit 1; }
|
||||
|
||||
# ── Cleanup trap ─────────────────────────────────────────────────────────────
|
||||
TMPDIR_WORK=""
|
||||
cleanup() {
|
||||
if [ -n "$TMPDIR_WORK" ] && [ -d "$TMPDIR_WORK" ]; then
|
||||
rm -rf "$TMPDIR_WORK"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
# ── Detect OS & Arch ─────────────────────────────────────────────────────────
|
||||
detect_platform() {
|
||||
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
case "$ARCH" in
|
||||
x86_64|amd64|x64) ARCH="amd64" ;;
|
||||
aarch64|arm64) ARCH="arm64" ;;
|
||||
*) die "Unsupported architecture: $ARCH (need amd64 or arm64)" ;;
|
||||
esac
|
||||
|
||||
case "$OS" in
|
||||
linux|darwin) ;;
|
||||
*) die "Unsupported operating system: $OS (need linux or darwin)" ;;
|
||||
esac
|
||||
|
||||
info "Detected platform: ${OS}/${ARCH}"
|
||||
}
|
||||
|
||||
# ── Resolve version ──────────────────────────────────────────────────────────
|
||||
resolve_version() {
|
||||
if [ -n "${OCR_VERSION:-}" ]; then
|
||||
VERSION="$OCR_VERSION"
|
||||
VERSION="v$(echo "$VERSION" | sed 's/^v//')"
|
||||
info "Using pinned version: ${VERSION}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Try fetching latest version from remote
|
||||
info "Fetching latest version..."
|
||||
VERSION=$(curl -fsSL --retry 3 --retry-delay 2 "${BASE_URL}/VERSION" 2>/dev/null || true)
|
||||
if [ -n "$VERSION" ]; then
|
||||
info "Latest version: ${VERSION}"
|
||||
return
|
||||
fi
|
||||
|
||||
# Fallback: detect locally built binary in dist/
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." 2>/dev/null && pwd || true)"
|
||||
if [ -n "$PROJECT_ROOT" ] && [ -d "${PROJECT_ROOT}/dist" ]; then
|
||||
LOCAL_BIN=""
|
||||
# Prefer platform-specific binary, fall back to generic one
|
||||
for pattern in \
|
||||
"${BINARY_NAME}-${VERSION:-*}-${OS}-${ARCH}" \
|
||||
"${BINARY_NAME}-${VERSION:-*}-${OS}-*" \
|
||||
"${BINARY_NAME}"; do
|
||||
LOCAL_BIN=$(ls "${PROJECT_ROOT}/dist/${pattern}" 2>/dev/null | head -1 || true)
|
||||
if [ -n "$LOCAL_BIN" ] && [ -f "$LOCAL_BIN" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -n "$LOCAL_BIN" ] && [ -f "$LOCAL_BIN" ]; then
|
||||
VERSION=$("$LOCAL_BIN" version 2>/dev/null | awk '{print $NF}' || echo "local")
|
||||
VERSION="v$(echo "$VERSION" | sed 's/^v//')"
|
||||
LOCAL_BINARY="$LOCAL_BIN"
|
||||
warn "Remote unavailable, using local build: ${VERSION}"
|
||||
warn " Source: ${LOCAL_BINARY}"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
die "Cannot determine version. Set OCR_VERSION explicitly, or build locally with 'make build'."
|
||||
}
|
||||
|
||||
# ── Download / locate binary ─────────────────────────────────────────────────
|
||||
locate_or_download_binary() {
|
||||
# If a local binary was already resolved during version detection, use it directly
|
||||
if [ -n "${LOCAL_BINARY:-}" ]; then
|
||||
DEST="$LOCAL_BINARY"
|
||||
info "Using local binary: ${DEST}"
|
||||
return
|
||||
fi
|
||||
|
||||
BINARY_FILE="${BINARY_NAME}-${VERSION}-${OS}-${ARCH}"
|
||||
DOWNLOAD_URL="${BASE_URL}/${BINARY_FILE}"
|
||||
|
||||
TMPDIR_WORK=$(mktemp -d)
|
||||
DEST="${TMPDIR_WORK}/${BINARY_NAME}"
|
||||
|
||||
info "Downloading ${DOWNLOAD_URL} ..."
|
||||
if ! curl -fsSL --retry 3 --retry-delay 2 -o "$DEST" "$DOWNLOAD_URL"; then
|
||||
die "Download failed. Check that version '${VERSION}' exists for ${OS}/${ARCH}."
|
||||
fi
|
||||
|
||||
chmod +x "$DEST"
|
||||
|
||||
# Verify checksum if available
|
||||
CHECKSUM_URL="${BASE_URL}/sha256sum-${VERSION}.txt"
|
||||
EXPECTED_CHECKSUM=$(curl -fsSL --retry 2 "$CHECKSUM_URL" 2>/dev/null | grep "$BINARY_FILE" | awk '{print $1}' || true)
|
||||
if [ -n "$EXPECTED_CHECKSUM" ]; then
|
||||
ACTUAL_CHECKSUM=$(shasum -a 256 "$DEST" | awk '{print $1}')
|
||||
if [ "$ACTUAL_CHECKSUM" != "$EXPECTED_CHECKSUM" ]; then
|
||||
die "Checksum mismatch! Expected: ${EXPECTED_CHECKSUM}, Got: ${ACTUAL_CHECKSUM}"
|
||||
fi
|
||||
info "Checksum verified."
|
||||
else
|
||||
warn "Checksum file not found at ${CHECKSUM_URL}; skipping integrity check."
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Install ──────────────────────────────────────────────────────────────────
|
||||
install_binary() {
|
||||
TARGET="${INSTALL_DIR}/${BINARY_NAME}"
|
||||
|
||||
# Ensure install directory exists
|
||||
if [ ! -d "$INSTALL_DIR" ]; then
|
||||
if command -v sudo >/dev/null 2>&1; then
|
||||
info "Creating install directory: ${INSTALL_DIR}"
|
||||
sudo mkdir -p "$INSTALL_DIR"
|
||||
else
|
||||
die "Install directory does not exist and sudo is unavailable: ${INSTALL_DIR}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$TARGET" ]; then
|
||||
CURRENT_VER=$("$TARGET" version 2>/dev/null | head -1 || echo "unknown")
|
||||
warn "Existing installation found (${CURRENT_VER}), replacing with ${VERSION}."
|
||||
fi
|
||||
|
||||
if [ ! -w "$INSTALL_DIR" ] && ! [ "$(id -u)" = "0" ]; then
|
||||
info "Installing to ${INSTALL_DIR} (sudo required)..."
|
||||
sudo cp "$DEST" "$TARGET"
|
||||
else
|
||||
cp "$DEST" "$TARGET"
|
||||
fi
|
||||
|
||||
info "Installed: ${TARGET}"
|
||||
}
|
||||
|
||||
# ── Verify installation ──────────────────────────────────────────────────────
|
||||
verify_install() {
|
||||
if command -v "${INSTALL_DIR}/${BINARY_NAME}" >/dev/null 2>&1; then
|
||||
INSTALLED_VER=$("${INSTALL_DIR}/${BINARY_NAME}" version 2>/dev/null || echo "?")
|
||||
info ""
|
||||
info "OpenCodeReview ${INSTALLED_VER} is ready!"
|
||||
info ""
|
||||
info "Quick start:"
|
||||
info " ocr version Show version info"
|
||||
info " ocr config set Configure your LLM provider"
|
||||
info " ocr review Start a code review"
|
||||
else
|
||||
warn ""
|
||||
warn "Installation completed but '${BINARY_NAME}' is not on PATH."
|
||||
warn "Add ${INSTALL_DIR} to your PATH, or run directly:"
|
||||
warn " ${TARGET} version"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Main ─────────────────────────────────────────────────────────────────────
|
||||
main() {
|
||||
info "OpenCodeReview CLI Installer"
|
||||
info "==================="
|
||||
|
||||
detect_platform
|
||||
resolve_version
|
||||
locate_or_download_binary
|
||||
install_binary
|
||||
verify_install
|
||||
}
|
||||
|
||||
main
|
||||
148
scripts/release.sh
Executable file
148
scripts/release.sh
Executable file
|
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# release.sh — Build all platform binaries and push to Alibaba Cloud OSS
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/release.sh # Builds using latest git tag as version
|
||||
# ./scripts/release.sh v0.1.0 # Explicit version tag
|
||||
#
|
||||
# Prerequisites:
|
||||
# - ossutil configured (run: ossutil config)
|
||||
# - Git tag exists for the version (or pass version explicitly)
|
||||
# - Go 1.25+ installed
|
||||
#
|
||||
# Environment variables:
|
||||
# OSS_ENDPOINT OSS endpoint URL (default: oss-cn-hangzhou.aliyuncs.com)
|
||||
# OSS_BUCKET Bucket name override
|
||||
# OSS_PREFIX Path prefix within bucket (default: opencodereview-cli)
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
|
||||
ENDPOINT="${OSS_ENDPOINT:-oss-cn-hangzhou.aliyuncs.com}"
|
||||
BUCKET="${OSS_BUCKET:-git.cn-hangzhou}"
|
||||
PREFIX="${OSS_PREFIX:-opencodereview-cli}"
|
||||
OSS_PATH="oss://${BUCKET}/${PREFIX}"
|
||||
|
||||
info() { echo "[INFO] $*"; }
|
||||
warn() { echo "[WARN] $*"; }
|
||||
error() { echo "[ERROR] $*"; }
|
||||
die() { error "$*"; exit 1; }
|
||||
|
||||
VERSION="${1:-}"
|
||||
|
||||
if [ -z "$VERSION" ]; then
|
||||
VERSION=$(git -C "$PROJECT_ROOT" describe --tags --abbrev=0 2>/dev/null || true)
|
||||
if [ -z "$VERSION" ]; then
|
||||
die "No git tag found. Pass a version explicitly or create a tag first."
|
||||
fi
|
||||
info "Using latest git tag: ${VERSION}"
|
||||
else
|
||||
[[ "$VERSION" != v* ]] && VERSION="v${VERSION}"
|
||||
fi
|
||||
|
||||
info "=== OpenCodeReview Release: ${VERSION} ==="
|
||||
|
||||
# ── Pre-flight checks ────────────────────────────────────────────────────────
|
||||
check_prereq() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "'$1' is required but not installed."
|
||||
}
|
||||
check_prereq go
|
||||
check_prereq ossutil
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
warn "Working tree has uncommitted changes. Proceeding anyway..."
|
||||
fi
|
||||
|
||||
# ── Build all platforms ──────────────────────────────────────────────────────
|
||||
DIST_DIR="${PROJECT_ROOT}/dist"
|
||||
mkdir -p "$DIST_DIR"
|
||||
rm -f "${DIST_DIR}/opencodereview-${VERSION}-"*
|
||||
|
||||
GIT_COMMIT="$(git rev-parse --short HEAD)"
|
||||
BUILD_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
LD_FLAGS="-s -w -X main.Version=${VERSION} -X main.GitCommit=${GIT_COMMIT} -X main.BuildDate=${BUILD_DATE}"
|
||||
|
||||
TARGETS=(
|
||||
"linux/amd64"
|
||||
"linux/arm64"
|
||||
"darwin/amd64"
|
||||
"darwin/arm64"
|
||||
)
|
||||
|
||||
for pair in "${TARGETS[@]}"; do
|
||||
GOOS="${pair%/*}"
|
||||
GOARCH="${pair#*/}"
|
||||
OS_ARCH="${GOOS}-${GOARCH}"
|
||||
OUTPUT_NAME="opencodereview-${VERSION}-${OS_ARCH}"
|
||||
|
||||
info "Building ${GOOS}/${GOARCH} → ${OUTPUT_NAME}"
|
||||
CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" \
|
||||
go build -ldflags "${LD_FLAGS}" \
|
||||
-o "${DIST_DIR}/${OUTPUT_NAME}" \
|
||||
./cmd/opencodereview
|
||||
done
|
||||
|
||||
# ── Generate per-version checksum file ───────────────────────────────────────
|
||||
CHECKSUM_FILE="${DIST_DIR}/sha256sum-${VERSION}.txt"
|
||||
|
||||
info "Generating checksums: sha256sum-${VERSION}.txt"
|
||||
(cd "$DIST_DIR" && shasum -a 256 opencodereview-"${VERSION}"-* | sort > "sha256sum-${VERSION}.txt")
|
||||
|
||||
info "Checksum contents:"
|
||||
cat "$CHECKSUM_FILE" | while read -r line; do echo " $line"; done
|
||||
|
||||
# ── Upload to OSS ────────────────────────────────────────────────────────────
|
||||
info ""
|
||||
info "Uploading to ${OSS_PATH} ..."
|
||||
|
||||
for f in "${DIST_DIR}"/opencodereview-"${VERSION}"-*; do
|
||||
BASENAME="$(basename "$f")"
|
||||
[[ "$BASENAME" == sha256sum-* ]] && continue
|
||||
info " Uploading ${BASENAME} ..."
|
||||
ossutil cp "$f" "${OSS_PATH}/${BASENAME}" \
|
||||
--endpoint "$ENDPOINT" \
|
||||
--acl public-read \
|
||||
--meta "Cache-Control:max-age=31536000"
|
||||
done
|
||||
|
||||
info " Uploading sha256sum-${VERSION}.txt ..."
|
||||
ossutil cp "$CHECKSUM_FILE" "${OSS_PATH}/sha256sum-${VERSION}.txt" \
|
||||
--endpoint "$ENDPOINT" \
|
||||
--acl public-read
|
||||
|
||||
info " Uploading install.sh ..."
|
||||
ossutil cp "${SCRIPT_DIR}/install.sh" "${OSS_PATH}/install.sh" \
|
||||
--endpoint "$ENDPOINT" \
|
||||
--acl public-read \
|
||||
--meta "Content-Type:text/x-sh"
|
||||
|
||||
echo -n "$VERSION" > "${DIST_DIR}/VERSION"
|
||||
info " Uploading VERSION sentinel ..."
|
||||
ossutil cp "${DIST_DIR}/VERSION" "${OSS_PATH}/VERSION" \
|
||||
--endpoint "$ENDPOINT" \
|
||||
--acl public-read \
|
||||
--meta "Cache-Control:no-cache"
|
||||
|
||||
# ── Summary ──────────────────────────────────────────────────────────────────
|
||||
CDN_URL="https://${BUCKET}.oss-cdn.aliyuncs.com/${PREFIX}"
|
||||
|
||||
info ""
|
||||
info "=== Release ${VERSION} published ==="
|
||||
info ""
|
||||
info "Install (latest):"
|
||||
info " curl -fsSL ${CDN_URL}/install.sh | sh"
|
||||
info ""
|
||||
info "Pinned install:"
|
||||
info " OCR_VERSION=${VERSION} curl -fsSL ${CDN_URL}/install.sh | sh"
|
||||
info ""
|
||||
info "Direct downloads:"
|
||||
for pair in "${TARGETS[@]}"; do
|
||||
GOOS="${pair%/*}"
|
||||
GOARCH="${pair#*/}"
|
||||
info " ${CDN_URL}/opencodereview-${VERSION}-${GOOS}-${GOARCH}"
|
||||
done
|
||||
Loading…
Add table
Add a link
Reference in a new issue