@nerdvana/parism 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -34,6 +34,20 @@ This has a cost. Running `ls` once looks simple, but the agent may spend dozens
34
34
 
35
35
  ---
36
36
 
37
+ ## The Honest Truth — Tokens Cost More
38
+
39
+ When building Parism, the expectation was token savings. Structured data should be more efficient than raw text.
40
+
41
+ Benchmarks across 17 scenarios flatly contradicted that. JSON output averages 205% heavier than raw text. For `ls -la` with 200 files: raw 5,807 tokens, Parism 15,531 tokens. Nearly triple, because key names repeat with every entry. What a human eye resolves from a single header row, JSON spells out N times.
42
+
43
+ But the same benchmarks revealed something else: the disappearance of "explanation tokens." With raw text, the agent needs context — "this format has permissions in the first column, owner in the third." That context prompt shrinks by an average of 61% with Parism. JSON describes its own structure. The agent just reads keys.
44
+
45
+ And there is a crossover point. For one-shot queries — run `ls` once, done — Parism costs more tokens. But the moment that result feeds into a next step, the cost structure inverts. An agent that misreads raw text writes to a nonexistent path, debugs the failure by scanning history, retries, fails again. Tokens snowball. An agent that starts with structured data never enters that cycle.
46
+
47
+ Parism's economics live not on the invoice, but in the space where mistakes and rework used to be. The cost of reading once more is nothing compared to the cost of reading once wrong.
48
+
49
+ ---
50
+
37
51
  ## What Parism Does
38
52
 
39
53
  A prism does not destroy light. It decomposes it.
@@ -62,12 +76,22 @@ The information does not change. The shape does. The agent no longer parses. It
62
76
 
63
77
  ### No More Parsing Errors
64
78
 
65
- Text parsing breaks easily. `ps aux` has different column ordering on Linux and macOS. The `1K-blocks` header in `df -h` varies by environment. Filenames with spaces almost always break `ls` parsing. Parism's parsers handle these cases directly. The agent receives structured data.
79
+ Text parsing breaks easily. `ps aux` has different column ordering on Linux and macOS. The `1K-blocks` header in `df -h` varies by environment. Filenames with spaces almost always break `ls` parsing.
80
+
81
+ In numbers: raw text parsing by agents has an average CFR (Critical Failure Rate) of 4.18%. With filenames containing spaces, it climbs to 28.6%. That means 286 out of 1,000 calls produce a wrong file listing that the agent then acts on — reading wrong files, writing to nonexistent paths, deleting the wrong thing.
82
+
83
+ macOS `stat` is a starker example. Its output format is entirely different from Linux. Linux uses labeled lines like `Size: 4096`; macOS outputs a single unlabeled line. Apply a Linux parsing pattern and accuracy drops to 0%. Parism detects the OS and selects the correct parser. The agent never needs to know the difference.
84
+
85
+ Parism's CFR is 0%. Parsers are deterministic code, not probabilistic inference. The agent receives structured data.
66
86
 
67
87
  ### Fewer Retries
68
88
 
69
89
  When an agent misinterprets output, it re-queries, runs a second command to verify, or proceeds with bad data. All three cost tokens. Structured output reduces room for misinterpretation. The file count is not something to infer — it is `entries.length`.
70
90
 
91
+ ### The Agent Gets Better at Everything Else
92
+
93
+ Parsing text is inference. Inference consumes cognitive resources. When the agent spends capacity decoding output formats, less remains for the actual work — analyzing code, making design judgments, deciding the next step. Structured data eliminates parsing as a task entirely. The agent reads instead of reasons, and the freed capacity flows into the work that matters.
94
+
71
95
  ### `raw` Is Always Preserved
72
96
 
73
97
  Parsers can be wrong. Some commands have no parser. So Parism always keeps `raw`. `parsed` is a bonus. `raw` is the fallback. The agent can always return to the original output.
@@ -87,6 +111,10 @@ Whether success or failure, `ok` and `exitCode` are always in the same place. Th
87
111
 
88
112
  Every response includes `duration_ms`. The agent can judge whether a command is slow or fast. Useful for debugging too.
89
113
 
114
+ ### diff Is Optional
115
+
116
+ `diff` (created/deleted/modified) is populated only when `includeDiff: true`. run/run_paged default to `includeDiff: false`, skipping snapshot cost to reduce MCP call latency.
117
+
90
118
  ---
91
119
 
92
120
  ## Guard — Why Not to Trust the Agent
@@ -99,7 +127,7 @@ There are four layers of defense.
99
127
 
100
128
  **Command Whitelist**: Commands not in `allowed_commands` are never executed. No process is created. Rejected silently.
101
129
 
102
- **Path Restriction**: When `allowed_paths` is set, Guard validates both `cwd` and path-like args (starting with `/`, `./`, `../`). Anything outside allowed paths is blocked.
130
+ **Path Restriction**: When `allowed_paths` is set, Guard validates `cwd` and path args. Args starting with `/`, `./`, `../` and positional args of path-taking commands (`cat`, `find`, `ls`, `grep` — e.g. `cat subdir/file`, `find src`) are checked. References outside allowed paths are blocked. This is a guard, not a kernel-level sandbox.
103
131
 
104
132
  **Injection Pattern Blocking**: If `;`, `$(`, `` ` ``, `&&`, `||`, `|`, `>`, `>>`, or `<` appear in any argument, the command is not executed.
105
133
 
@@ -121,46 +149,60 @@ The agent receives the block reason in the same envelope structure as any other
121
149
 
122
150
  ---
123
151
 
124
- ## Supported Commands — 34 Built-in Parsers
125
-
126
- | Category | Command | Parsed Output |
127
- |---|---|---|
128
- | Filesystem | `ls` | `entries[]` — name, type, permissions, size, modified time, owner |
129
- | Filesystem | `find` | `paths[]` — list of paths |
130
- | Filesystem | `stat` | `file`, `size_bytes`, `inode`, `permissions`, `uid`, `gid`, timestamps |
131
- | Filesystem | `du` | `entries[]` — size, path |
132
- | Filesystem | `df` | `filesystems[]` — partition, usage, mount point |
133
- | Filesystem | `tree` | `root`, `tree{}` — hierarchical node map, `total_files`, `total_dirs` |
134
- | Process | `ps` | `processes[]` — PID, CPU%, MEM%, command |
135
- | Process | `kill` | raw pass-through |
136
- | Network | `ping` | `target`, `packets_transmitted`, `packet_loss_percent`, `rtt_*_ms` |
137
- | Network | `curl -I` | `status_code`, `headers{}` |
138
- | Network | `netstat` | `connections[]` — proto, local/foreign address, state |
139
- | Network | `lsof -i` | `entries[]` — PID, process name, protocol, local/remote address, state |
140
- | Network | `ss` | `entries[]` — state, recv/send queue, local/peer address, process |
141
- | Network | `dig` | `query`, `answers[]` — type, value, TTL, `query_time_ms` |
142
- | Text | `grep` | `matches[]` — file, line number, text |
143
- | Text | `wc` | `entries[]` — count, filename |
144
- | Text | `head`, `tail`, `cat` | `lines[]` |
145
- | Git | `git status` | `branch`, `staged[]`, `modified[]`, `untracked[]` |
146
- | Git | `git log --oneline` | `commits[]` — hash, message |
147
- | Git | `git diff` | `files_changed[]` |
148
- | Git | `git branch -vv` | `branches[]` — name, current, upstream, ahead/behind |
149
- | DevOps | `kubectl get pods`, `kubectl get events` | `pods[]` / `events[]` — status, restarts, reasons, messages |
150
- | DevOps | `docker ps`, `docker stats --no-stream` | `containers[]` / `stats[]` — image, status, CPU/MEM/IO |
151
- | DevOps | `gh pr list` | `pull_requests[]` — number, title, state, author, labels |
152
- | Env | `env` | `vars{}` — key-value map (secrets filtered) |
153
- | Env | `pwd` | `path` |
154
- | Env | `which` | `paths[]` |
155
- | System | `free` | `mem`, `swap` total, used, free, available in bytes |
156
- | System | `uname` | `kernel_name`, `hostname`, `kernel_release`, `machine`, `os` |
157
- | System | `id` | `uid`, `gid`, `user`, `group`, `groups[]` id, name |
158
- | Windows | `dir` | `directory`, `entries[]` name, type, size, modified time, `free_bytes` |
159
- | Windows | `tasklist` | `processes[]` — name, PID, session, memory. CSV format supported |
160
- | Windows | `ipconfig` | `hostname`, `adapters[]` — IPv4/6, subnet, gateway, DNS, MAC |
161
- | Windows | `systeminfo` | `hostname`, `os_name`, memory, `hotfixes[]`, `network_cards[]` |
162
-
163
- Commands without a parser return `parsed: null`. `raw` is always present.
152
+ ## Supported Commands — 44 Built-in Parsers
153
+
154
+ | Category | Command | Parsed Output | Default |
155
+ |---|---|---|---|
156
+ | Filesystem | `ls` | `entries[]` — name, type, permissions, size, modified time, owner | O |
157
+ | Filesystem | `find` | `paths[]` — list of paths | O |
158
+ | Filesystem | `stat` | `file`, `size_bytes`, `inode`, `permissions`, `uid`, `gid`, timestamps | O |
159
+ | Filesystem | `du` | `entries[]` — size, path | O |
160
+ | Filesystem | `df` | `filesystems[]` — partition, usage, mount point | O |
161
+ | Filesystem | `tree` | `root`, `tree{}` — hierarchical node map, `total_files`, `total_dirs` | O |
162
+ | Process | `ps` | `processes[]` — PID, CPU%, MEM%, command | O |
163
+ | Process | `kill` | raw pass-through (blocked by default, add to prism.config.json to allow) | X |
164
+ | Network | `ping` | `target`, `packets_transmitted`, `packet_loss_percent`, `rtt_*_ms` | O |
165
+ | Network | `curl -I` | `status_code`, `headers{}` | O |
166
+ | Network | `netstat` | `connections[]` — proto, local/foreign address, state | O |
167
+ | Network | `lsof -i` | `entries[]` — PID, process name, protocol, local/remote address, state | X |
168
+ | Network | `ss` | `connections[]` — state, recv/send queue, local/peer address | X |
169
+ | Network | `dig` | `query`, `answers[]` — type, value, TTL, `query_time_ms` | X |
170
+ | Text | `grep -n` | `matches[]` — file, line number, text | O |
171
+ | Text | `wc` | `entries[]` — count, filename | O |
172
+ | Text | `head`, `tail`, `cat` | `lines[]` | O |
173
+ | Git | `git status` | `branch`, `staged[]`, `modified[]`, `untracked[]` | O |
174
+ | Git | `git log --oneline` | `commits[]` — hash, message | O |
175
+ | Git | `git diff` | `files_changed[]` | O |
176
+ | Git | `git branch -vv` | `branches[]` — name, current, upstream, ahead/behind | O |
177
+ | DevOps | `kubectl get pods`, `kubectl get events` | `pods[]` / `events[]` — status, restarts, reasons, messages | O |
178
+ | DevOps | `docker ps`, `docker stats --no-stream` | `containers[]` / `stats[]` — image, status, CPU/MEM/IO | O |
179
+ | DevOps | `gh pr list` | `pull_requests[]` — number, title, state, author, labels | O |
180
+ | DevOps | `helm list` | `releases[]` — name, namespace, status, chart, app_version | O |
181
+ | DevOps | `terraform plan` | `summary` — to_add, to_change, to_destroy | O |
182
+ | Env | `env` | `vars{}` — key-value map (secrets filtered) | O |
183
+ | Env | `pwd` | `path` | O |
184
+ | Env | `which` | `paths[]` | O |
185
+ | System | `free` | `mem`, `swap` total, used, free, available in bytes | X |
186
+ | System | `uname` | `kernel_name`, `hostname`, `kernel_release`, `machine`, `os` | O |
187
+ | System | `id` | `uid`, `gid`, `user`, `group`, `groups[]` — id, name | X |
188
+ | System | `systemctl list-units` | `units[]` — name, load, active, sub, description (Linux) | O |
189
+ | System | `journalctl -o short-iso` | `entries[]` — timestamp, hostname, unit, pid, message (Linux) | O |
190
+ | System | `apt list --installed` | `packages[]` — name, version, arch, status | O |
191
+ | System | `brew list --versions` | `packages[]` name, version | O |
192
+ | Package | `npm list`, `pnpm list`, `yarn list` | `dependencies[]` — name, version, depth | O |
193
+ | Package | `cargo tree` | `crates[]` — name, version, path | O |
194
+ | Windows | `dir` | `directory`, `entries[]` — name, type, size, modified time, `free_bytes` | X |
195
+ | Windows | `tasklist` | `processes[]` — name, PID, session, memory. CSV format supported | X |
196
+ | Windows | `ipconfig` | `hostname`, `adapters[]` — IPv4/6, subnet, gateway, DNS, MAC | X |
197
+ | Windows | `systeminfo` | `hostname`, `os_name`, memory, `hotfixes[]`, `network_cards[]` | X |
198
+
199
+ Default (O)=in DEFAULT_CONFIG. X=requires explicit allow in prism.config.json.
200
+
201
+ Commands without a parser return `parsed: null`. `raw` is always present. When a parser throws, `stdout.parse_error` contains `{ reason: "parser_exception", message: string }` so you can distinguish "no parser" from "parser bug".
202
+
203
+ ### Native JSON Passthrough
204
+
205
+ Commands without a dedicated parser still get JSON output passed through when the output is valid JSON (e.g. `kubectl get pods -o json`, `docker inspect`). Parism detects this and puts it in `parsed`. Guard checks and envelope wrapping apply the same. No extra configuration needed.
164
206
 
165
207
  ---
166
208
 
@@ -230,6 +272,8 @@ Parameters:
230
272
  - `cmd` — command name (e.g. `ls`, `git`)
231
273
  - `args` — argument array (default: `[]`)
232
274
  - `cwd` — working directory (default: current directory)
275
+ - `format` — output format (`"json"` default, `"compact"`, `"json-no-raw"`)
276
+ - `includeDiff` — include filesystem diff (default: `false`). `false` skips snapshot for lower latency. Recommended for MCP.
233
277
 
234
278
  ### run_paged
235
279
 
@@ -239,6 +283,7 @@ Parameters:
239
283
  - `cmd`, `args`, `cwd` — same as `run`
240
284
  - `page` — 0-indexed page number (default: `0`)
241
285
  - `page_size` — lines per page (default: `default_page_size`, 100 by default)
286
+ - `includeDiff` — include filesystem diff (default: `false`)
242
287
 
243
288
  Extra fields:
244
289
  - `page_info.total_lines` — total line count
@@ -254,7 +299,7 @@ Place `prism.config.json` in the project root to control Guard behavior.
254
299
  ```json
255
300
  {
256
301
  "guard": {
257
- "allowed_commands": ["ls", "git", "find", "grep", "env", "ps"],
302
+ "allowed_commands": ["ls", "git", "find", "grep", "env", "ps", "kubectl", "docker", "gh", "terraform", "helm", "cargo", "systemctl", "journalctl", "apt", "brew"],
258
303
  "allowed_paths": ["/home/user/projects"],
259
304
  "timeout_ms": 10000,
260
305
  "max_output_bytes": 102400,
package/README.md CHANGED
@@ -44,7 +44,11 @@ Parism을 만들 때 기대한 것은 토큰 절약이었다. 구조화된 데
44
44
 
45
45
  하지만 같은 벤치마크가 다른 사실 하나를 드러냈다. 에이전트가 raw 텍스트를 직접 파싱할 때 오독률이 평균 4.18%, 공백이 섞인 파일명에서는 28.6%에 달했다. 열 번 중 세 번은 틀린다. 틀린 결과로 에이전트가 다음 작업을 수행하고, 그 작업이 또 틀리고, 결국 사람이 개입해서 되돌린다. 재시도 토큰, 디버깅 시간, 롤백 비용. 보이지 않는 곳에서 비용이 불어난다.
46
46
 
47
- Parism의 경제성은 토큰 청구서 위에 있지 않다. 실수와 재작업이 사라지는 자리에 있다. 읽는 비용보다, 잘못 읽어서 치르는 비용이 크다.
47
+ 그러나 같은 벤치마크가 한 가지 더 보여준 것이 있다. "AI한테 설명하는 토큰"의 소멸이다. raw 텍스트를 주면 에이전트에게 "이 출력은 이런 형식이고, 번째 열이 권한이고, 번째가 소유자야"라고 알려줘야 한다. 컨텍스트 프롬프트가 Parism을 쓰면 평균 61% 줄어든다. JSON이 스스로 자기 구조를 설명하기 때문이다. 에이전트는 키를 읽으면 된다.
48
+
49
+ 그리고 역전이 일어나는 지점이 있다. 단발성 조회 — `ls` 한 번 치고 끝나는 작업 — 에서는 Parism이 토큰을 더 먹는다. 그러나 그 결과를 에이전트가 다음 작업에 사용하는 순간, 비용 구조가 뒤집힌다. raw를 잘못 읽은 에이전트가 존재하지 않는 경로에 파일을 쓰고, 그 오류를 디버깅하느라 히스토리를 뒤지고, 재시도하고, 또 틀리는 순환이 시작되면 토큰은 눈덩이가 된다. 구조화된 데이터로 시작한 에이전트는 그 순환에 진입하지 않는다.
50
+
51
+ Parism의 경제성은 청구서 위에 있지 않다. 한 번 더 읽는 비용보다, 한 번 잘못 읽어서 치르는 비용이 압도적으로 크다.
48
52
 
49
53
  ---
50
54
 
@@ -80,12 +84,18 @@ Parism의 경제성은 토큰 청구서 위에 있지 않다. 실수와 재작
80
84
 
81
85
  수치로 말하면: raw 텍스트를 에이전트가 직접 파싱할 때 평균 CFR(Critical Failure Rate)은 4.18%다. 공백이 포함된 파일명이 섞이면 28.6%까지 치솟는다. 1000회 호출 시 286회는 잘못된 파일 목록을 기반으로 에이전트가 다음 작업을 수행한다는 뜻이다. 잘못된 파일을 읽고, 존재하지 않는 경로에 쓰고, 엉뚱한 파일을 삭제한다.
82
86
 
87
+ macOS의 `stat`은 더 극적이다. Linux와 출력 형식이 완전히 다르다. Linux는 `Size: 4096`처럼 레이블이 붙지만, macOS는 레이블 없는 단일 줄이다. Linux 파싱 패턴을 적용하면 정확도는 0%다. Parism은 OS를 감지하고 적합한 파서를 선택한다. 에이전트는 그 차이를 알 필요가 없다.
88
+
83
89
  Parism의 CFR은 0%다. 파서는 deterministic code이기 때문이다. 정규표현식 추론이 아니라 구조적 분해다. 에이전트는 구조화된 데이터만 받는다.
84
90
 
85
91
  ### 재시도가 줄어든다
86
92
 
87
93
  에이전트가 출력을 잘못 해석하면 재질문하거나, 다른 명령으로 다시 확인하거나, 잘못된 정보를 바탕으로 다음 단계를 진행한다. 세 가지 모두 토큰이 든다. 구조화된 출력은 오해의 여지를 줄인다. 파일이 몇 개인지 묻지 않아도 `entries.length`다.
88
94
 
95
+ ### 에이전트가 다른 일을 더 잘하게 된다
96
+
97
+ 텍스트를 파싱하는 것은 추론이다. 추론에는 인지 자원이 소모된다. 에이전트가 출력 형식을 해독하는 데 자원을 쓰면, 실제 작업 — 코드를 분석하고, 설계를 판단하고, 다음 단계를 결정하는 일 — 에 쓸 자원이 줄어든다. 구조화된 데이터를 받으면 파싱이라는 작업 자체가 사라진다. 에이전트는 읽기만 하면 되고, 남은 역량을 본래의 작업에 집중할 수 있다.
98
+
89
99
  ### raw가 항상 보존된다
90
100
 
91
101
  파서가 틀릴 수도 있다. 파서가 없는 명령어일 수도 있다. 그래서 Parism은 `raw`를 항상 유지한다. `parsed`는 보너스다. `raw`는 보험이다. 에이전트는 항상 원본으로 돌아갈 수 있다.
@@ -105,6 +115,10 @@ Parism의 CFR은 0%다. 파서는 deterministic code이기 때문이다. 정규
105
115
 
106
116
  모든 응답에 `duration_ms`가 포함된다. 명령이 느린지 빠른지를 에이전트가 판단하는 데 쓸 수 있다. 디버깅할 때도 유용하다.
107
117
 
118
+ ### diff는 선택적이다
119
+
120
+ `includeDiff: true`일 때만 `diff`에 `created`, `deleted`, `modified`가 채워진다. run/run_paged 기본값은 `includeDiff: false`이므로 스냅샷 비용을 생략하여 MCP 호출 지연을 줄인다.
121
+
108
122
  ---
109
123
 
110
124
  ## 가드 — 에이전트를 신뢰하지 않는 이유
@@ -117,7 +131,7 @@ Parism의 CFR은 0%다. 파서는 deterministic code이기 때문이다. 정규
117
131
 
118
132
  **화이트리스트**: `allowed_commands`에 없는 명령어는 실행되지 않는다. 프로세스를 만들지도 않는다. 설명 없이 거절한다.
119
133
 
120
- **경로 제한**: `allowed_paths`를 설정하면 `cwd`뿐 아니라 경로형 인자(`/`, `./`, `../` 시작)도 검사한다. 허용 경로 밖을 참조하면 차단된다.
134
+ **경로 제한**: `allowed_paths`를 설정하면 `cwd`와 경로 인자를 검사한다. `/`, `./`, `../`로 시작하는 인자와, `cat`, `find`, `ls`, `grep` 등 경로를 받는 명령의 positional 인자(`cat subdir/file`, `find src`)도 허용 경로 밖이면 차단된다. 커널 수준 샌드박스는 아니며, 가드 수준의 방어선이다.
121
135
 
122
136
  **인젝션 패턴 차단**: `;`, `$(`, `` ` ``, `&&`, `||`, `|`, `>`, `>>`, `<`가 인자에 포함되면 실행하지 않는다.
123
137
 
@@ -141,52 +155,54 @@ Parism의 CFR은 0%다. 파서는 deterministic code이기 때문이다. 정규
141
155
 
142
156
  ## 지원 명령어 — 44종 내장 파서
143
157
 
144
- | 카테고리 | 명령어 | 파싱 결과 |
145
- |---|---|---|
146
- | 파일시스템 | `ls` | `entries[]` — 이름, 타입, 권한, 크기, 수정 시각, 소유자 |
147
- | 파일시스템 | `find` | `paths[]` — 경로 목록 |
148
- | 파일시스템 | `stat` | `file`, `size_bytes`, `inode`, `permissions`, `uid`, `gid`, 타임스탬프 |
149
- | 파일시스템 | `du` | `entries[]` — 크기, 경로 |
150
- | 파일시스템 | `df` | `filesystems[]` — 파티션, 사용량, 마운트 위치 |
151
- | 파일시스템 | `tree` | `root`, `tree{}` — 계층 구조 노드, `total_files`, `total_dirs` |
152
- | 프로세스 | `ps` | `processes[]` — PID, CPU%, MEM%, 명령어 |
153
- | 프로세스 | `kill` | raw pass-through |
154
- | 네트워크 | `ping` | `target`, `packets_transmitted`, `packet_loss_percent`, `rtt_*_ms` |
155
- | 네트워크 | `curl -I` | `status_code`, `headers{}` |
156
- | 네트워크 | `netstat` | `connections[]` — proto, local/foreign address, state |
157
- | 네트워크 | `lsof -i` | `entries[]` — PID, 프로세스명, 프로토콜, 로컬/원격 주소, 상태 |
158
- | 네트워크 | `ss` | `entries[]` — 상태, 수신/발신 큐, 로컬/피어 주소, 프로세스 |
159
- | 네트워크 | `dig` | `query`, `answers[]` — 타입, 값, TTL, `query_time_ms` |
160
- | 텍스트 | `grep -n` | `matches[]` — 파일, 라인 번호, 텍스트 |
161
- | 텍스트 | `wc` | `entries[]` — count, 파일명 |
162
- | 텍스트 | `head`, `tail`, `cat` | `lines[]` |
163
- | Git | `git status` | `branch`, `staged[]`, `modified[]`, `untracked[]` |
164
- | Git | `git log --oneline` | `commits[]` — hash, message |
165
- | Git | `git diff` | `files_changed[]` |
166
- | Git | `git branch -vv` | `branches[]` — 이름, current, upstream, ahead/behind |
167
- | DevOps | `kubectl get pods`, `kubectl get events` | `pods[]`/`events[]` — 상태, 재시도, 이벤트 사유/메시지 |
168
- | DevOps | `docker ps`, `docker stats --no-stream` | `containers[]`/`stats[]` — 이미지, 상태, CPU/MEM/IO |
169
- | DevOps | `gh pr list` | `pull_requests[]` — 번호, 제목, 상태, 작성자, 라벨 |
170
- | DevOps | `helm list` | `releases[]` — name, namespace, status, chart, app_version |
171
- | DevOps | `terraform plan` | `summary` — to_add, to_change, to_destroy |
172
- | 환경 | `env` | `vars{}` — 키-값 맵 |
173
- | 환경 | `pwd` | `path` |
174
- | 환경 | `which` | `paths[]` |
175
- | 시스템 | `free` | `rows{}` — mem/swap별 total, used, free, available (bytes) |
176
- | 시스템 | `uname` | `kernel`, `hostname`, `release`, `version`, `arch`, `os` |
177
- | 시스템 | `id` | `uid`, `gid`, `username`, `groups[]` — id, name |
178
- | 시스템 | `systemctl list-units` | `units[]` — name, load, active, sub, description (Linux) |
179
- | 시스템 | `journalctl -o short-iso` | `entries[]` — timestamp, hostname, unit, pid, message (Linux) |
180
- | 시스템 | `apt list --installed` | `packages[]` — name, version, arch, status |
181
- | 시스템 | `brew list --versions` | `packages[]` — name, version |
182
- | 패키지 | `npm list`, `pnpm list`, `yarn list` | `dependencies[]` — name, version, depth |
183
- | 패키지 | `cargo tree` | `crates[]` — name, version, path |
184
- | Windows | `dir` | `directory`, `entries[]` — 이름, 타입, 크기, 수정 시각, `free_bytes` |
185
- | Windows | `tasklist` | `processes[]` — 이름, PID, 세션, 메모리. CSV 형식 지원 |
186
- | Windows | `ipconfig` | `hostname`, `adapters[]` — IPv4/6, 서브넷, 게이트웨이, DNS, MAC |
187
- | Windows | `systeminfo` | `hostname`, `os_name`, 메모리, `hotfixes[]`, `network_cards[]` |
188
-
189
- 파서가 없는 명령어는 `parsed: null`로 반환된다. `raw`는 그대로 있다.
158
+ | 카테고리 | 명령어 | 파싱 결과 | 기본 허용 |
159
+ |---|---|---|---|
160
+ | 파일시스템 | `ls` | `entries[]` — 이름, 타입, 권한, 크기, 수정 시각, 소유자 | O |
161
+ | 파일시스템 | `find` | `paths[]` — 경로 목록 | O |
162
+ | 파일시스템 | `stat` | `file`, `size_bytes`, `inode`, `permissions`, `uid`, `gid`, 타임스탬프 | O |
163
+ | 파일시스템 | `du` | `entries[]` — 크기, 경로 | O |
164
+ | 파일시스템 | `df` | `filesystems[]` — 파티션, 사용량, 마운트 위치 | O |
165
+ | 파일시스템 | `tree` | `root`, `tree{}` — 계층 구조 노드, `total_files`, `total_dirs` | O |
166
+ | 프로세스 | `ps` | `processes[]` — PID, CPU%, MEM%, 명령어 | O |
167
+ | 프로세스 | `kill` | raw pass-through (기본 차단, prism.config.json에서 명시적 허용 시 사용) | X |
168
+ | 네트워크 | `ping` | `target`, `packets_transmitted`, `packet_loss_percent`, `rtt_*_ms` | O |
169
+ | 네트워크 | `curl -I` | `status_code`, `headers{}` | O |
170
+ | 네트워크 | `netstat` | `connections[]` — proto, local/foreign address, state | O |
171
+ | 네트워크 | `lsof -i` | `entries[]` — PID, 프로세스명, 프로토콜, 로컬/원격 주소, 상태 | X |
172
+ | 네트워크 | `ss` | `entries[]` — 상태, 수신/발신 큐, 로컬/피어 주소, 프로세스 | X |
173
+ | 네트워크 | `dig` | `query`, `answers[]` — 타입, 값, TTL, `query_time_ms` | X |
174
+ | 텍스트 | `grep -n` | `matches[]` — 파일, 라인 번호, 텍스트 | O |
175
+ | 텍스트 | `wc` | `entries[]` — count, 파일명 | O |
176
+ | 텍스트 | `head`, `tail`, `cat` | `lines[]` | O |
177
+ | Git | `git status` | `branch`, `staged[]`, `modified[]`, `untracked[]` | O |
178
+ | Git | `git log --oneline` | `commits[]` — hash, message | O |
179
+ | Git | `git diff` | `files_changed[]` | O |
180
+ | Git | `git branch -vv` | `branches[]` — 이름, current, upstream, ahead/behind | O |
181
+ | DevOps | `kubectl get pods`, `kubectl get events` | `pods[]`/`events[]` — 상태, 재시도, 이벤트 사유/메시지 | O |
182
+ | DevOps | `docker ps`, `docker stats --no-stream` | `containers[]`/`stats[]` — 이미지, 상태, CPU/MEM/IO | O |
183
+ | DevOps | `gh pr list` | `pull_requests[]` — 번호, 제목, 상태, 작성자, 라벨 | O |
184
+ | DevOps | `helm list` | `releases[]` — name, namespace, status, chart, app_version | O |
185
+ | DevOps | `terraform plan` | `summary` — to_add, to_change, to_destroy | O |
186
+ | 환경 | `env` | `vars{}` — 키-값 맵 | O |
187
+ | 환경 | `pwd` | `path` | O |
188
+ | 환경 | `which` | `paths[]` | O |
189
+ | 시스템 | `free` | `rows{}` — mem/swap별 total, used, free, available (bytes) | X |
190
+ | 시스템 | `uname` | `kernel`, `hostname`, `release`, `version`, `arch`, `os` | O |
191
+ | 시스템 | `id` | `uid`, `gid`, `username`, `groups[]` — id, name | X |
192
+ | 시스템 | `systemctl list-units` | `units[]` — name, load, active, sub, description (Linux) | O |
193
+ | 시스템 | `journalctl -o short-iso` | `entries[]` — timestamp, hostname, unit, pid, message (Linux) | O |
194
+ | 시스템 | `apt list --installed` | `packages[]` — name, version, arch, status | O |
195
+ | 시스템 | `brew list --versions` | `packages[]` — name, version | O |
196
+ | 패키지 | `npm list`, `pnpm list`, `yarn list` | `dependencies[]` — name, version, depth | O |
197
+ | 패키지 | `cargo tree` | `crates[]` — name, version, path | O |
198
+ | Windows | `dir` | `directory`, `entries[]` — 이름, 타입, 크기, 수정 시각, `free_bytes` | X |
199
+ | Windows | `tasklist` | `processes[]` — 이름, PID, 세션, 메모리. CSV 형식 지원 | X |
200
+ | Windows | `ipconfig` | `hostname`, `adapters[]` — IPv4/6, 서브넷, 게이트웨이, DNS, MAC | X |
201
+ | Windows | `systeminfo` | `hostname`, `os_name`, 메모리, `hotfixes[]`, `network_cards[]` | X |
202
+
203
+ 기본 허용(O)=DEFAULT_CONFIG에 포함. X=prism.config.json에서 명시적 허용 필요.
204
+
205
+ 파서가 없는 명령어는 `parsed: null`로 반환된다. `raw`는 그대로 있다. 파서가 예외를 던지면 `stdout.parse_error`에 `{ reason: "parser_exception", message: string }`가 포함되어 "파서 없음"과 "파서 버그"를 구분할 수 있다.
190
206
 
191
207
  ### 네이티브 JSON 패스스루
192
208
 
@@ -279,7 +295,8 @@ Claude Code (Linux):
279
295
  - `cmd` — 명령어 이름 (예: `ls`, `git`)
280
296
  - `args` — 인자 배열 (기본값: `[]`)
281
297
  - `cwd` — 작업 디렉토리 (기본값: 현재 디렉토리)
282
- - `format` — 출력 형식 (`"json"` 기본값, `"compact"` 가능). compact는 리스트형 출력을 schema+rows 컬럼 기반으로 압축하여 토큰 비용을 절감한다.
298
+ - `format` — 출력 형식 (`"json"` 기본값, `"compact"`, `"json-no-raw"`). compact는 리스트형 출력을 schema+rows 컬럼 기반으로 압축하여 토큰 비용을 절감한다.
299
+ - `includeDiff` — 파일시스템 diff 포함 여부 (기본값: `false`). `false`면 스냅샷 생략으로 지연 감소. MCP 고빈도 호출 시 권장.
283
300
 
284
301
  compact 예시:
285
302
 
@@ -298,6 +315,7 @@ compact 예시:
298
315
  - `cmd`, `args`, `cwd` — `run`과 동일
299
316
  - `page` — 0-indexed 페이지 번호 (기본값: `0`)
300
317
  - `page_size` — 페이지당 줄 수 (기본값: `default_page_size` 설정값, 기본 100)
318
+ - `includeDiff` — 파일시스템 diff 포함 여부 (기본값: `false`). `false`면 스냅샷 생략으로 지연 감소.
301
319
 
302
320
  응답 추가 필드:
303
321
  - `page_info.total_lines` — 전체 줄 수
@@ -4,6 +4,8 @@ import type { ResponseEnvelope } from "../types/envelope.js";
4
4
  * - 셸을 거치지 않으므로 셸 확장/인젝션 위험 없음
5
5
  * - secretPatterns에 해당하는 환경 변수는 자식 프로세스에 전달하지 않음
6
6
  * - 실행 실패(명령 없음 포함)는 예외 대신 ok=false 봉투로 반환
7
+ * - includeDiff=false면 파일시스템 스냅샷을 생략하여 지연을 줄인다 (MCP 고빈도 호출 권장)
7
8
  */
8
- export declare function execute(cmd: string, args: string[], cwd: string, secretPatterns?: string[], timeoutMs?: number, maxOutputBytes?: number): Promise<ResponseEnvelope>;
9
+ export declare function execute(cmd: string, args: string[], cwd: string, secretPatterns?: string[], timeoutMs?: number, maxOutputBytes?: number, // 0 = 무제한
10
+ includeDiff?: boolean): Promise<ResponseEnvelope>;
9
11
  //# sourceMappingURL=executor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAsB7D;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAc,MAAM,EACvB,IAAI,EAAa,MAAM,EAAE,EACzB,GAAG,EAAc,MAAM,EACvB,cAAc,GAAG,MAAM,EAAO,EAC9B,SAAS,GAAQ,MAAgB,EACjC,cAAc,GAAG,MAAY,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA6D3B"}
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAuB7D;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAc,MAAM,EACvB,IAAI,EAAa,MAAM,EAAE,EACzB,GAAG,EAAc,MAAM,EACvB,cAAc,GAAG,MAAM,EAAO,EAC9B,SAAS,GAAQ,MAAgB,EACjC,cAAc,GAAG,MAAY,EAAO,UAAU;AAC9C,WAAW,GAAM,OAAe,GAC/B,OAAO,CAAC,gBAAgB,CAAC,CA6D3B"}
@@ -23,10 +23,12 @@ function buildSanitizedEnv(secretPatterns) {
23
23
  * - 셸을 거치지 않으므로 셸 확장/인젝션 위험 없음
24
24
  * - secretPatterns에 해당하는 환경 변수는 자식 프로세스에 전달하지 않음
25
25
  * - 실행 실패(명령 없음 포함)는 예외 대신 ok=false 봉투로 반환
26
+ * - includeDiff=false면 파일시스템 스냅샷을 생략하여 지연을 줄인다 (MCP 고빈도 호출 권장)
26
27
  */
27
- export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 10000, maxOutputBytes = 0) {
28
+ export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 10000, maxOutputBytes = 0, // 0 = 무제한
29
+ includeDiff = true) {
28
30
  const start = Date.now();
29
- const before = await takeSnapshot(cwd);
31
+ const before = includeDiff ? await takeSnapshot(cwd) : null;
30
32
  try {
31
33
  const { stdout, stderr } = await execFileAsync(cmd, args, {
32
34
  cwd,
@@ -34,7 +36,7 @@ export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 1
34
36
  maxBuffer: 10 * 1024 * 1024, // 10 MB
35
37
  env: { ...buildSanitizedEnv(secretPatterns), LC_ALL: "C", LANG: "C" },
36
38
  });
37
- const after = await takeSnapshot(cwd);
39
+ const after = includeDiff ? await takeSnapshot(cwd) : null;
38
40
  // stdout 크기 제한: 초과 시 마지막 완전한 줄까지 잘라내고 truncated=true 표시
39
41
  let outRaw = stdout;
40
42
  let truncated;
@@ -55,14 +57,14 @@ export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 1
55
57
  duration_ms: Date.now() - start,
56
58
  stdout: { raw: outRaw, parsed: null },
57
59
  stderr: { raw: stderr, parsed: null },
58
- diff: computeDiff(before, after),
60
+ diff: before && after ? computeDiff(before, after) : null,
59
61
  truncated,
60
62
  };
61
63
  }
62
64
  catch (err) {
63
65
  const e = err;
64
66
  const exitCode = typeof e.code === "number" ? e.code : 1;
65
- const after = await takeSnapshot(cwd);
67
+ const after = includeDiff ? await takeSnapshot(cwd) : null;
66
68
  return {
67
69
  ok: false,
68
70
  exitCode,
@@ -72,7 +74,7 @@ export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 1
72
74
  duration_ms: Date.now() - start,
73
75
  stdout: { raw: e.stdout ?? "", parsed: null },
74
76
  stderr: { raw: e.stderr ?? e.message, parsed: null },
75
- diff: computeDiff(before, after),
77
+ diff: before && after ? computeDiff(before, after) : null,
76
78
  };
77
79
  }
78
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/engine/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;aAGjB,MAAM,EAClB,qBAAqB,GACrB,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB;gBALrB,OAAO,EAAE,MAAM,EACC,MAAM,EAClB,qBAAqB,GACrB,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB;CAKxB;AAgCD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAK,MAAM,EACd,IAAI,EAAI,MAAM,EAAE,EAChB,GAAG,EAAK,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,IAAI,CAyDN"}
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/engine/guard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;aAGjB,MAAM,EAClB,qBAAqB,GACrB,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB;gBALrB,OAAO,EAAE,MAAM,EACC,MAAM,EAClB,qBAAqB,GACrB,kBAAkB,GAClB,mBAAmB,GACnB,iBAAiB;CAKxB;AAiDD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAK,MAAM,EACd,IAAI,EAAI,MAAM,EAAE,EAChB,GAAG,EAAK,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,IAAI,CA4DN"}
@@ -28,13 +28,29 @@ function isAllowedPath(targetPath, allowedPaths) {
28
28
  });
29
29
  }
30
30
  /**
31
- * 명령 인자 중 실제 파일시스템 경로로 해석 가능한 값만 추출한다.
31
+ * 명령 인자 중 `/`, `./`, `../`로 시작하는 경로형 인자만 추출한다.
32
32
  */
33
33
  function getPathLikeArgs(args) {
34
34
  return args.filter((arg) => arg.startsWith("/") ||
35
35
  arg.startsWith("./") ||
36
36
  arg.startsWith("../"));
37
37
  }
38
+ /**
39
+ * 경로 인자를 받는 명령. 플래그가 아닌(positional) 인자를 경로 후보로 검사한다.
40
+ * find src, cat subdir/file, ls -la dir 등 상대경로(슬래시 없음)도 검사 대상.
41
+ */
42
+ const PATH_TAKING_COMMANDS = new Set([
43
+ "cat", "find", "stat", "du", "tree", "head", "tail", "ls", "grep", "wc",
44
+ ]);
45
+ /**
46
+ * 명령별로 경로로 해석되는 인자들을 수집한다.
47
+ * PATH_TAKING_COMMANDS에 있는 명령은 플래그로 시작하지 않는 인자를 경로 후보로 본다.
48
+ */
49
+ function getPathArgsFromCommand(cmd, args) {
50
+ if (!PATH_TAKING_COMMANDS.has(cmd))
51
+ return [];
52
+ return args.filter((arg) => arg !== "-" && !arg.startsWith("-"));
53
+ }
38
54
  /**
39
55
  * 명령 실행 허용 여부를 검사한다. 차단 조건 충족 시 GuardError를 던진다.
40
56
  *
@@ -72,7 +88,9 @@ export function checkGuard(cmd, args, cwd, config) {
72
88
  "Add guard.allowed_paths in prism.config.json or set [] to disable.", "path_not_allowed");
73
89
  }
74
90
  const pathLikeArgs = getPathLikeArgs(args);
75
- for (const arg of pathLikeArgs) {
91
+ const pathArgsByCmd = getPathArgsFromCommand(cmd, args);
92
+ const allPathArgs = [...new Set([...pathLikeArgs, ...pathArgsByCmd])];
93
+ for (const arg of allPathArgs) {
76
94
  const resolvedArgPath = path.resolve(cwd, arg);
77
95
  if (!isAllowedPath(resolvedArgPath, guard.allowed_paths)) {
78
96
  throw new GuardError(`Path argument '${arg}' resolves outside allowed paths. ` +
@@ -1 +1 @@
1
- {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/engine/guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/engine/guard.ts"],"names":[],"mappings":"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"}
@@ -17,17 +17,27 @@ export interface ParseContext {
17
17
  * 파서 함수 시그니처.
18
18
  */
19
19
  export type ParserFn = (cmd: string, args: string[], raw: string, ctx?: ParseContext) => unknown;
20
+ /**
21
+ * 파서 실행 결과. parsed가 null일 때 parse_error가 있으면 파서 예외, 없으면 파서 없음.
22
+ */
23
+ export interface ParseResult {
24
+ parsed: unknown | null;
25
+ parse_error?: {
26
+ reason: "parser_exception";
27
+ message: string;
28
+ };
29
+ }
20
30
  /**
21
31
  * 명령어 → 파서 함수의 매핑 테이블.
22
- * 파서가 없거나 실패하면 null 반환한다 (graceful degradation).
32
+ * 파서가 없으면 parsed=null. 파서가 예외를 던지면 parsed=null, parse_error 설정.
23
33
  */
24
34
  export declare class ParserRegistry {
25
35
  private readonly parsers;
26
36
  register(cmd: string, fn: ParserFn): void;
27
37
  /**
28
38
  * cmd에 등록된 파서를 찾아 실행한다.
29
- * 파서 없음 또는 예외 → null 반환.
39
+ * 파서 없음 { parsed: null }. 파서 예외 → { parsed: null, parse_error }.
30
40
  */
31
- parse(cmd: string, args: string[], raw: string, ctx?: ParseContext): unknown | null;
41
+ parse(cmd: string, args: string[], raw: string, ctx?: ParseContext): ParseResult;
32
42
  }
33
43
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAI,YAAY,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC;AAEjG;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IAEvD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI;IAIzC;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,OAAO,GAAG,IAAI;CAUpF"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAI,YAAY,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC;AAEjG;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAO,OAAO,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE;QAAE,MAAM,EAAE,kBAAkB,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IAEvD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI;IAIzC;;;OAGG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAAG,WAAW;CAYjF"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 명령어 → 파서 함수의 매핑 테이블.
3
- * 파서가 없거나 실패하면 null 반환한다 (graceful degradation).
3
+ * 파서가 없으면 parsed=null. 파서가 예외를 던지면 parsed=null, parse_error 설정.
4
4
  */
5
5
  export class ParserRegistry {
6
6
  parsers = new Map();
@@ -9,17 +9,19 @@ export class ParserRegistry {
9
9
  }
10
10
  /**
11
11
  * cmd에 등록된 파서를 찾아 실행한다.
12
- * 파서 없음 또는 예외 → null 반환.
12
+ * 파서 없음 { parsed: null }. 파서 예외 → { parsed: null, parse_error }.
13
13
  */
14
14
  parse(cmd, args, raw, ctx) {
15
15
  const fn = this.parsers.get(cmd);
16
16
  if (!fn)
17
- return null;
17
+ return { parsed: null };
18
18
  try {
19
- return fn(cmd, args, raw, ctx);
19
+ const parsed = fn(cmd, args, raw, ctx);
20
+ return { parsed: parsed ?? null };
20
21
  }
21
- catch {
22
- return null;
22
+ catch (err) {
23
+ const message = err instanceof Error ? err.message : String(err);
24
+ return { parsed: null, parse_error: { reason: "parser_exception", message } };
23
25
  }
24
26
  }
25
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAsBA;;;GAGG;AACH,MAAM,OAAO,cAAc;IACR,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEvD,QAAQ,CAAC,GAAW,EAAE,EAAY;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;QAChE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAErB,IAAI,CAAC;YACH,OAAO,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AA8BA;;;GAGG;AACH,MAAM,OAAO,cAAc;IACR,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAEvD,QAAQ,CAAC,GAAW,EAAE,EAAY;QAChC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;QAChE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAEjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;YACvC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,IAAI,EAAE,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAAC;QAChF,CAAC;IACH,CAAC;CACF"}
package/dist/server.d.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import type { PrismConfig } from "./config/loader.js";
3
3
  import type { OutputFormat } from "./parsers/registry.js";
4
- export declare const PACKAGE_VERSION = "0.3.0";
4
+ export declare const PACKAGE_VERSION = "0.4.0";
5
5
  /**
6
6
  * Guard 검사 → 실행 → JSON 직렬화까지의 파이프라인.
7
7
  * MCP 서버와 테스트 코드가 공통으로 사용한다.
8
8
  */
9
- export declare function buildRunResult(cmd: string, args: string[], cwd: string, config: PrismConfig, format?: OutputFormat): Promise<string>;
9
+ export declare function buildRunResult(cmd: string, args: string[], cwd: string, config: PrismConfig, format?: OutputFormat, includeDiff?: boolean): Promise<string>;
10
10
  /**
11
11
  * Guard 검사 → 실행 → 페이지 분할 → JSON 직렬화.
12
12
  * parsed는 항상 null (부분 출력은 구조화 파싱 불가).
13
13
  */
14
- export declare function buildPagedResult(cmd: string, args: string[], cwd: string, page: number, pageSize: number, config: PrismConfig): Promise<string>;
14
+ export declare function buildPagedResult(cmd: string, args: string[], cwd: string, page: number, pageSize: number, config: PrismConfig, includeDiff?: boolean): Promise<string>;
15
15
  /**
16
16
  * MCP 서버를 생성하고 `run` 도구를 등록한다.
17
17
  */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAY,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAW,uBAAuB,CAAC;AAI/D,eAAO,MAAM,eAAe,UAAU,CAAC;AAsBvC;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAK,MAAM,EACd,IAAI,EAAI,MAAM,EAAE,EAChB,GAAG,EAAK,MAAM,EACd,MAAM,EAAE,WAAW,EACnB,MAAM,GAAE,YAAqB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAuBjB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAO,MAAM,EAChB,IAAI,EAAM,MAAM,EAAE,EAClB,GAAG,EAAO,MAAM,EAChB,IAAI,EAAM,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAI,WAAW,GACpB,OAAO,CAAC,MAAM,CAAC,CAuBjB;AA2BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CA8C3D"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAY,oBAAoB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAW,uBAAuB,CAAC;AAI/D,eAAO,MAAM,eAAe,UAAU,CAAC;AAsBvC;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAU,MAAM,EACnB,IAAI,EAAS,MAAM,EAAE,EACrB,GAAG,EAAU,MAAM,EACnB,MAAM,EAAO,WAAW,EACxB,MAAM,GAAO,YAAqB,EAClC,WAAW,GAAE,OAAkB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAyBjB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAU,MAAM,EACnB,IAAI,EAAS,MAAM,EAAE,EACrB,GAAG,EAAU,MAAM,EACnB,IAAI,EAAS,MAAM,EACnB,QAAQ,EAAK,MAAM,EACnB,MAAM,EAAO,WAAW,EACxB,WAAW,GAAE,OAAc,GAC1B,OAAO,CAAC,MAAM,CAAC,CAwBjB;AA2BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAkD3D"}
package/dist/server.js CHANGED
@@ -6,7 +6,7 @@ import { defaultRegistry } from "./parsers/index.js";
6
6
  import { paginateLines } from "./engine/paginator.js";
7
7
  import { toCompact } from "./parsers/compact.js";
8
8
  import { tryParseNativeJson } from "./parsers/json-passthrough.js";
9
- export const PACKAGE_VERSION = "0.3.0";
9
+ export const PACKAGE_VERSION = "0.4.0";
10
10
  /**
11
11
  * Guard 차단 시 반환하는 에러 봉투를 생성한다.
12
12
  */
@@ -28,7 +28,7 @@ function buildGuardErrorEnvelope(cmd, args, cwd, err) {
28
28
  * Guard 검사 → 실행 → JSON 직렬화까지의 파이프라인.
29
29
  * MCP 서버와 테스트 코드가 공통으로 사용한다.
30
30
  */
31
- export async function buildRunResult(cmd, args, cwd, config, format = "json") {
31
+ export async function buildRunResult(cmd, args, cwd, config, format = "json", includeDiff = true) {
32
32
  try {
33
33
  checkGuard(cmd, args, cwd, config);
34
34
  }
@@ -37,15 +37,16 @@ export async function buildRunResult(cmd, args, cwd, config, format = "json") {
37
37
  return buildGuardErrorEnvelope(cmd, args, cwd, err);
38
38
  throw err;
39
39
  }
40
- const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns, config.guard.timeout_ms, config.guard.max_output_bytes);
40
+ const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns, config.guard.timeout_ms, config.guard.max_output_bytes, includeDiff);
41
41
  const parseFormat = format === "json-no-raw" ? "json" : format;
42
- let parsed = defaultRegistry.parse(cmd, args, envelope.stdout.raw, { maxItems: config.guard.max_items, format: parseFormat });
42
+ const parseResult = defaultRegistry.parse(cmd, args, envelope.stdout.raw, { maxItems: config.guard.max_items, format: parseFormat });
43
+ let parsed = parseResult.parsed;
43
44
  if (parsed == null)
44
45
  parsed = tryParseNativeJson(envelope.stdout.raw);
45
46
  const final = parseFormat === "compact" ? toCompact(parsed) : parsed;
46
47
  const stdout = format === "json-no-raw"
47
- ? { raw: "", parsed: final }
48
- : { ...envelope.stdout, parsed: final };
48
+ ? { raw: "", parsed: final, ...(parseResult.parse_error && { parse_error: parseResult.parse_error }) }
49
+ : { ...envelope.stdout, parsed: final, ...(parseResult.parse_error && { parse_error: parseResult.parse_error }) };
49
50
  const enriched = { ...envelope, stdout };
50
51
  return JSON.stringify(enriched, null, 2);
51
52
  }
@@ -53,7 +54,7 @@ export async function buildRunResult(cmd, args, cwd, config, format = "json") {
53
54
  * Guard 검사 → 실행 → 페이지 분할 → JSON 직렬화.
54
55
  * parsed는 항상 null (부분 출력은 구조화 파싱 불가).
55
56
  */
56
- export async function buildPagedResult(cmd, args, cwd, page, pageSize, config) {
57
+ export async function buildPagedResult(cmd, args, cwd, page, pageSize, config, includeDiff = true) {
57
58
  try {
58
59
  checkGuard(cmd, args, cwd, config);
59
60
  }
@@ -63,7 +64,7 @@ export async function buildPagedResult(cmd, args, cwd, page, pageSize, config) {
63
64
  throw err;
64
65
  }
65
66
  // 전체 stdout이 필요하므로 max_output_bytes 비활성 (0)
66
- const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns, config.guard.timeout_ms, 0);
67
+ const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns, config.guard.timeout_ms, 0, includeDiff);
67
68
  const { lines, page_info } = paginateLines(envelope.stdout.raw, page, pageSize);
68
69
  const pagedRaw = lines.join("\n") + (lines.length > 0 ? "\n" : "");
69
70
  const enriched = {
@@ -110,8 +111,10 @@ export function createServer(config) {
110
111
  cwd: z.string().default(process.cwd()).describe("Working directory"),
111
112
  format: z.enum(["json", "compact", "json-no-raw"]).default("json")
112
113
  .describe("Output format. 'compact'=columnar. 'json-no-raw'=omit raw for token savings."),
113
- }, async ({ cmd, args, cwd, format }) => {
114
- const result = await buildRunResult(cmd, args, cwd, config, format);
114
+ includeDiff: z.boolean().default(false)
115
+ .describe("Include filesystem diff (created/deleted/modified). false=skip snapshot, lower latency."),
116
+ }, async ({ cmd, args, cwd, format, includeDiff }) => {
117
+ const result = await buildRunResult(cmd, args, cwd, config, format, includeDiff);
115
118
  return {
116
119
  content: [{ type: "text", text: result }],
117
120
  };
@@ -125,8 +128,10 @@ export function createServer(config) {
125
128
  page: z.number().int().min(0).default(0).describe("Page index (0-based)"),
126
129
  page_size: z.number().int().min(1).default(config.guard.default_page_size)
127
130
  .describe("Lines per page"),
128
- }, async ({ cmd, args, cwd, page, page_size }) => {
129
- const result = await buildPagedResult(cmd, args, cwd, page, page_size, config);
131
+ includeDiff: z.boolean().default(false)
132
+ .describe("Include filesystem diff. false=skip snapshot, lower latency."),
133
+ }, async ({ cmd, args, cwd, page, page_size, includeDiff }) => {
134
+ const result = await buildPagedResult(cmd, args, cwd, page, page_size, config, includeDiff);
130
135
  return { content: [{ type: "text", text: result }] };
131
136
  });
132
137
  return server;
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,18 @@
1
+ /**
2
+ * 파서 예외 정보. 파서가 예외를 던졌을 때만 존재. "파서 없음"과 "파서 버그"를 구분한다.
3
+ */
4
+ export interface ParseErrorField {
5
+ reason: "parser_exception";
6
+ message: string;
7
+ }
1
8
  /**
2
9
  * 명령 stdout/stderr 필드. raw는 항상 보존되고, parsed는 파서 존재 시 채워진다.
10
+ * parse_error는 파서가 예외를 던졌을 때만 존재한다 (파서 없음과 구분).
3
11
  */
4
12
  export interface OutputField {
5
13
  raw: string;
6
14
  parsed: unknown | null;
15
+ parse_error?: ParseErrorField;
7
16
  }
8
17
  export type StdoutField = OutputField;
9
18
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/types/envelope.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAK,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC;CACxB;AAGD,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAG,MAAM,EAAE,CAAC;IACnB,OAAO,EAAG,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAS,MAAM,CAAC;IACpB,SAAS,EAAI,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAK,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAW,OAAO,CAAC;IACrB,QAAQ,EAAK,MAAM,CAAC;IACpB,GAAG,EAAU,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,EAAE,CAAC;IACtB,GAAG,EAAU,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAO,WAAW,CAAC;IACzB,MAAM,EAAO,WAAW,CAAC;IACzB,IAAI,EAAS,SAAS,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAG,OAAO,CAAC;IACrB,SAAS,CAAC,EAAG,QAAQ,CAAC;CACvB"}
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/types/envelope.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAG,kBAAkB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAU,MAAM,CAAC;IACpB,MAAM,EAAO,OAAO,GAAG,IAAI,CAAC;IAC5B,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAGD,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAG,MAAM,EAAE,CAAC;IACnB,OAAO,EAAG,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAS,MAAM,CAAC;IACpB,SAAS,EAAI,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAK,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAW,OAAO,CAAC;IACrB,QAAQ,EAAK,MAAM,CAAC;IACpB,GAAG,EAAU,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,EAAE,CAAC;IACtB,GAAG,EAAU,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAO,WAAW,CAAC;IACzB,MAAM,EAAO,WAAW,CAAC;IACzB,IAAI,EAAS,SAAS,GAAG,IAAI,CAAC;IAC9B,SAAS,CAAC,EAAG,OAAO,CAAC;IACrB,SAAS,CAAC,EAAG,QAAQ,CAAC;CACvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerdvana/parism",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Structured shell output wrapper for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/prism.config.json CHANGED
@@ -15,12 +15,15 @@
15
15
  "terraform", "helm", "cargo",
16
16
  "systemctl", "journalctl", "apt", "brew"
17
17
  ],
18
- "allowed_paths": [],
18
+ "allowed_paths": ["./"],
19
19
  "timeout_ms": 10000,
20
20
  "block_patterns": [";", "$(", "`", "&&", "||", ">", ">>", "<", "|"],
21
21
  "command_arg_restrictions": {
22
22
  "node": { "blocked_flags": ["-e", "--eval", "-r", "--require", "-p", "--print", "--input-type"] },
23
- "npx": { "blocked_flags": ["--yes", "-y"] }
23
+ "npx": { "blocked_flags": ["--yes", "-y"] },
24
+ "curl": {
25
+ "blocked_flags": ["-d", "--data", "-F", "--upload-file", "-T", "-K", "--config", "-o", "--output", "-O"]
26
+ }
24
27
  },
25
28
  "env_secret_patterns": [
26
29
  "TOKEN", "SECRET", "AUTHZ", "PASSWORD", "PASSWD", "CREDENTIAL"