token-goat 2.9.14 → 2.9.16

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 (46) hide show
  1. package/README.md +15 -1
  2. package/dist/{token-goat-chunk-2ESBO4IN.mjs → token-goat-chunk-2IEIBVVD.mjs} +16 -9
  3. package/dist/{token-goat-chunk-RUDOKYPJ.mjs → token-goat-chunk-2PCFAQAS.mjs} +6582 -6194
  4. package/dist/{token-goat-chunk-AMYCQJX4.mjs → token-goat-chunk-3H6FQT62.mjs} +49 -256
  5. package/dist/{token-goat-chunk-PRJVGIC5.mjs → token-goat-chunk-4DC6DDIB.mjs} +7 -5
  6. package/dist/token-goat-chunk-4EXFN2AW.mjs +29 -0
  7. package/dist/{token-goat-chunk-VZYD4OZB.mjs → token-goat-chunk-5USHO7B6.mjs} +416 -4168
  8. package/dist/token-goat-chunk-63QWJ6UM.mjs +277 -0
  9. package/dist/token-goat-chunk-BFNTLGVA.mjs +4547 -0
  10. package/dist/token-goat-chunk-BGHSSJUA.mjs +102 -0
  11. package/dist/{token-goat-chunk-T2IWWTHB.mjs → token-goat-chunk-DMQ32ZSR.mjs} +35 -1142
  12. package/dist/{token-goat-chunk-DBNY4RLN.mjs → token-goat-chunk-EJCY6KHO.mjs} +5 -3
  13. package/dist/token-goat-chunk-ERTXEKB6.mjs +228 -0
  14. package/dist/{token-goat-chunk-Z6UXPYJA.mjs → token-goat-chunk-F2ARFHLJ.mjs} +1 -1
  15. package/dist/{token-goat-chunk-EG3663UT.mjs → token-goat-chunk-GIMGT34T.mjs} +4 -2
  16. package/dist/{token-goat-chunk-XVZ4MNQC.mjs → token-goat-chunk-GMXBQS6O.mjs} +360 -116
  17. package/dist/{token-goat-chunk-SAQ5PG4L.mjs → token-goat-chunk-H3DXI6VD.mjs} +8 -4
  18. package/dist/token-goat-chunk-LJL6FGDS.mjs +35 -0
  19. package/dist/{token-goat-chunk-NEI4NC54.mjs → token-goat-chunk-LKSXAMJB.mjs} +7 -2
  20. package/dist/token-goat-chunk-LMFO66YD.mjs +331 -0
  21. package/dist/{token-goat-chunk-7OGKZ7AP.mjs → token-goat-chunk-M2R4UQ3B.mjs} +5 -3
  22. package/dist/{token-goat-chunk-YHGTGG6K.mjs → token-goat-chunk-MA5BZ2KI.mjs} +68 -7
  23. package/dist/{token-goat-chunk-ASVVF4JV.mjs → token-goat-chunk-MIL62GMN.mjs} +171 -23
  24. package/dist/{token-goat-chunk-ZFM4PWXL.mjs → token-goat-chunk-NAMH252H.mjs} +10 -7
  25. package/dist/{token-goat-chunk-YTQHZJXW.mjs → token-goat-chunk-NOBZV7PM.mjs} +96 -22
  26. package/dist/{token-goat-chunk-4SDX3QP3.mjs → token-goat-chunk-NQZCSVN2.mjs} +13 -5
  27. package/dist/{token-goat-chunk-XEH6KBWW.mjs → token-goat-chunk-OCI25AXY.mjs} +4 -3
  28. package/dist/token-goat-chunk-OSUFN2FV.mjs +326 -0
  29. package/dist/{token-goat-chunk-O5WAMISC.mjs → token-goat-chunk-QMZMHQRR.mjs} +29 -18
  30. package/dist/{token-goat-chunk-POBYR64E.mjs → token-goat-chunk-R3X5TCPB.mjs} +801 -3
  31. package/dist/token-goat-chunk-RRNZMM3A.mjs +3364 -0
  32. package/dist/{token-goat-chunk-PGGDW7DZ.mjs → token-goat-chunk-ULA4WCED.mjs} +9 -6
  33. package/dist/token-goat-chunk-UMXD2M7O.mjs +975 -0
  34. package/dist/{token-goat-chunk-3XQPEJMV.mjs → token-goat-chunk-UXHDBVUR.mjs} +1 -1
  35. package/dist/{token-goat-chunk-EZNVAIR3.mjs → token-goat-chunk-VVIYEFBI.mjs} +4 -3
  36. package/dist/token-goat-chunk-XOHTFRDH.mjs +10760 -0
  37. package/dist/{token-goat-chunk-HF6H7RNK.mjs → token-goat-chunk-YPS64ACE.mjs} +13 -3
  38. package/dist/{token-goat-chunk-DAMXYVIW.mjs → token-goat-chunk-Z5VPAXTC.mjs} +2560 -820
  39. package/dist/{token-goat-chunk-XQF5J25J.mjs → token-goat-chunk-ZEHFYJ7Z.mjs} +5 -4
  40. package/dist/token-goat-hook.mjs +15 -10
  41. package/dist/token-goat.core.mjs +24 -18
  42. package/docs/cli.md +8 -6
  43. package/package.json +1 -1
  44. package/dist/token-goat-chunk-IT6O3PNN.mjs +0 -15463
  45. package/dist/token-goat-chunk-ZD4EM4LR.mjs +0 -30
  46. package/dist/token-goat-chunk-ZYNNQ36L.mjs +0 -479
@@ -4,23 +4,26 @@ import {
4
4
  canRunWrappedShell,
5
5
  clipToDeliveryCap,
6
6
  deliveredOutputBytes
7
- } from "./token-goat-chunk-3XQPEJMV.mjs";
7
+ } from "./token-goat-chunk-UXHDBVUR.mjs";
8
8
  import {
9
9
  DEFAULT_RECONCILE_BUDGET_MS,
10
10
  HOOK_EVENTS,
11
11
  buildCommandManifest,
12
12
  checkSymbolBodySize,
13
+ diagnoseSqlFailure,
13
14
  flattenCommandNames,
14
15
  getWebOutput,
15
16
  isReconcileClean,
16
17
  readStdinJson,
17
18
  reconcileProject,
18
19
  storeWebOutput
19
- } from "./token-goat-chunk-ZYNNQ36L.mjs";
20
+ } from "./token-goat-chunk-UMXD2M7O.mjs";
20
21
  import {
22
+ BODY_FIRST_TOOL_RESPONSE_KEYS,
21
23
  GENERIC_SERVED_OUTPUT_KEY,
22
24
  OUTLINE_MAX_REPLACEMENT_RATIO,
23
25
  OUTLINE_MIN_HEADINGS,
26
+ OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
24
27
  WEB_FETCH_KEY_SEP,
25
28
  accumulateResidentLines,
26
29
  appendDirtyPath,
@@ -32,23 +35,30 @@ import {
32
35
  clearCurlDownload,
33
36
  compactPathFor,
34
37
  computeAdaptiveBudget,
38
+ contextOutput,
39
+ denyOutput,
40
+ emitRewrite,
41
+ emitRewriteIfChanged,
35
42
  enqueueDirtyPathSafe,
36
43
  ensureWorkerAlive,
44
+ estimateTokens,
37
45
  extractCompactFromMarker,
38
- extractMarkdownHeadings,
46
+ extractToolResponseField,
47
+ extractToolResultText,
39
48
  fenceUntrusted,
40
49
  fenceUntrustedSpans,
41
50
  fenceWithMatches,
42
51
  foldDelivery,
43
52
  foldDetail,
44
53
  foldingEnabled,
45
- formatHeadingTreeParts,
46
54
  formatProjectMap,
47
55
  formatShrinkSummary,
48
56
  getBashOutputId,
49
57
  getContextPressure,
50
58
  getCurlDownloadPath,
59
+ getCwd,
51
60
  getFileLineRanges,
61
+ getFilePath,
52
62
  getFileServedOutputs,
53
63
  getGlobMatchCount,
54
64
  getGrepMatchCount,
@@ -57,31 +67,41 @@ import {
57
67
  getSessionBashReruns,
58
68
  getSessionFiles,
59
69
  getSessionWebFetches,
70
+ getToolInput,
71
+ getToolName,
72
+ getTranscriptPath,
60
73
  hasSeenImage,
61
74
  hasSessionOutput,
62
75
  imageQualifiesForShrink,
63
76
  incrementSkillHit,
64
77
  indexServedBody,
65
78
  installedSkillPath,
79
+ isMcpErrorResponse,
66
80
  isStructuralRewriteAccepted,
81
+ isTextualContentBlock,
67
82
  lastTabContextMatches,
68
83
  lineMayCarryResidentSignal,
69
84
  listSiblingSessionStates,
70
85
  loadSessionCache,
71
86
  loadSessionState,
87
+ makeDedupHintHandlers,
72
88
  markCompactStale,
73
89
  markCompacted,
74
90
  markFileTruncated,
75
91
  markHintShown,
76
92
  matchesAllowPattern,
77
93
  matchesDenyPattern,
94
+ mcpContentBlocks,
78
95
  meetsSavingsFloor,
79
96
  metadataEndpointRefusal,
97
+ normalizePayload,
98
+ passOutput,
80
99
  planMarkdownOutline,
81
100
  planServedElisions,
82
101
  planSourceSkeleton,
83
102
  preToolPathDeclined,
84
103
  probeImageMeta,
104
+ readCopilotHooksOwners,
85
105
  readTranscriptTail,
86
106
  recordBashOutput,
87
107
  recordBashRerun,
@@ -99,13 +119,17 @@ import {
99
119
  recordSeenImage,
100
120
  recordSymbolRead,
101
121
  recordWebFetch,
122
+ registerHook,
102
123
  removeOutstandingAgentSpawn,
103
124
  repeatedSkillBodyHint,
125
+ runHook,
104
126
  saveSessionState,
105
127
  scanAndRecord,
128
+ serializeOutput,
106
129
  servedRunNotice,
107
130
  sessionOutputBodyBytes,
108
131
  sessionSidecarPath,
132
+ sessionStateKey,
109
133
  setLastTabContext,
110
134
  setTranscriptPath,
111
135
  shrinkImage,
@@ -118,68 +142,51 @@ import {
118
142
  vscodePathAllowed,
119
143
  wasCliReadThisSession,
120
144
  wasFileReadThisSession,
121
- wasHintShown
122
- } from "./token-goat-chunk-IT6O3PNN.mjs";
145
+ wasHintShown,
146
+ withPreservedBlocks
147
+ } from "./token-goat-chunk-XOHTFRDH.mjs";
123
148
  import {
124
149
  BASH_OUTPUT_SUBDIR,
125
- BODY_FIRST_TOOL_RESPONSE_KEYS,
126
- OUTPUT_FIRST_TOOL_RESPONSE_KEYS,
127
150
  commandHash,
128
151
  compressOutput,
129
- contextOutput,
130
- countSymbols,
131
152
  dedupeConsecutive,
132
- denyOutput,
133
153
  detectFromCommand,
134
- emitRewrite,
135
- emitRewriteIfChanged,
136
- estimateTokens,
137
- extractToolResponseField,
138
- extractToolResultText,
139
154
  filterByName,
140
155
  getBashOutput,
141
- getCwd,
142
- getFilePath,
143
156
  getMonitoringRecallHint,
144
- getToolInput,
145
- getToolName,
146
- getTranscriptPath,
147
157
  hasBareBackgroundOrNewline,
148
158
  hasUnquotedOperator,
149
159
  indexRecallEntry,
150
160
  isBashEntryStale,
151
161
  isBuildCommand,
152
- isMcpErrorResponse,
153
162
  isRewriteWorthwhile,
154
163
  isScopedGitStatusOrDiffStatCommand,
155
164
  isTestRunnerCommand,
156
- isTextualContentBlock,
157
- makeDedupHintHandlers,
158
- mcpContentBlocks,
159
- normalizePayload,
160
- passOutput,
161
- readCopilotHooksOwners,
162
- registerHook,
163
165
  resolveMinNetSavingsBytes,
164
- runHook,
165
- serializeOutput,
166
- sessionStateKey,
167
166
  shlexSplit,
168
167
  splitOwnTrailingNotices,
169
168
  storeBashOutput,
170
- summarizeOutputDelta,
171
- withPreservedBlocks
172
- } from "./token-goat-chunk-VZYD4OZB.mjs";
169
+ summarizeOutputDelta
170
+ } from "./token-goat-chunk-5USHO7B6.mjs";
173
171
  import {
174
- detectLanguage,
175
- getDb,
176
- languageHasFlag,
177
172
  recordStat,
178
173
  redactSecrets,
179
174
  savedTokensFromBytes,
180
175
  storeBlob,
181
176
  stripAnsiEscapes
182
- } from "./token-goat-chunk-T2IWWTHB.mjs";
177
+ } from "./token-goat-chunk-DMQ32ZSR.mjs";
178
+ import {
179
+ extractMarkdownHeadings,
180
+ formatHeadingTreeParts
181
+ } from "./token-goat-chunk-BFNTLGVA.mjs";
182
+ import {
183
+ countSymbols
184
+ } from "./token-goat-chunk-63QWJ6UM.mjs";
185
+ import {
186
+ detectLanguage,
187
+ getDb,
188
+ languageHasFlag
189
+ } from "./token-goat-chunk-R3X5TCPB.mjs";
183
190
  import {
184
191
  detectHarness,
185
192
  envBool,
@@ -189,34 +196,36 @@ import {
189
196
  isUnderSystemTemp,
190
197
  loadConfig,
191
198
  shortFingerprint
192
- } from "./token-goat-chunk-SAQ5PG4L.mjs";
199
+ } from "./token-goat-chunk-H3DXI6VD.mjs";
193
200
  import {
194
201
  ENV_KEYS,
195
202
  IDENTICAL_READ_MIN_BODY_BYTES,
196
203
  PER_FILE_COUNTERFACTUAL_CEILING,
197
- UNTRUSTED_TOOL_TAG,
198
204
  VERSION,
199
205
  atomicWriteText,
200
206
  containsLineRun,
201
207
  countNoun,
202
208
  dataDir,
203
- displaySafePath,
204
- displaySafeText,
205
209
  ensureDirSync,
206
210
  escapesOntoNetworkThroughLinks,
207
211
  extractErrorMessage,
208
- fenceUntrustedFileContent,
209
212
  foldPath,
210
213
  globalDbPath,
211
214
  hasCreatedConfig,
212
215
  isInsideRoot,
216
+ runGit,
217
+ toKB
218
+ } from "./token-goat-chunk-3H6FQT62.mjs";
219
+ import {
220
+ UNTRUSTED_TOOL_TAG,
221
+ displaySafePath,
222
+ displaySafeText,
223
+ fenceUntrustedFileContent,
213
224
  neutralizeSpokenMarkers,
214
225
  normalizePath,
215
226
  resolveIndexPath,
216
- runGit,
217
- toDisplayPath,
218
- toKB
219
- } from "./token-goat-chunk-AMYCQJX4.mjs";
227
+ toDisplayPath
228
+ } from "./token-goat-chunk-ERTXEKB6.mjs";
220
229
  import {
221
230
  init_define_import_meta_env
222
231
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -936,7 +945,7 @@ init_define_import_meta_env();
936
945
  var TRACKED_SKILL = "token-goat";
937
946
  var MAX_COMMANDS_SHOWN = 8;
938
947
  async function currentCommandNames() {
939
- const { buildProgram } = await import("./token-goat-chunk-O5WAMISC.mjs");
948
+ const { buildProgram } = await import("./token-goat-chunk-QMZMHQRR.mjs");
940
949
  return flattenCommandNames(buildCommandManifest(buildProgram()));
941
950
  }
942
951
  async function recordSkillVersionSnapshot(sessionId, skillName) {
@@ -7656,11 +7665,11 @@ import { statSync as statSync5 } from "node:fs";
7656
7665
  // src/bash_extractors.ts
7657
7666
  init_define_import_meta_env();
7658
7667
  import { statSync as statSync4, openSync as openSync2, readSync, closeSync as closeSync2 } from "node:fs";
7659
- function surgicalHintFor(hintPath, isEnv, isConfig, isDoc) {
7660
- return isEnv ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to read one function or class.';
7668
+ function surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml = false) {
7669
+ return isXml ? 'Use `token-goat xml-outline "' + hintPath + '"` to inspect structure, or `token-goat xml-query "' + hintPath + '" "<selector>"` to query specific nodes.' : isEnv ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` to read a specific variable.' : isConfig ? 'Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to read a specific value.' : isDoc ? 'Use `token-goat section "' + hintPath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + hintPath + '::SymbolName"` to read one function or class.';
7661
7670
  }
7662
- function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql) {
7663
- return isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isSql ? 'Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
7671
+ function surgicalHintForConfigDoc(filePath, isConfig, isDoc, isSql, isXml = false) {
7672
+ return isXml ? 'Use `token-goat xml-outline "' + filePath + '"` to inspect structure, or `token-goat xml-query "' + filePath + '" "<selector>"` to query specific nodes.' : isConfig ? 'Use `token-goat config-get "' + filePath + '" KEY_NAME` or `token-goat section "' + filePath + '::sectionName"` to read a specific value.' : isSql ? 'Use `token-goat section "' + filePath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.' : isDoc ? 'Use `token-goat section "' + filePath + '::SectionHeading"` to read one section.' : 'Use `token-goat read "' + filePath + '::SymbolName"` or `token-goat skeleton "' + filePath + '"` to see the file structure.';
7664
7673
  }
7665
7674
  function splitShellSegments(cmd) {
7666
7675
  const segments = [];
@@ -7713,19 +7722,21 @@ function extractCatSourceFile(cmd) {
7713
7722
  function classifyFileExtensions(filePath) {
7714
7723
  const basename3 = (filePath.includes("/") ? filePath.split("/").at(-1) : filePath.split("\\").at(-1)) ?? filePath;
7715
7724
  const isEnvFile = /^\.env(\.\w+)?$/i.test(basename3);
7716
- const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|conf|cfg|ini|properties|sql|ps1|psm1|env)$/i.test(filePath);
7725
+ const hasKnownExt = /\.(?:java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|dtsx|ampkg|xaml|conf|cfg|ini|properties|sql|ps1|psm1|env)$/i.test(filePath);
7717
7726
  if (!hasKnownExt && !isEnvFile) return null;
7718
7727
  const isSql = /\.sql$/i.test(filePath);
7719
7728
  const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
7720
7729
  const isEnv = isEnvFile || /\.env$/i.test(filePath);
7721
7730
  const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
7722
- return { isDoc, isEnv, isConfig, isSql };
7731
+ const isXml = /\.(?:xml|dtsx|ampkg|xaml)$/i.test(filePath);
7732
+ return { isDoc, isEnv, isConfig, isSql, isXml };
7723
7733
  }
7724
7734
  function classifyDocConfig(filePath) {
7725
7735
  const isDoc = /\.(?:md|mdx|rst|txt)$/i.test(filePath);
7726
7736
  const isConfig = /\.(?:json|yaml|yml|toml|conf|cfg|ini|properties)$/i.test(filePath);
7727
7737
  const isSql = /\.sql$/i.test(filePath);
7728
- return { isDoc, isConfig, isSql };
7738
+ const isXml = /\.(?:xml|dtsx|ampkg|xaml)$/i.test(filePath);
7739
+ return { isDoc, isConfig, isSql, isXml };
7729
7740
  }
7730
7741
  function classifyCatPath(filePath, cmd0) {
7731
7742
  if (isTempPath(filePath)) return null;
@@ -7802,10 +7813,10 @@ function extractPowerShellFileMethodRead(cmd, event) {
7802
7813
  }
7803
7814
  const flags = classifyFileExtensions(filePath);
7804
7815
  if (flags === null) {
7805
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
7806
- return { filePath, isDoc, isEnv: false, isConfig, isSql };
7816
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
7817
+ return { filePath, isDoc, isEnv: false, isConfig, isSql, isXml };
7807
7818
  }
7808
- return { filePath, isDoc: flags.isDoc, isEnv: flags.isEnv, isConfig: flags.isConfig, isSql: flags.isSql };
7819
+ return { filePath, isDoc: flags.isDoc, isEnv: flags.isEnv, isConfig: flags.isConfig, isSql: flags.isSql, isXml: flags.isXml };
7809
7820
  }
7810
7821
  function extractRgSymbolSearch(cmd) {
7811
7822
  if (!/^(?:rg|grep)\s+/.test(cmd)) return null;
@@ -7824,12 +7835,77 @@ function extractRgSymbolSearch(cmd) {
7824
7835
  }
7825
7836
  function extractCatJsonPipe(cmd) {
7826
7837
  const m = /^cat\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*\|\s*jq\b/.exec(cmd);
7827
- if (!m) return null;
7828
- const filePath = m[1] ?? m[2] ?? m[3];
7829
- if (!filePath) return null;
7830
- if (isTempPath(filePath)) return null;
7831
- if (!/\.(?:json|yaml|yml|toml)$/i.test(filePath)) return null;
7832
- return { filePath };
7838
+ if (m) {
7839
+ const filePath = m[1] ?? m[2] ?? m[3];
7840
+ if (filePath && !isTempPath(filePath) && /\.(?:json|yaml|yml|toml)$/i.test(filePath)) {
7841
+ return { filePath, isDirectJq: false };
7842
+ }
7843
+ }
7844
+ const jqDirect = /^jq(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z0-9-]+(?:=\S+)?))*\s+(?:"[^"]*"|'[^']*'|(?:\.[a-zA-Z0-9_.*[\]]+))\s+(?:"([^"]+)"|'([^']+)'|(\S+))\s*$/.exec(cmd);
7845
+ if (jqDirect) {
7846
+ const filePath = jqDirect[1] ?? jqDirect[2] ?? jqDirect[3];
7847
+ if (filePath && !isTempPath(filePath) && /\.(?:json|yaml|yml|toml)$/i.test(filePath)) {
7848
+ return { filePath, isDirectJq: true };
7849
+ }
7850
+ }
7851
+ return null;
7852
+ }
7853
+ function extractPowerShellJsonPipeline(cmd) {
7854
+ let inner = cmd.trim();
7855
+ const w = POWERSHELL_WRAP_RE.exec(inner);
7856
+ if (w) {
7857
+ inner = (w[1] ?? w[2] ?? "").trim();
7858
+ }
7859
+ if (!/\bConvertFrom-Json\b/i.test(inner)) return null;
7860
+ const parseTarget = (segment) => {
7861
+ const readAll = /\[(?:System\.)?IO\.File\]::ReadAllText\(\s*['"]?([^'")\s]+)['"]?\s*\)/i.exec(segment);
7862
+ if (readAll) {
7863
+ const p = readAll[1];
7864
+ return p && /\.(?:json|txt|log|temp)$/i.test(p) ? p : null;
7865
+ }
7866
+ const tokens = segment.trim().split(/\s+/);
7867
+ const cmdlets = /* @__PURE__ */ new Set(["get-content", "gc", "cat", "type"]);
7868
+ const idx = tokens.findIndex((t) => cmdlets.has(t.toLowerCase()));
7869
+ if (idx === -1) return null;
7870
+ let argIdx = idx + 1;
7871
+ while (argIdx < tokens.length) {
7872
+ const tok = tokens[argIdx];
7873
+ if (!tok) break;
7874
+ if (tok.startsWith("-")) {
7875
+ const flag = tok.toLowerCase();
7876
+ if (flag === "-path" && argIdx + 1 < tokens.length) {
7877
+ const next = tokens[argIdx + 1];
7878
+ if (next && !next.startsWith("-")) {
7879
+ const clean2 = next.replace(/^['"]|['"]$/g, "");
7880
+ return /\.(?:json|txt|log|temp)$/i.test(clean2) ? clean2 : null;
7881
+ }
7882
+ }
7883
+ if ((flag === "-encoding" || flag === "-totalcount") && argIdx + 1 < tokens.length) {
7884
+ argIdx += 2;
7885
+ continue;
7886
+ }
7887
+ argIdx++;
7888
+ continue;
7889
+ }
7890
+ const clean = tok.replace(/^['"(]|['")]$/g, "");
7891
+ return /\.(?:json|txt|log|temp)$/i.test(clean) ? clean : null;
7892
+ }
7893
+ return null;
7894
+ };
7895
+ const pipeIdx = inner.search(/\|\s*ConvertFrom-Json\b/i);
7896
+ if (pipeIdx !== -1) {
7897
+ const upstream = inner.slice(0, pipeIdx).trim();
7898
+ return { filePath: parseTarget(upstream) };
7899
+ }
7900
+ const parenMatch = /ConvertFrom-Json\s*\(([^)]+)\)/i.exec(inner);
7901
+ if (parenMatch) {
7902
+ const inside = parenMatch[1] ?? "";
7903
+ return { filePath: parseTarget(inside) };
7904
+ }
7905
+ if (/ConvertFrom-Json\s*\(/i.test(inner)) {
7906
+ return { filePath: null };
7907
+ }
7908
+ return null;
7833
7909
  }
7834
7910
  function extractWslCatFile(cmd) {
7835
7911
  const wslMatch = /^wsl(?:\s+-d\s+\S+)?\s+bash\s+-c\s+"cat(?:\s+(?:-[a-zA-Z]+|--[a-zA-Z-]+))*\s+\/mnt\/([a-z])\/([^"]*)"/.exec(cmd);
@@ -7960,7 +8036,7 @@ function pythonOpenPathsAreAllLiteral(text) {
7960
8036
  const calls = pythonOpenCalls(text);
7961
8037
  return calls.length > 0 && calls.every((call) => call.pathLiteral !== null);
7962
8038
  }
7963
- var KNOWN_PYTHON_EXT_STR = "java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|html|htm|conf|cfg|ini|properties|sql|ps1|psm1|env";
8039
+ var KNOWN_PYTHON_EXT_STR = "java|py|ts|tsx|js|jsx|go|rb|rs|cpp|cc|cxx|c|h|hpp|kt|swift|cs|php|scala|clj|css|scss|sass|less|md|mdx|rst|txt|json|yaml|yml|toml|xml|dtsx|ampkg|xaml|html|htm|conf|cfg|ini|properties|sql|ps1|psm1|env";
7964
8040
  var OPEN_EXT = new RegExp(`\\.(?:${KNOWN_PYTHON_EXT_STR})$`, "i");
7965
8041
  function extractPythonFileRead(cmd) {
7966
8042
  let inner = cmd.trim();
@@ -7986,11 +8062,11 @@ function extractPythonFileRead(cmd) {
7986
8062
  const classifyResult = (filePath) => {
7987
8063
  const flags = classifyFileExtensions(filePath);
7988
8064
  if (flags !== null) {
7989
- return { filePath, isDoc: flags.isDoc, isConfig: flags.isConfig, isEnv: flags.isEnv, isSql: flags.isSql, isOutputFile: false };
8065
+ return { filePath, isDoc: flags.isDoc, isConfig: flags.isConfig, isEnv: flags.isEnv, isSql: flags.isSql, isXml: flags.isXml, isOutputFile: false };
7990
8066
  }
7991
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
8067
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
7992
8068
  const isEnv = /\.env(\.\w+)?$/i.test(filePath);
7993
- return { filePath, isDoc, isConfig, isEnv, isSql, isOutputFile: false };
8069
+ return { filePath, isDoc, isConfig, isEnv, isSql, isXml, isOutputFile: false };
7994
8070
  };
7995
8071
  const heredocMatch = /^python3?\s+-\s+<<\s*'?(\w+)'?\s*\n([\s\S]*?)\n\1\s*$/.exec(pythonBody);
7996
8072
  if (heredocMatch) {
@@ -8044,9 +8120,9 @@ function extractHeadFile(cmd) {
8044
8120
  const filePath = direct !== null ? direct[3] ?? direct[4] ?? direct[5] : piped[1] ?? piped[2] ?? piped[3];
8045
8121
  if (filePath === void 0) return null;
8046
8122
  if (isTempPath(filePath)) return null;
8047
- if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
8048
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
8049
- return { filePath, isDoc, isConfig, isSql, n };
8123
+ if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
8124
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
8125
+ return { filePath, isDoc, isConfig, isSql, isXml, n };
8050
8126
  }
8051
8127
  function extractSedRange(cmd) {
8052
8128
  const m = /^sed\s+-n\s+(?:['"]((?:\d+,\d+p)(?:;\d+,\d+p)*)['"]|(\d+,\d+p))\s+(?:"([^"]+)"|'([^']+)'|(\S+))(?:\s+2>(?:\/dev\/null|&1))?\s*$/.exec(cmd);
@@ -8148,7 +8224,7 @@ function leadingLinesHint(lead, hintPath, start, end, flags, preHookCwd) {
8148
8224
  const key = resolveIndexPath(hintPath, preHookCwd ?? process.cwd());
8149
8225
  const prior = findRangeOverlap(getFileLineRanges(key), start, end);
8150
8226
  if (prior !== null) return sedOverlapHint(hintPath, prior, start, end);
8151
- return lead + surgicalHintForConfigDoc(hintPath, flags.isConfig, flags.isDoc, flags.isSql);
8227
+ return lead + surgicalHintForConfigDoc(hintPath, flags.isConfig, flags.isDoc, flags.isSql, flags.isXml ?? false);
8152
8228
  }
8153
8229
  function findRangeOverlap(prior, start, end) {
8154
8230
  let best = null;
@@ -8205,9 +8281,9 @@ function extractTailFile(cmd) {
8205
8281
  const filePath = direct !== null ? direct[3] ?? direct[4] ?? direct[5] : piped[1] ?? piped[2] ?? piped[3];
8206
8282
  if (!filePath) return null;
8207
8283
  if (isTempPath(filePath)) return null;
8208
- if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh)$/i.test(filePath)) return null;
8209
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
8210
- return { filePath, isDoc, isConfig, isSql };
8284
+ if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
8285
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
8286
+ return { filePath, isDoc, isConfig, isSql, isXml };
8211
8287
  }
8212
8288
  function extractGetContentTail(cmd) {
8213
8289
  const tailMatch = /-Tail\s+(\d+)/i.exec(cmd);
@@ -8222,9 +8298,9 @@ function extractGetContentTail(cmd) {
8222
8298
  const filePath = (beforeTail || afterTail).replace(/^["']|["']$/g, "");
8223
8299
  if (!filePath) return null;
8224
8300
  if (isTempPath(filePath)) return null;
8225
- if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
8226
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
8227
- return { filePath, isDoc, isConfig, isSql };
8301
+ if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
8302
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
8303
+ return { filePath, isDoc, isConfig, isSql, isXml };
8228
8304
  }
8229
8305
  function extractGetContentSelectFirst(cmd) {
8230
8306
  const m = /^(Get-Content|gc)\s+([^|]+)\s*\|\s*(Select-Object|select)\s+(-First\s+(\d+))/i.exec(cmd);
@@ -8234,9 +8310,9 @@ function extractGetContentSelectFirst(cmd) {
8234
8310
  if (n <= 10) return null;
8235
8311
  if (!filePath) return null;
8236
8312
  if (isTempPath(filePath)) return null;
8237
- if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1)$/i.test(filePath)) return null;
8238
- const { isDoc, isConfig, isSql } = classifyDocConfig(filePath);
8239
- return { filePath, isDoc, isConfig, isSql, n };
8313
+ if (!/\.(?:ts|tsx|js|jsx|py|go|java|rs|rb|cs|md|mdx|rst|txt|json|yaml|yml|toml|sql|sh|ps1|psm1|xml|dtsx|ampkg|xaml)$/i.test(filePath)) return null;
8314
+ const { isDoc, isConfig, isSql, isXml } = classifyDocConfig(filePath);
8315
+ return { filePath, isDoc, isConfig, isSql, isXml, n };
8240
8316
  }
8241
8317
  function taskOutputIsJsonlTranscript(outPath) {
8242
8318
  let fd = null;
@@ -8611,6 +8687,42 @@ function isCompressibleSingleCommand(cmd) {
8611
8687
  if (hasBareBackgroundOrNewline(cmd)) return false;
8612
8688
  return true;
8613
8689
  }
8690
+ function extractTerminalXmlParsing(cmd) {
8691
+ const trimmed = cmd.trim();
8692
+ if (!trimmed) return null;
8693
+ const selectXmlM = /\bSelect-Xml\b(?:\s+(?:-Path\s+)?["']?([^"'\s|;]+(?:\.xml|\.dtsx|\.ampkg|\.xaml))["']?)?/i.exec(trimmed);
8694
+ if (selectXmlM) {
8695
+ const rawPath = selectXmlM[1];
8696
+ const filePath = rawPath && !rawPath.startsWith("-") ? rawPath : void 0;
8697
+ return { filePath, toolOrScript: "Select-Xml" };
8698
+ }
8699
+ const psXmlCastM = /\[(?:xml|System\.Xml\.XmlDocument)\]/i.exec(trimmed);
8700
+ if (psXmlCastM) {
8701
+ const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed) || /(?:Get-Content|gc|ReadAllText)\s+["']?([^"'\s|;)]+\.(?:xml|dtsx|ampkg|xaml))["']?/i.exec(trimmed);
8702
+ const filePath = fileM?.[1];
8703
+ return { filePath, toolOrScript: psXmlCastM[0] };
8704
+ }
8705
+ const inspectScriptM = /(?:powershell|pwsh|&|\.)?\s*["']?(\.?[/\\]?inspect_[^"'\s|;]+\.ps1)["']/i.exec(trimmed) || /\b(inspect_[^"'\s|;]+\.ps1)\b/i.exec(trimmed);
8706
+ if (inspectScriptM) {
8707
+ const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed);
8708
+ const filePath = fileM?.[1];
8709
+ return { filePath, toolOrScript: inspectScriptM[1] ?? "inspect script" };
8710
+ }
8711
+ const pyXmlM = /\bpython(?:\d+(?:\.\d+)?)?(?:\.exe)?\b.*-c\s+["'].*?\b(xml\.etree|BeautifulSoup|minidom|lxml)\b/i.exec(trimmed);
8712
+ if (pyXmlM) {
8713
+ const fileM = /["']([^"'\r\n]+\.(?:xml|dtsx|ampkg|xaml))["']/i.exec(trimmed);
8714
+ const filePath = fileM?.[1];
8715
+ return { filePath, toolOrScript: `python ${pyXmlM[1]}` };
8716
+ }
8717
+ const cliXmlM = /\b(xmllint|xmlstarlet|xidel)\b/i.exec(trimmed);
8718
+ if (cliXmlM) {
8719
+ const fileM = /["']?([^"'\s|;]+\.(?:xml|dtsx|ampkg|xaml))["']?/i.exec(trimmed);
8720
+ const rawPath = fileM?.[1];
8721
+ const filePath = rawPath && !rawPath.startsWith("-") ? rawPath : void 0;
8722
+ return { filePath, toolOrScript: cliXmlM[1] };
8723
+ }
8724
+ return null;
8725
+ }
8614
8726
 
8615
8727
  // src/hooks_bash_commands.ts
8616
8728
  var CD_PREFIX_RE = /^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)[ \t]*(?:&&|;|\r?\n)\s*)+/;
@@ -9281,9 +9393,9 @@ async function maybeElideServedGenericOutput(cmd, output, exitCode, cwd, cacheMi
9281
9393
  if (rewrittenText === null) return null;
9282
9394
  return emitRewrite(rewrittenText, "already-served shell output collapsed", { kind: "bash_compress:generic-served-elision", originalBytes: deliveredOutputBytes(originalBytes) });
9283
9395
  }
9284
- async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes) {
9396
+ async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped = false) {
9285
9397
  if (process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0") return null;
9286
- if (isCompressibleSingleCommand(cmd)) return null;
9398
+ if (!isUnwrapped && isCompressibleSingleCommand(cmd)) return null;
9287
9399
  if (exitCode !== null && exitCode !== 0) return null;
9288
9400
  let cfg;
9289
9401
  try {
@@ -9293,7 +9405,7 @@ async function maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinB
9293
9405
  }
9294
9406
  if (!cfg.enabled || cfg.disabled_filters.includes("generic")) return null;
9295
9407
  if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return null;
9296
- const shaped = pipelineShapeFilter(cmd, cwd);
9408
+ const shaped = pipelineShapeFilter(cmd, cwd) ?? (isUnwrapped ? detectFromCommand(cmd, cwd ?? void 0)?.filter ?? null : null);
9297
9409
  const filter3 = shaped !== null && !cfg.disabled_filters.includes(shaped.name) ? shaped : filterByName("generic");
9298
9410
  if (filter3 === null) return null;
9299
9411
  const compressed = compressOutput(filter3, output, "", exitCode ?? 0, [], {
@@ -9436,6 +9548,15 @@ function preBashHandlerInner(event) {
9436
9548
  "Use `token-goat outline <file>` to see symbol names and line counts without loading files."
9437
9549
  );
9438
9550
  }
9551
+ const terminalXml = extractTerminalXmlParsing(cmd);
9552
+ if (terminalXml !== null) {
9553
+ const { filePath, toolOrScript } = terminalXml;
9554
+ recordStat("session_hint", 0, 0);
9555
+ const target = filePath ? displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath) : "<file>";
9556
+ return contextOutput(
9557
+ `token-goat available for this file type, consider 'token-goat xml-query "${target}" "<xpath>"' or 'token-goat xml-outline "${target}"' first instead of terminal XML parsing (${toolOrScript}).`
9558
+ );
9559
+ }
9439
9560
  const singleLineRangeRead = extractLineRangeRead(cmd);
9440
9561
  const sedReads = singleLineRangeRead !== null ? [singleLineRangeRead] : extractLineRangeReadsCompound(cmd);
9441
9562
  if (sedReads !== null) {
@@ -9462,30 +9583,44 @@ function preBashHandlerInner(event) {
9462
9583
  }
9463
9584
  const gcTailResult = extractGetContentTail(cmd);
9464
9585
  if (gcTailResult !== null) {
9465
- const { filePath, isDoc, isConfig, isSql } = gcTailResult;
9586
+ const { filePath, isDoc, isConfig, isSql, isXml } = gcTailResult;
9466
9587
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9467
9588
  recordStat("session_hint", 0, 0);
9468
- return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
9589
+ return contextOutput("`Get-Content -Tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql, isXml));
9469
9590
  }
9470
9591
  const gcSelectResult = extractGetContentSelectFirst(cmd);
9471
9592
  if (gcSelectResult !== null) {
9472
- const { filePath, isDoc, isConfig, isSql, n } = gcSelectResult;
9593
+ const { filePath, isDoc, isConfig, isSql, isXml, n } = gcSelectResult;
9473
9594
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9474
9595
  recordStat("session_hint", 0, 0);
9475
- return contextOutput(leadingLinesHint("`Select-Object -First` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql }, preHookCwd));
9596
+ return contextOutput(leadingLinesHint("`Select-Object -First` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql, isXml }, preHookCwd));
9476
9597
  }
9477
9598
  const catJsonPipe = extractCatJsonPipe(cmd);
9478
9599
  if (catJsonPipe !== null) {
9479
- const { filePath } = catJsonPipe;
9600
+ const { filePath, isDirectJq } = catJsonPipe;
9480
9601
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9481
9602
  recordStat("session_hint", 0, 0);
9603
+ const label = isDirectJq ? "`jq`" : "`cat | jq`";
9604
+ return contextOutput(
9605
+ label + ' loads the whole file. Use `token-goat json-query "' + hintPath + '" "<key>"` or `token-goat config-get "' + hintPath + '" KEY_NAME` to slice one value.'
9606
+ );
9607
+ }
9608
+ const psJsonPipe = extractPowerShellJsonPipeline(cmd);
9609
+ if (psJsonPipe !== null) {
9610
+ recordStat("session_hint", 0, 0);
9611
+ if (psJsonPipe.filePath) {
9612
+ const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, psJsonPipe.filePath, hintCwd) : psJsonPipe.filePath);
9613
+ return contextOutput(
9614
+ 'PowerShell `ConvertFrom-Json` pipeline detected. Use `token-goat json-query "' + hintPath + '" "<selector>"` to extract fields directly without shell conversion scripts.'
9615
+ );
9616
+ }
9482
9617
  return contextOutput(
9483
- '`cat | jq` loads the whole file. Use `token-goat config-get "' + hintPath + '" KEY_NAME` or `token-goat section "' + hintPath + '::sectionName"` to slice one value.'
9618
+ 'PowerShell `ConvertFrom-Json` pipeline detected. Use `token-goat json-query <file> "<selector>"` or `token-goat web-output` to extract fields directly.'
9484
9619
  );
9485
9620
  }
9486
9621
  const catResult = extractCatFile(cmd);
9487
9622
  if (catResult !== null) {
9488
- const { filePath, isDoc, isEnv, isConfig, isSql, cmd0, advisoryOnly } = catResult;
9623
+ const { filePath, isDoc, isEnv, isConfig, isSql, isXml, cmd0, advisoryOnly } = catResult;
9489
9624
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9490
9625
  recordStat("session_hint", 0, 0);
9491
9626
  if (isSql) {
@@ -9493,16 +9628,16 @@ function preBashHandlerInner(event) {
9493
9628
  "`" + cmd0 + '` loads the entire file into context. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
9494
9629
  );
9495
9630
  }
9496
- const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
9631
+ const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
9497
9632
  return cdStripped || advisoryOnly ? contextOutput("`" + cmd0 + "` loads the entire file into context. " + hint) : denyOutput("`" + cmd0 + "` loads the entire file into context. " + hint);
9498
9633
  }
9499
9634
  const catMulti = extractCatFilesMulti(cmd);
9500
9635
  if (catMulti !== null) {
9501
9636
  recordStat("session_hint", 0, 0);
9502
9637
  const cmd0 = catMulti[0].cmd0;
9503
- const perPath = catMulti.map(({ filePath, isDoc, isEnv, isConfig, isSql }) => {
9638
+ const perPath = catMulti.map(({ filePath, isDoc, isEnv, isConfig, isSql, isXml }) => {
9504
9639
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9505
- const how = isSql ? 'token-goat section "' + hintPath + '::table_name"' : isEnv || isConfig ? 'token-goat config-get "' + hintPath + '" KEY_NAME' : isDoc ? 'token-goat section "' + hintPath + '::SectionHeading"' : 'token-goat read "' + hintPath + '::SymbolName"';
9640
+ const how = isXml ? 'token-goat xml-outline "' + hintPath + '" or token-goat xml-query "' + hintPath + '" "<selector>"' : isSql ? 'token-goat section "' + hintPath + '::table_name"' : isEnv || isConfig ? 'token-goat config-get "' + hintPath + '" KEY_NAME' : isDoc ? 'token-goat section "' + hintPath + '::SectionHeading"' : 'token-goat read "' + hintPath + '::SymbolName"';
9506
9641
  return " " + hintPath + " -> `" + how + "`";
9507
9642
  });
9508
9643
  const msg = "`" + cmd0 + "` on multiple files loads them all into context. Read each surgically instead:\n" + perPath.join("\n");
@@ -9510,19 +9645,19 @@ function preBashHandlerInner(event) {
9510
9645
  }
9511
9646
  const psGetContentResult = extractPowerShellWrappedGetContent(cmd, event);
9512
9647
  if (psGetContentResult !== null) {
9513
- const { filePath, isDoc, isEnv, isConfig, isSql } = psGetContentResult;
9648
+ const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = psGetContentResult;
9514
9649
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9515
9650
  recordStat("session_hint", 0, 0);
9516
9651
  const lead = "`Get-Content` via a `powershell -Command` wrapper bypasses read hooks and loads the entire file into context. ";
9517
9652
  if (isSql) {
9518
9653
  return contextOutput(lead + 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.');
9519
9654
  }
9520
- const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
9655
+ const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
9521
9656
  return cdStripped ? contextOutput(lead + hint) : denyOutput(lead + hint);
9522
9657
  }
9523
9658
  const wslCatResult = extractWslCatFile(cmd);
9524
9659
  if (wslCatResult !== null) {
9525
- const { filePath, isDoc, isEnv, isConfig, isSql } = wslCatResult;
9660
+ const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = wslCatResult;
9526
9661
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9527
9662
  recordStat("session_hint", 0, 0);
9528
9663
  if (isSql) {
@@ -9530,12 +9665,12 @@ function preBashHandlerInner(event) {
9530
9665
  '`cat` loads the entire file into context. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
9531
9666
  );
9532
9667
  }
9533
- const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
9668
+ const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
9534
9669
  return cdStripped ? contextOutput("`cat` loads the entire file into context. " + hint) : denyOutput("`cat` loads the entire file into context. " + hint);
9535
9670
  }
9536
9671
  const pyRead = extractPythonFileRead(cmd);
9537
9672
  if (pyRead !== null) {
9538
- const { filePath, isDoc, isConfig, isEnv, isSql, isOutputFile } = pyRead;
9673
+ const { filePath, isDoc, isConfig, isEnv, isSql, isXml, isOutputFile } = pyRead;
9539
9674
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9540
9675
  recordStat("session_hint", 0, 0);
9541
9676
  if (isOutputFile) {
@@ -9552,22 +9687,22 @@ function preBashHandlerInner(event) {
9552
9687
  'Python `open()` file reads bypass read hooks. Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.'
9553
9688
  );
9554
9689
  }
9555
- const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
9690
+ const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
9556
9691
  return cdStripped ? contextOutput("Python `open()` file reads bypass read hooks. " + hint) : denyOutput("Python `open()` file reads bypass read hooks. " + hint);
9557
9692
  }
9558
9693
  const tailResult = extractTailFile(cmd);
9559
9694
  if (tailResult !== null) {
9560
- const { filePath, isDoc, isConfig, isSql } = tailResult;
9695
+ const { filePath, isDoc, isConfig, isSql, isXml } = tailResult;
9561
9696
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9562
9697
  recordStat("session_hint", 0, 0);
9563
- return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql));
9698
+ return contextOutput("`tail` bypasses read hooks. " + surgicalHintForConfigDoc(hintPath, isConfig, isDoc, isSql, isXml));
9564
9699
  }
9565
9700
  const headResult = extractHeadFile(cmd);
9566
9701
  if (headResult !== null) {
9567
- const { filePath, isDoc, isConfig, isSql, n } = headResult;
9702
+ const { filePath, isDoc, isConfig, isSql, isXml, n } = headResult;
9568
9703
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9569
9704
  recordStat("session_hint", 0, 0);
9570
- return contextOutput(leadingLinesHint("`head` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql }, preHookCwd));
9705
+ return contextOutput(leadingLinesHint("`head` bypasses read hooks. ", hintPath, 1, n, { isConfig, isDoc, isSql, isXml }, preHookCwd));
9571
9706
  }
9572
9707
  const nodeRead = extractNodeFileRead(cmd);
9573
9708
  if (nodeRead !== null) {
@@ -9584,14 +9719,14 @@ function preBashHandlerInner(event) {
9584
9719
  }
9585
9720
  const psMethodRead = extractPowerShellFileMethodRead(cmd, event);
9586
9721
  if (psMethodRead !== null) {
9587
- const { filePath, isDoc, isEnv, isConfig, isSql } = psMethodRead;
9722
+ const { filePath, isDoc, isEnv, isConfig, isSql, isXml } = psMethodRead;
9588
9723
  const hintPath = displaySafePath(cdStripped ? resolveCdHintPath(rawCmd, filePath, hintCwd) : filePath);
9589
9724
  const lead = "PowerShell `[IO.File]::ReadAllText()` bypasses read hooks. ";
9590
9725
  if (isSql) {
9591
9726
  recordStat("session_hint", 0, 0);
9592
9727
  return contextOutput(lead + 'Use `token-goat section "' + hintPath + '::table_name"` to pull one CREATE TABLE / CREATE TYPE block.');
9593
9728
  }
9594
- const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc);
9729
+ const hint = surgicalHintFor(hintPath, isEnv, isConfig, isDoc, isXml);
9595
9730
  recordStat("session_hint", 0, 0);
9596
9731
  return cdStripped ? contextOutput(lead + hint) : denyOutput(lead + hint);
9597
9732
  }
@@ -9763,15 +9898,25 @@ function extractExitCode(raw) {
9763
9898
  return null;
9764
9899
  }
9765
9900
  var GH_SECURITY_PATHS = ["/security_advisories", "/advisories", "security_events"];
9766
- var GH_SCOPE_PHRASES = ["Must have push access", "Resource not accessible by integration", "Must be an admin"];
9901
+ var GH_SCOPE_PHRASES = [
9902
+ "Must have push access",
9903
+ "Resource not accessible by integration",
9904
+ "Must be an admin",
9905
+ "You are not authorized to perform this operation"
9906
+ ];
9907
+ var GH_NOT_FOUND = /^gh: .*\(HTTP 404\)|"status":\s*"404"/m;
9767
9908
  function buildGhApiHint(cmd, stdout, exitCode) {
9768
9909
  if (stdout === "" || !cmd.startsWith("gh api")) return null;
9769
9910
  const hints = [];
9770
9911
  const isSecurityPath = GH_SECURITY_PATHS.some((p) => cmd.includes(p));
9771
9912
  const hasScopePhrase = GH_SCOPE_PHRASES.some((p) => stdout.includes(p));
9772
- const failedSecurityCall = exitCode !== null && exitCode !== 0 && isSecurityPath;
9773
- if (hasScopePhrase || failedSecurityCall) {
9913
+ const ambiguousSecurity404 = exitCode !== null && exitCode !== 0 && isSecurityPath && GH_NOT_FOUND.test(stdout);
9914
+ if (hasScopePhrase) {
9774
9915
  hints.push("[token-goat] GitHub API scope issue: try gh auth refresh -s security_events");
9916
+ } else if (ambiguousSecurity404) {
9917
+ hints.push(
9918
+ "[token-goat] GitHub answers 404 both for a resource that does not exist and for one your token cannot see: check the owner/repo spelling, then gh auth status for the security_events scope."
9919
+ );
9775
9920
  }
9776
9921
  const trimmed = stdout.trimStart();
9777
9922
  if (trimmed.startsWith("{")) {
@@ -9841,10 +9986,28 @@ function recordBashFileReadsForSessionCache(cmd, cwd) {
9841
9986
  return;
9842
9987
  }
9843
9988
  }
9989
+ async function maybeEmitLargeUncompressedHint(cmd, output, exitCode, cwd, isUnwrapped, event, ansiResult) {
9990
+ const outputBytes = Buffer.byteLength(output, "utf-8");
9991
+ if (outputBytes < 4096 || process.env["TOKEN_GOAT_BASH_COMPRESS"] === "0" || exitCode !== null && exitCode !== 0 || event.raw["_tg_harness"] !== "vscode" && (isCompressibleSingleCommand(cmd) || !isUnwrapped)) {
9992
+ return null;
9993
+ }
9994
+ const key = `bash-uncompressed-4k:${event.sessionId ?? ""}:${shortFingerprint(cmd)}`;
9995
+ if (wasHintShown(key)) return null;
9996
+ markHintShown(key);
9997
+ recordStat("session_hint", 0, 0);
9998
+ const id = await storeBashOutput(cmd, output, exitCode ?? 0, cwd);
9999
+ const kb = Math.round(outputBytes / 1024);
10000
+ const msg = `[tg] Output was ${kb}KB uncompressed. For large tool outputs, run with 'token-goat compress -c "${displaySafeText(cmd)}"' or inspect via 'token-goat bash-output ${id}'.`;
10001
+ if (ansiResult !== null && ansiResult.hookType === "rewriteOutput") {
10002
+ return emitRewrite(msg + "\n" + fenceUntrusted(ansiResult.updatedOutput, UNTRUSTED_TOOL_TAG), "large uncompressed output hint", void 0, "counted-elsewhere");
10003
+ }
10004
+ return contextOutput(msg);
10005
+ }
9844
10006
  async function postBashHandler(event) {
9845
10007
  try {
9846
10008
  const rawCmdRaw = extractCommand(event);
9847
10009
  if (rawCmdRaw === void 0) return passOutput();
10010
+ const isUnwrapped = unwrapCompressCommand(rawCmdRaw) === null;
9848
10011
  const rawCmd = unwrapCompressCommand(rawCmdRaw) ?? rawCmdRaw;
9849
10012
  const cmd = stripCdPrefix(rawCmd);
9850
10013
  const output = extractBashOutput(event.raw);
@@ -9928,18 +10091,27 @@ async function postBashHandler(event) {
9928
10091
  const gitScopedCacheId = await storeBashOutput(cmd, output, exitCode ?? 0, cwd);
9929
10092
  recordBashOutput(gitScopedCacheHash, gitScopedCacheId, Buffer.byteLength(output, "utf-8"));
9930
10093
  }
10094
+ if (isUnwrapped && /^git(?:\s+-[^\s]+|\s+--[^\s]+)*\s+diff\b/i.test(cmd)) {
10095
+ const unwrappedCompressed = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped);
10096
+ if (unwrappedCompressed !== null) return unwrappedCompressed;
10097
+ }
9931
10098
  const isMonitoring = getMonitoringRecallHint(cmd) !== null;
9932
10099
  const isFileRead = pureFileReadPath(cmd) !== null;
9933
10100
  if (isFileRead || !isMonitoring && !isBuildCommand(cmd) && !isCurlGetCommand(cmd)) {
9934
10101
  const identical = await maybeCollapseIdenticalRead(cmd, rawCmd, output, exitCode, cwd, cacheMinBytes);
9935
10102
  if (identical !== null) return identical;
9936
- const compound = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes);
9937
- if (compound !== null) return compound;
10103
+ if (!isFileRead && (!isUnwrapped || !isCompressibleSingleCommand(cmd))) {
10104
+ const compound = await maybeCompressCompoundOutput(cmd, output, exitCode, cwd, cacheMinBytes, isUnwrapped);
10105
+ if (compound !== null) return compound;
10106
+ }
9938
10107
  if (!isFileRead && extractLineRangeReadsCompound(cmd) === null) {
9939
10108
  const genericElision = await maybeElideServedGenericOutput(cmd, output, exitCode, cwd, cacheMinBytes);
9940
10109
  if (genericElision !== null) return genericElision;
9941
10110
  }
9942
- return maybeStripAnsiOnly(output) ?? passOutput();
10111
+ const ansiStripped = maybeStripAnsiOnly(output);
10112
+ const largeHint2 = await maybeEmitLargeUncompressedHint(cmd, output, exitCode, cwd, isUnwrapped, event, ansiStripped);
10113
+ if (largeHint2 !== null) return largeHint2;
10114
+ return ansiStripped ?? passOutput();
9943
10115
  }
9944
10116
  if (Buffer.byteLength(output, "utf-8") < cacheMinBytes) return passOutput();
9945
10117
  const cacheKey = isCurlGetCommand(cmd) ? extractCurlUrl(cmd) ?? cmd : stripOutputPipeline(cmd);
@@ -9959,6 +10131,8 @@ async function postBashHandler(event) {
9959
10131
  const curlHtmlFold = maybeFoldCurlHtml(cmd, output, id);
9960
10132
  if (curlHtmlFold !== null) return curlHtmlFold;
9961
10133
  const ansiOnly = maybeStripAnsiOnly(output);
10134
+ const largeHint = await maybeEmitLargeUncompressedHint(cmd, output, exitCode, cwd, isUnwrapped, event, ansiOnly);
10135
+ if (largeHint !== null) return largeHint;
9962
10136
  if (ansiOnly !== null) return ansiOnly;
9963
10137
  } catch {
9964
10138
  }
@@ -10275,6 +10449,7 @@ function postToolUseFailureHandler(event) {
10275
10449
  const ledger = readLedger(target);
10276
10450
  const priorState = ledger.seen[signature];
10277
10451
  const editDiagnostic = diagnoseEditFailure(event, errorText);
10452
+ const sqlDiagnostic = diagnoseSqlFailure(event, errorText);
10278
10453
  if (priorState === void 0) {
10279
10454
  ledger.seen[signature] = false;
10280
10455
  ledger.order.push(signature);
@@ -10288,6 +10463,11 @@ function postToolUseFailureHandler(event) {
10288
10463
  writeLedger(target, ledger);
10289
10464
  return contextOutput(editDiagnostic);
10290
10465
  }
10466
+ if (sqlDiagnostic !== null) {
10467
+ ledger.seen[signature] = true;
10468
+ writeLedger(target, ledger);
10469
+ return contextOutput(sqlDiagnostic);
10470
+ }
10291
10471
  return passOutput();
10292
10472
  }
10293
10473
  if (priorState) return passOutput();
@@ -10296,6 +10476,9 @@ function postToolUseFailureHandler(event) {
10296
10476
  if (editDiagnostic !== null) {
10297
10477
  return contextOutput(editDiagnostic);
10298
10478
  }
10479
+ if (sqlDiagnostic !== null) {
10480
+ return contextOutput(sqlDiagnostic);
10481
+ }
10299
10482
  return contextOutput(repeatFailureNotice(toolName));
10300
10483
  } catch {
10301
10484
  return passOutput();
@@ -10572,6 +10755,37 @@ function compressGithubMcpResult(toolName, resultText) {
10572
10755
  const stripped = deepStrip(parsed, githubShouldStrip);
10573
10756
  return finishWithGenericPass(resultText, stripped);
10574
10757
  }
10758
+ var ATLASSIAN_TOOL_RE = /(?:jira|confluence|atlassian)/i;
10759
+ var ATLASSIAN_STRIP_EXACT_KEYS = /* @__PURE__ */ new Set([
10760
+ "avatarUrls",
10761
+ "avatarUrl",
10762
+ "iconUrl",
10763
+ "iconUrls",
10764
+ "self",
10765
+ "expand",
10766
+ "schema",
10767
+ "operations",
10768
+ "editmeta",
10769
+ "names",
10770
+ "_links",
10771
+ "_expandable",
10772
+ "extensions",
10773
+ "timeZone"
10774
+ ]);
10775
+ function atlassianShouldStrip(key) {
10776
+ return ATLASSIAN_STRIP_EXACT_KEYS.has(key);
10777
+ }
10778
+ function compressAtlassianMcpResult(toolName, resultText) {
10779
+ if (!ATLASSIAN_TOOL_RE.test(toolName)) return null;
10780
+ let parsed;
10781
+ try {
10782
+ parsed = JSON.parse(resultText);
10783
+ } catch {
10784
+ return null;
10785
+ }
10786
+ const stripped = deepStrip(parsed, atlassianShouldStrip);
10787
+ return finishWithGenericPass(resultText, stripped);
10788
+ }
10575
10789
  var BROWSER_TOOL_RE = /^mcp__.*(?:chrome-devtools|claude-in-chrome|playwright).*__/i;
10576
10790
  var BROWSER_CONSOLE_METHOD_RE = /(?:^|_)(?:read|list)_console_messages$/i;
10577
10791
  var BROWSER_NETWORK_METHOD_RE = /(?:^|_)(?:read|list)_network_requests$/i;
@@ -10722,10 +10936,11 @@ function stripBase64DataUrls(resultText) {
10722
10936
  function compressMcpResultWithPacks(toolName, resultText) {
10723
10937
  const base64Stripped = stripBase64DataUrls(resultText);
10724
10938
  const text = base64Stripped ?? resultText;
10725
- return compressGithubMcpResult(toolName, text) ?? compressBrowserMcpResult(toolName, text) ?? compressGWorkspaceMcpResult(toolName, text) ?? base64Stripped;
10939
+ return compressGithubMcpResult(toolName, text) ?? compressAtlassianMcpResult(toolName, text) ?? compressBrowserMcpResult(toolName, text) ?? compressGWorkspaceMcpResult(toolName, text) ?? base64Stripped;
10726
10940
  }
10727
10941
 
10728
10942
  // src/hooks_mcp.ts
10943
+ var MCP_OVERSIZED_THRESHOLD_BYTES = 25e3;
10729
10944
  function preMcpHandler(event) {
10730
10945
  const toolName = getToolName(event);
10731
10946
  if (!toolName || !event.sessionId) return passOutput();
@@ -10783,9 +10998,15 @@ function postMcpHandler(event) {
10783
10998
  minNetSavingsBytes: resolveMinNetSavingsBytes()
10784
10999
  });
10785
11000
  if (worthwhile) {
11001
+ const bodyBytes = Buffer.byteLength(redactedBody, "utf-8");
11002
+ let finalBody = redactedBody;
11003
+ if (bodyBytes >= MCP_OVERSIZED_THRESHOLD_BYTES) {
11004
+ const preview = clipToDeliveryCap(redactedBody, Buffer.byteLength(notice, "utf-8") + 500);
11005
+ finalBody = preview.text + (preview.clipped ? "\n\n...[preview truncated by token-goat; use mcp-output above to query full payload]..." : "");
11006
+ }
10786
11007
  return preserve(
10787
11008
  emitRewrite(
10788
- `${notice}${fenceWithMatches(redactedBody, injectionMatches, UNTRUSTED_TOOL_TAG)}`,
11009
+ `${notice}${fenceWithMatches(finalBody, injectionMatches, UNTRUSTED_TOOL_TAG)}`,
10789
11010
  "mcp",
10790
11011
  { kind: "mcp:compress", originalBytes }
10791
11012
  )
@@ -10794,6 +11015,29 @@ function postMcpHandler(event) {
10794
11015
  }
10795
11016
  }
10796
11017
  }
11018
+ const rawBytes = Buffer.byteLength(resultText, "utf-8");
11019
+ if (rawBytes >= MCP_OVERSIZED_THRESHOLD_BYTES && process.env["TOKEN_GOAT_MCP_COMPRESS"] !== "0") {
11020
+ if (id === null) id = storeMcpOutput(event.sessionId, toolName, toolInput, resultText);
11021
+ if (id !== null) {
11022
+ const notice = `[token-goat: oversized MCP result (${rawBytes} bytes) cached as ${id}]
11023
+ The full payload was cached to prevent harness context spill. Slicing commands:
11024
+ token-goat mcp-output ${id} --json-query '<path>' (e.g. 'issues[*].key', 'values[*].id')
11025
+ token-goat mcp-output ${id} --section '<heading>'
11026
+ token-goat mcp-output ${id} --grep '<regex>' --max-matches 20
11027
+ token-goat mcp-output ${id} --head 50
11028
+
11029
+ `;
11030
+ const preview = clipToDeliveryCap(redactedResult.text, Buffer.byteLength(notice, "utf-8") + 500);
11031
+ const previewBody = preview.text + (preview.clipped ? "\n\n...[preview truncated by token-goat; use mcp-output above to query full payload]..." : "");
11032
+ return preserve(
11033
+ emitRewrite(
11034
+ `${notice}${fenceWithMatches(previewBody, injectionMatches, UNTRUSTED_TOOL_TAG)}`,
11035
+ "mcp",
11036
+ { kind: "mcp:oversized", originalBytes: rawBytes }
11037
+ )
11038
+ );
11039
+ }
11040
+ }
10797
11041
  return passOrFence();
10798
11042
  }
10799
11043
  registerHook("pre_tool_use", preMcpHandler, { toolPattern: "^mcp__" });
@@ -11028,7 +11272,7 @@ function buildSubagentBriefing() {
11028
11272
  }
11029
11273
  const tail = [];
11030
11274
  tail.push("");
11031
- tail.push('Before your first read of any file, check for a token-goat command that returns just what you need and run it instead of a full-file read or wide grep: `token-goat symbol <name>`, `token-goat read "file::symbol"`, `token-goat section "file::<heading>"`. Skipping that check is a violation, not an oversight; the only exemptions are a file under ~200 lines you need whole, a never-indexed file, or an image.');
11275
+ tail.push('Before your first read of any file, check for a token-goat command that returns just what you need and run it instead of a full-file read or wide grep: `token-goat symbol <name>`, `token-goat read "file::symbol"`, `token-goat section "file::<heading>"`, `token-goat json-query file \'a.b.c\'`. Skipping that check is a violation, not an oversight; the only exemptions are a file under ~200 lines you need whole, a never-indexed file, or an image.');
11032
11276
  tail.push("");
11033
11277
  tail.push('Report contract: cite evidence as `file::symbol` or a token-goat recall id (`token-goat mcp-output <id> --full`) rather than pasting bodies; paste a fenced block only when the exact bytes are load-bearing; state every unverified claim explicitly (e.g. "not verified: ...") rather than omitting it.');
11034
11278
  const withCacheIds = head.join("\n") + cacheIdsBlock + "\n" + tail.join("\n");