@uehaj/sys1grep 0.5.0-next.0 → 0.5.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@ and applies a threshold.
14
14
  ./sys1grep -n -e "customer is angry or frustrated" tickets.txt
15
15
  ```
16
16
 
17
- [![sys1grep demo: a Japanese meaning finds refund requests in six languages; "asking for a refund" vs "about a refund"; -Q finds the answer](docs/demo.svg)](https://uehaj.github.io/sys1grep/)
17
+ [![sys1grep demo: a Japanese meaning finds refund requests in six languages; "asking for a refund" vs "about a refund"; -Q finds the answer](docs/demo.svg)](https://uehaj.github.io/jev-semgrep/)
18
18
 
19
19
  <sub>▶ Click the demo, or open <a href="https://uehaj.github.io/sys1grep/">uehaj.github.io/sys1grep</a>, for the full demo on the landing page.</sub>
20
20
 
@@ -134,8 +134,7 @@ as a plain regex, with no request at all. It prefilters its AND term: only the l
134
134
  ever ask that term's meanings, so a cheap regex in front of a meaning cuts both the bill and the wait. A line is sent
135
135
  only if some term's regexes all hold for it (a term with no regex holds for every line), so with
136
136
  `-e '/re/' -a A -e B` a line without `re` is still sent, asked `B` only. A query of regex terms alone
137
- sends nothing, except that `--sentence` (`=jev`, the default) still asks Jev where wrapped lines
138
- break; use `--sentence=rules` to stay offline. Anything that isn't shaped like `/…/flags` is still a meaning, so
137
+ sends nothing, even with `--unit=sentence-by-jev`: the rules alone then decide where wrapped lines join. Anything that isn't shaped like `/…/flags` is still a meaning, so
139
138
  `-e '/etc 以下のファイルを変更している'` (no closing `/`) is unaffected; a meaning that really starts
140
139
  and ends with `/` can be written with a leading space to dodge the regex reading.
141
140
 
@@ -172,24 +171,49 @@ $ ./sys1grep -o -n -e '/[A-Z]+-\d+/' -a 'the ticket is still open' notes.txt #
172
171
  Every line sent to Jev costs money and time, so the cheapest line is the one never sent. From the widest cut
173
172
  to the narrowest:
174
173
 
175
- - **Which files.** `-r` skips `.git`, `node_modules`, binary files, likely secrets and what git ignores;
176
- [`git sys1grep`](#as-a-git-subcommand-git-sys1grep) searches tracked files only. `--include` / `--exclude`
177
- (file-name globs) and `--changed-within` (`30m`, `7d`, `today`, `this-week`, a date) narrow them further.
178
- A meaning that restricts itself to a language or a time of change narrows them by itself: see
179
- [Scope from the meaning](#scope-from-the-meaning).
174
+ - **Which files.** `-r` skips `.git`, `node_modules`, binary files, likely secrets, generated files (source maps,
175
+ minified JS/CSS, lock files) and what git ignores; [`git sys1grep`](#as-a-git-subcommand-git-sys1grep) searches
176
+ tracked files only. `--include` / `--exclude` (file-name globs) and `--changed-within` (`30m`, `7d`, `today`,
177
+ `this-week`, a date) narrow them further. A meaning that restricts itself to a language or a time of change
178
+ narrows them by itself: see [Scope from the meaning](#scope-from-the-meaning).
180
179
  - **Which lines.** A [regex term](#regex-terms) is matched locally, and only the lines it holds for are asked
181
- its AND term's meanings. Blank lines are never sent.
180
+ its AND term's meanings. Blank lines are never sent. Only the first `-M`/`--max-columns` characters of a line
181
+ (default 2000, 8000 with `-z`) are sent: it is still searched and judged, just not past that cutoff.
182
182
  - **How many times.** [`--dedup`](#one-line-per-template---dedup) judges one line per template: lines that
183
183
  differ only in ids, numbers, times or paths share one answer.
184
- - **Check before paying.** `--dry-run` sends nothing and prints the files, how many lines each would send and
185
- every request with its questions. Its last line estimates the input tokens and, for TypeSafe itself, the price
186
- (`~3178 input tokens, ~$0.000133`; within about 10%). `-i` shows the same totals on the terminal and sends only
187
- after `y`.
184
+ - **Check before paying.** `--dry-run` sends nothing and prints the settings the search would run with, the
185
+ files, how many lines each would send and every request with its questions. Its last line estimates the input
186
+ tokens and, for TypeSafe itself, the price (`~3178 input tokens, ~$0.000133`; within about 10%). `-i` shows the
187
+ same totals on the terminal and sends only after `y`.
188
+ Before the bulk of requests, every target is sized (`--max-filesize`, default 10M); one over it is skipped
189
+ outright, like `rg`'s own `--max-filesize`, named on stderr (`-y` does not affect it). A `.gz` is sized
190
+ decompressed (zlib stops at the limit, so an oversized one is never inflated in full). stdin is sized once it
191
+ is read (it is already in memory), and skipped the same way if it is over; a `--cached` or `<tree>:` target
192
+ is a blob rather than a file, sized from its content (already read in one `git cat-file --batch` call, not a
193
+ fresh git process per blob); `-g`'s commits stay out of this, since each is already bounded by `-M` when it
194
+ is sent. The input about to be sent is priced too (`--max-cost`,
195
+ default 1 USD); over it, one question asks to continue on the terminal, `-y` answers it yes, and without a
196
+ terminal it is exit 2 (this applies with `-q` too — scripts pass `-y`).
188
197
 
189
198
  ```sh
190
199
  $ sys1grep --dry-run -r --include='*.log' --changed-within=today -e '/ERROR|FATAL/' -a 'a customer is affected' logs/
191
200
  ```
192
201
 
202
+ `--verbose` (or `--dry-run`) also shows *where* a setting that was not typed on the command line came from
203
+ (`SYS1GREP_OPTS`, an environment variable, `~/.config/sys1grep/.env`, or a preset's default), so a result that
204
+ surprises you can be traced back to its source. The key's value never appears, only which option or variable
205
+ supplied it:
206
+
207
+ ```sh
208
+ $ SYS1GREP_OPTS='--level strict' sys1grep --verbose -e "the API key is read from a file" .
209
+ sys1grep: endpoint api.typesafe.ai/v1/systemone (default), model jev-latest (default)
210
+ sys1grep: key: SYS1GREP_API_KEY (~/.config/sys1grep/.env)
211
+ sys1grep: SYS1GREP_OPTS: --level strict
212
+ sys1grep: options: --level strict (SYS1GREP_OPTS) = -t 0.7 -T 0.3, --chunk 30, -j 8, scope on, -M 2000, --max-filesize 10M, --max-cost 1
213
+ sys1grep: file ./a.py: 120 lines, 120 to send
214
+ …
215
+ ```
216
+
193
217
  ## Install
194
218
 
195
219
  Two ways to use it: as a command-line tool (this section), or as a Claude Code skill
@@ -381,11 +405,18 @@ tests/tickets/sub/b.txt
381
405
  ```
382
406
 
383
407
  `-r` walks directories in sorted order and skips `.git`, `node_modules`, `.ssh`, `.aws`, `.gnupg`, `.kube`,
384
- `.docker`, binary files (a NUL byte in the first 8 KB, or a PDF; UTF-16 with a BOM is read as text) and files
408
+ `.docker`, binary files (a NUL byte in the first 8 KB, or a PDF; UTF-16 with a BOM is read as text), files
385
409
  that usually hold secrets (`.env*`, `.netrc`, `.npmrc`, `.pypirc`, `.pgpass`, `.git-credentials`, `*.pem`,
386
- `*.key`, `*.p12`, `*.pfx`, `*.jks`, `*.keystore`, `id_rsa*` and friends; names compared without case). **Every line that is searched is sent to the TypeSafe API**, so point `-r` at a directory
410
+ `*.key`, `*.p12`, `*.pfx`, `*.jks`, `*.keystore`, `id_rsa*` and friends; names compared without case) and
411
+ generated files (`*.map`, `*.min.js`, `*.min.css`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`,
412
+ `Cargo.lock`, `poetry.lock`, `composer.lock`, `Gemfile.lock`, `go.sum`). **Every line that is searched is sent
413
+ to the TypeSafe API**, so point `-r` at a directory
387
414
  you mean to scan. Inside a git repository, `-r` also skips what git ignores (`.gitignore`, `.git/info/exclude`, the
388
415
  global excludes file), so build output and local files stay home; a tracked file is searched even if it matches.
416
+ A file named `*.gz` (a rotated log: `app.log.1.gz`) is read decompressed, as `zgrep` does, and printed by its
417
+ name on disk (`app.log.1.gz:12:...`); `--include='*.gz'` picks those, the binary sniff sees the decompressed
418
+ bytes, a gzipped secret (`private.key.gz`) is skipped like the plain one, and a corrupt `.gz` is an unreadable file.
419
+ Only gzip, only by the name.
389
420
  A file named explicitly on the command line is always searched, even if it matches the skip list or is ignored;
390
421
  so is a directory that git ignores, when you name it (`sys1grep -r -e ... dist`). `-l` prints each
391
422
  matching file once, in the order matches are found, and works with or without `-r`. `-c` prints the number of
@@ -453,6 +484,25 @@ applies even to tracked files. `--include`, `--exclude` and `--changed-within` f
453
484
  by a pathspec included. `--changed-within` reads the working tree's modification times, not git history: right after
454
485
  a clone or a checkout, every file it wrote counts as just changed. For help use `git sys1grep -h`: git takes `--help` itself and looks for a man page.
455
486
 
487
+ `--cached`, `--untracked` and a `<tree>...` choose what is searched instead of the working tree, as `git grep` has
488
+ them (only one of the three at a time):
489
+
490
+ ```sh
491
+ $ git sys1grep --cached -e "a retry is attempted" # staged, uncommitted changes included
492
+ $ git sys1grep --untracked -e "a retry is attempted" # tracked files plus untracked ones (.gitignore still applies)
493
+ $ git sys1grep -n -e "a retry is attempted" main v0.3.1 -- '*.py'
494
+ main:src/job.py:42: retry(job, times=3)
495
+ v0.3.1:src/job.py:40: retry(job)
496
+ ```
497
+
498
+ A `<tree>` (a branch, tag, commit or `@{u}`) is any argument before `--` that resolves as a revision; several may
499
+ be given, searched in the order given, each line prefixed with the name as typed (`@{u}:path`, not the branch it
500
+ resolves to). `--changed-within` needs the working tree: a blob (`--cached`, a `<tree>`) has no mtime of its own.
501
+ A `<tree>`'s own pathspec takes a glob too, same as elsewhere in sys1grep (`git diff-tree` against the empty
502
+ tree, not `git ls-tree`'s own literal/directory-prefix match); `--include` / `--exclude` (by name) still work.
503
+ **An old `<tree>` can hold a secret an ordinary file once carried and was later removed from**: the skip list
504
+ drops files by name only, not by what changed since.
505
+
456
506
  ### Everything that is *not* something
457
507
 
458
508
  ```sh
@@ -480,15 +530,15 @@ Matching records are printed NUL-terminated too, so pipe them through `tr '\0' '
480
530
  File names (`-l`) and counts (`-c`) stay on newlines, as they do in grep. With `-z`, `-n` numbers records,
481
531
  `-A` / `-B` / `-C` count neighbouring records, and `--chunk` counts records per request.
482
532
 
483
- ### One sentence at a time (`--sentence`)
533
+ ### One sentence at a time (`--unit=sentence-by-*`)
484
534
 
485
- `--sentence` judges each sentence instead of each line. The output is still lines, as in grep: every line a
535
+ `--unit=sentence-by-jev` (or `sentence-by-rule`, below) judges each sentence instead of each line. The output is still lines, as in grep: every line a
486
536
  matching sentence touches is printed, and on a terminal the sentence itself is in bold yellow (a regex match inside it, in grep's bold red).
487
537
  Wrapped lines are joined before splitting, so a sentence that runs over several lines is judged as one.
488
538
  [`tests/prose.txt`](tests/prose.txt) wraps an English paragraph and a Japanese one:
489
539
 
490
540
  ```sh
491
- $ ./sys1grep -n --sentence -e "the author admits they made a mistake" tests/prose.txt
541
+ $ ./sys1grep -n --unit=sentence-by-jev -e "the author admits they made a mistake" tests/prose.txt
492
542
  1:I should have checked the input
493
543
  2:before shipping, and that was my
494
544
  3:mistake. Next time I will add a test
@@ -500,14 +550,14 @@ The sentence starts on line 1 and ends at `mistake.` on line 3; only that part i
500
550
  On a terminal, with both meanings and `-C 3` for context, the colors show where each sentence starts and ends
501
551
  inside a line: lines 3 and 9 are colored only up to the end of the matching sentence, and lines 4-7 are context (`-`):
502
552
 
503
- ![--sentence -C 3 --color: the matching sentences in bold yellow, up to mistake. on line 3 and 返金してほしいです。 on line 9; lines 4 to 7 as context](docs/sentence.svg)
553
+ ![--unit=sentence-by-jev -C 3 --color: the matching sentences in bold yellow, up to mistake. on line 3 and 返金してほしいです。 on line 9; lines 4 to 7 as context](docs/sentence.svg)
504
554
 
505
555
  `-o` prints only the matching sentences, one per line, as `grep -o` prints only the matching part.
506
556
  `-n` then gives the line where the sentence starts. Japanese is joined without a space, as are Chinese,
507
557
  Thai, Lao, Khmer, Myanmar and Tibetan, which do not put spaces between words:
508
558
 
509
559
  ```sh
510
- $ ./sys1grep -n -o --sentence -e "the author admits they made a mistake" -e "customer is asking for a refund" tests/prose.txt
560
+ $ ./sys1grep -n -o --unit=sentence-by-jev -e "the author admits they made a mistake" -e "customer is asking for a refund" tests/prose.txt
511
561
  1:I should have checked the input before shipping, and that was my mistake.
512
562
  8:先週買った掃除機が初日から動かないので返金してほしいです。
513
563
  ```
@@ -515,20 +565,20 @@ $ ./sys1grep -n -o --sentence -e "the author admits they made a mistake" -e "cus
515
565
  Without `-o`, `-c` counts lines and `-A` / `-B` / `-C` count lines, as usual. With `-o` they count sentences.
516
566
  With `-z`, each record is split on its own and matching records are printed whole.
517
567
 
518
- Jev finds a matching sentence inside a long line on its own, so `--sentence` is not needed for accuracy.
568
+ Jev finds a matching sentence inside a long line on its own, so `--unit=sentence-by-jev` is not needed for accuracy.
519
569
  Use it to see which sentence matched, to get the sentences with `-o`, and when AND should hold within one
520
570
  sentence: the expression is evaluated per sentence. For the same reason `-v X` alone prints every line
521
- with at least one sentence that is not X; to find lines that are not X as a whole, leave `--sentence` off.
571
+ with at least one sentence that is not X; to find lines that are not X as a whole, leave `--unit` at `line`.
522
572
 
523
573
  Japanese and Chinese entries often end without `。`: a chat message, a support ticket, a memo line. Joining
524
- them would glue separate entries into one "sentence". So by default (`--sentence`, the same as
525
- `--sentence=jev`) sys1grep asks Jev about each unpunctuated break next to a script written without word
574
+ them would glue separate entries into one "sentence". So with
575
+ `--unit=sentence-by-jev` sys1grep asks Jev about each unpunctuated break next to a script written without word
526
576
  spaces: "does this line break end a sentence or entry, or is it a wrap inside a sentence?" It sends 30 lines
527
577
  per request with one yes/no per break, and keeps the lines apart when the answer is 0.7 or more. On
528
578
  [`tests/corpus.txt`](tests/corpus.txt) this keeps the four one-line Japanese tickets apart, so
529
- `--sentence` finds the same refund requests (lines 14 and 18) as a line-by-line search, where the rules alone
579
+ `--unit=sentence-by-jev` finds the same refund requests (lines 14 and 18) as a line-by-line search, where the rules alone
530
580
  merged the tickets and missed line 18. The extra requests cost about as much as one more meaning; use
531
- `--sentence=rules` to skip them. Breaks between English lines are never asked: joining them keeps a space,
581
+ `--unit=sentence-by-rule` to skip them. Breaks between English lines are never asked: joining them keeps a space,
532
582
  and the full stop still ends the sentence.
533
583
 
534
584
  Where a newline cannot be inside a sentence, lines are not joined: at a blank line, next to brackets or
@@ -538,6 +588,38 @@ own. Sentences are cut by `Intl.Segmenter` ([Unicode UAX #29](https://unicode.or
538
588
  which splits at `.` `!` `?` `。` `!` `?` but also after abbreviations such as `Mr.`. Logs are not prose:
539
589
  consecutive log lines that start with a letter, such as `WARN ...` after `ERROR ...`, get joined.
540
590
 
591
+ ### One function at a time (`--unit=function`)
592
+
593
+ In code the question is usually about a function ("retries on network failure"), and one line of it rarely
594
+ says so. `--unit=function` judges each function and prints its lines, with `-n` giving file line numbers:
595
+
596
+ ```sh
597
+ $ ./sys1grep -n --unit=function -e "retries on network failure" src/net.js
598
+ src/net.js:3:async function fetchWithRetry(url) {
599
+ src/net.js:4: for (let i = 0; i < 5; i++) {
600
+ src/net.js:5: try { return await fetch(url); }
601
+ src/net.js:6: catch { await sleep(2 ** i * 100); }
602
+ src/net.js:7: }
603
+ src/net.js:8:}
604
+ ```
605
+
606
+ A function runs from a funcname line to the line before the next one, as `git grep -W` finds it; lines
607
+ before the first funcname line are one unit, and blank lines at a function's end are not printed. The
608
+ funcname lines are git's: the `diff=<driver>` attribute in `.gitattributes`, then `diff.<driver>.xfuncname`
609
+ in git config. Without one, sys1grep has its own rule for JavaScript/TypeScript (a top-level `function`,
610
+ `class`, or `const` / `let` / `var` bound to a function) and Python (`def` / `class`, nested ones too); a decorator line (`@retry`) starts
611
+ the function it decorates. Otherwise it uses git's default: a line starting with a letter, `_` or `$`. git's own builtin drivers
612
+ (`diff=python` and so on) are not read, so a driver without an `xfuncname` falls back the same way:
613
+
614
+ ```sh
615
+ $ printf '*.go diff=golang\n' >> .gitattributes
616
+ $ git config diff.golang.xfuncname '^(func|type)[[:space:]]'
617
+ ```
618
+
619
+ `-M` defaults to 8000 characters here, as with `-z`; a longer function is judged on its first 8000.
620
+ `--chunk` counts functions, `-A`/`-B`/`-C` and `-c` count lines, as with the sentence units. `-z`, `-g` and
621
+ `-o` are refused.
622
+
541
623
  ### One line per template (`--dedup`)
542
624
 
543
625
  Cost is proportional to the text sent, and machine-generated logs are mostly one skeleton with a different
@@ -561,7 +643,7 @@ could change a match, and those kinds are kept apart (one of the two requests ab
561
643
  Measured on real logs, with nothing kept: a 43,071-line system log folds into 550 templates (1.2% of the
562
644
  bytes), `install.log` to 21.1%, a Claude Code transcript (jsonl) only to 56.8%. It is for machine-generated
563
645
  logs; prose has no shared skeleton, and a meaning that reads a timestamp folds almost nothing. With `-z` or
564
- `--sentence` the records or sentences fold instead of lines.
646
+ `--unit=sentence-by-*` the records or sentences fold instead of lines.
565
647
 
566
648
  After a search, the summary line says what the folding saved: `(2 folded by --dedup, ~235 input tokens /
567
649
  ~$0.000010 saved, 21%)` above. It estimates what the folded lines would have cost as requests of their own and subtracts
@@ -589,15 +671,44 @@ The expensive model reads only what Jev kept. Asking why `./.env` is no longer r
589
671
  `git log` (168 commits), Claude's input fell from 22,059 tokens to 1,356, the total cost with Jev's from
590
672
  $0.094 to $0.013, with the same answer (#69). It pays when the answer sits in a few lines.
591
673
 
592
- - The matching lines leave the machine a second time, to Anthropic.
674
+ - The matching lines leave the machine a second time, to Anthropic (or whatever TOOL talks to).
593
675
  - `-n`, `-A/-B/-C`, `-p` and file names go in as they would print; colors never do. No match runs nothing (exit 1).
594
- - `SYS1GREP_SUMMARIZER` picks the TOOL of a bare `--summarize` (only `claude` so far), `SYS1GREP_SUMMARIZER_MODEL` its model.
676
+ - `SYS1GREP_SUMMARIZER` picks the TOOL of a bare `--summarize`, `SYS1GREP_SUMMARIZER_MODEL` its model.
595
677
  - `-q`, `-l` and `-c` print no lines, so they cannot be combined with it.
678
+ - The answer is plain text: an LLM that is not told writes Markdown, noise on a terminal, so plain is asked for.
679
+ `--summarize-format=markdown` or `=html` asks for those instead (`… --summarize-format=html … > summary.html`).
680
+ The answer prints as it comes, unchecked. In `SYS1GREP_OPTS` it is a standing preference, ignored without `--summarize`.
596
681
  - With `--dedup`, the TOOL gets what Jev got: each template's representative once, marked `(×N like it)`,
597
682
  not every line its answer was reused for.
598
683
  - More than 200 KB (about 50k tokens) is not sent at all: exit 2, with the size, before the TOOL is paid.
599
684
  It is never cut short, since a summary of the first part would read as a summary of all of it.
600
685
 
686
+ `--summarize-prompt=TEXT` adds your own instruction after the fixed one (how long, what to focus on):
687
+
688
+ ```sh
689
+ $ sys1grep -r -n --summarize --summarize-prompt="3 lines or fewer, just which file to fix" \
690
+ -e "the API key is read from a file" .
691
+ ```
692
+
693
+ It needs `--summarize`; empty TEXT is the same as leaving it out. It comes after the `--summarize-format` sentence,
694
+ so TEXT can override the format.
695
+
696
+ Other TOOLs:
697
+
698
+ ```sh
699
+ $ sys1grep --summarize=llm -e "..." FILE # Simon Willison's llm, tools off (no -T given)
700
+ $ sys1grep --summarize=pi -e "..." FILE # pi --print --no-tools --no-session ...
701
+ $ SYS1GREP_SUMMARIZER_MODEL=qwen3.5:9b sys1grep --summarize=ollama -e "..." FILE
702
+ $ SYS1GREP_SUMMARIZER_MODEL=some-id sys1grep --summarize=lmstudio -e "..." FILE # model id from GET /v1/models
703
+ $ SYS1GREP_SUMMARIZER_MODEL=some-id sys1grep --summarize=http://localhost:8080/v1 -e "..." FILE # llama.cpp, vLLM, LocalAI, a gateway
704
+ ```
705
+
706
+ `ollama` and `lmstudio` talk to a local OpenAI-compatible server (`POST /v1/chat/completions`) by `fetch`, no
707
+ CLI: the matching lines never leave the machine a second time. A plain `http(s)://` URL is any other
708
+ OpenAI-compatible server. All three need `SYS1GREP_SUMMARIZER_MODEL`: none has a default model.
709
+ `SYS1GREP_SUMMARIZER_API_KEY` goes as `Authorization: Bearer` to a URL TOOL only (never `SYS1GREP_API_KEY`,
710
+ which is Jev's). `OLLAMA_HOST` moves ollama's host, as it does for the `ollama` CLI itself.
711
+
601
712
  ## Use it from Claude Code
602
713
 
603
714
  There is a Claude Code skill that runs sys1grep for you: describe what you are looking for in plain words
@@ -651,7 +762,11 @@ usage: sys1grep [OPTION]... -e MEANING|-Q QUESTION [-a MEANING] [-v MEANING]...
651
762
  -T THRESH negative threshold: "not X" when probability < THRESH (overrides --level)
652
763
  with -t 0.6 -T 0.3 a line at 0.3..0.6 matches neither X nor not-X
653
764
  -r recurse into directories (current directory when FILE is omitted);
654
- skips .git, node_modules, binary files, likely secrets and what git ignores
765
+ skips .git, node_modules, binary files, likely secrets, generated files and what git ignores
766
+ --cached git sys1grep only: search the index instead of the working tree, as git grep --cached
767
+ --untracked git sys1grep only: also search untracked files (.gitignore still applies), as git grep --untracked
768
+ <tree>... git sys1grep only: a branch, tag, commit or @{u} before -- searches that revision's tree
769
+ instead, as git grep does; output is prefixed <tree>: with the name as typed
655
770
  --include=GLOB, --exclude=GLOB with -r and git sys1grep, only files whose name matches GLOB, or not
656
771
  (with -r a file named on the command line is always searched; git sys1grep's pathspecs are filtered)
657
772
  --changed-within=WHEN with -r and git sys1grep, only files modified within 30m / 2h / 7d / 2w, since a date
@@ -670,13 +785,26 @@ usage: sys1grep [OPTION]... -e MEANING|-Q QUESTION [-a MEANING] [-v MEANING]...
670
785
  on ambiguous lines, not just speed
671
786
  -j N concurrent requests (default 8)
672
787
  -n print line numbers
673
- -z, --null-data judge NUL-terminated records instead of lines, and print them NUL-terminated (see "Records that span several lines" above)
674
- --sentence[=HOW] judge each sentence instead of each line; HOW is jev (default) or rules (see "One sentence at a time" above)
675
- -o with --sentence, print only the matching sentences
788
+ --unit=UNIT the unit of judgement: line (default), zero, sentence-by-jev, sentence-by-rule or function
789
+ -z, --null-data --unit=zero: judge NUL-terminated records instead of lines, and print them NUL-terminated (see "Records that span several lines" above);
790
+ with --unit=sentence-by-*, each record is split into sentences
791
+ --unit=sentence-by-jev|sentence-by-rule judge each sentence instead of each line (see "One sentence at a time" above)
792
+ --unit=function judge each function and print its lines (see "One function at a time" above)
793
+ -o with --unit=sentence-by-*, print only the matching sentences
676
794
  -p print each meaning's probability at the end of the line
677
- --dry-run send nothing; print the endpoint, each file searched and each request with its questions
795
+ --dry-run send nothing; print the settings the search would run with (and their source, when not the
796
+ command line), each file searched and each request with its questions
678
797
  --verbose print the same to stderr while searching
679
798
  -i, --interactive show what --dry-run would send, and search only after y on the terminal
799
+ -M NUM, --max-columns=NUM send at most the first NUM characters of a line (or record, with -z); still
800
+ searched and judged, just not past that cutoff (default 2000, 8000 with -z)
801
+ --max-filesize=SIZE size every target first (K/M/G, default 10M); over it, skip it outright, like rg's own
802
+ --max-filesize (-y does not affect it). stdin is sized once read, and skipped the same way if
803
+ it is over; a --cached / <tree>: target is a blob, sized from its content; -g's commits stay
804
+ out of this (each is already bounded by -M when sent)
805
+ --max-cost=USD price the input about to be sent; over it (default 1), ask to continue on the terminal; -y
806
+ answers yes without asking; no terminal and the limit exceeded is exit 2, unchanged by -q
807
+ (scripts pass -y); -i already asks unconditionally and earlier, so this does not ask again
680
808
  --dedup judge one line per template and reuse its answer for the rest (see "One line per template" above)
681
809
  --color[=WHEN] auto (default: color when stdout is a terminal) / always / never; bare --color means auto
682
810
  file and line number use grep's colors; with -p, probabilities are
@@ -766,14 +894,14 @@ fmt -w 100000 essay.txt | sys1grep -n -e "the author admits they made a mistake"
766
894
 
767
895
  Each output line is then a whole paragraph, and `-n` counts the lines of `fmt`'s output, not of the file.
768
896
  `fmt` puts a space where it joins two Japanese lines; Jev reads through it. To judge sentences across
769
- wrapped lines you need neither: `--sentence` already joins them.
897
+ wrapped lines you need neither: `--unit=sentence-by-jev` already joins them.
770
898
 
771
899
  ### How do I search a JSONL chat log one message at a time?
772
900
 
773
901
  Take the text out with `jq` and end each message with NUL, then judge records with `-z`:
774
902
 
775
903
  ```sh
776
- jq -j '.content + "\u0000"' chat.jsonl | sys1grep -z -n --sentence -e "the customer is asking for a refund" | tr '\0' '\n'
904
+ jq -j '.content + "\u0000"' chat.jsonl | sys1grep -z -n --unit=sentence-by-jev -e "the customer is asking for a refund" | tr '\0' '\n'
777
905
  ```
778
906
 
779
907
  Adjust `.content` to where your log keeps the text. Each message becomes one record, so a sentence never
package/docs/sentence.svg CHANGED
@@ -1,6 +1,6 @@
1
1
  <svg xmlns="http://www.w3.org/2000/svg" width="808" height="240" font-family="SFMono-Regular,Menlo,Consolas,monospace" font-size="13">
2
2
  <rect width="100%" height="100%" rx="6" fill="#1e1e2e"/>
3
- <text x="16" y="29" xml:space="preserve"><tspan fill="#cdd6f4">$ sys1grep -n --sentence -C 3 --color \</tspan></text>
3
+ <text x="16" y="29" xml:space="preserve"><tspan fill="#cdd6f4">$ sys1grep -n --unit=sentence-by-jev -C 3 --color \</tspan></text>
4
4
  <text x="16" y="49" xml:space="preserve"><tspan fill="#cdd6f4"> -e "the author admits they made a mistake" -e "customer is asking for a refund" tests/prose.txt</tspan></text>
5
5
  <text x="16" y="69" xml:space="preserve"><tspan fill="#8ce99a">1</tspan><tspan fill="#66d9e8">:</tspan><tspan fill="#ffd43b" font-weight="700">I should have checked the input</tspan></text>
6
6
  <text x="16" y="89" xml:space="preserve"><tspan fill="#8ce99a">2</tspan><tspan fill="#66d9e8">:</tspan><tspan fill="#ffd43b" font-weight="700">before shipping, and that was my</tspan></text>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uehaj/sys1grep",
3
- "version": "0.5.0-next.0",
3
+ "version": "0.5.0-next.1",
4
4
  "description": "grep by meaning, across languages. TypeSafe Jev scores every line against a meaning; combine meanings with AND/OR/NOT.",
5
5
  "keywords": [
6
6
  "grep",