@webywz/context-diet 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +170 -2
- package/dist/blocks.d.ts +8 -0
- package/dist/blocks.d.ts.map +1 -0
- package/dist/blocks.js +129 -0
- package/dist/blocks.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +149 -0
- package/dist/cli.js.map +1 -0
- package/dist/diet.d.ts +12 -0
- package/dist/diet.d.ts.map +1 -0
- package/dist/diet.js +66 -0
- package/dist/diet.js.map +1 -0
- package/dist/heuristics.d.ts +13 -0
- package/dist/heuristics.d.ts.map +1 -0
- package/dist/heuristics.js +238 -0
- package/dist/heuristics.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/llm.d.ts +12 -0
- package/dist/llm.d.ts.map +1 -0
- package/dist/llm.js +107 -0
- package/dist/llm.js.map +1 -0
- package/dist/package-info.d.ts +5 -0
- package/dist/package-info.d.ts.map +1 -0
- package/dist/package-info.js +13 -0
- package/dist/package-info.js.map +1 -0
- package/dist/parse-args.d.ts +19 -0
- package/dist/parse-args.d.ts.map +1 -0
- package/dist/parse-args.js +172 -0
- package/dist/parse-args.js.map +1 -0
- package/dist/report.d.ts +24 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +56 -0
- package/dist/report.js.map +1 -0
- package/dist/tokens.d.ts +6 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +73 -0
- package/dist/tokens.js.map +1 -0
- package/dist/truncate.d.ts +4 -0
- package/dist/truncate.d.ts.map +1 -0
- package/dist/truncate.js +136 -0
- package/dist/truncate.js.map +1 -0
- package/dist/types.d.ts +48 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 webywz
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,3 +1,171 @@
|
|
|
1
|
-
#
|
|
1
|
+
# context-diet
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Slim LLM context before you send it.** Drop the noise, keep the signal, estimate tokens — locally, offline, in milliseconds.
|
|
4
|
+
|
|
5
|
+
Engineers paste logs, docs, and chat history into models. Most of it is filler: repeated `DEBUG` lines, email signatures, duplicated paragraphs, 4KB of base64. `context-diet` is a small CLI that strips that chrome, optionally fits a token budget, and tells you what it cut.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g @webywz/context-diet
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
context-diet logs.txt --max-tokens 2000 --keep headings|code
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -g @webywz/context-diet
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Node 18+ is required. No tokenizer files, no GPU, no account.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# one-off
|
|
25
|
+
npx @webywz/context-diet --help
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# file → slimmed text on stdout, report on stderr
|
|
32
|
+
context-diet input.txt
|
|
33
|
+
|
|
34
|
+
# stdin
|
|
35
|
+
cat noisy.log | context-diet --max-tokens 1500 > slim.txt
|
|
36
|
+
|
|
37
|
+
# write the body to a file
|
|
38
|
+
context-diet notes.md -o slim.md --keep headings,code,lists
|
|
39
|
+
|
|
40
|
+
# machine-readable
|
|
41
|
+
context-diet input.txt --json | jq '{tokens: .output.tokens, cuts}'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Before / after
|
|
45
|
+
|
|
46
|
+
Input (`examples/noisy.txt`) — repeated logs, a duplicated runbook, a signature, a fat blob:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
[2026-03-14 09:01:02] INFO Starting request handler
|
|
50
|
+
[2026-03-14 09:01:02] DEBUG loading config from /etc/app/config.yaml
|
|
51
|
+
[2026-03-14 09:01:03] DEBUG loading config from /etc/app/config.yaml
|
|
52
|
+
[2026-03-14 09:01:03] DEBUG loading config from /etc/app/config.yaml
|
|
53
|
+
…
|
|
54
|
+
CONFIDENTIALITY NOTICE
|
|
55
|
+
This email is confidential and intended only for the recipient.
|
|
56
|
+
…
|
|
57
|
+
|
|
58
|
+
The deploy runbook covers staging and production.
|
|
59
|
+
The deploy runbook covers staging and production rollouts.
|
|
60
|
+
…
|
|
61
|
+
|
|
62
|
+
Sent from my iPhone
|
|
63
|
+
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAY… (huge)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
context-diet examples/noisy.txt --keep headings|code|lists
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Stderr:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
context-diet 0.1.0
|
|
74
|
+
source: examples/noisy.txt
|
|
75
|
+
chars: 1,666 → 834 (−49.9%)
|
|
76
|
+
tokens: ~667 → ~312 (−53.2%)
|
|
77
|
+
cut:
|
|
78
|
+
ansi sequences 0
|
|
79
|
+
boilerplate lines 9
|
|
80
|
+
duplicate paragraphs 2
|
|
81
|
+
whitespace runs 5
|
|
82
|
+
omitted heavy blobs 1
|
|
83
|
+
truncated blocks 0
|
|
84
|
+
truncated tokens ~0
|
|
85
|
+
llm deepen no
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Stdout keeps the redis error, the unique runbook facts, the rollback list, and the `healthz` fence — not the fourth identical `DEBUG` line, not the iPhone signature, not the blob.
|
|
89
|
+
|
|
90
|
+
## What it does
|
|
91
|
+
|
|
92
|
+
All of this is **offline heuristics**. No network unless you pass `--deepen`.
|
|
93
|
+
|
|
94
|
+
| Step | Behavior |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| Strip ANSI | Terminal color / OSC sequences |
|
|
97
|
+
| Omit heavy blobs | Long base64 / data-URIs → `[omitted blob: N chars]` |
|
|
98
|
+
| Collapse whitespace | Trailing space, squeezed blanks — **never inside code fences** |
|
|
99
|
+
| Drop boilerplate | Repeated log lines (timestamps/UUIDs normalized), signatures, `DEBUG` chrome, horizontal rules |
|
|
100
|
+
| Dedupe paragraphs | Exact and near-identical (Jaccard ≥ 0.87) prose/list blocks |
|
|
101
|
+
| Truncate | `--max-tokens N` drops low-value blocks first; `--keep headings\|code\|lists` pins those types |
|
|
102
|
+
|
|
103
|
+
Token estimates are **cl100k-ish** (GPT-4 family grain: ~4 chars/word, 1 CJK char ≈ 1 token, punctuation is dense). Good enough to budget a prompt. Not a billed tokenizer — do not invoice with it.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
context-diet [file] [options]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
| Flag | Meaning |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `[file]` | Path to read. Omit or pass `-` to read stdin |
|
|
114
|
+
| `-o, --output <file>` | Write slimmed text here instead of stdout |
|
|
115
|
+
| `--max-tokens <n>` | Cap estimated output tokens |
|
|
116
|
+
| `--keep <cats>` | Prefer `headings`, `code`, `lists` when truncating (comma or `\|`) |
|
|
117
|
+
| `--json` | JSON report on stdout (includes `text`, unless `-o` was set) |
|
|
118
|
+
| `--deepen` | Optional LLM rewrite (see below) |
|
|
119
|
+
| `--provider openai\|anthropic` | Force a provider for `--deepen` |
|
|
120
|
+
| `-q, --quiet` | No human report on stderr |
|
|
121
|
+
| `-h, --help` | Help |
|
|
122
|
+
| `-V, --version` | Version |
|
|
123
|
+
|
|
124
|
+
Default I/O: **slimmed body on stdout**, **human report on stderr**, so this stays pipe-friendly:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
pbpaste | context-diet --max-tokens 800 --keep code | pbcopy
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Optional LLM pass
|
|
131
|
+
|
|
132
|
+
`--deepen` is **never required**. If you already have a key and want a second squeeze after the local diet:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
export OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY
|
|
136
|
+
context-diet chapter.md --deepen --max-tokens 1200
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Defaults: `gpt-4o-mini` / `claude-3-5-haiku-20241022` (override with `OPENAI_MODEL` or `ANTHROPIC_MODEL`). The local result wins if the model comes back *longer*. Without a key, `--deepen` exits `2` with a clear message and does not phone home.
|
|
140
|
+
|
|
141
|
+
## Library
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { diet, dietAsync, estimateTokens } from "@webywz/context-diet";
|
|
145
|
+
|
|
146
|
+
const { text, input, output, cuts } = diet(raw, {
|
|
147
|
+
maxTokens: 2000,
|
|
148
|
+
keep: ["headings", "code"],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await dietAsync(raw, { deepen: true }); // keys from process.env
|
|
152
|
+
estimateTokens(text); // cl100k-ish heuristic
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Exit codes
|
|
156
|
+
|
|
157
|
+
| Code | Meaning |
|
|
158
|
+
| --- | --- |
|
|
159
|
+
| 0 | Success |
|
|
160
|
+
| 1 | Usage / missing input / unreadable file |
|
|
161
|
+
| 2 | `--deepen` failed (no key, HTTP error) |
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
npm test
|
|
167
|
+
npm run build
|
|
168
|
+
node dist/cli.js --help
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
MIT © webywz
|
package/dist/blocks.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type BlockType = "code" | "heading" | "list" | "paragraph" | "blank" | "rule";
|
|
2
|
+
export interface Block {
|
|
3
|
+
type: BlockType;
|
|
4
|
+
raw: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function parseBlocks(text: string): Block[];
|
|
7
|
+
export declare function joinBlocks(blocks: Block[]): string;
|
|
8
|
+
//# sourceMappingURL=blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,SAAS,GACT,MAAM,GACN,WAAW,GACX,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;CACb;AAuBD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CA4GjD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAOlD"}
|
package/dist/blocks.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const FENCE_RE = /^ {0,3}(`{3,}|~{3,})(.*)$/;
|
|
2
|
+
const ATX_RE = /^ {0,3}#{1,6}(?:\s+\S|\s*$)/;
|
|
3
|
+
const RULE_RE = /^ {0,3}(?:(?:-[\t ]*){3,}|(?:_[\t ]*){3,}|(?:\*[\t ]*){3,})\s*$/;
|
|
4
|
+
const LIST_RE = /^ {0,3}(?:[-+*]|\d{1,9}[.)])\s+\S/;
|
|
5
|
+
const SETEXT_RE = /^ {0,3}(=+|-+)\s*$/;
|
|
6
|
+
function isSetextUnderline(line, heading) {
|
|
7
|
+
if (!SETEXT_RE.test(line))
|
|
8
|
+
return false;
|
|
9
|
+
const mark = line.trim();
|
|
10
|
+
// Long runs of =/- are banners, not Setext underlines.
|
|
11
|
+
if (mark.length > 40)
|
|
12
|
+
return false;
|
|
13
|
+
if (heading.trim().length > 80)
|
|
14
|
+
return false;
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
function fenceCloser(opener) {
|
|
18
|
+
const ch = opener[0] === "~" ? "~" : "`";
|
|
19
|
+
const n = opener.length;
|
|
20
|
+
return new RegExp(`^ {0,3}${ch}{${n},}\\s*$`);
|
|
21
|
+
}
|
|
22
|
+
export function parseBlocks(text) {
|
|
23
|
+
const lines = text.split("\n");
|
|
24
|
+
const blocks = [];
|
|
25
|
+
let i = 0;
|
|
26
|
+
const push = (type, chunk) => {
|
|
27
|
+
if (chunk.length === 0)
|
|
28
|
+
return;
|
|
29
|
+
blocks.push({ type, raw: chunk.join("\n") });
|
|
30
|
+
};
|
|
31
|
+
while (i < lines.length) {
|
|
32
|
+
const line = lines[i];
|
|
33
|
+
const fence = FENCE_RE.exec(line);
|
|
34
|
+
if (fence) {
|
|
35
|
+
const marker = fence[1];
|
|
36
|
+
const chunk = [line];
|
|
37
|
+
i++;
|
|
38
|
+
const closer = fenceCloser(marker);
|
|
39
|
+
while (i < lines.length) {
|
|
40
|
+
chunk.push(lines[i]);
|
|
41
|
+
const isClose = closer.test(lines[i]);
|
|
42
|
+
i++;
|
|
43
|
+
if (isClose)
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
push("code", chunk);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (line.trim() === "") {
|
|
50
|
+
const chunk = [line];
|
|
51
|
+
i++;
|
|
52
|
+
while (i < lines.length && lines[i].trim() === "") {
|
|
53
|
+
chunk.push(lines[i]);
|
|
54
|
+
i++;
|
|
55
|
+
}
|
|
56
|
+
push("blank", chunk);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (RULE_RE.test(line)) {
|
|
60
|
+
blocks.push({ type: "rule", raw: line });
|
|
61
|
+
i++;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (ATX_RE.test(line)) {
|
|
65
|
+
blocks.push({ type: "heading", raw: line });
|
|
66
|
+
i++;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (i + 1 < lines.length &&
|
|
70
|
+
line.trim() !== "" &&
|
|
71
|
+
!LIST_RE.test(line) &&
|
|
72
|
+
isSetextUnderline(lines[i + 1], line)) {
|
|
73
|
+
blocks.push({ type: "heading", raw: `${line}\n${lines[i + 1]}` });
|
|
74
|
+
i += 2;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (LIST_RE.test(line)) {
|
|
78
|
+
const chunk = [line];
|
|
79
|
+
i++;
|
|
80
|
+
while (i < lines.length) {
|
|
81
|
+
const next = lines[i];
|
|
82
|
+
if (next.trim() === "")
|
|
83
|
+
break;
|
|
84
|
+
if (FENCE_RE.test(next) || ATX_RE.test(next) || RULE_RE.test(next))
|
|
85
|
+
break;
|
|
86
|
+
if (LIST_RE.test(next) || /^\s+\S/.test(next)) {
|
|
87
|
+
chunk.push(next);
|
|
88
|
+
i++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
push("list", chunk);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const chunk = [line];
|
|
97
|
+
i++;
|
|
98
|
+
while (i < lines.length) {
|
|
99
|
+
const next = lines[i];
|
|
100
|
+
if (next.trim() === "")
|
|
101
|
+
break;
|
|
102
|
+
if (FENCE_RE.test(next) ||
|
|
103
|
+
ATX_RE.test(next) ||
|
|
104
|
+
RULE_RE.test(next) ||
|
|
105
|
+
LIST_RE.test(next)) {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
if (i + 1 < lines.length &&
|
|
109
|
+
next.trim() !== "" &&
|
|
110
|
+
isSetextUnderline(lines[i + 1], next)) {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
chunk.push(next);
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
push("paragraph", chunk);
|
|
117
|
+
}
|
|
118
|
+
return blocks;
|
|
119
|
+
}
|
|
120
|
+
export function joinBlocks(blocks) {
|
|
121
|
+
const chunks = blocks
|
|
122
|
+
.filter((b) => b.type !== "blank")
|
|
123
|
+
.map((b) => b.raw.replace(/[ \t]+$/gm, "").trimEnd())
|
|
124
|
+
.filter((s) => s.length > 0);
|
|
125
|
+
if (chunks.length === 0)
|
|
126
|
+
return "";
|
|
127
|
+
return `${chunks.join("\n\n")}\n`;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../src/blocks.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
export interface Io {
|
|
3
|
+
stdin: NodeJS.ReadableStream;
|
|
4
|
+
stdout: NodeJS.WritableStream;
|
|
5
|
+
stderr: NodeJS.WritableStream;
|
|
6
|
+
stdinIsTTY: boolean | undefined;
|
|
7
|
+
env: NodeJS.ProcessEnv;
|
|
8
|
+
readFile: (path: string) => Promise<string>;
|
|
9
|
+
writeFile: (path: string, contents: string) => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function run(argv: string[], io?: Io): Promise<number>;
|
|
12
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAWA,MAAM,WAAW,EAAE;IACjB,KAAK,EAAE,MAAM,CAAC,cAAc,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,cAAc,CAAC;IAC9B,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9D;AAqDD,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,EAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0E/E"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { dietAsync } from "./diet.js";
|
|
7
|
+
import { DeepenError } from "./llm.js";
|
|
8
|
+
import { packageInfo } from "./package-info.js";
|
|
9
|
+
import { HELP_TEXT, parseArgs, UsageError } from "./parse-args.js";
|
|
10
|
+
import { formatHumanReport, toJsonReport } from "./report.js";
|
|
11
|
+
const defaultIo = () => ({
|
|
12
|
+
stdin: process.stdin,
|
|
13
|
+
stdout: process.stdout,
|
|
14
|
+
stderr: process.stderr,
|
|
15
|
+
stdinIsTTY: process.stdin.isTTY,
|
|
16
|
+
env: process.env,
|
|
17
|
+
readFile: (path) => readFile(path, "utf8"),
|
|
18
|
+
writeFile: (path, contents) => writeFile(path, contents, "utf8"),
|
|
19
|
+
});
|
|
20
|
+
function readStream(stream) {
|
|
21
|
+
return new Promise((resolve, reject) => {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
stream.on("data", (c) => {
|
|
24
|
+
chunks.push(typeof c === "string" ? Buffer.from(c) : c);
|
|
25
|
+
});
|
|
26
|
+
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
|
|
27
|
+
stream.on("error", reject);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function readInput(args, io) {
|
|
31
|
+
if (args.file && args.file !== "-") {
|
|
32
|
+
try {
|
|
33
|
+
const text = await io.readFile(args.file);
|
|
34
|
+
return { text, source: args.file };
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
throw new UsageError(`Cannot read ${args.file}: ${msg}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const useStdin = !args.file || args.file === "-";
|
|
42
|
+
if (useStdin && io.stdinIsTTY) {
|
|
43
|
+
throw new UsageError("No input. Pass a file path, pipe stdin, or use `-` with redirected input.");
|
|
44
|
+
}
|
|
45
|
+
const text = await readStream(io.stdin);
|
|
46
|
+
return { text, source: "stdin" };
|
|
47
|
+
}
|
|
48
|
+
function writeOut(stream, chunk) {
|
|
49
|
+
return new Promise((resolveWrite, reject) => {
|
|
50
|
+
stream.write(chunk, "utf8", (err) => {
|
|
51
|
+
if (err)
|
|
52
|
+
reject(err);
|
|
53
|
+
else
|
|
54
|
+
resolveWrite();
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export async function run(argv, io = defaultIo()) {
|
|
59
|
+
let args;
|
|
60
|
+
try {
|
|
61
|
+
args = parseArgs(argv);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (err instanceof UsageError) {
|
|
65
|
+
await writeOut(io.stderr, `${err.message}\n\n${HELP_TEXT}`);
|
|
66
|
+
return 1;
|
|
67
|
+
}
|
|
68
|
+
throw err;
|
|
69
|
+
}
|
|
70
|
+
const { version } = packageInfo();
|
|
71
|
+
if (args.help) {
|
|
72
|
+
await writeOut(io.stdout, HELP_TEXT);
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
if (args.version) {
|
|
76
|
+
await writeOut(io.stdout, `${version}\n`);
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
79
|
+
let source;
|
|
80
|
+
let text;
|
|
81
|
+
try {
|
|
82
|
+
const input = await readInput(args, io);
|
|
83
|
+
source = input.source;
|
|
84
|
+
text = input.text;
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if (err instanceof UsageError) {
|
|
88
|
+
await writeOut(io.stderr, `${err.message}\n`);
|
|
89
|
+
return 1;
|
|
90
|
+
}
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
let result;
|
|
94
|
+
try {
|
|
95
|
+
result = await dietAsync(text, {
|
|
96
|
+
maxTokens: args.maxTokens,
|
|
97
|
+
keep: args.keep,
|
|
98
|
+
deepen: args.deepen,
|
|
99
|
+
provider: args.provider,
|
|
100
|
+
env: io.env,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
if (err instanceof DeepenError) {
|
|
105
|
+
await writeOut(io.stderr, `${err.message}\n`);
|
|
106
|
+
return 2;
|
|
107
|
+
}
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
const json = toJsonReport(result, source);
|
|
111
|
+
if (args.output) {
|
|
112
|
+
await io.writeFile(args.output, result.text);
|
|
113
|
+
}
|
|
114
|
+
if (args.json) {
|
|
115
|
+
const payload = args.output ? { ...json, text: undefined, outputPath: args.output } : json;
|
|
116
|
+
await writeOut(io.stdout, `${JSON.stringify(payload, null, 2)}\n`);
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
if (!args.output) {
|
|
120
|
+
await writeOut(io.stdout, result.text);
|
|
121
|
+
}
|
|
122
|
+
if (!args.quiet) {
|
|
123
|
+
await writeOut(io.stderr, formatHumanReport(result, source, version));
|
|
124
|
+
}
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
function isMainModule() {
|
|
128
|
+
const entry = process.argv[1];
|
|
129
|
+
if (!entry)
|
|
130
|
+
return false;
|
|
131
|
+
try {
|
|
132
|
+
const self = fileURLToPath(import.meta.url);
|
|
133
|
+
const resolved = isAbsolute(entry) ? entry : resolve(entry);
|
|
134
|
+
return self === resolved;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (isMainModule()) {
|
|
141
|
+
run(process.argv.slice(2)).then((code) => {
|
|
142
|
+
process.exitCode = code;
|
|
143
|
+
}, (err) => {
|
|
144
|
+
const msg = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
145
|
+
process.stderr.write(`${msg}\n`);
|
|
146
|
+
process.exitCode = 1;
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/diet.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DietOptions, type DietResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Offline diet: strip chrome, collapse whitespace, dedupe near-identical
|
|
4
|
+
* paragraphs, and optionally truncate to a token budget.
|
|
5
|
+
*/
|
|
6
|
+
export declare function diet(text: string, options?: DietOptions): DietResult;
|
|
7
|
+
/**
|
|
8
|
+
* Same as {@link diet}, then optionally asks OpenAI/Anthropic to compress
|
|
9
|
+
* further. Keys are never required; pass `deepen: true` to opt in.
|
|
10
|
+
*/
|
|
11
|
+
export declare function dietAsync(text: string, options?: DietOptions): Promise<DietResult>;
|
|
12
|
+
//# sourceMappingURL=diet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diet.d.ts","sourceRoot":"","sources":["../src/diet.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAiCpB;;;GAGG;AACH,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,UAAU,CAKxE;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAsBrB"}
|
package/dist/diet.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { joinBlocks, parseBlocks } from "./blocks.js";
|
|
2
|
+
import { omitHeavyBlobs, stripAnsi, tidy, } from "./heuristics.js";
|
|
3
|
+
import { deepenText } from "./llm.js";
|
|
4
|
+
import { snapshot } from "./tokens.js";
|
|
5
|
+
import { truncateToBudget } from "./truncate.js";
|
|
6
|
+
import { emptyCuts, } from "./types.js";
|
|
7
|
+
function localDiet(text, options) {
|
|
8
|
+
const cuts = emptyCuts();
|
|
9
|
+
const input = snapshot(text);
|
|
10
|
+
let next = stripAnsi(text, cuts);
|
|
11
|
+
next = omitHeavyBlobs(next, cuts);
|
|
12
|
+
next = tidy(next, cuts);
|
|
13
|
+
if (options.maxTokens && options.maxTokens > 0) {
|
|
14
|
+
const blocks = parseBlocks(next);
|
|
15
|
+
const trimmed = truncateToBudget(blocks, options.maxTokens, options.keep ?? [], cuts);
|
|
16
|
+
next = joinBlocks(trimmed);
|
|
17
|
+
}
|
|
18
|
+
// Final trailing-newline hygiene.
|
|
19
|
+
next = next.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
20
|
+
if (next.length > 0 && !next.endsWith("\n"))
|
|
21
|
+
next += "\n";
|
|
22
|
+
return {
|
|
23
|
+
text: next,
|
|
24
|
+
input,
|
|
25
|
+
output: snapshot(next),
|
|
26
|
+
cuts,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Offline diet: strip chrome, collapse whitespace, dedupe near-identical
|
|
31
|
+
* paragraphs, and optionally truncate to a token budget.
|
|
32
|
+
*/
|
|
33
|
+
export function diet(text, options = {}) {
|
|
34
|
+
return localDiet(text, {
|
|
35
|
+
maxTokens: options.maxTokens,
|
|
36
|
+
keep: options.keep,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Same as {@link diet}, then optionally asks OpenAI/Anthropic to compress
|
|
41
|
+
* further. Keys are never required; pass `deepen: true` to opt in.
|
|
42
|
+
*/
|
|
43
|
+
export async function dietAsync(text, options = {}) {
|
|
44
|
+
const local = localDiet(text, options);
|
|
45
|
+
if (!options.deepen)
|
|
46
|
+
return local;
|
|
47
|
+
const deepened = await deepenText(local.text, {
|
|
48
|
+
provider: options.provider,
|
|
49
|
+
env: options.env,
|
|
50
|
+
fetch: options.fetch,
|
|
51
|
+
});
|
|
52
|
+
// Keep whichever version is actually smaller; models sometimes ramble.
|
|
53
|
+
const localTokens = local.output.tokens;
|
|
54
|
+
const deepTokens = snapshot(deepened).tokens;
|
|
55
|
+
if (deepTokens >= localTokens) {
|
|
56
|
+
return { ...local, cuts: { ...local.cuts, deepened: true } };
|
|
57
|
+
}
|
|
58
|
+
const textOut = deepened.endsWith("\n") ? deepened : `${deepened}\n`;
|
|
59
|
+
return {
|
|
60
|
+
text: textOut,
|
|
61
|
+
input: local.input,
|
|
62
|
+
output: snapshot(textOut),
|
|
63
|
+
cuts: { ...local.cuts, deepened: true },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=diet.js.map
|
package/dist/diet.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diet.js","sourceRoot":"","sources":["../src/diet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Block } from "./blocks.js";
|
|
2
|
+
import type { CutCounts } from "./types.js";
|
|
3
|
+
export declare function stripAnsi(text: string, cuts: CutCounts): string;
|
|
4
|
+
export declare function omitHeavyBlobs(text: string, cuts: CutCounts): string;
|
|
5
|
+
export declare function collapseBlankBlocks(blocks: Block[], cuts: CutCounts): Block[];
|
|
6
|
+
/**
|
|
7
|
+
* Drop repeated log/chrome lines and known signatures, keeping the first few
|
|
8
|
+
* occurrences so the pattern is still visible.
|
|
9
|
+
*/
|
|
10
|
+
export declare function stripBoilerplate(blocks: Block[], cuts: CutCounts): Block[];
|
|
11
|
+
export declare function dedupeParagraphs(blocks: Block[], cuts: CutCounts): Block[];
|
|
12
|
+
export declare function tidy(text: string, cuts: CutCounts): string;
|
|
13
|
+
//# sourceMappingURL=heuristics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heuristics.d.ts","sourceRoot":"","sources":["../src/heuristics.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AA0B5C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAQ/D;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAepE;AAeD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,CAsB7E;AAgCD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,CAiD1E;AAyBD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,KAAK,EAAE,CAyC1E;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,MAAM,CAQ1D"}
|