jsonseek 0.1.0__tar.gz
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.
- jsonseek-0.1.0/LICENSE +21 -0
- jsonseek-0.1.0/MANIFEST.in +9 -0
- jsonseek-0.1.0/PKG-INFO +588 -0
- jsonseek-0.1.0/README.md +557 -0
- jsonseek-0.1.0/README_ZH.md +556 -0
- jsonseek-0.1.0/pyproject.toml +53 -0
- jsonseek-0.1.0/setup.cfg +4 -0
- jsonseek-0.1.0/setup.py +15 -0
- jsonseek-0.1.0/skills/jsonseek/SKILL.md +285 -0
- jsonseek-0.1.0/skills/jsonseek/references/commands.md +221 -0
- jsonseek-0.1.0/skills/jsonseek/references/path-syntax.md +67 -0
- jsonseek-0.1.0/src/jsonseek/__init__.py +3 -0
- jsonseek-0.1.0/src/jsonseek/cli.py +162 -0
- jsonseek-0.1.0/src/jsonseek/commands/__init__.py +14 -0
- jsonseek-0.1.0/src/jsonseek/commands/add_cmd.py +148 -0
- jsonseek-0.1.0/src/jsonseek/commands/append_cmd.py +116 -0
- jsonseek-0.1.0/src/jsonseek/commands/concat_cmd.py +73 -0
- jsonseek-0.1.0/src/jsonseek/commands/cutline_cmd.py +45 -0
- jsonseek-0.1.0/src/jsonseek/commands/del_cmd.py +182 -0
- jsonseek-0.1.0/src/jsonseek/commands/extend_cmd.py +80 -0
- jsonseek-0.1.0/src/jsonseek/commands/extract_cmd.py +57 -0
- jsonseek-0.1.0/src/jsonseek/commands/fields_cmd.py +59 -0
- jsonseek-0.1.0/src/jsonseek/commands/get_cmd.py +42 -0
- jsonseek-0.1.0/src/jsonseek/commands/ls_cmd.py +45 -0
- jsonseek-0.1.0/src/jsonseek/commands/query_cmd.py +58 -0
- jsonseek-0.1.0/src/jsonseek/commands/replaceline_cmd.py +57 -0
- jsonseek-0.1.0/src/jsonseek/commands/set_cmd.py +153 -0
- jsonseek-0.1.0/src/jsonseek/commands/shape_cmd.py +146 -0
- jsonseek-0.1.0/src/jsonseek/detect.py +57 -0
- jsonseek-0.1.0/src/jsonseek/errors.py +23 -0
- jsonseek-0.1.0/src/jsonseek/formatters.py +260 -0
- jsonseek-0.1.0/src/jsonseek/io/__init__.py +0 -0
- jsonseek-0.1.0/src/jsonseek/io/encoding.py +83 -0
- jsonseek-0.1.0/src/jsonseek/io/json_file.py +122 -0
- jsonseek-0.1.0/src/jsonseek/io/jsonl_file.py +154 -0
- jsonseek-0.1.0/src/jsonseek/io/rewrite.py +60 -0
- jsonseek-0.1.0/src/jsonseek/patch/__init__.py +0 -0
- jsonseek-0.1.0/src/jsonseek/patch/array_ops.py +22 -0
- jsonseek-0.1.0/src/jsonseek/patch/locator.py +101 -0
- jsonseek-0.1.0/src/jsonseek/patch/object_ops.py +24 -0
- jsonseek-0.1.0/src/jsonseek/path_parser.py +136 -0
- jsonseek-0.1.0/src/jsonseek/types.py +65 -0
- jsonseek-0.1.0/src/jsonseek/value_utils.py +98 -0
- jsonseek-0.1.0/src/jsonseek/walkers/__init__.py +0 -0
- jsonseek-0.1.0/src/jsonseek/walkers/field_scan.py +59 -0
- jsonseek-0.1.0/src/jsonseek/walkers/query_scan.py +140 -0
- jsonseek-0.1.0/src/jsonseek/walkers/tree_walk.py +48 -0
- jsonseek-0.1.0/src/jsonseek.egg-info/PKG-INFO +588 -0
- jsonseek-0.1.0/src/jsonseek.egg-info/SOURCES.txt +84 -0
- jsonseek-0.1.0/src/jsonseek.egg-info/dependency_links.txt +1 -0
- jsonseek-0.1.0/src/jsonseek.egg-info/entry_points.txt +2 -0
- jsonseek-0.1.0/src/jsonseek.egg-info/top_level.txt +1 -0
- jsonseek-0.1.0/tests/create_broken_jsons.py +32 -0
- jsonseek-0.1.0/tests/data/__init__.py +1 -0
- jsonseek-0.1.0/tests/data/bad_bytes_utf8.json +1 -0
- jsonseek-0.1.0/tests/data/bad_json_syntax.json +1 -0
- jsonseek-0.1.0/tests/data/enc_ascii.json +1 -0
- jsonseek-0.1.0/tests/data/enc_garbage.json +1 -0
- jsonseek-0.1.0/tests/data/enc_gbk.json +1 -0
- jsonseek-0.1.0/tests/data/enc_utf16.json +0 -0
- jsonseek-0.1.0/tests/data/enc_utf8.json +1 -0
- jsonseek-0.1.0/tests/data/enc_utf8bom.json +1 -0
- jsonseek-0.1.0/tests/data/gbk_with_fake_bom.json +1 -0
- jsonseek-0.1.0/tests/data/mixed_enc_utf8_gbk.json +1 -0
- jsonseek-0.1.0/tests/data/null_byte_json.json +0 -0
- jsonseek-0.1.0/tests/data/test_broken.json +7 -0
- jsonseek-0.1.0/tests/data/test_broken.jsonl +3 -0
- jsonseek-0.1.0/tests/data/test_company.json +25 -0
- jsonseek-0.1.0/tests/data/test_data.json +41 -0
- jsonseek-0.1.0/tests/data/test_data.jsonl +5 -0
- jsonseek-0.1.0/tests/data/test_garbled.json +4 -0
- jsonseek-0.1.0/tests/data/test_multi_error.json +8 -0
- jsonseek-0.1.0/tests/data/test_multi_error.jsonl +5 -0
- jsonseek-0.1.0/tests/data/test_path.json +8 -0
- jsonseek-0.1.0/tests/data/test_products.jsonl +3 -0
- jsonseek-0.1.0/tests/data/test_valid.json +7 -0
- jsonseek-0.1.0/tests/test_concat.py +140 -0
- jsonseek-0.1.0/tests/test_fields_json.py +34 -0
- jsonseek-0.1.0/tests/test_fields_jsonl.py +34 -0
- jsonseek-0.1.0/tests/test_patch_json.py +87 -0
- jsonseek-0.1.0/tests/test_patch_jsonl.py +63 -0
- jsonseek-0.1.0/tests/test_path_parser.py +82 -0
- jsonseek-0.1.0/tests/test_query_json.py +37 -0
- jsonseek-0.1.0/tests/test_query_jsonl.py +26 -0
- jsonseek-0.1.0/tests/test_shape_json.py +46 -0
- jsonseek-0.1.0/tests/test_shape_jsonl.py +30 -0
jsonseek-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 lo2589
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
jsonseek-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: jsonseek
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Query and patch JSON/JSONL files from the command line
|
|
5
|
+
Author: lo2589
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/lo2589/jsonseek
|
|
8
|
+
Project-URL: Repository, https://github.com/lo2589/jsonseek
|
|
9
|
+
Project-URL: Issues, https://github.com/lo2589/jsonseek/issues
|
|
10
|
+
Keywords: json,jsonl,cli,json-query,json-patch,jsonl-tools
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Classifier: Typing :: Typed
|
|
26
|
+
Requires-Python: >=3.8
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
|
|
32
|
+
# JSONSEEK
|
|
33
|
+
|
|
34
|
+
> **A JSON/JSONL navigation and partial manipulation tool for developers and coding agents.**
|
|
35
|
+
>
|
|
36
|
+
> Core purpose: Reduce token waste from LLMs reading entire large JSON files. Use `shape`/`fields`/`query` to locate, then `get`/`set`/`add`/`del`/`append` for partial operations.
|
|
37
|
+
>
|
|
38
|
+
> Supports structural understanding, field summaries, partial querying, and partial modification for both JSON and JSONL.
|
|
39
|
+
>
|
|
40
|
+
> Supports bug detection and partial fixes for both JSON and JSONL.
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Why JSON Deserves a Dedicated Tool
|
|
44
|
+
|
|
45
|
+
JSON is the de facto standard for modern data exchange. From ML experiment logs, API configs, application log streams, to microservice registries and crawler data stores, JSON/JSONL is everywhere:
|
|
46
|
+
|
|
47
|
+
- **ML Experiment Tracking**: Training parameters, metric curves, and model configs all live in JSON — a single experiment directory can easily reach tens of MB
|
|
48
|
+
- **API/Microservice Configs**: Service discovery, routing rules, and environment variables are often managed as JSON configs
|
|
49
|
+
- **Logs & Event Streams**: Structured logs (JSONL) are easier to query than plain text, but file sizes grow extremely fast
|
|
50
|
+
- **Data Exchange**: Frontend-backend communication, inter-service RPC, and crawler output — JSON is the most common format
|
|
51
|
+
|
|
52
|
+
The problem: **The larger the JSON file, the more expensive it is for LLMs and developers to process**. `cat`-ing a 10MB JSON into context burns millions of tokens; even human developers suffer when searching for a field in thousands of lines of nested structure.
|
|
53
|
+
|
|
54
|
+
**JSONSEEK solves this** — by replacing full reads with partial operations, and manual scanning with structured queries. For coding agents and developers who frequently handle JSON/JSONL, this tool is worth a look.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Why Use JSONSEEK (For Coding Agents)
|
|
59
|
+
|
|
60
|
+
When facing a 10MB JSON file, `cat`-ing the entire file into context is catastrophic token waste. JSONSEEK lets you:
|
|
61
|
+
|
|
62
|
+
1. **Understand structure first** — `shape` for the skeleton, `fields` for the field list, without reading content
|
|
63
|
+
2. **Locate targets next** — `query` to search keywords, `ls` to see child nodes at a layer, `get` to fetch specific values
|
|
64
|
+
3. **Modify partially last** — `set`/`add`/`del`/`append` only where needed
|
|
65
|
+
|
|
66
|
+
### Token Savings Estimate
|
|
67
|
+
|
|
68
|
+
| File Size | Operation | Full Read | JSONSEEK Output | Savings |
|
|
69
|
+
|---|---|---|---|---|
|
|
70
|
+
| 100KB config JSON | `shape` | ~25K tokens | ~100 tokens | **99%+** |
|
|
71
|
+
| 100KB config JSON | `fields` | ~25K tokens | ~300 tokens | **98%+** |
|
|
72
|
+
| 100KB config JSON | `get` single value | ~25K tokens | ~10 tokens | **99%+** |
|
|
73
|
+
| 100KB config JSON | `query` hits a few | ~25K tokens | ~100 tokens | **99%+** |
|
|
74
|
+
| 10MB log JSONL | `shape` sampling | ~2.5M tokens | ~200 tokens | **99.9%+** |
|
|
75
|
+
| 10MB log JSONL | `query` hits dozens | ~2.5M tokens | ~1K tokens | **99.9%+** |
|
|
76
|
+
|
|
77
|
+
> Rough estimate: 1 token ≈ 4 bytes of English text. Actual ratios vary by content and tokenizer, but the order of magnitude holds — **the larger the file, the more dramatic the savings**.
|
|
78
|
+
|
|
79
|
+
**Typical agent workflow:**
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Step 1: Understand structure (zero content read, metadata only)
|
|
83
|
+
jsonseek shape config.json # See depth, array sizes
|
|
84
|
+
jsonseek fields config.json # See all field names and types
|
|
85
|
+
|
|
86
|
+
# Step 2: Locate target (read only matching parts)
|
|
87
|
+
jsonseek query config.json api_key # Find where api_key is
|
|
88
|
+
jsonseek get config.json services[0].endpoint
|
|
89
|
+
|
|
90
|
+
# Step 3: Partial modification (write only target path)
|
|
91
|
+
jsonseek set config.json services[0].endpoint "https://new.api.com"
|
|
92
|
+
jsonseek del config.json services[0].deprecated_field
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Installation
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install -e .
|
|
101
|
+
jsonseek --version # JSONSEEK 0.1.0
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Requires Python >= 3.8. Cross-platform support for Windows / macOS / Linux.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Global Options
|
|
109
|
+
|
|
110
|
+
The following options apply to most commands:
|
|
111
|
+
|
|
112
|
+
| Option | Description |
|
|
113
|
+
|--------|-------------|
|
|
114
|
+
| `--output {pretty,json}` | Output format; `json` is machine-readable |
|
|
115
|
+
| `--backup` | Create `.bak` backup before writing |
|
|
116
|
+
| `--dry-run` | Preview changes without actually writing |
|
|
117
|
+
| `--kind {json,jsonl}` | Force file type (auto-detect by default) |
|
|
118
|
+
| `--encoding ENCODING` | Force file encoding (auto-detect by default) |
|
|
119
|
+
| `--context N` | Show N lines of context around target line (JSONL only, default 2) |
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Command Cheatsheet (Agent Mode)
|
|
124
|
+
|
|
125
|
+
### Read-Only Commands (Safe, will not modify files)
|
|
126
|
+
|
|
127
|
+
| Command | Purpose | Agent Scenario |
|
|
128
|
+
|---|---|---|
|
|
129
|
+
| `shape FILE` | Display JSON skeleton tree | First look at an unknown JSON, quickly grasp structure |
|
|
130
|
+
| `fields FILE [KEYWORD]` | List all fields and types | Find field names, see type distribution, filter by keyword |
|
|
131
|
+
| `ls FILE [PATH]` | List child nodes at a path | Browse JSON like `ls` on directories |
|
|
132
|
+
| `get FILE PATH` | Get value at a path | Precisely read a single value, avoid full load |
|
|
133
|
+
| `query FILE TERM` | Search keys or values | Find where a config item is |
|
|
134
|
+
| `extract PATTERN PATH` | Batch extract values at same path | Grab the same field from multiple config files |
|
|
135
|
+
| `concat PATTERN` | Merge multiple JSONs into JSONL | Batch format conversion, data aggregation |
|
|
136
|
+
|
|
137
|
+
### Write Commands (Will modify files, `--backup` recommended)
|
|
138
|
+
|
|
139
|
+
| Command | Purpose | Agent Scenario |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `set FILE PATH VALUE` | Set value | Modify config items, update URLs, change numbers |
|
|
142
|
+
| `add FILE PATH VALUE` | Add new key to object | Add new config fields |
|
|
143
|
+
| `del FILE PATH` | Delete key or array element | Clean up deprecated fields |
|
|
144
|
+
| `append FILE PATH VALUE` | Append single element to array (JSON) | Add a new item to a list |
|
|
145
|
+
| `extend FILE PATH VALUE` | Batch append to array (JSON) | Add multiple elements to a list at once |
|
|
146
|
+
| `append FILE VALUE` | Append record (JSONL) | Add a record to end of JSONL |
|
|
147
|
+
|
|
148
|
+
### Repair Commands
|
|
149
|
+
|
|
150
|
+
| Command | Purpose |
|
|
151
|
+
|---------|---------|
|
|
152
|
+
| `cutline FILE LINE` | Extract a specific line to stdout or temp file |
|
|
153
|
+
| `replaceline FILE LINE [CONTENT]` | Replace a specific line |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Command Parameters
|
|
158
|
+
|
|
159
|
+
### `shape`
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
jsonseek shape FILE [--max-depth N] [--array-mode {sample,full}] [--sample-size N]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
| Parameter | Description |
|
|
166
|
+
|-----------|-------------|
|
|
167
|
+
| `--max-depth N` | Maximum traversal depth |
|
|
168
|
+
| `--array-mode {sample,full}` | Array traversal mode; `sample` (default) or `full` |
|
|
169
|
+
| `--sample-size N` | Number of records to sample for JSONL (default 100) |
|
|
170
|
+
|
|
171
|
+
### `fields`
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
jsonseek fields FILE [KEYWORD] [--top]
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
| Parameter | Description |
|
|
178
|
+
|-----------|-------------|
|
|
179
|
+
| `KEYWORD` | Optional, filter field names |
|
|
180
|
+
| `--top` | Show only top-level fields |
|
|
181
|
+
|
|
182
|
+
### `ls`
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
jsonseek ls FILE [PATH]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `get`
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
jsonseek get FILE PATH
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### `query`
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
jsonseek query FILE TERM [--case-sensitive] [--exact] [--match-mode {key,value,both}] [--max-results N] [--record-id-field FIELD] [--preview-field FIELD]
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
| Parameter | Description |
|
|
201
|
+
|-----------|-------------|
|
|
202
|
+
| `--case-sensitive` | Case-sensitive matching |
|
|
203
|
+
| `--exact` | Exact match (default is substring) |
|
|
204
|
+
| `--match-mode {key,value,both}` | Match key, value, or both (default both) |
|
|
205
|
+
| `--max-results N` | Limit number of results |
|
|
206
|
+
| `--record-id-field FIELD` | Use this field as record ID in JSONL output |
|
|
207
|
+
| `--preview-field FIELD` | Also show preview of this field in JSONL output |
|
|
208
|
+
|
|
209
|
+
### `set`
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
jsonseek set FILE PATH VALUE [--create-missing] [--from-file FILE]
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
| Parameter | Description |
|
|
216
|
+
|-----------|-------------|
|
|
217
|
+
| `--create-missing` | Auto-create missing intermediate paths |
|
|
218
|
+
| `--from-file FILE` | Read value from file (avoids shell quoting issues) |
|
|
219
|
+
|
|
220
|
+
### `add`
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
jsonseek add FILE PATH VALUE [--create-missing] [--from-file FILE]
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Same parameters as `set`.
|
|
227
|
+
|
|
228
|
+
### `del`
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
jsonseek del FILE PATH [-y]
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
| Parameter | Description |
|
|
235
|
+
|-----------|-------------|
|
|
236
|
+
| `-y`, `--yes` | Skip confirmation prompt |
|
|
237
|
+
|
|
238
|
+
### `append`
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
# JSON: append to array
|
|
242
|
+
jsonseek append FILE ARRAY_PATH VALUE
|
|
243
|
+
|
|
244
|
+
# JSONL: append record at root
|
|
245
|
+
jsonseek append FILE VALUE
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### `extend`
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
jsonseek extend FILE ARRAY_PATH JSON_ARRAY
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### `extract`
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
jsonseek extract PATTERN PATH [--include-missing] [--output {pretty,json}]
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Parameter | Description |
|
|
261
|
+
|-----------|-------------|
|
|
262
|
+
| `--include-missing` | Include files where path is missing (default skip) |
|
|
263
|
+
|
|
264
|
+
### `concat`
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
jsonseek concat PATTERN [-o OUTPUT] [--no-sort]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
| Parameter | Description |
|
|
271
|
+
|-----------|-------------|
|
|
272
|
+
| `-o, --output-file OUTPUT` | Output file (default stdout) |
|
|
273
|
+
| `--no-sort` | Preserve glob order (default sort by filename) |
|
|
274
|
+
|
|
275
|
+
### `cutline`
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
jsonseek cutline FILE LINE [--save-temp]
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
| Parameter | Description |
|
|
282
|
+
|-----------|-------------|
|
|
283
|
+
| `--save-temp` | Save to temp file and return path |
|
|
284
|
+
|
|
285
|
+
### `replaceline`
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
jsonseek replaceline FILE LINE [CONTENT] [--from-file FILE]
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
| Parameter | Description |
|
|
292
|
+
|-----------|-------------|
|
|
293
|
+
| `--from-file FILE` | Read replacement content from file |
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## `--dry-run` Preview
|
|
298
|
+
|
|
299
|
+
All write commands support `--dry-run` to preview changes before applying them.
|
|
300
|
+
|
|
301
|
+
**JSON preview:**
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
$ jsonseek set config.json services[2].endpoint "https://new.api.com" --dry-run
|
|
305
|
+
[DRY-RUN] Before: services[2].endpoint = "https://old.api.com"
|
|
306
|
+
[DRY-RUN] After: services[2].endpoint = "https://new.api.com"
|
|
307
|
+
(Dry run, no changes made)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**JSONL preview (with line-number context):**
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
$ jsonseek set logs.jsonl '[15].level' "WARNING" --dry-run
|
|
314
|
+
[DRY-RUN] Before:
|
|
315
|
+
>>>15: {"level":"ERROR","msg":"connection failed"} [TO BE MODIFIED]
|
|
316
|
+
14: {"level":"INFO","msg":"ok"}
|
|
317
|
+
|
|
318
|
+
[DRY-RUN] After:
|
|
319
|
+
>>>15: {"level":"WARNING","msg":"connection failed"} [MODIFIED]
|
|
320
|
+
14: {"level":"INFO","msg":"ok"}
|
|
321
|
+
(Dry run, no changes made)
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**Machine-readable output (`--output json`):**
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
$ jsonseek set config.json services[2].endpoint "https://new.api.com" \
|
|
328
|
+
--dry-run --output json
|
|
329
|
+
{"ok":true,"dry_run":true,"path":"services[2].endpoint",
|
|
330
|
+
"before":"https://old.api.com","after":"https://new.api.com"}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Operation tags:
|
|
334
|
+
- `[TO BE MODIFIED]` / `[MODIFIED]`
|
|
335
|
+
- `[TO BE DELETED]` / (line removed)
|
|
336
|
+
- `[APPENDED]`
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Path Syntax
|
|
341
|
+
|
|
342
|
+
```bash
|
|
343
|
+
# Dot-separated
|
|
344
|
+
jsonseek get data.json meta.settings.timeout
|
|
345
|
+
|
|
346
|
+
# Bracket keys (supports string keys)
|
|
347
|
+
jsonseek get data.json meta[settings][timeout]
|
|
348
|
+
jsonseek get data.json users[0][name]
|
|
349
|
+
|
|
350
|
+
# Array indices
|
|
351
|
+
jsonseek get data.json items[0][1]
|
|
352
|
+
|
|
353
|
+
# JSONL record selector
|
|
354
|
+
jsonseek get data.jsonl '[0].name'
|
|
355
|
+
jsonseek get data.jsonl 'records[12].payload.diff'
|
|
356
|
+
jsonseek set data.jsonl '[0].age' 30
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Rules:
|
|
360
|
+
- `[number]` → Array index (`[0]`, `[12]`)
|
|
361
|
+
- `[string]` → Object key (`[name]`, `[key-1]`)
|
|
362
|
+
- Consecutive brackets chain directly: `a[b][c]`
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## JSON vs JSONL Quick Reference
|
|
367
|
+
|
|
368
|
+
| | JSON | JSONL |
|
|
369
|
+
|---|---|---|
|
|
370
|
+
| Reading | Load entire file into memory | Stream line by line |
|
|
371
|
+
| `shape` | Full tree | Sample first N records |
|
|
372
|
+
| `fields` | Count occurrences | Coverage (record coverage rate) |
|
|
373
|
+
| `get`/`ls` | Parse `path` directly | Path must start with `[N].` or `records[N].` |
|
|
374
|
+
| `set`/`add`/`del` | Direct patch in-memory tree | Full file rewrite (atomic replacement) |
|
|
375
|
+
| `append` | Append inside array | Append record at root level |
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Agent Practical Examples
|
|
380
|
+
|
|
381
|
+
### Scenario 1: Explore Unknown Config JSON
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
jsonseek shape config.json
|
|
385
|
+
# (root)
|
|
386
|
+
# services
|
|
387
|
+
# services[*] (object) [5]
|
|
388
|
+
# services[*].name
|
|
389
|
+
# services[*].endpoint
|
|
390
|
+
# services[*].timeout
|
|
391
|
+
# database
|
|
392
|
+
# database.host
|
|
393
|
+
# database.port
|
|
394
|
+
|
|
395
|
+
jsonseek fields config.json
|
|
396
|
+
# services types=array paths=1
|
|
397
|
+
# name types=string paths=5
|
|
398
|
+
# endpoint types=string paths=5
|
|
399
|
+
# timeout types=integer paths=5
|
|
400
|
+
# database types=object paths=1
|
|
401
|
+
# host types=string paths=1
|
|
402
|
+
# port types=integer paths=1
|
|
403
|
+
|
|
404
|
+
jsonseek query config.json production
|
|
405
|
+
# services[2].name [value] 'production'
|
|
406
|
+
|
|
407
|
+
jsonseek get config.json services[2].endpoint
|
|
408
|
+
# https://prod.api.example.com
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Scenario 2: Batch Modify JSONL
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
jsonseek shape logs.jsonl
|
|
415
|
+
# (root)
|
|
416
|
+
# timestamp (string)
|
|
417
|
+
# level (string)
|
|
418
|
+
# message (string)
|
|
419
|
+
|
|
420
|
+
jsonseek query logs.jsonl ERROR --max-results 5
|
|
421
|
+
# message [value] 'connection failed' record=12 line=15
|
|
422
|
+
|
|
423
|
+
# Change level of record 12 to warning
|
|
424
|
+
jsonseek set logs.jsonl '[12].level' "warning"
|
|
425
|
+
|
|
426
|
+
# Delete record 100
|
|
427
|
+
jsonseek del logs.jsonl '[100]'
|
|
428
|
+
|
|
429
|
+
# Append new record
|
|
430
|
+
jsonseek append logs.jsonl '{"timestamp":"2024-01-01","level":"info","message":"started"}'
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Scenario 3: Precise Partial Modification (Avoid Full Read)
|
|
434
|
+
|
|
435
|
+
```bash
|
|
436
|
+
# Don't do this: cat 10MB.json | feed to LLM for analysis
|
|
437
|
+
# Do this instead:
|
|
438
|
+
jsonseek get large.json data[0].metrics.cpu_usage
|
|
439
|
+
# 42.5
|
|
440
|
+
|
|
441
|
+
jsonseek set large.json data[0].metrics.cpu_usage 45.0
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
### Scenario 4: Batch Extract and Array Extension
|
|
445
|
+
|
|
446
|
+
```bash
|
|
447
|
+
# Batch extract same field from multiple experiment records
|
|
448
|
+
jsonseek extract "experiments/*/metrics.json" training.loss --output json
|
|
449
|
+
# [{"file":"exp1/metrics.json","value":0.12,"ok":true}, ...]
|
|
450
|
+
|
|
451
|
+
# Append multiple elements to array at once (extend unpacks array and appends one by one)
|
|
452
|
+
jsonseek extend data.json tags '["urgent", "review"]'
|
|
453
|
+
# Equivalent to sequentially appending "urgent" and "review"
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
### Scenario 5: Merge Multiple JSONs into JSONL
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
# Convert all JSON experiment records in directory to single JSONL
|
|
460
|
+
jsonseek concat "experiments/*/result.json" -o combined.jsonl
|
|
461
|
+
# combined.jsonl:
|
|
462
|
+
# {"experiment":"exp1","accuracy":0.95}
|
|
463
|
+
# {"experiment":"exp2","accuracy":0.92}
|
|
464
|
+
|
|
465
|
+
# Default sorted by filename; add --no-sort to preserve original order
|
|
466
|
+
jsonseek concat "logs/*.json" --no-sort -o logs.jsonl
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Scenario 6: Large File Debug and Error Fix
|
|
470
|
+
|
|
471
|
+
When JSON files are corrupted or have syntax errors, JSONSEEK can precisely locate problematic lines, and together with the temp file method enables safe fixes:
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Step 1: Discover errors (auto-locate to line)
|
|
475
|
+
jsonseek shape broken.jsonl
|
|
476
|
+
# Error: Found 2 invalid lines in broken.jsonl:
|
|
477
|
+
# Line 5: {"id": 5, "broken
|
|
478
|
+
# Error: Unterminated string starting at
|
|
479
|
+
# Line 12: {"id": 12, "another}
|
|
480
|
+
# Error: Unterminated string starting at
|
|
481
|
+
|
|
482
|
+
# Step 2: Extract problematic line to temp file
|
|
483
|
+
jsonseek cutline broken.jsonl 5 --save-temp
|
|
484
|
+
# C:\Users\...\tmpXXXX.jsonline
|
|
485
|
+
|
|
486
|
+
# Step 3: Fix temp file with Python (bypass PowerShell quoting issues)
|
|
487
|
+
python -c "open(r'C:\Users\...\tmpXXXX.jsonline','w',encoding='utf-8').write('{\"id\": 5, \"name\": \"fixed\"}')"
|
|
488
|
+
|
|
489
|
+
# Step 4: Replace back into original file
|
|
490
|
+
jsonseek replaceline broken.jsonl 5 --from-file C:\Users\...\tmpXXXX.jsonline
|
|
491
|
+
|
|
492
|
+
# Step 5: Verify fix
|
|
493
|
+
jsonseek shape broken.jsonl
|
|
494
|
+
# (root)
|
|
495
|
+
# id (integer)
|
|
496
|
+
# name (string)
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
**Debug Scenario Token Savings Comparison:**
|
|
500
|
+
|
|
501
|
+
| Scenario | Traditional (Full Read) | JSONSEEK Way | Savings |
|
|
502
|
+
|-----|---------------------|---------------|------|
|
|
503
|
+
| Locate syntax error in 10MB JSONL | Read full ~2.5M tokens | shape output ~200 tokens | **99.99%** |
|
|
504
|
+
| Fix line 5 of corrupted JSONL | Read context + modify ~500K tokens | cutline + replaceline ~1K tokens | **99.8%** |
|
|
505
|
+
| Batch fix N errors | N × context reads | N × (cutline + replaceline) | **~99%** |
|
|
506
|
+
|
|
507
|
+
---
|
|
508
|
+
|
|
509
|
+
## Windows PowerShell: Query via CLI, Write via Python API
|
|
510
|
+
|
|
511
|
+
On Windows PowerShell, **read-only commands** (`shape`, `fields`, `get`, `query`, `ls`, `extract`, `concat`) work fine via CLI. However, **write commands** (`set`, `add`, `del`, `append`, `extend`, `replaceline`) are problematic because PowerShell strips double quotes from JSON strings, causing complex values to fail.
|
|
512
|
+
|
|
513
|
+
> **Recommendation for Windows:** Use CLI for all read/query operations. Use Python API for all write/modify operations.
|
|
514
|
+
|
|
515
|
+
### Python API (Recommended for Writes on Windows)
|
|
516
|
+
|
|
517
|
+
```python
|
|
518
|
+
import sys
|
|
519
|
+
sys.path.insert(0, 'src')
|
|
520
|
+
from jsonseek.commands.set_cmd import set_value
|
|
521
|
+
from jsonseek.commands.add_cmd import add_value
|
|
522
|
+
from jsonseek.commands.del_cmd import del_value
|
|
523
|
+
from jsonseek.commands.replaceline_cmd import replace_line
|
|
524
|
+
|
|
525
|
+
# Safe on Windows — no shell quoting issues
|
|
526
|
+
set_value('data.json', 'path', {"key": "value"})
|
|
527
|
+
add_value('data.json', 'items', ["item1", "item2"])
|
|
528
|
+
del_value('data.json', 'path')
|
|
529
|
+
replace_line('data.jsonl', 5, '{"id": 5, "fixed": true}')
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Fallback: Temp File Method
|
|
533
|
+
|
|
534
|
+
If you must use CLI for writes on Windows, use `--from-file` to avoid passing JSON strings on the command line:
|
|
535
|
+
|
|
536
|
+
```powershell
|
|
537
|
+
# For set/add with complex values
|
|
538
|
+
echo '{"key": "value"}' > tmp.json
|
|
539
|
+
jsonseek set data.json path --from-file tmp.json
|
|
540
|
+
|
|
541
|
+
# For cutline/replaceline workflow
|
|
542
|
+
jsonseek cutline broken.jsonl 5 --save-temp
|
|
543
|
+
# C:\Users\...\tmpXXXX.jsonline
|
|
544
|
+
# Edit the temp file, then:
|
|
545
|
+
jsonseek replaceline broken.jsonl 5 --from-file C:\Users\...\tmpXXXX.jsonline
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
No quoting issues on macOS/Linux bash or Windows CMD.
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Project Structure
|
|
553
|
+
|
|
554
|
+
```
|
|
555
|
+
src/jsonseek/
|
|
556
|
+
cli.py # CLI entry point
|
|
557
|
+
types.py # Core data types
|
|
558
|
+
errors.py # Exceptions
|
|
559
|
+
detect.py # File type detection
|
|
560
|
+
formatters.py # Output formatting (pretty/json), incl. patch preview
|
|
561
|
+
path_parser.py # Path parsing (supports . / [] mixed)
|
|
562
|
+
value_utils.py # Type inference and input coercion
|
|
563
|
+
io/ # File I/O (json, jsonl, rewrite, encoding)
|
|
564
|
+
walkers/ # Tree traversal (shape, fields, query)
|
|
565
|
+
patch/ # Patch operations (locator, object/array ops)
|
|
566
|
+
commands/ # Command handlers (14 subcommands)
|
|
567
|
+
tests/ # Unit tests (53 cases)
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Roadmap
|
|
573
|
+
|
|
574
|
+
- [x] JSON read/write and patch
|
|
575
|
+
- [x] JSONL streaming scan and rewrite
|
|
576
|
+
- [x] `--output json` machine-readable output
|
|
577
|
+
- [x] `--dry-run` preview modifications
|
|
578
|
+
- [x] Windows / macOS / Linux cross-platform support
|
|
579
|
+
- [x] Large file error location and fix (cutline/replaceline)
|
|
580
|
+
- [x] Python API methods (set_value/add_value/del_value)
|
|
581
|
+
- [x] PowerShell temp file bypass solution
|
|
582
|
+
- [ ] Claude Code / Cursor / OpenAI-compatible coding workflows plugin integration
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## License
|
|
587
|
+
|
|
588
|
+
MIT
|