새 기능을 만들어서 tools/ 디렉토리에 .ts 파일로 떨궜다. opencode가 자동으로 로드해주니까, 그냥 넣기만 하면 된다고 생각했다.

결과는 w0(()=>X(Q)).then is not a function.

무슨 일이었나

opencode 1.17.13에서 ~/.config/opencode/tools/ 디렉토리에 .ts 파일을 넣으면 자동으로 MCP 툴로 등록해준다. 공식 문서에도 그렇게 나와 있다. 그래서 recall(), remember(), memory-stats() 세 개의 knowledge 툴을 .ts 파일로 작성했다.

그런데 opencode 바이너리가 이 .ts 파일을 실행할 때, 내부 JS 런타임의 버그로 then is not a function 에러가 났다. 내 코드는 전혀 문제가 없었다. opencode의 @opencode-ai/plugin 패키지가 정상적으로 번들링되지 않는 문제였다.

삽질 과정

처음에는 내 코드가 잘못됐다고 생각했다. tool() 함수 호출 방식이 바뀐 건가, export 형식이 문제인가 — 한 시간 넘게 디버깅했다. node로 직접 실행하면 정상 작동하는데, opencode에 넣으면 터진다.

결국 opencode 저장소 이슈를 뒤져서 발견했다. 바이너리에 내장된 JS 번들러가 export const server = { ... } 패턴을 제대로 처리하지 못하는 게 원인이었다. 코드 문제가 아니었다.

해결: tools/ → plugins/

해결책은 단순했다. opencode 1.17.13는 tools/ 대신 plugins/ 디렉토리를 지원한다. 플러그인은 CommonJS 형식의 index.js를 사용하고, import { tool } from "@opencode-ai/plugin" + export const server 패턴으로 작성한다.

파일을 옮기고 형식만 바꿨는데 바로 동작했다.

교훈

문서에 “이렇게 하면 된다”고 나와 있어도, 실제 바이너리 버전에 따라 안 될 수 있다. 특히 빠르게 발전하는 도구일수록 문서보다 구현이 뒤쳐지는 경우가 많다.

지금은 AGENTS.md Known Pitfalls에 “opencode 1.17.13: tools/ 디렉토리 .ts 파일 실행 불가”로 기록해두고, 새 프로젝트에서 knowledge 툴을 만들 때는 바로 plugins/로 시작한다.

이런 작은 삽질 하나하나가 쌓여서 내일의 나를 구한다.