mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-09-22 09:58:04 +00:00
example/memo: 待办与备忘分离(待办提醒、备忘纯记事)
- 待办(todo_add/todo_complete/todo_list):保留原有主动提醒能力—— stagePreAction 注入未完成条数 + periodicCheck 每 5 分钟 InjectInterruptText; 数据文件 todos.json - 备忘(memo_create/memo_list/memo_delete):纯记事用途,不参与任何提醒 (无 stage 注入、无周期中断);数据文件 memos.json - cleanupData 卸载时清理两个数据文件;ID 各自独立递增
This commit is contained in:
@ -13,20 +13,31 @@ import (
|
|||||||
"gitcode.com/JianFeeeee/homeagent-sdk/sdk"
|
"gitcode.com/JianFeeeee/homeagent-sdk/sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Memo struct {
|
// Todo 待办条目:会被主动提醒
|
||||||
|
type Todo struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Content string `json:"content"`
|
Content string `json:"content"`
|
||||||
CreatedAt int64 `json:"created_at"`
|
CreatedAt int64 `json:"created_at"`
|
||||||
Done bool `json:"done"`
|
Done bool `json:"done"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Memo 备忘录条目:纯记事,不主动提醒
|
||||||
|
type Memo struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
CreatedAt int64 `json:"created_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type Plugin struct {
|
type Plugin struct {
|
||||||
name string
|
name string
|
||||||
sdk *sdk.PluginSDK
|
sdk *sdk.PluginSDK
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
todos []Todo
|
||||||
|
nextTID int64
|
||||||
memos []Memo
|
memos []Memo
|
||||||
nextID int64
|
nextMID int64
|
||||||
filePath string
|
todoPath string
|
||||||
|
memoPath string
|
||||||
stopCh chan struct{}
|
stopCh chan struct{}
|
||||||
tp string
|
tp string
|
||||||
}
|
}
|
||||||
@ -43,67 +54,134 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|||||||
if err != nil || dataDirVal == "" {
|
if err != nil || dataDirVal == "" {
|
||||||
dataDirVal = "."
|
dataDirVal = "."
|
||||||
}
|
}
|
||||||
p.filePath = filepath.Join(fmt.Sprint(dataDirVal), "memos.json")
|
dir := fmt.Sprint(dataDirVal)
|
||||||
p.load()
|
p.todoPath = filepath.Join(dir, "todos.json")
|
||||||
|
p.memoPath = filepath.Join(dir, "memos.json")
|
||||||
|
p.loadTodos()
|
||||||
|
p.loadMemos()
|
||||||
|
|
||||||
// 卸载(删除)时清理备忘数据文件;重载不触发
|
// 卸载(删除)时清理数据文件;重载不触发
|
||||||
s.RegisterOnRemoveHandler(p.cleanupData)
|
s.RegisterOnRemoveHandler(p.cleanupData)
|
||||||
|
|
||||||
s.RegisterTool(p.tp+"create", sdk.ToolDef{
|
// ── 待办(会被主动提醒)──
|
||||||
Name: p.tp + "create",
|
s.RegisterTool(p.tp+"todo_add", sdk.ToolDef{
|
||||||
Description: "创建一条备忘条目。备忘内容应包含具体事项的完整描述。",
|
Name: p.tp + "todo_add",
|
||||||
|
Description: "添加一条待办事项。待办会被主动提醒,完成后请及时用 todo_complete 标记。",
|
||||||
Parameters: map[string]interface{}{
|
Parameters: map[string]interface{}{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": map[string]interface{}{
|
"properties": map[string]interface{}{
|
||||||
"content": map[string]interface{}{"type": "string", "description": "备忘内容"},
|
"content": map[string]interface{}{"type": "string", "description": "待办内容"},
|
||||||
},
|
},
|
||||||
"required": []string{"content"},
|
"required": []string{"content"},
|
||||||
},
|
},
|
||||||
}, p.handleCreate)
|
}, p.handleTodoAdd)
|
||||||
|
|
||||||
s.RegisterTool(p.tp+"complete", sdk.ToolDef{
|
s.RegisterTool(p.tp+"todo_complete", sdk.ToolDef{
|
||||||
Name: p.tp + "complete",
|
Name: p.tp + "todo_complete",
|
||||||
Description: "将指定ID的备忘标记为已完成。",
|
Description: "将指定ID的待办标记为已完成(不再提醒)。",
|
||||||
Parameters: map[string]interface{}{
|
Parameters: map[string]interface{}{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": map[string]interface{}{
|
"properties": map[string]interface{}{
|
||||||
"id": map[string]interface{}{"type": "integer", "description": "备忘ID"},
|
"id": map[string]interface{}{"type": "integer", "description": "待办ID"},
|
||||||
},
|
},
|
||||||
"required": []string{"id"},
|
"required": []string{"id"},
|
||||||
},
|
},
|
||||||
}, p.handleComplete)
|
}, p.handleTodoComplete)
|
||||||
|
|
||||||
s.RegisterTool(p.tp+"list", sdk.ToolDef{
|
s.RegisterTool(p.tp+"todo_list", sdk.ToolDef{
|
||||||
Name: p.tp + "list",
|
Name: p.tp + "todo_list",
|
||||||
Description: "列出所有未完成的备忘条目,包含ID、内容和创建时间。",
|
Description: "列出所有未完成的待办事项,包含ID、内容和创建时间。",
|
||||||
Parameters: map[string]interface{}{
|
Parameters: map[string]interface{}{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": map[string]interface{}{},
|
"properties": map[string]interface{}{},
|
||||||
},
|
},
|
||||||
}, p.handleList)
|
}, p.handleTodoList)
|
||||||
|
|
||||||
|
// ── 备忘(纯记事,不提醒)──
|
||||||
|
s.RegisterTool(p.tp+"memo_create", sdk.ToolDef{
|
||||||
|
Name: p.tp + "memo_create",
|
||||||
|
Description: "创建一条备忘录。备忘录是纯记事(备注)用途,不会主动提醒,内容应包含完整信息供后续查阅。",
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"type": "object",
|
||||||
|
"properties": map[string]interface{}{
|
||||||
|
"content": map[string]interface{}{"type": "string", "description": "备忘录内容"},
|
||||||
|
},
|
||||||
|
"required": []string{"content"},
|
||||||
|
},
|
||||||
|
}, p.handleMemoCreate)
|
||||||
|
|
||||||
|
s.RegisterTool(p.tp+"memo_list", sdk.ToolDef{
|
||||||
|
Name: p.tp + "memo_list",
|
||||||
|
Description: "列出所有备忘录,包含ID、内容和创建时间。",
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"type": "object",
|
||||||
|
"properties": map[string]interface{}{},
|
||||||
|
},
|
||||||
|
}, p.handleMemoList)
|
||||||
|
|
||||||
|
s.RegisterTool(p.tp+"memo_delete", sdk.ToolDef{
|
||||||
|
Name: p.tp + "memo_delete",
|
||||||
|
Description: "删除指定ID的备忘录。",
|
||||||
|
Parameters: map[string]interface{}{
|
||||||
|
"type": "object",
|
||||||
|
"properties": map[string]interface{}{
|
||||||
|
"id": map[string]interface{}{"type": "integer", "description": "备忘录ID"},
|
||||||
|
},
|
||||||
|
"required": []string{"id"},
|
||||||
|
},
|
||||||
|
}, p.handleMemoDelete)
|
||||||
|
|
||||||
|
// 待办提醒:预动作注入未完成条数 + 周期主动提醒(备忘录不参与)
|
||||||
s.RegisterStage(sdk.StagePreAction, p.stagePreAction)
|
s.RegisterStage(sdk.StagePreAction, p.stagePreAction)
|
||||||
|
|
||||||
go p.periodicCheck()
|
go p.periodicCheck()
|
||||||
|
|
||||||
log.Printf("[%s] started, path=%s", p.name, p.filePath)
|
log.Printf("[%s] started, todos=%s memos=%s", p.name, p.todoPath, p.memoPath)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) Stop() error {
|
func (p *Plugin) Stop() error {
|
||||||
close(p.stopCh)
|
close(p.stopCh)
|
||||||
p.save()
|
p.saveTodos()
|
||||||
|
p.saveMemos()
|
||||||
log.Printf("[%s] stopped", p.name)
|
log.Printf("[%s] stopped", p.name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) load() {
|
func (p *Plugin) loadTodos() {
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
defer p.mu.Unlock()
|
defer p.mu.Unlock()
|
||||||
data, err := os.ReadFile(p.filePath)
|
data, err := os.ReadFile(p.todoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.memos = nil
|
p.todos = []Todo{}
|
||||||
p.nextID = 1
|
p.nextTID = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var store struct {
|
||||||
|
Todos []Todo `json:"todos"`
|
||||||
|
NextID int64 `json:"next_id"`
|
||||||
|
}
|
||||||
|
if json.Unmarshal(data, &store) != nil {
|
||||||
|
p.todos = []Todo{}
|
||||||
|
p.nextTID = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.todos = store.Todos
|
||||||
|
p.nextTID = store.NextID
|
||||||
|
if p.todos == nil {
|
||||||
|
p.todos = []Todo{}
|
||||||
|
}
|
||||||
|
if p.nextTID < 1 {
|
||||||
|
p.nextTID = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plugin) loadMemos() {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
data, err := os.ReadFile(p.memoPath)
|
||||||
|
if err != nil {
|
||||||
|
p.memos = []Memo{}
|
||||||
|
p.nextMID = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var store struct {
|
var store struct {
|
||||||
@ -111,66 +189,78 @@ func (p *Plugin) load() {
|
|||||||
NextID int64 `json:"next_id"`
|
NextID int64 `json:"next_id"`
|
||||||
}
|
}
|
||||||
if json.Unmarshal(data, &store) != nil {
|
if json.Unmarshal(data, &store) != nil {
|
||||||
p.memos = nil
|
p.memos = []Memo{}
|
||||||
p.nextID = 1
|
p.nextMID = 1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.memos = store.Memos
|
p.memos = store.Memos
|
||||||
p.nextID = store.NextID
|
p.nextMID = store.NextID
|
||||||
if p.memos == nil {
|
if p.memos == nil {
|
||||||
p.memos = []Memo{}
|
p.memos = []Memo{}
|
||||||
}
|
}
|
||||||
if p.nextID < 1 {
|
if p.nextMID < 1 {
|
||||||
p.nextID = 1
|
p.nextMID = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) save() {
|
func (p *Plugin) saveTodos() {
|
||||||
data, _ := json.MarshalIndent(map[string]interface{}{
|
data, _ := json.MarshalIndent(map[string]interface{}{
|
||||||
"memos": p.memos,
|
"todos": p.todos,
|
||||||
"next_id": p.nextID,
|
"next_id": p.nextTID,
|
||||||
}, "", " ")
|
}, "", " ")
|
||||||
os.WriteFile(p.filePath, data, 0644)
|
os.WriteFile(p.todoPath, data, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) pendingCount() int {
|
func (p *Plugin) saveMemos() {
|
||||||
|
data, _ := json.MarshalIndent(map[string]interface{}{
|
||||||
|
"memos": p.memos,
|
||||||
|
"next_id": p.nextMID,
|
||||||
|
}, "", " ")
|
||||||
|
os.WriteFile(p.memoPath, data, 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 待办:未完成计数与提醒 ──
|
||||||
|
|
||||||
|
func (p *Plugin) pendingTodoCount() int {
|
||||||
p.mu.RLock()
|
p.mu.RLock()
|
||||||
defer p.mu.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
n := 0
|
n := 0
|
||||||
for _, m := range p.memos {
|
for _, t := range p.todos {
|
||||||
if !m.Done {
|
if !t.Done {
|
||||||
n++
|
n++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) pendingMemos() []Memo {
|
func (p *Plugin) pendingTodos() []Todo {
|
||||||
p.mu.RLock()
|
p.mu.RLock()
|
||||||
defer p.mu.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
var out []Memo
|
var out []Todo
|
||||||
for _, m := range p.memos {
|
for _, t := range p.todos {
|
||||||
if !m.Done {
|
if !t.Done {
|
||||||
out = append(out, m)
|
out = append(out, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stagePreAction 仅在待办未完成时注入上下文提示(备忘录不提示)
|
||||||
func (p *Plugin) stagePreAction(ctx *sdk.StageContext) error {
|
func (p *Plugin) stagePreAction(ctx *sdk.StageContext) error {
|
||||||
n := p.pendingCount()
|
n := p.pendingTodoCount()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ctx.Lock()
|
ctx.Lock()
|
||||||
ctx.ContextMsgs = append(ctx.ContextMsgs, map[string]interface{}{
|
ctx.ContextMsgs = append(ctx.ContextMsgs, map[string]interface{}{
|
||||||
"role": "system",
|
"role": "system",
|
||||||
"content": fmt.Sprintf("目前有%d条备忘未完成,调用%slist工具读取具体内容", n, p.tp),
|
"content": fmt.Sprintf("目前有%d条待办未完成,调用%s todo_list 工具读取具体内容", n, p.tp),
|
||||||
})
|
})
|
||||||
ctx.Unlock()
|
ctx.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// periodicCheck 周期主动提醒未完成待办(备忘录不提醒)
|
||||||
func (p *Plugin) periodicCheck() {
|
func (p *Plugin) periodicCheck() {
|
||||||
ticker := time.NewTicker(5 * time.Minute)
|
ticker := time.NewTicker(5 * time.Minute)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
@ -179,19 +269,97 @@ func (p *Plugin) periodicCheck() {
|
|||||||
case <-p.stopCh:
|
case <-p.stopCh:
|
||||||
return
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
n := p.pendingCount()
|
n := p.pendingTodoCount()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p.sdk != nil {
|
if p.sdk != nil {
|
||||||
p.sdk.InjectInterruptText(p.name, p.name,
|
p.sdk.InjectInterruptText(p.name, p.name,
|
||||||
fmt.Sprintf("注意,你还有%d条备忘未标记完成,请检查", n))
|
fmt.Sprintf("注意,你还有%d条待办未完成,请检查", n))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleCreate(args map[string]interface{}) (interface{}, error) {
|
// ── 待办工具 ──
|
||||||
|
|
||||||
|
func (p *Plugin) handleTodoAdd(args map[string]interface{}) (interface{}, error) {
|
||||||
|
content, _ := args["content"].(string)
|
||||||
|
if content == "" {
|
||||||
|
return errorResult("content is required"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mu.Lock()
|
||||||
|
todo := Todo{
|
||||||
|
ID: p.nextTID,
|
||||||
|
Content: content,
|
||||||
|
CreatedAt: time.Now().Unix(),
|
||||||
|
Done: false,
|
||||||
|
}
|
||||||
|
p.nextTID++
|
||||||
|
p.todos = append(p.todos, todo)
|
||||||
|
p.mu.Unlock()
|
||||||
|
p.saveTodos()
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"content": fmt.Sprintf("待办已添加 (ID: %d)", todo.ID),
|
||||||
|
"id": todo.ID,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plugin) handleTodoComplete(args map[string]interface{}) (interface{}, error) {
|
||||||
|
id, ok := args["id"].(float64)
|
||||||
|
if !ok {
|
||||||
|
return errorResult("id is required"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
p.mu.Lock()
|
||||||
|
found := false
|
||||||
|
for i := range p.todos {
|
||||||
|
if p.todos[i].ID == int64(id) && !p.todos[i].Done {
|
||||||
|
p.todos[i].Done = true
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return errorResult(fmt.Sprintf("未找到未完成的待办 ID: %d", int64(id))), nil
|
||||||
|
}
|
||||||
|
p.saveTodos()
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"content": fmt.Sprintf("待办 %d 已标记为完成", int64(id)),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Plugin) handleTodoList(args map[string]interface{}) (interface{}, error) {
|
||||||
|
todos := p.pendingTodos()
|
||||||
|
if len(todos) == 0 {
|
||||||
|
return map[string]interface{}{
|
||||||
|
"content": "暂无未完成的待办",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var sb strings.Builder
|
||||||
|
for i, t := range todos {
|
||||||
|
ts := time.Unix(t.CreatedAt, 0).Format("01-02 15:04")
|
||||||
|
if i > 0 {
|
||||||
|
sb.WriteString("\n")
|
||||||
|
}
|
||||||
|
sb.WriteString(fmt.Sprintf("%d. [ID:%d] %s — %s", i+1, t.ID, t.Content, ts))
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]interface{}{
|
||||||
|
"content": sb.String(),
|
||||||
|
"count": len(todos),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 备忘工具 ──
|
||||||
|
|
||||||
|
func (p *Plugin) handleMemoCreate(args map[string]interface{}) (interface{}, error) {
|
||||||
content, _ := args["content"].(string)
|
content, _ := args["content"].(string)
|
||||||
if content == "" {
|
if content == "" {
|
||||||
return errorResult("content is required"), nil
|
return errorResult("content is required"), nil
|
||||||
@ -199,23 +367,22 @@ func (p *Plugin) handleCreate(args map[string]interface{}) (interface{}, error)
|
|||||||
|
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
memo := Memo{
|
memo := Memo{
|
||||||
ID: p.nextID,
|
ID: p.nextMID,
|
||||||
Content: content,
|
Content: content,
|
||||||
CreatedAt: time.Now().Unix(),
|
CreatedAt: time.Now().Unix(),
|
||||||
Done: false,
|
|
||||||
}
|
}
|
||||||
p.nextID++
|
p.nextMID++
|
||||||
p.memos = append(p.memos, memo)
|
p.memos = append(p.memos, memo)
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
p.save()
|
p.saveMemos()
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"content": fmt.Sprintf("备忘已创建 (ID: %d)", memo.ID),
|
"content": fmt.Sprintf("备忘录已创建 (ID: %d)", memo.ID),
|
||||||
"id": memo.ID,
|
"id": memo.ID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleComplete(args map[string]interface{}) (interface{}, error) {
|
func (p *Plugin) handleMemoDelete(args map[string]interface{}) (interface{}, error) {
|
||||||
id, ok := args["id"].(float64)
|
id, ok := args["id"].(float64)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errorResult("id is required"), nil
|
return errorResult("id is required"), nil
|
||||||
@ -224,8 +391,8 @@ func (p *Plugin) handleComplete(args map[string]interface{}) (interface{}, error
|
|||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
found := false
|
found := false
|
||||||
for i := range p.memos {
|
for i := range p.memos {
|
||||||
if p.memos[i].ID == int64(id) && !p.memos[i].Done {
|
if p.memos[i].ID == int64(id) {
|
||||||
p.memos[i].Done = true
|
p.memos = append(p.memos[:i], p.memos[i+1:]...)
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -233,30 +400,33 @@ func (p *Plugin) handleComplete(args map[string]interface{}) (interface{}, error
|
|||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
return errorResult(fmt.Sprintf("未找到未完成的备忘 ID: %d", int64(id))), nil
|
return errorResult(fmt.Sprintf("未找到备忘录 ID: %d", int64(id))), nil
|
||||||
}
|
}
|
||||||
p.save()
|
p.saveMemos()
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"content": fmt.Sprintf("备忘 %d 已标记为完成", int64(id)),
|
"content": fmt.Sprintf("备忘录 %d 已删除", int64(id)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Plugin) handleList(args map[string]interface{}) (interface{}, error) {
|
func (p *Plugin) handleMemoList(args map[string]interface{}) (interface{}, error) {
|
||||||
memos := p.pendingMemos()
|
p.mu.RLock()
|
||||||
|
memos := append([]Memo{}, p.memos...)
|
||||||
|
p.mu.RUnlock()
|
||||||
|
|
||||||
if len(memos) == 0 {
|
if len(memos) == 0 {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
"content": "暂无未完成的备忘",
|
"content": "暂无备忘录",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
for i, m := range memos {
|
for i, m := range memos {
|
||||||
t := time.Unix(m.CreatedAt, 0).Format("01-02 15:04")
|
ts := time.Unix(m.CreatedAt, 0).Format("01-02 15:04")
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
sb.WriteString("\n")
|
sb.WriteString("\n")
|
||||||
}
|
}
|
||||||
sb.WriteString(fmt.Sprintf("%d. [ID:%d] %s — %s", i+1, m.ID, m.Content, t))
|
sb.WriteString(fmt.Sprintf("%d. [ID:%d] %s — %s", i+1, m.ID, m.Content, ts))
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
@ -276,9 +446,12 @@ func NewPluginFactory(name string, config map[string]interface{}) (sdk.Plugin, e
|
|||||||
return &Plugin{name: name}, nil
|
return &Plugin{name: name}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanupData 卸载时清理备忘数据文件
|
// cleanupData 卸载时清理数据文件(待办 + 备忘)
|
||||||
func (p *Plugin) cleanupData() {
|
func (p *Plugin) cleanupData() {
|
||||||
if p.filePath != "" {
|
if p.todoPath != "" {
|
||||||
os.Remove(p.filePath)
|
os.Remove(p.todoPath)
|
||||||
|
}
|
||||||
|
if p.memoPath != "" {
|
||||||
|
os.Remove(p.memoPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user