token-goat 2.6.32 → 2.6.33

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 (35) hide show
  1. package/README.md +20 -1
  2. package/dist/{token-goat-chunk-W3MX4LQV.mjs → token-goat-chunk-72R7M5H7.mjs} +6 -9
  3. package/dist/{token-goat-chunk-DNEPSN3P.mjs → token-goat-chunk-77CX3MCN.mjs} +4 -7
  4. package/dist/token-goat-chunk-AEX54RUZ.mjs +11 -0
  5. package/dist/{token-goat-chunk-3KW5C2KQ.mjs → token-goat-chunk-AO2QD2AG.mjs} +0 -4
  6. package/dist/{token-goat-hook-chunk-TKXOXN4J.mjs → token-goat-chunk-DG53MVNJ.mjs} +2 -98
  7. package/dist/{token-goat-chunk-N53GXI2Z.mjs → token-goat-chunk-FN6WLFIX.mjs} +14 -32
  8. package/dist/{token-goat-chunk-YWYITDOS.mjs → token-goat-chunk-G6XLWJWI.mjs} +2 -5
  9. package/dist/{token-goat-chunk-TBCLQTPG.mjs → token-goat-chunk-HPWPUBAK.mjs} +7 -7
  10. package/dist/{token-goat-chunk-DFBD2FFU.mjs → token-goat-chunk-L6FVTDPD.mjs} +9 -121
  11. package/dist/{token-goat-chunk-O7TGKV5I.mjs → token-goat-chunk-OHQ7RBLL.mjs} +23 -24
  12. package/dist/{token-goat-chunk-RD6O3PJU.mjs → token-goat-chunk-RPOXYJWK.mjs} +3642 -3329
  13. package/dist/{token-goat-chunk-GWZJ5SI2.mjs → token-goat-chunk-RQQ4SY2P.mjs} +1 -31
  14. package/dist/{token-goat-chunk-X5OPORR4.mjs → token-goat-chunk-TDYTBCT4.mjs} +1031 -1784
  15. package/dist/{token-goat-chunk-5EXIMDHA.mjs → token-goat-chunk-WFRR2DBG.mjs} +1131 -51
  16. package/dist/{token-goat-hook-chunk-UXD3B4OY.mjs → token-goat-hook-chunk-26DLRODR.mjs} +4 -7
  17. package/dist/{token-goat-chunk-4M7PSAO3.mjs → token-goat-hook-chunk-3QYSN4QV.mjs} +2 -98
  18. package/dist/{token-goat-hook-chunk-J2ZK2FYW.mjs → token-goat-hook-chunk-BUOCULAM.mjs} +0 -4
  19. package/dist/{token-goat-hook-chunk-DHW6SRHR.mjs → token-goat-hook-chunk-E6AIPKNF.mjs} +1131 -51
  20. package/dist/{token-goat-hook-chunk-TBJ5PUPQ.mjs → token-goat-hook-chunk-EKGDLI4D.mjs} +6 -9
  21. package/dist/{token-goat-hook-chunk-VHZECEQD.mjs → token-goat-hook-chunk-HXHFLKEL.mjs} +1 -31
  22. package/dist/{token-goat-hook-chunk-DJZGX27J.mjs → token-goat-hook-chunk-QD2DX2U7.mjs} +7 -120
  23. package/dist/token-goat-hook-chunk-RFRLWOQH.mjs +11 -0
  24. package/dist/{token-goat-hook-chunk-WBTHUYJP.mjs → token-goat-hook-chunk-UWV4MTYI.mjs} +1039 -1790
  25. package/dist/{token-goat-hook-chunk-Q5URQRIF.mjs → token-goat-hook-chunk-VDXQXYJK.mjs} +14 -32
  26. package/dist/{token-goat-hook-chunk-6NF4WM2U.mjs → token-goat-hook-chunk-WBBHV6TZ.mjs} +3643 -3330
  27. package/dist/token-goat-hook-chunk-XBOWDNJB.mjs +23 -0
  28. package/dist/{token-goat-hook-chunk-PCP4W65Z.mjs → token-goat-hook-chunk-XUMIVYEN.mjs} +2 -5
  29. package/dist/{token-goat-hook-chunk-LFYT4DLB.mjs → token-goat-hook-chunk-ZT47M3IA.mjs} +23 -24
  30. package/dist/token-goat-hook.mjs +7 -12
  31. package/dist/token-goat.core.mjs +7 -10
  32. package/package.json +13 -33
  33. package/dist/token-goat-chunk-3UOG7PSZ.mjs +0 -63
  34. package/dist/token-goat-hook-chunk-ANFXTEQO.mjs +0 -23
  35. package/dist/token-goat-hook-chunk-K33JMLL7.mjs +0 -63
@@ -2,17 +2,13 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  registerReset
5
- } from "./token-goat-chunk-3KW5C2KQ.mjs";
6
- import {
7
- init_define_import_meta_env
8
- } from "./token-goat-chunk-3UOG7PSZ.mjs";
5
+ } from "./token-goat-chunk-AO2QD2AG.mjs";
9
6
 
10
7
  // src/version.ts
11
- init_define_import_meta_env();
12
8
  import { createRequire } from "node:module";
13
9
  function resolveVersion() {
14
10
  if (true) {
15
- return "2.6.32";
11
+ return "2.6.33";
16
12
  }
17
13
  const require2 = createRequire(import.meta.url);
18
14
  const pkg = require2("../package.json");
@@ -21,7 +17,6 @@ function resolveVersion() {
21
17
  var VERSION = resolveVersion();
22
18
 
23
19
  // src/constants.ts
24
- init_define_import_meta_env();
25
20
  import * as fs from "node:fs";
26
21
  import * as os from "node:os";
27
22
  import * as path from "node:path";
@@ -137,7 +132,6 @@ var ENV_KEYS = {
137
132
  var SYMBOL_BODY_CHAR_CAP = 128 * 1024;
138
133
 
139
134
  // src/bridges/registry.ts
140
- init_define_import_meta_env();
141
135
  var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
142
136
  "claudecode",
143
137
  "codex",
@@ -149,6 +143,7 @@ var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
149
143
  "copilot_cli",
150
144
  "grok",
151
145
  "qwen",
146
+ "kimi",
152
147
  "generic"
153
148
  ]);
154
149
  function detectHarness() {
@@ -199,7 +194,6 @@ function resetHarnessCache() {
199
194
  registerReset(resetHarnessCache);
200
195
 
201
196
  // src/fingerprint.ts
202
- init_define_import_meta_env();
203
197
  import { createHash } from "node:crypto";
204
198
  import * as fs2 from "node:fs";
205
199
  function fingerprintContent(content) {
@@ -221,7 +215,6 @@ function fingerprintFile(filePath) {
221
215
  }
222
216
 
223
217
  // src/paths.ts
224
- init_define_import_meta_env();
225
218
  import * as fs3 from "node:fs";
226
219
  import * as path2 from "node:path";
227
220
  var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
@@ -318,7 +311,6 @@ function safeJoin(base, ...parts) {
318
311
  }
319
312
 
320
313
  // src/util.ts
321
- init_define_import_meta_env();
322
314
  import { spawn, spawnSync } from "node:child_process";
323
315
  import { chmodSync as chmodSync2, closeSync, copyFileSync, existsSync, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync as readFileSync2, renameSync, statSync as statSync2, unlinkSync, writeFileSync, writeSync } from "node:fs";
324
316
  import * as path3 from "node:path";
@@ -945,7 +937,6 @@ function suggestPackageNames(query, names) {
945
937
  }
946
938
 
947
939
  // src/project.ts
948
- init_define_import_meta_env();
949
940
  import * as fs4 from "node:fs";
950
941
  import * as os2 from "node:os";
951
942
  import * as path4 from "node:path";
@@ -1159,24 +1150,10 @@ function isInsideRoot(target, root) {
1159
1150
  }
1160
1151
 
1161
1152
  // src/config.ts
1162
- init_define_import_meta_env();
1163
1153
  import * as fs5 from "node:fs";
1164
1154
  import * as path5 from "node:path";
1165
1155
 
1166
- // node_modules/smol-toml/dist/index.js
1167
- init_define_import_meta_env();
1168
-
1169
- // node_modules/smol-toml/dist/parse.js
1170
- init_define_import_meta_env();
1171
-
1172
- // node_modules/smol-toml/dist/struct.js
1173
- init_define_import_meta_env();
1174
-
1175
- // node_modules/smol-toml/dist/primitive.js
1176
- init_define_import_meta_env();
1177
-
1178
1156
  // node_modules/smol-toml/dist/date.js
1179
- init_define_import_meta_env();
1180
1157
  var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
1181
1158
  var TomlDate = class _TomlDate extends Date {
1182
1159
  #hasDate = false;
@@ -1269,7 +1246,6 @@ var TomlDate = class _TomlDate extends Date {
1269
1246
  };
1270
1247
 
1271
1248
  // node_modules/smol-toml/dist/error.js
1272
- init_define_import_meta_env();
1273
1249
  function getLineColFromPtr(string, ptr) {
1274
1250
  let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
1275
1251
  return [lines.length, lines.pop().length + 1];
@@ -1468,11 +1444,7 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
1468
1444
  return date;
1469
1445
  }
1470
1446
 
1471
- // node_modules/smol-toml/dist/extract.js
1472
- init_define_import_meta_env();
1473
-
1474
1447
  // node_modules/smol-toml/dist/util.js
1475
- init_define_import_meta_env();
1476
1448
  function indexOfNewline(str, start = 0, end = str.length) {
1477
1449
  let idx = str.indexOf("\n", start);
1478
1450
  if (str[idx - 1] === "\r")
@@ -1862,7 +1834,6 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
1862
1834
  }
1863
1835
 
1864
1836
  // node_modules/smol-toml/dist/stringify.js
1865
- init_define_import_meta_env();
1866
1837
  var BARE_KEY = /^[a-z0-9-_]+$/i;
1867
1838
  function extendedTypeOf(obj) {
1868
1839
  let type = typeof obj;
@@ -2004,7 +1975,6 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
2004
1975
  }
2005
1976
 
2006
1977
  // src/env.ts
2007
- init_define_import_meta_env();
2008
1978
  var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
2009
1979
  var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
2010
1980
  function envStr(key, defaultVal) {
@@ -3248,11 +3218,1051 @@ function saveConfig(config) {
3248
3218
  _cached2 = null;
3249
3219
  }
3250
3220
 
3221
+ // src/parser_types.ts
3222
+ import * as path6 from "node:path";
3223
+ var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
3224
+ [".py", "python"],
3225
+ [".pyi", "python"],
3226
+ [".ts", "typescript"],
3227
+ [".tsx", "typescript"],
3228
+ [".mts", "typescript"],
3229
+ [".cts", "typescript"],
3230
+ [".js", "javascript"],
3231
+ [".jsx", "javascript"],
3232
+ [".mjs", "javascript"],
3233
+ [".cjs", "javascript"],
3234
+ [".rs", "rust"],
3235
+ [".go", "go"],
3236
+ [".c", "c"],
3237
+ [".h", "c"],
3238
+ [".cpp", "cpp"],
3239
+ [".cc", "cpp"],
3240
+ [".cxx", "cpp"],
3241
+ [".hpp", "cpp"],
3242
+ [".hxx", "cpp"],
3243
+ [".rb", "ruby"],
3244
+ [".ruby", "ruby"],
3245
+ // Rake task files (lib/tasks/foo.rake) are plain Ruby syntax (`task :foo do ... end`),
3246
+ // parsed identically by the ruby tree-sitter grammar. Without this entry a `.rake` file
3247
+ // fell through to 'unknown' and indexed zero symbols despite the grammar handling its
3248
+ // content exactly like any other .rb file -- the same has-extractor-but-no-extension gap
3249
+ // previously fixed for `.mk` (Makefile fragments).
3250
+ [".rake", "ruby"],
3251
+ [".java", "java"],
3252
+ [".sh", "bash"],
3253
+ [".bash", "bash"],
3254
+ [".md", "markdown"],
3255
+ [".markdown", "markdown"],
3256
+ // MDX heading syntax is plain ATX and works with the existing markdown extractor as-is,
3257
+ // unlike .rst which genuinely needs an underline-style heading parser this extractor doesn't
3258
+ // implement (left as 'unknown' deliberately).
3259
+ [".mdx", "markdown"],
3260
+ [".toml", "toml"],
3261
+ [".json", "json"],
3262
+ [".yaml", "yaml"],
3263
+ [".yml", "yaml"],
3264
+ [".css", "css"],
3265
+ [".scss", "css"],
3266
+ [".sass", "css"],
3267
+ [".less", "css"],
3268
+ [".cs", "csharp"],
3269
+ [".php", "php"],
3270
+ [".html", "html"],
3271
+ [".htm", "html"],
3272
+ [".liquid", "liquid"],
3273
+ [".kt", "kotlin"],
3274
+ [".kts", "kotlin"],
3275
+ [".swift", "swift"],
3276
+ [".scala", "scala"],
3277
+ [".sc", "scala"],
3278
+ [".lua", "lua"],
3279
+ [".ex", "elixir"],
3280
+ [".exs", "elixir"],
3281
+ [".dart", "dart"],
3282
+ [".zig", "zig"],
3283
+ [".r", "r"],
3284
+ [".graphql", "graphql"],
3285
+ [".gql", "graphql"],
3286
+ [".sql", "sql"],
3287
+ [".ini", "ini"],
3288
+ [".cfg", "ini"],
3289
+ [".conf", "ini"],
3290
+ [".proto", "proto"],
3291
+ // `.mk` is the idiomatic extension for included Makefile fragments (config.mk, rules.mk,
3292
+ // common.mk); their syntax is identical to a bare `Makefile`, which FILENAME_LANGUAGE already
3293
+ // maps. Without this entry a `.mk` fragment fell through to 'unknown' and was indexed with zero
3294
+ // symbols despite extractMakefile handling its content fine -- the same has-extractor-but-no-
3295
+ // extension gap previously seen for other adapters. (importsExtensionFor already treats bare
3296
+ // Makefile basenames as `.mk` for the imports command, so extractImports' `.mk` branch was
3297
+ // reachable while symbol indexing was not.)
3298
+ [".mk", "makefile"],
3299
+ [".tf", "terraform"],
3300
+ [".tfvars", "terraform"],
3301
+ [".hcl", "terraform"],
3302
+ [".ps1", "powershell"],
3303
+ [".psm1", "powershell"],
3304
+ [".env", "env_file"],
3305
+ [".cls", "apex"],
3306
+ [".trigger", "apex"],
3307
+ [".cmp", "salesforce_markup"],
3308
+ [".app", "salesforce_markup"],
3309
+ [".evt", "salesforce_markup"],
3310
+ [".intf", "salesforce_markup"],
3311
+ [".design", "salesforce_markup"],
3312
+ [".auradoc", "salesforce_markup"],
3313
+ [".tokens", "salesforce_markup"],
3314
+ [".page", "salesforce_markup"],
3315
+ [".component", "salesforce_markup"],
3316
+ [".email", "salesforce_markup"],
3317
+ [".vue", "vue"],
3318
+ [".svelte", "svelte"],
3319
+ [".astro", "astro"],
3320
+ [".ipynb", "ipynb"]
3321
+ ]);
3322
+ var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
3323
+ ["dockerfile", "dockerfile"],
3324
+ ["makefile", "makefile"],
3325
+ ["gnumakefile", "makefile"],
3326
+ ["bsdmakefile", "makefile"],
3327
+ ["cargo.toml", "toml"],
3328
+ ["pyproject.toml", "toml"],
3329
+ ["package.json", "json"],
3330
+ ["tsconfig.json", "json"],
3331
+ [".envrc", "env_file"],
3332
+ // Gemfile and Rakefile are plain Ruby syntax with no extension -- the dominant, idiomatic
3333
+ // dependency-manifest and task-runner files in virtually every real Ruby project (analogous to
3334
+ // package.json for Node or a bare Makefile). Without these entries both fell through to
3335
+ // 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling their
3336
+ // content exactly like any other .rb file -- the same has-extractor-but-no-dispatch-entry gap
3337
+ // already fixed for bare `Makefile` / `.mk` fragments above.
3338
+ ["gemfile", "ruby"],
3339
+ ["rakefile", "ruby"],
3340
+ // Vagrantfile, Guardfile, Podfile, Capfile, Fastfile: same idiomatic extensionless-Ruby-DSL
3341
+ // pattern as Gemfile/Rakefile above -- `Vagrant.configure(...) do ... end`, Guard's `guard
3342
+ // 'rspec' do ... end`, CocoaPods' `Pod::Spec.new do |s| ... end`, Capistrano's `set :application`,
3343
+ // and fastlane's `lane :build do ... end` are all plain Ruby, parsed identically by the ruby
3344
+ // tree-sitter grammar. Without these entries each fell through to 'unknown' and indexed zero
3345
+ // symbols despite the grammar handling their content exactly like any other .rb file.
3346
+ ["vagrantfile", "ruby"],
3347
+ ["guardfile", "ruby"],
3348
+ ["podfile", "ruby"],
3349
+ ["capfile", "ruby"],
3350
+ ["fastfile", "ruby"],
3351
+ // Brewfile: Homebrew Bundle's dependency manifest (`brew "wget"`, `cask "..."`, `tap "..."`)
3352
+ // is ordinary Ruby method-call syntax, evaluated by Homebrew's own Ruby DSL -- the extensionless
3353
+ // macOS-dev-environment analogue of Gemfile/package.json, and near-universal in dotfiles repos
3354
+ // that use `brew bundle dump`/`brew bundle install`. Same has-extractor-but-no-dispatch-entry
3355
+ // gap as the other extensionless Ruby DSL files above: without this entry it fell through to
3356
+ // 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling its content
3357
+ // exactly like any other .rb file.
3358
+ ["brewfile", "ruby"]
3359
+ ]);
3360
+ var DOTENV_VARIANT_RE = /^\.env(\..+)?$/;
3361
+ function detectLanguage(filePath) {
3362
+ const base = path6.basename(filePath).toLowerCase();
3363
+ if (DOTENV_VARIANT_RE.test(base)) return "env_file";
3364
+ const byName = FILENAME_LANGUAGE.get(base);
3365
+ if (byName !== void 0) return byName;
3366
+ if (base.endsWith("-meta.xml")) {
3367
+ return "salesforce_metadata";
3368
+ }
3369
+ const ext = path6.extname(base).toLowerCase();
3370
+ return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
3371
+ }
3372
+ var UNSUPPORTED_LANGUAGE_EXTENSIONS = /* @__PURE__ */ new Map([]);
3373
+ function unsupportedLanguageName(filePath) {
3374
+ const ext = path6.extname(filePath).toLowerCase();
3375
+ return UNSUPPORTED_LANGUAGE_EXTENSIONS.get(ext);
3376
+ }
3377
+
3378
+ // src/doc_comment.ts
3379
+ function precedingDocComment(lines, lineStart, style) {
3380
+ const aboveIdx = lineStart - 2;
3381
+ if (aboveIdx < 0 || aboveIdx >= lines.length) return "";
3382
+ const aboveLine = lines[aboveIdx];
3383
+ if (aboveLine === void 0) return "";
3384
+ const aboveTrimmed = aboveLine.trim();
3385
+ if (style === "hash") {
3386
+ if (!aboveTrimmed.startsWith("#")) return "";
3387
+ const collected = [];
3388
+ let i = aboveIdx;
3389
+ while (i >= 0) {
3390
+ const line = lines[i];
3391
+ if (line === void 0) break;
3392
+ const trimmed = line.trim();
3393
+ if (!trimmed.startsWith("#")) break;
3394
+ collected.unshift(trimmed.replace(/^#+\s?/, ""));
3395
+ i--;
3396
+ }
3397
+ return collected.join("\n").trim();
3398
+ }
3399
+ if (aboveTrimmed.endsWith("*/")) {
3400
+ let blockStart = aboveIdx;
3401
+ while (blockStart >= 0) {
3402
+ const l = lines[blockStart];
3403
+ if (l === void 0) break;
3404
+ if (l.trim().startsWith("/*")) break;
3405
+ blockStart--;
3406
+ }
3407
+ if (blockStart < 0) return "";
3408
+ const opener = lines[blockStart];
3409
+ if (opener === void 0 || !opener.trim().startsWith("/*")) return "";
3410
+ const region = lines.slice(blockStart, aboveIdx + 1);
3411
+ const joined = region.join("\n").trimEnd();
3412
+ if (joined.indexOf("*/") !== joined.length - 2) return "";
3413
+ return region.map(
3414
+ (l) => l.trim().replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^\*\s?/, "").trim()
3415
+ ).filter((l) => l !== "").join("\n");
3416
+ }
3417
+ if (aboveTrimmed.startsWith("//")) {
3418
+ const collected = [];
3419
+ let i = aboveIdx;
3420
+ while (i >= 0) {
3421
+ const line = lines[i];
3422
+ if (line === void 0) break;
3423
+ const trimmed = line.trim();
3424
+ if (!trimmed.startsWith("//")) break;
3425
+ collected.unshift(trimmed.replace(/^\/\/[/!]?\s?/, ""));
3426
+ i--;
3427
+ }
3428
+ return collected.join("\n").trim();
3429
+ }
3430
+ return "";
3431
+ }
3432
+
3433
+ // src/languages/common.ts
3434
+ function buildLineIndex(text) {
3435
+ const idx = [0];
3436
+ for (let i = 0; i < text.length; i++) {
3437
+ if (text[i] === "\n") idx.push(i + 1);
3438
+ }
3439
+ return idx;
3440
+ }
3441
+ function offsetToLine(lineIndex, offset) {
3442
+ let lo = 0;
3443
+ let hi = lineIndex.length - 1;
3444
+ while (lo < hi) {
3445
+ const mid = lo + hi + 1 >> 1;
3446
+ const lineStart = lineIndex[mid];
3447
+ if (lineStart === void 0 || lineStart > offset) {
3448
+ hi = mid - 1;
3449
+ } else {
3450
+ lo = mid;
3451
+ }
3452
+ }
3453
+ return lo + 1;
3454
+ }
3455
+ function stripCstyleComments(text, lineCommentRe) {
3456
+ const lines = text.split("\n");
3457
+ let inComment = false;
3458
+ const outLines = [];
3459
+ for (const line of lines) {
3460
+ const { code, inComment: nextInComment } = stripBlockCommentSpan(line, inComment);
3461
+ outLines.push(code);
3462
+ inComment = nextInComment;
3463
+ }
3464
+ let out = outLines.join("\n");
3465
+ if (lineCommentRe !== void 0) {
3466
+ out = out.replace(lineCommentRe, (m) => " ".repeat(m.length));
3467
+ }
3468
+ return out;
3469
+ }
3470
+ function stripXmlComments(text) {
3471
+ const lines = text.split("\n");
3472
+ let inComment = false;
3473
+ const outLines = [];
3474
+ for (const line of lines) {
3475
+ let result = "";
3476
+ let j = 0;
3477
+ while (j < line.length) {
3478
+ if (!inComment) {
3479
+ const open = line.indexOf("<!--", j);
3480
+ if (open === -1) {
3481
+ result += line.slice(j);
3482
+ break;
3483
+ }
3484
+ result += line.slice(j, open);
3485
+ const close = line.indexOf("-->", open + 4);
3486
+ if (close === -1) {
3487
+ result += " ".repeat(line.length - open);
3488
+ inComment = true;
3489
+ break;
3490
+ }
3491
+ result += " ".repeat(close + 3 - open);
3492
+ j = close + 3;
3493
+ inComment = false;
3494
+ } else {
3495
+ const close = line.indexOf("-->", j);
3496
+ if (close === -1) {
3497
+ result += " ".repeat(line.length - j);
3498
+ break;
3499
+ }
3500
+ result += " ".repeat(close + 3 - j);
3501
+ j = close + 3;
3502
+ inComment = false;
3503
+ }
3504
+ }
3505
+ outLines.push(result);
3506
+ }
3507
+ return outLines.join("\n");
3508
+ }
3509
+ function scanQuotedStringEnd(content, start) {
3510
+ const quote = content[start];
3511
+ const n = content.length;
3512
+ let j = start + 1;
3513
+ while (j < n) {
3514
+ if (content[j] === "\\" && j + 1 < n) {
3515
+ j += 2;
3516
+ continue;
3517
+ }
3518
+ if (content[j] === quote) {
3519
+ j++;
3520
+ break;
3521
+ }
3522
+ if (quote !== "`" && content[j] === "\n") {
3523
+ j++;
3524
+ break;
3525
+ }
3526
+ j++;
3527
+ }
3528
+ return j;
3529
+ }
3530
+ function stripJsComments(content) {
3531
+ let out = "";
3532
+ let i = 0;
3533
+ const n = content.length;
3534
+ while (i < n) {
3535
+ const ch = content[i];
3536
+ if (ch === "/" && content[i + 1] === "/") {
3537
+ let j = i;
3538
+ while (j < n && content[j] !== "\n") j++;
3539
+ out += " ".repeat(j - i);
3540
+ i = j;
3541
+ continue;
3542
+ }
3543
+ if (ch === "/" && content[i + 1] === "*") {
3544
+ let j = i + 2;
3545
+ while (j < n && !(content[j] === "*" && content[j + 1] === "/")) j++;
3546
+ const end = j < n ? j + 2 : n;
3547
+ out += content.slice(i, end).replace(/[^\n]/g, " ");
3548
+ i = end;
3549
+ continue;
3550
+ }
3551
+ if (ch === '"' || ch === "'" || ch === "`") {
3552
+ const j = scanQuotedStringEnd(content, i);
3553
+ out += content.slice(i, j);
3554
+ i = j;
3555
+ continue;
3556
+ }
3557
+ out += ch;
3558
+ i++;
3559
+ }
3560
+ return out;
3561
+ }
3562
+ function stripHashComments(text) {
3563
+ return text.split("\n").map((line) => {
3564
+ for (let i = 0; i < line.length; i++) {
3565
+ if (line[i] === "#" && !isInsideStringLiteral(line, i)) {
3566
+ return line.slice(0, i) + " ".repeat(line.length - i);
3567
+ }
3568
+ }
3569
+ return line;
3570
+ }).join("\n");
3571
+ }
3572
+ var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
3573
+ var HTML_SCRIPT_BODY_RE = /(<script\b[^>]*>)([\s\S]*?)(<\/script\s*>)/gi;
3574
+ var HTML_CDATA_RE = /<!\[CDATA\[[\s\S]*?\]\]>/g;
3575
+ var LIQUID_COMMENT_RE = /{%-?\s*comment\s*-?%}[\s\S]*?{%-?\s*endcomment\s*-?%}/gi;
3576
+ function maskHtmlNoise(text) {
3577
+ let out = text.replace(
3578
+ HTML_SCRIPT_BODY_RE,
3579
+ (_m, open, body, close) => open + body.replace(/[^\n]/g, " ") + close
3580
+ );
3581
+ out = out.replace(HTML_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
3582
+ out = out.replace(LIQUID_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
3583
+ out = out.replace(HTML_CDATA_RE, (m) => m.replace(/[^\n]/g, " "));
3584
+ return out;
3585
+ }
3586
+ var HTML_HEADING_RE = /<h([1-6])[^>]*>(.*?)<\/h\1>/gis;
3587
+ var HTML_HEADING_TAG_STRIP_RE = /<[^>]+>/g;
3588
+ function findHtmlHeadingMatches(content) {
3589
+ const masked = maskHtmlNoise(content);
3590
+ const matches = [];
3591
+ for (const m of masked.matchAll(HTML_HEADING_RE)) {
3592
+ const level = parseInt(m[1] ?? "1", 10);
3593
+ const raw = m[2] ?? "";
3594
+ const heading = raw.replace(HTML_HEADING_TAG_STRIP_RE, "").trim();
3595
+ matches.push({ level, heading, offset: m.index ?? 0, tag: m[0] ?? "" });
3596
+ }
3597
+ return matches;
3598
+ }
3599
+ function isInsideStringLiteral(line, index, from = 0) {
3600
+ let openQuote = null;
3601
+ let i = from;
3602
+ while (i < index) {
3603
+ const ch = line[i];
3604
+ if (openQuote !== null && ch === "\\" && i + 1 < line.length) {
3605
+ i += 2;
3606
+ continue;
3607
+ }
3608
+ if (ch === '"' || ch === "'") {
3609
+ if (openQuote === null) {
3610
+ openQuote = ch;
3611
+ } else if (openQuote === ch) {
3612
+ openQuote = null;
3613
+ }
3614
+ }
3615
+ i++;
3616
+ }
3617
+ return openQuote !== null;
3618
+ }
3619
+ function stripBlockCommentSpan(line, inComment) {
3620
+ let code = "";
3621
+ let j = 0;
3622
+ let comment = inComment;
3623
+ while (j < line.length) {
3624
+ if (!comment) {
3625
+ const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
3626
+ let open = line.indexOf("/*", j);
3627
+ while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
3628
+ open = line.indexOf("/*", open + 1);
3629
+ }
3630
+ if (open === -1) {
3631
+ code += line.slice(j);
3632
+ break;
3633
+ }
3634
+ code += line.slice(j, open);
3635
+ const close = line.indexOf("*/", open + 2);
3636
+ if (close === -1) {
3637
+ code += " ".repeat(line.length - open);
3638
+ comment = true;
3639
+ break;
3640
+ }
3641
+ code += " ".repeat(close + 2 - open);
3642
+ j = close + 2;
3643
+ comment = false;
3644
+ } else {
3645
+ const close = line.indexOf("*/", j);
3646
+ if (close === -1) {
3647
+ code += " ".repeat(line.length - j);
3648
+ break;
3649
+ }
3650
+ code += " ".repeat(close + 2 - j);
3651
+ j = close + 2;
3652
+ comment = false;
3653
+ }
3654
+ }
3655
+ return { code, inComment: comment };
3656
+ }
3657
+ function stripNestedBlockCommentSpan(line, depth) {
3658
+ let code = "";
3659
+ let j = 0;
3660
+ let d = depth;
3661
+ while (j < line.length) {
3662
+ if (d === 0) {
3663
+ const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
3664
+ let open = line.indexOf("/*", j);
3665
+ while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
3666
+ open = line.indexOf("/*", open + 1);
3667
+ }
3668
+ if (open === -1) {
3669
+ code += line.slice(j);
3670
+ break;
3671
+ }
3672
+ code += line.slice(j, open);
3673
+ code += " ";
3674
+ j = open + 2;
3675
+ d = 1;
3676
+ } else {
3677
+ const open = line.indexOf("/*", j);
3678
+ const close = line.indexOf("*/", j);
3679
+ if (close === -1 && open === -1) {
3680
+ code += " ".repeat(line.length - j);
3681
+ break;
3682
+ }
3683
+ const next = close === -1 ? open : open === -1 ? close : Math.min(open, close);
3684
+ code += " ".repeat(next + 2 - j);
3685
+ d = Math.max(0, d + (next === open ? 1 : -1));
3686
+ j = next + 2;
3687
+ }
3688
+ }
3689
+ return { code, depth: d };
3690
+ }
3691
+ function stripLineComment(line, markers = ["//"]) {
3692
+ const cutIdx = lineCommentStartIndex(line, markers);
3693
+ return cutIdx === -1 ? line : line.slice(0, cutIdx);
3694
+ }
3695
+ function lineCommentStartIndex(line, markers, from = 0) {
3696
+ let cutIdx = -1;
3697
+ for (const marker of markers) {
3698
+ let idx = line.indexOf(marker, from);
3699
+ while (idx !== -1 && isInsideStringLiteral(line, idx, from)) {
3700
+ idx = line.indexOf(marker, idx + 1);
3701
+ }
3702
+ if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
3703
+ }
3704
+ return cutIdx;
3705
+ }
3706
+ function stripStringLiterals(line) {
3707
+ let out = "";
3708
+ let i = 0;
3709
+ const stack = [];
3710
+ while (i < line.length) {
3711
+ const ch = line[i];
3712
+ if (ch === "\n") {
3713
+ out += ch;
3714
+ i++;
3715
+ stack.length = 0;
3716
+ continue;
3717
+ }
3718
+ const top = stack[stack.length - 1];
3719
+ if (top === void 0) {
3720
+ if (ch === '"' || ch === "'") {
3721
+ const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
3722
+ stack.push({ kind: "string", quote: ch, bareBraceHole });
3723
+ out += ch;
3724
+ i++;
3725
+ continue;
3726
+ }
3727
+ out += ch;
3728
+ i++;
3729
+ continue;
3730
+ }
3731
+ if (top.kind === "hole") {
3732
+ if (ch === '"' || ch === "'") {
3733
+ const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
3734
+ stack.push({ kind: "string", quote: ch, bareBraceHole });
3735
+ out += ch;
3736
+ i++;
3737
+ continue;
3738
+ }
3739
+ if (ch === "{") {
3740
+ top.depth++;
3741
+ out += ch;
3742
+ i++;
3743
+ continue;
3744
+ }
3745
+ if (ch === "}") {
3746
+ if (top.depth > 0) {
3747
+ top.depth--;
3748
+ } else {
3749
+ stack.pop();
3750
+ }
3751
+ out += ch;
3752
+ i++;
3753
+ continue;
3754
+ }
3755
+ out += ch;
3756
+ i++;
3757
+ continue;
3758
+ }
3759
+ if (ch === "\\" && i + 1 < line.length) {
3760
+ out += " ";
3761
+ i += 2;
3762
+ continue;
3763
+ }
3764
+ if (ch === top.quote) {
3765
+ stack.pop();
3766
+ out += ch;
3767
+ i++;
3768
+ continue;
3769
+ }
3770
+ if (top.quote === '"') {
3771
+ if (top.bareBraceHole && ch === "{") {
3772
+ if (line[i + 1] === "{") {
3773
+ out += " ";
3774
+ i += 2;
3775
+ continue;
3776
+ }
3777
+ stack.push({ kind: "hole", depth: 0 });
3778
+ out += ch;
3779
+ i++;
3780
+ continue;
3781
+ }
3782
+ if (!top.bareBraceHole && ch === "$" && line[i + 1] === "{") {
3783
+ stack.push({ kind: "hole", depth: 0 });
3784
+ out += line.slice(i, i + 2);
3785
+ i += 2;
3786
+ continue;
3787
+ }
3788
+ if (!top.bareBraceHole && ch === "{" && line[i + 1] === "$") {
3789
+ stack.push({ kind: "hole", depth: 0 });
3790
+ out += ch;
3791
+ i++;
3792
+ continue;
3793
+ }
3794
+ }
3795
+ out += " ";
3796
+ i++;
3797
+ }
3798
+ return out;
3799
+ }
3800
+ function findMultilineCloser(line, from, state) {
3801
+ switch (state.kind) {
3802
+ case "heredoc":
3803
+ case "nowdoc": {
3804
+ const re = new RegExp(`^[ \\t]*${escapeRegExp(state.identifier)}\\b`);
3805
+ const m = re.exec(line);
3806
+ return m ? { maskEnd: m[0].length } : null;
3807
+ }
3808
+ case "tripleSingleQuote": {
3809
+ const m = /'{3,}/.exec(line.slice(from));
3810
+ return m === null ? null : { maskEnd: from + m.index + m[0].length };
3811
+ }
3812
+ case "tripleQuote": {
3813
+ const n = state.identifier !== "" ? parseInt(state.identifier, 10) : 3;
3814
+ const re = new RegExp(`"{${n},}`);
3815
+ const m = re.exec(line.slice(from));
3816
+ return m === null ? null : { maskEnd: from + m.index + m[0].length };
3817
+ }
3818
+ case "verbatim": {
3819
+ if (!state.interpolated) {
3820
+ let j2 = from;
3821
+ while (j2 < line.length) {
3822
+ if (line[j2] === '"') {
3823
+ if (line[j2 + 1] === '"') {
3824
+ j2 += 2;
3825
+ continue;
3826
+ }
3827
+ return { maskEnd: j2 + 1 };
3828
+ }
3829
+ j2++;
3830
+ }
3831
+ return null;
3832
+ }
3833
+ let j = from;
3834
+ let holeDepth = 0;
3835
+ let nestedQuote = null;
3836
+ while (j < line.length) {
3837
+ const c = line[j];
3838
+ if (nestedQuote !== null) {
3839
+ if (c === "\\" && j + 1 < line.length) {
3840
+ j += 2;
3841
+ continue;
3842
+ }
3843
+ if (c === nestedQuote) {
3844
+ nestedQuote = null;
3845
+ }
3846
+ j++;
3847
+ continue;
3848
+ }
3849
+ if (holeDepth > 0) {
3850
+ if (c === '"' || c === "'") {
3851
+ nestedQuote = c;
3852
+ j++;
3853
+ continue;
3854
+ }
3855
+ if (c === "{") holeDepth++;
3856
+ else if (c === "}") holeDepth--;
3857
+ j++;
3858
+ continue;
3859
+ }
3860
+ if (c === "{") {
3861
+ holeDepth = 1;
3862
+ j++;
3863
+ continue;
3864
+ }
3865
+ if (c === '"') {
3866
+ if (line[j + 1] === '"') {
3867
+ j += 2;
3868
+ continue;
3869
+ }
3870
+ return { maskEnd: j + 1 };
3871
+ }
3872
+ j++;
3873
+ }
3874
+ return null;
3875
+ }
3876
+ case "psHereDouble":
3877
+ return line.startsWith('"@', from) ? { maskEnd: from + 2 } : null;
3878
+ case "psHereSingle":
3879
+ return line.startsWith("'@", from) ? { maskEnd: from + 2 } : null;
3880
+ default:
3881
+ return null;
3882
+ }
3883
+ }
3884
+ var MULTILINE_OPENER_COMMENT_MARKERS = {
3885
+ php: ["//", "#"],
3886
+ kotlin: ["//"],
3887
+ csharp: ["//"],
3888
+ powershell: ["#"],
3889
+ swift: ["//"],
3890
+ elixir: ["#"]
3891
+ };
3892
+ var MULTILINE_OPENER_BLOCK_COMMENT_LANGS = /* @__PURE__ */ new Set(["php", "kotlin", "csharp", "swift"]);
3893
+ function isInsideSameLineBlockComment(line, idx, from = 0) {
3894
+ let comment = false;
3895
+ let j = from;
3896
+ while (j < idx) {
3897
+ if (!comment) {
3898
+ const open = line.indexOf("/*", j);
3899
+ if (open === -1 || open >= idx) return false;
3900
+ if (isInsideStringLiteral(line, open, from)) {
3901
+ j = open + 2;
3902
+ continue;
3903
+ }
3904
+ comment = true;
3905
+ j = open + 2;
3906
+ } else {
3907
+ const close = line.indexOf("*/", j);
3908
+ if (close === -1 || close >= idx) return true;
3909
+ comment = false;
3910
+ j = close + 2;
3911
+ }
3912
+ }
3913
+ return comment;
3914
+ }
3915
+ function findMultilineOpener(line, from, lang) {
3916
+ const commentIdx = lineCommentStartIndex(line, MULTILINE_OPENER_COMMENT_MARKERS[lang], from);
3917
+ const isCommented = (idx) => commentIdx !== -1 && idx >= commentIdx || MULTILINE_OPENER_BLOCK_COMMENT_LANGS.has(lang) && isInsideSameLineBlockComment(line, idx, from);
3918
+ if (lang === "php") {
3919
+ const re = /<<<\s*(['"]?)([A-Za-z_]\w*)\1/g;
3920
+ re.lastIndex = from;
3921
+ const m = re.exec(line);
3922
+ if (!m || isInsideStringLiteral(line, m.index, from) || isCommented(m.index)) return null;
3923
+ const identifier = m[2] ?? "";
3924
+ const kind = m[1] === "'" ? "nowdoc" : "heredoc";
3925
+ return { openStart: m.index, closesSameLine: null, state: { kind, identifier } };
3926
+ }
3927
+ if (lang === "kotlin") {
3928
+ const idx = line.indexOf('"""', from);
3929
+ if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3930
+ const closeIdx = line.indexOf('"""', idx + 3);
3931
+ if (closeIdx !== -1) {
3932
+ return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
3933
+ }
3934
+ return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
3935
+ }
3936
+ if (lang === "swift") {
3937
+ const idx = line.indexOf('"""', from);
3938
+ if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3939
+ const closeIdx = line.indexOf('"""', idx + 3);
3940
+ if (closeIdx !== -1) {
3941
+ return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
3942
+ }
3943
+ return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
3944
+ }
3945
+ if (lang === "elixir") {
3946
+ const candidates = [];
3947
+ const dq = line.indexOf('"""', from);
3948
+ if (dq !== -1) candidates.push([dq, "tripleQuote", '"""']);
3949
+ const sq = line.indexOf("'''", from);
3950
+ if (sq !== -1) candidates.push([sq, "tripleSingleQuote", "'''"]);
3951
+ candidates.sort((a, b) => a[0] - b[0]);
3952
+ const first = candidates[0];
3953
+ if (first === void 0) return null;
3954
+ const [idx, kind, delim] = first;
3955
+ if (isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3956
+ const closeIdx = line.indexOf(delim, idx + 3);
3957
+ const state = { kind, identifier: "3" };
3958
+ if (closeIdx !== -1) return { openStart: idx, closesSameLine: closeIdx + 3, state };
3959
+ return { openStart: idx, closesSameLine: null, state };
3960
+ }
3961
+ if (lang === "csharp") {
3962
+ const tripleRe = /"{3,}/g;
3963
+ tripleRe.lastIndex = from;
3964
+ const tripleM = tripleRe.exec(line);
3965
+ let tripleIdx = tripleM ? tripleM.index : -1;
3966
+ const tripleLen = tripleM ? tripleM[0].length : 0;
3967
+ if (tripleIdx !== -1 && (isInsideStringLiteral(line, tripleIdx, from) || isCommented(tripleIdx))) tripleIdx = -1;
3968
+ const verbRe = /\$?@\$?"/g;
3969
+ verbRe.lastIndex = from;
3970
+ const verbM = verbRe.exec(line);
3971
+ let verbIdx = verbM ? verbM.index : -1;
3972
+ if (verbIdx !== -1 && isCommented(verbIdx)) verbIdx = -1;
3973
+ if (verbIdx !== -1 && isInsideStringLiteral(line, verbIdx, from)) verbIdx = -1;
3974
+ if (tripleIdx === -1 && verbIdx === -1) return null;
3975
+ const useTriple = tripleIdx !== -1 && (verbIdx === -1 || tripleIdx < verbIdx);
3976
+ if (useTriple) {
3977
+ const closeRe = new RegExp(`"{${tripleLen},}`);
3978
+ const closeM = closeRe.exec(line.slice(tripleIdx + tripleLen));
3979
+ if (closeM !== null) {
3980
+ const closeIdx = tripleIdx + tripleLen + closeM.index;
3981
+ return { openStart: tripleIdx, closesSameLine: closeIdx + closeM[0].length, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
3982
+ }
3983
+ return { openStart: tripleIdx, closesSameLine: null, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
3984
+ }
3985
+ const quoteIdx = verbIdx + (verbM?.[0].length ?? 1) - 1;
3986
+ const interpolated = (verbM?.[0] ?? "").includes("$");
3987
+ const closer = findMultilineCloser(line, quoteIdx + 1, { kind: "verbatim", identifier: "", interpolated });
3988
+ if (closer !== null) {
3989
+ return { openStart: verbIdx, closesSameLine: closer.maskEnd, state: { kind: "verbatim", identifier: "", interpolated } };
3990
+ }
3991
+ return { openStart: verbIdx, closesSameLine: null, state: { kind: "verbatim", identifier: "", interpolated } };
3992
+ }
3993
+ if (lang === "powershell") {
3994
+ const re = /@("|')\s*$/;
3995
+ const tail = line.slice(from);
3996
+ const m = re.exec(tail);
3997
+ if (!m) return null;
3998
+ const openStart = from + m.index;
3999
+ if (isCommented(openStart)) return null;
4000
+ if (isInsideStringLiteral(line, openStart, from)) return null;
4001
+ const kind = m[1] === '"' ? "psHereDouble" : "psHereSingle";
4002
+ return { openStart, closesSameLine: null, state: { kind, identifier: "" } };
4003
+ }
4004
+ return null;
4005
+ }
4006
+ function stripMultilineStringSpan(line, state, lang) {
4007
+ let code = "";
4008
+ let i = 0;
4009
+ let cur = state;
4010
+ while (i < line.length) {
4011
+ if (cur !== null) {
4012
+ const closed = findMultilineCloser(line, i, cur);
4013
+ if (closed === null) {
4014
+ code += " ".repeat(line.length - i);
4015
+ i = line.length;
4016
+ continue;
4017
+ }
4018
+ code += " ".repeat(closed.maskEnd - i);
4019
+ i = closed.maskEnd;
4020
+ cur = null;
4021
+ continue;
4022
+ }
4023
+ const opened = findMultilineOpener(line, i, lang);
4024
+ if (opened === null) {
4025
+ code += line.slice(i);
4026
+ break;
4027
+ }
4028
+ code += line.slice(i, opened.openStart);
4029
+ if (opened.closesSameLine !== null) {
4030
+ code += " ".repeat(opened.closesSameLine - opened.openStart);
4031
+ i = opened.closesSameLine;
4032
+ cur = null;
4033
+ } else {
4034
+ code += " ".repeat(line.length - opened.openStart);
4035
+ i = line.length;
4036
+ cur = opened.state;
4037
+ }
4038
+ }
4039
+ return { code, state: cur };
4040
+ }
4041
+ function makeSpanSymbol(filePath, name, kind, span, parent = "", lines, style) {
4042
+ return {
4043
+ filePath,
4044
+ name,
4045
+ kind,
4046
+ lineStart: span.startLine,
4047
+ lineEnd: span.endLine,
4048
+ body: span.body,
4049
+ docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, span.startLine, style) : "",
4050
+ parent
4051
+ };
4052
+ }
4053
+ function makeLineSymbol(filePath, name, kind, line, sig, parent, lines, style) {
4054
+ return {
4055
+ filePath,
4056
+ name,
4057
+ kind,
4058
+ lineStart: line,
4059
+ lineEnd: line,
4060
+ body: sig ?? "",
4061
+ docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, line, style) : "",
4062
+ parent: parent ?? ""
4063
+ };
4064
+ }
4065
+ function makeSymbolEmitter(symbols, sections, seen, filePath, maxSymbols = 500, maxHeadingLen = 120) {
4066
+ return function emit(name, kind, line) {
4067
+ if (!name || name.length > maxHeadingLen) return;
4068
+ if (symbols.length >= maxSymbols) return;
4069
+ const key = `${name}\0${kind}\0${line}`;
4070
+ if (seen.has(key)) return;
4071
+ seen.add(key);
4072
+ symbols.push({
4073
+ filePath,
4074
+ name,
4075
+ kind,
4076
+ lineStart: line,
4077
+ lineEnd: line,
4078
+ body: "",
4079
+ docstring: "",
4080
+ parent: ""
4081
+ });
4082
+ sections.push({ heading: name, level: 1, line, endLine: line });
4083
+ };
4084
+ }
4085
+ function assignFlatEndLines(sections, totalLines) {
4086
+ for (let i = 0; i < sections.length; i++) {
4087
+ const next = sections[i + 1];
4088
+ const s = sections[i];
4089
+ if (s === void 0) continue;
4090
+ const end = next !== void 0 ? next.line - 1 : totalLines;
4091
+ s.endLine = end < s.line ? s.line : end;
4092
+ }
4093
+ }
4094
+ function propagateEndLinesToSymbols(symbols, sections) {
4095
+ const sectionMap = /* @__PURE__ */ new Map();
4096
+ for (const sec of sections) {
4097
+ const key = `${sec.heading}\0${sec.line}`;
4098
+ const queue = sectionMap.get(key);
4099
+ if (queue !== void 0) queue.push(sec.endLine);
4100
+ else sectionMap.set(key, [sec.endLine]);
4101
+ }
4102
+ return symbols.map((sym) => {
4103
+ const key = `${sym.name}\0${sym.lineStart}`;
4104
+ const endLine = sectionMap.get(key)?.shift();
4105
+ if (endLine !== void 0 && endLine !== sym.lineEnd) {
4106
+ return { ...sym, lineEnd: endLine };
4107
+ }
4108
+ return sym;
4109
+ });
4110
+ }
4111
+ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex) {
4112
+ let depth = 0;
4113
+ let quote = null;
4114
+ for (let i = openBraceIndex; i < content.length; i++) {
4115
+ const ch = content[i];
4116
+ if (quote !== null) {
4117
+ if (ch === "\\") {
4118
+ i++;
4119
+ continue;
4120
+ }
4121
+ if (ch === quote) quote = null;
4122
+ continue;
4123
+ }
4124
+ if (ch === '"' || ch === "'") {
4125
+ quote = ch;
4126
+ continue;
4127
+ }
4128
+ if (ch === "{") depth++;
4129
+ else if (ch === "}") {
4130
+ depth--;
4131
+ if (depth === 0) {
4132
+ return offsetToLine(lineIndex, i);
4133
+ }
4134
+ }
4135
+ }
4136
+ return totalLines;
4137
+ }
4138
+
4139
+ // src/languages/ini_idx.ts
4140
+ var MAX_SECTIONS = 200;
4141
+ var MAX_HEADING_LEN = 200;
4142
+ var MAX_ENV_KEYS = 200;
4143
+ var HEADER_RE = /^\[([^\]\r\n]+)\]\s*(?:[;#].*)?$/;
4144
+ var ENV_KEY_RE = /^(?:export\s+)?([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
4145
+ function extractIni(content, filePath) {
4146
+ const symbols = [];
4147
+ const sections = [];
4148
+ const seen = /* @__PURE__ */ new Set();
4149
+ const lines = content.split(/\r?\n/);
4150
+ const totalLines = lines.length;
4151
+ for (let i = 0; i < lines.length; i++) {
4152
+ if (symbols.length >= MAX_SECTIONS) break;
4153
+ const line = lines[i] ?? "";
4154
+ if (!line || line[0] !== "[") continue;
4155
+ const m = HEADER_RE.exec(line);
4156
+ if (m === null) continue;
4157
+ const name = m[1]?.trim() ?? "";
4158
+ if (!name || name.length > MAX_HEADING_LEN) continue;
4159
+ const key = `${name}\0${i + 1}`;
4160
+ if (seen.has(key)) continue;
4161
+ seen.add(key);
4162
+ symbols.push(makeLineSymbol(filePath, name, "ini_section", i + 1));
4163
+ sections.push({ heading: name, level: 1, line: i + 1, endLine: i + 1 });
4164
+ }
4165
+ sections.sort((a, b) => a.line - b.line);
4166
+ assignFlatEndLines(sections, totalLines);
4167
+ return propagateEndLinesToSymbols(symbols, sections);
4168
+ }
4169
+ function _isEscapedQuote(line, i, q) {
4170
+ if (q === "'") return false;
4171
+ let backslashes = 0;
4172
+ let j = i - 1;
4173
+ while (j >= 0 && line[j] === "\\") {
4174
+ backslashes++;
4175
+ j--;
4176
+ }
4177
+ return backslashes % 2 === 1;
4178
+ }
4179
+ function _lineClosesQuote(line, q) {
4180
+ for (let i = 0; i < line.length; i++) {
4181
+ if (line[i] === q && !_isEscapedQuote(line, i, q)) return true;
4182
+ }
4183
+ return false;
4184
+ }
4185
+ function _detectOpenQuote(value) {
4186
+ const trimmed = value.replace(/^\s+/, "");
4187
+ const q = trimmed[0];
4188
+ if (q !== '"' && q !== "'") return null;
4189
+ for (let i = 1; i < trimmed.length; i++) {
4190
+ if (trimmed[i] === q && !_isEscapedQuote(trimmed, i, q)) return null;
4191
+ }
4192
+ return q;
4193
+ }
4194
+ function extractEnv(content, filePath) {
4195
+ const symbols = [];
4196
+ const seen = /* @__PURE__ */ new Set();
4197
+ const lines = content.split(/\r?\n/);
4198
+ let openQuote = null;
4199
+ for (let i = 0; i < lines.length; i++) {
4200
+ if (symbols.length >= MAX_ENV_KEYS) break;
4201
+ const line = lines[i] ?? "";
4202
+ if (openQuote !== null) {
4203
+ if (_lineClosesQuote(line, openQuote)) openQuote = null;
4204
+ continue;
4205
+ }
4206
+ if (!line || line[0] === "#" || line[0] === ";" || line[0] === " " || line[0] === " ") continue;
4207
+ const m = ENV_KEY_RE.exec(line);
4208
+ if (m === null) continue;
4209
+ const name = m[1]?.trim() ?? "";
4210
+ if (!name || name.length > MAX_HEADING_LEN) continue;
4211
+ const key = `${name}\0${i + 1}`;
4212
+ if (seen.has(key)) continue;
4213
+ seen.add(key);
4214
+ symbols.push(makeLineSymbol(filePath, name, "env_key", i + 1));
4215
+ openQuote = _detectOpenQuote(line.slice(m[0].length));
4216
+ }
4217
+ return symbols;
4218
+ }
4219
+
4220
+ // src/dotenv_redact.ts
4221
+ var DOTENV_VALUE_PLACEHOLDER = "[REDACTED:dotenv_value]";
4222
+ var ASSIGNMENT_RE = /^(\s*(?:export\s+)?[A-Za-z_][\w.-]*\s*(?:\+?=|:(?!\/\/)))/;
4223
+ var SAFE_LINE_RE = /^\s*(?:[#;].*)?$/;
4224
+ function isDotenvPath(filePath) {
4225
+ return detectLanguage(filePath) === "env_file";
4226
+ }
4227
+ function redactDotenvValues(text) {
4228
+ const lines = text.split("\n");
4229
+ const out = [];
4230
+ let openQuote = null;
4231
+ for (const raw of lines) {
4232
+ const hasCr = raw.endsWith("\r");
4233
+ const line = hasCr ? raw.slice(0, -1) : raw;
4234
+ const eol = hasCr ? "\r" : "";
4235
+ const emit = (s) => {
4236
+ out.push(`${s}${eol}`);
4237
+ };
4238
+ if (openQuote !== null) {
4239
+ if (_lineClosesQuote(line, openQuote)) openQuote = null;
4240
+ emit(DOTENV_VALUE_PLACEHOLDER);
4241
+ continue;
4242
+ }
4243
+ if (SAFE_LINE_RE.test(line)) {
4244
+ emit(line);
4245
+ continue;
4246
+ }
4247
+ const m = ASSIGNMENT_RE.exec(line);
4248
+ if (m === null || m[1] === void 0) {
4249
+ emit(DOTENV_VALUE_PLACEHOLDER);
4250
+ continue;
4251
+ }
4252
+ const prefix = m[1];
4253
+ openQuote = _detectOpenQuote(line.slice(prefix.length));
4254
+ emit(`${prefix}${DOTENV_VALUE_PLACEHOLDER}`);
4255
+ }
4256
+ return out.join("\n");
4257
+ }
4258
+ function redactIfDotenv(filePath, text) {
4259
+ return isDotenvPath(filePath) ? redactDotenvValues(text) : text;
4260
+ }
4261
+
3251
4262
  // src/db.ts
3252
- init_define_import_meta_env();
3253
4263
  import * as fs6 from "node:fs";
3254
4264
  import { createRequire as createRequire2 } from "node:module";
3255
- import * as path6 from "node:path";
4265
+ import * as path7 from "node:path";
3256
4266
  import Database from "better-sqlite3";
3257
4267
  var _require = createRequire2(import.meta.url);
3258
4268
  var _connections = /* @__PURE__ */ new Map();
@@ -3504,7 +4514,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
3504
4514
  VALUES (new.row_id, new.label, new.content);
3505
4515
  END;
3506
4516
  `;
3507
- var SCHEMA_VERSION = 10;
4517
+ var SCHEMA_VERSION = 11;
3508
4518
  function alterTableIdempotent(conn, sql) {
3509
4519
  try {
3510
4520
  conn.exec(sql);
@@ -3512,6 +4522,26 @@ function alterTableIdempotent(conn, sql) {
3512
4522
  if (!(err instanceof Error) || !/duplicate column/i.test(err.message)) throw err;
3513
4523
  }
3514
4524
  }
4525
+ function purgeDotenvEmbeddings(conn) {
4526
+ let paths;
4527
+ try {
4528
+ paths = conn.prepare("SELECT DISTINCT file_path FROM chunks").all().map((r) => r.file_path).filter(isDotenvPath);
4529
+ } catch {
4530
+ return;
4531
+ }
4532
+ if (paths.length === 0) return;
4533
+ for (const p of paths) {
4534
+ try {
4535
+ conn.prepare("DELETE FROM chunk_vectors WHERE rowid IN (SELECT id FROM chunks WHERE file_path = ?)").run(p);
4536
+ } catch {
4537
+ }
4538
+ conn.prepare("DELETE FROM chunks WHERE file_path = ?").run(p);
4539
+ try {
4540
+ conn.prepare("UPDATE files SET embed_sha = NULL WHERE path = ?").run(p);
4541
+ } catch {
4542
+ }
4543
+ }
4544
+ }
3515
4545
  var MIGRATIONS = {
3516
4546
  // v1 -> v2: adds files.embed_sha, tracked separately from files.sha so embedding freshness can be gated independently of parse freshness (see makeIndexer in worker.ts). A pre-existing v1 database's `files` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, so a genuine ALTER TABLE failure is never silently lost.
3517
4547
  1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
@@ -3520,7 +4550,15 @@ var MIGRATIONS = {
3520
4550
  // v8 -> v9: adds symbols.parent (see SCHEMA_VERSION comment above for why). A pre-existing v8 database's `symbols` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v1 -> v2 / v2 -> v3 above.
3521
4551
  8: (conn) => alterTableIdempotent(conn, "ALTER TABLE symbols ADD COLUMN parent TEXT NOT NULL DEFAULT ''"),
3522
4552
  // v9 -> v10: adds hint_emissions.bytes_emitted (see SCHEMA_VERSION comment above for why). A pre-existing v9 database's `hint_emissions` table predates the column, so it needs an explicit ALTER TABLE here; a brand-new database already has the column from SCHEMA_SQL's CREATE TABLE above, so the ALTER TABLE would fail with "duplicate column name" there -- swallow exactly that error and rethrow anything else, same pattern as v1 -> v2 / v2 -> v3 / v8 -> v9 above.
3523
- 9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER")
4553
+ 9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER"),
4554
+ // v10 -> v11: purge chunks (and their vectors) for dotenv files. Until this version, a tracked
4555
+ // `.env` was chunked and embedded verbatim on the git path, so `semantic` returned its values --
4556
+ // see dotenv_redact.ts. Redacting from now on is not enough on its own: the embed-freshness gate
4557
+ // (isEmbedFresh in parser.ts) skips a file whose bytes have not changed, so an already-indexed
4558
+ // .env would have kept serving its pre-fix chunks indefinitely. Deleting the rows here both
4559
+ // removes the stored secrets and, by clearing embed_sha, makes the next drain re-embed the file
4560
+ // through the redacting path.
4561
+ 10: purgeDotenvEmbeddings
3524
4562
  };
3525
4563
  function runMigrations(conn, fromVersion, toVersion) {
3526
4564
  for (let v = fromVersion; v < toVersion; v++) {
@@ -3566,8 +4604,8 @@ function initConnection(conn) {
3566
4604
  }
3567
4605
  }
3568
4606
  function resolveDbPath(dbPath) {
3569
- if (path6.isAbsolute(dbPath)) return dbPath;
3570
- if (dbPath.includes("/") || dbPath.includes("\\")) return path6.resolve(dbPath);
4607
+ if (path7.isAbsolute(dbPath)) return dbPath;
4608
+ if (dbPath.includes("/") || dbPath.includes("\\")) return path7.resolve(dbPath);
3571
4609
  return safeJoin(dataDir(), dbPath);
3572
4610
  }
3573
4611
  function connectionKey(dbPath) {
@@ -3578,7 +4616,7 @@ function getDb(dbPath) {
3578
4616
  const { resolved, key } = connectionKey(dbPath);
3579
4617
  const existing = _connections.get(key);
3580
4618
  if (existing !== void 0) return existing;
3581
- const dir = path6.dirname(resolved);
4619
+ const dir = path7.dirname(resolved);
3582
4620
  try {
3583
4621
  ensureDirSync(dir);
3584
4622
  } catch (e) {
@@ -3609,7 +4647,6 @@ function closeAllDbs() {
3609
4647
  registerReset(closeAllDbs);
3610
4648
 
3611
4649
  // src/render/ansi.ts
3612
- init_define_import_meta_env();
3613
4650
  function _colorStream(isatty) {
3614
4651
  if (process.env["NO_COLOR"]) return false;
3615
4652
  return isatty;
@@ -3684,11 +4721,9 @@ var C = {
3684
4721
  };
3685
4722
 
3686
4723
  // src/stats.ts
3687
- init_define_import_meta_env();
3688
- import * as path7 from "node:path";
4724
+ import * as path8 from "node:path";
3689
4725
 
3690
4726
  // src/render/stats_renderer.ts
3691
- init_define_import_meta_env();
3692
4727
  var _STATS_MESSAGES_FALLBACK = {
3693
4728
  bytesModeOnlyNote: "tracks bytes, not vision tokens",
3694
4729
  sessionHintSplitNote: "session_hint shows realized savings; session_hint_overhead shows injected hint cost",
@@ -4578,7 +5613,7 @@ var _globalSchemaApplied = /* @__PURE__ */ new Set();
4578
5613
  registerReset(() => _globalSchemaApplied.clear());
4579
5614
  function getGlobalDb(homeDir) {
4580
5615
  const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
4581
- const dbPath = path7.join(basePath, "global.db");
5616
+ const dbPath = path8.join(basePath, "global.db");
4582
5617
  const db = getDb(dbPath);
4583
5618
  if (!_globalSchemaApplied.has(dbPath)) {
4584
5619
  db.exec(GLOBAL_SCHEMA_SQL);
@@ -4816,7 +5851,6 @@ function renderStats2(opts) {
4816
5851
  }
4817
5852
 
4818
5853
  // src/secret_redact.ts
4819
- init_define_import_meta_env();
4820
5854
  var SECRET_PATTERNS = [
4821
5855
  // Anthropic keys share OpenAI's "sk-" prefix but are more specific
4822
5856
  // ("sk-ant-"), so they're matched first — the generic OpenAI pattern's
@@ -4844,8 +5878,13 @@ var SECRET_PATTERNS = [
4844
5878
  // Redacts only the token itself, not the "Authorization: Bearer " prefix -- the lookbehind
4845
5879
  // anchors on the header name and scheme so the surrounding request-log line stays readable,
4846
5880
  // matching how AWS_ACCESS_KEY_ID=... above keeps its own prefix intact.
4847
- ["auth_bearer_token", /(?<=Authorization:\s*Bearer\s)[A-Za-z0-9\-._~+/]{10,}=*/gi],
4848
- ["auth_basic_token", /(?<=Authorization:\s*Basic\s)[A-Za-z0-9+/]{6,}=*/gi],
5881
+ // The optional quotes on either side of the colon are what let this see a header carried in
5882
+ // JSON rather than in raw wire format. Without them the lookbehind demanded the colon sit
5883
+ // directly against the header name and the scheme directly against the space, so a body like
5884
+ // {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in
5885
+ // -- matched nothing and the token was cached verbatim.
5886
+ ["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Bearer[ \t])[A-Za-z0-9\-._~+/]{10,}=*/gi],
5887
+ ["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t])[A-Za-z0-9+/]{6,}=*/gi],
4849
5888
  // JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest
4850
5889
  // realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
4851
5890
  // anchor here -- each of the three dot-separated segments requires a minimum length to avoid
@@ -4864,6 +5903,13 @@ var SECRET_PATTERNS = [
4864
5903
  // are what make the short, generic 'sig' name safe to key on: a prose or code mention of "sig"
4865
5904
  // never sits directly after a query separator followed by that much opaque token.
4866
5905
  ["presigned_signature", /(?<=[?&](?:X-Amz-Signature|X-Goog-Signature|sig)=)[A-Za-z0-9%+/=_-]{16,}/gi],
5906
+ // A password inside a connection url. `postgres://user:hunter2@db.internal` carries the
5907
+ // credential in the authority section, where there is no `key=value` separator for the
5908
+ // generic pattern below to anchor on, so a DATABASE_URL echoed by a failing migration or a
5909
+ // psql error went through untouched. The anchors are what keep this narrow: a scheme's `://`,
5910
+ // a userinfo segment, the colon, and a following `@`. `http://host:8080/path` has no `@` and
5911
+ // is left alone; so is any url without credentials.
5912
+ ["url_credentials", /(?<=:\/\/[^\s:@/]{1,64}:)[^\s:@/]{1,256}(?=@)/g],
4867
5913
  // Generic key=value assignments in .env-file and connection-string/query-string shape. The
4868
5914
  // lookbehind again redacts only the value, and the value's character class deliberately
4869
5915
  // excludes whitespace, '&', ';', '#', quote characters, and '[' ']' ':' -- that exclusion is
@@ -4879,13 +5925,19 @@ var SECRET_PATTERNS = [
4879
5925
  // this cannot backtrack catastrophically -- there is no nested or overlapping quantifier for
4880
5926
  // the engine to explore multiple ways of matching, so removing the upper bound does not
4881
5927
  // introduce a ReDoS risk.
5928
+ // Quotes are permitted around the separator, but never inside the value class. A quoted value
5929
+ // is the ordinary way secrets are written -- .env files, JSON, YAML, TOML all quote by default
5930
+ // -- and the lookbehind used to stop dead at the opening quote, so `API_KEY="..."` passed
5931
+ // through in full while the bare `API_KEY=...` was caught. The closing quote of the key name
5932
+ // blocked it from the other side too, which is what kept every JSON body unredacted. Keeping
5933
+ // quotes out of the value class is still what stops the match running past the closing quote.
4882
5934
  // The keyword may be a prefix of a longer key name rather than the whole of it, so the
4883
5935
  // trailing identifier class below is load-bearing: without it the lookbehind required the
4884
5936
  // keyword to sit immediately before the separator, and AWS_SECRET_ACCESS_KEY=,
4885
5937
  // SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches
4886
5938
  // identifier characters only, so prose that merely mentions a keyword still never reaches
4887
5939
  // a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
4888
- ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key)[a-z0-9_-]*\s*[:=]\s*)[^\s&;#'"[\]:]{4,}/gi]
5940
+ ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token)[a-z0-9_-]{0,64}["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)(?:\\[^\n]|[^\s\\&;#'"[\],{}:]){4,}/gi]
4889
5941
  ];
4890
5942
  function redactSecrets(text) {
4891
5943
  let count = 0;
@@ -4900,7 +5952,6 @@ function redactSecrets(text) {
4900
5952
  }
4901
5953
 
4902
5954
  // src/filters.ts
4903
- init_define_import_meta_env();
4904
5955
  var DROP = () => null;
4905
5956
  var FILTERS = [
4906
5957
  {
@@ -4961,7 +6012,6 @@ var FILTERS = [
4961
6012
  ];
4962
6013
 
4963
6014
  // src/bash_compress.ts
4964
- init_define_import_meta_env();
4965
6015
  function stripAnsiCodes(text) {
4966
6016
  return stripAnsiEscapes(text);
4967
6017
  }
@@ -5055,6 +6105,36 @@ export {
5055
6105
  loadPersistedConfig,
5056
6106
  CONFIG_KEY_ENV_OVERRIDES,
5057
6107
  saveConfig,
6108
+ precedingDocComment,
6109
+ buildLineIndex,
6110
+ offsetToLine,
6111
+ stripCstyleComments,
6112
+ stripXmlComments,
6113
+ scanQuotedStringEnd,
6114
+ stripJsComments,
6115
+ stripHashComments,
6116
+ maskHtmlNoise,
6117
+ findHtmlHeadingMatches,
6118
+ isInsideStringLiteral,
6119
+ stripBlockCommentSpan,
6120
+ stripNestedBlockCommentSpan,
6121
+ stripLineComment,
6122
+ stripStringLiterals,
6123
+ stripMultilineStringSpan,
6124
+ makeSpanSymbol,
6125
+ makeLineSymbol,
6126
+ makeSymbolEmitter,
6127
+ assignFlatEndLines,
6128
+ propagateEndLinesToSymbols,
6129
+ findMatchingBraceEndLine,
6130
+ extractIni,
6131
+ _lineClosesQuote,
6132
+ _detectOpenQuote,
6133
+ extractEnv,
6134
+ detectLanguage,
6135
+ unsupportedLanguageName,
6136
+ isDotenvPath,
6137
+ redactIfDotenv,
5058
6138
  getDb,
5059
6139
  colorStdout,
5060
6140
  RESET,