token-goat 2.9.28 → 2.9.30

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 (134) hide show
  1. package/README.md +36 -40
  2. package/SECURITY.md +28 -10
  3. package/THIRD_PARTY_NOTICES.md +40 -3
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/ort-wasm-simd-threaded.mjs +59 -0
  7. package/dist/token-goat-chunk-3CHUNJ2O.mjs +53 -0
  8. package/dist/token-goat-chunk-3Z5S4KGM.mjs +918 -0
  9. package/dist/token-goat-chunk-4FVIAHSI.mjs +211 -0
  10. package/dist/{token-goat-chunk-66LODAUT.mjs → token-goat-chunk-4JJS54TR.mjs} +4 -3
  11. package/dist/token-goat-chunk-4LCCNRTG.mjs +313 -0
  12. package/dist/token-goat-chunk-54K3EUV3.mjs +35 -0
  13. package/dist/token-goat-chunk-56EIMS3E.mjs +159 -0
  14. package/dist/token-goat-chunk-5BCIJXMO.mjs +609 -0
  15. package/dist/token-goat-chunk-5KDMCMF2.mjs +362 -0
  16. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  17. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  18. package/dist/{token-goat-chunk-NILVK7XM.mjs → token-goat-chunk-64FBPDTK.mjs} +12 -6
  19. package/dist/{token-goat-chunk-LEG3JNJ6.mjs → token-goat-chunk-664RTTUV.mjs} +31 -15
  20. package/dist/token-goat-chunk-67TQJ76B.mjs +57 -0
  21. package/dist/token-goat-chunk-6QMAS7AB.mjs +42 -0
  22. package/dist/token-goat-chunk-7BXSNBY5.mjs +253 -0
  23. package/dist/{token-goat-chunk-F7QZRIWM.mjs → token-goat-chunk-7F2UBPD3.mjs} +42 -35
  24. package/dist/{token-goat-chunk-CC2PYJM7.mjs → token-goat-chunk-7IN2MKDS.mjs} +718 -595
  25. package/dist/token-goat-chunk-7NADEDKJ.mjs +124 -0
  26. package/dist/{token-goat-chunk-6SGLIPQB.mjs → token-goat-chunk-A3CK6N5Z.mjs} +621 -72
  27. package/dist/{token-goat-chunk-HXNAC4ZF.mjs → token-goat-chunk-AFLYLHDH.mjs} +48 -33
  28. package/dist/token-goat-chunk-AM5V6GSX.mjs +367 -0
  29. package/dist/{token-goat-chunk-I7CB3X4K.mjs → token-goat-chunk-APGZXSPS.mjs} +44 -148
  30. package/dist/{token-goat-chunk-BJBRGPBX.mjs → token-goat-chunk-ARDNEC2U.mjs} +11 -7
  31. package/dist/token-goat-chunk-ATCPY7EQ.mjs +134 -0
  32. package/dist/token-goat-chunk-B2RZZCSS.mjs +354 -0
  33. package/dist/{token-goat-chunk-QM76S6YS.mjs → token-goat-chunk-B45VMIIH.mjs} +6 -5
  34. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  35. package/dist/{token-goat-chunk-GGLEE35R.mjs → token-goat-chunk-C63JQV5K.mjs} +49 -10
  36. package/dist/{token-goat-chunk-RJH64KQH.mjs → token-goat-chunk-COBQGL5S.mjs} +2661 -2440
  37. package/dist/token-goat-chunk-COTXZHTS.mjs +39 -0
  38. package/dist/token-goat-chunk-CYCEYAEO.mjs +265 -0
  39. package/dist/token-goat-chunk-CZ3LUXYZ.mjs +4115 -0
  40. package/dist/token-goat-chunk-DZX2YDPT.mjs +15 -0
  41. package/dist/token-goat-chunk-E3OQX2XT.mjs +824 -0
  42. package/dist/token-goat-chunk-EFHMMIGP.mjs +68 -0
  43. package/dist/token-goat-chunk-ETBHVDB6.mjs +328 -0
  44. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  45. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  46. package/dist/{token-goat-chunk-6Z5ULNE5.mjs → token-goat-chunk-FBNQNSJK.mjs} +2490 -4957
  47. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  48. package/dist/{token-goat-chunk-XI2VFAV6.mjs → token-goat-chunk-FZ3NEW5O.mjs} +33 -19
  49. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  50. package/dist/{token-goat-chunk-VE27HPIF.mjs → token-goat-chunk-GFBSN7BD.mjs} +30 -398
  51. package/dist/{token-goat-chunk-L45ZQRT7.mjs → token-goat-chunk-GOLEOXZP.mjs} +780 -786
  52. package/dist/token-goat-chunk-H2K3QP6H.mjs +24 -0
  53. package/dist/token-goat-chunk-H2PHHGM5.mjs +188 -0
  54. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  55. package/dist/token-goat-chunk-HG45AF2B.mjs +2228 -0
  56. package/dist/{token-goat-chunk-CBMY2FGI.mjs → token-goat-chunk-HOJLCGDP.mjs} +17113 -15554
  57. package/dist/{token-goat-chunk-HUDC5GS5.mjs → token-goat-chunk-HYBFA5X3.mjs} +120 -19
  58. package/dist/token-goat-chunk-IVALLT3S.mjs +48 -0
  59. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  60. package/dist/{token-goat-chunk-UBUKHVYW.mjs → token-goat-chunk-IVKIZWAB.mjs} +3 -3
  61. package/dist/{token-goat-chunk-4JMWPWCS.mjs → token-goat-chunk-JB6QN6VF.mjs} +6 -4
  62. package/dist/{token-goat-chunk-Q4S3UQGO.mjs → token-goat-chunk-JDHE26RP.mjs} +10 -3
  63. package/dist/{token-goat-chunk-7R2XYKC5.mjs → token-goat-chunk-JDU3EXSU.mjs} +14 -10
  64. package/dist/token-goat-chunk-JDWCRD6M.mjs +253 -0
  65. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-JN4XMLSD.mjs} +7 -4
  66. package/dist/token-goat-chunk-JTQQGXZH.mjs +733 -0
  67. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  68. package/dist/token-goat-chunk-KQNZDCBD.mjs +47 -0
  69. package/dist/{token-goat-chunk-4RN64ZND.mjs → token-goat-chunk-KWPNJBDH.mjs} +28 -3
  70. package/dist/token-goat-chunk-LOBGHXPB.mjs +242 -0
  71. package/dist/token-goat-chunk-MKPF4CL5.mjs +37 -0
  72. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  73. package/dist/{token-goat-chunk-YWSP6IU7.mjs → token-goat-chunk-N2NMER56.mjs} +25 -15
  74. package/dist/token-goat-chunk-NYKZLXMK.mjs +218 -0
  75. package/dist/token-goat-chunk-OJBNYTJP.mjs +3087 -0
  76. package/dist/token-goat-chunk-P4QMM4WK.mjs +295 -0
  77. package/dist/token-goat-chunk-PD5VKH46.mjs +184 -0
  78. package/dist/token-goat-chunk-PEPTHRFF.mjs +129 -0
  79. package/dist/{token-goat-chunk-VWZKZPSR.mjs → token-goat-chunk-PU7V3FD6.mjs} +8752 -11098
  80. package/dist/token-goat-chunk-PY533T7F.mjs +46 -0
  81. package/dist/token-goat-chunk-Q5VTGRH7.mjs +761 -0
  82. package/dist/{token-goat-chunk-IHKZ3QNA.mjs → token-goat-chunk-QCLDAQTS.mjs} +33 -19
  83. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-QSBRTGM2.mjs} +9 -2
  84. package/dist/{token-goat-chunk-4STDIGYC.mjs → token-goat-chunk-RC35RBUL.mjs} +7 -5
  85. package/dist/{token-goat-chunk-D5ICEPSB.mjs → token-goat-chunk-RHXKCZX3.mjs} +887 -507
  86. package/dist/{token-goat-chunk-RSS3TLXU.mjs → token-goat-chunk-RZRTDST7.mjs} +17 -7
  87. package/dist/{token-goat-chunk-MAMQPC43.mjs → token-goat-chunk-SJHWVNDQ.mjs} +15 -21
  88. package/dist/token-goat-chunk-SMVRN2HU.mjs +188 -0
  89. package/dist/{token-goat-chunk-EL7M26WP.mjs → token-goat-chunk-SQSSNQPE.mjs} +2100 -1442
  90. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-T4FK7VOV.mjs} +3 -3
  91. package/dist/token-goat-chunk-U4N3BN2W.mjs +92 -0
  92. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  93. package/dist/{token-goat-chunk-XKY4VKJ4.mjs → token-goat-chunk-UQ5UK2T7.mjs} +15 -4
  94. package/dist/token-goat-chunk-USILZ3T3.mjs +53 -0
  95. package/dist/token-goat-chunk-VES7EL7O.mjs +205 -0
  96. package/dist/{token-goat-chunk-M56BWPBN.mjs → token-goat-chunk-VL3YIFHZ.mjs} +550 -49
  97. package/dist/{token-goat-chunk-IZXKVT4A.mjs → token-goat-chunk-VPBBTSJR.mjs} +362 -128
  98. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-W3QCJS6G.mjs} +10 -2
  99. package/dist/{token-goat-chunk-FSTWAOW6.mjs → token-goat-chunk-WY3L4DVT.mjs} +11 -5
  100. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  101. package/dist/token-goat-chunk-XKI4SEMX.mjs +66 -0
  102. package/dist/token-goat-chunk-XU4P6Z24.mjs +133 -0
  103. package/dist/{token-goat-chunk-6CCQDAYY.mjs → token-goat-chunk-Y776AENC.mjs} +138 -33
  104. package/dist/token-goat-chunk-YARZFCZS.mjs +359 -0
  105. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  106. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-Z44YO3QZ.mjs} +12 -6
  107. package/dist/token-goat-chunk-Z57YODA2.mjs +35 -0
  108. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-ZCDTCVIS.mjs} +49 -30
  109. package/dist/token-goat-chunk-ZEJVMUQH.mjs +48 -0
  110. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  111. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  112. package/dist/{token-goat-chunk-SJEKA7Y2.mjs → token-goat-chunk-ZQSJMO2R.mjs} +381 -201
  113. package/dist/token-goat-hook-client.cjs +539 -0
  114. package/dist/token-goat-hook-client.mjs +26 -0
  115. package/dist/token-goat-hook.mjs +48 -28
  116. package/dist/token-goat.core.mjs +10 -45
  117. package/docs/C4_RUNTIME_ARCHITECTURE.md +3 -3
  118. package/docs/cli.md +82 -47
  119. package/docs/install.md +58 -23
  120. package/docs/security.md +7 -7
  121. package/package.json +17 -7
  122. package/scripts/verify-native-dist.mjs +386 -0
  123. package/dist/token-goat-chunk-4JJBFT7V.mjs +0 -20
  124. package/dist/token-goat-chunk-5NNYIUGV.mjs +0 -143
  125. package/dist/token-goat-chunk-6DQNNFJ6.mjs +0 -294
  126. package/dist/token-goat-chunk-7MAFDRVR.mjs +0 -47
  127. package/dist/token-goat-chunk-BCN2YQC6.mjs +0 -32
  128. package/dist/token-goat-chunk-D7GHQKQD.mjs +0 -30
  129. package/dist/token-goat-chunk-GMOUBOX4.mjs +0 -386
  130. package/dist/token-goat-chunk-IFORDBGC.mjs +0 -192
  131. package/dist/token-goat-chunk-JXK2HQXS.mjs +0 -318
  132. package/dist/token-goat-chunk-L7SDVGBT.mjs +0 -430
  133. package/dist/token-goat-chunk-MMLMALWK.mjs +0 -1381
  134. package/dist/token-goat-chunk-MVSWBNMD.mjs +0 -1985
@@ -1,735 +1,497 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
- MSYS_PATH_RE,
5
- WSL_PATH_RE,
6
- expandShortPath,
7
- isUncOrDevicePath,
8
- lowercaseDriveLetter,
9
- normalizeDarwinSystemAlias,
4
+ foldPath,
5
+ isInsideRoot,
6
+ quotePowershellPath,
7
+ quoteShellPath,
8
+ sleepSync
9
+ } from "./token-goat-chunk-AM5V6GSX.mjs";
10
+ import {
10
11
  normalizePath
11
- } from "./token-goat-chunk-NMTKNYGF.mjs";
12
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
12
13
  import {
13
- compileGuardedRegex
14
- } from "./token-goat-chunk-GMOUBOX4.mjs";
14
+ dataDir,
15
+ ensureStorageRootPrivate,
16
+ isTokenGoatStorage
17
+ } from "./token-goat-chunk-VES7EL7O.mjs";
15
18
  import {
16
19
  init_define_import_meta_env
17
20
  } from "./token-goat-chunk-A37V4PBF.mjs";
18
21
 
19
- // src/version.ts
22
+ // src/bridges/created_configs.ts
20
23
  init_define_import_meta_env();
21
- import { createRequire } from "node:module";
22
- function resolveVersion() {
23
- if (true) {
24
- return "2.9.28";
25
- }
26
- const require2 = createRequire(import.meta.url);
27
- const pkg = require2("../package.json");
28
- return pkg.version ?? "0.0.0";
29
- }
30
- var VERSION = resolveVersion();
31
- function resolvePackageName() {
32
- try {
33
- const require2 = createRequire(import.meta.url);
34
- const pkg = require2("../package.json");
35
- if (typeof pkg.name === "string" && pkg.name !== "") return pkg.name;
36
- } catch {
37
- }
38
- return "token-goat";
39
- }
40
- var PACKAGE_NAME = resolvePackageName();
41
- function resolveIssuesUrl() {
42
- try {
43
- const require2 = createRequire(import.meta.url);
44
- const pkg = require2("../package.json");
45
- if (typeof pkg.bugs?.url === "string" && pkg.bugs.url !== "") return pkg.bugs.url;
46
- } catch {
47
- }
48
- return "https://github.com/DFKHelper/token-goat/issues";
49
- }
50
- var ISSUES_URL = resolveIssuesUrl();
51
- var SUPPORT_EMAIL = "token-goat@dfkhelper.com";
52
- function supportRequestLine(what) {
53
- return `To ask for ${what} support, open an issue at ${ISSUES_URL} or email ${SUPPORT_EMAIL}.`;
54
- }
24
+ import * as fs from "fs";
25
+ import * as path4 from "path";
26
+
27
+ // src/util.ts
28
+ init_define_import_meta_env();
29
+ import { chmodSync, closeSync, constants as fsConstants, copyFileSync, existsSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync as readFileSync2, readlinkSync, renameSync, rmdirSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
30
+ import * as path3 from "node:path";
55
31
 
56
- // src/constants.ts
32
+ // src/bridges/project_scope_guard.ts
57
33
  init_define_import_meta_env();
58
- import * as fs from "node:fs";
59
- import * as os from "node:os";
60
34
  import * as path from "node:path";
61
- function safeEnvDir(value) {
62
- const stripped = value.trim();
63
- if (stripped === "") return void 0;
64
- if (!path.isAbsolute(stripped)) return void 0;
65
- if (process.platform === "win32") {
66
- const root = path.parse(stripped).root;
67
- if (root === "" || root === "\\" || root === "/") return void 0;
68
- }
69
- return stripped;
70
- }
71
- function dataDirForHome(homeDir) {
72
- const platform = process.platform;
73
- if (platform === "win32") {
74
- return path.join(homeDir, "AppData", "Local", "dfk-helper", "token-goat");
75
- }
76
- if (platform === "darwin") {
77
- return path.join(homeDir, "Library", "Application Support", "token-goat");
78
- }
79
- return path.join(homeDir, ".local", "share", "token-goat");
80
- }
81
- function homeFallbackOrGuard() {
82
- const inVitest = process.env["VITEST_WORKER_ID"] !== void 0 || process.env["VITEST"] === "true";
83
- if (inVitest && process.env["VITEST_ALLOW_REAL_DATA_DIR"] !== "1") {
84
- throw new Error(
85
- "token-goat: refusing to resolve DATA_DIR against the real home directory inside a Vitest worker (LOCALAPPDATA/XDG_DATA_HOME is unset). This would read or write the developer's real global.db/config.toml. Set LOCALAPPDATA/XDG_DATA_HOME explicitly for this process, or VITEST_ALLOW_REAL_DATA_DIR=1 if this is an intentional mocked-home test."
86
- );
87
- }
88
- return dataDirForHome(os.homedir());
89
- }
90
- function defaultDataDir() {
91
- const platform = process.platform;
92
- if (platform === "win32") {
93
- const raw = process.env["LOCALAPPDATA"] ?? "";
94
- const base2 = raw ? safeEnvDir(raw) : void 0;
95
- if (base2 !== void 0) {
96
- return path.join(base2, "dfk-helper", "token-goat");
97
- }
98
- return homeFallbackOrGuard();
99
- }
100
- if (platform === "darwin") {
101
- const raw = process.env["XDG_DATA_HOME"] ?? "";
102
- const base2 = raw ? safeEnvDir(raw) : void 0;
103
- if (base2 !== void 0) {
104
- return path.join(base2, "token-goat");
105
- }
106
- return homeFallbackOrGuard();
107
- }
108
- const xdg = process.env["XDG_DATA_HOME"] ?? "";
109
- const base = xdg ? safeEnvDir(xdg) : void 0;
110
- if (base !== void 0) {
111
- return path.join(base, "token-goat");
112
- }
113
- return homeFallbackOrGuard();
114
- }
115
- var DATA_DIR = defaultDataDir();
116
- function dataDir() {
117
- return DATA_DIR;
35
+ function assertProjectScopeTarget(target, projectRoot) {
36
+ if (projectRoot === void 0) return;
37
+ if (isInsideRoot(target, projectRoot)) return;
38
+ throw new Error(
39
+ `refusing to touch ${target}: it resolves outside the project (${projectRoot}). A repository can check a config path in as a symlink to a private file, and installing over it would read and back up that file's contents into the working tree. Remove the link, or run the install with --user.`
40
+ );
118
41
  }
119
- var dataDirHardened = false;
120
- function ensureDataDirPrivate() {
121
- if (dataDirHardened) return;
42
+ var installProjectRoot;
43
+ function withInstallScope(projectRoot, fn) {
44
+ const previous = installProjectRoot;
45
+ installProjectRoot = projectRoot === void 0 ? void 0 : path.resolve(projectRoot);
122
46
  try {
123
- fs.mkdirSync(path.dirname(DATA_DIR), { recursive: true });
124
- fs.mkdirSync(DATA_DIR, { recursive: true, mode: 448 });
125
- if (process.platform !== "win32") {
126
- const current = fs.statSync(DATA_DIR).mode & 511;
127
- if ((current & 63) !== 0) fs.chmodSync(DATA_DIR, 448);
47
+ const result = fn();
48
+ if (typeof result?.then === "function") {
49
+ throw new Error(
50
+ "withInstallScope was given a function that returned a thenable. The install scope is held in a module-level variable and restored synchronously, so an async installer would run every write after its first await with containment already switched off. Make the installer synchronous, or move the scope to AsyncLocalStorage first."
51
+ );
128
52
  }
129
- dataDirHardened = true;
130
- } catch {
53
+ return result;
54
+ } finally {
55
+ installProjectRoot = previous;
131
56
  }
132
57
  }
133
- function tokenGoatHome() {
134
- const override = safeEnvDir(process.env["TOKEN_GOAT_HOME"] ?? "");
135
- if (override !== void 0) return override;
136
- return path.join(os.homedir(), ".token-goat");
58
+ function projectScopeRoot(opts) {
59
+ if (opts === void 0) return void 0;
60
+ if (opts.project !== true && opts.local !== true) return void 0;
61
+ return path.resolve(opts.projectRoot ?? process.cwd());
137
62
  }
138
- var hardenedHomes = /* @__PURE__ */ new Set();
139
- function ensureHomeDirPrivate() {
140
- const home = tokenGoatHome();
141
- if (hardenedHomes.has(home)) return;
142
- try {
143
- fs.mkdirSync(path.dirname(home), { recursive: true });
144
- fs.mkdirSync(home, { recursive: true, mode: 448 });
145
- if (process.platform !== "win32") {
146
- const current = fs.statSync(home).mode & 511;
147
- if ((current & 63) !== 0) fs.chmodSync(home, 448);
148
- }
149
- hardenedHomes.add(home);
150
- } catch {
151
- }
63
+ function assertWriteInScope(target) {
64
+ const root = installProjectRoot;
65
+ if (root === void 0) return;
66
+ if (isTokenGoatStorage(target)) return;
67
+ assertProjectScopeTarget(target, root);
152
68
  }
153
- function isUnderRoot(child, parent) {
154
- const rel = path.relative(parent, child);
155
- return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
156
- }
157
- function isTokenGoatStorage(p) {
158
- return isUnderRoot(p, DATA_DIR) || isUnderRoot(p, tokenGoatHome());
159
- }
160
- function ensureStorageRootPrivate(dir) {
161
- if (isUnderRoot(dir, DATA_DIR)) ensureDataDirPrivate();
162
- if (isUnderRoot(dir, tokenGoatHome())) ensureHomeDirPrivate();
163
- }
164
- function globalDbPath() {
165
- return path.join(DATA_DIR, "global.db");
166
- }
167
- function configPath() {
168
- return path.join(DATA_DIR, "config.toml");
169
- }
170
- var PROJECT_CONFIG_FILENAME = ".token-goat.toml";
171
- function projectConfigPath(projectRoot) {
172
- return path.join(projectRoot, PROJECT_CONFIG_FILENAME);
173
- }
174
- var ENV_KEYS = {
175
- COMPACT_ASSIST: "TOKEN_GOAT_COMPACT_ASSIST",
176
- COMPACT_ASSIST_LEGACY: "TOKENWISE_COMPACT_ASSIST",
177
- BASH_COMPRESS: "TOKEN_GOAT_BASH_COMPRESS",
178
- SESSION_BRIEF: "TOKEN_GOAT_SESSION_BRIEF",
179
- SKILL_PRESERVATION: "TOKEN_GOAT_SKILL_PRESERVATION",
180
- ORPHAN_SWEEP: "TOKEN_GOAT_ORPHAN_SWEEP",
181
- HINT_BUDGET: "TOKEN_GOAT_HINT_BUDGET",
182
- HINT_JSON_SIDECAR: "TOKEN_GOAT_HINT_JSON_SIDECAR",
183
- BASH_DEDUP_MIN_BYTES: "TOKEN_GOAT_BASH_DEDUP_MIN_BYTES",
184
- WEB_DEDUP_MIN_BYTES: "TOKEN_GOAT_WEB_DEDUP_MIN_BYTES",
185
- GREP_DEDUP_MIN_MATCHES: "TOKEN_GOAT_GREP_DEDUP_MIN_MATCHES",
186
- GLOB_DEDUP_MIN_MATCHES: "TOKEN_GOAT_GLOB_DEDUP_MIN_MATCHES",
187
- LARGE_READ_BYTES: "TOKEN_GOAT_LARGE_READ_BYTES",
188
- REPOMAP_COMPACT_THRESHOLD: "TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD",
189
- WEB_CACHE_MAX_FILES: "TOKEN_GOAT_WEB_CACHE_MAX_FILES",
190
- WEB_CACHE_MAX_BYTES: "TOKEN_GOAT_WEB_CACHE_MAX_BYTES",
191
- WEB_COMPRESS: "TOKEN_GOAT_WEB_COMPRESS",
192
- BASH_CACHE_MIN_BYTES: "TOKEN_GOAT_BASH_CACHE_MIN_BYTES",
193
- BASH_CACHE_MAX_FILES: "TOKEN_GOAT_BASH_CACHE_MAX_FILES",
194
- BASH_CACHE_MAX_BYTES: "TOKEN_GOAT_BASH_CACHE_MAX_BYTES",
195
- BASH_CACHE_MAX_BYTES_PER_OUTPUT: "TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT",
196
- WORKER_WATCHDOG: "TOKEN_GOAT_WORKER_WATCHDOG",
197
- WORKER_MAX_POOL: "TOKEN_GOAT_WORKER_MAX_POOL",
198
- COMPRESS_PROFILE: "TOKEN_GOAT_COMPRESS_PROFILE",
199
- SKILL_COMPRESS: "TOKEN_GOAT_SKILL_COMPRESS",
200
- SERVE_DIFF_ON_REREAD: "TOKEN_GOAT_SERVE_DIFF_ON_REREAD",
201
- ELIDE_SERVED_LINES: "TOKEN_GOAT_ELIDE_SERVED_LINES",
202
- OVERFLOW_GUARD: "TOKEN_GOAT_OVERFLOW_GUARD",
203
- OVERFLOW_MAX_TOKENS: "TOKEN_GOAT_OVERFLOW_MAX_TOKENS",
204
- HARNESS_OVERRIDE: "TOKEN_GOAT_HARNESS_OVERRIDE",
205
- RECONCILE: "TOKEN_GOAT_RECONCILE",
206
- RECONCILE_BUDGET_MS: "TOKEN_GOAT_RECONCILE_BUDGET_MS",
207
- MCP_TOOLS: "TOKEN_GOAT_MCP_TOOLS"
208
- };
209
- var SYMBOL_BODY_CHAR_CAP = 128 * 1024;
210
- var SKELETON_SYMBOL_CAP = 5e3;
69
+ function projectPathIsConsultable(target, projectRoot) {
70
+ return isInsideRoot(target, projectRoot);
71
+ }
72
+
73
+ // src/util.ts
74
+ import { spawnSync } from "node:child_process";
211
75
 
212
- // src/path_containment.ts
76
+ // src/regex_guard.ts
213
77
  init_define_import_meta_env();
214
- import * as fs2 from "node:fs";
215
- import * as path2 from "node:path";
216
- function isCaseInsensitiveFs() {
217
- const o = process.env["TOKEN_GOAT_CASE_INSENSITIVE_FS"];
218
- if (o === "1") return true;
219
- if (o === "0") return false;
220
- return process.platform === "win32" || process.platform === "darwin";
221
- }
222
- function foldPath(p) {
223
- return isCaseInsensitiveFs() ? foldCase(p) : p;
224
- }
225
- function isNodeModulesPath(p) {
226
- const check = foldPath(p);
227
- return check.includes("/node_modules/") || check.includes("\\node_modules\\");
228
- }
229
- function foldCase(s) {
230
- return s.toLowerCase();
231
- }
232
- function foldCaseForContainment(s) {
233
- return s.replace(/[A-Z]/g, (c) => c.toLowerCase());
234
- }
235
- function foldPathForContainment(p) {
236
- return isCaseInsensitiveFs() ? foldCaseForContainment(p) : p;
237
- }
238
- var CYGWIN_PREFIX_RE = /^\/cygdrive\/([a-zA-Z])\/(.*)$/s;
239
- function normalizeShellDrivePrefix(posixStr) {
240
- let m = WSL_PATH_RE.exec(posixStr);
241
- if (m) {
242
- return `${m[1].toLowerCase()}:/${m[2]}`;
243
- }
244
- m = CYGWIN_PREFIX_RE.exec(posixStr);
245
- if (m) {
246
- return `${m[1].toLowerCase()}:/${m[2]}`;
247
- }
248
- m = MSYS_PATH_RE.exec(posixStr);
249
- if (m) {
250
- return `${m[1].toLowerCase()}:${m[2] ?? "/"}`;
251
- }
252
- return posixStr;
253
- }
254
- function canonicalize(inputPath, baseDir) {
255
- const pathStr = typeof inputPath === "string" ? inputPath : inputPath.pathname;
256
- const isWin32 = process.platform === "win32";
257
- const base = baseDir ?? process.cwd();
258
- const slashed = pathStr.replace(/\\/g, "/");
259
- let pre = isWin32 ? normalizeShellDrivePrefix(slashed) : slashed;
260
- if (pre !== slashed) {
261
- pre = (isWin32 ? path2.win32.resolve : path2.resolve)(base, pre);
262
- } else {
263
- pre = (isWin32 ? path2.win32.resolve : path2.resolve)(base, pathStr);
264
- }
265
- let normalized = pre.replace(/\\/g, "/");
266
- if (isWin32) {
267
- normalized = normalizeShellDrivePrefix(normalized);
268
- }
269
- normalized = expandShortPath(normalized);
270
- normalized = normalizeDarwinSystemAlias(normalized);
271
- normalized = lowercaseDriveLetter(normalized);
272
- return normalized;
273
- }
274
- var UNRESOLVABLE_PATH = "unresolvable-link-chain";
275
- var MAX_LINK_HOPS = 40;
276
- var MAX_RESOLVE_PATH_BYTES = 4096;
277
- var MAX_WALK_SEGMENTS = MAX_RESOLVE_PATH_BYTES * (MAX_LINK_HOPS + 1);
278
- function rootAndSegments(p) {
279
- const parts = p.replace(/\\/g, "/").split("/");
280
- const up = parts.indexOf("..");
281
- const head = up === -1 ? parts.join("/") : parts.slice(0, up).join("/");
282
- const canon = canonicalize(head === "" ? "." : head);
283
- const m = /^(\/\/[^/]+\/[^/]+|[a-z]:\/|\/)/i.exec(canon);
284
- const root = m === null ? "/" : m[1];
285
- const rest = canon.slice(root.length).split("/");
286
- return { root, segs: up === -1 ? rest : [...rest, ...parts.slice(up)] };
287
- }
288
- function joinSegment(base, seg) {
289
- return base.endsWith("/") ? base + seg : `${base}/${seg}`;
290
- }
291
- function parentSegment(base, root) {
292
- const cut = base.lastIndexOf("/");
293
- return cut < root.length ? root : base.slice(0, cut);
294
- }
295
- var DRIVE_RELATIVE_PATH = /^[a-z]:(?![\\/])/i;
296
- function linkTarget(link) {
297
- const raw = link.replace(/\\/g, "/").replace(/^\/\/\?\/(UNC\/)?/i, (_m, unc) => unc === void 0 ? "" : "//");
298
- if (!/^(\/\/[^/]+\/|[a-z]:\/|\/)/i.test(raw)) return { root: null, segs: raw.split("/") };
299
- const abs = rootAndSegments(raw);
300
- return { root: abs.root, segs: abs.segs };
301
- }
302
- function resolveThroughLinks(p) {
303
- if (Buffer.byteLength(p, "utf8") > MAX_RESOLVE_PATH_BYTES) return UNRESOLVABLE_PATH;
304
- const start = rootAndSegments(p);
305
- let root = start.root;
306
- let base = root;
307
- const stack = start.segs.slice().reverse();
308
- let hops = 0;
309
- let walked = 0;
310
- while (stack.length > 0) {
311
- if (++walked > MAX_WALK_SEGMENTS) return UNRESOLVABLE_PATH;
312
- const seg = stack.pop();
313
- if (seg === "" || seg === ".") continue;
314
- if (seg === "..") {
315
- base = parentSegment(base, root);
316
- continue;
317
- }
318
- const candidate = joinSegment(base, seg);
319
- if (Buffer.byteLength(candidate, "utf8") > MAX_RESOLVE_PATH_BYTES) return UNRESOLVABLE_PATH;
320
- let link = null;
321
- try {
322
- if (fs2.lstatSync(candidate).isSymbolicLink()) link = fs2.readlinkSync(candidate);
323
- } catch (err) {
324
- const code = err.code;
325
- if (code !== "ENOENT" && code !== "ENOTDIR") return UNRESOLVABLE_PATH;
326
- link = null;
327
- }
328
- if (link === null) {
329
- base = candidate;
330
- continue;
331
- }
332
- if (++hops > MAX_LINK_HOPS) return UNRESOLVABLE_PATH;
333
- if (DRIVE_RELATIVE_PATH.test(link)) return UNRESOLVABLE_PATH;
334
- const target = linkTarget(link);
335
- if (target.root !== null) {
336
- if (!isUncOrDevicePath(root) && isUncOrDevicePath(target.root)) return UNRESOLVABLE_PATH;
337
- root = target.root;
338
- base = target.root;
339
- }
340
- for (let i = target.segs.length - 1; i >= 0; i--) stack.push(target.segs[i]);
341
- }
342
- return base;
343
- }
344
- function normalizeForFs(p) {
345
- return process.platform === "darwin" ? p.normalize("NFC") : p;
346
- }
347
- function escapesOntoNetworkThroughLinks(target, cwd) {
348
- if (isUncOrDevicePath(target)) return true;
349
- let absolute;
350
- try {
351
- absolute = path2.resolve(cwd ?? process.cwd(), target);
352
- } catch {
353
- return true;
354
- }
355
- if (isUncOrDevicePath(absolute)) return true;
356
- const resolved = resolveThroughLinks(absolute);
357
- return resolved === UNRESOLVABLE_PATH || isUncOrDevicePath(resolved);
358
- }
359
- function isInsideRoot(target, root) {
360
- if (reachesForeignShare(target, root)) return false;
361
- const rt = resolveThroughLinks(target);
362
- const rr = resolveThroughLinks(root);
363
- if (rt === UNRESOLVABLE_PATH || rr === UNRESOLVABLE_PATH) return false;
364
- const nt = normalizeForFs(rt);
365
- const nr = normalizeForFs(rr);
366
- const t = foldPathForContainment(nt);
367
- const r = foldPathForContainment(nr);
368
- if (t !== r && !t.startsWith(r.endsWith("/") ? r : r + "/")) return false;
369
- if (nt.slice(0, nr.length) === nr) return true;
370
- return sameDirectory(nt.slice(0, nr.length), nr);
371
- }
372
- function isNetworkPath(p, platform = process.platform) {
373
- return networkShareRoot(p, platform) !== null;
374
- }
375
- function networkShareRoot(p, platform = process.platform) {
376
- if (platform !== "win32") return null;
377
- const device = /^[\\/]{2}([?.][\\/])?/.exec(p);
378
- if (device === null) return null;
379
- let rest = p.slice(device[0].length);
380
- if (device[1] !== void 0) {
381
- const unc = /^UNC[\\/]/i.exec(rest);
382
- if (unc === null) return null;
383
- rest = rest.slice(unc[0].length);
78
+ var GROUP_PREFIX = String.raw`\((?:\?(?::|<?[=!]|<\w+>|[a-z]*(?:-[a-z]*)?:))?`;
79
+ var NESTED_QUANTIFIER = new RegExp(GROUP_PREFIX + String.raw`[^()*+]*(?:[*+]|\{\d+,\d*\})[^()]*\)\s*(?:[*+]|\{\d+,\d*\})`);
80
+ function hasNestedQuantifier(source) {
81
+ return NESTED_QUANTIFIER.test(source);
82
+ }
83
+ var PROBE_ALPHABETS = ["a", "0", "a0"];
84
+ var PROBE_STEP = 4;
85
+ var PROBE_MAX_LENGTH = 512;
86
+ var PROBE_LENGTHS = Array.from({ length: PROBE_MAX_LENGTH / PROBE_STEP }, (_, i) => (i + 1) * PROBE_STEP);
87
+ var PROJECTED_LINE_LENGTH = 1e4;
88
+ var PROJECTION_BUDGET_MS = 1e3;
89
+ var TIMING_SIGNAL_MS = 1;
90
+ var PROBE_GROWTH_FACTOR = 12;
91
+ function climbsBetweenRungs(previous, elapsed) {
92
+ return previous !== void 0 && elapsed > TIMING_SIGNAL_MS && elapsed > previous * PROBE_GROWTH_FACTOR;
93
+ }
94
+ var PROBE_TERMINATORS = ["!", "a", "0", " ", "\uFFFF", "\n", "\u2028"];
95
+ var PROBE_BUDGET_MS = 25;
96
+ var LINEAR_BY_CONSTRUCTION_EXCLUDES = /[*+?{|]/;
97
+ var MAX_COUNTED_REPEAT = 8;
98
+ var LITERAL_RUN_ATOM = /[^\\()[\]{}|^$*+?]/;
99
+ var QUANTIFIER_AT = /^[*+?{]/;
100
+ function timeMatch(re, input) {
101
+ const probe = new RegExp(re.source, re.flags.replace("g", ""));
102
+ const started = performance.now();
103
+ const matched = probe.test(input);
104
+ const first = performance.now() - started;
105
+ if (first <= TIMING_SIGNAL_MS) return { ms: first, matched };
106
+ const again = new RegExp(re.source, re.flags.replace("g", ""));
107
+ const restarted = performance.now();
108
+ again.test(input);
109
+ return { ms: Math.min(first, performance.now() - restarted), matched };
110
+ }
111
+ function confirmed(re, input, first) {
112
+ const again = timeMatch(re, input);
113
+ return again.ms < first.ms ? { ms: again.ms, matched: first.matched } : first;
114
+ }
115
+ function remeasuredForProjection(re, timings, inputs) {
116
+ const hi = timings.length - 1;
117
+ const hiLength = PROBE_LENGTHS[hi];
118
+ const lo = hiLength === void 0 ? -1 : PROBE_LENGTHS.findIndex((l) => l * 2 >= hiLength);
119
+ const out = [...timings];
120
+ for (const i of /* @__PURE__ */ new Set([lo, hi])) {
121
+ const input = inputs[i];
122
+ const ms = out[i];
123
+ if (input !== void 0 && ms !== void 0) out[i] = Math.min(ms, timeMatch(re, input).ms);
384
124
  }
385
- const [host = "", share = ""] = rest.split(/[\\/]/);
386
- return `//${foldCase(host)}/${foldCase(share)}`;
387
- }
388
- function reachesForeignShare(target, root, platform = process.platform) {
389
- const share = networkShareRoot(target, platform);
390
- return share !== null && share !== networkShareRoot(root, platform);
125
+ return out;
391
126
  }
392
- function sameDirectory(a, b, platform = process.platform) {
393
- if (isNetworkPath(a, platform) || isNetworkPath(b, platform)) return false;
394
- let canonicalRoot;
395
- try {
396
- canonicalRoot = fs2.realpathSync.native(b);
397
- } catch {
398
- return true;
399
- }
127
+ var ESCAPE_SAMPLES = {
128
+ s: " ",
129
+ S: "a",
130
+ d: "0",
131
+ D: "a",
132
+ w: "a",
133
+ W: "-",
134
+ t: " ",
135
+ n: "\n",
136
+ r: "\r",
137
+ f: "\f",
138
+ v: "\v",
139
+ "0": "\0",
140
+ b: "",
141
+ B: ""
142
+ };
143
+ var LOOKAROUND_AT = /^\(\?<?[=!]/;
144
+ var CLASS_CANDIDATES = ["a", "0", " ", "x", "-", "!", "~", " ", "\n", "A", "\xE9", "\u03B1", "\u0434", "\u05D0", "\u0627", "\u4E2D", "\u3042", "\u{1F600}"];
145
+ function firstMatch(source, flags, candidates) {
146
+ let re;
400
147
  try {
401
- return fs2.realpathSync.native(a) === canonicalRoot;
148
+ re = new RegExp(source, flags);
402
149
  } catch {
403
- return false;
404
- }
405
- }
406
-
407
- // src/process_util.ts
408
- init_define_import_meta_env();
409
- import { existsSync, realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
410
- import * as path3 from "node:path";
411
- function sleepSync(ms) {
412
- if (ms <= 0) return;
413
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
414
- }
415
- function isWindows() {
416
- return process.platform === "win32";
417
- }
418
- function windowsCmdQuoteArg(arg) {
419
- if (arg === "") return '""';
420
- if (arg[0] === '"' && arg[arg.length - 1] === '"') {
421
- throw new Error(`windowsCmdQuoteArg: cannot faithfully encode an argument that both starts and ends with a literal double quote for cmd.exe: ${JSON.stringify(arg)}`);
422
- }
423
- let out = "";
424
- let inQuote = false;
425
- let backslashes = 0;
426
- const flushBackslashesPlain = () => {
427
- if (backslashes > 0) {
428
- out += "\\".repeat(backslashes);
429
- backslashes = 0;
150
+ return "";
151
+ }
152
+ for (const candidate of candidates) if (re.test(candidate)) return candidate;
153
+ return "";
154
+ }
155
+ function classEnd(source, start) {
156
+ let i = start + 1;
157
+ if (source[i] === "^") i++;
158
+ if (source[i] === "]") i++;
159
+ for (; i < source.length; i++) {
160
+ if (source[i] === "\\") {
161
+ i++;
162
+ continue;
430
163
  }
164
+ if (source[i] === "]") return i;
165
+ }
166
+ return -1;
167
+ }
168
+ var CLASS_SWEEP = [
169
+ ...Array.from({ length: 95 }, (_, i) => String.fromCharCode(32 + i)),
170
+ ...Array.from({ length: 1024 }, (_, i) => String.fromCharCode(160 + i * 63))
171
+ ];
172
+ var SWEEP_TAILS = CLASS_SWEEP.flatMap((c, i) => {
173
+ const other = CLASS_SWEEP[(i + 1) % CLASS_SWEEP.length];
174
+ return [c.repeat(MAX_COUNTED_REPEAT + 1), c.repeat(MAX_COUNTED_REPEAT) + other];
175
+ });
176
+ var MAX_SWEEPS = 3;
177
+ var SWEEP_BUDGET_MS = 150;
178
+ var QUANTIFIED_GROUP = /\)\s*(?:[*+]|\{\d+(?:,\d*)?\})/;
179
+ function sampleClass(cls) {
180
+ const named = sampleCharacters(cls.slice(1, -1));
181
+ return firstMatch(cls, "", [...named, ...CLASS_CANDIDATES]) || firstMatch(cls, "", CLASS_SWEEP);
182
+ }
183
+ function sampleCharacters(source) {
184
+ const out = [];
185
+ const seen = /* @__PURE__ */ new Set();
186
+ const push = (c) => {
187
+ if (c === "" || seen.has(c)) return;
188
+ seen.add(c);
189
+ out.push(c);
431
190
  };
432
- const flushBackslashesDoubled = () => {
433
- out += "\\".repeat(backslashes * 2);
434
- backslashes = 0;
435
- };
436
- const ensureQuoteOpen = () => {
437
- if (!inQuote) {
438
- flushBackslashesDoubled();
439
- out += '"';
440
- inQuote = true;
441
- } else {
442
- flushBackslashesPlain();
191
+ for (let i = 0; i < source.length; i++) {
192
+ const c = source[i];
193
+ if (c === "[") {
194
+ const end = classEnd(source, i);
195
+ if (end !== -1) {
196
+ push(sampleClass(source.slice(i, end + 1)));
197
+ i = end;
198
+ continue;
199
+ }
443
200
  }
444
- };
445
- const ensureQuoteClosed = () => {
446
- if (inQuote) {
447
- flushBackslashesDoubled();
448
- out += '"';
449
- inQuote = false;
450
- } else {
451
- flushBackslashesPlain();
201
+ if (c !== "\\") {
202
+ if (/[^\s()[\]{}|^$*+?.-]/.test(c)) push(c);
203
+ continue;
452
204
  }
453
- };
454
- for (const ch of arg) {
455
- if (ch === "\\") {
456
- backslashes++;
205
+ const next = source[i + 1] ?? "";
206
+ i++;
207
+ if (next >= "0" && next <= "7") {
208
+ let digits = /^[0-7]{1,3}/.exec(source.slice(i))[0];
209
+ if (parseInt(digits, 8) > 255) digits = digits.slice(0, 2);
210
+ push(String.fromCharCode(parseInt(digits, 8)));
211
+ if (digits.length === 1 && next !== "0") push(next);
212
+ i += digits.length - 1;
457
213
  continue;
458
214
  }
459
- if (ch === '"') {
460
- flushBackslashesDoubled();
461
- if (inQuote) {
462
- out += '"';
463
- inQuote = false;
215
+ if (next === "x" || next === "u") {
216
+ if (next === "u" && source[i + 1] === "{") {
217
+ const close = source.indexOf("}", i + 2);
218
+ const digits2 = close === -1 ? "" : source.slice(i + 2, close);
219
+ if (/^[0-9a-fA-F]{1,6}$/.test(digits2)) {
220
+ push(String.fromCodePoint(parseInt(digits2, 16)));
221
+ i = close;
222
+ }
223
+ continue;
464
224
  }
465
- out += '\\^"';
225
+ const width = next === "x" ? 2 : 4;
226
+ const digits = source.slice(i + 1, i + 1 + width);
227
+ i += width;
228
+ if (/^[0-9a-fA-F]+$/.test(digits) && digits.length === width) push(String.fromCharCode(parseInt(digits, 16)));
466
229
  continue;
467
230
  }
468
- if (ch === "%" || ch === "!") {
469
- ensureQuoteClosed();
470
- out += `^${ch}`;
231
+ if (next === "c" && /[a-zA-Z]/.test(source[i + 1] ?? "")) {
232
+ push(String.fromCharCode(source[i + 1].toUpperCase().charCodeAt(0) % 32));
233
+ i++;
471
234
  continue;
472
235
  }
473
- ensureQuoteOpen();
474
- out += ch;
475
- }
476
- ensureQuoteClosed();
477
- return out;
478
- }
479
- function quoteShellPath(value) {
480
- if (process.platform === "win32") return `"${value}"`;
481
- return `"${value.replace(/[\\$`"]/g, "\\$&")}"`;
482
- }
483
- function quotePowershellPath(value) {
484
- return `'${value.replace(/'/g, "''")}'`;
485
- }
486
- function resolveOnPath(label) {
487
- if (path3.isAbsolute(label)) return existsSync(label) ? label : null;
488
- if (label.includes("/") || label.includes("\\")) return null;
489
- const onWindows = process.platform === "win32";
490
- const exts = onWindows ? (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD").split(";").filter((e) => e.trim() !== "") : [""];
491
- let cwd;
492
- try {
493
- cwd = realpathSync2(process.cwd());
494
- } catch {
495
- cwd = path3.resolve(process.cwd());
496
- }
497
- for (const rawDir of (process.env["PATH"] ?? "").split(path3.delimiter)) {
498
- const dir = rawDir.trim().replace(/^"|"$/g, "");
499
- if (dir === "" || dir === ".") continue;
500
- let resolvedDir;
501
- try {
502
- resolvedDir = realpathSync2(path3.resolve(dir));
503
- } catch {
504
- continue;
505
- }
506
- if (foldPath(resolvedDir) === foldPath(cwd)) continue;
507
- for (const ext of exts) {
508
- const candidate = path3.join(resolvedDir, label + ext);
509
- try {
510
- if (statSync2(candidate).isFile()) return candidate;
511
- } catch {
236
+ if ((next === "p" || next === "P") && source[i + 1] === "{") {
237
+ const close = source.indexOf("}", i + 2);
238
+ if (close !== -1) {
239
+ push(firstMatch(source.slice(i - 1, close + 1), "u", CLASS_CANDIDATES));
240
+ i = close;
241
+ continue;
512
242
  }
513
243
  }
244
+ const sample = ESCAPE_SAMPLES[next];
245
+ push(sample ?? next);
514
246
  }
515
- return null;
516
- }
517
- function installEpipeGuard(streams) {
518
- const targets = (streams ?? [process.stdout, process.stderr]).filter((s) => s !== void 0);
519
- for (const stream of targets) {
520
- stream.on("error", (err) => {
521
- if (err.code === "EPIPE") {
522
- process.exitCode = 0;
523
- return;
524
- }
525
- throw err;
526
- });
527
- }
528
- return targets;
529
- }
530
-
531
- // src/encoding.ts
532
- init_define_import_meta_env();
533
- function stripBom(text) {
534
- return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
535
- }
536
- function detectSourceEncoding(buf) {
537
- if (buf.length >= 4) {
538
- if (buf[0] === 255 && buf[1] === 254 && buf[2] === 0 && buf[3] === 0) return "utf32le";
539
- if (buf[0] === 0 && buf[1] === 0 && buf[2] === 254 && buf[3] === 255) return "utf32be";
540
- }
541
- if (buf.length >= 2) {
542
- if (buf[0] === 255 && buf[1] === 254) return "utf16le";
543
- if (buf[0] === 254 && buf[1] === 255) return "utf16be";
544
- }
545
- if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) return "utf8-bom";
546
- return "utf8";
547
- }
548
- function decodeSource(buf) {
549
- switch (detectSourceEncoding(buf)) {
550
- case "utf32le":
551
- return decodeUtf32(buf.subarray(4), true);
552
- case "utf32be":
553
- return decodeUtf32(buf.subarray(4), false);
554
- case "utf16le":
555
- return buf.subarray(2).toString("utf16le");
556
- case "utf16be":
557
- return swap16(buf.subarray(2)).toString("utf16le");
558
- case "utf8-bom":
559
- return buf.subarray(3).toString("utf8");
560
- default:
561
- return buf.toString("utf8");
562
- }
563
- }
564
- function encodeSource(text, encoding) {
565
- switch (encoding) {
566
- case "utf32le":
567
- return Buffer.concat([Buffer.from([255, 254, 0, 0]), encodeUtf32(text, true)]);
568
- case "utf32be":
569
- return Buffer.concat([Buffer.from([0, 0, 254, 255]), encodeUtf32(text, false)]);
570
- case "utf16le":
571
- return Buffer.concat([Buffer.from([255, 254]), Buffer.from(text, "utf16le")]);
572
- case "utf16be":
573
- return Buffer.concat([Buffer.from([254, 255]), swap16(Buffer.from(text, "utf16le"))]);
574
- case "utf8-bom":
575
- return Buffer.concat([Buffer.from([239, 187, 191]), Buffer.from(text, "utf8")]);
576
- default:
577
- return Buffer.from(text, "utf8");
578
- }
579
- }
580
- function swap16(buf) {
581
- const out = Buffer.from(buf);
582
- return out.subarray(0, out.length - out.length % 2).swap16();
583
- }
584
- function decodeUtf32(buf, littleEndian) {
585
- const points = [];
586
- for (let i = 0; i + 4 <= buf.length; i += 4) {
587
- const cp = littleEndian ? buf.readUInt32LE(i) : buf.readUInt32BE(i);
588
- points.push(cp > 1114111 || cp >= 55296 && cp <= 57343 ? 65533 : cp);
589
- }
590
- return String.fromCodePoint(...points);
591
- }
592
- function encodeUtf32(text, littleEndian) {
593
- const points = [...text];
594
- const out = Buffer.alloc(points.length * 4);
595
- points.forEach((ch, i) => {
596
- const cp = ch.codePointAt(0) ?? 65533;
597
- if (littleEndian) out.writeUInt32LE(cp, i * 4);
598
- else out.writeUInt32BE(cp, i * 4);
599
- });
600
247
  return out;
601
248
  }
602
-
603
- // src/util.ts
604
- init_define_import_meta_env();
605
- import { spawn } from "node:child_process";
606
- import { chmodSync as chmodSync2, closeSync, constants as fsConstants, copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync as readFileSync3, renameSync, rmdirSync, statSync as statSync3, unlinkSync, writeFileSync, writeSync } from "node:fs";
607
- import * as path7 from "node:path";
608
-
609
- // src/bridges/created_configs.ts
610
- init_define_import_meta_env();
611
- import * as fs3 from "fs";
612
- import * as path4 from "path";
613
- function ledgerPath() {
614
- return path4.join(dataDir(), "created-configs.json");
615
- }
616
- function keyOf(filePath) {
617
- return normalizePath(path4.resolve(filePath));
618
- }
619
- function foldKey(key) {
620
- return foldPath(key);
621
- }
622
- function readLedger() {
623
- try {
624
- const parsed = JSON.parse(fs3.readFileSync(ledgerPath(), "utf8"));
625
- return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : [];
626
- } catch {
627
- return [];
628
- }
629
- }
630
- function writeLedger(entries) {
631
- try {
632
- ensureDirSync(path4.dirname(ledgerPath()));
633
- atomicWriteText(ledgerPath(), `${JSON.stringify(entries)}
634
- `);
635
- } catch {
636
- }
637
- }
638
- function recordCreatedConfig(filePath) {
639
- const key = keyOf(filePath);
640
- const entries = readLedger();
641
- if (entries.some((entry) => foldKey(entry) === foldKey(key))) return;
642
- writeLedger([...entries, key]);
643
- }
644
- function hasCreatedConfig(filePath) {
645
- const key = foldKey(keyOf(filePath));
646
- return readLedger().some((entry) => foldKey(entry) === key);
647
- }
648
- function takeCreatedConfig(filePath) {
649
- const key = foldKey(keyOf(filePath));
650
- const entries = readLedger();
651
- if (!entries.some((entry) => foldKey(entry) === key)) return false;
652
- writeLedger(entries.filter((entry) => foldKey(entry) !== key));
653
- return true;
654
- }
655
- function recordCreatedBackup(backupPath) {
656
- recordCreatedConfig(backupPath);
657
- }
658
- function forgetCreatedBackup(backupPath) {
659
- takeCreatedConfig(backupPath);
660
- }
661
- function createdBackupsFor(configPath2) {
662
- const prefix = foldKey(`${keyOf(configPath2)}.bak.`);
663
- return readLedger().filter((entry) => foldKey(entry).startsWith(prefix)).sort();
664
- }
665
- function removeCreatedBackups(configPath2) {
666
- const prefix = foldKey(`${keyOf(configPath2)}.bak.`);
667
- const entries = readLedger();
668
- const ours = entries.filter((entry) => foldKey(entry).startsWith(prefix));
669
- if (ours.length === 0) return 0;
670
- const failed = /* @__PURE__ */ new Set();
671
- let removed = 0;
672
- for (const target of ours) {
249
+ var MAX_PATTERN_ALPHABETS = 12;
250
+ function probeAlphabets(source) {
251
+ const samples = sampleCharacters(source);
252
+ const counts = /* @__PURE__ */ new Map();
253
+ for (const ch of source) counts.set(ch, (counts.get(ch) ?? 0) + 1);
254
+ const counted = samples.map((c, i) => ({ c, i, n: counts.get(c) ?? 0 }));
255
+ counted.sort((a, b) => b.n - a.n || a.i - b.i);
256
+ const kept = counted.slice(0, MAX_PATTERN_ALPHABETS).map((s) => s.c);
257
+ const extra = kept.length > 1 ? [kept.join("")] : [];
258
+ return [...PROBE_ALPHABETS, ...kept, ...extra];
259
+ }
260
+ function growsExponentially(re) {
261
+ const relaxed = detune(re.source);
262
+ if (relaxed === null || !relaxed.hadLookaround) {
263
+ const cause = climbsPastBudget(re);
264
+ if (cause !== null) return cause;
265
+ }
266
+ if (relaxed === null) return null;
267
+ for (const body of relaxed.negativeBodies) {
268
+ let inner;
673
269
  try {
674
- if (fs3.existsSync(target) && removeFileInScope(target)) {
675
- removed++;
676
- }
270
+ inner = new RegExp(body, re.flags);
677
271
  } catch {
678
- failed.add(target);
272
+ continue;
679
273
  }
274
+ const innerCause = growsExponentially(inner);
275
+ if (innerCause !== null) return innerCause;
680
276
  }
681
- writeLedger(entries.filter((entry) => !ours.includes(entry) || failed.has(entry)));
682
- return removed;
683
- }
684
-
685
- // src/bridges/project_scope_guard.ts
686
- init_define_import_meta_env();
687
- import * as path5 from "node:path";
688
- function assertProjectScopeTarget(target, projectRoot) {
689
- if (projectRoot === void 0) return;
690
- if (isInsideRoot(target, projectRoot)) return;
691
- throw new Error(
692
- `refusing to touch ${target}: it resolves outside the project (${projectRoot}). A repository can check a config path in as a symlink to a private file, and installing over it would read and back up that file's contents into the working tree. Remove the link, or run the install with --user.`
693
- );
694
- }
695
- var installProjectRoot;
696
- function withInstallScope(projectRoot, fn) {
697
- const previous = installProjectRoot;
698
- installProjectRoot = projectRoot === void 0 ? void 0 : path5.resolve(projectRoot);
277
+ let widened;
699
278
  try {
700
- const result = fn();
701
- if (typeof result?.then === "function") {
702
- throw new Error(
703
- "withInstallScope was given a function that returned a thenable. The install scope is held in a module-level variable and restored synchronously, so an async installer would run every write after its first await with containment already switched off. Make the installer synchronous, or move the scope to AsyncLocalStorage first."
704
- );
279
+ widened = new RegExp(relaxed.source, re.flags);
280
+ } catch {
281
+ return null;
282
+ }
283
+ return growsExponentially(widened);
284
+ }
285
+ function climbsPastBudget(re) {
286
+ const probe = new RegExp(re.source, re.flags.replace("g", ""));
287
+ let sweptMs = 0;
288
+ let falsified = false;
289
+ for (const alphabet of probeAlphabets(re.source)) {
290
+ let sweeps = 0;
291
+ const body = (n) => alphabet.repeat(Math.ceil(n / alphabet.length)).slice(0, n);
292
+ const tail = PROBE_TERMINATORS.find((t) => !probe.test(body(PROBE_STEP) + t)) ?? PROBE_TERMINATORS[0];
293
+ const candidates = [tail, ...PROBE_TERMINATORS.filter((t) => t !== tail)];
294
+ let swept;
295
+ const timings = [];
296
+ const inputs = [];
297
+ let previous;
298
+ for (const length of PROBE_LENGTHS) {
299
+ let failing;
300
+ let last;
301
+ let failingInput = "";
302
+ let lastInput = "";
303
+ const attempt = (candidate) => {
304
+ const input = body(length) + candidate;
305
+ let m = timeMatch(re, input);
306
+ if (m.ms > PROBE_BUDGET_MS) m = confirmed(re, input, m);
307
+ last = m;
308
+ lastInput = input;
309
+ if (m.ms > PROBE_BUDGET_MS) return "over-budget";
310
+ if (!m.matched) {
311
+ failing = m;
312
+ failingInput = input;
313
+ }
314
+ return m;
315
+ };
316
+ for (const candidate of swept === void 0 ? candidates : [swept, ...candidates]) {
317
+ if (attempt(candidate) === "over-budget") return "over-budget";
318
+ if (failing !== void 0) break;
319
+ }
320
+ if (failing === void 0 && sweeps < MAX_SWEEPS && sweptMs < SWEEP_BUDGET_MS) {
321
+ sweeps++;
322
+ const sweepStarted = Date.now();
323
+ for (const candidate of SWEEP_TAILS) {
324
+ if (attempt(candidate) === "over-budget") return "over-budget";
325
+ if (failing !== void 0) {
326
+ swept = candidate;
327
+ break;
328
+ }
329
+ }
330
+ sweptMs += Date.now() - sweepStarted;
331
+ }
332
+ if (failing !== void 0) falsified = true;
333
+ let elapsed = (failing ?? last).ms;
334
+ const rungInput = failing !== void 0 ? failingInput : lastInput;
335
+ if (climbsBetweenRungs(previous, elapsed)) {
336
+ elapsed = confirmed(re, rungInput, { ms: elapsed, matched: false }).ms;
337
+ if (climbsBetweenRungs(previous, elapsed)) return "ratio";
338
+ }
339
+ previous = elapsed;
340
+ timings.push(elapsed);
341
+ inputs.push(rungInput);
705
342
  }
706
- return result;
707
- } finally {
708
- installProjectRoot = previous;
343
+ if (projectsPastBudget(timings) && projectsPastBudget(remeasuredForProjection(re, timings, inputs))) return "projection";
709
344
  }
345
+ if (!falsified && QUANTIFIED_GROUP.test(re.source)) return "unfalsifiable";
346
+ return null;
710
347
  }
711
- function projectScopeRoot(opts) {
712
- if (opts === void 0) return void 0;
713
- if (opts.project !== true && opts.local !== true) return void 0;
714
- return path5.resolve(opts.projectRoot ?? process.cwd());
715
- }
716
- function assertWriteInScope(target) {
717
- const root = installProjectRoot;
718
- if (root === void 0) return;
719
- if (isTokenGoatStorage(target)) return;
720
- assertProjectScopeTarget(target, root);
348
+ function groupEnd(source, start) {
349
+ let depth = 0;
350
+ let inClass = false;
351
+ for (let i = start; i < source.length; i++) {
352
+ const c = source[i];
353
+ if (c === "\\") {
354
+ i++;
355
+ continue;
356
+ }
357
+ if (inClass) {
358
+ if (c === "]") inClass = false;
359
+ continue;
360
+ }
361
+ if (c === "[") inClass = true;
362
+ else if (c === "(") depth++;
363
+ else if (c === ")" && --depth === 0) return i;
364
+ }
365
+ return -1;
721
366
  }
722
- function projectPathIsConsultable(target, projectRoot) {
723
- return isInsideRoot(target, projectRoot);
367
+ function detune(source) {
368
+ let out = "";
369
+ let changed = false;
370
+ let hadLookaround = false;
371
+ const negativeBodies = [];
372
+ let inClass = false;
373
+ for (let i = 0; i < source.length; i++) {
374
+ const c = source[i];
375
+ if (c === "\\") {
376
+ out += c + (source[i + 1] ?? "");
377
+ i++;
378
+ continue;
379
+ }
380
+ if (inClass) {
381
+ out += c;
382
+ if (c === "]") inClass = false;
383
+ continue;
384
+ }
385
+ if (c === "[") {
386
+ out += c;
387
+ inClass = true;
388
+ continue;
389
+ }
390
+ if (c === "{") {
391
+ const counted = /^\{(\d+)(,(\d*))?\}/.exec(source.slice(i));
392
+ if (counted !== null) {
393
+ const min = Math.min(parseInt(counted[1], 10), MAX_COUNTED_REPEAT);
394
+ const upper = counted[3];
395
+ const max = upper === void 0 || upper === "" ? "" : String(Math.min(parseInt(upper, 10), MAX_COUNTED_REPEAT));
396
+ const rebuilt = counted[2] === void 0 ? `{${min}}` : `{${min},${max}}`;
397
+ if (rebuilt !== counted[0]) changed = true;
398
+ out += rebuilt;
399
+ i += counted[0].length - 1;
400
+ continue;
401
+ }
402
+ }
403
+ if (c === "(" && LOOKAROUND_AT.test(source.slice(i, i + 4))) {
404
+ const end = groupEnd(source, i);
405
+ if (end === -1) return null;
406
+ const behind = source[i + 2] === "<";
407
+ const negative = source[i + (behind ? 3 : 2)] === "!";
408
+ const body = source.slice(i + (behind ? 4 : 3), end);
409
+ if (negative) negativeBodies.push(body);
410
+ else out += `(?:${body})`;
411
+ i = end;
412
+ changed = true;
413
+ hadLookaround = true;
414
+ continue;
415
+ }
416
+ if (LITERAL_RUN_ATOM.test(c)) {
417
+ let run = 1;
418
+ while (source[i + run] === c) run++;
419
+ const quantified = QUANTIFIER_AT.test(source.slice(i + run, i + run + 1));
420
+ const collapsible = quantified ? run - 1 : run;
421
+ if (collapsible > MAX_COUNTED_REPEAT) {
422
+ out += c.repeat(MAX_COUNTED_REPEAT) + (quantified ? c : "");
423
+ i += run - 1;
424
+ changed = true;
425
+ continue;
426
+ }
427
+ }
428
+ out += c;
429
+ }
430
+ return changed ? { source: out, hadLookaround, negativeBodies } : null;
431
+ }
432
+ function projectsPastBudget(timings) {
433
+ const hi = timings.length - 1;
434
+ const hiLength = PROBE_LENGTHS[hi];
435
+ if (hiLength === void 0) return false;
436
+ const lo = PROBE_LENGTHS.findIndex((l) => l * 2 >= hiLength);
437
+ const loLength = PROBE_LENGTHS[lo];
438
+ const top = timings[hi];
439
+ const prior = timings[lo];
440
+ if (top === void 0 || prior === void 0 || loLength === void 0 || loLength >= hiLength) return false;
441
+ if (top <= TIMING_SIGNAL_MS || prior <= 0) return false;
442
+ const exponent = Math.log2(top / prior) / Math.log2(hiLength / loLength);
443
+ return top * (PROJECTED_LINE_LENGTH / hiLength) ** exponent > PROJECTION_BUDGET_MS;
444
+ }
445
+ var MAX_PATTERN_LENGTH = 4096;
446
+ function compileGuardedRegex(pattern, flags = "") {
447
+ if (pattern.length > MAX_PATTERN_LENGTH) {
448
+ return { ok: false, reason: `is longer than ${MAX_PATTERN_LENGTH} characters, which is past what can be checked for a stall` };
449
+ }
450
+ let re;
451
+ try {
452
+ re = new RegExp(pattern, flags);
453
+ } catch (e) {
454
+ return { ok: false, reason: e instanceof Error ? e.message : "is not a valid regular expression" };
455
+ }
456
+ if (!LINEAR_BY_CONSTRUCTION_EXCLUDES.test(pattern)) return { ok: true, re };
457
+ const cause = growsExponentially(re);
458
+ if (cause !== null) {
459
+ return {
460
+ ok: false,
461
+ reason: hasNestedQuantifier(pattern) ? "repeats a group that already repeats, which can take exponential time to match" : "takes time that climbs steeply with the length of the line, which can stall on ordinary text",
462
+ cause
463
+ };
464
+ }
465
+ return { ok: true, re };
466
+ }
467
+ var GUARDED_CACHE_LIMIT = 64;
468
+ var guardedCache = /* @__PURE__ */ new Map();
469
+ function compileGuardedRegexCached(pattern, flags = "") {
470
+ const key = `${flags}/${pattern}`;
471
+ const hit = guardedCache.get(key);
472
+ if (hit !== void 0) return hit;
473
+ const result = compileGuardedRegex(pattern, flags);
474
+ if (guardedCache.size >= GUARDED_CACHE_LIMIT) {
475
+ const oldest = guardedCache.keys().next();
476
+ if (!oldest.done) guardedCache.delete(oldest.value);
477
+ }
478
+ guardedCache.set(key, result);
479
+ return result;
724
480
  }
725
481
 
726
- // src/util.ts
727
- import { spawnSync } from "node:child_process";
728
-
729
482
  // src/util_config.ts
730
483
  init_define_import_meta_env();
731
- import { readFileSync as readFileSync2 } from "node:fs";
732
- import * as path6 from "node:path";
484
+ import { readFileSync } from "node:fs";
485
+ import * as path2 from "node:path";
486
+ function commandHookFields(h) {
487
+ if (typeof h?.command !== "string") return void 0;
488
+ const args = Array.isArray(h.args) && h.args.every((a) => typeof a === "string") ? h.args : void 0;
489
+ return { command: h.command, args };
490
+ }
491
+ function isOwnHookEntry(h, isOurs) {
492
+ const fields = commandHookFields(h);
493
+ return fields !== void 0 && isOurs(fields.command, fields.args);
494
+ }
733
495
  function stripOwnHooksFromMap(hooks, isOurs) {
734
496
  let removed = false;
735
497
  for (const eventKey of Object.keys(hooks)) {
@@ -738,7 +500,7 @@ function stripOwnHooksFromMap(hooks, isOurs) {
738
500
  const kept = [];
739
501
  for (const group of groups) {
740
502
  const keptHooks = (group.hooks ?? []).filter((h) => {
741
- const isOur = isOurs(h.command, h.args);
503
+ const isOur = isOwnHookEntry(h, isOurs);
742
504
  if (isOur) removed = true;
743
505
  return !isOur;
744
506
  });
@@ -764,7 +526,7 @@ function stripStaleGroupHooks(groups, isOurs, matcherFilter) {
764
526
  next.push(group);
765
527
  continue;
766
528
  }
767
- const keptHooks = (group.hooks ?? []).filter((h) => !isOurs(h.command, h.args));
529
+ const keptHooks = (group.hooks ?? []).filter((h) => !isOwnHookEntry(h, isOurs));
768
530
  if (keptHooks.length > 0) {
769
531
  next.push({ ...group, hooks: keptHooks });
770
532
  } else if ((group.hooks ?? []).length === 0) {
@@ -773,10 +535,13 @@ function stripStaleGroupHooks(groups, isOurs, matcherFilter) {
773
535
  }
774
536
  return next;
775
537
  }
538
+ function detectEol(text) {
539
+ return text.includes("\r\n") ? "\r\n" : "\n";
540
+ }
776
541
  function stripDelimitedBlock(p, beginMarker, endMarker, keepBackups = false) {
777
542
  let existing;
778
543
  try {
779
- existing = readFileSync2(p, "utf8");
544
+ existing = readFileSync(p, "utf8");
780
545
  } catch {
781
546
  return false;
782
547
  }
@@ -786,29 +551,29 @@ function stripDelimitedBlock(p, beginMarker, endMarker, keepBackups = false) {
786
551
  const before = existing.slice(0, beginIdx).replace(/\s+$/, "");
787
552
  const after = existing.slice(endIdx + endMarker.length).replace(/^\s+/, "");
788
553
  let next;
554
+ const eol = detectEol(existing);
789
555
  if (before.length > 0 && after.length > 0) {
790
- next = `${before}
791
-
792
- ${after}`;
556
+ next = `${before}${eol}${eol}${after}`;
793
557
  } else if (before.length > 0) {
794
- next = `${before}
795
- `;
558
+ next = `${before}${eol}`;
796
559
  } else {
797
560
  next = after;
798
561
  }
799
562
  backupFile(p);
800
- atomicWriteText(p, next);
563
+ atomicWriteText(p, keepBom(existing, next));
801
564
  if (!keepBackups) removeCreatedBackups(p);
802
565
  return true;
803
566
  }
804
- function upsertDelimitedBlock(p, beginMarker, endMarker, block) {
567
+ function upsertDelimitedBlock(p, beginMarker, endMarker, blockText) {
805
568
  assertWriteInScope(p);
806
569
  let existing;
807
570
  try {
808
- existing = readFileSync2(p, "utf8");
571
+ existing = readFileSync(p, "utf8");
809
572
  } catch {
810
573
  existing = "";
811
574
  }
575
+ const eol = detectEol(existing);
576
+ const block = eol === "\n" ? blockText : blockText.replace(/\r?\n/g, eol);
812
577
  const beginIdx = existing.indexOf(beginMarker);
813
578
  const endIdx = existing.indexOf(endMarker);
814
579
  if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
@@ -816,42 +581,136 @@ function upsertDelimitedBlock(p, beginMarker, endMarker, block) {
816
581
  const after = existing.slice(endIdx + endMarker.length);
817
582
  const current = existing.slice(beginIdx, endIdx + endMarker.length);
818
583
  if (current === block) return false;
819
- ensureDirSync(path6.dirname(p));
584
+ ensureDirSync(path2.dirname(p));
820
585
  backupFile(p);
821
586
  atomicWriteText(p, `${before}${block}${after}`);
822
587
  return true;
823
588
  }
824
589
  const trimmed = existing.replace(/\s+$/, "");
825
- const next = trimmed.length > 0 ? `${trimmed}
826
-
827
- ${block}
828
- ` : `${block}
829
- `;
830
- ensureDirSync(path6.dirname(p));
590
+ const next = trimmed.length > 0 ? `${trimmed}${eol}${eol}${block}${eol}` : `${block}${eol}`;
591
+ ensureDirSync(path2.dirname(p));
831
592
  backupFile(p);
832
- atomicWriteText(p, next);
593
+ atomicWriteText(p, keepBom(existing, next));
833
594
  return true;
834
595
  }
835
596
  function writeJsonSettings(p, settings) {
836
- ensureDirSync(path6.dirname(p));
597
+ ensureDirSync(path2.dirname(p));
598
+ let existing = "";
599
+ try {
600
+ existing = readFileSync(p, "utf8");
601
+ } catch {
602
+ }
837
603
  backupFile(p);
838
- atomicWriteText(p, `${JSON.stringify(settings, null, 2)}
839
- `);
604
+ const eol = detectEol(existing);
605
+ const body = JSON.stringify(settings, null, detectJsonIndent(existing)).replace(/\n/g, eol);
606
+ atomicWriteText(p, keepBom(existing, existing.length > 0 && !existing.endsWith("\n") ? body : `${body}${eol}`));
607
+ }
608
+ var BOM = String.fromCharCode(65279);
609
+ function keepBom(existing, next) {
610
+ return existing?.startsWith(BOM) && !next.startsWith(BOM) ? `${BOM}${next}` : next;
611
+ }
612
+ function writeConfigText(p, next) {
613
+ let existing;
614
+ try {
615
+ existing = readFileSync(p, "utf8");
616
+ } catch {
617
+ existing = void 0;
618
+ }
619
+ atomicWriteText(p, keepBom(existing, next));
620
+ }
621
+ function detectJsonIndent(text) {
622
+ const lead = /^([ \t]+)\S/m.exec(text)?.[1];
623
+ if (lead === void 0) return " ";
624
+ return lead.startsWith(" ") ? " " : lead.slice(0, 10);
840
625
  }
841
626
  function writeIfDifferent(p, content, backup = false) {
842
627
  let existing;
843
628
  try {
844
- existing = readFileSync2(p, "utf8");
629
+ existing = readFileSync(p, "utf8");
845
630
  } catch {
846
631
  existing = void 0;
847
632
  }
848
633
  if (existing === content) return false;
849
634
  if (backup) backupFile(p);
850
- ensureDirSync(path6.dirname(p));
635
+ ensureDirSync(path2.dirname(p));
851
636
  atomicWriteText(p, content);
852
637
  return true;
853
638
  }
854
639
 
640
+ // src/encoding.ts
641
+ init_define_import_meta_env();
642
+ function stripBom(text) {
643
+ return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
644
+ }
645
+ function detectSourceEncoding(buf) {
646
+ if (buf.length >= 4) {
647
+ if (buf[0] === 255 && buf[1] === 254 && buf[2] === 0 && buf[3] === 0) return "utf32le";
648
+ if (buf[0] === 0 && buf[1] === 0 && buf[2] === 254 && buf[3] === 255) return "utf32be";
649
+ }
650
+ if (buf.length >= 2) {
651
+ if (buf[0] === 255 && buf[1] === 254) return "utf16le";
652
+ if (buf[0] === 254 && buf[1] === 255) return "utf16be";
653
+ }
654
+ if (buf.length >= 3 && buf[0] === 239 && buf[1] === 187 && buf[2] === 191) return "utf8-bom";
655
+ return "utf8";
656
+ }
657
+ function decodeSource(buf) {
658
+ switch (detectSourceEncoding(buf)) {
659
+ case "utf32le":
660
+ return decodeUtf32(buf.subarray(4), true);
661
+ case "utf32be":
662
+ return decodeUtf32(buf.subarray(4), false);
663
+ case "utf16le":
664
+ return buf.subarray(2).toString("utf16le");
665
+ case "utf16be":
666
+ return swap16(buf.subarray(2)).toString("utf16le");
667
+ case "utf8-bom":
668
+ return buf.subarray(3).toString("utf8");
669
+ default:
670
+ return buf.toString("utf8");
671
+ }
672
+ }
673
+ function encodeSource(text, encoding) {
674
+ switch (encoding) {
675
+ case "utf32le":
676
+ return Buffer.concat([Buffer.from([255, 254, 0, 0]), encodeUtf32(text, true)]);
677
+ case "utf32be":
678
+ return Buffer.concat([Buffer.from([0, 0, 254, 255]), encodeUtf32(text, false)]);
679
+ case "utf16le":
680
+ return Buffer.concat([Buffer.from([255, 254]), Buffer.from(text, "utf16le")]);
681
+ case "utf16be":
682
+ return Buffer.concat([Buffer.from([254, 255]), swap16(Buffer.from(text, "utf16le"))]);
683
+ case "utf8-bom":
684
+ return Buffer.concat([Buffer.from([239, 187, 191]), Buffer.from(text, "utf8")]);
685
+ default:
686
+ return Buffer.from(text, "utf8");
687
+ }
688
+ }
689
+ function swap16(buf) {
690
+ const out = Buffer.from(buf);
691
+ return out.subarray(0, out.length - out.length % 2).swap16();
692
+ }
693
+ function decodeUtf32(buf, littleEndian) {
694
+ const points = [];
695
+ for (let i = 0; i + 4 <= buf.length; i += 4) {
696
+ const cp = littleEndian ? buf.readUInt32LE(i) : buf.readUInt32BE(i);
697
+ points.push(cp > 1114111 || cp >= 55296 && cp <= 57343 ? 65533 : cp);
698
+ }
699
+ let out = "";
700
+ for (let i = 0; i < points.length; i += 8192) out += String.fromCodePoint(...points.slice(i, i + 8192));
701
+ return out;
702
+ }
703
+ function encodeUtf32(text, littleEndian) {
704
+ const points = [...text];
705
+ const out = Buffer.alloc(points.length * 4);
706
+ points.forEach((ch, i) => {
707
+ const cp = ch.codePointAt(0) ?? 65533;
708
+ if (littleEndian) out.writeUInt32LE(cp, i * 4);
709
+ else out.writeUInt32BE(cp, i * 4);
710
+ });
711
+ return out;
712
+ }
713
+
855
714
  // src/util.ts
856
715
  function runGit(args, opts = {}) {
857
716
  const subArgs = args[0] === "diff" ? [args[0], "--no-ext-diff", "--no-textconv", ...args.slice(1)] : args;
@@ -881,7 +740,7 @@ function runGit(args, opts = {}) {
881
740
  }
882
741
  function statSize(absPath) {
883
742
  try {
884
- const st = statSync3(absPath);
743
+ const st = statSync(absPath);
885
744
  return st.isFile() ? st.size : null;
886
745
  } catch {
887
746
  return null;
@@ -894,14 +753,16 @@ function isRetryable(err) {
894
753
  return typeof code === "string" && RETRYABLE_ERRNO.has(code);
895
754
  }
896
755
  function isEExist(err) {
897
- if (typeof err !== "object" || err === null) return false;
898
- return err.code === "EEXIST";
756
+ return errnoCode(err) === "EEXIST";
757
+ }
758
+ function errnoCode(err) {
759
+ return typeof err === "object" && err !== null ? err.code : void 0;
899
760
  }
900
761
  function ensureDirSync(dir) {
901
762
  assertWriteInScope(dir);
902
763
  ensureStorageRootPrivate(dir);
903
764
  try {
904
- mkdirSync2(dir, { recursive: true });
765
+ mkdirSync(dir, { recursive: true });
905
766
  } catch (err) {
906
767
  if (!isEExist(err)) {
907
768
  throw err;
@@ -922,10 +783,28 @@ function withRetryOnLock(fn) {
922
783
  }
923
784
  throw lastErr;
924
785
  }
925
- function atomicWriteCore(dest, content) {
926
- assertWriteInScope(dest);
786
+ function resolveSymlinkChain(p) {
787
+ const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
788
+ let current = p;
789
+ for (let hops = 0; hops < 40; hops++) {
790
+ let st;
791
+ try {
792
+ st = lstatSync(current);
793
+ } catch (err) {
794
+ if (err.code === "ENOENT") return current;
795
+ throw err;
796
+ }
797
+ if (!st.isSymbolicLink() || uid !== void 0 && st.uid !== uid && st.uid !== 0) return current;
798
+ current = path3.resolve(path3.dirname(current), readlinkSync(current));
799
+ }
800
+ throw Object.assign(new Error(`ELOOP: too many levels of symbolic links, resolving ${p}`), { code: "ELOOP" });
801
+ }
802
+ function atomicWriteCore(requested, content) {
803
+ assertWriteInScope(requested);
804
+ const dest = resolveSymlinkChain(requested);
805
+ if (dest !== requested) assertWriteInScope(dest);
927
806
  const tmp = `${dest}.${process.pid}.${process.hrtime.bigint().toString()}.tmp`;
928
- ensureDirSync(path7.dirname(dest));
807
+ ensureDirSync(path3.dirname(dest));
929
808
  try {
930
809
  const fd = openSync(tmp, "w", 384);
931
810
  try {
@@ -938,8 +817,8 @@ function atomicWriteCore(dest, content) {
938
817
  closeSync(fd);
939
818
  }
940
819
  try {
941
- const destMode = statSync3(dest).mode;
942
- chmodSync2(tmp, destMode);
820
+ const destStat = lstatSync(dest);
821
+ if (!destStat.isSymbolicLink()) chmodSync(tmp, destStat.mode);
943
822
  } catch (e) {
944
823
  if (e.code !== "ENOENT") throw e;
945
824
  }
@@ -961,19 +840,19 @@ function atomicWriteBytes(filePath, content) {
961
840
  function installSingleFilePlugin(filePath, sidecarPath, template) {
962
841
  let existing;
963
842
  try {
964
- existing = readFileSync3(filePath, "utf8");
843
+ existing = readFileSync2(filePath, "utf8");
965
844
  } catch {
966
845
  existing = void 0;
967
846
  }
968
847
  const entryPath = process.argv[1];
969
848
  if (entryPath) {
970
- ensureDirSync(path7.dirname(filePath));
849
+ ensureDirSync(path3.dirname(filePath));
971
850
  atomicWriteText(sidecarPath, JSON.stringify({ entryPath }));
972
851
  }
973
852
  if (existing === template) {
974
853
  return { filePath, alreadyInstalled: true };
975
854
  }
976
- ensureDirSync(path7.dirname(filePath));
855
+ ensureDirSync(path3.dirname(filePath));
977
856
  atomicWriteText(filePath, template);
978
857
  return { filePath, alreadyInstalled: false };
979
858
  }
@@ -1007,7 +886,7 @@ var MAX_BACKUPS_PER_FILE = 5;
1007
886
  var MAX_BACKUP_NAME_ATTEMPTS = 16;
1008
887
  function backupFile(p) {
1009
888
  assertWriteInScope(p);
1010
- if (!existsSync3(p)) return;
889
+ if (!existsSync(p)) return;
1011
890
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1012
891
  let backupPath;
1013
892
  for (let attempt = 0; ; attempt++) {
@@ -1047,34 +926,43 @@ function containsLineRun(haystack, needle) {
1047
926
  var LOCK_WAIT_MS = 2e3;
1048
927
  var LOCK_STALE_MS = 5e3;
1049
928
  var LOCK_WAIT_MS_HARDENED = 15e3;
1050
- var HEARTBEAT_SCRIPT = `
1051
- const fs = require('fs')
1052
- const [, lockPath, token, ms] = process.argv
1053
- const ppid = process.ppid
1054
- function tick() {
929
+ var LOCK_LIVE_HOLDER_MAX_MS = 6e4;
930
+ var LOCK_EPERM_RUN_MS = 1e3;
931
+ function lockHolderAlive(token) {
932
+ const pid = Number(/^(\d+):/.exec(token)?.[1]);
933
+ if (!Number.isSafeInteger(pid) || pid <= 0 || pid === process.pid) return false;
1055
934
  try {
1056
- process.kill(ppid, 0)
1057
- } catch {
1058
- // Parent is gone (crashed, killed, ...): stop ticking so a genuinely dead holder's lock still goes stale and gets reclaimed. Windows ties this child's lifetime to its parent's Job Object automatically, but POSIX does not -- without this check, a plain spawn() child outlives a crashed parent as an orphan and would refresh the lock file forever, permanently wedging it. This is the actual enforcement mechanism on POSIX (this project's CI runs on ubuntu-latest); on Windows it is a harmless backstop.
1059
- process.exit(0)
935
+ process.kill(pid, 0);
936
+ return true;
937
+ } catch (err) {
938
+ return err.code === "EPERM";
1060
939
  }
940
+ }
941
+ function lockAbandoned(lockPath, staleMs) {
942
+ const age = Date.now() - statSync(lockPath).mtimeMs;
943
+ return age > staleMs && (age > Math.max(staleMs, LOCK_LIVE_HOLDER_MAX_MS) || !lockHolderAlive(readFileSync2(lockPath, "utf8")));
944
+ }
945
+ function stealAbandoned(lockPath, staleMs) {
946
+ const guardPath = `${lockPath}.steal`;
1061
947
  try {
1062
- // Only ever refresh the token already on disk; never (re)create the file. This preserves the ownership check in withFileLock's finally block unchanged -- the heartbeat never changes what makes a lock file "belong" to a holder, only how fresh its mtime looks.
1063
- if (fs.readFileSync(lockPath, 'utf8') === token) fs.writeFileSync(lockPath, token)
1064
- } catch {}
1065
- }
1066
- setInterval(tick, Number(ms))
1067
- `;
1068
- function startHeartbeat(lockPath, token, staleMs) {
1069
- const intervalMs = Math.max(20, Math.floor(staleMs / 3));
948
+ writeFileSync(guardPath, "", { flag: "wx" });
949
+ } catch (err) {
950
+ try {
951
+ if (isEExist(err) && Date.now() - statSync(guardPath).mtimeMs > staleMs) unlinkSync(guardPath);
952
+ } catch {
953
+ }
954
+ return false;
955
+ }
1070
956
  try {
1071
- return spawn(process.execPath, ["-e", HEARTBEAT_SCRIPT, lockPath, token, String(intervalMs)], {
1072
- stdio: "ignore",
1073
- windowsHide: true
1074
- });
957
+ if (lockAbandoned(lockPath, staleMs)) unlinkSync(lockPath);
1075
958
  } catch {
1076
- return void 0;
959
+ } finally {
960
+ try {
961
+ unlinkSync(guardPath);
962
+ } catch {
963
+ }
1077
964
  }
965
+ return true;
1078
966
  }
1079
967
  function withFileLock(lockPath, fn, opts = {}) {
1080
968
  const waitMs = opts.waitMs ?? LOCK_WAIT_MS;
@@ -1082,40 +970,37 @@ function withFileLock(lockPath, fn, opts = {}) {
1082
970
  const token = `${process.pid}:${process.hrtime.bigint().toString()}`;
1083
971
  const deadline = Date.now() + waitMs;
1084
972
  let attempt = 0;
973
+ let epermSince;
1085
974
  for (; ; ) {
1086
975
  try {
1087
976
  writeFileSync(lockPath, token, { flag: "wx" });
1088
977
  break;
1089
978
  } catch (err) {
979
+ if (process.platform === "win32" && errnoCode(err) === "EPERM") {
980
+ epermSince ??= Date.now();
981
+ if (Date.now() >= deadline || Date.now() - epermSince >= LOCK_EPERM_RUN_MS) return void 0;
982
+ sleepSync(Math.min(20 * ++attempt, 200));
983
+ continue;
984
+ }
1090
985
  if (!isEExist(err)) return void 0;
986
+ epermSince = void 0;
1091
987
  }
1092
988
  let stale;
1093
989
  try {
1094
- const st = statSync3(lockPath);
1095
- stale = Date.now() - st.mtimeMs > staleMs;
1096
- } catch {
1097
- stale = true;
1098
- }
1099
- if (stale) {
1100
- try {
1101
- unlinkSync(lockPath);
1102
- } catch {
1103
- }
1104
- continue;
990
+ stale = lockAbandoned(lockPath, staleMs);
991
+ } catch (err) {
992
+ if (errnoCode(err) === "ENOENT") continue;
993
+ stale = false;
1105
994
  }
995
+ if (stale && stealAbandoned(lockPath, staleMs)) continue;
1106
996
  if (Date.now() >= deadline) return void 0;
1107
997
  sleepSync(Math.min(20 * ++attempt, 200));
1108
998
  }
1109
- const heartbeat = startHeartbeat(lockPath, token, staleMs);
1110
999
  try {
1111
1000
  return fn();
1112
1001
  } finally {
1113
1002
  try {
1114
- heartbeat?.kill();
1115
- } catch {
1116
- }
1117
- try {
1118
- if (readFileSync3(lockPath, "utf8") === token) unlinkSync(lockPath);
1003
+ if (readFileSync2(lockPath, "utf8") === token) unlinkSync(lockPath);
1119
1004
  } catch {
1120
1005
  }
1121
1006
  }
@@ -1173,9 +1058,9 @@ function redactUrlQuery(raw) {
1173
1058
  }
1174
1059
  function withExtension(filePath, format) {
1175
1060
  const ext = format === "jpeg" ? ".jpg" : `.${format}`;
1176
- const dir = path7.dirname(filePath);
1177
- const base = path7.basename(filePath, path7.extname(filePath));
1178
- return path7.join(dir, `${base}${ext}`);
1061
+ const dir = path3.dirname(filePath);
1062
+ const base = path3.basename(filePath, path3.extname(filePath));
1063
+ return path3.join(dir, `${base}${ext}`);
1179
1064
  }
1180
1065
  function ensureNewline(text) {
1181
1066
  return text.endsWith("\n") ? text : text + "\n";
@@ -1234,10 +1119,10 @@ function isTestFile(p) {
1234
1119
  }
1235
1120
  function isUnderBlockedRoot(filePath, blockedRoots) {
1236
1121
  if (blockedRoots.length === 0) return false;
1237
- const target = foldPath(normalizePath(path7.resolve(filePath)));
1122
+ const target = foldPath(normalizePath(path3.resolve(filePath)));
1238
1123
  for (const root of blockedRoots) {
1239
1124
  if (!root) continue;
1240
- const normRoot = foldPath(normalizePath(path7.resolve(root)));
1125
+ const normRoot = foldPath(normalizePath(path3.resolve(root)));
1241
1126
  if (target === normRoot) return true;
1242
1127
  const boundary = normRoot.endsWith("/") ? normRoot : `${normRoot}/`;
1243
1128
  if (target.startsWith(boundary)) return true;
@@ -1270,50 +1155,159 @@ function hookPowershellCommand(scriptPath, event) {
1270
1155
  return `${quotePowershellPath(process.execPath)} ${quotePowershellPath(scriptPath)} ${event}${entryArg}`;
1271
1156
  }
1272
1157
 
1158
+ // src/bridges/created_configs.ts
1159
+ function ledgerPath() {
1160
+ return path4.join(dataDir(), "created-configs.json");
1161
+ }
1162
+ function keyOf(filePath) {
1163
+ return normalizePath(path4.resolve(filePath));
1164
+ }
1165
+ function foldKey(key) {
1166
+ return foldPath(key);
1167
+ }
1168
+ function readLedger() {
1169
+ try {
1170
+ const parsed = JSON.parse(fs.readFileSync(ledgerPath(), "utf8"));
1171
+ return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : [];
1172
+ } catch {
1173
+ return [];
1174
+ }
1175
+ }
1176
+ function writeLedger(entries) {
1177
+ try {
1178
+ ensureDirSync(path4.dirname(ledgerPath()));
1179
+ atomicWriteText(ledgerPath(), `${JSON.stringify(entries)}
1180
+ `);
1181
+ } catch {
1182
+ }
1183
+ }
1184
+ function recordCreatedConfig(filePath) {
1185
+ const key = keyOf(filePath);
1186
+ const entries = readLedger();
1187
+ if (entries.some((entry) => foldKey(entry) === foldKey(key))) return;
1188
+ writeLedger([...entries, key]);
1189
+ }
1190
+ function hasCreatedConfig(filePath) {
1191
+ const key = foldKey(keyOf(filePath));
1192
+ return readLedger().some((entry) => foldKey(entry) === key);
1193
+ }
1194
+ function takeCreatedConfig(filePath) {
1195
+ const key = foldKey(keyOf(filePath));
1196
+ const entries = readLedger();
1197
+ if (!entries.some((entry) => foldKey(entry) === key)) return false;
1198
+ writeLedger(entries.filter((entry) => foldKey(entry) !== key));
1199
+ return true;
1200
+ }
1201
+ function rootKeyMarker(filePath, rootKey) {
1202
+ return `${filePath}#root-key=${rootKey}`;
1203
+ }
1204
+ function recordCreatedRootKey(filePath, rootKey) {
1205
+ recordCreatedConfig(rootKeyMarker(filePath, rootKey));
1206
+ }
1207
+ function takeCreatedRootKey(filePath, rootKey) {
1208
+ return takeCreatedConfig(rootKeyMarker(filePath, rootKey));
1209
+ }
1210
+ function recordCreatedBackup(backupPath) {
1211
+ recordCreatedConfig(backupPath);
1212
+ }
1213
+ function forgetCreatedBackup(backupPath) {
1214
+ takeCreatedConfig(backupPath);
1215
+ }
1216
+ function createdBackupsFor(configPath) {
1217
+ const prefix = foldKey(`${keyOf(configPath)}.bak.`);
1218
+ return readLedger().filter((entry) => foldKey(entry).startsWith(prefix)).sort();
1219
+ }
1220
+ function removeCreatedBackups(configPath) {
1221
+ const prefix = foldKey(`${keyOf(configPath)}.bak.`);
1222
+ const entries = readLedger();
1223
+ const ours = entries.filter((entry) => foldKey(entry).startsWith(prefix));
1224
+ if (ours.length === 0) return 0;
1225
+ const failed = /* @__PURE__ */ new Set();
1226
+ let removed = 0;
1227
+ for (const target of ours) {
1228
+ try {
1229
+ if (fs.existsSync(target) && removeFileInScope(target)) {
1230
+ removed++;
1231
+ }
1232
+ } catch {
1233
+ failed.add(target);
1234
+ }
1235
+ }
1236
+ writeLedger(entries.filter((entry) => !ours.includes(entry) || failed.has(entry)));
1237
+ return removed;
1238
+ }
1239
+ function ensureDirRecordingCreation(dir) {
1240
+ const existed = fs.existsSync(dir);
1241
+ ensureDirSync(dir);
1242
+ if (!existed) recordCreatedConfig(dir);
1243
+ }
1244
+ function holdsNothing(text) {
1245
+ const trimmed = text.trim();
1246
+ return trimmed === "" || /^\{\s*\}$/.test(trimmed);
1247
+ }
1248
+ function removeCreatedIfEmpty(target) {
1249
+ if (!hasCreatedConfig(target)) return;
1250
+ let removed = false;
1251
+ try {
1252
+ removed = fs.lstatSync(target).isDirectory() ? removeEmptyDirInScope(target) : holdsNothing(fs.readFileSync(target, "utf8")) && removeFileInScope(target);
1253
+ } catch {
1254
+ }
1255
+ if (removed) takeCreatedConfig(target);
1256
+ }
1257
+ function recordCreatedBy(targets, work) {
1258
+ const absent = /* @__PURE__ */ new Set();
1259
+ for (const target of targets) {
1260
+ for (let p = path4.resolve(target); !fs.existsSync(p) && !absent.has(p); p = path4.dirname(p)) absent.add(p);
1261
+ }
1262
+ try {
1263
+ return work();
1264
+ } finally {
1265
+ for (const p of absent) if (fs.existsSync(p)) recordCreatedConfig(p);
1266
+ }
1267
+ }
1268
+ function removeCreatedTree(targets) {
1269
+ const paths = /* @__PURE__ */ new Set();
1270
+ for (const target of targets) {
1271
+ for (let p = path4.resolve(target); !paths.has(p); p = path4.dirname(p)) {
1272
+ paths.add(p);
1273
+ if (path4.dirname(p) === p) break;
1274
+ }
1275
+ }
1276
+ for (const p of [...paths].sort((a, b) => b.length - a.length)) {
1277
+ if (fs.existsSync(p)) removeCreatedIfEmpty(p);
1278
+ else if (hasCreatedConfig(p)) takeCreatedConfig(p);
1279
+ }
1280
+ }
1281
+
1273
1282
  export {
1274
- VERSION,
1275
- PACKAGE_NAME,
1276
- supportRequestLine,
1277
- dataDirForHome,
1278
- dataDir,
1279
- ensureDataDirPrivate,
1280
- tokenGoatHome,
1281
- globalDbPath,
1282
- configPath,
1283
- projectConfigPath,
1284
- ENV_KEYS,
1285
- SYMBOL_BODY_CHAR_CAP,
1286
- SKELETON_SYMBOL_CAP,
1287
1283
  recordCreatedConfig,
1288
1284
  hasCreatedConfig,
1289
1285
  takeCreatedConfig,
1286
+ recordCreatedRootKey,
1287
+ takeCreatedRootKey,
1290
1288
  removeCreatedBackups,
1291
- isCaseInsensitiveFs,
1292
- foldPath,
1293
- isNodeModulesPath,
1294
- foldCase,
1295
- foldCaseForContainment,
1296
- foldPathForContainment,
1297
- canonicalize,
1298
- escapesOntoNetworkThroughLinks,
1299
- isInsideRoot,
1289
+ ensureDirRecordingCreation,
1290
+ removeCreatedIfEmpty,
1291
+ recordCreatedBy,
1292
+ removeCreatedTree,
1300
1293
  assertProjectScopeTarget,
1301
1294
  withInstallScope,
1302
1295
  projectScopeRoot,
1303
1296
  assertWriteInScope,
1304
1297
  projectPathIsConsultable,
1298
+ hasNestedQuantifier,
1299
+ growsExponentially,
1300
+ compileGuardedRegex,
1301
+ compileGuardedRegexCached,
1302
+ commandHookFields,
1303
+ isOwnHookEntry,
1305
1304
  stripOwnHooksFromMap,
1306
1305
  stripStaleGroupHooks,
1307
1306
  stripDelimitedBlock,
1308
1307
  upsertDelimitedBlock,
1309
1308
  writeJsonSettings,
1309
+ writeConfigText,
1310
1310
  writeIfDifferent,
1311
- sleepSync,
1312
- isWindows,
1313
- windowsCmdQuoteArg,
1314
- quoteShellPath,
1315
- resolveOnPath,
1316
- installEpipeGuard,
1317
1311
  stripBom,
1318
1312
  detectSourceEncoding,
1319
1313
  decodeSource,