token-goat 2.9.13 → 2.9.14

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 (44) hide show
  1. package/README.md +13 -0
  2. package/dist/token-goat-chunk-2ESBO4IN.mjs +209 -0
  3. package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
  4. package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-3XQPEJMV.mjs} +1 -1
  5. package/dist/token-goat-chunk-4SDX3QP3.mjs +122 -0
  6. package/dist/token-goat-chunk-7OGKZ7AP.mjs +142 -0
  7. package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
  8. package/dist/token-goat-chunk-AMYCQJX4.mjs +1548 -0
  9. package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-ASVVF4JV.mjs} +10 -7
  10. package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-DAMXYVIW.mjs} +12026 -11796
  11. package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-DBNY4RLN.mjs} +2 -2
  12. package/dist/token-goat-chunk-EG3663UT.mjs +226 -0
  13. package/dist/token-goat-chunk-EZNVAIR3.mjs +21 -0
  14. package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
  15. package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-HF6H7RNK.mjs} +1 -1
  16. package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-IT6O3PNN.mjs} +2874 -7088
  17. package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
  18. package/dist/token-goat-chunk-O5WAMISC.mjs +167 -0
  19. package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-PGGDW7DZ.mjs} +28 -13
  20. package/dist/token-goat-chunk-POBYR64E.mjs +1632 -0
  21. package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-PRJVGIC5.mjs} +6 -4
  22. package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-RUDOKYPJ.mjs} +10160 -10053
  23. package/dist/token-goat-chunk-SAQ5PG4L.mjs +2634 -0
  24. package/dist/{token-goat-chunk-UMXJN7DI.mjs → token-goat-chunk-T2IWWTHB.mjs} +288 -2654
  25. package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-VZYD4OZB.mjs} +1164 -92
  26. package/dist/token-goat-chunk-XEH6KBWW.mjs +23 -0
  27. package/dist/token-goat-chunk-XQF5J25J.mjs +33 -0
  28. package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
  29. package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-XVZ4MNQC.mjs} +587 -587
  30. package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
  31. package/dist/token-goat-chunk-YHGTGG6K.mjs +396 -0
  32. package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-YTQHZJXW.mjs} +20 -11
  33. package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
  34. package/dist/token-goat-chunk-ZD4EM4LR.mjs +30 -0
  35. package/dist/token-goat-chunk-ZFM4PWXL.mjs +585 -0
  36. package/dist/{token-goat-chunk-FQCNJV4V.mjs → token-goat-chunk-ZYNNQ36L.mjs} +116 -330
  37. package/dist/token-goat-hook.mjs +12 -8
  38. package/dist/token-goat.core.mjs +22 -10
  39. package/docs/cli.md +1 -0
  40. package/package.json +4 -2
  41. package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
  42. package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
  43. package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
  44. package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
package/README.md CHANGED
@@ -298,6 +298,15 @@ Built-in output compression covers 150+ dev tool CLIs: `pytest`, `jest` / `vites
298
298
 
299
299
  A failing `pytest` / `jest` / `vitest` / `go test` / `cargo test` run (including bare `npm test`/`npm run test`/`yarn test`/`pnpm test`) also gets a one-line advisory naming the exact `token-goat bash-output <id> | token-goat failures` command to run instead of re-reading the raw dump. Silent on a passing run, a non-test command, or output too small to be worth reducing.
300
300
 
301
+ Give the command three ways: as positional arguments (`token-goat compress pytest -v tests/`), as one string with `-c` / `--cmd`, or base64-encoded with `--cmd-b64`. The base64 form preserves quotes, backslashes, and dollar signs that a harness or an intermediate shell would otherwise mangle; it takes precedence when more than one form is supplied. `--native` runs the command through the platform's own shell (`cmd.exe` on Windows) instead of bash, which keeps Windows path backslashes intact for tools that reject the forward-slash form.
302
+
303
+ `-q` / `--quiet-success` trades a clean run's output for one line. On exit code 0 the full output is stored for recall and only the summary prints; on any other exit code the compressed output is delivered as usual.
304
+
305
+ ```
306
+ $ token-goat compress -q --cmd "npm run lint"
307
+ [tg: ok] npm run lint (22.2s, recall: token-goat bash-output 326d9800e732eb9d)
308
+ ```
309
+
301
310
  ### 6. Context pressure
302
311
 
303
312
  Token-goat tracks how close a session is to the autocompact trigger and tightens its hints as the window fills. Surgical-read suggestions kick in on progressively smaller files as pressure builds (500 lines at cool, down to 50 at critical), so large reads get flagged before they tip the session over. The PreCompact manifest also shrinks: capped at 500 tokens once the window runs hot, 300 once critical, so it stops contributing to the pressure it measures. The denominator is always the fixed 660,000-token autocompact trigger budget, not the model's raw context window, so the same thresholds apply across models. Run `token-goat doctor --context` to see the current footprint.
@@ -478,6 +487,8 @@ The file-by-file table for each harness, and the path that file sits at: **[What
478
487
 
479
488
  Hooks fire automatically on every tool call once installed — nothing to start or restart there. The background worker is a separate, manual step: `token-goat worker start` launches it as a detached process, `token-goat worker status` checks it, `token-goat worker stop` kills it. It restarts itself automatically if it crashes or gets killed while the machine is running — an edit hook checks its liveness and respawns it, rate-limited to about once every 5 minutes. It does not survive a reboot or logout, though; re-run `worker start` after either. `token-goat uninstall` removes the hook entries, `CLAUDE.md` block, and skill directory, but does not touch a running worker — stop it separately with `token-goat worker stop` if you no longer want it running.
480
489
 
490
+ To move to a newer release, `token-goat upgrade` installs it from npm and then re-runs `token-goat install`, so your hooks and integration manifests point at the build that just landed. `token-goat upgrade --check` reports whether one is available without installing anything, and `--json` gives the same answer for a script. Both go quiet when `network.offline` is set, and `token-goat doctor` mentions an available update at the end of its report.
491
+
481
492
  ## Verify
482
493
 
483
494
  ```
@@ -701,6 +712,8 @@ Bug reports go to the same place. The most useful ones include:
701
712
  - The matching log line from `%LOCALAPPDATA%\dfk-helper\token-goat\logs\` on Windows or `~/.local/share/token-goat/logs/` on Linux/WSL
702
713
  - What you expected and what actually happened
703
714
 
715
+ To audit an existing AI session for missed savings, hook friction, or optimization opportunities before opening an issue, see the [Session Mining Prompt](docs/PROMPT_SESSION_MINING.md).
716
+
704
717
  For private questions, commercial licensing, or anything you'd rather not post publicly, contact me at token-goat@dfkhelper.com.
705
718
 
706
719
  ## Disclaimer
@@ -0,0 +1,209 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ NotAnOfficeDocumentError,
5
+ assertOoxmlWithinDeadline,
6
+ collectElements,
7
+ collectTextRuns,
8
+ decodeZipEntry,
9
+ ooxmlPartBudget,
10
+ ooxmlWorkDeadline,
11
+ parseOoxmlPart,
12
+ readOoxmlZip,
13
+ sortNumberedParts
14
+ } from "./token-goat-chunk-YHGTGG6K.mjs";
15
+ import {
16
+ compileGuardedRegex
17
+ } from "./token-goat-chunk-GMOUBOX4.mjs";
18
+ import {
19
+ init_define_import_meta_env
20
+ } from "./token-goat-chunk-A37V4PBF.mjs";
21
+
22
+ // src/pptx_extract.ts
23
+ init_define_import_meta_env();
24
+ function shapePlaceholderType(shape) {
25
+ const sp = shape;
26
+ return sp["p:nvSpPr"]?.["p:nvPr"]?.["p:ph"]?.["@_type"];
27
+ }
28
+ function slideShapes(parsedSlide) {
29
+ return collectElements(parsedSlide, "p:sp");
30
+ }
31
+ function shapeText(shape) {
32
+ return collectTextRuns(shape, "a:t").join(" ").trim();
33
+ }
34
+ function tableRowBlocks(parsedSlide) {
35
+ const blocks = [];
36
+ for (const tbl of collectElements(parsedSlide, "a:tbl")) {
37
+ for (const row of collectElements(tbl, "a:tr")) {
38
+ const cellTexts = collectElements(row, "a:tc").map((cell) => collectTextRuns(cell, "a:t").join(" ").trim());
39
+ const rowText = cellTexts.join(" | ").trim();
40
+ if (rowText.length > 0) blocks.push(rowText);
41
+ }
42
+ }
43
+ return blocks;
44
+ }
45
+ async function slidePathsInPresentationOrder(entries, budget) {
46
+ const presXml = decodeZipEntry(entries, "ppt/presentation.xml", budget);
47
+ const relsXml = decodeZipEntry(entries, "ppt/_rels/presentation.xml.rels", budget);
48
+ if (presXml === null || relsXml === null) return null;
49
+ const presParsed = await parseOoxmlPart(presXml);
50
+ const relsParsed = await parseOoxmlPart(relsXml);
51
+ const ridToTarget = /* @__PURE__ */ new Map();
52
+ for (const rel of collectElements(relsParsed, "Relationship")) {
53
+ if (rel["@_Id"] !== void 0 && rel["@_Target"] !== void 0) {
54
+ ridToTarget.set(rel["@_Id"], rel["@_Target"]);
55
+ }
56
+ }
57
+ const ordered = [];
58
+ const seen = /* @__PURE__ */ new Set();
59
+ for (const sldId of collectElements(presParsed, "p:sldId")) {
60
+ const rid = sldId["@_r:id"];
61
+ if (rid === void 0) continue;
62
+ const target = ridToTarget.get(rid);
63
+ if (target === void 0) continue;
64
+ const normalized = target.startsWith("slides/") ? `ppt/${target}` : `ppt/slides/${target}`;
65
+ if (entries[normalized] === void 0 || seen.has(normalized)) continue;
66
+ seen.add(normalized);
67
+ ordered.push(normalized);
68
+ }
69
+ return ordered.length > 0 ? ordered : null;
70
+ }
71
+ async function listSlideParts(filePath) {
72
+ const entries = await readOoxmlZip(filePath, ".pptx");
73
+ const budget = ooxmlPartBudget();
74
+ const slidePaths = await slidePathsInPresentationOrder(entries, budget) ?? sortNumberedParts(
75
+ Object.keys(entries).filter((p) => /^ppt\/slides\/slide\d+\.xml$/.test(p)),
76
+ /slide(\d+)\.xml$/
77
+ );
78
+ if (slidePaths.length === 0) throw new NotAnOfficeDocumentError(`no slides found in ${filePath} (not a valid .pptx?)`);
79
+ return { entries, slidePaths, budget };
80
+ }
81
+ function relsPathFor(slidePath) {
82
+ const idx = slidePath.lastIndexOf("/");
83
+ return `${slidePath.slice(0, idx)}/_rels/${slidePath.slice(idx + 1)}.rels`;
84
+ }
85
+ function resolveRelativeTarget(basePath, target) {
86
+ const baseDir = basePath.slice(0, basePath.lastIndexOf("/"));
87
+ const segments = `${baseDir}/${target}`.split("/");
88
+ const resolved = [];
89
+ for (const segment of segments) {
90
+ if (segment === "" || segment === ".") continue;
91
+ if (segment === "..") resolved.pop();
92
+ else resolved.push(segment);
93
+ }
94
+ return resolved.join("/");
95
+ }
96
+ async function notesPathFor(entries, slidePath, budget) {
97
+ const relsXml = decodeZipEntry(entries, relsPathFor(slidePath), budget);
98
+ if (relsXml === null) return null;
99
+ const relsParsed = await parseOoxmlPart(relsXml);
100
+ for (const rel of collectElements(relsParsed, "Relationship")) {
101
+ if (rel["@_Target"] !== void 0 && rel["@_Type"]?.endsWith("/notesSlide") === true) {
102
+ return resolveRelativeTarget(slidePath, rel["@_Target"]);
103
+ }
104
+ }
105
+ return null;
106
+ }
107
+ async function parseSlide(entries, path, budget) {
108
+ const xml = decodeZipEntry(entries, path, budget);
109
+ if (xml === null) throw new Error(`missing part: ${path}`);
110
+ return parseOoxmlPart(xml);
111
+ }
112
+ async function notesTextFor(entries, notesPath, budget) {
113
+ if (notesPath === null) return "";
114
+ const xml = decodeZipEntry(entries, notesPath, budget);
115
+ if (xml === null) return "";
116
+ const parsed = await parseOoxmlPart(xml);
117
+ const shapes = collectElements(parsed, "p:sp");
118
+ const bodyShape = shapes.find((s) => shapePlaceholderType(s) === "body");
119
+ return bodyShape !== void 0 ? shapeText(bodyShape) : collectTextRuns(parsed, "a:t").join(" ").trim();
120
+ }
121
+ async function pptxOutline(filePath, deadline = ooxmlWorkDeadline()) {
122
+ const { entries, slidePaths, budget } = await listSlideParts(filePath);
123
+ const out = [];
124
+ for (let i = 0; i < slidePaths.length; i++) {
125
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific slides with pptx-slide, or use a smaller deck.");
126
+ const path = slidePaths[i];
127
+ const parsed = await parseSlide(entries, path, budget);
128
+ const shapes = slideShapes(parsed);
129
+ const titleShape = shapes.find((s) => {
130
+ const t = shapePlaceholderType(s);
131
+ return t === "title" || t === "ctrTitle";
132
+ });
133
+ const title = titleShape !== void 0 ? shapeText(titleShape) : "";
134
+ const allText = collectTextRuns(parsed, "a:t").join(" ");
135
+ const bodyChars = Math.max(0, allText.length - title.length);
136
+ const hasNotes = (await notesTextFor(entries, await notesPathFor(entries, path, budget), budget)).length > 0;
137
+ out.push({ slide: i + 1, title, bodyChars, hasNotes });
138
+ }
139
+ return out;
140
+ }
141
+ async function slideTextFromParts(entries, slidePaths, slideNumber, includeNotes, budget) {
142
+ if (slideNumber < 1 || slideNumber > slidePaths.length) {
143
+ throw new Error(`slide ${slideNumber} out of range (this deck has ${slidePaths.length} slides)`);
144
+ }
145
+ const path = slidePaths[slideNumber - 1];
146
+ const parsed = await parseSlide(entries, path, budget);
147
+ const shapes = slideShapes(parsed);
148
+ const blocks = [...shapes.map(shapeText).filter((t) => t.length > 0), ...tableRowBlocks(parsed)];
149
+ const lines = [`# Slide ${slideNumber}`, ...blocks];
150
+ if (includeNotes) {
151
+ const notes = await notesTextFor(entries, await notesPathFor(entries, path, budget), budget);
152
+ if (notes.length > 0) lines.push("", "## Speaker notes", notes);
153
+ }
154
+ return lines.join("\n\n");
155
+ }
156
+ async function pptxSlideText(filePath, slideNumber, includeNotes) {
157
+ const { entries, slidePaths, budget } = await listSlideParts(filePath);
158
+ return slideTextFromParts(entries, slidePaths, slideNumber, includeNotes, budget);
159
+ }
160
+ async function pptxAllSlidesText(filePath, includeNotes, deadline = ooxmlWorkDeadline()) {
161
+ const { entries, slidePaths, budget } = await listSlideParts(filePath);
162
+ const slideTexts = [];
163
+ for (let i = 1; i <= slidePaths.length; i++) {
164
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific slides with pptx-slide, or use a smaller deck.");
165
+ slideTexts.push(await slideTextFromParts(entries, slidePaths, i, includeNotes, budget));
166
+ }
167
+ return slideTexts.join("\n\n");
168
+ }
169
+ async function pptxNotesText(filePath, slideNumber, deadline = ooxmlWorkDeadline()) {
170
+ const { entries, slidePaths, budget } = await listSlideParts(filePath);
171
+ const targets = slideNumber !== void 0 ? [slideNumber] : slidePaths.map((_, i) => i + 1);
172
+ const sections = [];
173
+ for (const n of targets) {
174
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to one slide with the slide-number argument, or use a smaller deck.");
175
+ if (n < 1 || n > slidePaths.length) throw new Error(`slide ${n} out of range (this deck has ${slidePaths.length} slides)`);
176
+ const notesPath = await notesPathFor(entries, slidePaths[n - 1], budget);
177
+ const text = await notesTextFor(entries, notesPath, budget);
178
+ if (text.length > 0) sections.push(`# Slide ${n} notes
179
+
180
+ ${text}`);
181
+ }
182
+ return sections.join("\n\n");
183
+ }
184
+ async function pptxTextGrep(filePath, pattern, deadline = ooxmlWorkDeadline()) {
185
+ const { entries, slidePaths, budget } = await listSlideParts(filePath);
186
+ const guarded = compileGuardedRegex(pattern, "i");
187
+ if (!guarded.ok) throw new Error(`invalid --grep pattern: ${pattern} -- the pattern ${guarded.reason}`);
188
+ const re = guarded.re;
189
+ const out = [];
190
+ for (let i = 0; i < slidePaths.length; i++) {
191
+ assertOoxmlWithinDeadline(deadline, "Narrow the read to specific slides with pptx-slide, or use a smaller deck.");
192
+ const parsed = await parseSlide(entries, slidePaths[i], budget);
193
+ const text = collectTextRuns(parsed, "a:t").join(" ");
194
+ if (re.test(text)) {
195
+ const idx = text.search(re);
196
+ const snippet = text.slice(Math.max(0, idx - 40), idx + 80).trim();
197
+ out.push({ slide: i + 1, snippet });
198
+ }
199
+ }
200
+ return out;
201
+ }
202
+
203
+ export {
204
+ pptxOutline,
205
+ pptxSlideText,
206
+ pptxAllSlidesText,
207
+ pptxNotesText,
208
+ pptxTextGrep
209
+ };