a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
96 lines
3.2 KiB
Go
96 lines
3.2 KiB
Go
package mcp
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"github.com/zzet/gortex/internal/config"
|
|
"github.com/zzet/gortex/internal/gitcmd"
|
|
)
|
|
|
|
// autoIndexFileLimit bounds zero-config auto-indexing: a cwd repo with more
|
|
// git-tracked files than this is left for an explicit `gortex track`, so a
|
|
// stray tool call never silently chews through an enormous tree.
|
|
const autoIndexFileLimit = 25000
|
|
|
|
// maybeAutoIndexCWD lazily background-indexes the current working directory
|
|
// the first time a tool is called in a session, when the cwd is an untracked
|
|
// git repo. It is OFF by default and opt-in via GORTEX_AUTOINDEX=1 — the
|
|
// consent guardrail: auto-indexing is expensive, so the user asks for it.
|
|
// The request path pays only one getenv + a sync.Once check; all real work
|
|
// (git probing, the size bound, the index) runs on a background goroutine.
|
|
func (s *Server) maybeAutoIndexCWD() {
|
|
if s == nil || s.multiIndexer == nil {
|
|
return
|
|
}
|
|
if os.Getenv("GORTEX_AUTOINDEX") != "1" {
|
|
return
|
|
}
|
|
s.autoIndexOnce.Do(func() { go s.autoIndexCWDBackground() })
|
|
}
|
|
|
|
// autoIndexCWDBackground performs the bounded, consented auto-index off the
|
|
// request path: resolve the git root of the cwd, skip it when already
|
|
// covered or oversized, and otherwise track it.
|
|
func (s *Server) autoIndexCWDBackground() {
|
|
cwd, err := os.Getwd()
|
|
if err != nil || cwd == "" {
|
|
return
|
|
}
|
|
// Already covered by a tracked repo? nothing to do.
|
|
if s.multiIndexer.RepoForFile(cwd) != "" {
|
|
return
|
|
}
|
|
root := gitRepoRoot(cwd)
|
|
if root == "" || s.multiIndexer.RepoForFile(root) != "" {
|
|
return
|
|
}
|
|
// Bounded: a tree larger than the limit is left for an explicit track.
|
|
if n, over := repoFileCountOverLimit(root, autoIndexFileLimit); over {
|
|
if s.logger != nil {
|
|
s.logger.Info("auto-index: cwd repo exceeds the file-count limit; run `gortex track` to index it",
|
|
zap.String("root", root), zap.Int("limit", autoIndexFileLimit), zap.Int("at_least", n))
|
|
}
|
|
return
|
|
}
|
|
if s.logger != nil {
|
|
s.logger.Info("auto-index: background-indexing untracked cwd", zap.String("root", root))
|
|
}
|
|
if _, err := s.multiIndexer.TrackRepoCtx(context.Background(), config.RepoEntry{Path: root}); err != nil && s.logger != nil {
|
|
s.logger.Warn("auto-index: track failed", zap.String("root", root), zap.Error(err))
|
|
}
|
|
}
|
|
|
|
// gitRepoRoot resolves the git working-tree root containing dir, or "" when
|
|
// dir is not in a git repo.
|
|
func gitRepoRoot(dir string) string {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
out, err := gitcmd.Output(ctx, dir, "rev-parse", "--show-toplevel")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(out)
|
|
}
|
|
|
|
// repoFileCountOverLimit counts git-tracked files under root, reporting
|
|
// whether the count exceeds limit. A git error returns (0, false) — when we
|
|
// cannot measure the size we do not block (the indexer's own caps apply).
|
|
func repoFileCountOverLimit(root string, limit int) (int, bool) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
out, err := gitcmd.Output(ctx, root, "ls-files")
|
|
if err != nil {
|
|
return 0, false
|
|
}
|
|
n := strings.Count(out, "\n")
|
|
if strings.TrimSpace(out) != "" && !strings.HasSuffix(out, "\n") {
|
|
n++ // last line without a trailing newline
|
|
}
|
|
return n, n > limit
|
|
}
|