delete.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package crud
  6
  7import (
  8	"context"
  9
 10	"git.secluded.site/go-lunatask"
 11	"git.secluded.site/lune/internal/mcp/shared"
 12	"github.com/modelcontextprotocol/go-sdk/mcp"
 13)
 14
 15// DeleteToolName is the name of the consolidated delete tool.
 16const DeleteToolName = "delete"
 17
 18// DeleteToolDescription describes the delete tool for LLMs.
 19const DeleteToolDescription = `Deletes an entity from Lunatask.
 20
 21Required:
 22- entity: Type to delete (task, note, person)
 23- id: Entity UUID or lunatask:// deep link
 24
 25This action is permanent and cannot be undone.
 26
 27Returns confirmation of deletion with the entity's deep link.`
 28
 29// DeleteInput is the input schema for the consolidated delete tool.
 30type DeleteInput struct {
 31	Entity string `json:"entity" jsonschema:"required"`
 32	ID     string `json:"id"     jsonschema:"required"`
 33}
 34
 35// DeleteOutput is the output schema for the consolidated delete tool.
 36type DeleteOutput struct {
 37	Entity   string `json:"entity"`
 38	DeepLink string `json:"deep_link"`
 39	Success  bool   `json:"success"`
 40}
 41
 42// HandleDelete deletes an entity based on the entity type.
 43func (h *Handler) HandleDelete(
 44	ctx context.Context,
 45	_ *mcp.CallToolRequest,
 46	input DeleteInput,
 47) (*mcp.CallToolResult, DeleteOutput, error) {
 48	switch input.Entity {
 49	case EntityTask:
 50		return h.deleteTask(ctx, input)
 51	case EntityNote:
 52		return h.deleteNote(ctx, input)
 53	case EntityPerson:
 54		return h.deletePerson(ctx, input)
 55	default:
 56		return shared.ErrorResult("invalid entity: must be task, note, or person"),
 57			DeleteOutput{Entity: input.Entity}, nil
 58	}
 59}
 60
 61func (h *Handler) deleteTask(
 62	ctx context.Context,
 63	input DeleteInput,
 64) (*mcp.CallToolResult, DeleteOutput, error) {
 65	_, id, err := lunatask.ParseReference(input.ID)
 66	if err != nil {
 67		return shared.ErrorResult("invalid ID: expected UUID or lunatask:// deep link"),
 68			DeleteOutput{Entity: input.Entity}, nil
 69	}
 70
 71	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceTask, id)
 72
 73	if _, err := h.client.DeleteTask(ctx, id); err != nil {
 74		return shared.ErrorResult(err.Error()), DeleteOutput{Entity: input.Entity}, nil
 75	}
 76
 77	return &mcp.CallToolResult{
 78		Content: []mcp.Content{&mcp.TextContent{
 79			Text: "Task deleted: " + deepLink,
 80		}},
 81	}, DeleteOutput{Entity: input.Entity, DeepLink: deepLink, Success: true}, nil
 82}
 83
 84func (h *Handler) deleteNote(
 85	ctx context.Context,
 86	input DeleteInput,
 87) (*mcp.CallToolResult, DeleteOutput, error) {
 88	_, id, err := lunatask.ParseReference(input.ID)
 89	if err != nil {
 90		return shared.ErrorResult("invalid ID: expected UUID or lunatask:// deep link"),
 91			DeleteOutput{Entity: input.Entity}, nil
 92	}
 93
 94	note, err := h.client.DeleteNote(ctx, id)
 95	if err != nil {
 96		return shared.ErrorResult(err.Error()), DeleteOutput{Entity: input.Entity}, nil
 97	}
 98
 99	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourceNote, note.ID)
100
101	return &mcp.CallToolResult{
102		Content: []mcp.Content{&mcp.TextContent{
103			Text: "Note deleted: " + deepLink,
104		}},
105	}, DeleteOutput{Entity: input.Entity, DeepLink: deepLink, Success: true}, nil
106}
107
108func (h *Handler) deletePerson(
109	ctx context.Context,
110	input DeleteInput,
111) (*mcp.CallToolResult, DeleteOutput, error) {
112	_, id, err := lunatask.ParseReference(input.ID)
113	if err != nil {
114		return shared.ErrorResult("invalid ID: expected UUID or lunatask:// deep link"),
115			DeleteOutput{Entity: input.Entity}, nil
116	}
117
118	person, err := h.client.DeletePerson(ctx, id)
119	if err != nil {
120		return shared.ErrorResult(err.Error()), DeleteOutput{Entity: input.Entity}, nil
121	}
122
123	deepLink, _ := lunatask.BuildDeepLink(lunatask.ResourcePerson, person.ID)
124
125	return &mcp.CallToolResult{
126		Content: []mcp.Content{&mcp.TextContent{
127			Text: "Person deleted: " + deepLink,
128		}},
129	}, DeleteOutput{Entity: input.Entity, DeepLink: deepLink, Success: true}, nil
130}