test-mlua-lsp
mlua LSP Skill
MSW .mlua 작성/수정 시 @choigawoon/mlua-lsp@0.5.0을 npx로 호출해 코드 검증과 탐색을 수행한다.
프로토콜 범위 — 정직한 경계
이 스킬이 에이전트에게 노출하는 serve / mlua-batch.js / 단발 CLI는 LSP 프로토콜 자체가 아니라 데몬의 커스텀 newline-JSON RPC다. (1-based 좌표, 세션 없음, command 필드.) 내부에서 이 RPC는 진짜 LSP 서버(MSW 공식 msw.mlua 확장의 languageServer)를 구동한다.
진짜 LSP(JSON-RPC 2.0 + Content-Length + 0-based + initialize/didOpen/textDocument/*)가 필요하면 에디터가 쓰는 mlua-lsp server --stdio 엔드포인트를 직접 붙인다 — plugin.json의 lspServers가 이미 이 경로를 사용 중이다.
원칙
.d.mlua파일을 직접 읽지 않는다. MSW SDK는 600+ 정의 파일이라 토큰 낭비. 대신hover/complete로 조회.- 추측하지 말고 먼저 확인 →
hover·complete·signature로 API를 본 뒤 작성. - 작성 후 반드시
diagnose→errors: 0이 될 때까지 수정 루프. - 수정된
.mlua는 모아서 한 번에 batch diagnose — Edit/Write/MultiEdit로.mlua를 건드렸다면, 해당 작업 단위(유저 턴 또는 연속된 수정 배치)가 끝나는 시점에 수정된 모든 파일을 단 한 번의mlua-batch.js호출로 묶어 diagnose한다. 파일마다 개별 호출 금지 — queries.jsonl에 한 줄씩 쌓아서 일괄 전송. 응답의errors > 0인 파일만 수정 후 같은 방식으로 재진단. 자세한 절차는 "자동 점검 프로토콜" 참조. - 기본은
serve/batch(persistent stdin/stdout) — 한 번의 프로세스/TCP 연결로 N개 쿼리를 상각. 단발 CLI는 1개짜리 즉석 확인에만 사용. - 프로젝트 단위로 데몬 1개 — 다른 프로젝트로 넘어갈 때는
stop호출. 유휴 30분 뒤 자동 종료(MLUA_LSP_IDLE_MINUTES로 조정).
프로젝트 루트 (project-root)
모든 명령의 첫 인자는 MSW 프로젝트 루트여야 한다.
RootDesk/MyDesk/와Environment/NativeScripts/(.d.mlua)를 포함하는 상위 디렉토리- 잘못된 루트를 넘기면 hover/complete가 빈 결과를 반환하고 diagnose가 무의미해진다
- 동일 루트로 일관되게 호출해야 데몬이 워크스페이스 인덱스를 재사용
예: /Users/you/msw-projects/MyGame/ (내부에 RootDesk/MyDesk/·Environment/ 존재)
기본 호출 — 배치 (serve)
# 파일로부터
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> queries.jsonl
# stdin에서
cat queries.jsonl | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root>
요청 포맷 (newline-JSON, 한 줄 1쿼리)
{"id":1,"command":"diagnose","file":"/abs/path/a.mlua"}
{"id":2,"command":"hover","file":"/abs/path/b.mlua","line":10,"col":5}
{"id":3,"command":"complete","file":"/abs/path/c.mlua","line":7,"col":12}
line/col은 1-based. 생략 시null.id는 선택 (숫자 또는 문자열 모두 OK — 데몬은 opaque하게 echo back). 응답 상관관계 추적에 유용.- 응답도 newline-JSON으로 stdout에 순서대로 출력.
왜 batch가 기본인가
| 경로 | 1쿼리 | N쿼리 (warm) |
|---|---|---|
단발 CLI (mlua-lsp.js <cmd> …) |
~22ms | ~22ms × N (매 호출 Node + TCP) |
mlua-batch.js (serve) |
~22ms + α | ~22ms + N × daemon-RPC (p50 <5ms) |
에이전트가 여러 심볼을 연속 조회하거나 여러 파일을 진단할 때 batch가 수 배 빠르다. v4 벤치(MineSimulator 279파일, warm 6.2s @ 22ms 평균)는 단발 CLI 기준이므로, serve 사용 시 더 단축된다.
단발 호출 (fallback, 1쿼리)
한 지점만 확인하는 경우:
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-lsp.js <command> <project-root> <file> [line] [col]
- 래퍼가
npx -y @choigawoon/mlua-lsp@0.5.0을 통해 실행 — 별도 설치 불필요. - 출력은 pretty-printed JSON.
- 데몬 실패 시
--no-daemonone-shot으로 자동 폴백.
명령
| 명령 | 용도 | 반환 핵심 |
|---|---|---|
diagnose |
타입/문법/미존재 멤버 에러 | { errors, warnings, diagnostics[] } |
hover |
해당 위치의 타입·설명 | { type, documentation } |
complete |
. 직후 멤버 목록 |
{ summary, completions[] } |
definition |
정의 위치 이동 | { locations[] } |
references |
사용 지점 찾기 | { count, locations[] } |
signature |
함수 시그니처·파라미터 | { signatures[] } |
status |
데몬 상태 | { status, port, pid } |
dump |
데몬 live 스냅샷 (in-flight · 완료 카운트, --verbose로 open-file 목록) |
{ inflight, completed, openFiles? } |
describe |
머신 리더블 커맨드 카탈로그 (데몬 없이도 동작) | JSON 카탈로그 |
stop |
데몬 종료 | — |
serve (raw) |
newline-JSON 프록시 (batch의 하위 계층) | stdin→stdout JSONL |
diagnose·status·dump·describe·stop은 위치가 불필요, 나머지는 line/col 필수.
⚠️ Cold-daemon false positive (FP) — 글로벌 'Symbol not found' 의 함정
증상: diagnose / hover / signature 가 다음 중 다수에 found: false 또는 "Symbol not found" (info severity) 를 반환:
_로 시작하는 서비스 글로벌:_SpawnService,_TimerService,_UserService,_GameLogic,_UtilLogic,_MapService,_HttpService,_DataStorageService,_InputService, …- 빌트인 타입 생성자:
Vector2,Vector3,Quaternion,Color,Vector4 - 빌트인 컴포넌트 타입:
TextComponent,TransformComponent,UITransformComponent, …
원인: 데몬이 갓 떴거나 .d.mlua 파싱이 미완료 — 워크스페이스 인덱스 cold 상태. 진짜 미존재 아님.
왜 위험한가: 이 상태에서는 해당 글로벌의 member 호출 인자 타입 검증이 우회된다. 예 — _SpawnService:SpawnByModelId(id, name, Vector2(x,y), map) 처럼 4번째 위치에 Vector2 를 넘겨도 LSP 가 통과시킴. 런타임에 LEA-3005 InvalidArgument 가 터질 때까지 잡히지 않음. 실제 발생 이력 있음 (Vampire Survivor SpawnMonster, Vector3 자리에 Vector2 — LSP cold FP 로 묻힘).
처치 — Warm-up & re-diagnose 절차:
-
WARMUP —
.mlua편집을 시작하기 전, 또는 cold 의심 시점에 핵심 글로벌을 한 번씩 hover 로 두드린다. 한 번에 batch 로:cat <<EOF | node <plugin>/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> {"id":"w1","command":"hover","file":"<any project .mlua>","line":1,"col":1} {"id":"w2","command":"complete","file":"<any project .mlua>","line":1,"col":1} EOF직접 호출 대신 — 편집 대상 파일에
_SpawnService/Vector3가 등장하는 줄·열로 hover 던지기. 응답이found:false라도 데몬이 그 시점부터 인덱싱을 시작. 30초~수분 후 재시도. -
RE-DIAGNOSE — warmup 후 동일 파일을 batch diagnose 재실행. cold 시 떴던 13개 "Symbol not found" 가 사라지고 진짜 진단(시그니처 미스매치 등) 만 남는다.
-
글로벌이 여전히 not-found 면 두 가지 경우:
- Case A — 루트 잘못:
<project-root>/Environment/NativeScripts/Service/가 비어있거나 없음. 데몬은 아무리 기다려도 글로벌을 못 찾는다. 정답: 올바른 워크스페이스 루트로 재시작. - Case B — 인덱서 sticky:
mlua-lsp.js status가workspaceLoaded: true라고 보고하는데도 동일 FP 가 지속. 이는 데몬이 인덱스를 적재했다고 믿지만 실제 심볼 테이블이 비어있는 상태.mlua-lsp.js stop으로 데몬 죽이고 재호출 시도. 그래도 동일하면 워크스페이스의Environment/디렉토리 자체가 손상되었거나 버전 불일치. 이 경우 현재 턴에서 LSP 검증은 포기하고, 코드 리뷰(시그니처 수동 확인 —*.d.mlua직접 grep) 로 대체. 사용자에게 "LSP 인덱서 sticky 상태 — 수동 검증으로 진행" 명시.
판별 단서: 동일 워크스페이스의 기존 작동하는
.mlua파일(예:UIPopup.mlua) 에 diagnose 던졌을 때도 같은 글로벌이 not-found 로 나오면 sticky/workspace 문제 (편집 파일 책임 아님). - Case A — 루트 잘못:
식별 기준 — FP 인지 진짜인지:
| 토큰 모양 | not-found 의미 |
|---|---|
_ 로 시작 (_SpawnService) |
거의 항상 cold FP — warmup |
Vector2/Vector3/Quaternion/Color |
거의 항상 cold FP — warmup |
대문자 시작 빌트인 컴포넌트 (TextComponent, TransformComponent) |
거의 항상 cold FP — warmup |
사용자 정의 모듈/스크립트명 (MyManager, VampireGameManager) |
진짜 — 정의 누락 또는 오타 |
메소드/멤버 ('CurrentMap' not found in 'Entity') |
warmup 후에도 남아있으면 진짜 — 진짜 API 누락 |
금지 — "어차피 cold FP 일 거다" 로 진단 결과 통째 무시 후 ship. 반드시 warmup → 재진단으로 진짜 결과를 본 뒤 turn 마감.
워크플로
0. [WARMUP] 새 데몬 또는 의심 시 — 글로벌 hover 한 차례로 인덱스 깨우기
1. [PRE] batch로 hover/complete/signature 묶어서 API 확인
2. [WRITE] .mlua 작성 (여러 파일이어도 OK — 수정된 파일 경로를 머릿속에 쌓아둔다)
3. [POST] 수정된 전 파일을 한 번의 batch diagnose로 일괄 점검 → errors > 0인 파일만 수정 → 재진단 루프 → 전부 errors: 0
⚠️ diagnose 결과에 글로벌 'Symbol not found' 가 다수면 cold FP 의심 — warmup 후 재진단
4. [PLAY] (선택) msw-maker-mcp play로 실행 검증
예: 한 심볼에 대해 hover + definition + references를 동시에 알고 싶을 때 세 번의 단발 호출 대신 한 번의 batch.
cat <<EOF | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js /path/to/MyGame
{"id":1,"command":"hover","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":2,"command":"definition","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":3,"command":"references","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
EOF
자동 점검 프로토콜 — .mlua 편집 배치 끝에 반드시 수행
이 스킬을 로드한 에이전트는 다음 절차를 기본 동작으로 간주한다. Claude Code 훅이 자동 발화하지 않으므로, 스킬 지시를 따르는 에이전트가 스스로 수행해야 한다.
- 편집 트래킹 — Edit / Write / MultiEdit로
.mlua파일을 수정할 때마다 그 절대경로를 세션 내에서 모아둔다 (중복 제거). 한 파일을 여러 번 고쳤다면 한 번만 카운트. - 체크포인트 — 아래 중 하나에 도달하면 즉시 batch diagnose를 실행한다:
- 유저 턴에 요청된 편집 작업을 모두 마쳤을 때 (응답을 마무리하기 직전)
- 편집 파일 수가 10개를 넘어갈 때 (중간 점검)
- 유저가 "점검", "diagnose", "검수" 등을 명시적으로 요청할 때
- 실행 — 수집한 경로 집합을 newline-JSON 쿼리로 조립해 단 한 번의
mlua-batch.js호출로 전송.# 예: 수정된 파일 N개를 한 번에 printf '%s\n' "${edited_files[@]}" \ | awk '{printf "{\"id\":%d,\"command\":\"diagnose\",\"file\":\"%s\"}\n", NR, $0}' \ | node /path/to/mlua-batch.js <project-root> - 수정 루프 — 응답 중
errors > 0인 파일만 골라 diagnostics를 근거로 수정 → 해당 파일들만 다시 batch diagnose. 모든 파일이errors: 0이 될 때까지 반복. - 리포트 — 최종 결과를 유저에게 요약: 수정 파일 수 / clean 수 / 남은 에러 수 / (해결 불가한 경우) 원인 분석. 아무것도 수정하지 않았더라도 "편집 없음 — diagnose 생략"이라고 명시해 누락 여부를 투명하게.
금지 사항:
- 파일마다 개별
mlua-lsp.js diagnose호출 — TCP handshake × N으로 수 배 느려짐. - 편집 직후 매번 진단 — 연속 수정 흐름을 끊고 데몬 캐시를 낭비.
- diagnose 생략 후 턴 종료 — 에이전트의 재량에 맡기지 말고 체크포인트에 도달하면 무조건 실행.
에디터 LSP 연동 (진짜 LSP 경로)
plugin.json의 lspServers가 .mlua 파일을 열면 자동으로 mlua-lsp server --stdio를 붙인다 (npx 기반, 설치 불필요). 이쪽이 실제 LSP 스펙을 따르는 경로 — 에디터는 Content-Length 프레이밍 + 세션 lifecycle로 통신한다. 본 스킬의 에이전트 검증 루프(커스텀 RPC)와는 독립된 LSP 인스턴스를 사용하므로 둘은 공존한다.
참고
- docs/mlua-syntax.md — mlua 문법 요약 + MSW 프로젝트 구조
More from choigawoon/choigawoon-test-plugins
test-msw-vfs-cli
MSW `.map` / `.ui` / `.gamelogic` / `.model` 에셋과 `world.yaml` 을 버전 고정된 `@choigawoon/msw-vfs-cli`(npx) 로 읽고·탐색·편집·변환하는 스킬. '맵 구조 확인', '맵 엔티티 목록', 'UI 계층', 'HP바/텍스트 조사', 'entity 값 수정', '컴포넌트 추가/삭제', '.model 값 편집', 'YAML export/import', 'world 빌드', '.map/.ui/.gamelogic/.model 파일 분석' 요청 시 사용. L1(경로 기반 VFS) + L2(entity 단위) + .model + YAML/World 모두 지원.
7test-msw-map-ui-edit
MSW .map/.ui 에셋(맵 · UI 그룹 2종 포맷)을 VFS 도구로 읽고 분석하는 스킬. '맵 구조 확인', '맵 엔티티 목록', 'UI 구조', 'UI 계층', 'HP바/텍스트 조사', 'map/ui 파일 분석' 요청 시 사용. 현재 읽기 전용 — 편집은 복원 예정.
1