@comfanion/usethis_todo 0.1.15-dev.0 → 0.1.15-dev.2

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 (3) hide show
  1. package/index.ts +48 -15
  2. package/package.json +1 -1
  3. package/tools.ts +7 -12
package/index.ts CHANGED
@@ -11,19 +11,7 @@ interface TodoPruneState {
11
11
  const pruneStates = new Map<string, TodoPruneState>()
12
12
 
13
13
  const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
14
- // Resolve the authoritative state path from OpenCode server (non-blocking).
15
- // Must NOT await — server may block until plugin init completes → deadlock.
16
- // Wrapped in try-catch because client.path may not exist (sync TypeError).
17
- try {
18
- client?.path?.get()?.then((pathInfo: any) => {
19
- const state = pathInfo?.data?.state
20
- if (state) setNativeStorageBase(state)
21
- }).catch(() => {})
22
- } catch {
23
- // client.path not available in this SDK version — fall back to guessed paths
24
- }
25
-
26
- // Ensure enhanced storage directory exists on init
14
+ // Ensure storage directory exists on init
27
15
  try {
28
16
  const todoDir = path.join(directory, ".opencode", "session-todo")
29
17
  await fs.mkdir(todoDir, { recursive: true })
@@ -31,6 +19,18 @@ const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
31
19
  // ignore
32
20
  }
33
21
 
22
+ // Resolve native storage path (non-blocking — MUST NOT await in init)
23
+ client.path.get().then((res) => {
24
+ try {
25
+ const state = (res as any)?.data?.state
26
+ if (state && typeof state === "string") {
27
+ setNativeStorageBase(state)
28
+ }
29
+ } catch {
30
+ // ignore
31
+ }
32
+ }).catch(() => {})
33
+
34
34
  return {
35
35
  "experimental.chat.messages.transform": async (_input: unknown, output: { messages: any[] }) => {
36
36
  const messages = output.messages || []
@@ -141,8 +141,41 @@ const UsethisTodoPlugin: Plugin = async ({ directory, client }) => {
141
141
  output.title = "📋 Task details"
142
142
  }
143
143
 
144
- // Native storage write handles sidebar updates now (via client.path.get()).
145
- // The old session.prompt snapshot was causing "table chunks not found" errors.
144
+ // Only publish for our write/update tools
145
+ const writeTools = new Set([
146
+ "usethis_todo_write",
147
+ "usethis_todo_update",
148
+ ])
149
+
150
+ if (!writeTools.has(input.tool)) return
151
+
152
+ // Attempt sidebar refresh via tui.command.execute hack
153
+ // The server may recognize a command that forces re-read of todo storage
154
+ try {
155
+ await (client as any)?.tui?.publish?.({
156
+ body: {
157
+ type: "tui.command.execute",
158
+ properties: { command: "session.todo.refresh" },
159
+ },
160
+ })
161
+ } catch {
162
+ // ignore — experimental
163
+ }
164
+
165
+ // Fallback: publish snapshot into chat (helps when sidebar doesn't refresh)
166
+ const text = ["## TODO", "", out].join("\n")
167
+
168
+ try {
169
+ await client?.session?.prompt?.({
170
+ path: { id: input.sessionID },
171
+ body: {
172
+ noReply: true,
173
+ parts: [{ type: "text", text }],
174
+ },
175
+ })
176
+ } catch {
177
+ // non-fatal
178
+ }
146
179
  },
147
180
  }
148
181
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@comfanion/usethis_todo",
3
- "version": "0.1.15-dev.0",
3
+ "version": "0.1.15-dev.2",
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
@@ -111,16 +111,11 @@ interface TodoGraph {
111
111
  // Storage — dual write
112
112
  // ============================================================================
113
113
 
114
- // Native storage base path (set by plugin init via client.path.get())
115
- let _nativeStorageBase: string | null = null
114
+ // Native storage base path (resolved from client.path.get() at runtime)
115
+ let nativeStorageBase: string | null = null
116
116
 
117
- /**
118
- * Set the native storage base path (OpenCode's state directory).
119
- * Called once during plugin initialization with the result of client.path.get().
120
- * This ensures we write to the exact path OpenCode reads from for the sidebar.
121
- */
122
117
  export function setNativeStorageBase(statePath: string): void {
123
- _nativeStorageBase = statePath
118
+ nativeStorageBase = statePath
124
119
  }
125
120
 
126
121
  // Resolve project directory (context.directory may be undefined via MCP)
@@ -171,12 +166,12 @@ async function getNativeDataDirs(): Promise<string[]> {
171
166
  async function getNativePaths(sid: string): Promise<string[]> {
172
167
  const file = `${sid || "current"}.json`
173
168
 
174
- // Prefer the authoritative path from OpenCode server API
175
- if (_nativeStorageBase) {
176
- return [path.join(_nativeStorageBase, "storage", "todo", file)]
169
+ // Prefer resolved path from client.path.get()
170
+ if (nativeStorageBase) {
171
+ return [path.join(nativeStorageBase, "storage", "todo", file)]
177
172
  }
178
173
 
179
- // Fallback: guess from well-known data dirs
174
+ // Fallback to guessed paths
180
175
  const baseDirs = await getNativeDataDirs()
181
176
  return baseDirs.map((base) => path.join(base, "opencode", "storage", "todo", file))
182
177
  }