@comfanion/usethis_todo 0.1.15-dev.12 → 0.1.15-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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tools.ts +38 -40
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/usethis_todo",
3
- "version": "0.1.15-dev.12",
3
+ "version": "0.1.15-dev.13",
4
4
  "description": "OpenCode plugin: enhanced TODO tools (dual storage + dependency graph)",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/tools.ts CHANGED
@@ -150,26 +150,22 @@ async function getNativeDataDirs(): Promise<string[]> {
150
150
  return [...dirs]
151
151
  }
152
152
 
153
- async function getStoragePath(sid: string): Promise<string> {
153
+ async function getStoragePaths(sid: string): Promise<string[]> {
154
154
  const file = `${sid || "current"}.json`
155
+ const paths: string[] = []
155
156
 
156
- // 1. Prefer authoritative path from OpenCode server
157
+ // 1. Authoritative path from OpenCode server
157
158
  if (_nativeStorageBase) {
158
- return path.join(_nativeStorageBase, "storage", "todo", file)
159
+ paths.push(path.join(_nativeStorageBase, "storage", "todo", file))
159
160
  }
160
161
 
161
- // 2. Fallback: guess from well-known data dirs (first one that exists or default)
162
+ // 2. Well-known data dirs (fallbacks)
162
163
  const baseDirs = await getNativeDataDirs()
163
- // Try to find one that exists
164
164
  for (const base of baseDirs) {
165
- try {
166
- await fs.access(base)
167
- return path.join(base, "opencode", "storage", "todo", file)
168
- } catch {}
165
+ paths.push(path.join(base, "opencode", "storage", "todo", file))
169
166
  }
170
167
 
171
- // Default to first one
172
- return path.join(baseDirs[0], "opencode", "storage", "todo", file)
168
+ return [...new Set(paths)] // Unique paths
173
169
  }
174
170
 
175
171
  // ============================================================================
@@ -217,21 +213,21 @@ function toNativePriority(priority: string): string {
217
213
 
218
214
  async function readTodos(sid: string, directory?: string): Promise<Todo[]> {
219
215
  try {
220
- const storagePath = await getStoragePath(sid)
221
- const raw = JSON.parse(await fs.readFile(storagePath, "utf-8"))
222
- if (!Array.isArray(raw)) return []
223
-
224
- return raw.map((t: any) => {
225
- // Restore our rich status from shadow field if present
226
- const realStatus = fromNativeStatus(t.status, t.usethisStatus)
227
- const realPriority = t.usethisPriority || t.priority // Fallback if not shadowed
228
-
229
- return normalizeTodo({
230
- ...t,
231
- status: realStatus,
232
- priority: realPriority
233
- })
234
- })
216
+ const storagePaths = await getStoragePaths(sid)
217
+ // Try to read from any available path, starting with authoritative
218
+ for (const storagePath of storagePaths) {
219
+ try {
220
+ const raw = JSON.parse(await fs.readFile(storagePath, "utf-8"))
221
+ if (Array.isArray(raw)) {
222
+ return raw.map((t: any) => {
223
+ const realStatus = fromNativeStatus(t.status, t.usethisStatus)
224
+ const realPriority = t.usethisPriority || t.priority
225
+ return normalizeTodo({ ...t, status: realStatus, priority: realPriority })
226
+ })
227
+ }
228
+ } catch { continue }
229
+ }
230
+ return []
235
231
  } catch {
236
232
  return []
237
233
  }
@@ -243,25 +239,17 @@ function getEnhancedPath(sid: string, directory?: string): string {
243
239
  }
244
240
 
245
241
  async function writeTodos(todos: Todo[], sid: string, directory?: string): Promise<void> {
246
- const storagePath = await getStoragePath(sid)
242
+ const storagePaths = await getStoragePaths(sid)
247
243
  const enhancedPath = getEnhancedPath(sid, directory)
248
244
 
249
- // Prepare for storage:
250
- // 1. Set native-compatible fields (status, priority)
251
- // 2. Store real values in shadow fields (usethisStatus, usethisPriority)
252
- // 3. Keep all other fields (blockedBy, etc)
253
-
254
245
  const storageTodos = todos.map(t => {
255
246
  const nativeStatus = toNativeStatus(t.status)
256
247
  const nativePriority = toNativePriority(t.priority)
257
248
 
258
249
  return {
259
250
  ...t,
260
- // Native fields for Sidebar compatibility
261
251
  status: nativeStatus,
262
252
  priority: nativePriority,
263
-
264
- // Shadow fields (our source of truth)
265
253
  usethisStatus: t.status,
266
254
  usethisPriority: t.priority
267
255
  }
@@ -269,16 +257,26 @@ async function writeTodos(todos: Todo[], sid: string, directory?: string): Promi
269
257
 
270
258
  const json = JSON.stringify(storageTodos, null, 2)
271
259
 
272
- // 1. Write to Global Storage (for Sidebar)
273
- await fs.mkdir(path.dirname(storagePath), { recursive: true })
274
- await fs.writeFile(storagePath, json, "utf-8")
260
+ // 1. Write to Global Storages (for Sidebar)
261
+ await Promise.allSettled(
262
+ storagePaths.map(async (p) => {
263
+ try {
264
+ await fs.mkdir(path.dirname(p), { recursive: true })
265
+ await fs.writeFile(p, json, "utf-8")
266
+ await logAction(directory || "", "debug", `Writing to global: ${p}`)
267
+ } catch (e) {
268
+ await logAction(directory || "", "error", `Global write failed for ${p}: ${String(e)}`)
269
+ }
270
+ })
271
+ )
275
272
 
276
273
  // 2. Write to Local Storage (for User visibility/Git)
277
274
  try {
278
275
  await fs.mkdir(path.dirname(enhancedPath), { recursive: true })
279
276
  await fs.writeFile(enhancedPath, json, "utf-8")
280
- } catch {
281
- // ignore local write errors (non-fatal)
277
+ await logAction(directory || "", "debug", `Writing to local: ${enhancedPath}`)
278
+ } catch (e) {
279
+ await logAction(directory || "", "error", `Local write failed: ${String(e)}`)
282
280
  }
283
281
  }
284
282