( event: any, deps: CommandDeps )
| 196 | } |
| 197 | |
| 198 | export async function handleAnnotateCommand( |
| 199 | event: any, |
| 200 | deps: CommandDeps |
| 201 | ) { |
| 202 | const { client, htmlContent, getSharingEnabled, getShareBaseUrl, getPasteApiUrl, directory } = deps; |
| 203 | const startServer = deps.startAnnotateServer ?? startAnnotateServer; |
| 204 | |
| 205 | // @ts-ignore - Event properties contain arguments |
| 206 | const rawArgs = event.properties?.arguments || event.arguments || ""; |
| 207 | // Split known annotate flags out of the args; rest is the file path. |
| 208 | // --json is accepted silently (OpenCode writes to session, not stdout). |
| 209 | // parseAnnotateArgs strips leading @ on filePath (reference-mode convention). |
| 210 | // `rawFilePath` preserves it for the scoped-package markdown fallback. |
| 211 | const { filePath, rawFilePath, gate, renderMarkdown: renderMarkdownFlag, noJina } = parseAnnotateArgs(rawArgs); |
| 212 | |
| 213 | if (!filePath) { |
| 214 | client.app.log({ level: "error", message: "Usage: /plannotator-annotate <file.md | file.txt | file.html | https://... | folder/> [--markdown] [--no-jina] [--gate] [--json]" }); |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | let markdown: string; |
| 219 | let rawHtml: string | undefined; |
| 220 | let absolutePath: string; |
| 221 | let folderPath: string | undefined; |
| 222 | let annotateMode: "annotate" | "annotate-folder" = "annotate"; |
| 223 | let isFolder = false; |
| 224 | let sourceInfo: string | undefined; |
| 225 | let sourceConverted = false; |
| 226 | const agentCwd = directory || process.cwd(); |
| 227 | |
| 228 | // --- URL annotation --- |
| 229 | const isUrl = /^https?:\/\//i.test(filePath); |
| 230 | |
| 231 | if (isUrl) { |
| 232 | const useJina = resolveUseJina(noJina, loadConfig()); |
| 233 | client.app.log({ level: "info", message: `Fetching: ${filePath}${useJina ? " (via Jina Reader)" : " (via fetch+Turndown)"}...` }); |
| 234 | try { |
| 235 | const result = await urlToMarkdown(filePath, { useJina }); |
| 236 | markdown = result.markdown; |
| 237 | sourceConverted = isConvertedSource(result.source); |
| 238 | } catch (err) { |
| 239 | client.app.log({ level: "error", message: `Failed to fetch URL: ${err instanceof Error ? err.message : String(err)}` }); |
| 240 | return; |
| 241 | } |
| 242 | absolutePath = filePath; |
| 243 | sourceInfo = filePath; |
| 244 | } else { |
| 245 | const projectRoot = agentCwd; |
| 246 | const resolvedArg = resolveUserPath(filePath, projectRoot); |
| 247 | |
| 248 | try { |
| 249 | isFolder = statSync(resolvedArg).isDirectory(); |
| 250 | } catch { |
| 251 | // Not a directory, fall through to file resolution. |
| 252 | } |
| 253 | |
| 254 | if (isFolder) { |
| 255 | if (!hasMarkdownFiles(resolvedArg, FILE_BROWSER_EXCLUDED, /\.(mdx?|txt|html?)$/i)) { |
no test coverage detected