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-hook-chunk-J2ZK2FYW.mjs";
6
- import {
7
- init_define_import_meta_env
8
- } from "./token-goat-hook-chunk-K33JMLL7.mjs";
5
+ } from "./token-goat-hook-chunk-BUOCULAM.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/paths.ts
202
- init_define_import_meta_env();
203
197
  import * as fs2 from "node:fs";
204
198
  import * as path2 from "node:path";
205
199
  var WSL_PATH_RE = /^\/mnt\/([a-zA-Z])\/(.*)$/s;
@@ -296,7 +290,6 @@ function safeJoin(base, ...parts) {
296
290
  }
297
291
 
298
292
  // src/util.ts
299
- init_define_import_meta_env();
300
293
  import { spawn, spawnSync } from "node:child_process";
301
294
  import { chmodSync as chmodSync2, closeSync, copyFileSync, existsSync, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync, renameSync, statSync as statSync2, unlinkSync, writeFileSync, writeSync } from "node:fs";
302
295
  import * as path3 from "node:path";
@@ -910,7 +903,6 @@ function suggestPackageNames(query, names) {
910
903
  }
911
904
 
912
905
  // src/fingerprint.ts
913
- init_define_import_meta_env();
914
906
  import { createHash } from "node:crypto";
915
907
  import * as fs3 from "node:fs";
916
908
  function fingerprintContent(content) {
@@ -932,7 +924,6 @@ function fingerprintFile(filePath) {
932
924
  }
933
925
 
934
926
  // src/project.ts
935
- init_define_import_meta_env();
936
927
  import * as fs4 from "node:fs";
937
928
  import * as os2 from "node:os";
938
929
  import * as path4 from "node:path";
@@ -1146,24 +1137,10 @@ function isInsideRoot(target, root) {
1146
1137
  }
1147
1138
 
1148
1139
  // src/config.ts
1149
- init_define_import_meta_env();
1150
1140
  import * as fs5 from "node:fs";
1151
1141
  import * as path5 from "node:path";
1152
1142
 
1153
- // node_modules/smol-toml/dist/index.js
1154
- init_define_import_meta_env();
1155
-
1156
- // node_modules/smol-toml/dist/parse.js
1157
- init_define_import_meta_env();
1158
-
1159
- // node_modules/smol-toml/dist/struct.js
1160
- init_define_import_meta_env();
1161
-
1162
- // node_modules/smol-toml/dist/primitive.js
1163
- init_define_import_meta_env();
1164
-
1165
1143
  // node_modules/smol-toml/dist/date.js
1166
- init_define_import_meta_env();
1167
1144
  var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
1168
1145
  var TomlDate = class _TomlDate extends Date {
1169
1146
  #hasDate = false;
@@ -1256,7 +1233,6 @@ var TomlDate = class _TomlDate extends Date {
1256
1233
  };
1257
1234
 
1258
1235
  // node_modules/smol-toml/dist/error.js
1259
- init_define_import_meta_env();
1260
1236
  function getLineColFromPtr(string, ptr) {
1261
1237
  let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
1262
1238
  return [lines.length, lines.pop().length + 1];
@@ -1455,11 +1431,7 @@ function parseValue(value, toml, ptr, integersAsBigInt) {
1455
1431
  return date;
1456
1432
  }
1457
1433
 
1458
- // node_modules/smol-toml/dist/extract.js
1459
- init_define_import_meta_env();
1460
-
1461
1434
  // node_modules/smol-toml/dist/util.js
1462
- init_define_import_meta_env();
1463
1435
  function indexOfNewline(str, start = 0, end = str.length) {
1464
1436
  let idx = str.indexOf("\n", start);
1465
1437
  if (str[idx - 1] === "\r")
@@ -1849,7 +1821,6 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
1849
1821
  }
1850
1822
 
1851
1823
  // node_modules/smol-toml/dist/stringify.js
1852
- init_define_import_meta_env();
1853
1824
  var BARE_KEY = /^[a-z0-9-_]+$/i;
1854
1825
  function extendedTypeOf(obj) {
1855
1826
  let type = typeof obj;
@@ -1991,7 +1962,6 @@ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
1991
1962
  }
1992
1963
 
1993
1964
  // src/env.ts
1994
- init_define_import_meta_env();
1995
1965
  var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
1996
1966
  var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
1997
1967
  function envStr(key, defaultVal) {
@@ -3235,11 +3205,1051 @@ function saveConfig(config) {
3235
3205
  _cached2 = null;
3236
3206
  }
3237
3207
 
3208
+ // src/parser_types.ts
3209
+ import * as path6 from "node:path";
3210
+ var EXTENSION_LANGUAGE = /* @__PURE__ */ new Map([
3211
+ [".py", "python"],
3212
+ [".pyi", "python"],
3213
+ [".ts", "typescript"],
3214
+ [".tsx", "typescript"],
3215
+ [".mts", "typescript"],
3216
+ [".cts", "typescript"],
3217
+ [".js", "javascript"],
3218
+ [".jsx", "javascript"],
3219
+ [".mjs", "javascript"],
3220
+ [".cjs", "javascript"],
3221
+ [".rs", "rust"],
3222
+ [".go", "go"],
3223
+ [".c", "c"],
3224
+ [".h", "c"],
3225
+ [".cpp", "cpp"],
3226
+ [".cc", "cpp"],
3227
+ [".cxx", "cpp"],
3228
+ [".hpp", "cpp"],
3229
+ [".hxx", "cpp"],
3230
+ [".rb", "ruby"],
3231
+ [".ruby", "ruby"],
3232
+ // Rake task files (lib/tasks/foo.rake) are plain Ruby syntax (`task :foo do ... end`),
3233
+ // parsed identically by the ruby tree-sitter grammar. Without this entry a `.rake` file
3234
+ // fell through to 'unknown' and indexed zero symbols despite the grammar handling its
3235
+ // content exactly like any other .rb file -- the same has-extractor-but-no-extension gap
3236
+ // previously fixed for `.mk` (Makefile fragments).
3237
+ [".rake", "ruby"],
3238
+ [".java", "java"],
3239
+ [".sh", "bash"],
3240
+ [".bash", "bash"],
3241
+ [".md", "markdown"],
3242
+ [".markdown", "markdown"],
3243
+ // MDX heading syntax is plain ATX and works with the existing markdown extractor as-is,
3244
+ // unlike .rst which genuinely needs an underline-style heading parser this extractor doesn't
3245
+ // implement (left as 'unknown' deliberately).
3246
+ [".mdx", "markdown"],
3247
+ [".toml", "toml"],
3248
+ [".json", "json"],
3249
+ [".yaml", "yaml"],
3250
+ [".yml", "yaml"],
3251
+ [".css", "css"],
3252
+ [".scss", "css"],
3253
+ [".sass", "css"],
3254
+ [".less", "css"],
3255
+ [".cs", "csharp"],
3256
+ [".php", "php"],
3257
+ [".html", "html"],
3258
+ [".htm", "html"],
3259
+ [".liquid", "liquid"],
3260
+ [".kt", "kotlin"],
3261
+ [".kts", "kotlin"],
3262
+ [".swift", "swift"],
3263
+ [".scala", "scala"],
3264
+ [".sc", "scala"],
3265
+ [".lua", "lua"],
3266
+ [".ex", "elixir"],
3267
+ [".exs", "elixir"],
3268
+ [".dart", "dart"],
3269
+ [".zig", "zig"],
3270
+ [".r", "r"],
3271
+ [".graphql", "graphql"],
3272
+ [".gql", "graphql"],
3273
+ [".sql", "sql"],
3274
+ [".ini", "ini"],
3275
+ [".cfg", "ini"],
3276
+ [".conf", "ini"],
3277
+ [".proto", "proto"],
3278
+ // `.mk` is the idiomatic extension for included Makefile fragments (config.mk, rules.mk,
3279
+ // common.mk); their syntax is identical to a bare `Makefile`, which FILENAME_LANGUAGE already
3280
+ // maps. Without this entry a `.mk` fragment fell through to 'unknown' and was indexed with zero
3281
+ // symbols despite extractMakefile handling its content fine -- the same has-extractor-but-no-
3282
+ // extension gap previously seen for other adapters. (importsExtensionFor already treats bare
3283
+ // Makefile basenames as `.mk` for the imports command, so extractImports' `.mk` branch was
3284
+ // reachable while symbol indexing was not.)
3285
+ [".mk", "makefile"],
3286
+ [".tf", "terraform"],
3287
+ [".tfvars", "terraform"],
3288
+ [".hcl", "terraform"],
3289
+ [".ps1", "powershell"],
3290
+ [".psm1", "powershell"],
3291
+ [".env", "env_file"],
3292
+ [".cls", "apex"],
3293
+ [".trigger", "apex"],
3294
+ [".cmp", "salesforce_markup"],
3295
+ [".app", "salesforce_markup"],
3296
+ [".evt", "salesforce_markup"],
3297
+ [".intf", "salesforce_markup"],
3298
+ [".design", "salesforce_markup"],
3299
+ [".auradoc", "salesforce_markup"],
3300
+ [".tokens", "salesforce_markup"],
3301
+ [".page", "salesforce_markup"],
3302
+ [".component", "salesforce_markup"],
3303
+ [".email", "salesforce_markup"],
3304
+ [".vue", "vue"],
3305
+ [".svelte", "svelte"],
3306
+ [".astro", "astro"],
3307
+ [".ipynb", "ipynb"]
3308
+ ]);
3309
+ var FILENAME_LANGUAGE = /* @__PURE__ */ new Map([
3310
+ ["dockerfile", "dockerfile"],
3311
+ ["makefile", "makefile"],
3312
+ ["gnumakefile", "makefile"],
3313
+ ["bsdmakefile", "makefile"],
3314
+ ["cargo.toml", "toml"],
3315
+ ["pyproject.toml", "toml"],
3316
+ ["package.json", "json"],
3317
+ ["tsconfig.json", "json"],
3318
+ [".envrc", "env_file"],
3319
+ // Gemfile and Rakefile are plain Ruby syntax with no extension -- the dominant, idiomatic
3320
+ // dependency-manifest and task-runner files in virtually every real Ruby project (analogous to
3321
+ // package.json for Node or a bare Makefile). Without these entries both fell through to
3322
+ // 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling their
3323
+ // content exactly like any other .rb file -- the same has-extractor-but-no-dispatch-entry gap
3324
+ // already fixed for bare `Makefile` / `.mk` fragments above.
3325
+ ["gemfile", "ruby"],
3326
+ ["rakefile", "ruby"],
3327
+ // Vagrantfile, Guardfile, Podfile, Capfile, Fastfile: same idiomatic extensionless-Ruby-DSL
3328
+ // pattern as Gemfile/Rakefile above -- `Vagrant.configure(...) do ... end`, Guard's `guard
3329
+ // 'rspec' do ... end`, CocoaPods' `Pod::Spec.new do |s| ... end`, Capistrano's `set :application`,
3330
+ // and fastlane's `lane :build do ... end` are all plain Ruby, parsed identically by the ruby
3331
+ // tree-sitter grammar. Without these entries each fell through to 'unknown' and indexed zero
3332
+ // symbols despite the grammar handling their content exactly like any other .rb file.
3333
+ ["vagrantfile", "ruby"],
3334
+ ["guardfile", "ruby"],
3335
+ ["podfile", "ruby"],
3336
+ ["capfile", "ruby"],
3337
+ ["fastfile", "ruby"],
3338
+ // Brewfile: Homebrew Bundle's dependency manifest (`brew "wget"`, `cask "..."`, `tap "..."`)
3339
+ // is ordinary Ruby method-call syntax, evaluated by Homebrew's own Ruby DSL -- the extensionless
3340
+ // macOS-dev-environment analogue of Gemfile/package.json, and near-universal in dotfiles repos
3341
+ // that use `brew bundle dump`/`brew bundle install`. Same has-extractor-but-no-dispatch-entry
3342
+ // gap as the other extensionless Ruby DSL files above: without this entry it fell through to
3343
+ // 'unknown' and indexed zero symbols despite the ruby tree-sitter grammar handling its content
3344
+ // exactly like any other .rb file.
3345
+ ["brewfile", "ruby"]
3346
+ ]);
3347
+ var DOTENV_VARIANT_RE = /^\.env(\..+)?$/;
3348
+ function detectLanguage(filePath) {
3349
+ const base = path6.basename(filePath).toLowerCase();
3350
+ if (DOTENV_VARIANT_RE.test(base)) return "env_file";
3351
+ const byName = FILENAME_LANGUAGE.get(base);
3352
+ if (byName !== void 0) return byName;
3353
+ if (base.endsWith("-meta.xml")) {
3354
+ return "salesforce_metadata";
3355
+ }
3356
+ const ext = path6.extname(base).toLowerCase();
3357
+ return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
3358
+ }
3359
+ var UNSUPPORTED_LANGUAGE_EXTENSIONS = /* @__PURE__ */ new Map([]);
3360
+ function unsupportedLanguageName(filePath) {
3361
+ const ext = path6.extname(filePath).toLowerCase();
3362
+ return UNSUPPORTED_LANGUAGE_EXTENSIONS.get(ext);
3363
+ }
3364
+
3365
+ // src/doc_comment.ts
3366
+ function precedingDocComment(lines, lineStart, style) {
3367
+ const aboveIdx = lineStart - 2;
3368
+ if (aboveIdx < 0 || aboveIdx >= lines.length) return "";
3369
+ const aboveLine = lines[aboveIdx];
3370
+ if (aboveLine === void 0) return "";
3371
+ const aboveTrimmed = aboveLine.trim();
3372
+ if (style === "hash") {
3373
+ if (!aboveTrimmed.startsWith("#")) return "";
3374
+ const collected = [];
3375
+ let i = aboveIdx;
3376
+ while (i >= 0) {
3377
+ const line = lines[i];
3378
+ if (line === void 0) break;
3379
+ const trimmed = line.trim();
3380
+ if (!trimmed.startsWith("#")) break;
3381
+ collected.unshift(trimmed.replace(/^#+\s?/, ""));
3382
+ i--;
3383
+ }
3384
+ return collected.join("\n").trim();
3385
+ }
3386
+ if (aboveTrimmed.endsWith("*/")) {
3387
+ let blockStart = aboveIdx;
3388
+ while (blockStart >= 0) {
3389
+ const l = lines[blockStart];
3390
+ if (l === void 0) break;
3391
+ if (l.trim().startsWith("/*")) break;
3392
+ blockStart--;
3393
+ }
3394
+ if (blockStart < 0) return "";
3395
+ const opener = lines[blockStart];
3396
+ if (opener === void 0 || !opener.trim().startsWith("/*")) return "";
3397
+ const region = lines.slice(blockStart, aboveIdx + 1);
3398
+ const joined = region.join("\n").trimEnd();
3399
+ if (joined.indexOf("*/") !== joined.length - 2) return "";
3400
+ return region.map(
3401
+ (l) => l.trim().replace(/^\/\*+/, "").replace(/\*+\/$/, "").replace(/^\*\s?/, "").trim()
3402
+ ).filter((l) => l !== "").join("\n");
3403
+ }
3404
+ if (aboveTrimmed.startsWith("//")) {
3405
+ const collected = [];
3406
+ let i = aboveIdx;
3407
+ while (i >= 0) {
3408
+ const line = lines[i];
3409
+ if (line === void 0) break;
3410
+ const trimmed = line.trim();
3411
+ if (!trimmed.startsWith("//")) break;
3412
+ collected.unshift(trimmed.replace(/^\/\/[/!]?\s?/, ""));
3413
+ i--;
3414
+ }
3415
+ return collected.join("\n").trim();
3416
+ }
3417
+ return "";
3418
+ }
3419
+
3420
+ // src/languages/common.ts
3421
+ function buildLineIndex(text) {
3422
+ const idx = [0];
3423
+ for (let i = 0; i < text.length; i++) {
3424
+ if (text[i] === "\n") idx.push(i + 1);
3425
+ }
3426
+ return idx;
3427
+ }
3428
+ function offsetToLine(lineIndex, offset) {
3429
+ let lo = 0;
3430
+ let hi = lineIndex.length - 1;
3431
+ while (lo < hi) {
3432
+ const mid = lo + hi + 1 >> 1;
3433
+ const lineStart = lineIndex[mid];
3434
+ if (lineStart === void 0 || lineStart > offset) {
3435
+ hi = mid - 1;
3436
+ } else {
3437
+ lo = mid;
3438
+ }
3439
+ }
3440
+ return lo + 1;
3441
+ }
3442
+ function stripCstyleComments(text, lineCommentRe) {
3443
+ const lines = text.split("\n");
3444
+ let inComment = false;
3445
+ const outLines = [];
3446
+ for (const line of lines) {
3447
+ const { code, inComment: nextInComment } = stripBlockCommentSpan(line, inComment);
3448
+ outLines.push(code);
3449
+ inComment = nextInComment;
3450
+ }
3451
+ let out = outLines.join("\n");
3452
+ if (lineCommentRe !== void 0) {
3453
+ out = out.replace(lineCommentRe, (m) => " ".repeat(m.length));
3454
+ }
3455
+ return out;
3456
+ }
3457
+ function stripXmlComments(text) {
3458
+ const lines = text.split("\n");
3459
+ let inComment = false;
3460
+ const outLines = [];
3461
+ for (const line of lines) {
3462
+ let result = "";
3463
+ let j = 0;
3464
+ while (j < line.length) {
3465
+ if (!inComment) {
3466
+ const open = line.indexOf("<!--", j);
3467
+ if (open === -1) {
3468
+ result += line.slice(j);
3469
+ break;
3470
+ }
3471
+ result += line.slice(j, open);
3472
+ const close = line.indexOf("-->", open + 4);
3473
+ if (close === -1) {
3474
+ result += " ".repeat(line.length - open);
3475
+ inComment = true;
3476
+ break;
3477
+ }
3478
+ result += " ".repeat(close + 3 - open);
3479
+ j = close + 3;
3480
+ inComment = false;
3481
+ } else {
3482
+ const close = line.indexOf("-->", j);
3483
+ if (close === -1) {
3484
+ result += " ".repeat(line.length - j);
3485
+ break;
3486
+ }
3487
+ result += " ".repeat(close + 3 - j);
3488
+ j = close + 3;
3489
+ inComment = false;
3490
+ }
3491
+ }
3492
+ outLines.push(result);
3493
+ }
3494
+ return outLines.join("\n");
3495
+ }
3496
+ function scanQuotedStringEnd(content, start) {
3497
+ const quote = content[start];
3498
+ const n = content.length;
3499
+ let j = start + 1;
3500
+ while (j < n) {
3501
+ if (content[j] === "\\" && j + 1 < n) {
3502
+ j += 2;
3503
+ continue;
3504
+ }
3505
+ if (content[j] === quote) {
3506
+ j++;
3507
+ break;
3508
+ }
3509
+ if (quote !== "`" && content[j] === "\n") {
3510
+ j++;
3511
+ break;
3512
+ }
3513
+ j++;
3514
+ }
3515
+ return j;
3516
+ }
3517
+ function stripJsComments(content) {
3518
+ let out = "";
3519
+ let i = 0;
3520
+ const n = content.length;
3521
+ while (i < n) {
3522
+ const ch = content[i];
3523
+ if (ch === "/" && content[i + 1] === "/") {
3524
+ let j = i;
3525
+ while (j < n && content[j] !== "\n") j++;
3526
+ out += " ".repeat(j - i);
3527
+ i = j;
3528
+ continue;
3529
+ }
3530
+ if (ch === "/" && content[i + 1] === "*") {
3531
+ let j = i + 2;
3532
+ while (j < n && !(content[j] === "*" && content[j + 1] === "/")) j++;
3533
+ const end = j < n ? j + 2 : n;
3534
+ out += content.slice(i, end).replace(/[^\n]/g, " ");
3535
+ i = end;
3536
+ continue;
3537
+ }
3538
+ if (ch === '"' || ch === "'" || ch === "`") {
3539
+ const j = scanQuotedStringEnd(content, i);
3540
+ out += content.slice(i, j);
3541
+ i = j;
3542
+ continue;
3543
+ }
3544
+ out += ch;
3545
+ i++;
3546
+ }
3547
+ return out;
3548
+ }
3549
+ function stripHashComments(text) {
3550
+ return text.split("\n").map((line) => {
3551
+ for (let i = 0; i < line.length; i++) {
3552
+ if (line[i] === "#" && !isInsideStringLiteral(line, i)) {
3553
+ return line.slice(0, i) + " ".repeat(line.length - i);
3554
+ }
3555
+ }
3556
+ return line;
3557
+ }).join("\n");
3558
+ }
3559
+ var HTML_COMMENT_RE = /<!--[\s\S]*?-->/g;
3560
+ var HTML_SCRIPT_BODY_RE = /(<script\b[^>]*>)([\s\S]*?)(<\/script\s*>)/gi;
3561
+ var HTML_CDATA_RE = /<!\[CDATA\[[\s\S]*?\]\]>/g;
3562
+ var LIQUID_COMMENT_RE = /{%-?\s*comment\s*-?%}[\s\S]*?{%-?\s*endcomment\s*-?%}/gi;
3563
+ function maskHtmlNoise(text) {
3564
+ let out = text.replace(
3565
+ HTML_SCRIPT_BODY_RE,
3566
+ (_m, open, body, close) => open + body.replace(/[^\n]/g, " ") + close
3567
+ );
3568
+ out = out.replace(HTML_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
3569
+ out = out.replace(LIQUID_COMMENT_RE, (m) => m.replace(/[^\n]/g, " "));
3570
+ out = out.replace(HTML_CDATA_RE, (m) => m.replace(/[^\n]/g, " "));
3571
+ return out;
3572
+ }
3573
+ var HTML_HEADING_RE = /<h([1-6])[^>]*>(.*?)<\/h\1>/gis;
3574
+ var HTML_HEADING_TAG_STRIP_RE = /<[^>]+>/g;
3575
+ function findHtmlHeadingMatches(content) {
3576
+ const masked = maskHtmlNoise(content);
3577
+ const matches = [];
3578
+ for (const m of masked.matchAll(HTML_HEADING_RE)) {
3579
+ const level = parseInt(m[1] ?? "1", 10);
3580
+ const raw = m[2] ?? "";
3581
+ const heading = raw.replace(HTML_HEADING_TAG_STRIP_RE, "").trim();
3582
+ matches.push({ level, heading, offset: m.index ?? 0, tag: m[0] ?? "" });
3583
+ }
3584
+ return matches;
3585
+ }
3586
+ function isInsideStringLiteral(line, index, from = 0) {
3587
+ let openQuote = null;
3588
+ let i = from;
3589
+ while (i < index) {
3590
+ const ch = line[i];
3591
+ if (openQuote !== null && ch === "\\" && i + 1 < line.length) {
3592
+ i += 2;
3593
+ continue;
3594
+ }
3595
+ if (ch === '"' || ch === "'") {
3596
+ if (openQuote === null) {
3597
+ openQuote = ch;
3598
+ } else if (openQuote === ch) {
3599
+ openQuote = null;
3600
+ }
3601
+ }
3602
+ i++;
3603
+ }
3604
+ return openQuote !== null;
3605
+ }
3606
+ function stripBlockCommentSpan(line, inComment) {
3607
+ let code = "";
3608
+ let j = 0;
3609
+ let comment = inComment;
3610
+ while (j < line.length) {
3611
+ if (!comment) {
3612
+ const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
3613
+ let open = line.indexOf("/*", j);
3614
+ while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
3615
+ open = line.indexOf("/*", open + 1);
3616
+ }
3617
+ if (open === -1) {
3618
+ code += line.slice(j);
3619
+ break;
3620
+ }
3621
+ code += line.slice(j, open);
3622
+ const close = line.indexOf("*/", open + 2);
3623
+ if (close === -1) {
3624
+ code += " ".repeat(line.length - open);
3625
+ comment = true;
3626
+ break;
3627
+ }
3628
+ code += " ".repeat(close + 2 - open);
3629
+ j = close + 2;
3630
+ comment = false;
3631
+ } else {
3632
+ const close = line.indexOf("*/", j);
3633
+ if (close === -1) {
3634
+ code += " ".repeat(line.length - j);
3635
+ break;
3636
+ }
3637
+ code += " ".repeat(close + 2 - j);
3638
+ j = close + 2;
3639
+ comment = false;
3640
+ }
3641
+ }
3642
+ return { code, inComment: comment };
3643
+ }
3644
+ function stripNestedBlockCommentSpan(line, depth) {
3645
+ let code = "";
3646
+ let j = 0;
3647
+ let d = depth;
3648
+ while (j < line.length) {
3649
+ if (d === 0) {
3650
+ const lineCommentIdx = lineCommentStartIndex(line, ["//"], j);
3651
+ let open = line.indexOf("/*", j);
3652
+ while (open !== -1 && (isInsideStringLiteral(line, open, j) || lineCommentIdx !== -1 && open >= lineCommentIdx)) {
3653
+ open = line.indexOf("/*", open + 1);
3654
+ }
3655
+ if (open === -1) {
3656
+ code += line.slice(j);
3657
+ break;
3658
+ }
3659
+ code += line.slice(j, open);
3660
+ code += " ";
3661
+ j = open + 2;
3662
+ d = 1;
3663
+ } else {
3664
+ const open = line.indexOf("/*", j);
3665
+ const close = line.indexOf("*/", j);
3666
+ if (close === -1 && open === -1) {
3667
+ code += " ".repeat(line.length - j);
3668
+ break;
3669
+ }
3670
+ const next = close === -1 ? open : open === -1 ? close : Math.min(open, close);
3671
+ code += " ".repeat(next + 2 - j);
3672
+ d = Math.max(0, d + (next === open ? 1 : -1));
3673
+ j = next + 2;
3674
+ }
3675
+ }
3676
+ return { code, depth: d };
3677
+ }
3678
+ function stripLineComment(line, markers = ["//"]) {
3679
+ const cutIdx = lineCommentStartIndex(line, markers);
3680
+ return cutIdx === -1 ? line : line.slice(0, cutIdx);
3681
+ }
3682
+ function lineCommentStartIndex(line, markers, from = 0) {
3683
+ let cutIdx = -1;
3684
+ for (const marker of markers) {
3685
+ let idx = line.indexOf(marker, from);
3686
+ while (idx !== -1 && isInsideStringLiteral(line, idx, from)) {
3687
+ idx = line.indexOf(marker, idx + 1);
3688
+ }
3689
+ if (idx !== -1 && (cutIdx === -1 || idx < cutIdx)) cutIdx = idx;
3690
+ }
3691
+ return cutIdx;
3692
+ }
3693
+ function stripStringLiterals(line) {
3694
+ let out = "";
3695
+ let i = 0;
3696
+ const stack = [];
3697
+ while (i < line.length) {
3698
+ const ch = line[i];
3699
+ if (ch === "\n") {
3700
+ out += ch;
3701
+ i++;
3702
+ stack.length = 0;
3703
+ continue;
3704
+ }
3705
+ const top = stack[stack.length - 1];
3706
+ if (top === void 0) {
3707
+ if (ch === '"' || ch === "'") {
3708
+ const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
3709
+ stack.push({ kind: "string", quote: ch, bareBraceHole });
3710
+ out += ch;
3711
+ i++;
3712
+ continue;
3713
+ }
3714
+ out += ch;
3715
+ i++;
3716
+ continue;
3717
+ }
3718
+ if (top.kind === "hole") {
3719
+ if (ch === '"' || ch === "'") {
3720
+ const bareBraceHole = ch === '"' && i > 0 && line[i - 1] === "$";
3721
+ stack.push({ kind: "string", quote: ch, bareBraceHole });
3722
+ out += ch;
3723
+ i++;
3724
+ continue;
3725
+ }
3726
+ if (ch === "{") {
3727
+ top.depth++;
3728
+ out += ch;
3729
+ i++;
3730
+ continue;
3731
+ }
3732
+ if (ch === "}") {
3733
+ if (top.depth > 0) {
3734
+ top.depth--;
3735
+ } else {
3736
+ stack.pop();
3737
+ }
3738
+ out += ch;
3739
+ i++;
3740
+ continue;
3741
+ }
3742
+ out += ch;
3743
+ i++;
3744
+ continue;
3745
+ }
3746
+ if (ch === "\\" && i + 1 < line.length) {
3747
+ out += " ";
3748
+ i += 2;
3749
+ continue;
3750
+ }
3751
+ if (ch === top.quote) {
3752
+ stack.pop();
3753
+ out += ch;
3754
+ i++;
3755
+ continue;
3756
+ }
3757
+ if (top.quote === '"') {
3758
+ if (top.bareBraceHole && ch === "{") {
3759
+ if (line[i + 1] === "{") {
3760
+ out += " ";
3761
+ i += 2;
3762
+ continue;
3763
+ }
3764
+ stack.push({ kind: "hole", depth: 0 });
3765
+ out += ch;
3766
+ i++;
3767
+ continue;
3768
+ }
3769
+ if (!top.bareBraceHole && ch === "$" && line[i + 1] === "{") {
3770
+ stack.push({ kind: "hole", depth: 0 });
3771
+ out += line.slice(i, i + 2);
3772
+ i += 2;
3773
+ continue;
3774
+ }
3775
+ if (!top.bareBraceHole && ch === "{" && line[i + 1] === "$") {
3776
+ stack.push({ kind: "hole", depth: 0 });
3777
+ out += ch;
3778
+ i++;
3779
+ continue;
3780
+ }
3781
+ }
3782
+ out += " ";
3783
+ i++;
3784
+ }
3785
+ return out;
3786
+ }
3787
+ function findMultilineCloser(line, from, state) {
3788
+ switch (state.kind) {
3789
+ case "heredoc":
3790
+ case "nowdoc": {
3791
+ const re = new RegExp(`^[ \\t]*${escapeRegExp(state.identifier)}\\b`);
3792
+ const m = re.exec(line);
3793
+ return m ? { maskEnd: m[0].length } : null;
3794
+ }
3795
+ case "tripleSingleQuote": {
3796
+ const m = /'{3,}/.exec(line.slice(from));
3797
+ return m === null ? null : { maskEnd: from + m.index + m[0].length };
3798
+ }
3799
+ case "tripleQuote": {
3800
+ const n = state.identifier !== "" ? parseInt(state.identifier, 10) : 3;
3801
+ const re = new RegExp(`"{${n},}`);
3802
+ const m = re.exec(line.slice(from));
3803
+ return m === null ? null : { maskEnd: from + m.index + m[0].length };
3804
+ }
3805
+ case "verbatim": {
3806
+ if (!state.interpolated) {
3807
+ let j2 = from;
3808
+ while (j2 < line.length) {
3809
+ if (line[j2] === '"') {
3810
+ if (line[j2 + 1] === '"') {
3811
+ j2 += 2;
3812
+ continue;
3813
+ }
3814
+ return { maskEnd: j2 + 1 };
3815
+ }
3816
+ j2++;
3817
+ }
3818
+ return null;
3819
+ }
3820
+ let j = from;
3821
+ let holeDepth = 0;
3822
+ let nestedQuote = null;
3823
+ while (j < line.length) {
3824
+ const c = line[j];
3825
+ if (nestedQuote !== null) {
3826
+ if (c === "\\" && j + 1 < line.length) {
3827
+ j += 2;
3828
+ continue;
3829
+ }
3830
+ if (c === nestedQuote) {
3831
+ nestedQuote = null;
3832
+ }
3833
+ j++;
3834
+ continue;
3835
+ }
3836
+ if (holeDepth > 0) {
3837
+ if (c === '"' || c === "'") {
3838
+ nestedQuote = c;
3839
+ j++;
3840
+ continue;
3841
+ }
3842
+ if (c === "{") holeDepth++;
3843
+ else if (c === "}") holeDepth--;
3844
+ j++;
3845
+ continue;
3846
+ }
3847
+ if (c === "{") {
3848
+ holeDepth = 1;
3849
+ j++;
3850
+ continue;
3851
+ }
3852
+ if (c === '"') {
3853
+ if (line[j + 1] === '"') {
3854
+ j += 2;
3855
+ continue;
3856
+ }
3857
+ return { maskEnd: j + 1 };
3858
+ }
3859
+ j++;
3860
+ }
3861
+ return null;
3862
+ }
3863
+ case "psHereDouble":
3864
+ return line.startsWith('"@', from) ? { maskEnd: from + 2 } : null;
3865
+ case "psHereSingle":
3866
+ return line.startsWith("'@", from) ? { maskEnd: from + 2 } : null;
3867
+ default:
3868
+ return null;
3869
+ }
3870
+ }
3871
+ var MULTILINE_OPENER_COMMENT_MARKERS = {
3872
+ php: ["//", "#"],
3873
+ kotlin: ["//"],
3874
+ csharp: ["//"],
3875
+ powershell: ["#"],
3876
+ swift: ["//"],
3877
+ elixir: ["#"]
3878
+ };
3879
+ var MULTILINE_OPENER_BLOCK_COMMENT_LANGS = /* @__PURE__ */ new Set(["php", "kotlin", "csharp", "swift"]);
3880
+ function isInsideSameLineBlockComment(line, idx, from = 0) {
3881
+ let comment = false;
3882
+ let j = from;
3883
+ while (j < idx) {
3884
+ if (!comment) {
3885
+ const open = line.indexOf("/*", j);
3886
+ if (open === -1 || open >= idx) return false;
3887
+ if (isInsideStringLiteral(line, open, from)) {
3888
+ j = open + 2;
3889
+ continue;
3890
+ }
3891
+ comment = true;
3892
+ j = open + 2;
3893
+ } else {
3894
+ const close = line.indexOf("*/", j);
3895
+ if (close === -1 || close >= idx) return true;
3896
+ comment = false;
3897
+ j = close + 2;
3898
+ }
3899
+ }
3900
+ return comment;
3901
+ }
3902
+ function findMultilineOpener(line, from, lang) {
3903
+ const commentIdx = lineCommentStartIndex(line, MULTILINE_OPENER_COMMENT_MARKERS[lang], from);
3904
+ const isCommented = (idx) => commentIdx !== -1 && idx >= commentIdx || MULTILINE_OPENER_BLOCK_COMMENT_LANGS.has(lang) && isInsideSameLineBlockComment(line, idx, from);
3905
+ if (lang === "php") {
3906
+ const re = /<<<\s*(['"]?)([A-Za-z_]\w*)\1/g;
3907
+ re.lastIndex = from;
3908
+ const m = re.exec(line);
3909
+ if (!m || isInsideStringLiteral(line, m.index, from) || isCommented(m.index)) return null;
3910
+ const identifier = m[2] ?? "";
3911
+ const kind = m[1] === "'" ? "nowdoc" : "heredoc";
3912
+ return { openStart: m.index, closesSameLine: null, state: { kind, identifier } };
3913
+ }
3914
+ if (lang === "kotlin") {
3915
+ const idx = line.indexOf('"""', from);
3916
+ if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3917
+ const closeIdx = line.indexOf('"""', idx + 3);
3918
+ if (closeIdx !== -1) {
3919
+ return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
3920
+ }
3921
+ return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
3922
+ }
3923
+ if (lang === "swift") {
3924
+ const idx = line.indexOf('"""', from);
3925
+ if (idx === -1 || isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3926
+ const closeIdx = line.indexOf('"""', idx + 3);
3927
+ if (closeIdx !== -1) {
3928
+ return { openStart: idx, closesSameLine: closeIdx + 3, state: { kind: "tripleQuote", identifier: "3" } };
3929
+ }
3930
+ return { openStart: idx, closesSameLine: null, state: { kind: "tripleQuote", identifier: "3" } };
3931
+ }
3932
+ if (lang === "elixir") {
3933
+ const candidates = [];
3934
+ const dq = line.indexOf('"""', from);
3935
+ if (dq !== -1) candidates.push([dq, "tripleQuote", '"""']);
3936
+ const sq = line.indexOf("'''", from);
3937
+ if (sq !== -1) candidates.push([sq, "tripleSingleQuote", "'''"]);
3938
+ candidates.sort((a, b) => a[0] - b[0]);
3939
+ const first = candidates[0];
3940
+ if (first === void 0) return null;
3941
+ const [idx, kind, delim] = first;
3942
+ if (isInsideStringLiteral(line, idx, from) || isCommented(idx)) return null;
3943
+ const closeIdx = line.indexOf(delim, idx + 3);
3944
+ const state = { kind, identifier: "3" };
3945
+ if (closeIdx !== -1) return { openStart: idx, closesSameLine: closeIdx + 3, state };
3946
+ return { openStart: idx, closesSameLine: null, state };
3947
+ }
3948
+ if (lang === "csharp") {
3949
+ const tripleRe = /"{3,}/g;
3950
+ tripleRe.lastIndex = from;
3951
+ const tripleM = tripleRe.exec(line);
3952
+ let tripleIdx = tripleM ? tripleM.index : -1;
3953
+ const tripleLen = tripleM ? tripleM[0].length : 0;
3954
+ if (tripleIdx !== -1 && (isInsideStringLiteral(line, tripleIdx, from) || isCommented(tripleIdx))) tripleIdx = -1;
3955
+ const verbRe = /\$?@\$?"/g;
3956
+ verbRe.lastIndex = from;
3957
+ const verbM = verbRe.exec(line);
3958
+ let verbIdx = verbM ? verbM.index : -1;
3959
+ if (verbIdx !== -1 && isCommented(verbIdx)) verbIdx = -1;
3960
+ if (verbIdx !== -1 && isInsideStringLiteral(line, verbIdx, from)) verbIdx = -1;
3961
+ if (tripleIdx === -1 && verbIdx === -1) return null;
3962
+ const useTriple = tripleIdx !== -1 && (verbIdx === -1 || tripleIdx < verbIdx);
3963
+ if (useTriple) {
3964
+ const closeRe = new RegExp(`"{${tripleLen},}`);
3965
+ const closeM = closeRe.exec(line.slice(tripleIdx + tripleLen));
3966
+ if (closeM !== null) {
3967
+ const closeIdx = tripleIdx + tripleLen + closeM.index;
3968
+ return { openStart: tripleIdx, closesSameLine: closeIdx + closeM[0].length, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
3969
+ }
3970
+ return { openStart: tripleIdx, closesSameLine: null, state: { kind: "tripleQuote", identifier: String(tripleLen) } };
3971
+ }
3972
+ const quoteIdx = verbIdx + (verbM?.[0].length ?? 1) - 1;
3973
+ const interpolated = (verbM?.[0] ?? "").includes("$");
3974
+ const closer = findMultilineCloser(line, quoteIdx + 1, { kind: "verbatim", identifier: "", interpolated });
3975
+ if (closer !== null) {
3976
+ return { openStart: verbIdx, closesSameLine: closer.maskEnd, state: { kind: "verbatim", identifier: "", interpolated } };
3977
+ }
3978
+ return { openStart: verbIdx, closesSameLine: null, state: { kind: "verbatim", identifier: "", interpolated } };
3979
+ }
3980
+ if (lang === "powershell") {
3981
+ const re = /@("|')\s*$/;
3982
+ const tail = line.slice(from);
3983
+ const m = re.exec(tail);
3984
+ if (!m) return null;
3985
+ const openStart = from + m.index;
3986
+ if (isCommented(openStart)) return null;
3987
+ if (isInsideStringLiteral(line, openStart, from)) return null;
3988
+ const kind = m[1] === '"' ? "psHereDouble" : "psHereSingle";
3989
+ return { openStart, closesSameLine: null, state: { kind, identifier: "" } };
3990
+ }
3991
+ return null;
3992
+ }
3993
+ function stripMultilineStringSpan(line, state, lang) {
3994
+ let code = "";
3995
+ let i = 0;
3996
+ let cur = state;
3997
+ while (i < line.length) {
3998
+ if (cur !== null) {
3999
+ const closed = findMultilineCloser(line, i, cur);
4000
+ if (closed === null) {
4001
+ code += " ".repeat(line.length - i);
4002
+ i = line.length;
4003
+ continue;
4004
+ }
4005
+ code += " ".repeat(closed.maskEnd - i);
4006
+ i = closed.maskEnd;
4007
+ cur = null;
4008
+ continue;
4009
+ }
4010
+ const opened = findMultilineOpener(line, i, lang);
4011
+ if (opened === null) {
4012
+ code += line.slice(i);
4013
+ break;
4014
+ }
4015
+ code += line.slice(i, opened.openStart);
4016
+ if (opened.closesSameLine !== null) {
4017
+ code += " ".repeat(opened.closesSameLine - opened.openStart);
4018
+ i = opened.closesSameLine;
4019
+ cur = null;
4020
+ } else {
4021
+ code += " ".repeat(line.length - opened.openStart);
4022
+ i = line.length;
4023
+ cur = opened.state;
4024
+ }
4025
+ }
4026
+ return { code, state: cur };
4027
+ }
4028
+ function makeSpanSymbol(filePath, name, kind, span, parent = "", lines, style) {
4029
+ return {
4030
+ filePath,
4031
+ name,
4032
+ kind,
4033
+ lineStart: span.startLine,
4034
+ lineEnd: span.endLine,
4035
+ body: span.body,
4036
+ docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, span.startLine, style) : "",
4037
+ parent
4038
+ };
4039
+ }
4040
+ function makeLineSymbol(filePath, name, kind, line, sig, parent, lines, style) {
4041
+ return {
4042
+ filePath,
4043
+ name,
4044
+ kind,
4045
+ lineStart: line,
4046
+ lineEnd: line,
4047
+ body: sig ?? "",
4048
+ docstring: lines !== void 0 && style !== void 0 ? precedingDocComment(lines, line, style) : "",
4049
+ parent: parent ?? ""
4050
+ };
4051
+ }
4052
+ function makeSymbolEmitter(symbols, sections, seen, filePath, maxSymbols = 500, maxHeadingLen = 120) {
4053
+ return function emit(name, kind, line) {
4054
+ if (!name || name.length > maxHeadingLen) return;
4055
+ if (symbols.length >= maxSymbols) return;
4056
+ const key = `${name}\0${kind}\0${line}`;
4057
+ if (seen.has(key)) return;
4058
+ seen.add(key);
4059
+ symbols.push({
4060
+ filePath,
4061
+ name,
4062
+ kind,
4063
+ lineStart: line,
4064
+ lineEnd: line,
4065
+ body: "",
4066
+ docstring: "",
4067
+ parent: ""
4068
+ });
4069
+ sections.push({ heading: name, level: 1, line, endLine: line });
4070
+ };
4071
+ }
4072
+ function assignFlatEndLines(sections, totalLines) {
4073
+ for (let i = 0; i < sections.length; i++) {
4074
+ const next = sections[i + 1];
4075
+ const s = sections[i];
4076
+ if (s === void 0) continue;
4077
+ const end = next !== void 0 ? next.line - 1 : totalLines;
4078
+ s.endLine = end < s.line ? s.line : end;
4079
+ }
4080
+ }
4081
+ function propagateEndLinesToSymbols(symbols, sections) {
4082
+ const sectionMap = /* @__PURE__ */ new Map();
4083
+ for (const sec of sections) {
4084
+ const key = `${sec.heading}\0${sec.line}`;
4085
+ const queue = sectionMap.get(key);
4086
+ if (queue !== void 0) queue.push(sec.endLine);
4087
+ else sectionMap.set(key, [sec.endLine]);
4088
+ }
4089
+ return symbols.map((sym) => {
4090
+ const key = `${sym.name}\0${sym.lineStart}`;
4091
+ const endLine = sectionMap.get(key)?.shift();
4092
+ if (endLine !== void 0 && endLine !== sym.lineEnd) {
4093
+ return { ...sym, lineEnd: endLine };
4094
+ }
4095
+ return sym;
4096
+ });
4097
+ }
4098
+ function findMatchingBraceEndLine(content, openBraceIndex, totalLines, lineIndex) {
4099
+ let depth = 0;
4100
+ let quote = null;
4101
+ for (let i = openBraceIndex; i < content.length; i++) {
4102
+ const ch = content[i];
4103
+ if (quote !== null) {
4104
+ if (ch === "\\") {
4105
+ i++;
4106
+ continue;
4107
+ }
4108
+ if (ch === quote) quote = null;
4109
+ continue;
4110
+ }
4111
+ if (ch === '"' || ch === "'") {
4112
+ quote = ch;
4113
+ continue;
4114
+ }
4115
+ if (ch === "{") depth++;
4116
+ else if (ch === "}") {
4117
+ depth--;
4118
+ if (depth === 0) {
4119
+ return offsetToLine(lineIndex, i);
4120
+ }
4121
+ }
4122
+ }
4123
+ return totalLines;
4124
+ }
4125
+
4126
+ // src/languages/ini_idx.ts
4127
+ var MAX_SECTIONS = 200;
4128
+ var MAX_HEADING_LEN = 200;
4129
+ var MAX_ENV_KEYS = 200;
4130
+ var HEADER_RE = /^\[([^\]\r\n]+)\]\s*(?:[;#].*)?$/;
4131
+ var ENV_KEY_RE = /^(?:export\s+)?([A-Za-z_][\w.-]*)\s*(?:=|:(?!\/\/))/;
4132
+ function extractIni(content, filePath) {
4133
+ const symbols = [];
4134
+ const sections = [];
4135
+ const seen = /* @__PURE__ */ new Set();
4136
+ const lines = content.split(/\r?\n/);
4137
+ const totalLines = lines.length;
4138
+ for (let i = 0; i < lines.length; i++) {
4139
+ if (symbols.length >= MAX_SECTIONS) break;
4140
+ const line = lines[i] ?? "";
4141
+ if (!line || line[0] !== "[") continue;
4142
+ const m = HEADER_RE.exec(line);
4143
+ if (m === null) continue;
4144
+ const name = m[1]?.trim() ?? "";
4145
+ if (!name || name.length > MAX_HEADING_LEN) continue;
4146
+ const key = `${name}\0${i + 1}`;
4147
+ if (seen.has(key)) continue;
4148
+ seen.add(key);
4149
+ symbols.push(makeLineSymbol(filePath, name, "ini_section", i + 1));
4150
+ sections.push({ heading: name, level: 1, line: i + 1, endLine: i + 1 });
4151
+ }
4152
+ sections.sort((a, b) => a.line - b.line);
4153
+ assignFlatEndLines(sections, totalLines);
4154
+ return propagateEndLinesToSymbols(symbols, sections);
4155
+ }
4156
+ function _isEscapedQuote(line, i, q) {
4157
+ if (q === "'") return false;
4158
+ let backslashes = 0;
4159
+ let j = i - 1;
4160
+ while (j >= 0 && line[j] === "\\") {
4161
+ backslashes++;
4162
+ j--;
4163
+ }
4164
+ return backslashes % 2 === 1;
4165
+ }
4166
+ function _lineClosesQuote(line, q) {
4167
+ for (let i = 0; i < line.length; i++) {
4168
+ if (line[i] === q && !_isEscapedQuote(line, i, q)) return true;
4169
+ }
4170
+ return false;
4171
+ }
4172
+ function _detectOpenQuote(value) {
4173
+ const trimmed = value.replace(/^\s+/, "");
4174
+ const q = trimmed[0];
4175
+ if (q !== '"' && q !== "'") return null;
4176
+ for (let i = 1; i < trimmed.length; i++) {
4177
+ if (trimmed[i] === q && !_isEscapedQuote(trimmed, i, q)) return null;
4178
+ }
4179
+ return q;
4180
+ }
4181
+ function extractEnv(content, filePath) {
4182
+ const symbols = [];
4183
+ const seen = /* @__PURE__ */ new Set();
4184
+ const lines = content.split(/\r?\n/);
4185
+ let openQuote = null;
4186
+ for (let i = 0; i < lines.length; i++) {
4187
+ if (symbols.length >= MAX_ENV_KEYS) break;
4188
+ const line = lines[i] ?? "";
4189
+ if (openQuote !== null) {
4190
+ if (_lineClosesQuote(line, openQuote)) openQuote = null;
4191
+ continue;
4192
+ }
4193
+ if (!line || line[0] === "#" || line[0] === ";" || line[0] === " " || line[0] === " ") continue;
4194
+ const m = ENV_KEY_RE.exec(line);
4195
+ if (m === null) continue;
4196
+ const name = m[1]?.trim() ?? "";
4197
+ if (!name || name.length > MAX_HEADING_LEN) continue;
4198
+ const key = `${name}\0${i + 1}`;
4199
+ if (seen.has(key)) continue;
4200
+ seen.add(key);
4201
+ symbols.push(makeLineSymbol(filePath, name, "env_key", i + 1));
4202
+ openQuote = _detectOpenQuote(line.slice(m[0].length));
4203
+ }
4204
+ return symbols;
4205
+ }
4206
+
4207
+ // src/dotenv_redact.ts
4208
+ var DOTENV_VALUE_PLACEHOLDER = "[REDACTED:dotenv_value]";
4209
+ var ASSIGNMENT_RE = /^(\s*(?:export\s+)?[A-Za-z_][\w.-]*\s*(?:\+?=|:(?!\/\/)))/;
4210
+ var SAFE_LINE_RE = /^\s*(?:[#;].*)?$/;
4211
+ function isDotenvPath(filePath) {
4212
+ return detectLanguage(filePath) === "env_file";
4213
+ }
4214
+ function redactDotenvValues(text) {
4215
+ const lines = text.split("\n");
4216
+ const out = [];
4217
+ let openQuote = null;
4218
+ for (const raw of lines) {
4219
+ const hasCr = raw.endsWith("\r");
4220
+ const line = hasCr ? raw.slice(0, -1) : raw;
4221
+ const eol = hasCr ? "\r" : "";
4222
+ const emit = (s) => {
4223
+ out.push(`${s}${eol}`);
4224
+ };
4225
+ if (openQuote !== null) {
4226
+ if (_lineClosesQuote(line, openQuote)) openQuote = null;
4227
+ emit(DOTENV_VALUE_PLACEHOLDER);
4228
+ continue;
4229
+ }
4230
+ if (SAFE_LINE_RE.test(line)) {
4231
+ emit(line);
4232
+ continue;
4233
+ }
4234
+ const m = ASSIGNMENT_RE.exec(line);
4235
+ if (m === null || m[1] === void 0) {
4236
+ emit(DOTENV_VALUE_PLACEHOLDER);
4237
+ continue;
4238
+ }
4239
+ const prefix = m[1];
4240
+ openQuote = _detectOpenQuote(line.slice(prefix.length));
4241
+ emit(`${prefix}${DOTENV_VALUE_PLACEHOLDER}`);
4242
+ }
4243
+ return out.join("\n");
4244
+ }
4245
+ function redactIfDotenv(filePath, text) {
4246
+ return isDotenvPath(filePath) ? redactDotenvValues(text) : text;
4247
+ }
4248
+
3238
4249
  // src/db.ts
3239
- init_define_import_meta_env();
3240
4250
  import * as fs6 from "node:fs";
3241
4251
  import { createRequire as createRequire2 } from "node:module";
3242
- import * as path6 from "node:path";
4252
+ import * as path7 from "node:path";
3243
4253
  import Database from "better-sqlite3";
3244
4254
  var _require = createRequire2(import.meta.url);
3245
4255
  var _connections = /* @__PURE__ */ new Map();
@@ -3491,7 +4501,7 @@ CREATE TRIGGER IF NOT EXISTS cache_recall_au AFTER UPDATE ON cache_recall BEGIN
3491
4501
  VALUES (new.row_id, new.label, new.content);
3492
4502
  END;
3493
4503
  `;
3494
- var SCHEMA_VERSION = 10;
4504
+ var SCHEMA_VERSION = 11;
3495
4505
  function alterTableIdempotent(conn, sql) {
3496
4506
  try {
3497
4507
  conn.exec(sql);
@@ -3499,6 +4509,26 @@ function alterTableIdempotent(conn, sql) {
3499
4509
  if (!(err instanceof Error) || !/duplicate column/i.test(err.message)) throw err;
3500
4510
  }
3501
4511
  }
4512
+ function purgeDotenvEmbeddings(conn) {
4513
+ let paths;
4514
+ try {
4515
+ paths = conn.prepare("SELECT DISTINCT file_path FROM chunks").all().map((r) => r.file_path).filter(isDotenvPath);
4516
+ } catch {
4517
+ return;
4518
+ }
4519
+ if (paths.length === 0) return;
4520
+ for (const p of paths) {
4521
+ try {
4522
+ conn.prepare("DELETE FROM chunk_vectors WHERE rowid IN (SELECT id FROM chunks WHERE file_path = ?)").run(p);
4523
+ } catch {
4524
+ }
4525
+ conn.prepare("DELETE FROM chunks WHERE file_path = ?").run(p);
4526
+ try {
4527
+ conn.prepare("UPDATE files SET embed_sha = NULL WHERE path = ?").run(p);
4528
+ } catch {
4529
+ }
4530
+ }
4531
+ }
3502
4532
  var MIGRATIONS = {
3503
4533
  // 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.
3504
4534
  1: (conn) => alterTableIdempotent(conn, "ALTER TABLE files ADD COLUMN embed_sha TEXT"),
@@ -3507,7 +4537,15 @@ var MIGRATIONS = {
3507
4537
  // 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.
3508
4538
  8: (conn) => alterTableIdempotent(conn, "ALTER TABLE symbols ADD COLUMN parent TEXT NOT NULL DEFAULT ''"),
3509
4539
  // 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.
3510
- 9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER")
4540
+ 9: (conn) => alterTableIdempotent(conn, "ALTER TABLE hint_emissions ADD COLUMN bytes_emitted INTEGER"),
4541
+ // v10 -> v11: purge chunks (and their vectors) for dotenv files. Until this version, a tracked
4542
+ // `.env` was chunked and embedded verbatim on the git path, so `semantic` returned its values --
4543
+ // see dotenv_redact.ts. Redacting from now on is not enough on its own: the embed-freshness gate
4544
+ // (isEmbedFresh in parser.ts) skips a file whose bytes have not changed, so an already-indexed
4545
+ // .env would have kept serving its pre-fix chunks indefinitely. Deleting the rows here both
4546
+ // removes the stored secrets and, by clearing embed_sha, makes the next drain re-embed the file
4547
+ // through the redacting path.
4548
+ 10: purgeDotenvEmbeddings
3511
4549
  };
3512
4550
  function runMigrations(conn, fromVersion, toVersion) {
3513
4551
  for (let v = fromVersion; v < toVersion; v++) {
@@ -3553,8 +4591,8 @@ function initConnection(conn) {
3553
4591
  }
3554
4592
  }
3555
4593
  function resolveDbPath(dbPath) {
3556
- if (path6.isAbsolute(dbPath)) return dbPath;
3557
- if (dbPath.includes("/") || dbPath.includes("\\")) return path6.resolve(dbPath);
4594
+ if (path7.isAbsolute(dbPath)) return dbPath;
4595
+ if (dbPath.includes("/") || dbPath.includes("\\")) return path7.resolve(dbPath);
3558
4596
  return safeJoin(dataDir(), dbPath);
3559
4597
  }
3560
4598
  function connectionKey(dbPath) {
@@ -3565,7 +4603,7 @@ function getDb(dbPath) {
3565
4603
  const { resolved, key } = connectionKey(dbPath);
3566
4604
  const existing = _connections.get(key);
3567
4605
  if (existing !== void 0) return existing;
3568
- const dir = path6.dirname(resolved);
4606
+ const dir = path7.dirname(resolved);
3569
4607
  try {
3570
4608
  ensureDirSync(dir);
3571
4609
  } catch (e) {
@@ -3596,7 +4634,6 @@ function closeAllDbs() {
3596
4634
  registerReset(closeAllDbs);
3597
4635
 
3598
4636
  // src/render/ansi.ts
3599
- init_define_import_meta_env();
3600
4637
  function _colorStream(isatty) {
3601
4638
  if (process.env["NO_COLOR"]) return false;
3602
4639
  return isatty;
@@ -3671,11 +4708,9 @@ var C = {
3671
4708
  };
3672
4709
 
3673
4710
  // src/stats.ts
3674
- init_define_import_meta_env();
3675
- import * as path7 from "node:path";
4711
+ import * as path8 from "node:path";
3676
4712
 
3677
4713
  // src/render/stats_renderer.ts
3678
- init_define_import_meta_env();
3679
4714
  var _STATS_MESSAGES_FALLBACK = {
3680
4715
  bytesModeOnlyNote: "tracks bytes, not vision tokens",
3681
4716
  sessionHintSplitNote: "session_hint shows realized savings; session_hint_overhead shows injected hint cost",
@@ -4565,7 +5600,7 @@ var _globalSchemaApplied = /* @__PURE__ */ new Set();
4565
5600
  registerReset(() => _globalSchemaApplied.clear());
4566
5601
  function getGlobalDb(homeDir) {
4567
5602
  const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
4568
- const dbPath = path7.join(basePath, "global.db");
5603
+ const dbPath = path8.join(basePath, "global.db");
4569
5604
  const db = getDb(dbPath);
4570
5605
  if (!_globalSchemaApplied.has(dbPath)) {
4571
5606
  db.exec(GLOBAL_SCHEMA_SQL);
@@ -4803,7 +5838,6 @@ function renderStats2(opts) {
4803
5838
  }
4804
5839
 
4805
5840
  // src/secret_redact.ts
4806
- init_define_import_meta_env();
4807
5841
  var SECRET_PATTERNS = [
4808
5842
  // Anthropic keys share OpenAI's "sk-" prefix but are more specific
4809
5843
  // ("sk-ant-"), so they're matched first — the generic OpenAI pattern's
@@ -4831,8 +5865,13 @@ var SECRET_PATTERNS = [
4831
5865
  // Redacts only the token itself, not the "Authorization: Bearer " prefix -- the lookbehind
4832
5866
  // anchors on the header name and scheme so the surrounding request-log line stays readable,
4833
5867
  // matching how AWS_ACCESS_KEY_ID=... above keeps its own prefix intact.
4834
- ["auth_bearer_token", /(?<=Authorization:\s*Bearer\s)[A-Za-z0-9\-._~+/]{10,}=*/gi],
4835
- ["auth_basic_token", /(?<=Authorization:\s*Basic\s)[A-Za-z0-9+/]{6,}=*/gi],
5868
+ // The optional quotes on either side of the colon are what let this see a header carried in
5869
+ // JSON rather than in raw wire format. Without them the lookbehind demanded the colon sit
5870
+ // directly against the header name and the scheme directly against the space, so a body like
5871
+ // {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in
5872
+ // -- matched nothing and the token was cached verbatim.
5873
+ ["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Bearer[ \t])[A-Za-z0-9\-._~+/]{10,}=*/gi],
5874
+ ["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t])[A-Za-z0-9+/]{6,}=*/gi],
4836
5875
  // JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest
4837
5876
  // realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical
4838
5877
  // anchor here -- each of the three dot-separated segments requires a minimum length to avoid
@@ -4851,6 +5890,13 @@ var SECRET_PATTERNS = [
4851
5890
  // are what make the short, generic 'sig' name safe to key on: a prose or code mention of "sig"
4852
5891
  // never sits directly after a query separator followed by that much opaque token.
4853
5892
  ["presigned_signature", /(?<=[?&](?:X-Amz-Signature|X-Goog-Signature|sig)=)[A-Za-z0-9%+/=_-]{16,}/gi],
5893
+ // A password inside a connection url. `postgres://user:hunter2@db.internal` carries the
5894
+ // credential in the authority section, where there is no `key=value` separator for the
5895
+ // generic pattern below to anchor on, so a DATABASE_URL echoed by a failing migration or a
5896
+ // psql error went through untouched. The anchors are what keep this narrow: a scheme's `://`,
5897
+ // a userinfo segment, the colon, and a following `@`. `http://host:8080/path` has no `@` and
5898
+ // is left alone; so is any url without credentials.
5899
+ ["url_credentials", /(?<=:\/\/[^\s:@/]{1,64}:)[^\s:@/]{1,256}(?=@)/g],
4854
5900
  // Generic key=value assignments in .env-file and connection-string/query-string shape. The
4855
5901
  // lookbehind again redacts only the value, and the value's character class deliberately
4856
5902
  // excludes whitespace, '&', ';', '#', quote characters, and '[' ']' ':' -- that exclusion is
@@ -4866,13 +5912,19 @@ var SECRET_PATTERNS = [
4866
5912
  // this cannot backtrack catastrophically -- there is no nested or overlapping quantifier for
4867
5913
  // the engine to explore multiple ways of matching, so removing the upper bound does not
4868
5914
  // introduce a ReDoS risk.
5915
+ // Quotes are permitted around the separator, but never inside the value class. A quoted value
5916
+ // is the ordinary way secrets are written -- .env files, JSON, YAML, TOML all quote by default
5917
+ // -- and the lookbehind used to stop dead at the opening quote, so `API_KEY="..."` passed
5918
+ // through in full while the bare `API_KEY=...` was caught. The closing quote of the key name
5919
+ // blocked it from the other side too, which is what kept every JSON body unredacted. Keeping
5920
+ // quotes out of the value class is still what stops the match running past the closing quote.
4869
5921
  // The keyword may be a prefix of a longer key name rather than the whole of it, so the
4870
5922
  // trailing identifier class below is load-bearing: without it the lookbehind required the
4871
5923
  // keyword to sit immediately before the separator, and AWS_SECRET_ACCESS_KEY=,
4872
5924
  // SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches
4873
5925
  // identifier characters only, so prose that merely mentions a keyword still never reaches
4874
5926
  // a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too.
4875
- ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key)[a-z0-9_-]*\s*[:=]\s*)[^\s&;#'"[\]:]{4,}/gi]
5927
+ ["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]
4876
5928
  ];
4877
5929
  function redactSecrets(text) {
4878
5930
  let count = 0;
@@ -4887,7 +5939,6 @@ function redactSecrets(text) {
4887
5939
  }
4888
5940
 
4889
5941
  // src/filters.ts
4890
- init_define_import_meta_env();
4891
5942
  var DROP = () => null;
4892
5943
  var FILTERS = [
4893
5944
  {
@@ -4948,7 +5999,6 @@ var FILTERS = [
4948
5999
  ];
4949
6000
 
4950
6001
  // src/bash_compress.ts
4951
- init_define_import_meta_env();
4952
6002
  function stripAnsiCodes(text) {
4953
6003
  return stripAnsiEscapes(text);
4954
6004
  }
@@ -5042,6 +6092,36 @@ export {
5042
6092
  CONFIG_KEY_ENV_OVERRIDES,
5043
6093
  saveConfig,
5044
6094
  redactSecrets,
6095
+ precedingDocComment,
6096
+ buildLineIndex,
6097
+ offsetToLine,
6098
+ stripCstyleComments,
6099
+ stripXmlComments,
6100
+ scanQuotedStringEnd,
6101
+ stripJsComments,
6102
+ stripHashComments,
6103
+ maskHtmlNoise,
6104
+ findHtmlHeadingMatches,
6105
+ isInsideStringLiteral,
6106
+ stripBlockCommentSpan,
6107
+ stripNestedBlockCommentSpan,
6108
+ stripLineComment,
6109
+ stripStringLiterals,
6110
+ stripMultilineStringSpan,
6111
+ makeSpanSymbol,
6112
+ makeLineSymbol,
6113
+ makeSymbolEmitter,
6114
+ assignFlatEndLines,
6115
+ propagateEndLinesToSymbols,
6116
+ findMatchingBraceEndLine,
6117
+ extractIni,
6118
+ _lineClosesQuote,
6119
+ _detectOpenQuote,
6120
+ extractEnv,
6121
+ detectLanguage,
6122
+ unsupportedLanguageName,
6123
+ isDotenvPath,
6124
+ redactIfDotenv,
5045
6125
  getDb,
5046
6126
  colorStdout,
5047
6127
  RESET,