opencode-plannotator-tui 0.2.1 → 0.2.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.2
4
+
5
+ - All confirmation dialogs, status notices, errors, and the feedback header sent
6
+ to the assistant are now in English.
7
+
3
8
  ## 0.2.1
4
9
 
5
10
  - Use an English command description in the slash menu and command palette.
package/README.md CHANGED
@@ -61,8 +61,8 @@ Manual configuration, preserving other entries:
61
61
  3. Press `c` to comment, `a` for “looks good,” or `d` to request deletion.
62
62
  Without a selection, `c` comments on the current block. Enter saves a comment.
63
63
  4. Press **`q`** to return to OpenCode.
64
- 5. Choose **发送并继续** (“Send and continue”) to submit the annotations. Escape or
65
- **取消** cancels. The adapter's confirmation and status messages are currently Chinese.
64
+ 5. Choose **Send and continue** to submit the annotations. Escape or **Cancel**
65
+ cancels.
66
66
 
67
67
  The upstream **`E`** action copies to the clipboard. This adapter's automatic
68
68
  delivery path is **q → confirm** and does not need clipboard access.
@@ -162,7 +162,7 @@ See [release instructions](docs/releasing.md) and [changelog](CHANGELOG.md).
162
162
  - `/annotate`:批注上一条完整回复。
163
163
  - `/annotate 文档.md`:批注文档,支持中文、空格和相对路径。
164
164
  - `/annotate-last`:同义入口,也可带文件路径。
165
- - 选中文字 → `c` 写批注 → Enter 保存 → `q` 返回 →「发送并继续」。
165
+ - 选中文字 → `c` 写批注 → Enter 保存 → `q` 返回 →「Send and continue」。
166
166
  - 文档采用独立快照,反馈附原文件路径,确认后发回发起批注的会话。
167
167
  - 更新:`opencode plugin update opencode-plannotator-tui@latest`,然后重新打开终端客户端。
168
168
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-plannotator-tui",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Unofficial OpenCode adapter for Plannotator TUI: annotate replies and documents without leaving your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/review.mjs CHANGED
@@ -15,26 +15,26 @@ async function documentSource(input, client, sessionID, signal) {
15
15
  target = target.slice(1, -1)
16
16
  }
17
17
  if (!target || !documentExtensions.has(path.extname(target).toLowerCase())) {
18
- throw new Error("请指定一个 Markdown 或纯文本文件(.md、.mdx、.markdown、.txt)。")
18
+ throw new Error("Choose a Markdown or plain-text file (.md, .mdx, .markdown, .txt).")
19
19
  }
20
- if (/^[a-z][a-z0-9+.-]*:\/\//i.test(target)) throw new Error("请指定本地文件路径。")
20
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(target)) throw new Error("Use a local file path.")
21
21
  if (target.startsWith("~/")) target = path.join(os.homedir(), target.slice(2))
22
22
  const session = await client.session.get({ sessionID }, { signal })
23
23
  const directory = session.location?.directory
24
- if (!path.isAbsolute(target) && !directory) throw new Error("无法确定当前会话的工作目录。")
24
+ if (!path.isAbsolute(target) && !directory) throw new Error("Can't determine the current session's working directory.")
25
25
  const filePath = path.isAbsolute(target) ? path.normalize(target) : path.resolve(directory, target)
26
26
  try {
27
27
  const info = await stat(filePath)
28
- if (!info.isFile()) throw new Error("目标不是文件。")
29
- if (info.size > maxDocumentBytes) throw new Error("文件超过 2 MiB,请先选取较小的文档。")
28
+ if (!info.isFile()) throw new Error("The target is not a file.")
29
+ if (info.size > maxDocumentBytes) throw new Error("The file is larger than 2 MiB. Choose a smaller document.")
30
30
  const bytes = await readFile(filePath, { signal })
31
- if (bytes.length > maxDocumentBytes) throw new Error("文件超过 2 MiB。")
32
- if (bytes.includes(0)) throw new Error("文件包含二进制内容。")
31
+ if (bytes.length > maxDocumentBytes) throw new Error("The file is larger than 2 MiB.")
32
+ if (bytes.includes(0)) throw new Error("The file contains binary content.")
33
33
  let text
34
34
  try {
35
35
  text = new TextDecoder("utf-8", { fatal: true }).decode(bytes)
36
36
  } catch {
37
- throw new Error("请使用 UTF-8 编码的文本文件。")
37
+ throw new Error("Use a UTF-8 text file.")
38
38
  }
39
39
  return {
40
40
  text, filePath,
@@ -43,7 +43,7 @@ async function documentSource(input, client, sessionID, signal) {
43
43
  }
44
44
  } catch (error) {
45
45
  if (signal.aborted) throw error
46
- throw new Error(`无法读取文档「${filePath}」:${error.code === "ENOENT" ? "文件不存在。" : error.message}`)
46
+ throw new Error(`Can't read document "${filePath}": ${error.code === "ENOENT" ? "file not found." : error.message}`)
47
47
  }
48
48
  }
49
49
 
@@ -71,7 +71,7 @@ async function latestReply(client, sessionID, signal) {
71
71
  const reply = selectReply(page.data)
72
72
  if (reply) return reply
73
73
  cursor = page.cursor?.next
74
- if (cursor && seen.has(cursor)) throw new Error("读取会话历史时收到重复分页游标。")
74
+ if (cursor && seen.has(cursor)) throw new Error("Session history returned a repeated page cursor.")
75
75
  seen.add(cursor)
76
76
  } while (cursor)
77
77
  }
@@ -88,7 +88,7 @@ async function archivedNotes(data) {
88
88
 
89
89
  async function interactive({ binary, file, cwd, env, signal }) {
90
90
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
91
- throw new Error("请在 OpenCode 完整终端界面中运行 /annotate。")
91
+ throw new Error("Run /annotate in the full OpenCode terminal interface.")
92
92
  }
93
93
  await new Promise((resolve, reject) => {
94
94
  const child = spawn(binary, [file], { cwd, env, stdio: "inherit", signal })
@@ -111,10 +111,10 @@ export function createReviewCommand(context, options = {}) {
111
111
 
112
112
  async function run(input = "") {
113
113
  if (disposed) return
114
- if (active) return notice("已有批注正在进行。")
114
+ if (active) return notice("An annotation is already in progress.")
115
115
  // Capture before the first await: changing tabs must never redirect a review.
116
116
  const route = context.ui.router.current()
117
- if (route.type !== "session") return notice("请先打开一个会话。")
117
+ if (route.type !== "session") return notice("Open a session first.")
118
118
  const sessionID = route.sessionID
119
119
  const title = context.data.session.get(sessionID)?.title ?? sessionID
120
120
  const controller = new AbortController()
@@ -129,7 +129,7 @@ export function createReviewCommand(context, options = {}) {
129
129
  ? await documentSource(target, context.client, sessionID, controller.signal)
130
130
  : await latestReply(context.client, sessionID, controller.signal)
131
131
  if (controller.signal.aborted) return
132
- if (!source) return notice("当前会话还没有已完成的助手回复。")
132
+ if (!source) return notice("This session has no completed assistant reply yet.")
133
133
 
134
134
  directory = await mkdtemp(path.join(options.tempRoot ?? os.tmpdir(), "opencode-annotate-"))
135
135
  keepDraft = true
@@ -171,42 +171,42 @@ export function createReviewCommand(context, options = {}) {
171
171
  })
172
172
  const feedback = stdout.trim()
173
173
  const archived = await archivedNotes(data)
174
- const retainedArchive = archived ? `\n${archived} 条归档批注保留在 ${directory}。` : ""
174
+ const retainedArchive = archived ? `\n${archived} archived ${archived === 1 ? "note was" : "notes were"} kept in ${directory}.` : ""
175
175
  // Upstream 0.9.4 emits this sentinel rather than empty stdout.
176
176
  if (!feedback || feedback === "No annotations.") {
177
177
  keepDraft = archived > 0
178
- return notice(archived ? `没有待发送的批注。${retainedArchive}` : "没有批注,已返回会话。", archived ? "warning" : "info")
178
+ return notice(archived ? `No annotations to send.${retainedArchive}` : "No annotations. Returned to the session.", archived ? "warning" : "info")
179
179
  }
180
- if (!feedback.startsWith("# Annotations on ")) throw new Error("无法识别 TUI 的批注导出格式。")
180
+ if (!feedback.startsWith("# Annotations on ")) throw new Error("Can't recognize the TUI annotation export format.")
181
181
  const subject = source.filePath
182
- ? `以下是我对文档 ${JSON.stringify(source.filePath)} 的批注,请按反馈处理该文件。\n批注基于打开时的文档快照(SHA-256:${source.sourceHash});修改前请重新读取原文件并核对引用。`
183
- : `以下是我对你回复 ${source.id} 的批注,请按反馈处理。`
182
+ ? `Here are my annotations on the document ${JSON.stringify(source.filePath)}. Please apply the feedback to that file.\nThe annotations are based on a snapshot taken when the document was opened (SHA-256: ${source.sourceHash}). Re-read the file and check the quoted text before editing.`
183
+ : `Here are my annotations on your reply ${source.id}. Please address the feedback.`
184
184
  const text = `${subject}\n\n${feedback}`
185
185
  const feedbackPath = path.join(directory, "feedback.md")
186
186
  await writeFile(feedbackPath, text, { mode: 0o600 })
187
187
  const count = (feedback.match(/^## Annotation /gm) ?? []).length
188
188
  const confirmed = await context.ui.dialog.confirm({
189
- title: "发送批注?",
190
- message: `${source.filePath ? `文档:${source.filePath}\n` : ""}将 ${count} 条批注发送到「${title}」,并让助手继续处理?`,
191
- label: { confirm: "发送并继续", cancel: "取消" },
189
+ title: "Send annotations?",
190
+ message: `${source.filePath ? `Document: ${source.filePath}\n` : ""}Send ${count} ${count === 1 ? "annotation" : "annotations"} to "${title}" and let the assistant continue?`,
191
+ label: { confirm: "Send and continue", cancel: "Cancel" },
192
192
  })
193
193
  if (controller.signal.aborted) return
194
194
  if (confirmed !== true) {
195
195
  keepDraft = archived > 0
196
- return notice(`已取消发送。${retainedArchive}`)
196
+ return notice(`Sending cancelled.${retainedArchive}`)
197
197
  }
198
198
  await context.client.session.prompt({
199
199
  sessionID, id: promptID, text, delivery: "queue", resume: true,
200
200
  })
201
201
  keepDraft = archived > 0
202
- notice(`已发送 ${count} 条批注。${retainedArchive}`, "success")
202
+ notice(`Sent ${count} ${count === 1 ? "annotation" : "annotations"}.${retainedArchive}`, "success")
203
203
  } catch (error) {
204
204
  if (!disposed) {
205
205
  const detail = error?.code === "ENOENT"
206
- ? "找不到 plannotator-tui;请检查安装和 PATH。"
206
+ ? "Can't find plannotator-tui. Check that it is installed and on PATH."
207
207
  : error instanceof Error ? error.message : String(error)
208
208
  const recovery = keepDraft && directory
209
- ? `\n草稿保留在 ${directory};若已导出,反馈文件为 feedback.md。`
209
+ ? `\nThe draft was kept in ${directory}. If it was exported, the feedback is in feedback.md.`
210
210
  : ""
211
211
  notice(`${detail}${recovery}`, "error")
212
212
  }