@comfanion/usethis_todo 0.1.15-dev.6 → 0.1.15-dev.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.ts +12 -69
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -8,7 +8,7 @@ interface TodoPruneState {
8
8
 
9
9
  const pruneStates = new Map<string, TodoPruneState>()
10
10
 
11
- const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
11
+ const UsethisTodoPlugin: Plugin = async ({ directory }) => {
12
12
  // Ensure storage directory exists on init
13
13
  try {
14
14
  const todoDir = path.join(directory, ".opencode", "session-todo")
@@ -37,56 +37,26 @@ const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
37
37
  "todoread",
38
38
  ])
39
39
 
40
- // 1. Collect all TODO-related parts
40
+ // Collect all TODO-related tool parts
41
41
  const toolParts: { part: any; isLast: boolean }[] = []
42
- const snapshotParts = new Set<any>()
43
- let lastSnapshotPart: any = null
44
42
 
45
43
  for (const msg of messages) {
46
44
  for (const part of (msg.parts || [])) {
47
- // Tool parts (contain both state.input and state.output)
48
45
  if (part.type === "tool" && prunedToolNames.has(part.tool) && part.state?.status === "completed") {
49
46
  toolParts.push({ part, isLast: part.callID === state.lastToolCallId })
50
47
  }
51
- // User "## TODO" snapshot text parts
52
- if (part.type === "text" && typeof part.text === "string" && part.text.startsWith("## TODO")) {
53
- snapshotParts.add(part)
54
- lastSnapshotPart = part
55
- }
56
48
  }
57
49
  }
58
50
 
59
- if (toolParts.length === 0 && snapshotParts.size === 0) return
60
-
61
- // 2. Check if all tasks are done by parsing the latest snapshot
62
- const lastSnapshotText = lastSnapshotPart?.text || ""
63
- const doneMatch = lastSnapshotText.match(/\[(\d+)\/(\d+) done/)
64
- const allDone = doneMatch && doneMatch[1] === doneMatch[2] && parseInt(doneMatch[1]) > 0
51
+ if (toolParts.length === 0) return
65
52
 
66
- // 3. Prune old tool parts — clear BOTH input and output
53
+ // Prune old tool parts — clear BOTH input and output, keep only last
67
54
  for (const { part, isLast } of toolParts) {
68
- if (allDone || !isLast) {
55
+ if (!isLast) {
69
56
  part.state.output = "[TODO pruned]"
70
57
  if (part.state.input) part.state.input = {}
71
58
  }
72
59
  }
73
-
74
- // 4. Remove old "## TODO" snapshot parts entirely from messages
75
- // Keep only the last snapshot (or none if allDone)
76
- const snapshotsToRemove = new Set(snapshotParts)
77
- if (!allDone && lastSnapshotPart) {
78
- snapshotsToRemove.delete(lastSnapshotPart)
79
- }
80
-
81
- if (snapshotsToRemove.size > 0) {
82
- for (const msg of messages) {
83
- if (!Array.isArray(msg.parts)) continue
84
- msg.parts = msg.parts.filter((p: any) => !snapshotsToRemove.has(p))
85
- }
86
- }
87
-
88
- // 5. Remove messages that became empty after part removal
89
- output.messages = messages.filter((msg: any) => (msg.parts || []).length > 0)
90
60
  },
91
61
 
92
62
  tool: {
@@ -96,12 +66,12 @@ const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
96
66
  usethis_todo_read_five: read_five,
97
67
  usethis_todo_read_by_id: read_by_id,
98
68
  usethis_todo_update: update,
99
- // Override native tools — server may emit todo.updated for these names
69
+ // Override native tools — same implementation, native names
100
70
  todowrite: write,
101
71
  todoread: read,
102
72
  },
103
73
 
104
- // UI niceties + publish snapshot into the chat
74
+ // Set nicer titles in TUI + track prune state
105
75
  "tool.execute.after": async (input, output) => {
106
76
  if (!input.tool.startsWith("usethis_todo_") && input.tool !== "todowrite" && input.tool !== "todoread") return
107
77
 
@@ -118,44 +88,17 @@ const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
118
88
  // Set a nicer title in TUI
119
89
  if (input.tool === "usethis_todo_write" || input.tool === "todowrite") {
120
90
  const match = out.match(/\[(\d+)\/(\d+) done/)
121
- output.title = match ? `📋 TODO: ${match[2]} tasks` : "📋 TODO updated"
91
+ output.title = match ? `TODO: ${match[2]} tasks` : "TODO updated"
122
92
  } else if (input.tool === "usethis_todo_update") {
123
93
  const match = out.match(/^✅ (.+)$/m)
124
- output.title = match ? `📝 ${match[1]}` : "📝 Task updated"
94
+ output.title = match ? match[1] : "Task updated"
125
95
  } else if (input.tool === "usethis_todo_read" || input.tool === "todoread") {
126
96
  const match = out.match(/\[(\d+)\/(\d+) done, (\d+) in progress\]/)
127
- output.title = match ? `📋 TODO [${match[1]}/${match[2]} done]` : "📋 TODO list"
97
+ output.title = match ? `TODO [${match[1]}/${match[2]} done]` : "TODO list"
128
98
  } else if (input.tool === "usethis_todo_read_five") {
129
- output.title = "📋 Next 5 tasks"
99
+ output.title = "Next 5 tasks"
130
100
  } else if (input.tool === "usethis_todo_read_by_id") {
131
- output.title = "📋 Task details"
132
- }
133
-
134
- // Publish snapshot into chat (sidebar doesn't refresh from plugin writes)
135
- const publishTools = new Set([
136
- "usethis_todo_write",
137
- "usethis_todo_update",
138
- "usethis_todo_read",
139
- "usethis_todo_read_five",
140
- "usethis_todo_read_by_id",
141
- "todowrite",
142
- "todoread",
143
- ])
144
-
145
- if (!publishTools.has(input.tool)) return
146
-
147
- const text = ["## TODO", "", out].join("\n")
148
-
149
- try {
150
- await client?.session?.prompt?.({
151
- path: { id: input.sessionID },
152
- body: {
153
- noReply: true,
154
- parts: [{ type: "text", text }],
155
- },
156
- })
157
- } catch {
158
- // non-fatal
101
+ output.title = "Task details"
159
102
  }
160
103
  },
161
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/usethis_todo",
3
- "version": "0.1.15-dev.6",
3
+ "version": "0.1.15-dev.7",
4
4
  "description": "OpenCode plugin: enhanced TODO tools (dual storage + dependency graph)",
5
5
  "type": "module",
6
6
  "main": "./index.ts",