This commit is contained in:
Tomas Dvorak
2026-02-24 10:33:59 +01:00
parent 409acd2e08
commit 898a3c303f
1374 changed files with 290409 additions and 29187 deletions
+78 -26
View File
@@ -1,25 +1,32 @@
package cmd
import (
"context"
"fmt"
"net/url"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/yourorg/devour/internal/scraper"
"github.com/yourorg/devour/internal/search"
"github.com/yourorg/devour/internal/storage"
)
var pushCmd = &cobra.Command{
Use: "push <path>",
Short: "Push documents to remote MCP server",
Long: `Push local documents to a remote Devour MCP server.
Short: "Import local documents into Devour storage/index",
Long: `Push local documents into your Devour local workspace.
Useful for:
- Syncing local documentation to a shared server
- Backing up indexed content
- Contributing to a team knowledge base
Current stable behavior:
- local ingest into docs storage
- local reindex for query/ask/status
Remote push is experimental and not enabled by default.
Examples:
devour push ./docs
devour push ./docs --server http://devour.company.com
devour push ./docs --server http://localhost:8080 --project my-project`,
devour push ./docs --project my-project`,
Args: cobra.ExactArgs(1),
RunE: runPush,
}
@@ -30,33 +37,78 @@ var (
)
func init() {
pushCmd.Flags().StringVar(&pushServer, "server", "", "remote Devour server URL")
pushCmd.Flags().StringVarP(&pushProject, "project", "p", "", "project name on remote server")
pushCmd.Flags().StringVar(&pushServer, "server", "", "remote Devour server URL (experimental)")
pushCmd.Flags().StringVarP(&pushProject, "project", "p", "", "project name label")
}
func runPush(cmd *cobra.Command, args []string) error {
path := args[0]
if pushServer == "" {
// Try to get from config
pushServer = "http://localhost:8080"
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("path does not exist: %s", path)
}
fmt.Printf("📤 Pushing to: %s\n", pushServer)
fmt.Printf(" Path: %s\n", path)
if pushProject != "" {
fmt.Printf(" Project: %s\n", pushProject)
cfg, err := loadAppConfig()
if err != nil {
return err
}
// TODO: Implement actual push logic
// 1. Scan path for documents
// 2. Connect to remote server
// 3. Upload documents
// 4. Wait for indexing confirmation
server := strings.TrimSpace(pushServer)
if server != "" && !isLocalServer(server) {
return fmt.Errorf("remote push is experimental and not enabled in this build; use local push without --server")
}
fmt.Println()
fmt.Println("⚠️ Push functionality not yet implemented")
fmt.Println(" Remote server support coming soon")
projectName := strings.TrimSpace(pushProject)
if projectName == "" {
projectName = "local-push"
}
fmt.Printf("📤 Ingesting local docs from: %s\n", path)
fmt.Printf(" Project: %s\n", projectName)
fmt.Printf(" Target docs dir: %s\n", cfg.Storage.DocsDir)
s := scraper.NewScraper(scraper.SourceTypeLocal, toScraperConfig(cfg, 0))
if s == nil {
return fmt.Errorf("local scraper not available")
}
docs, err := s.Scrape(context.Background(), &scraper.Source{
Name: projectName,
Type: scraper.SourceTypeLocal,
Path: path,
Include: []string{`.*`},
})
if err != nil {
return fmt.Errorf("local ingest failed: %w", err)
}
saved, err := storage.SaveDocuments(docs, storage.SaveOptions{
Format: "json",
OutputDir: cfg.Storage.DocsDir,
AllowEmpty: false,
PrintWriter: nil,
})
if err != nil {
return fmt.Errorf("save docs failed: %w", err)
}
engine := search.NewEngine(cfg)
stats, err := engine.Rebuild(context.Background())
if err != nil {
return fmt.Errorf("reindex failed: %w", err)
}
fmt.Println("\n✓ Push complete")
fmt.Printf(" Documents imported: %d\n", saved.Count)
fmt.Printf(" Index docs: %d\n", stats.Documents)
fmt.Printf(" Index path: %s\n", stats.IndexPath)
return nil
}
func isLocalServer(raw string) bool {
u, err := url.Parse(raw)
if err != nil {
return false
}
host := strings.ToLower(u.Hostname())
return host == "" || host == "localhost" || host == "127.0.0.1"
}