token-goat 2.9.1 → 2.9.2

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.
@@ -25,7 +25,7 @@ import {
25
25
  runSkeleton,
26
26
  runSymbol,
27
27
  withPinnedReads
28
- } from "./token-goat-chunk-SXSWQMNP.mjs";
28
+ } from "./token-goat-chunk-FXAPKVRG.mjs";
29
29
  import {
30
30
  buildProjectMap,
31
31
  embeddingsDepsAvailable,
@@ -34,7 +34,7 @@ import {
34
34
  getProjectIndexCounts,
35
35
  isWorkerRunning,
36
36
  mapLookupBytesSaved
37
- } from "./token-goat-chunk-FDXINYK4.mjs";
37
+ } from "./token-goat-chunk-LJ3CHCTT.mjs";
38
38
  import {
39
39
  ENV_KEYS,
40
40
  VERSION,
@@ -48,7 +48,7 @@ import {
48
48
  recordStat,
49
49
  resolveProjectRoot,
50
50
  savedTokensFromBytes
51
- } from "./token-goat-chunk-4ZDRTNGV.mjs";
51
+ } from "./token-goat-chunk-UZ2NFOOZ.mjs";
52
52
  import "./token-goat-chunk-AO2QD2AG.mjs";
53
53
  import "./token-goat-chunk-AEX54RUZ.mjs";
54
54
 
@@ -96,7 +96,7 @@ import {
96
96
  toDisplayPath,
97
97
  toKB,
98
98
  withFileLock
99
- } from "./token-goat-chunk-4ZDRTNGV.mjs";
99
+ } from "./token-goat-chunk-UZ2NFOOZ.mjs";
100
100
  import {
101
101
  registerReset
102
102
  } from "./token-goat-chunk-AO2QD2AG.mjs";
@@ -3825,10 +3825,10 @@ function getGlobMatchCount(signature) {
3825
3825
  return _globQueries.get(signature) ?? null;
3826
3826
  }
3827
3827
  function setLastTabContext(text) {
3828
- _lastTabContext = text;
3828
+ _lastTabContext = shortFingerprint(text);
3829
3829
  }
3830
- function getLastTabContext() {
3831
- return _lastTabContext;
3830
+ function lastTabContextMatches(text) {
3831
+ return _lastTabContext !== null && _lastTabContext === shortFingerprint(text);
3832
3832
  }
3833
3833
  var MAX_SEEN_IMAGE_HASHES = 16;
3834
3834
  function hasSeenImage(hash2) {
@@ -3966,7 +3966,7 @@ function exportSessionState() {
3966
3966
  grepQueries: Array.from(_grepQueries.entries()),
3967
3967
  globQueries: Array.from(_globQueries.entries()),
3968
3968
  outstandingAgentSpawns: _outstandingAgentSpawns.map((e) => [e.prompt, e.ts]),
3969
- ..._lastTabContext !== null ? { lastTabContext: _lastTabContext } : {},
3969
+ ..._lastTabContext !== null ? { lastTabContextDigest: _lastTabContext } : {},
3970
3970
  ..._seenImageHashes.length > 0 ? { seenImageHashes: [..._seenImageHashes] } : {},
3971
3971
  ..._compactedAt > 0 ? { compactedAt: _compactedAt } : {}
3972
3972
  };
@@ -3993,7 +3993,7 @@ function importSessionState(s) {
3993
3993
  _globQueries = new Map(s.globQueries ?? []);
3994
3994
  _outstandingAgentSpawns = (s.outstandingAgentSpawns ?? []).map(([prompt, ts]) => ({ prompt, ts }));
3995
3995
  _outstandingAgentSpawnsAtLoad = [..._outstandingAgentSpawns];
3996
- _lastTabContext = s.lastTabContext ?? null;
3996
+ _lastTabContext = s.lastTabContextDigest ?? null;
3997
3997
  _seenImageHashes = [...s.seenImageHashes ?? []];
3998
3998
  _compactedAt = s.compactedAt ?? 0;
3999
3999
  }
@@ -4851,12 +4851,12 @@ var COMMAND_PATTERNS = {
4851
4851
  gitImmutable: /^\s*git\s+show\s+[0-9a-f]{40}\b/i,
4852
4852
  gitDiffScoped: /\s--\s+\S/,
4853
4853
  dirListing: /^\s*(?:ls|eza|exa|dir|Get-ChildItem|gci)\b/i,
4854
- depList: /^\s*(?:npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:ls|list)\b|pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:list|freeze)\b|uv\s+pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:list|freeze)\b|pnpm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:list|ls)\b|yarn\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:list)\b|cargo\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*tree\b|bundle\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:list|show)\b|composer\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*show\b)/i,
4855
- npmInstall: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*(?:install|ci)\b/i,
4856
- npmAudit: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*audit\b(?!.*(?:--fix|fix)\b)/i,
4857
- npmOutdated: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=)?)*outdated\b/i,
4854
+ depList: /^\s*(?:npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:ls|list)\b|pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|uv\s+pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|pnpm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|ls)\b|yarn\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list)\b|cargo\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*tree\b|bundle\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|show)\b|composer\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*show\b)/i,
4855
+ npmInstall: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:install|ci)\b/i,
4856
+ npmAudit: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*audit\b(?!.*(?:--fix|fix)\b)/i,
4857
+ npmOutdated: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*outdated\b/i,
4858
4858
  envProbe: /^\s*(?:node\s+(?:-v|--version)|npm\s+(?:-v|--version)|python3?\s+(?:(?:-V)\b|--?version)|git\s+--version|uv\s+--version|go\s+version|rustc\s+--version|cargo\s+--version|java\s+--version|ruby\s+--version|gem\s+--version|php\s+--version|which\b|where\b)/i,
4859
- npx: /^\s*npx\s+(?:--?yes\s+)?(?!.*\b(?:install|add|remove|uninstall|i|rm|update|upgrade|set|get|publish|link|ci|audit|shrinkwrap|dedupe|prune|rebuild)\b)/i,
4859
+ npx: /^(?!.*\b(?:install|add|remove|uninstall|i|rm|update|upgrade|set|get|publish|link|ci|audit|shrinkwrap|dedupe|prune|rebuild)\b)\s*npx\s+(?:--?yes\s+)?/i,
4860
4860
  gitPush: /^\s*git\s+push\b/i,
4861
4861
  testRunner: /^\s*(?:npx\s+)?(?:pytest|vitest|jest|go\s+test)\b/i,
4862
4862
  lintCommand: /^\s*(?:(?:npx\s+)?eslint|(?:uv\s+run\s+)?ruff)\b/i,
@@ -5354,7 +5354,7 @@ function coerce(raw) {
5354
5354
  grepQueries,
5355
5355
  globQueries,
5356
5356
  outstandingAgentSpawns,
5357
- ...typeof o["lastTabContext"] === "string" ? { lastTabContext: o["lastTabContext"] } : {},
5357
+ ...typeof o["lastTabContextDigest"] === "string" ? { lastTabContextDigest: o["lastTabContextDigest"] } : {},
5358
5358
  ...seenImageHashes.length > 0 ? { seenImageHashes } : {},
5359
5359
  ...typeof o["compactedAt"] === "number" ? { compactedAt: o["compactedAt"] } : {},
5360
5360
  ...typeof o["created_ts"] === "number" ? { created_ts: o["created_ts"] } : {}
@@ -5483,7 +5483,7 @@ function mergeSessionState(disk, mem) {
5483
5483
  // in memory, applied again here because a union of two capped lists can exceed the cap.
5484
5484
  seenImageHashes: mergeSeenImageHashes(disk.seenImageHashes ?? [], mem.seenImageHashes ?? []),
5485
5485
  // Last-seen scalar, not an accumulating collection: prefer mem's value (this process's freshest observation) over disk's, since a newer write always supersedes an older one.
5486
- ...mem.lastTabContext !== void 0 ? { lastTabContext: mem.lastTabContext } : disk.lastTabContext !== void 0 ? { lastTabContext: disk.lastTabContext } : {},
5486
+ ...mem.lastTabContextDigest !== void 0 ? { lastTabContextDigest: mem.lastTabContextDigest } : disk.lastTabContextDigest !== void 0 ? { lastTabContextDigest: disk.lastTabContextDigest } : {},
5487
5487
  // Prefer the value already on disk: it marks the original creation time, and must never be bumped forward to the merge's "now". `mem` never carries one (it is not tracked in memory), so this is really "keep whatever disk has".
5488
5488
  ...disk.created_ts !== void 0 ? { created_ts: disk.created_ts } : mem.created_ts !== void 0 ? { created_ts: mem.created_ts } : {}
5489
5489
  };
@@ -11107,7 +11107,7 @@ function getTrackedFiles(cwd = process.cwd()) {
11107
11107
  }
11108
11108
 
11109
11109
  // src/parser_fingerprint.ts
11110
- var PARSER_FINGERPRINT = "b68587f48a3f933e";
11110
+ var PARSER_FINGERPRINT = "4659c517f042a452";
11111
11111
 
11112
11112
  // src/parser.ts
11113
11113
  import * as fs22 from "node:fs";
@@ -14440,7 +14440,7 @@ function extractSalesforceMarkup(content, filePath) {
14440
14440
  }
14441
14441
  attributeRefs(refs, markupNoComments, filePath, "controller");
14442
14442
  attributeRefs(refs, markupNoComments, filePath, "extensions", true);
14443
- const actionRe = isAura ? /\{!\s*c\.([A-Za-z_$][\w$]*)[^}]*\}/gi : /\baction\s*=\s*["']\{!\s*(?:c\.)?([A-Za-z_$][\w$]*)[^}]*\}["']/gi;
14443
+ const actionRe = isAura ? /\{!\s*c\.([A-Za-z_$][\w$]*)(?:[^}\w$][^}]*)?\}/gi : /\baction\s*=\s*["']\{!\s*(?:c\.)?([A-Za-z_$][\w$]*)(?:[^}\w$][^}]*)?\}["']/gi;
14444
14444
  for (const match of markupNoComments.matchAll(actionRe)) {
14445
14445
  const line = matchLine(markupNoComments, match.index ?? 0);
14446
14446
  refs.push(ref(filePath, match[1] ?? "", line, 0, lineContext(content, line)));
@@ -16305,7 +16305,7 @@ var FALLBACK_PATTERNS = [
16305
16305
  { re: /^[ \t]*class\s+([A-Za-z_]\w*)/, kind: "class", style: "hash" },
16306
16306
  // TS/JS function & class declarations (optionally exported/async)
16307
16307
  {
16308
- re: /^[ \t]*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/,
16308
+ re: /^[ \t]*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s*(?:\*\s*)?([A-Za-z_$][\w$]*)/,
16309
16309
  kind: "function",
16310
16310
  style: "c"
16311
16311
  },
@@ -17827,6 +17827,87 @@ function urlPolicyDenialReason(url, policy) {
17827
17827
  }
17828
17828
  return null;
17829
17829
  }
17830
+ function parseIpv6Groups(text) {
17831
+ let rest = text;
17832
+ const zoneAt = rest.indexOf("%");
17833
+ if (zoneAt !== -1) rest = rest.slice(0, zoneAt);
17834
+ if (!/^[0-9a-f:.]+$/i.test(rest) || !rest.includes(":")) return null;
17835
+ const lastColon = rest.lastIndexOf(":");
17836
+ const tail = rest.slice(lastColon + 1);
17837
+ if (tail.includes(".")) {
17838
+ const quad = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(tail);
17839
+ if (!quad) return null;
17840
+ const octets = [Number(quad[1]), Number(quad[2]), Number(quad[3]), Number(quad[4])];
17841
+ if (octets.some((n) => n > 255)) return null;
17842
+ const hi = octets[0] << 8 | octets[1];
17843
+ const lo = octets[2] << 8 | octets[3];
17844
+ rest = `${rest.slice(0, lastColon + 1)}${hi.toString(16)}:${lo.toString(16)}`;
17845
+ }
17846
+ const parseGroup = (g) => /^[0-9a-f]{1,4}$/i.test(g) ? parseInt(g, 16) : null;
17847
+ const halves = rest.split("::");
17848
+ if (halves.length > 2) return null;
17849
+ let parts;
17850
+ if (halves.length === 2) {
17851
+ const left = halves[0].length > 0 ? halves[0].split(":") : [];
17852
+ const right = halves[1].length > 0 ? halves[1].split(":") : [];
17853
+ if (left.length + right.length > 7) return null;
17854
+ parts = [...left, ...Array(8 - left.length - right.length).fill("0"), ...right];
17855
+ } else {
17856
+ parts = rest.split(":");
17857
+ if (parts.length !== 8) return null;
17858
+ }
17859
+ const groups = [];
17860
+ for (const part of parts) {
17861
+ const value = parseGroup(part);
17862
+ if (value === null) return null;
17863
+ groups.push(value);
17864
+ }
17865
+ return groups;
17866
+ }
17867
+ var METADATA_HOSTNAMES = /* @__PURE__ */ new Set([
17868
+ "metadata.google.internal",
17869
+ "metadata.goog",
17870
+ // GCE answers on the bare name too, and it is the form most of Google's own docs use.
17871
+ "metadata",
17872
+ // Alibaba Cloud's equivalent of 169.254.169.254.
17873
+ "100.100.100.200",
17874
+ // EC2 resolves both of these to 169.254.169.254 inside a VPC, and neither is a dotted quad, so
17875
+ // the link-local test below never sees them.
17876
+ "instance-data",
17877
+ "instance-data.ec2.internal"
17878
+ ]);
17879
+ var METADATA_IPV6 = /* @__PURE__ */ new Set(["fd00:ec2::254", "[fd00:ec2::254]"]);
17880
+ function metadataEndpointRefusal(url) {
17881
+ let host;
17882
+ try {
17883
+ host = new URL(url).hostname.toLowerCase().replace(/\.$/, "");
17884
+ } catch {
17885
+ return null;
17886
+ }
17887
+ if (METADATA_HOSTNAMES.has(host) || METADATA_IPV6.has(host)) {
17888
+ return `URL is a cloud instance-metadata endpoint (${host})`;
17889
+ }
17890
+ if (/^169\.254\.\d{1,3}\.\d{1,3}$/.test(host)) {
17891
+ return `URL is a link-local address (${host}), where cloud metadata services answer`;
17892
+ }
17893
+ if (embeddedIpv4Candidates(host).some(([a, b]) => a === 169 && b === 254)) {
17894
+ return `URL is a link-local address written as IPv6 (${host}), where cloud metadata services answer`;
17895
+ }
17896
+ return null;
17897
+ }
17898
+ function embeddedIpv4Candidates(host) {
17899
+ const groups = parseIpv6Groups(host.replace(/^\[/, "").replace(/\]$/, ""));
17900
+ if (groups === null) return [];
17901
+ const split = (hi, lo) => [
17902
+ hi >> 8,
17903
+ hi & 255,
17904
+ lo >> 8,
17905
+ lo & 255
17906
+ ];
17907
+ const out = [split(groups[6] ?? 0, groups[7] ?? 0)];
17908
+ if (groups[0] === 8194) out.push(split(groups[1] ?? 0, groups[2] ?? 0));
17909
+ return out;
17910
+ }
17830
17911
 
17831
17912
  export {
17832
17913
  createLazyModuleLoader,
@@ -17897,7 +17978,7 @@ export {
17897
17978
  recordGlobQuery,
17898
17979
  getGlobMatchCount,
17899
17980
  setLastTabContext,
17900
- getLastTabContext,
17981
+ lastTabContextMatches,
17901
17982
  hasSeenImage,
17902
17983
  recordSeenImage,
17903
17984
  recordOutstandingAgentSpawn,
@@ -18072,5 +18153,7 @@ export {
18072
18153
  enqueueDirtyPathSafe,
18073
18154
  matchesAllowPattern,
18074
18155
  matchesDenyPattern,
18075
- urlPolicyDenialReason
18156
+ urlPolicyDenialReason,
18157
+ parseIpv6Groups,
18158
+ metadataEndpointRefusal
18076
18159
  };
@@ -3,7 +3,7 @@ const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  deliveredOutputBytes,
5
5
  wrappedShell
6
- } from "./token-goat-chunk-LHMC5ENL.mjs";
6
+ } from "./token-goat-chunk-CGWACYYZ.mjs";
7
7
  import {
8
8
  ToolFilter,
9
9
  capTokens,
@@ -17,7 +17,7 @@ import {
17
17
  resolveMinNetSavingsBytes,
18
18
  selectFilter,
19
19
  shlexSplit
20
- } from "./token-goat-chunk-4ZDRTNGV.mjs";
20
+ } from "./token-goat-chunk-UZ2NFOOZ.mjs";
21
21
  import "./token-goat-chunk-AO2QD2AG.mjs";
22
22
  import "./token-goat-chunk-AEX54RUZ.mjs";
23
23
 
@@ -18,7 +18,7 @@ import {
18
18
  storeWebOutput,
19
19
  summarizeResidentContext,
20
20
  taskListPruneHint
21
- } from "./token-goat-chunk-MR7MNSDR.mjs";
21
+ } from "./token-goat-chunk-VCNW7BGU.mjs";
22
22
  import {
23
23
  BASH_OUTPUT_SUBDIR,
24
24
  UNTRUSTED_TOOL_TAG,
@@ -49,7 +49,6 @@ import {
49
49
  getFileServedOutputs,
50
50
  getGlobMatchCount,
51
51
  getGrepMatchCount,
52
- getLastTabContext,
53
52
  getMonitoringRecallHint,
54
53
  getOutstandingAgentSpawns,
55
54
  getSessionBashOutputs,
@@ -66,6 +65,7 @@ import {
66
65
  isBuildCommand,
67
66
  isScopedGitStatusOrDiffStatCommand,
68
67
  isTestRunnerCommand,
68
+ lastTabContextMatches,
69
69
  listSiblingSessionStates,
70
70
  loadSessionCache,
71
71
  loadSessionState,
@@ -76,6 +76,7 @@ import {
76
76
  matchesAllowPattern,
77
77
  matchesDenyPattern,
78
78
  meetsSavingsFloor,
79
+ metadataEndpointRefusal,
79
80
  probeImageMeta,
80
81
  recordBashOutput,
81
82
  recordBashRerun,
@@ -110,11 +111,11 @@ import {
110
111
  wasCliReadThisSession,
111
112
  wasFileReadThisSession,
112
113
  wasHintShown
113
- } from "./token-goat-chunk-FDXINYK4.mjs";
114
+ } from "./token-goat-chunk-LJ3CHCTT.mjs";
114
115
  import {
115
116
  canRunWrappedShell,
116
117
  deliveredOutputBytes
117
- } from "./token-goat-chunk-LHMC5ENL.mjs";
118
+ } from "./token-goat-chunk-CGWACYYZ.mjs";
118
119
  import {
119
120
  BODY_FIRST_TOOL_RESPONSE_KEYS,
120
121
  ENV_KEYS,
@@ -170,7 +171,48 @@ import {
170
171
  shortFingerprint,
171
172
  stripAnsiEscapes,
172
173
  toKB
173
- } from "./token-goat-chunk-4ZDRTNGV.mjs";
174
+ } from "./token-goat-chunk-UZ2NFOOZ.mjs";
175
+
176
+ // src/hint_suggestion_guard.ts
177
+ function looksLikeSuggestion(slice) {
178
+ return slice.includes('"');
179
+ }
180
+ var SAFE_OUTSIDE_QUOTES = /^[A-Za-z0-9 \t_./=:,@+-]*$/;
181
+ var CONTROL_OR_BIDI = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F\u200E\u200F\u202A-\u202E\u2066-\u2069\u061C\u200B-\u200D\u2028\u2029\uFE00-\uFE0F]|[\u{E0000}-\u{E007F}]/u;
182
+ function suggestionIsUnsafe(slice) {
183
+ if (slice.includes("$") || slice.includes("\n") || slice.includes("\r") || slice.includes("`")) return true;
184
+ if (CONTROL_OR_BIDI.test(slice)) return true;
185
+ const regions = slice.split('"');
186
+ if (regions.length % 2 === 0) return true;
187
+ for (let i = 2; i < regions.length; i += 2) {
188
+ if (!SAFE_OUTSIDE_QUOTES.test(regions[i] ?? "")) return true;
189
+ }
190
+ return false;
191
+ }
192
+ var OMITTED = "token-goat (command omitted: the path contains shell metacharacters)";
193
+ function stripUnsafeSuggestions(text) {
194
+ if (!text.includes("token-goat ")) return text;
195
+ let out = "";
196
+ let at = 0;
197
+ for (; ; ) {
198
+ const start = text.indexOf("token-goat ", at);
199
+ if (start === -1) return out + text.slice(at);
200
+ const lineBreak = text.slice(start).search(/[\r\n]/);
201
+ const line = lineBreak === -1 ? text.slice(start) : text.slice(start, start + lineBreak);
202
+ const firstTick = line.indexOf("`");
203
+ const narrow = firstTick === -1 ? line : line.slice(0, firstTick);
204
+ out += text.slice(at, start);
205
+ if (!looksLikeSuggestion(narrow) || !suggestionIsUnsafe(narrow)) {
206
+ out += narrow;
207
+ at = start + narrow.length;
208
+ continue;
209
+ }
210
+ const lastTick = line.lastIndexOf("`");
211
+ const wide = lastTick === -1 ? line : line.slice(0, lastTick);
212
+ out += OMITTED;
213
+ at = start + wide.length;
214
+ }
215
+ }
174
216
 
175
217
  // src/hooks_grep.ts
176
218
  function grepIntInput(toolInput, key) {
@@ -645,7 +687,7 @@ import crypto from "node:crypto";
645
687
  var TRACKED_SKILL = "token-goat";
646
688
  var MAX_COMMANDS_SHOWN = 8;
647
689
  async function currentCommandNames() {
648
- const { buildProgram } = await import("./token-goat-chunk-V5T3YNYR.mjs");
690
+ const { buildProgram } = await import("./token-goat-chunk-JMUBXBG7.mjs");
649
691
  return flattenCommandNames(buildCommandManifest(buildProgram()));
650
692
  }
651
693
  async function recordSkillVersionSnapshot(sessionId, skillName) {
@@ -5218,7 +5260,7 @@ function resolveCyclicReferences(value, utils, meta) {
5218
5260
  }
5219
5261
  const hierarchy = getMetaDataHierarchy(meta);
5220
5262
  const depth = getCyclicReferenceDepth(value, hierarchy, 0);
5221
- if (depth > 0 && hierarchy !== void 0) {
5263
+ if (hierarchy !== void 0 && depth > 0) {
5222
5264
  return hierarchy[hierarchy.length - depth]?.result;
5223
5265
  }
5224
5266
  const type = getObjectType(value);
@@ -7035,6 +7077,10 @@ function preFetchHandler(event) {
7035
7077
  try {
7036
7078
  const urlOnlyCtx = resolveWebFetchUrl(event);
7037
7079
  if (urlOnlyCtx !== null) {
7080
+ const metadataRefusal = metadataEndpointRefusal(urlOnlyCtx.url);
7081
+ if (metadataRefusal !== null) {
7082
+ return denyOutput(`WebFetch blocked: ${metadataRefusal}.`);
7083
+ }
7038
7084
  const wfCfg = loadConfig().webfetch;
7039
7085
  if (wfCfg.deny.length > 0 && matchesDenyPattern(urlOnlyCtx.url, wfCfg.deny)) {
7040
7086
  return denyOutput(`WebFetch blocked: URL matches a configured webfetch.deny pattern.`);
@@ -10104,7 +10150,7 @@ ${dataUrl}`, changed: true, savedBytes: saved, savedTokens };
10104
10150
  var TAB_CONTEXT_UNCHANGED_NOTICE = "(tabs unchanged since last check)";
10105
10151
  function dedupTabContext(text) {
10106
10152
  if (!TAB_CONTEXT_RE.test(text)) return { text, changed: false };
10107
- const isRepeat = getLastTabContext() === text;
10153
+ const isRepeat = lastTabContextMatches(text);
10108
10154
  setLastTabContext(text);
10109
10155
  if (!isRepeat) return { text, changed: false };
10110
10156
  const worthwhile = isRewriteWorthwhile({
@@ -10534,6 +10580,11 @@ function harnessForNormalization() {
10534
10580
  if (detected === "copilot_cli") return "copilot_cli";
10535
10581
  return "claude";
10536
10582
  }
10583
+ function safeSuggestions(output) {
10584
+ if (output.hookType === "deny") return { hookType: "deny", message: stripUnsafeSuggestions(output.message) };
10585
+ if (output.hookType === "context") return { hookType: "context", context: stripUnsafeSuggestions(output.context) };
10586
+ return output;
10587
+ }
10537
10588
  async function relayInProcess(eventName, rawPayload) {
10538
10589
  try {
10539
10590
  if (!isHookEventName(eventName)) {
@@ -10556,7 +10607,7 @@ async function relayInProcess(eventName, rawPayload) {
10556
10607
  loadSessionState(stateKey);
10557
10608
  } catch {
10558
10609
  }
10559
- const output = await runHook(event);
10610
+ const output = safeSuggestions(await runHook(event));
10560
10611
  try {
10561
10612
  saveSessionState(stateKey);
10562
10613
  } catch {