feat: agregar auto update

spec: separar responsabilidades
feat: agregra pipeline de construccion en gitea
This commit is contained in:
Carlos Sandoval
2026-09-02 20:01:35 +00:00
parent c1a060312f
commit 55eff5df89
9 changed files with 316 additions and 33 deletions
+33 -10
View File
@@ -64,7 +64,7 @@ func (c *OutlineClient) post(ctx context.Context, path string, payload any, resu
if err != nil {
return fmt.Errorf("error ejecutando petición: %w", err)
}
defer resp.Body.Close()
defer resp.Body.Close() //nolint:errcheck //nolint:errcheck
respBody, err := io.ReadAll(resp.Body)
if err != nil {
@@ -72,6 +72,13 @@ func (c *OutlineClient) post(ctx context.Context, path string, payload any, resu
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
var apiErr struct {
OK bool `json:"ok"`
Error string `json:"error"`
}
if json.Unmarshal(respBody, &apiErr) == nil && apiErr.Error != "" {
return fmt.Errorf("API error %d: %s", resp.StatusCode, apiErr.Error)
}
return fmt.Errorf("API error %d: %s", resp.StatusCode, string(respBody))
}
@@ -125,9 +132,14 @@ func handleSearch(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
var resp struct {
Data []struct {
ID string `json:"id"`
Title string `json:"title"`
URL string `json:"url"`
ID string `json:"id"`
Ranking int `json:"ranking"`
Context string `json:"context"`
Document struct {
ID string `json:"id"`
Title string `json:"title"`
URL string `json:"url"`
} `json:"document"`
} `json:"data"`
}
if err := client.post(ctx, "/api/documents.search", map[string]any{"query": query}, &resp); err != nil {
@@ -139,8 +151,11 @@ func handleSearch(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolRe
}
var lines []string
for _, d := range resp.Data {
lines = append(lines, fmt.Sprintf("- **%s** (id: %s) %s", d.Title, d.ID, d.URL))
for _, r := range resp.Data {
lines = append(lines, fmt.Sprintf("- **%s** (id: %s) %s", r.Document.Title, r.Document.ID, r.Document.URL))
if r.Context != "" {
lines = append(lines, " "+r.Context)
}
}
return mcp.NewToolResultText(strings.Join(lines, "\n")), nil
}
@@ -189,6 +204,8 @@ func handleCreateDocument(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
return mcp.NewToolResultError("Los parámetros title, text y collection_id son requeridos."), nil
}
publish := req.GetBool("publish", true)
var resp struct {
Data struct {
ID string `json:"id"`
@@ -199,6 +216,7 @@ func handleCreateDocument(ctx context.Context, req mcp.CallToolRequest) (*mcp.Ca
"title": title,
"text": text,
"collectionId": collectionID,
"publish": publish,
}, &resp); err != nil {
return mcp.NewToolResultError(err.Error()), nil
}
@@ -218,6 +236,8 @@ type giteaRelease struct {
func parseVersion(v string) (int, int, int, error) {
v = strings.TrimPrefix(v, "v")
v = strings.SplitN(v, "-", 2)[0]
v = strings.SplitN(v, "+", 2)[0]
parts := strings.SplitN(v, ".", 3)
if len(parts) != 3 {
return 0, 0, 0, fmt.Errorf("formato de versión inválido: %s", v)
@@ -268,10 +288,10 @@ func doUpdate() error {
if err != nil {
return fmt.Errorf("error consultando Gitea: %w", err)
}
defer resp.Body.Close()
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode != 200 {
return fmt.Errorf("Gitea respondió con código %d", resp.StatusCode)
return fmt.Errorf("gitea respondió con código %d", resp.StatusCode)
}
var release giteaRelease
@@ -310,13 +330,13 @@ func doUpdate() error {
if err != nil {
return fmt.Errorf("error descargando asset: %w", err)
}
defer resp.Body.Close()
defer resp.Body.Close() //nolint:errcheck
if resp.StatusCode != 200 {
return fmt.Errorf("error descargando asset: código %d", resp.StatusCode)
}
if err := selfupdate.Apply(resp.Body); err != nil {
if err := selfupdate.Apply(resp.Body, selfupdate.Options{}); err != nil {
return fmt.Errorf("error aplicando actualización: %w", err)
}
@@ -391,6 +411,9 @@ func main() {
mcp.Required(),
mcp.Description("ID de la colección destino"),
),
mcp.WithBoolean("publish",
mcp.Description("Publicar el documento (true por defecto). Si false, se crea como borrador"),
),
),
handleCreateDocument,
)