@comfanion/usethis_todo 0.1.16-dev.12 → 0.1.16-dev.13
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.
- package/index.ts +4 -1
- package/package.json +1 -1
- package/tools.ts +70 -6
package/index.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Plugin } from "@opencode-ai/plugin"
|
|
|
2
2
|
import path from "path"
|
|
3
3
|
import fs from "fs/promises"
|
|
4
4
|
|
|
5
|
-
import { write, read, read_five, read_by_id, setNativeStorageBase, readTodos } from "./tools"
|
|
5
|
+
import { write, read, read_five, read_by_id, setNativeStorageBase, readTodos, setClientStorage } from "./tools"
|
|
6
6
|
|
|
7
7
|
interface TodoPruneState {
|
|
8
8
|
lastToolCallId: string | null
|
|
@@ -11,6 +11,9 @@ interface TodoPruneState {
|
|
|
11
11
|
const pruneStates = new Map<string, TodoPruneState>()
|
|
12
12
|
|
|
13
13
|
const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
|
|
14
|
+
// Set client storage API for native Storage operations
|
|
15
|
+
setClientStorage(client)
|
|
16
|
+
|
|
14
17
|
// Resolve the authoritative state path from OpenCode server (non-blocking).
|
|
15
18
|
// Must NOT await — server may block until plugin init completes → deadlock.
|
|
16
19
|
client.path.get().then((pathInfo: any) => {
|
package/package.json
CHANGED
package/tools.ts
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* usethis_todo_read_by_id({ id }) - read task by id with its blockers
|
|
9
9
|
*
|
|
10
10
|
* Storage:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Dual: Native OpenCode storage (via client.storage) + Local file backup (.opencode/session-todo/)
|
|
12
|
+
* Native storage uses await client.storage.write(["todo", sessionID], todos)
|
|
13
13
|
*
|
|
14
14
|
* Features:
|
|
15
15
|
* - Stores FULL enhanced schema (blockedBy, priority, etc) in the native file
|
|
@@ -23,6 +23,44 @@ import path from "path"
|
|
|
23
23
|
import os from "os"
|
|
24
24
|
import fs from "fs/promises"
|
|
25
25
|
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Client Storage Wrapper
|
|
28
|
+
// ============================================================================
|
|
29
|
+
|
|
30
|
+
let _clientStorage: any = null
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Set the OpenCode client storage API.
|
|
34
|
+
* Called during plugin initialization.
|
|
35
|
+
*/
|
|
36
|
+
export function setClientStorage(client: any): void {
|
|
37
|
+
_clientStorage = client
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Write to native OpenCode storage.
|
|
42
|
+
*/
|
|
43
|
+
async function writeNativeStorage(key: string[], value: any): Promise<void> {
|
|
44
|
+
if (!_clientStorage?.write) return
|
|
45
|
+
try {
|
|
46
|
+
await _clientStorage.write(key, value)
|
|
47
|
+
} catch {
|
|
48
|
+
// ignore - native storage may not be available
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Read from native OpenCode storage.
|
|
54
|
+
*/
|
|
55
|
+
async function readNativeStorage<T>(key: string[]): Promise<T | null> {
|
|
56
|
+
if (!_clientStorage?.read) return null
|
|
57
|
+
try {
|
|
58
|
+
return await _clientStorage.read(key)
|
|
59
|
+
} catch {
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
26
64
|
// ============================================================================
|
|
27
65
|
// Types
|
|
28
66
|
// ============================================================================
|
|
@@ -195,12 +233,30 @@ function toNativePriority(priority: string): string {
|
|
|
195
233
|
// ============================================================================
|
|
196
234
|
|
|
197
235
|
export async function readTodos(sid: string, directory?: string): Promise<Todo[]> {
|
|
236
|
+
// 1. Try Native OpenCode Storage first (primary)
|
|
237
|
+
try {
|
|
238
|
+
const nativeData = await readNativeStorage<Todo[]>(["todo", sid])
|
|
239
|
+
if (Array.isArray(nativeData) && nativeData.length > 0) {
|
|
240
|
+
await logAction(directory || "", "debug", `Reading from native storage: todo/${sid}`)
|
|
241
|
+
return nativeData.map((t: any) => {
|
|
242
|
+
// Restore "ready" status if it was saved
|
|
243
|
+
const realStatus = t.usethisStatus || t.status
|
|
244
|
+
const realPriority = t.usethisPriority || t.priority
|
|
245
|
+
return normalizeTodo({ ...t, status: realStatus, priority: realPriority })
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
} catch (e) {
|
|
249
|
+
await logAction(directory || "", "debug", `Native storage read failed, falling back to files: ${String(e)}`)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// 2. Fallback to file storage
|
|
198
253
|
try {
|
|
199
254
|
const storagePaths = await getStoragePaths(sid)
|
|
200
255
|
for (const storagePath of storagePaths) {
|
|
201
256
|
try {
|
|
202
257
|
const raw = JSON.parse(await fs.readFile(storagePath, "utf-8"))
|
|
203
258
|
if (Array.isArray(raw)) {
|
|
259
|
+
await logAction(directory || "", "debug", `Reading from global file: ${storagePath}`)
|
|
204
260
|
return raw.map((t: any) => {
|
|
205
261
|
// Restore "ready" status if it was saved
|
|
206
262
|
const realStatus = t.usethisStatus || t.status
|
|
@@ -224,12 +280,12 @@ function getEnhancedPath(sid: string, directory?: string): string {
|
|
|
224
280
|
async function writeTodos(todos: Todo[], sid: string, directory?: string): Promise<void> {
|
|
225
281
|
const storagePaths = await getStoragePaths(sid)
|
|
226
282
|
const enhancedPath = getEnhancedPath(sid, directory)
|
|
227
|
-
|
|
283
|
+
|
|
228
284
|
const storageTodos = todos.map(t => {
|
|
229
285
|
// Status is already native — map "ready" to "in_progress" for native storage
|
|
230
286
|
const nativeStatus = t.status === "ready" ? "in_progress" : t.status
|
|
231
287
|
const nativePriority = toNativePriority(t.priority)
|
|
232
|
-
|
|
288
|
+
|
|
233
289
|
return {
|
|
234
290
|
...t,
|
|
235
291
|
status: nativeStatus,
|
|
@@ -242,7 +298,15 @@ async function writeTodos(todos: Todo[], sid: string, directory?: string): Promi
|
|
|
242
298
|
|
|
243
299
|
const json = JSON.stringify(storageTodos, null, 2)
|
|
244
300
|
|
|
245
|
-
// 1. Write to
|
|
301
|
+
// 1. Write to Native OpenCode Storage (primary)
|
|
302
|
+
try {
|
|
303
|
+
await writeNativeStorage(["todo", sid], storageTodos)
|
|
304
|
+
await logAction(directory || "", "debug", `Writing to native storage: todo/${sid}`)
|
|
305
|
+
} catch (e) {
|
|
306
|
+
await logAction(directory || "", "error", `Native storage write failed: ${String(e)}`)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 2. Write to Global Storages (for Sidebar - fallback)
|
|
246
310
|
await Promise.allSettled(
|
|
247
311
|
storagePaths.map(async (p) => {
|
|
248
312
|
try {
|
|
@@ -255,7 +319,7 @@ async function writeTodos(todos: Todo[], sid: string, directory?: string): Promi
|
|
|
255
319
|
})
|
|
256
320
|
)
|
|
257
321
|
|
|
258
|
-
//
|
|
322
|
+
// 3. Write to Local Storage (for User visibility/Git - backup)
|
|
259
323
|
try {
|
|
260
324
|
await fs.mkdir(path.dirname(enhancedPath), { recursive: true })
|
|
261
325
|
await fs.writeFile(enhancedPath, json, "utf-8")
|