Skip to content

Commit 1b0a8ad

Browse files
committed
refactor(comment-checker): remove WASM fallback, use CLI-only with lazy download
- Remove tree-sitter-wasms and web-tree-sitter dependencies - Delete detector.ts (320 lines of WASM implementation) - Add downloader.ts for lazy binary download from GitHub Releases - Simplify index.ts to CLI-only mode - Cache binary at ~/.cache/oh-my-opencode/bin/ - Fall back to 'Comment checking disabled' when binary unavailable
1 parent 4b7a4b0 commit 1b0a8ad

File tree

8 files changed

+361
-541
lines changed

8 files changed

+361
-541
lines changed

bun.lock

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
"dependencies": {
88
"@ast-grep/cli": "^0.40.0",
99
"@ast-grep/napi": "^0.40.0",
10+
"@code-yeongyu/comment-checker": "^0.4.1",
1011
"@opencode-ai/plugin": "^1.0.7",
11-
"tree-sitter-wasms": "^0.1.12",
12-
"web-tree-sitter": "^0.24.7",
1312
"zod": "^4.1.8",
1413
},
1514
"devDependencies": {
@@ -23,6 +22,8 @@
2322
},
2423
"trustedDependencies": [
2524
"@ast-grep/cli",
25+
"@ast-grep/napi",
26+
"@code-yeongyu/comment-checker",
2627
],
2728
"packages": {
2829
"@ast-grep/cli": ["@ast-grep/[email protected]", "", { "dependencies": { "detect-libc": "2.1.2" }, "optionalDependencies": { "@ast-grep/cli-darwin-arm64": "0.40.0", "@ast-grep/cli-darwin-x64": "0.40.0", "@ast-grep/cli-linux-arm64-gnu": "0.40.0", "@ast-grep/cli-linux-x64-gnu": "0.40.0", "@ast-grep/cli-win32-arm64-msvc": "0.40.0", "@ast-grep/cli-win32-ia32-msvc": "0.40.0", "@ast-grep/cli-win32-x64-msvc": "0.40.0" }, "bin": { "sg": "sg", "ast-grep": "ast-grep" } }, "sha512-L8AkflsfI2ZP70yIdrwqvjR02ScCuRmM/qNGnJWUkOFck+e6gafNVJ4e4jjGQlEul+dNdBpx36+O2Op629t47A=="],
@@ -61,6 +62,8 @@
6162

6263
"@ast-grep/napi-win32-x64-msvc": ["@ast-grep/[email protected]", "", { "os": "win32", "cpu": "x64" }, "sha512-Hk2IwfPqMFGZt5SRxsoWmGLxBXxprow4LRp1eG6V8EEiJCNHxZ9ZiEaIc5bNvMDBjHVSnqZAXT22dROhrcSKQg=="],
6364

65+
"@code-yeongyu/comment-checker": ["@code-yeongyu/[email protected]", "", { "os": [ "linux", "win32", "darwin", ], "cpu": [ "x64", "arm64", ], "bin": { "comment-checker": "bin/comment-checker" } }, "sha512-E7p1V8CsRj9hMbwENd9BfxZGWYu+lKS5tXGuNNcNtkRMhWvwM/ononysKpLB7LXdxfSYAn0j7heJydyzEmm+lg=="],
66+
6467
"@opencode-ai/plugin": ["@opencode-ai/[email protected]", "", { "dependencies": { "@opencode-ai/sdk": "1.0.128", "zod": "4.1.8" } }, "sha512-M5vjz3I6KeoBSNduWmT5iHXRtTLCqICM5ocs+WrB3uxVorslcO3HVwcLzrERh/ntpxJ/1xhnHQaeG6Mg+P744A=="],
6568

6669
"@opencode-ai/sdk": ["@opencode-ai/[email protected]", "", {}, "sha512-Kow3Ivg8bR8dNRp8C0LwF9e8+woIrwFgw3ZALycwCfqS/UujDkJiBeYHdr1l/07GSHP9sZPmvJ6POuvfZ923EA=="],
@@ -95,14 +98,10 @@
9598

9699
"detect-libc": ["[email protected]", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
97100

98-
"tree-sitter-wasms": ["[email protected]", "", { "dependencies": { "tree-sitter-wasms": "^0.1.11" } }, "sha512-wT+cR6DwaIz80/vho3AvSF0N4txuNx/5bcRKoXouOfClpxh/qqrF4URNLQXbbt8MaAxeksZcZd1j8gcGjc+QxQ=="],
99-
100101
"typescript": ["[email protected]", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
101102

102103
"undici-types": ["[email protected]", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
103104

104-
"web-tree-sitter": ["[email protected]", "", {}, "sha512-CdC/TqVFbXqR+C51v38hv6wOPatKEUGxa39scAeFSm98wIhZxAYonhRQPSMmfZ2w7JDI0zQDdzdmgtNk06/krQ=="],
105-
106105
"zod": ["[email protected]", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="],
107106
}
108107
}

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "oh-my-opencode",
3-
"version": "0.1.13",
3+
"version": "0.1.14",
44
"description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",
@@ -44,9 +44,8 @@
4444
"dependencies": {
4545
"@ast-grep/cli": "^0.40.0",
4646
"@ast-grep/napi": "^0.40.0",
47+
"@code-yeongyu/comment-checker": "^0.4.1",
4748
"@opencode-ai/plugin": "^1.0.7",
48-
"tree-sitter-wasms": "^0.1.12",
49-
"web-tree-sitter": "^0.24.7",
5049
"zod": "^4.1.8"
5150
},
5251
"devDependencies": {
@@ -58,6 +57,7 @@
5857
},
5958
"trustedDependencies": [
6059
"@ast-grep/cli",
61-
"@ast-grep/napi"
60+
"@ast-grep/napi",
61+
"@code-yeongyu/comment-checker"
6262
]
6363
}

src/hooks/comment-checker/cli.ts

Lines changed: 114 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { createRequire } from "module"
33
import { dirname, join } from "path"
44
import { existsSync } from "fs"
55
import * as fs from "fs"
6+
import { getCachedBinaryPath, ensureCommentCheckerBinary } from "./downloader"
67

78
const DEBUG = process.env.COMMENT_CHECKER_DEBUG === "1"
89
const DEBUG_FILE = "/tmp/comment-checker-debug.log"
@@ -35,7 +36,12 @@ function getBinaryName(): string {
3536
return process.platform === "win32" ? "comment-checker.exe" : "comment-checker"
3637
}
3738

38-
function findCommentCheckerPath(): string | null {
39+
/**
40+
* Synchronously find comment-checker binary path.
41+
* Checks installed packages, homebrew, cache, and system PATH.
42+
* Does NOT trigger download.
43+
*/
44+
function findCommentCheckerPathSync(): string | null {
3945
const binaryName = getBinaryName()
4046

4147
// 1. Try to find from @code-yeongyu/comment-checker package
@@ -85,13 +91,87 @@ function findCommentCheckerPath(): string | null {
8591
}
8692
}
8793

88-
// 4. Try system PATH
89-
const systemPath = "comment-checker"
90-
debugLog("falling back to system PATH:", systemPath)
91-
return systemPath
94+
// 4. Try cached binary (lazy download location)
95+
const cachedPath = getCachedBinaryPath()
96+
if (cachedPath) {
97+
debugLog("found binary in cache:", cachedPath)
98+
return cachedPath
99+
}
100+
101+
// 5. Try system PATH (as fallback)
102+
debugLog("no binary found in known locations")
103+
return null
92104
}
93105

94-
export const COMMENT_CHECKER_CLI_PATH = findCommentCheckerPath()
106+
// Cached resolved path
107+
let resolvedCliPath: string | null = null
108+
let initPromise: Promise<string | null> | null = null
109+
110+
/**
111+
* Asynchronously get comment-checker binary path.
112+
* Will trigger lazy download if binary not found.
113+
*/
114+
export async function getCommentCheckerPath(): Promise<string | null> {
115+
// Return cached path if already resolved
116+
if (resolvedCliPath !== null) {
117+
return resolvedCliPath
118+
}
119+
120+
// Return existing promise if initialization is in progress
121+
if (initPromise) {
122+
return initPromise
123+
}
124+
125+
initPromise = (async () => {
126+
// First try sync path resolution
127+
const syncPath = findCommentCheckerPathSync()
128+
if (syncPath && existsSync(syncPath)) {
129+
resolvedCliPath = syncPath
130+
debugLog("using sync-resolved path:", syncPath)
131+
return syncPath
132+
}
133+
134+
// Lazy download if not found
135+
debugLog("triggering lazy download...")
136+
const downloadedPath = await ensureCommentCheckerBinary()
137+
if (downloadedPath) {
138+
resolvedCliPath = downloadedPath
139+
debugLog("using downloaded path:", downloadedPath)
140+
return downloadedPath
141+
}
142+
143+
debugLog("no binary available")
144+
return null
145+
})()
146+
147+
return initPromise
148+
}
149+
150+
/**
151+
* Synchronously get comment-checker path (no download).
152+
* Returns cached path or searches known locations.
153+
*/
154+
export function getCommentCheckerPathSync(): string | null {
155+
return resolvedCliPath ?? findCommentCheckerPathSync()
156+
}
157+
158+
/**
159+
* Start background initialization.
160+
* Call this early to trigger download while other init happens.
161+
*/
162+
export function startBackgroundInit(): void {
163+
if (!initPromise) {
164+
initPromise = getCommentCheckerPath()
165+
initPromise.then(path => {
166+
debugLog("background init complete:", path || "no binary")
167+
}).catch(err => {
168+
debugLog("background init error:", err)
169+
})
170+
}
171+
}
172+
173+
// Legacy export for backwards compatibility (sync, no download)
174+
export const COMMENT_CHECKER_CLI_PATH = findCommentCheckerPathSync()
95175

96176
export interface HookInput {
97177
session_id: string
@@ -114,17 +194,29 @@ export interface CheckResult {
114194
message: string
115195
}
116196

117-
export async function runCommentChecker(input: HookInput): Promise<CheckResult> {
118-
if (!COMMENT_CHECKER_CLI_PATH) {
197+
/**
198+
* Run comment-checker CLI with given input.
199+
* @param input Hook input to check
200+
* @param cliPath Optional explicit path to CLI binary
201+
*/
202+
export async function runCommentChecker(input: HookInput, cliPath?: string): Promise<CheckResult> {
203+
const binaryPath = cliPath ?? resolvedCliPath ?? COMMENT_CHECKER_CLI_PATH
204+
205+
if (!binaryPath) {
119206
debugLog("comment-checker binary not found")
120207
return { hasComments: false, message: "" }
121208
}
122209

210+
if (!existsSync(binaryPath)) {
211+
debugLog("comment-checker binary does not exist:", binaryPath)
212+
return { hasComments: false, message: "" }
213+
}
214+
123215
const jsonInput = JSON.stringify(input)
124216
debugLog("running comment-checker with input:", jsonInput.substring(0, 200))
125217

126218
try {
127-
const proc = spawn([COMMENT_CHECKER_CLI_PATH], {
219+
const proc = spawn([binaryPath], {
128220
stdin: "pipe",
129221
stdout: "pipe",
130222
stderr: "pipe",
@@ -158,6 +250,18 @@ export async function runCommentChecker(input: HookInput): Promise<CheckResult>
158250
}
159251
}
160252

253+
/**
254+
* Check if CLI is available (sync check, no download).
255+
*/
161256
export function isCliAvailable(): boolean {
162-
return COMMENT_CHECKER_CLI_PATH !== null && existsSync(COMMENT_CHECKER_CLI_PATH)
257+
const path = getCommentCheckerPathSync()
258+
return path !== null && existsSync(path)
259+
}
260+
261+
/**
262+
* Check if CLI will be available (async, may trigger download).
263+
*/
264+
export async function ensureCliAvailable(): Promise<boolean> {
265+
const path = await getCommentCheckerPath()
266+
return path !== null && existsSync(path)
163267
}
Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,3 @@
1-
import type { LanguageConfig } from "./types"
2-
3-
export const EXTENSION_TO_LANGUAGE: Record<string, string> = {
4-
py: "python",
5-
js: "javascript",
6-
jsx: "javascript",
7-
ts: "typescript",
8-
tsx: "tsx",
9-
go: "golang",
10-
java: "java",
11-
kt: "kotlin",
12-
scala: "scala",
13-
c: "c",
14-
h: "c",
15-
cpp: "cpp",
16-
cc: "cpp",
17-
cxx: "cpp",
18-
hpp: "cpp",
19-
rs: "rust",
20-
rb: "ruby",
21-
sh: "bash",
22-
bash: "bash",
23-
cs: "csharp",
24-
swift: "swift",
25-
ex: "elixir",
26-
exs: "elixir",
27-
lua: "lua",
28-
php: "php",
29-
ml: "ocaml",
30-
mli: "ocaml",
31-
sql: "sql",
32-
html: "html",
33-
htm: "html",
34-
css: "css",
35-
yaml: "yaml",
36-
yml: "yaml",
37-
toml: "toml",
38-
hcl: "hcl",
39-
tf: "hcl",
40-
dockerfile: "dockerfile",
41-
proto: "protobuf",
42-
svelte: "svelte",
43-
elm: "elm",
44-
groovy: "groovy",
45-
cue: "cue",
46-
}
47-
48-
export const QUERY_TEMPLATES: Record<string, string> = {
49-
python: "(comment) @comment",
50-
javascript: "(comment) @comment",
51-
typescript: "(comment) @comment",
52-
tsx: "(comment) @comment",
53-
golang: "(comment) @comment",
54-
rust: `
55-
(line_comment) @comment
56-
(block_comment) @comment
57-
`,
58-
kotlin: `
59-
(line_comment) @comment
60-
(multiline_comment) @comment
61-
`,
62-
java: `
63-
(line_comment) @comment
64-
(block_comment) @comment
65-
`,
66-
c: "(comment) @comment",
67-
cpp: "(comment) @comment",
68-
csharp: "(comment) @comment",
69-
ruby: "(comment) @comment",
70-
bash: "(comment) @comment",
71-
swift: "(comment) @comment",
72-
elixir: "(comment) @comment",
73-
lua: "(comment) @comment",
74-
php: "(comment) @comment",
75-
ocaml: "(comment) @comment",
76-
sql: "(comment) @comment",
77-
html: "(comment) @comment",
78-
css: "(comment) @comment",
79-
yaml: "(comment) @comment",
80-
toml: "(comment) @comment",
81-
hcl: "(comment) @comment",
82-
dockerfile: "(comment) @comment",
83-
protobuf: "(comment) @comment",
84-
svelte: "(comment) @comment",
85-
elm: "(comment) @comment",
86-
groovy: "(comment) @comment",
87-
cue: "(comment) @comment",
88-
scala: "(comment) @comment",
89-
}
90-
91-
export const DOCSTRING_QUERIES: Record<string, string> = {
92-
python: `
93-
(module . (expression_statement (string) @docstring))
94-
(class_definition body: (block . (expression_statement (string) @docstring)))
95-
(function_definition body: (block . (expression_statement (string) @docstring)))
96-
`,
97-
javascript: `
98-
(comment) @jsdoc
99-
(#match? @jsdoc "^/\\\\*\\\\*")
100-
`,
101-
typescript: `
102-
(comment) @jsdoc
103-
(#match? @jsdoc "^/\\\\*\\\\*")
104-
`,
105-
tsx: `
106-
(comment) @jsdoc
107-
(#match? @jsdoc "^/\\\\*\\\\*")
108-
`,
109-
java: `
110-
(comment) @javadoc
111-
(#match? @javadoc "^/\\\\*\\\\*")
112-
`,
113-
}
114-
1151
export const BDD_KEYWORDS = new Set([
1162
"given",
1173
"when",
@@ -191,14 +77,3 @@ Review in the above priority order and take the corresponding action EVERY TIME
19177
19278
Detected comments/docstrings:
19379
`
194-
195-
export function getLanguageByExtension(filePath: string): string | null {
196-
const lastDot = filePath.lastIndexOf(".")
197-
if (lastDot === -1) {
198-
const baseName = filePath.split("/").pop()?.toLowerCase()
199-
if (baseName === "dockerfile") return "dockerfile"
200-
return null
201-
}
202-
const ext = filePath.slice(lastDot + 1).toLowerCase()
203-
return EXTENSION_TO_LANGUAGE[ext] ?? null
204-
}

0 commit comments

Comments
 (0)