@nerdvana/parism 0.1.2 → 0.1.4

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.
Files changed (45) hide show
  1. package/README.en.md +256 -0
  2. package/README.md +52 -4
  3. package/dist/config/loader.d.ts +3 -0
  4. package/dist/config/loader.d.ts.map +1 -1
  5. package/dist/config/loader.js +4 -1
  6. package/dist/config/loader.js.map +1 -1
  7. package/dist/engine/executor.d.ts +1 -1
  8. package/dist/engine/executor.d.ts.map +1 -1
  9. package/dist/engine/executor.js +21 -4
  10. package/dist/engine/executor.js.map +1 -1
  11. package/dist/engine/paginator.d.ts +11 -0
  12. package/dist/engine/paginator.d.ts.map +1 -0
  13. package/dist/engine/paginator.js +25 -0
  14. package/dist/engine/paginator.js.map +1 -0
  15. package/dist/engine/state-tracker.d.ts +14 -0
  16. package/dist/engine/state-tracker.d.ts.map +1 -0
  17. package/dist/engine/state-tracker.js +53 -0
  18. package/dist/engine/state-tracker.js.map +1 -0
  19. package/dist/parsers/fs/find.d.ts +8 -1
  20. package/dist/parsers/fs/find.d.ts.map +1 -1
  21. package/dist/parsers/fs/find.js +8 -1
  22. package/dist/parsers/fs/find.js.map +1 -1
  23. package/dist/parsers/fs/ls.d.ts +8 -1
  24. package/dist/parsers/fs/ls.d.ts.map +1 -1
  25. package/dist/parsers/fs/ls.js +8 -1
  26. package/dist/parsers/fs/ls.js.map +1 -1
  27. package/dist/parsers/process/ps.d.ts +8 -1
  28. package/dist/parsers/process/ps.d.ts.map +1 -1
  29. package/dist/parsers/process/ps.js +8 -1
  30. package/dist/parsers/process/ps.js.map +1 -1
  31. package/dist/parsers/registry.d.ts +9 -2
  32. package/dist/parsers/registry.d.ts.map +1 -1
  33. package/dist/parsers/registry.js +2 -2
  34. package/dist/parsers/registry.js.map +1 -1
  35. package/dist/parsers/text/grep.d.ts +8 -1
  36. package/dist/parsers/text/grep.d.ts.map +1 -1
  37. package/dist/parsers/text/grep.js +16 -3
  38. package/dist/parsers/text/grep.js.map +1 -1
  39. package/dist/server.d.ts +5 -0
  40. package/dist/server.d.ts.map +1 -1
  41. package/dist/server.js +54 -3
  42. package/dist/server.js.map +1 -1
  43. package/dist/types/envelope.d.ts +11 -0
  44. package/dist/types/envelope.d.ts.map +1 -1
  45. package/package.json +8 -3
package/README.en.md ADDED
@@ -0,0 +1,256 @@
1
+ # Parism
2
+
3
+ > Refract the Shell. Every command, structured.
4
+
5
+ <p align="right"><a href="README.md">한국어</a> | <a href="README.en.md">English</a></p>
6
+
7
+ ---
8
+
9
+ ## The Shell Was Not Designed for You
10
+
11
+ In 1969, when Ken Thompson built Unix, he assumed the output would be read by a human — specifically, a creature with eyes sitting in front of a terminal.
12
+
13
+ Half a century later, that assumption no longer holds.
14
+
15
+ An AI agent runs `ls -la` and receives its output. Then the real work begins: split on whitespace, figure out that the first column is permissions, the third is the owner, infer where the filename starts — burning tokens to reason through what a human eye processes in 0.1 seconds.
16
+
17
+ This is not translation. It is decrypting a message that was never encrypted.
18
+
19
+ ---
20
+
21
+ ## Why This Is a Problem
22
+
23
+ Three translations happen.
24
+
25
+ First: the kernel manages filesystem metadata as `stat` structures — `inode`, `mode`, `uid`, `gid`, `size`, `mtime`. Already perfectly structured data.
26
+
27
+ Second: `ls` flattens that structure into human-readable text. `drwxr-xr-x 2 user group 4096 Mar 06 09:23 src`. Structure collapses into string.
28
+
29
+ Third: the agent tries to reconstruct that structure from the text. Rebuilding what was just torn down.
30
+
31
+ Parism intervenes between the second and third step. It recovers what was discarded.
32
+
33
+ This has a cost. Running `ls` once looks simple, but the agent may spend dozens of inference steps parsing the output — and often gets it wrong. Edge cases, unexpected whitespace, OS-specific formatting quirks. Wrong means retry. Retry means more tokens.
34
+
35
+ ---
36
+
37
+ ## What Parism Does
38
+
39
+ A prism does not destroy light. It decomposes it.
40
+
41
+ ```
42
+ "drwxr-xr-x 2 user group 4096 Mar 06 09:23 src"
43
+
44
+ ↓ Parism
45
+
46
+ {
47
+ "type": "directory",
48
+ "name": "src",
49
+ "permissions": { "owner": "rwx", "group": "r-x", "other": "r-x" },
50
+ "size_bytes": 4096,
51
+ "owner": "user",
52
+ "group": "group",
53
+ "modified_at": "2026-03-06T09:23:00"
54
+ }
55
+ ```
56
+
57
+ The information does not change. The shape does. The agent no longer parses. It reads.
58
+
59
+ ---
60
+
61
+ ## Why This Is Better
62
+
63
+ ### No More Parsing Errors
64
+
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.
66
+
67
+ ### Fewer Retries
68
+
69
+ 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
+
71
+ ### `raw` Is Always Preserved
72
+
73
+ 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.
74
+
75
+ ```json
76
+ "stdout": {
77
+ "raw": "drwxr-xr-x ...",
78
+ "parsed": { "entries": [ ... ] }
79
+ }
80
+ ```
81
+
82
+ ### Consistent Response Structure
83
+
84
+ Whether success or failure, `ok` and `exitCode` are always in the same place. The agent's branching logic becomes simple. Not "parse stdout to check for errors" — just `if (!result.ok)`.
85
+
86
+ ### Execution Time Is Recorded
87
+
88
+ Every response includes `duration_ms`. The agent can judge whether a command is slow or fast. Useful for debugging too.
89
+
90
+ ---
91
+
92
+ ## Guard — Why Not to Trust the Agent
93
+
94
+ `rm -rf /` can be written in three characters.
95
+
96
+ Agents make mistakes. They lose context, confuse paths, generate unintended commands. Guard is not about distrust — it is about designing so that agent mistakes do not become catastrophes.
97
+
98
+ There are four layers of defense.
99
+
100
+ **Command Whitelist**: Commands not in `allowed_commands` are never executed. No process is created. Rejected silently.
101
+
102
+ **Path Restriction**: When `allowed_paths` is set, commands referencing paths outside it are blocked. The agent cannot touch `/etc`.
103
+
104
+ **Injection Pattern Blocking**: If `;`, `$(`, `` ` ``, `&&`, `||`, or `|` appear in any argument, the command is not executed. Regardless of agent intent.
105
+
106
+ **Per-Command Argument Restrictions** *(v0.1.2)*: Specific flags can be blocked per command. `node -e` and `node --eval` allow arbitrary code execution — they are blocked by default. `npx --yes` silently installs packages from the internet — also blocked.
107
+
108
+ A blocked command returns this:
109
+
110
+ ```json
111
+ {
112
+ "ok": false,
113
+ "guard_error": {
114
+ "reason": "command_not_allowed",
115
+ "message": "Command 'rm' is not in the allowed list"
116
+ }
117
+ }
118
+ ```
119
+
120
+ The agent receives the block reason in the same envelope structure as any other result. No exceptions thrown. No pipeline broken.
121
+
122
+ ---
123
+
124
+ ## Supported Commands — 31 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
+ | Env | `env` | `vars{}` — key-value map (secrets filtered) |
150
+ | Env | `pwd` | `path` |
151
+ | Env | `which` | `paths[]` |
152
+ | System | `free` | `mem`, `swap` — total, used, free, available in bytes |
153
+ | System | `uname` | `kernel_name`, `hostname`, `kernel_release`, `machine`, `os` |
154
+ | System | `id` | `uid`, `gid`, `user`, `group`, `groups[]` — id, name |
155
+ | Windows | `dir` | `directory`, `entries[]` — name, type, size, modified time, `free_bytes` |
156
+ | Windows | `tasklist` | `processes[]` — name, PID, session, memory. CSV format supported |
157
+ | Windows | `ipconfig` | `hostname`, `adapters[]` — IPv4/6, subnet, gateway, DNS, MAC |
158
+ | Windows | `systeminfo` | `hostname`, `os_name`, memory, `hotfixes[]`, `network_cards[]` |
159
+
160
+ Commands without a parser return `parsed: null`. `raw` is always present.
161
+
162
+ ---
163
+
164
+ ## Installation
165
+
166
+ ### npx
167
+
168
+ ```bash
169
+ npx @nerdvana/parism
170
+ ```
171
+
172
+ ### Local Build
173
+
174
+ ```bash
175
+ git clone https://github.com/your-org/parism
176
+ cd parism
177
+ npm install && npm run build
178
+ node dist/index.js
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Claude Desktop Integration
184
+
185
+ `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
186
+ `%APPDATA%\Claude\claude_desktop_config.json` (Windows)
187
+
188
+ ```json
189
+ {
190
+ "mcpServers": {
191
+ "parism": {
192
+ "command": "npx",
193
+ "args": ["-y", "@nerdvana/parism"]
194
+ }
195
+ }
196
+ }
197
+ ```
198
+
199
+ Claude Code (Linux):
200
+
201
+ ```json
202
+ {
203
+ "mcpServers": {
204
+ "parism": {
205
+ "command": "node",
206
+ "args": ["/path/to/parism/dist/index.js"],
207
+ "cwd": "/path/to/parism"
208
+ }
209
+ }
210
+ }
211
+ ```
212
+
213
+ Once connected, a single `run` tool is exposed. The agent uses it to execute commands and receive JSON.
214
+
215
+ ---
216
+
217
+ ## Configuration
218
+
219
+ Place `prism.config.json` in the project root to control Guard behavior.
220
+
221
+ ```json
222
+ {
223
+ "guard": {
224
+ "allowed_commands": ["ls", "git", "find", "grep", "env", "ps"],
225
+ "allowed_paths": ["/home/user/projects"],
226
+ "timeout_ms": 10000,
227
+ "block_patterns": [";", "$(", "`", "&&", "||", "|"],
228
+ "command_arg_restrictions": {
229
+ "node": { "blocked_flags": ["-e", "--eval", "-r", "--require", "-p", "--print"] },
230
+ "npx": { "blocked_flags": ["--yes", "-y"] }
231
+ },
232
+ "env_secret_patterns": ["TOKEN", "SECRET", "AUTHZ", "PASSWORD", "CREDENTIAL"]
233
+ }
234
+ }
235
+ ```
236
+
237
+ `allowed_paths` being empty means no path restriction. That decision is yours.
238
+
239
+ `env_secret_patterns` strips matching environment variables from child processes before execution. The `env` command will not expose them.
240
+
241
+ ---
242
+
243
+ ## What Parism Is Not
244
+
245
+ Parism is not a new shell. It does not replace bash. It sits above bash, receives output, and structures it.
246
+
247
+ Parism is not an operating system for AI. Its concern is singular: when an agent issues a command, return the result in a form the agent can understand.
248
+
249
+ The Unix philosophy was "do one thing well." Parism understands that.
250
+
251
+ ---
252
+
253
+ <p align="center">
254
+ Made by <a href="mailto:jinho.von.choi@nerdvana.kr">Jinho Choi</a> &nbsp;|&nbsp;
255
+ <a href="https://buymeacoffee.com/jinho.von.choi">Buy me a coffee</a>
256
+ </p>
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  > Refract the Shell. Every command, structured.
4
4
 
5
+ <p align="right"><a href="README.md">한국어</a> | <a href="README.en.md">English</a></p>
6
+
5
7
  ---
6
8
 
7
9
  ## 셸은 당신을 위해 설계되지 않았다
@@ -93,7 +95,7 @@ Parism이 개입하는 것은 두 번째와 세 번째 사이다. 한 번 버려
93
95
 
94
96
  에이전트는 오류를 범한다. 문맥을 잃고, 경로를 착각하고, 의도하지 않은 명령을 생성한다. Guard는 에이전트를 불신하는 것이 아니다. 에이전트의 실수가 파국으로 이어지지 않도록 설계하는 것이다.
95
97
 
96
- 겹의 방어선이 있다.
98
+ 겹의 방어선이 있다.
97
99
 
98
100
  **화이트리스트**: `allowed_commands`에 없는 명령어는 실행되지 않는다. 프로세스를 만들지도 않는다. 설명 없이 거절한다.
99
101
 
@@ -101,6 +103,8 @@ Parism이 개입하는 것은 두 번째와 세 번째 사이다. 한 번 버려
101
103
 
102
104
  **인젝션 패턴 차단**: `;`, `$(`, `` ` ``, `&&`, `||`, `|`가 인자에 포함되면 실행하지 않는다. 에이전트가 의도했든 아니든.
103
105
 
106
+ **명령별 인자 제한** *(v0.1.2)*: 명령마다 차단할 플래그를 지정할 수 있다. `node -e`와 `node --eval`은 임의 코드 실행 경로이므로 기본 차단된다. `npx --yes`는 인터넷에서 패키지를 설치하므로 마찬가지다.
107
+
104
108
  차단된 명령은 이런 응답을 반환한다.
105
109
 
106
110
  ```json
@@ -123,7 +127,7 @@ Parism이 개입하는 것은 두 번째와 세 번째 사이다. 한 번 버려
123
127
  |---|---|---|
124
128
  | 파일시스템 | `ls` | `entries[]` — 이름, 타입, 권한, 크기, 수정 시각, 소유자 |
125
129
  | 파일시스템 | `find` | `paths[]` — 경로 목록 |
126
- | 파일시스템 | `stat` | `lines[]` 원본 라인 배열 |
130
+ | 파일시스템 | `stat` | `file`, `size_bytes`, `inode`, `permissions`, `uid`, `gid`, 타임스탬프 |
127
131
  | 파일시스템 | `du` | `entries[]` — 크기, 경로 |
128
132
  | 파일시스템 | `df` | `filesystems[]` — 파티션, 사용량, 마운트 위치 |
129
133
  | 파일시스템 | `tree` | `root`, `tree{}` — 계층 구조 노드, `total_files`, `total_dirs` |
@@ -206,7 +210,43 @@ Claude Code (Linux):
206
210
  }
207
211
  ```
208
212
 
209
- 연결이 되면 `run` 도구 하나가 노출된다. 에이전트는 이 도구로 명령을 실행하고 JSON을 받는다.
213
+ 연결이 되면 `run`과 `run_paged` 도구가 노출된다. 에이전트는 이 도구로 명령을 실행하고 JSON을 받는다.
214
+
215
+ ---
216
+
217
+ ## Tools
218
+
219
+ ### run
220
+
221
+ 모든 명령의 기본 도구. 출력이 작거나 구조화 파싱이 필요할 때 사용한다.
222
+
223
+ 파라미터:
224
+ - `cmd` — 명령어 이름 (예: `ls`, `git`)
225
+ - `args` — 인자 배열 (기본값: `[]`)
226
+ - `cwd` — 작업 디렉토리 (기본값: 현재 디렉토리)
227
+
228
+ ### run_paged
229
+
230
+ 대용량 출력을 페이지 단위로 읽는다. `ps aux`, `find`, `grep -r` 등에 사용한다.
231
+
232
+ 파라미터:
233
+ - `cmd`, `args`, `cwd` — `run`과 동일
234
+ - `page` — 0-indexed 페이지 번호 (기본값: `0`)
235
+ - `page_size` — 페이지당 줄 수 (기본값: `default_page_size` 설정값, 기본 100)
236
+
237
+ 응답 추가 필드:
238
+ - `page_info.total_lines` — 전체 줄 수
239
+ - `page_info.has_next` — 다음 페이지 존재 여부
240
+ - `stdout.parsed` — 항상 `null` (부분 출력은 구조화 불가)
241
+
242
+ 에이전트 패턴:
243
+
244
+ ```
245
+ 1. run_paged(cmd, page=0) → page_info.total_lines 확인
246
+ 2. 범위가 작으면 그대로 사용
247
+ 3. 범위가 크면 grep으로 먼저 필터링 후 run 호출
248
+ 4. 필요한 페이지만 run_paged(page=N) 추가 호출
249
+ ```
210
250
 
211
251
  ---
212
252
 
@@ -220,13 +260,21 @@ Claude Code (Linux):
220
260
  "allowed_commands": ["ls", "git", "find", "grep", "env", "ps"],
221
261
  "allowed_paths": ["/home/user/projects"],
222
262
  "timeout_ms": 10000,
223
- "block_patterns": [";", "$(", "`", "&&", "||", "|"]
263
+ "block_patterns": [";", "$(", "`", "&&", "||", "|"],
264
+ "command_arg_restrictions": {
265
+ "node": { "blocked_flags": ["-e", "--eval", "-r", "--require", "-p", "--print"] },
266
+ "npx": { "blocked_flags": ["--yes", "-y"] }
267
+ },
268
+ "env_secret_patterns": ["TOKEN", "SECRET", "AUTHZ", "PASSWORD", "CREDENTIAL"],
269
+ "default_page_size": 100
224
270
  }
225
271
  }
226
272
  ```
227
273
 
228
274
  `allowed_paths`가 비어 있으면 경로 제한 없이 실행된다. 판단은 당신 몫이다.
229
275
 
276
+ `env_secret_patterns`에 일치하는 환경 변수는 실행 전 자식 프로세스에서 제거된다. `env` 명령 실행 시 해당 변수가 노출되지 않는다.
277
+
230
278
  ---
231
279
 
232
280
  ## Parism이 아닌 것
@@ -5,6 +5,9 @@ export interface PrismGuardConfig {
5
5
  allowed_commands: string[];
6
6
  allowed_paths: string[];
7
7
  timeout_ms: number;
8
+ max_output_bytes: number;
9
+ max_items: number;
10
+ default_page_size: number;
8
11
  block_patterns: string[];
9
12
  command_arg_restrictions: Record<string, CommandArgRestriction>;
10
13
  env_secret_patterns: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAU,MAAM,EAAE,CAAC;IACnC,aAAa,EAAa,MAAM,EAAE,CAAC;IACnC,UAAU,EAAgB,MAAM,CAAC;IACjC,cAAc,EAAY,MAAM,EAAE,CAAC;IACnC,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChE,mBAAmB,EAAO,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,gBAAgB,CAAC;CACzB;AAED,eAAO,MAAM,cAAc,EAAE,WAsB5B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAWzE"}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,EAAU,MAAM,EAAE,CAAC;IACnC,aAAa,EAAa,MAAM,EAAE,CAAC;IACnC,UAAU,EAAgB,MAAM,CAAC;IACjC,gBAAgB,EAAU,MAAM,CAAC;IACjC,SAAS,EAAiB,MAAM,CAAC;IACjC,iBAAiB,EAAS,MAAM,CAAC;IACjC,cAAc,EAAY,MAAM,EAAE,CAAC;IACnC,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IAChE,mBAAmB,EAAO,MAAM,EAAE,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,gBAAgB,CAAC;CACzB;AAED,eAAO,MAAM,cAAc,EAAE,WAyB5B,CAAC;AAEF;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAWzE"}
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
2
2
  export const DEFAULT_CONFIG = {
3
3
  guard: {
4
4
  allowed_commands: [
5
- "ls", "find", "stat", "du", "df",
5
+ "ls", "find", "stat", "du", "df", "tree",
6
6
  "ps", "kill",
7
7
  "ping", "curl", "netstat",
8
8
  "grep", "wc", "head", "tail", "cat",
@@ -12,6 +12,9 @@ export const DEFAULT_CONFIG = {
12
12
  ],
13
13
  allowed_paths: [],
14
14
  timeout_ms: 10000,
15
+ max_output_bytes: 102400, // 100 KB
16
+ max_items: 500,
17
+ default_page_size: 100,
15
18
  block_patterns: [";", "$(", "`", "&&", "||", ">", ">>", "<", "|"],
16
19
  command_arg_restrictions: {
17
20
  node: { blocked_flags: ["-e", "--eval", "-r", "--require", "-p", "--print", "--input-type"] },
@@ -1 +1 @@
1
- {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAmB5C,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,KAAK,EAAE;QACL,gBAAgB,EAAE;YAChB,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI;YAChC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM,EAAE,SAAS;YACzB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;YACnC,KAAK;YACL,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU;SACpC;QACD,aAAa,EAAG,EAAE;QAClB,UAAU,EAAM,KAAK;QACrB,cAAc,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC;QACjE,wBAAwB,EAAE;YACxB,IAAI,EAAE,EAAE,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,EAAE;YAC7F,GAAG,EAAG,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;SACzC;QACD,mBAAmB,EAAE;YACnB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY;SAC/D;KACF;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAI,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;QAErD,OAAO;YACL,KAAK,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE;SAC1D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAsB5C,MAAM,CAAC,MAAM,cAAc,GAAgB;IACzC,KAAK,EAAE;QACL,gBAAgB,EAAE;YAChB,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM;YACxC,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM,EAAE,SAAS;YACzB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK;YACnC,KAAK;YACL,KAAK,EAAE,KAAK,EAAE,OAAO;YACrB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU;SACpC;QACD,aAAa,EAAK,EAAE;QACpB,UAAU,EAAQ,KAAK;QACvB,gBAAgB,EAAG,MAAM,EAAI,SAAS;QACtC,SAAS,EAAU,GAAG;QACtB,iBAAiB,EAAE,GAAG;QACtB,cAAc,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC;QACjE,wBAAwB,EAAE;YACxB,IAAI,EAAE,EAAE,aAAa,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,cAAc,CAAC,EAAE;YAC7F,GAAG,EAAG,EAAE,aAAa,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;SACzC;QACD,mBAAmB,EAAE;YACnB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY;SAC/D;KACF;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,IAAI,CAAC;QACH,MAAM,GAAG,GAAI,MAAM,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyB,CAAC;QAErD,OAAO;YACL,KAAK,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE;SAC1D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC;IACxB,CAAC;AACH,CAAC"}
@@ -5,5 +5,5 @@ import type { ResponseEnvelope } from "../types/envelope.js";
5
5
  * - secretPatterns에 해당하는 환경 변수는 자식 프로세스에 전달하지 않음
6
6
  * - 실행 실패(명령 없음 포함)는 예외 대신 ok=false 봉투로 반환
7
7
  */
8
- export declare function execute(cmd: string, args: string[], cwd: string, secretPatterns?: string[]): Promise<ResponseEnvelope>;
8
+ export declare function execute(cmd: string, args: string[], cwd: string, secretPatterns?: string[], timeoutMs?: number, maxOutputBytes?: number): Promise<ResponseEnvelope>;
9
9
  //# 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;AAqB7D;;;;;GAKG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAa,MAAM,EACtB,IAAI,EAAY,MAAM,EAAE,EACxB,GAAG,EAAa,MAAM,EACtB,cAAc,GAAE,MAAM,EAAO,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA0C3B"}
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,5 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { promisify } from "node:util";
3
+ import { takeSnapshot, computeDiff } from "./state-tracker.js";
3
4
  const execFileAsync = promisify(execFile);
4
5
  /**
5
6
  * process.env에서 시크릿 패턴과 일치하는 변수를 제거한 환경 객체를 반환한다.
@@ -23,14 +24,28 @@ function buildSanitizedEnv(secretPatterns) {
23
24
  * - secretPatterns에 해당하는 환경 변수는 자식 프로세스에 전달하지 않음
24
25
  * - 실행 실패(명령 없음 포함)는 예외 대신 ok=false 봉투로 반환
25
26
  */
26
- export async function execute(cmd, args, cwd, secretPatterns = []) {
27
+ export async function execute(cmd, args, cwd, secretPatterns = [], timeoutMs = 10000, maxOutputBytes = 0) {
27
28
  const start = Date.now();
29
+ const before = await takeSnapshot(cwd);
28
30
  try {
29
31
  const { stdout, stderr } = await execFileAsync(cmd, args, {
30
32
  cwd,
33
+ timeout: timeoutMs,
31
34
  maxBuffer: 10 * 1024 * 1024, // 10 MB
32
35
  env: { ...buildSanitizedEnv(secretPatterns), LC_ALL: "C", LANG: "C" },
33
36
  });
37
+ const after = await takeSnapshot(cwd);
38
+ // stdout 크기 제한: 초과 시 마지막 완전한 줄까지 잘라내고 truncated=true 표시
39
+ let outRaw = stdout;
40
+ let truncated;
41
+ if (maxOutputBytes > 0 && Buffer.byteLength(outRaw, "utf8") > maxOutputBytes) {
42
+ const buf = Buffer.from(outRaw, "utf8").subarray(0, maxOutputBytes);
43
+ const partial = buf.toString("utf8");
44
+ const lastNewline = partial.lastIndexOf("\n");
45
+ outRaw = lastNewline > 0 ? partial.slice(0, lastNewline + 1) : partial;
46
+ outRaw += `...[truncated: output exceeded ${maxOutputBytes} bytes]\n`;
47
+ truncated = true;
48
+ }
34
49
  return {
35
50
  ok: true,
36
51
  exitCode: 0,
@@ -38,14 +53,16 @@ export async function execute(cmd, args, cwd, secretPatterns = []) {
38
53
  args,
39
54
  cwd,
40
55
  duration_ms: Date.now() - start,
41
- stdout: { raw: stdout, parsed: null },
56
+ stdout: { raw: outRaw, parsed: null },
42
57
  stderr: { raw: stderr, parsed: null },
43
- diff: null,
58
+ diff: computeDiff(before, after),
59
+ truncated,
44
60
  };
45
61
  }
46
62
  catch (err) {
47
63
  const e = err;
48
64
  const exitCode = typeof e.code === "number" ? e.code : 1;
65
+ const after = await takeSnapshot(cwd);
49
66
  return {
50
67
  ok: false,
51
68
  exitCode,
@@ -55,7 +72,7 @@ export async function execute(cmd, args, cwd, secretPatterns = []) {
55
72
  duration_ms: Date.now() - start,
56
73
  stdout: { raw: e.stdout ?? "", parsed: null },
57
74
  stderr: { raw: e.stderr ?? e.message, parsed: null },
58
- diff: null,
75
+ diff: computeDiff(before, after),
59
76
  };
60
77
  }
61
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;GAGG;AACH,SAAS,iBAAiB,CAAC,cAAwB;IACjD,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC;IAEpD,MAAM,SAAS,GAAsB,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvD,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC;YAC/D,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAsB,EACtB,IAAwB,EACxB,GAAsB,EACtB,iBAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEzB,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE;YACxD,GAAG;YACH,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;YACrC,GAAG,EAAE,EAAE,GAAG,iBAAiB,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE;SACtE,CAAC,CAAC;QAEH,OAAO;YACL,EAAE,EAAW,IAAI;YACjB,QAAQ,EAAK,CAAC;YACd,GAAG;YACH,IAAI;YACJ,GAAG;YACH,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC/B,MAAM,EAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;YAC1C,MAAM,EAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE;YAC1C,IAAI,EAAS,IAAI;SAClB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,GAIT,CAAC;QAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAEzD,OAAO;YACL,EAAE,EAAW,KAAK;YAClB,QAAQ;YACR,GAAG;YACH,IAAI;YACJ,GAAG;YACH,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;YAC/B,MAAM,EAAO,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE;YAClD,MAAM,EAAO,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE;YACzD,IAAI,EAAS,IAAI;SAClB,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/engine/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { PageInfo } from "../types/envelope.js";
2
+ export interface PaginateResult {
3
+ lines: string[];
4
+ page_info: PageInfo;
5
+ }
6
+ /**
7
+ * raw stdout을 줄 단위로 분할하고 지정 페이지를 반환한다.
8
+ * trailing 빈 줄(마지막 newline으로 인한 빈 문자열)은 제외한다.
9
+ */
10
+ export declare function paginateLines(raw: string, page: number, pageSize: number): PaginateResult;
11
+ //# sourceMappingURL=paginator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginator.d.ts","sourceRoot":"","sources":["../../src/engine/paginator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAM,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,QAAQ,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAqBzF"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * raw stdout을 줄 단위로 분할하고 지정 페이지를 반환한다.
3
+ * trailing 빈 줄(마지막 newline으로 인한 빈 문자열)은 제외한다.
4
+ */
5
+ export function paginateLines(raw, page, pageSize) {
6
+ const allLines = raw.split("\n");
7
+ // trailing empty string from final newline 제거
8
+ if (allLines.length > 0 && allLines[allLines.length - 1] === "") {
9
+ allLines.pop();
10
+ }
11
+ const totalLines = allLines.length;
12
+ const start = page * pageSize;
13
+ const end = start + pageSize;
14
+ const sliced = allLines.slice(start, end);
15
+ return {
16
+ lines: sliced,
17
+ page_info: {
18
+ page,
19
+ page_size: pageSize,
20
+ total_lines: totalLines,
21
+ has_next: end < totalLines,
22
+ },
23
+ };
24
+ }
25
+ //# sourceMappingURL=paginator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paginator.js","sourceRoot":"","sources":["../../src/engine/paginator.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,IAAY,EAAE,QAAgB;IACvE,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,8CAA8C;IAC9C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QAChE,QAAQ,CAAC,GAAG,EAAE,CAAC;IACjB,CAAC;IAED,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;IACnC,MAAM,KAAK,GAAQ,IAAI,GAAG,QAAQ,CAAC;IACnC,MAAM,GAAG,GAAU,KAAK,GAAG,QAAQ,CAAC;IACpC,MAAM,MAAM,GAAO,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAE9C,OAAO;QACL,KAAK,EAAM,MAAM;QACjB,SAAS,EAAE;YACT,IAAI;YACJ,SAAS,EAAI,QAAQ;YACrB,WAAW,EAAE,UAAU;YACvB,QAAQ,EAAK,GAAG,GAAG,UAAU;SAC9B;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { DiffField } from "../types/envelope.js";
2
+ /**
3
+ * 디렉토리 내 파일 경로 → mtime(ms) 맵.
4
+ */
5
+ export type FileSnapshot = Map<string, number>;
6
+ /**
7
+ * cwd 기준 depth 단계까지 재귀 스캔하여 파일 스냅샷을 반환한다.
8
+ */
9
+ export declare function takeSnapshot(cwd: string, depth?: number): Promise<FileSnapshot>;
10
+ /**
11
+ * 두 스냅샷을 비교하여 생성/삭제/수정된 경로 목록을 반환한다.
12
+ */
13
+ export declare function computeDiff(before: FileSnapshot, after: FileSnapshot): DiffField;
14
+ //# sourceMappingURL=state-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-tracker.d.ts","sourceRoot":"","sources":["../../src/engine/state-tracker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAwB/C;;GAEG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,OAAO,CAAC,YAAY,CAAC,CAIhF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,SAAS,CAgBhF"}
@@ -0,0 +1,53 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ async function walk(dir, depth, out) {
3
+ if (depth < 0)
4
+ return;
5
+ let entries;
6
+ try {
7
+ entries = await readdir(dir, { withFileTypes: true });
8
+ }
9
+ catch {
10
+ return; // 권한 없음 등
11
+ }
12
+ for (const entry of entries) {
13
+ const full = `${dir}/${entry.name}`;
14
+ try {
15
+ const s = await stat(full);
16
+ out.set(full, s.mtimeMs);
17
+ if (entry.isDirectory())
18
+ await walk(full, depth - 1, out);
19
+ }
20
+ catch {
21
+ // 개별 항목 오류 무시
22
+ }
23
+ }
24
+ }
25
+ /**
26
+ * cwd 기준 depth 단계까지 재귀 스캔하여 파일 스냅샷을 반환한다.
27
+ */
28
+ export async function takeSnapshot(cwd, depth = 2) {
29
+ const snap = new Map();
30
+ await walk(cwd, depth, snap);
31
+ return snap;
32
+ }
33
+ /**
34
+ * 두 스냅샷을 비교하여 생성/삭제/수정된 경로 목록을 반환한다.
35
+ */
36
+ export function computeDiff(before, after) {
37
+ const created = [];
38
+ const deleted = [];
39
+ const modified = [];
40
+ for (const [path, mtime] of after) {
41
+ const prev = before.get(path);
42
+ if (prev === undefined)
43
+ created.push(path);
44
+ else if (prev !== mtime)
45
+ modified.push(path);
46
+ }
47
+ for (const path of before.keys()) {
48
+ if (!after.has(path))
49
+ deleted.push(path);
50
+ }
51
+ return { created, deleted, modified };
52
+ }
53
+ //# sourceMappingURL=state-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-tracker.js","sourceRoot":"","sources":["../../src/engine/state-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAQjD,KAAK,UAAU,IAAI,CAAC,GAAW,EAAE,KAAa,EAAE,GAAiB;IAC/D,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO;IAEtB,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,UAAU;IACpB,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3B,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YACzB,IAAI,KAAK,CAAC,WAAW,EAAE;gBAAE,MAAM,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,KAAK,GAAG,CAAC;IACvD,MAAM,IAAI,GAAiB,IAAI,GAAG,EAAE,CAAC;IACrC,MAAM,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAoB,EAAE,KAAmB;IACnE,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,SAAS;YAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aACvC,IAAI,IAAI,KAAK,KAAK;YAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC"}
@@ -1,4 +1,11 @@
1
- export declare function parseFind(cmd: string, args: string[], raw: string): {
1
+ import type { ParseContext } from "../registry.js";
2
+ export interface FindSummary {
3
+ total: number;
4
+ shown: number;
5
+ truncated: boolean;
6
+ }
7
+ export declare function parseFind(cmd: string, args: string[], raw: string, ctx?: ParseContext): {
2
8
  paths: string[];
9
+ _summary?: FindSummary;
3
10
  };
4
11
  //# sourceMappingURL=find.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/parsers/fs/find.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAGvF"}
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/parsers/fs/find.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAM,MAAM,CAAC;IAClB,KAAK,EAAM,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAC3D;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,WAAW,CAAA;CAAE,CAW7C"}
@@ -1,5 +1,12 @@
1
- export function parseFind(cmd, args, raw) {
1
+ export function parseFind(cmd, args, raw, ctx) {
2
2
  const paths = raw.split("\n").map(l => l.trim()).filter(Boolean);
3
+ const maxItems = ctx?.maxItems ?? 0;
4
+ if (maxItems > 0 && paths.length > maxItems) {
5
+ return {
6
+ paths: paths.slice(0, maxItems),
7
+ _summary: { total: paths.length, shown: maxItems, truncated: true },
8
+ };
9
+ }
3
10
  return { paths };
4
11
  }
5
12
  //# sourceMappingURL=find.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/parsers/fs/find.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW;IAChE,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjE,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC"}
1
+ {"version":3,"file":"find.js","sourceRoot":"","sources":["../../../src/parsers/fs/find.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,SAAS,CACvB,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;IAE5D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAEjE,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC5C,OAAO;YACL,KAAK,EAAK,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YAClC,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACpE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { ParseContext } from "../registry.js";
1
2
  export interface LsEntry {
2
3
  permissions: string;
3
4
  links: number;
@@ -8,7 +9,13 @@ export interface LsEntry {
8
9
  name: string;
9
10
  type: "file" | "directory" | "symlink" | "other";
10
11
  }
11
- export declare function parseLs(cmd: string, args: string[], raw: string): {
12
+ export interface LsSummary {
13
+ total: number;
14
+ shown: number;
15
+ truncated: boolean;
16
+ }
17
+ export declare function parseLs(cmd: string, args: string[], raw: string, ctx?: ParseContext): {
12
18
  entries: LsEntry[];
19
+ _summary?: LsSummary;
13
20
  };
14
21
  //# sourceMappingURL=ls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/parsers/fs/ls.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,UAAU,EAAG,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;CACzD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,EAAE,CAAA;CAAE,CA6BxF"}
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/parsers/fs/ls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,OAAO;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,KAAK,EAAQ,MAAM,CAAC;IACpB,UAAU,EAAG,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,CAAC;IACpB,IAAI,EAAS,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC;CACzD;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAM,MAAM,CAAC;IAClB,KAAK,EAAM,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAC3D;IAAE,OAAO,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAoC9C"}
@@ -1,4 +1,4 @@
1
- export function parseLs(cmd, args, raw) {
1
+ export function parseLs(cmd, args, raw, ctx) {
2
2
  const entries = [];
3
3
  for (const line of raw.split("\n")) {
4
4
  if (!line || line.startsWith("total "))
@@ -21,6 +21,13 @@ export function parseLs(cmd, args, raw) {
21
21
  : "other",
22
22
  });
23
23
  }
24
+ const maxItems = ctx?.maxItems ?? 0;
25
+ if (maxItems > 0 && entries.length > maxItems) {
26
+ return {
27
+ entries: entries.slice(0, maxItems),
28
+ _summary: { total: entries.length, shown: maxItems, truncated: true },
29
+ };
30
+ }
24
31
  return { entries };
25
32
  }
26
33
  //# sourceMappingURL=ls.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/parsers/fs/ls.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW;IAC9D,MAAM,OAAO,GAAc,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEjD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAClB,0FAA0F,CAC3F,CAAC;QACF,IAAI,CAAC,CAAC;YAAE,SAAS;QAEjB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAEtE,OAAO,CAAC,IAAI,CAAC;YACX,WAAW,EAAE,QAAQ,GAAG,KAAK;YAC7B,KAAK,EAAQ,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YAChC,KAAK;YACL,KAAK;YACL,UAAU,EAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/B,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE;YACzB,IAAI,EAAS,IAAI,CAAC,IAAI,EAAE;YACxB,IAAI,EAAS,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW;gBAChC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS;oBAC9B,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM;wBAC3B,CAAC,CAAC,OAAO;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"ls.js","sourceRoot":"","sources":["../../../src/parsers/fs/ls.ts"],"names":[],"mappings":"AAmBA,MAAM,UAAU,OAAO,CACrB,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;IAE5D,MAAM,OAAO,GAAc,EAAE,CAAC;IAE9B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,SAAS;QAEjD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAClB,0FAA0F,CAC3F,CAAC;QACF,IAAI,CAAC,CAAC;YAAE,SAAS;QAEjB,MAAM,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QAEtE,OAAO,CAAC,IAAI,CAAC;YACX,WAAW,EAAE,QAAQ,GAAG,KAAK;YAC7B,KAAK,EAAQ,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YAChC,KAAK;YACL,KAAK;YACL,UAAU,EAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/B,WAAW,EAAE,KAAK,CAAC,IAAI,EAAE;YACzB,IAAI,EAAS,IAAI,CAAC,IAAI,EAAE;YACxB,IAAI,EAAS,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW;gBAChC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,SAAS;oBAC9B,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM;wBAC3B,CAAC,CAAC,OAAO;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC9C,OAAO;YACL,OAAO,EAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YACpC,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACtE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { ParseContext } from "../registry.js";
1
2
  export interface PsEntry {
2
3
  user: string;
3
4
  pid: number;
@@ -11,7 +12,13 @@ export interface PsEntry {
11
12
  time: string;
12
13
  command: string;
13
14
  }
14
- export declare function parsePs(cmd: string, args: string[], raw: string): {
15
+ export interface PsSummary {
16
+ total: number;
17
+ shown: number;
18
+ truncated: boolean;
19
+ }
20
+ export declare function parsePs(cmd: string, args: string[], raw: string, ctx?: ParseContext): {
15
21
  processes: PsEntry[];
22
+ _summary?: PsSummary;
16
23
  };
17
24
  //# sourceMappingURL=ps.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ps.d.ts","sourceRoot":"","sources":["../../../src/parsers/process/ps.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAK,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,IAAI,EAAK,MAAM,CAAC;IAChB,KAAK,EAAI,MAAM,CAAC;IAChB,IAAI,EAAK,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,OAAO,EAAE,CAAA;CAAE,CAuB1F"}
1
+ {"version":3,"file":"ps.d.ts","sourceRoot":"","sources":["../../../src/parsers/process/ps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAK,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,GAAG,EAAM,MAAM,CAAC;IAChB,IAAI,EAAK,MAAM,CAAC;IAChB,KAAK,EAAI,MAAM,CAAC;IAChB,IAAI,EAAK,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAM,MAAM,CAAC;IAClB,KAAK,EAAM,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,OAAO,CACrB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAC3D;IAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CA8BhD"}
@@ -1,4 +1,4 @@
1
- export function parsePs(cmd, args, raw) {
1
+ export function parsePs(cmd, args, raw, ctx) {
2
2
  const lines = raw.split("\n").filter(Boolean);
3
3
  const processes = [];
4
4
  for (const line of lines.slice(1)) {
@@ -19,6 +19,13 @@ export function parsePs(cmd, args, raw) {
19
19
  command: cols.slice(10).join(" "),
20
20
  });
21
21
  }
22
+ const maxItems = ctx?.maxItems ?? 0;
23
+ if (maxItems > 0 && processes.length > maxItems) {
24
+ return {
25
+ processes: processes.slice(0, maxItems),
26
+ _summary: { total: processes.length, shown: maxItems, truncated: true },
27
+ };
28
+ }
22
29
  return { processes };
23
30
  }
24
31
  //# sourceMappingURL=ps.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ps.js","sourceRoot":"","sources":["../../../src/parsers/process/ps.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW;IAC9D,MAAM,KAAK,GAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAc,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS;QAC/B,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,GAAG,EAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,IAAI,CAAC,CAAC,CAAC;YAChB,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,KAAK,EAAI,IAAI,CAAC,CAAC,CAAC;YAChB,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
1
+ {"version":3,"file":"ps.js","sourceRoot":"","sources":["../../../src/parsers/process/ps.ts"],"names":[],"mappings":"AAsBA,MAAM,UAAU,OAAO,CACrB,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;IAE5D,MAAM,KAAK,GAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,SAAS,GAAc,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;YAAE,SAAS;QAC/B,SAAS,CAAC,IAAI,CAAC;YACb,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,GAAG,EAAM,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9B,GAAG,EAAM,IAAI,CAAC,CAAC,CAAC;YAChB,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,KAAK,EAAI,IAAI,CAAC,CAAC,CAAC;YAChB,IAAI,EAAK,IAAI,CAAC,CAAC,CAAC;YAChB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC,IAAI,SAAS,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAChD,OAAO;YACL,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YACvC,QAAQ,EAAG,EAAE,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACzE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
@@ -1,7 +1,14 @@
1
+ /**
2
+ * 파서가 항목 수를 제한할 때 사용하는 컨텍스트.
3
+ * maxItems=0 이면 무제한.
4
+ */
5
+ export interface ParseContext {
6
+ maxItems: number;
7
+ }
1
8
  /**
2
9
  * 파서 함수 시그니처.
3
10
  */
4
- export type ParserFn = (cmd: string, args: string[], raw: string) => unknown;
11
+ export type ParserFn = (cmd: string, args: string[], raw: string, ctx?: ParseContext) => unknown;
5
12
  /**
6
13
  * 명령어 → 파서 함수의 매핑 테이블.
7
14
  * 파서가 없거나 실패하면 null을 반환한다 (graceful degradation).
@@ -13,6 +20,6 @@ export declare class ParserRegistry {
13
20
  * cmd에 등록된 파서를 찾아 실행한다.
14
21
  * 파서 없음 또는 예외 → null 반환.
15
22
  */
16
- parse(cmd: string, args: string[], raw: string): unknown | null;
23
+ parse(cmd: string, args: string[], raw: string, ctx?: ParseContext): unknown | null;
17
24
  }
18
25
  //# sourceMappingURL=registry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;AAE7E;;;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,GAAG,OAAO,GAAG,IAAI;CAUhE"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;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"}
@@ -11,12 +11,12 @@ export class ParserRegistry {
11
11
  * cmd에 등록된 파서를 찾아 실행한다.
12
12
  * 파서 없음 또는 예외 → null 반환.
13
13
  */
14
- parse(cmd, args, raw) {
14
+ parse(cmd, args, raw, ctx) {
15
15
  const fn = this.parsers.get(cmd);
16
16
  if (!fn)
17
17
  return null;
18
18
  try {
19
- return fn(cmd, args, raw);
19
+ return fn(cmd, args, raw, ctx);
20
20
  }
21
21
  catch {
22
22
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/parsers/registry.ts"],"names":[],"mappings":"AAKA;;;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;QAC5C,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,CAAC,CAAC;QAC5B,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":"AAaA;;;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,9 +1,16 @@
1
+ import type { ParseContext } from "../registry.js";
1
2
  export interface GrepMatch {
2
3
  file: string;
3
4
  line: number;
4
5
  text: string;
5
6
  }
6
- export declare function parseGrep(cmd: string, args: string[], raw: string): {
7
+ export interface GrepSummary {
8
+ total: number;
9
+ shown: number;
10
+ truncated: boolean;
11
+ }
12
+ export declare function parseGrep(cmd: string, args: string[], raw: string, ctx?: ParseContext): {
7
13
  matches: GrepMatch[];
14
+ _summary?: GrepSummary;
8
15
  };
9
16
  //# sourceMappingURL=grep.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/parsers/text/grep.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,SAAS,EAAE,CAAA;CAAE,CA+B5F"}
1
+ {"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/parsers/text/grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAM,MAAM,CAAC;IAClB,KAAK,EAAM,MAAM,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,YAAY,GAC3D;IAAE,OAAO,EAAE,SAAS,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,WAAW,CAAA;CAAE,CA6ClD"}
@@ -1,9 +1,15 @@
1
- export function parseGrep(cmd, args, raw) {
1
+ export function parseGrep(cmd, args, raw, ctx) {
2
2
  const matches = [];
3
3
  for (const line of raw.split("\n")) {
4
4
  if (!line.trim())
5
5
  continue;
6
- // file:line:text 형태 (grep -rn 또는 grep -n)
6
+ // Case 1: 첫 세그먼트가 순수 숫자 → linenum:text (단일파일 grep -n)
7
+ const lineNumOnly = line.match(/^(\d+):(.*)$/);
8
+ if (lineNumOnly) {
9
+ matches.push({ file: "", line: parseInt(lineNumOnly[1], 10), text: lineNumOnly[2] });
10
+ continue;
11
+ }
12
+ // Case 2: file:linenum:text 형태 (grep -rn 또는 다중파일 -n)
7
13
  const withLineNum = line.match(/^([^:]+):(\d+):(.*)$/);
8
14
  if (withLineNum) {
9
15
  matches.push({
@@ -13,7 +19,7 @@ export function parseGrep(cmd, args, raw) {
13
19
  });
14
20
  continue;
15
21
  }
16
- // file:text 형태 (grep -r without -n) — 콜론 앞이 파일 경로
22
+ // Case 3: file:text 형태 (grep -r without -n) — 콜론 앞이 파일 경로
17
23
  const colonIdx = line.indexOf(":");
18
24
  if (colonIdx > 0) {
19
25
  matches.push({
@@ -26,6 +32,13 @@ export function parseGrep(cmd, args, raw) {
26
32
  matches.push({ file: "", line: 0, text: line });
27
33
  }
28
34
  }
35
+ const maxItems = ctx?.maxItems ?? 0;
36
+ if (maxItems > 0 && matches.length > maxItems) {
37
+ return {
38
+ matches: matches.slice(0, maxItems),
39
+ _summary: { total: matches.length, shown: maxItems, truncated: true },
40
+ };
41
+ }
29
42
  return { matches };
30
43
  }
31
44
  //# sourceMappingURL=grep.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/parsers/text/grep.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,IAAc,EAAE,GAAW;IAChE,MAAM,OAAO,GAAgB,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAE3B,0CAA0C;QAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACvD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE;gBACrB,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;gBACnC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE;aACtB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,kDAAkD;QAClD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;gBAC7B,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
1
+ {"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/parsers/text/grep.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,SAAS,CACvB,GAAW,EAAE,IAAc,EAAE,GAAW,EAAE,GAAkB;IAE5D,MAAM,OAAO,GAAgB,EAAE,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAE3B,sDAAsD;QACtD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YACvF,SAAS;QACX,CAAC;QAED,qDAAqD;QACrD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACvD,IAAI,WAAW,EAAE,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE;gBACrB,IAAI,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;gBACnC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAE;aACtB,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,0DAA0D;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YACjB,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;gBAC7B,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC;aAC/B,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,EAAE,QAAQ,IAAI,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC;QAC9C,OAAO;YACL,OAAO,EAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC;YACpC,QAAQ,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;SACtE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
package/dist/server.d.ts CHANGED
@@ -5,6 +5,11 @@ import type { PrismConfig } from "./config/loader.js";
5
5
  * MCP 서버와 테스트 코드가 공통으로 사용한다.
6
6
  */
7
7
  export declare function buildRunResult(cmd: string, args: string[], cwd: string, config: PrismConfig): Promise<string>;
8
+ /**
9
+ * Guard 검사 → 실행 → 페이지 분할 → JSON 직렬화.
10
+ * parsed는 항상 null (부분 출력은 구조화 파싱 불가).
11
+ */
12
+ export declare function buildPagedResult(cmd: string, args: string[], cwd: string, page: number, pageSize: number, config: PrismConfig): Promise<string>;
8
13
  /**
9
14
  * MCP 서버를 생성하고 `run` 도구를 등록한다.
10
15
  */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAmB,yCAAyC,CAAC;AAMjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAY,oBAAoB,CAAC;AAI5D;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAK,MAAM,EACd,IAAI,EAAI,MAAM,EAAE,EAChB,GAAG,EAAK,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAwB3D"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAmB,yCAAyC,CAAC;AAOjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAY,oBAAoB,CAAC;AAI5D;;;GAGG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAK,MAAM,EACd,IAAI,EAAI,MAAM,EAAE,EAChB,GAAG,EAAK,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,CAAC,CA+BjB;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,CAqCjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CA2C3D"}
package/dist/server.js CHANGED
@@ -3,7 +3,8 @@ import { z } from "zod";
3
3
  import { execute } from "./engine/executor.js";
4
4
  import { checkGuard, GuardError } from "./engine/guard.js";
5
5
  import { defaultRegistry } from "./parsers/index.js";
6
- const PACKAGE_VERSION = "0.1.2";
6
+ import { paginateLines } from "./engine/paginator.js";
7
+ const PACKAGE_VERSION = "0.1.4";
7
8
  /**
8
9
  * Guard 검사 → 실행 → JSON 직렬화까지의 파이프라인.
9
10
  * MCP 서버와 테스트 코드가 공통으로 사용한다.
@@ -30,11 +31,48 @@ export async function buildRunResult(cmd, args, cwd, config) {
30
31
  }
31
32
  throw err;
32
33
  }
33
- const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns);
34
- const parsed = defaultRegistry.parse(cmd, args, envelope.stdout.raw);
34
+ const envelope = await execute(cmd, args, cwd, config.guard.env_secret_patterns, config.guard.timeout_ms, config.guard.max_output_bytes);
35
+ const parsed = defaultRegistry.parse(cmd, args, envelope.stdout.raw, { maxItems: config.guard.max_items });
35
36
  const enriched = { ...envelope, stdout: { ...envelope.stdout, parsed } };
36
37
  return JSON.stringify(enriched, null, 2);
37
38
  }
39
+ /**
40
+ * Guard 검사 → 실행 → 페이지 분할 → JSON 직렬화.
41
+ * parsed는 항상 null (부분 출력은 구조화 파싱 불가).
42
+ */
43
+ export async function buildPagedResult(cmd, args, cwd, page, pageSize, config) {
44
+ try {
45
+ checkGuard(cmd, args, cwd, config);
46
+ }
47
+ catch (err) {
48
+ if (err instanceof GuardError) {
49
+ const envelope = {
50
+ ok: false,
51
+ exitCode: -1,
52
+ cmd,
53
+ args,
54
+ cwd,
55
+ duration_ms: 0,
56
+ stdout: { raw: "", parsed: null },
57
+ stderr: { raw: err.message, parsed: null },
58
+ diff: null,
59
+ guard_error: { reason: err.reason, message: err.message },
60
+ };
61
+ return JSON.stringify(envelope, null, 2);
62
+ }
63
+ throw err;
64
+ }
65
+ // 전체 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 { lines, page_info } = paginateLines(envelope.stdout.raw, page, pageSize);
68
+ const pagedRaw = lines.join("\n") + (lines.length > 0 ? "\n" : "");
69
+ const enriched = {
70
+ ...envelope,
71
+ stdout: { raw: pagedRaw, parsed: null },
72
+ page_info,
73
+ };
74
+ return JSON.stringify(enriched, null, 2);
75
+ }
38
76
  /**
39
77
  * MCP 서버를 생성하고 `run` 도구를 등록한다.
40
78
  */
@@ -54,6 +92,19 @@ export function createServer(config) {
54
92
  content: [{ type: "text", text: result }],
55
93
  };
56
94
  });
95
+ server.tool("run_paged", "Execute a shell command and return paginated stdout. " +
96
+ "Use this for commands with large output (ps aux, find, grep -r). " +
97
+ "Returns page_info with total_lines and has_next for navigation.", {
98
+ cmd: z.string().describe("Command name"),
99
+ args: z.array(z.string()).default([]).describe("Command arguments"),
100
+ cwd: z.string().default(process.cwd()).describe("Working directory"),
101
+ page: z.number().int().min(0).default(0).describe("Page index (0-based)"),
102
+ page_size: z.number().int().min(1).default(config.guard.default_page_size)
103
+ .describe("Lines per page"),
104
+ }, async ({ cmd, args, cwd, page, page_size }) => {
105
+ const result = await buildPagedResult(cmd, args, cwd, page, page_size, config);
106
+ return { content: [{ type: "text", text: result }] };
107
+ });
57
108
  return server;
58
109
  }
59
110
  //# sourceMappingURL=server.js.map
@@ -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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"}
@@ -14,6 +14,15 @@ export interface DiffField {
14
14
  deleted: string[];
15
15
  modified: string[];
16
16
  }
17
+ /**
18
+ * run_paged 응답에 포함되는 페이지 메타데이터.
19
+ */
20
+ export interface PageInfo {
21
+ page: number;
22
+ page_size: number;
23
+ total_lines: number;
24
+ has_next: boolean;
25
+ }
17
26
  /**
18
27
  * Prism의 모든 명령 실행 결과가 따르는 응답 봉투.
19
28
  * - ok: 실행 성공 여부 (exitCode === 0)
@@ -29,5 +38,7 @@ export interface ResponseEnvelope {
29
38
  stdout: OutputField;
30
39
  stderr: OutputField;
31
40
  diff: DiffField | null;
41
+ truncated?: boolean;
42
+ page_info?: PageInfo;
32
43
  }
33
44
  //# sourceMappingURL=envelope.d.ts.map
@@ -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;;;;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;CAC/B"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nerdvana/parism",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Structured shell output wrapper for AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -23,6 +23,11 @@
23
23
  "typescript": "^5.7.0",
24
24
  "vitest": "^3.0.0"
25
25
  },
26
- "files": ["dist", "prism.config.json"],
27
- "engines": { "node": ">=20" }
26
+ "files": [
27
+ "dist",
28
+ "prism.config.json"
29
+ ],
30
+ "engines": {
31
+ "node": ">=20"
32
+ }
28
33
  }