privateer-agent 0.15.4 → 0.15.6

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 (229) hide show
  1. package/README.md +11 -0
  2. package/bin/boot-bundle.d.mts +2 -0
  3. package/bin/boot-bundle.mjs +44 -0
  4. package/bin/fresh-supervisor.d.mts +5 -1
  5. package/bin/fresh-supervisor.mjs +47 -10
  6. package/bin/privateer-launch.mjs +27 -3
  7. package/bin/privateer-subagent.mjs +5 -2
  8. package/bin/privateer-verify.mjs +12 -0
  9. package/bin/session-recovery.d.mts +53 -0
  10. package/bin/session-recovery.mjs +240 -0
  11. package/bin/session-seal-preload.mjs +17 -0
  12. package/bin/session-seal.d.mts +25 -0
  13. package/bin/session-seal.mjs +242 -0
  14. package/dist-boot/boot.mjs +3 -0
  15. package/dist-boot/c-27JKSMWL.mjs +1460 -0
  16. package/dist-boot/c-2BMRFV24.mjs +269 -0
  17. package/dist-boot/c-2CTF6JA3.mjs +166 -0
  18. package/dist-boot/c-2G3BBHRJ.mjs +84 -0
  19. package/dist-boot/c-2IDLKXX6.mjs +250 -0
  20. package/dist-boot/c-2NJD5VYM.mjs +8 -0
  21. package/dist-boot/c-2S5EEQPW.mjs +1602 -0
  22. package/dist-boot/c-2WRDCUVI.mjs +25 -0
  23. package/dist-boot/c-2YN3M256.mjs +14 -0
  24. package/dist-boot/c-37GM3GMU.mjs +187 -0
  25. package/dist-boot/c-3STKRSVO.mjs +2480 -0
  26. package/dist-boot/c-3TPV6TQQ.mjs +2320 -0
  27. package/dist-boot/c-3UVHLQDJ.mjs +225 -0
  28. package/dist-boot/c-42PUUZYC.mjs +697 -0
  29. package/dist-boot/c-4D5UMWVW.mjs +683 -0
  30. package/dist-boot/c-4ETZRMTA.mjs +46 -0
  31. package/dist-boot/c-4QT25BD5.mjs +1482 -0
  32. package/dist-boot/c-4WVR32AP.mjs +2579 -0
  33. package/dist-boot/c-5EMM567G.mjs +152 -0
  34. package/dist-boot/c-5FA4CV63.mjs +145 -0
  35. package/dist-boot/c-5GV3X3RB.mjs +14 -0
  36. package/dist-boot/c-5JCEPRIY.mjs +52 -0
  37. package/dist-boot/c-5NDKIIWT.mjs +16 -0
  38. package/dist-boot/c-5QL3AR26.mjs +4665 -0
  39. package/dist-boot/c-5XY6MFKN.mjs +5142 -0
  40. package/dist-boot/c-65UZIZC7.mjs +2897 -0
  41. package/dist-boot/c-6FUXKHOK.mjs +1969 -0
  42. package/dist-boot/c-6JHWQE4V.mjs +18242 -0
  43. package/dist-boot/c-6LOBR4I6.mjs +5280 -0
  44. package/dist-boot/c-6QHOZXKQ.mjs +14394 -0
  45. package/dist-boot/c-6ZO2SADQ.mjs +178 -0
  46. package/dist-boot/c-6ZORVVZP.mjs +1449 -0
  47. package/dist-boot/c-76QH4UCP.mjs +2441 -0
  48. package/dist-boot/c-77GO5L5Y.mjs +20982 -0
  49. package/dist-boot/c-7M23XFTN.mjs +5052 -0
  50. package/dist-boot/c-7TC367E2.mjs +32 -0
  51. package/dist-boot/c-7UOG7POX.mjs +1524 -0
  52. package/dist-boot/c-7VHP3FLN.mjs +376 -0
  53. package/dist-boot/c-A73JHZP2.mjs +13207 -0
  54. package/dist-boot/c-ABXULAFL.mjs +71 -0
  55. package/dist-boot/c-ANDD2AQO.mjs +74 -0
  56. package/dist-boot/c-AOY77AZL.mjs +1430 -0
  57. package/dist-boot/c-AXEPZ22I.mjs +108 -0
  58. package/dist-boot/c-B2Y7VNHU.mjs +427 -0
  59. package/dist-boot/c-B7VJUH73.mjs +77 -0
  60. package/dist-boot/c-BFW6CDVL.mjs +24 -0
  61. package/dist-boot/c-BHNIF2AR.mjs +188 -0
  62. package/dist-boot/c-BKF2O6BL.mjs +23 -0
  63. package/dist-boot/c-BOZXFTZN.mjs +8 -0
  64. package/dist-boot/c-BRNYJWZL.mjs +28 -0
  65. package/dist-boot/c-C3N4Z2HO.mjs +93 -0
  66. package/dist-boot/c-C4IV7ZFG.mjs +717 -0
  67. package/dist-boot/c-C5NK6UYV.mjs +793 -0
  68. package/dist-boot/c-C67644MB.mjs +1659 -0
  69. package/dist-boot/c-C6S2YB53.mjs +620 -0
  70. package/dist-boot/c-CDBEJSBF.mjs +37 -0
  71. package/dist-boot/c-CG47HBKU.mjs +435 -0
  72. package/dist-boot/c-CKCTWCT5.mjs +51 -0
  73. package/dist-boot/c-CN77DCGF.mjs +60 -0
  74. package/dist-boot/c-CRBXNKFO.mjs +1795 -0
  75. package/dist-boot/c-CRIHASQ6.mjs +973 -0
  76. package/dist-boot/c-CU4NGAUO.mjs +3786 -0
  77. package/dist-boot/c-CWRFLGQU.mjs +1883 -0
  78. package/dist-boot/c-CYQB2USO.mjs +32 -0
  79. package/dist-boot/c-DEE67DJO.mjs +379 -0
  80. package/dist-boot/c-DIFDBYOP.mjs +1258 -0
  81. package/dist-boot/c-DOSGVXDZ.mjs +34879 -0
  82. package/dist-boot/c-DR7XQI32.mjs +381 -0
  83. package/dist-boot/c-DTGPSB46.mjs +14666 -0
  84. package/dist-boot/c-DTHDNA4P.mjs +320 -0
  85. package/dist-boot/c-E4Z3Y5B5.mjs +3864 -0
  86. package/dist-boot/c-E66Z2TI7.mjs +203 -0
  87. package/dist-boot/c-EBU6RLRV.mjs +1527 -0
  88. package/dist-boot/c-EBZZNGSF.mjs +432 -0
  89. package/dist-boot/c-EC3LJ2KF.mjs +1032 -0
  90. package/dist-boot/c-EQBKXWNX.mjs +15829 -0
  91. package/dist-boot/c-EUEPIW4S.mjs +574 -0
  92. package/dist-boot/c-EX4YVWAT.mjs +378 -0
  93. package/dist-boot/c-EYZGSAJU.mjs +98 -0
  94. package/dist-boot/c-F75VRKY4.mjs +172 -0
  95. package/dist-boot/c-FH4NXKHV.mjs +177 -0
  96. package/dist-boot/c-FHNUCTEM.mjs +140 -0
  97. package/dist-boot/c-FJ5T42DS.mjs +5349 -0
  98. package/dist-boot/c-FPCNRL7G.mjs +1728 -0
  99. package/dist-boot/c-G4DLN7Q4.mjs +8 -0
  100. package/dist-boot/c-G56GYQFZ.mjs +2507 -0
  101. package/dist-boot/c-GLIOERDQ.mjs +1200 -0
  102. package/dist-boot/c-GMJ5HUBM.mjs +14 -0
  103. package/dist-boot/c-H3HSGMAQ.mjs +461 -0
  104. package/dist-boot/c-HIKTO6P7.mjs +275 -0
  105. package/dist-boot/c-I2MCJ34O.mjs +464 -0
  106. package/dist-boot/c-I3C6LBW4.mjs +765 -0
  107. package/dist-boot/c-I54OKQHW.mjs +387 -0
  108. package/dist-boot/c-IFSP3R4D.mjs +80 -0
  109. package/dist-boot/c-IZK77VB7.mjs +171 -0
  110. package/dist-boot/c-J3Y25UGE.mjs +54 -0
  111. package/dist-boot/c-J5IESS7W.mjs +27750 -0
  112. package/dist-boot/c-JJWZBY7L.mjs +254 -0
  113. package/dist-boot/c-JKTFXTGF.mjs +463 -0
  114. package/dist-boot/c-JN57AXQ4.mjs +77 -0
  115. package/dist-boot/c-KFIO6LUW.mjs +1096 -0
  116. package/dist-boot/c-KIEMEFWW.mjs +478 -0
  117. package/dist-boot/c-KIVXWBYD.mjs +28 -0
  118. package/dist-boot/c-KP6CRIP4.mjs +580 -0
  119. package/dist-boot/c-L26VOJX4.mjs +11558 -0
  120. package/dist-boot/c-L5GHWG5G.mjs +5988 -0
  121. package/dist-boot/c-M7NSQAKK.mjs +353 -0
  122. package/dist-boot/c-MCEWOPBW.mjs +56 -0
  123. package/dist-boot/c-MGPIEG7I.mjs +20 -0
  124. package/dist-boot/c-NREXJV3M.mjs +393 -0
  125. package/dist-boot/c-O5PP6CTX.mjs +162 -0
  126. package/dist-boot/c-OBQDHSXM.mjs +1774 -0
  127. package/dist-boot/c-OLQHHDD4.mjs +21 -0
  128. package/dist-boot/c-OXW4JQQH.mjs +319 -0
  129. package/dist-boot/c-P3D7ZUWN.mjs +1288 -0
  130. package/dist-boot/c-P4PQZVV5.mjs +948 -0
  131. package/dist-boot/c-P63T3XL2.mjs +26373 -0
  132. package/dist-boot/c-P6N5DQGZ.mjs +194 -0
  133. package/dist-boot/c-P7MLKQFC.mjs +58 -0
  134. package/dist-boot/c-PB3PZJL5.mjs +1276 -0
  135. package/dist-boot/c-PTN4S6G2.mjs +1259 -0
  136. package/dist-boot/c-PYCE5J7U.mjs +1083 -0
  137. package/dist-boot/c-Q4HYCRLB.mjs +19410 -0
  138. package/dist-boot/c-QUXMETGG.mjs +68 -0
  139. package/dist-boot/c-RDMJZCOX.mjs +356 -0
  140. package/dist-boot/c-ROGJK76M.mjs +17 -0
  141. package/dist-boot/c-RQJJ26T4.mjs +708 -0
  142. package/dist-boot/c-RSKCUPJF.mjs +7559 -0
  143. package/dist-boot/c-RVJU4O6P.mjs +37 -0
  144. package/dist-boot/c-S2RVHR3M.mjs +165 -0
  145. package/dist-boot/c-SKMK3PEE.mjs +91120 -0
  146. package/dist-boot/c-TI7SM4EG.mjs +20 -0
  147. package/dist-boot/c-TILJ6GXD.mjs +1235 -0
  148. package/dist-boot/c-TT6BCUJD.mjs +114 -0
  149. package/dist-boot/c-U4ITOXAN.mjs +2107 -0
  150. package/dist-boot/c-UGERXVO2.mjs +7120 -0
  151. package/dist-boot/c-UPBH5AXY.mjs +1363 -0
  152. package/dist-boot/c-US2PUNZL.mjs +597 -0
  153. package/dist-boot/c-UU4WZPPE.mjs +20 -0
  154. package/dist-boot/c-UWVIYPQS.mjs +39 -0
  155. package/dist-boot/c-V4RHQBPQ.mjs +17683 -0
  156. package/dist-boot/c-V5MRVK47.mjs +351 -0
  157. package/dist-boot/c-V6CL266R.mjs +1755 -0
  158. package/dist-boot/c-VJTMFKYE.mjs +14975 -0
  159. package/dist-boot/c-VJTRUKIB.mjs +773 -0
  160. package/dist-boot/c-W4IFSHPW.mjs +43 -0
  161. package/dist-boot/c-WETGB2CF.mjs +113 -0
  162. package/dist-boot/c-WO3QSZUU.mjs +1337 -0
  163. package/dist-boot/c-WQLH73TY.mjs +242 -0
  164. package/dist-boot/c-XL735JW5.mjs +500 -0
  165. package/dist-boot/c-Y7HADL5B.mjs +1107 -0
  166. package/dist-boot/c-YGQHSVSK.mjs +41 -0
  167. package/dist-boot/c-YMP2AMEB.mjs +10350 -0
  168. package/dist-boot/c-YRDO2WEF.mjs +12012 -0
  169. package/dist-boot/c-YUSTRATJ.mjs +8 -0
  170. package/dist-boot/c-Z2262R22.mjs +2697 -0
  171. package/dist-boot/c-Z4ALQMJC.mjs +709 -0
  172. package/dist-boot/c-Z5ZUQVUY.mjs +62 -0
  173. package/dist-boot/c-ZDZUKXF7.mjs +874 -0
  174. package/dist-boot/c-ZJYLGIC3.mjs +32 -0
  175. package/dist-boot/c-ZNA5CDMI.mjs +77 -0
  176. package/dist-boot/c-ZSO6DI3M.mjs +204 -0
  177. package/dist-boot/c-ZWUVHKMK.mjs +100 -0
  178. package/dist-boot/c-ZY4MESEW.mjs +832 -0
  179. package/dist-boot/c-ZZ5REI4L.mjs +329 -0
  180. package/dist-boot/cli.mjs +51 -0
  181. package/dist-boot/ext-anthropic-attribution.mjs +207 -0
  182. package/dist-boot/ext-pi-background-tasks.mjs +7234 -0
  183. package/dist-boot/ext-pi-subagents.mjs +37 -0
  184. package/dist-boot/ext-privateer-account.mjs +4426 -0
  185. package/dist-boot/ext-privateer-brand.mjs +5274 -0
  186. package/dist-boot/ext-privateer-codemode.mjs +37 -0
  187. package/dist-boot/ext-privateer-computer.mjs +626 -0
  188. package/dist-boot/ext-privateer-connect.mjs +1862 -0
  189. package/dist-boot/ext-privateer-context.mjs +323 -0
  190. package/dist-boot/ext-privateer-desktop.mjs +92 -0
  191. package/dist-boot/ext-privateer-final-audit.mjs +48 -0
  192. package/dist-boot/ext-privateer-fresh.mjs +81 -0
  193. package/dist-boot/ext-privateer-gate.mjs +5959 -0
  194. package/dist-boot/ext-privateer-hints.mjs +236 -0
  195. package/dist-boot/ext-privateer-media.mjs +2626 -0
  196. package/dist-boot/ext-privateer-models.mjs +3397 -0
  197. package/dist-boot/ext-privateer-posture.mjs +3006 -0
  198. package/dist-boot/ext-privateer-privacy.mjs +4578 -0
  199. package/dist-boot/ext-privateer-recovery.mjs +287 -0
  200. package/dist-boot/ext-privateer-speak.mjs +4754 -0
  201. package/dist-boot/ext-privateer-terminals.mjs +725 -0
  202. package/dist-boot/ext-privateer-tools.mjs +528 -0
  203. package/dist-boot/ext-privateer-truncation.mjs +74 -0
  204. package/dist-boot/ext-privateer-update.mjs +210 -0
  205. package/dist-boot/ext-privateer-vision.mjs +148 -0
  206. package/dist-boot/ext-privateer-web.mjs +543 -0
  207. package/dist-boot/ext-rpiv-ask-user-question.mjs +710 -0
  208. package/dist-boot/manifest.json +9 -0
  209. package/extensions/privateer-brand.ts +3 -1
  210. package/extensions/privateer-context.ts +4 -2
  211. package/extensions/privateer-final-audit.ts +17 -0
  212. package/extensions/privateer-gate.ts +55 -9
  213. package/extensions/privateer-recovery.ts +175 -0
  214. package/extensions/privateer-web.ts +4 -4
  215. package/package.json +3 -1
  216. package/patches/@earendil-works+pi-coding-agent+1.3.0.patch +199 -2
  217. package/patches/pi-background-tasks+2.6.10.patch +91 -7
  218. package/src/cli/chat.ts +7 -1
  219. package/src/config/moatManifest.json +2 -0
  220. package/src/config/whatsNew.json +4 -4
  221. package/src/context.ts +33 -5
  222. package/src/engine/finalAudit.ts +38 -0
  223. package/src/engine/stallWatchdog.ts +8 -1
  224. package/src/providers/account.ts +34 -3
  225. package/src/remote/attentionPush.ts +40 -0
  226. package/src/remote/liveTaskSession.ts +7 -1
  227. package/src/remote/relayClient.ts +38 -4
  228. package/src/remote/remoteBridge.ts +17 -0
  229. package/src/remote/transcriptSnapshot.ts +104 -0
@@ -0,0 +1,1969 @@
1
+ import{createRequire as __pvCR}from"node:module";import{fileURLToPath as __pvF}from"node:url";import{dirname as __pvD}from"node:path";const require=__pvCR(import.meta.url);const __pvUrl=(r)=>new URL(r,import.meta.url).href;const __pvFile=(r)=>__pvF(new URL(r,import.meta.url));
2
+ import {
3
+ value_exports
4
+ } from "./c-6LOBR4I6.mjs";
5
+ import {
6
+ typebox_exports
7
+ } from "./c-RQJJ26T4.mjs";
8
+ import {
9
+ __name
10
+ } from "./c-CN77DCGF.mjs";
11
+
12
+ // node_modules/@juicesharp/rpiv-web-tools/providers/brave.ts?ext=privateer-web
13
+ var BRAVE_SEARCH_API_URL = "https://api.search.brave.com/res/v1/web/search";
14
+ var BRAVE_API_KEY_ENV_VAR = "BRAVE_SEARCH_API_KEY";
15
+ var BRAVE_PROVIDER_META = {
16
+ name: "brave",
17
+ label: "Brave",
18
+ envVar: BRAVE_API_KEY_ENV_VAR,
19
+ roles: ["search"]
20
+ };
21
+ function normalizeBraveResults(raw) {
22
+ return (raw.web?.results ?? []).map((r) => ({
23
+ title: r.title ?? "",
24
+ url: r.url ?? "",
25
+ snippet: r.description ?? ""
26
+ }));
27
+ }
28
+ __name(normalizeBraveResults, "normalizeBraveResults");
29
+ var BraveProvider = class {
30
+ constructor(apiKey) {
31
+ this.apiKey = apiKey;
32
+ }
33
+ apiKey;
34
+ static {
35
+ __name(this, "BraveProvider");
36
+ }
37
+ name = BRAVE_PROVIDER_META.name;
38
+ label = BRAVE_PROVIDER_META.label;
39
+ envVar = BRAVE_PROVIDER_META.envVar;
40
+ async search(query, maxResults, signal) {
41
+ if (!this.apiKey) {
42
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
43
+ }
44
+ const url = new URL(BRAVE_SEARCH_API_URL);
45
+ url.searchParams.set("q", query);
46
+ url.searchParams.set("count", String(maxResults));
47
+ const res = await fetch(url.toString(), {
48
+ method: "GET",
49
+ headers: {
50
+ Accept: "application/json",
51
+ "Accept-Encoding": "gzip",
52
+ "X-Subscription-Token": this.apiKey
53
+ },
54
+ signal
55
+ });
56
+ if (!res.ok) {
57
+ const text = await res.text();
58
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
59
+ }
60
+ const raw = await res.json();
61
+ return { query, results: normalizeBraveResults(raw) };
62
+ }
63
+ };
64
+
65
+ // node_modules/@juicesharp/rpiv-web-tools/providers/exa.ts?ext=privateer-web
66
+ var EXA_API_URL = "https://api.exa.ai/search";
67
+ var EXA_CONTENTS_API_URL = "https://api.exa.ai/contents";
68
+ var EXA_API_KEY_ENV_VAR = "EXA_API_KEY";
69
+ var EXA_PROVIDER_META = {
70
+ name: "exa",
71
+ label: "Exa",
72
+ envVar: EXA_API_KEY_ENV_VAR,
73
+ roles: ["search", "fetch"]
74
+ };
75
+ var EXA_MAX_SNIPPET_CHARACTERS = 300;
76
+ var EXA_MAX_FETCH_CHARACTERS = 1e6;
77
+ function normalizeExaResults(results) {
78
+ return results.map((r) => ({
79
+ title: r.title ?? "",
80
+ url: r.url ?? "",
81
+ snippet: r.text ?? ""
82
+ }));
83
+ }
84
+ __name(normalizeExaResults, "normalizeExaResults");
85
+ var ExaProvider = class {
86
+ constructor(apiKey) {
87
+ this.apiKey = apiKey;
88
+ }
89
+ apiKey;
90
+ static {
91
+ __name(this, "ExaProvider");
92
+ }
93
+ name = EXA_PROVIDER_META.name;
94
+ label = EXA_PROVIDER_META.label;
95
+ envVar = EXA_PROVIDER_META.envVar;
96
+ async search(query, maxResults, signal) {
97
+ if (!this.apiKey) {
98
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
99
+ }
100
+ const res = await fetch(EXA_API_URL, {
101
+ method: "POST",
102
+ headers: {
103
+ "Content-Type": "application/json",
104
+ "x-api-key": this.apiKey
105
+ },
106
+ body: JSON.stringify({
107
+ query,
108
+ numResults: maxResults,
109
+ contents: {
110
+ text: { maxCharacters: EXA_MAX_SNIPPET_CHARACTERS }
111
+ }
112
+ }),
113
+ signal
114
+ });
115
+ if (!res.ok) {
116
+ const text = await res.text();
117
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
118
+ }
119
+ const raw = await res.json();
120
+ return { query, results: normalizeExaResults(raw.results ?? []) };
121
+ }
122
+ async fetch(url, _raw, signal) {
123
+ if (!this.apiKey) {
124
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
125
+ }
126
+ const res = await fetch(EXA_CONTENTS_API_URL, {
127
+ method: "POST",
128
+ headers: {
129
+ "Content-Type": "application/json",
130
+ "x-api-key": this.apiKey
131
+ },
132
+ body: JSON.stringify({
133
+ ids: [url],
134
+ text: { maxCharacters: EXA_MAX_FETCH_CHARACTERS }
135
+ }),
136
+ signal
137
+ });
138
+ if (!res.ok) {
139
+ const text = await res.text();
140
+ throw new Error(`${this.label} Fetch API error (${res.status}): ${text}`);
141
+ }
142
+ const data = await res.json();
143
+ const result = data.results?.[0];
144
+ if (!result?.text) {
145
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
146
+ }
147
+ return {
148
+ text: result.text,
149
+ title: result.title || void 0,
150
+ contentType: "text/plain"
151
+ };
152
+ }
153
+ };
154
+
155
+ // node_modules/@juicesharp/rpiv-web-tools/providers/firecrawl.ts?ext=privateer-web
156
+ var FIRECRAWL_API_URL = "https://api.firecrawl.dev/v1";
157
+ var FIRECRAWL_API_KEY_ENV_VAR = "FIRECRAWL_API_KEY";
158
+ var FIRECRAWL_PROVIDER_META = {
159
+ name: "firecrawl",
160
+ label: "Firecrawl",
161
+ envVar: FIRECRAWL_API_KEY_ENV_VAR,
162
+ roles: ["search", "fetch"]
163
+ };
164
+ function normalizeFirecrawlResults(results) {
165
+ return results.map((r) => ({
166
+ title: r.title ?? "",
167
+ url: r.url ?? "",
168
+ snippet: r.description ?? ""
169
+ }));
170
+ }
171
+ __name(normalizeFirecrawlResults, "normalizeFirecrawlResults");
172
+ var FirecrawlProvider = class {
173
+ constructor(apiKey) {
174
+ this.apiKey = apiKey;
175
+ }
176
+ apiKey;
177
+ static {
178
+ __name(this, "FirecrawlProvider");
179
+ }
180
+ name = FIRECRAWL_PROVIDER_META.name;
181
+ label = FIRECRAWL_PROVIDER_META.label;
182
+ envVar = FIRECRAWL_PROVIDER_META.envVar;
183
+ async search(query, maxResults, signal) {
184
+ if (!this.apiKey) {
185
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
186
+ }
187
+ const res = await fetch(`${FIRECRAWL_API_URL}/search`, {
188
+ method: "POST",
189
+ headers: {
190
+ "Content-Type": "application/json",
191
+ Authorization: `Bearer ${this.apiKey}`
192
+ },
193
+ body: JSON.stringify({
194
+ query,
195
+ limit: maxResults
196
+ }),
197
+ signal
198
+ });
199
+ if (!res.ok) {
200
+ const text = await res.text();
201
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
202
+ }
203
+ const raw = await res.json();
204
+ return { query, results: normalizeFirecrawlResults(raw.data ?? []) };
205
+ }
206
+ async fetch(url, _raw, signal) {
207
+ if (!this.apiKey) {
208
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
209
+ }
210
+ const res = await fetch(`${FIRECRAWL_API_URL}/scrape`, {
211
+ method: "POST",
212
+ headers: {
213
+ "Content-Type": "application/json",
214
+ Authorization: `Bearer ${this.apiKey}`
215
+ },
216
+ body: JSON.stringify({
217
+ url,
218
+ formats: ["markdown"]
219
+ }),
220
+ signal
221
+ });
222
+ if (!res.ok) {
223
+ const text = await res.text();
224
+ throw new Error(`${this.label} Fetch API error (${res.status}): ${text}`);
225
+ }
226
+ const raw = await res.json();
227
+ if (!raw.success) {
228
+ throw new Error(`${this.label} Fetch API error: ${raw.error ?? "scrape failed"}`);
229
+ }
230
+ if (!raw.data?.markdown) {
231
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
232
+ }
233
+ return {
234
+ text: raw.data.markdown,
235
+ title: raw.data.metadata?.title || void 0,
236
+ contentType: "text/markdown"
237
+ };
238
+ }
239
+ };
240
+
241
+ // node_modules/@juicesharp/rpiv-web-tools/providers/jina.ts?ext=privateer-web
242
+ var JINA_SEARCH_API_URL = "https://s.jina.ai/";
243
+ var JINA_READER_API_URL = "https://r.jina.ai/";
244
+ var JINA_API_KEY_ENV_VAR = "JINA_API_KEY";
245
+ var JINA_PROVIDER_META = {
246
+ name: "jina",
247
+ label: "Jina",
248
+ envVar: JINA_API_KEY_ENV_VAR,
249
+ roles: ["search", "fetch"]
250
+ };
251
+ function normalizeJinaResults(results) {
252
+ return results.map((r) => ({
253
+ title: r.title ?? "",
254
+ url: r.url ?? "",
255
+ snippet: r.description ?? ""
256
+ }));
257
+ }
258
+ __name(normalizeJinaResults, "normalizeJinaResults");
259
+ var JinaProvider = class {
260
+ constructor(apiKey) {
261
+ this.apiKey = apiKey;
262
+ }
263
+ apiKey;
264
+ static {
265
+ __name(this, "JinaProvider");
266
+ }
267
+ name = JINA_PROVIDER_META.name;
268
+ label = JINA_PROVIDER_META.label;
269
+ envVar = JINA_PROVIDER_META.envVar;
270
+ async search(query, maxResults, signal) {
271
+ if (!this.apiKey) {
272
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
273
+ }
274
+ const url = new URL(`${JINA_SEARCH_API_URL}${encodeURIComponent(query)}`);
275
+ url.searchParams.set("num", String(maxResults));
276
+ const res = await fetch(url.toString(), {
277
+ method: "GET",
278
+ headers: {
279
+ Accept: "application/json",
280
+ Authorization: `Bearer ${this.apiKey}`
281
+ },
282
+ signal
283
+ });
284
+ if (!res.ok) {
285
+ const text = await res.text();
286
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
287
+ }
288
+ const raw = await res.json();
289
+ const results = normalizeJinaResults(Array.isArray(raw.data) ? raw.data : raw.data?.results ?? []).slice(
290
+ 0,
291
+ maxResults
292
+ );
293
+ return { query, results };
294
+ }
295
+ async fetch(url, _raw, signal) {
296
+ if (!this.apiKey) {
297
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
298
+ }
299
+ const res = await fetch(`${JINA_READER_API_URL}${url}`, {
300
+ method: "GET",
301
+ headers: {
302
+ Authorization: `Bearer ${this.apiKey}`
303
+ },
304
+ signal
305
+ });
306
+ if (!res.ok) {
307
+ const text2 = await res.text();
308
+ throw new Error(`${this.label} Fetch API error (${res.status}): ${text2}`);
309
+ }
310
+ const text = await res.text();
311
+ if (!text.trim()) {
312
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
313
+ }
314
+ return {
315
+ text,
316
+ contentType: "text/markdown"
317
+ };
318
+ }
319
+ };
320
+
321
+ // node_modules/@juicesharp/rpiv-web-tools/providers/types.ts?ext=privateer-web
322
+ function isCancellation(input) {
323
+ return input == null;
324
+ }
325
+ __name(isCancellation, "isCancellation");
326
+
327
+ // node_modules/@juicesharp/rpiv-web-tools/providers/ollama.ts?ext=privateer-web
328
+ var OLLAMA_API_KEY_ENV_VAR = "OLLAMA_API_KEY";
329
+ var OLLAMA_HOST_ENV_VAR = "OLLAMA_HOST";
330
+ var OLLAMA_DEFAULT_URL = "http://localhost:11434";
331
+ var CLOUD_SEARCH_PATH = "/api/web_search";
332
+ var CLOUD_FETCH_PATH = "/api/web_fetch";
333
+ var LOCAL_SEARCH_PATH = "/api/experimental/web_search";
334
+ var LOCAL_FETCH_PATH = "/api/experimental/web_fetch";
335
+ function isLocalHost(baseUrl) {
336
+ try {
337
+ const hostname = new URL(baseUrl).hostname;
338
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "[::1]";
339
+ } catch {
340
+ return true;
341
+ }
342
+ }
343
+ __name(isLocalHost, "isLocalHost");
344
+ var MASK_VISIBLE_CHARS = 4;
345
+ var OLLAMA_PROVIDER_META = {
346
+ name: "ollama",
347
+ label: "Ollama",
348
+ envVar: OLLAMA_API_KEY_ENV_VAR,
349
+ baseUrlEnvVar: OLLAMA_HOST_ENV_VAR,
350
+ defaultBaseUrl: OLLAMA_DEFAULT_URL,
351
+ roles: ["search", "fetch"],
352
+ configure: /* @__PURE__ */ __name((ui, current) => configureOllama(ui, current), "configure")
353
+ };
354
+ function normalizeOllamaResults(raw) {
355
+ return (raw.results ?? []).map((r) => ({
356
+ title: r.title ?? "",
357
+ url: r.url ?? "",
358
+ snippet: r.content ?? ""
359
+ }));
360
+ }
361
+ __name(normalizeOllamaResults, "normalizeOllamaResults");
362
+ function stripTrailingSlashes(url) {
363
+ return url.replace(/\/+$/, "");
364
+ }
365
+ __name(stripTrailingSlashes, "stripTrailingSlashes");
366
+ function assertHttpUrl(url) {
367
+ let parsed;
368
+ try {
369
+ parsed = new URL(url);
370
+ } catch {
371
+ throw new Error(`${OLLAMA_HOST_ENV_VAR} is not a valid URL (got: ${url})`);
372
+ }
373
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
374
+ throw new Error(
375
+ `${OLLAMA_HOST_ENV_VAR} must use http:// or https:// (got: ${parsed.protocol.replace(":", "")}://)`
376
+ );
377
+ }
378
+ }
379
+ __name(assertHttpUrl, "assertHttpUrl");
380
+ function isConnectionRefused(error) {
381
+ if (error instanceof TypeError) {
382
+ const cause = error.cause;
383
+ return cause?.code === "ECONNREFUSED";
384
+ }
385
+ return false;
386
+ }
387
+ __name(isConnectionRefused, "isConnectionRefused");
388
+ function connectionRefusedError(host) {
389
+ return new Error(`Could not connect to Ollama at ${host}. Make sure Ollama is running (ollama serve).`);
390
+ }
391
+ __name(connectionRefusedError, "connectionRefusedError");
392
+ var OllamaProvider = class {
393
+ static {
394
+ __name(this, "OllamaProvider");
395
+ }
396
+ name = "ollama";
397
+ label = "Ollama";
398
+ envVar = OLLAMA_API_KEY_ENV_VAR;
399
+ apiKey;
400
+ baseUrl;
401
+ local;
402
+ constructor(options) {
403
+ this.apiKey = options.apiKey?.trim() || void 0;
404
+ const trimmed = stripTrailingSlashes(options.baseUrl?.trim() ?? "");
405
+ if (trimmed) assertHttpUrl(trimmed);
406
+ this.baseUrl = trimmed;
407
+ this.local = isLocalHost(trimmed);
408
+ }
409
+ async search(query, maxResults, signal) {
410
+ this.requireBaseUrl();
411
+ const path = this.local ? LOCAL_SEARCH_PATH : CLOUD_SEARCH_PATH;
412
+ try {
413
+ const res = await fetch(`${this.baseUrl}${path}`, {
414
+ method: "POST",
415
+ headers: this.buildHeaders(),
416
+ body: JSON.stringify({ query, max_results: maxResults }),
417
+ signal
418
+ });
419
+ if (!res.ok) throw await this.formatError("Search", res);
420
+ const raw = await res.json();
421
+ return { query, results: normalizeOllamaResults(raw) };
422
+ } catch (error) {
423
+ if (isConnectionRefused(error)) throw connectionRefusedError(this.baseUrl);
424
+ throw error;
425
+ }
426
+ }
427
+ async fetch(url, _raw, signal) {
428
+ this.requireBaseUrl();
429
+ const path = this.local ? LOCAL_FETCH_PATH : CLOUD_FETCH_PATH;
430
+ try {
431
+ const res = await fetch(`${this.baseUrl}${path}`, {
432
+ method: "POST",
433
+ headers: this.buildHeaders(),
434
+ body: JSON.stringify({ url }),
435
+ signal
436
+ });
437
+ if (!res.ok) throw await this.formatError("Fetch", res);
438
+ const data = await res.json();
439
+ if (!data.content) {
440
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
441
+ }
442
+ return {
443
+ text: data.content,
444
+ title: data.title || void 0,
445
+ contentType: "text/plain"
446
+ };
447
+ } catch (error) {
448
+ if (isConnectionRefused(error)) throw connectionRefusedError(this.baseUrl);
449
+ throw error;
450
+ }
451
+ }
452
+ requireBaseUrl() {
453
+ if (!this.baseUrl) {
454
+ throw new Error(`${OLLAMA_HOST_ENV_VAR} is not set. Run /web-tools to configure, or export the env var.`);
455
+ }
456
+ }
457
+ buildHeaders() {
458
+ const headers = { "Content-Type": "application/json" };
459
+ if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;
460
+ return headers;
461
+ }
462
+ async formatError(label, res) {
463
+ const body = await res.text();
464
+ const hint = hintForStatus(res.status);
465
+ return new Error(`${this.label} ${label} API error (${res.status})${hint}: ${body}`);
466
+ }
467
+ };
468
+ function hintForStatus(status) {
469
+ if (status === 401) {
470
+ return " (run `ollama signin` to authenticate)";
471
+ }
472
+ if (status === 404) {
473
+ return " (the Ollama instance may not support web search; ensure you are running a recent version)";
474
+ }
475
+ return "";
476
+ }
477
+ __name(hintForStatus, "hintForStatus");
478
+ function maskKey(key) {
479
+ const head = key.slice(0, MASK_VISIBLE_CHARS);
480
+ const tail = key.slice(-MASK_VISIBLE_CHARS);
481
+ return `${head}...${tail}`;
482
+ }
483
+ __name(maskKey, "maskKey");
484
+ async function promptForBaseUrl(ui, current) {
485
+ const existing = current?.trim();
486
+ const input = await ui.input(
487
+ "Ollama base URL",
488
+ existing ? `Press Enter to keep current (${existing}), or type new URL` : `Press Enter for default (${OLLAMA_DEFAULT_URL}), or type instance URL`
489
+ );
490
+ if (isCancellation(input)) return void 0;
491
+ return input.trim() || existing || OLLAMA_DEFAULT_URL;
492
+ }
493
+ __name(promptForBaseUrl, "promptForBaseUrl");
494
+ async function promptForOptionalKey(ui, current) {
495
+ const existing = current?.trim() || void 0;
496
+ const input = await ui.input(
497
+ "Ollama API key (optional \u2014 for direct cloud access; local Ollama authenticates via `ollama signin`)",
498
+ existing ? `Press Enter to keep current (${maskKey(existing)}), or type new key` : "Press Enter to leave unset, or type a key"
499
+ );
500
+ if (isCancellation(input)) return void 0;
501
+ return input.trim() || existing || null;
502
+ }
503
+ __name(promptForOptionalKey, "promptForOptionalKey");
504
+ async function configureOllama(ui, current) {
505
+ const baseUrl = await promptForBaseUrl(ui, current.baseUrl);
506
+ if (baseUrl === void 0) return null;
507
+ const apiKey = await promptForOptionalKey(ui, current.apiKey);
508
+ if (apiKey === void 0) return null;
509
+ return { baseUrl, apiKey };
510
+ }
511
+ __name(configureOllama, "configureOllama");
512
+
513
+ // node_modules/@juicesharp/rpiv-web-tools/providers/perplexity.ts?ext=privateer-web
514
+ var PERPLEXITY_API_URL = "https://api.perplexity.ai/search";
515
+ var PERPLEXITY_API_KEY_ENV_VAR = "PERPLEXITY_API_KEY";
516
+ var PERPLEXITY_PROVIDER_META = {
517
+ name: "perplexity",
518
+ label: "Perplexity",
519
+ envVar: PERPLEXITY_API_KEY_ENV_VAR,
520
+ roles: ["search"]
521
+ };
522
+ function normalizePerplexityResults(results) {
523
+ return results.map((r) => ({
524
+ title: r.title ?? "",
525
+ url: r.url ?? "",
526
+ snippet: r.snippet ?? ""
527
+ }));
528
+ }
529
+ __name(normalizePerplexityResults, "normalizePerplexityResults");
530
+ var PerplexityProvider = class {
531
+ constructor(apiKey) {
532
+ this.apiKey = apiKey;
533
+ }
534
+ apiKey;
535
+ static {
536
+ __name(this, "PerplexityProvider");
537
+ }
538
+ name = PERPLEXITY_PROVIDER_META.name;
539
+ label = PERPLEXITY_PROVIDER_META.label;
540
+ envVar = PERPLEXITY_PROVIDER_META.envVar;
541
+ async search(query, maxResults, signal) {
542
+ if (!this.apiKey) {
543
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
544
+ }
545
+ const res = await fetch(PERPLEXITY_API_URL, {
546
+ method: "POST",
547
+ headers: {
548
+ "Content-Type": "application/json",
549
+ Authorization: `Bearer ${this.apiKey}`
550
+ },
551
+ body: JSON.stringify({
552
+ query,
553
+ max_results: maxResults
554
+ }),
555
+ signal
556
+ });
557
+ if (!res.ok) {
558
+ const text = await res.text();
559
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
560
+ }
561
+ const raw = await res.json();
562
+ return { query, results: normalizePerplexityResults(raw.results ?? []) };
563
+ }
564
+ };
565
+
566
+ // node_modules/@juicesharp/rpiv-web-tools/providers/searxng.ts?ext=privateer-web
567
+ var SEARXNG_API_KEY_ENV_VAR = "SEARXNG_API_KEY";
568
+ var SEARXNG_URL_ENV_VAR = "SEARXNG_URL";
569
+ var SEARXNG_DEFAULT_URL = "http://localhost:8080";
570
+ var SEARXNG_SEARCH_PATH = "/search";
571
+ var SEARXNG_FORMAT_JSON = "json";
572
+ var SEARXNG_SAFESEARCH_OFF = "0";
573
+ var MASK_VISIBLE_CHARS2 = 4;
574
+ var SEARXNG_PROVIDER_META = {
575
+ name: "searxng",
576
+ label: "SearXNG",
577
+ envVar: SEARXNG_API_KEY_ENV_VAR,
578
+ baseUrlEnvVar: SEARXNG_URL_ENV_VAR,
579
+ defaultBaseUrl: SEARXNG_DEFAULT_URL,
580
+ roles: ["search"],
581
+ configure: /* @__PURE__ */ __name((ui, current) => configureSearxng(ui, current), "configure")
582
+ };
583
+ function normalizeSearxngResults(raw, maxResults) {
584
+ return (raw.results ?? []).slice(0, maxResults).map((r) => ({
585
+ title: r.title ?? "",
586
+ url: r.url ?? "",
587
+ snippet: r.content ?? ""
588
+ }));
589
+ }
590
+ __name(normalizeSearxngResults, "normalizeSearxngResults");
591
+ function stripTrailingSlashes2(url) {
592
+ return url.replace(/\/+$/, "");
593
+ }
594
+ __name(stripTrailingSlashes2, "stripTrailingSlashes");
595
+ function assertHttpUrl2(url) {
596
+ let parsed;
597
+ try {
598
+ parsed = new URL(url);
599
+ } catch {
600
+ throw new Error(`${SEARXNG_URL_ENV_VAR} is not a valid URL (got: ${url})`);
601
+ }
602
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
603
+ throw new Error(
604
+ `${SEARXNG_URL_ENV_VAR} must use http:// or https:// (got: ${parsed.protocol.replace(":", "")}://)`
605
+ );
606
+ }
607
+ }
608
+ __name(assertHttpUrl2, "assertHttpUrl");
609
+ function hintForSearchStatus(status) {
610
+ if (status === 401) {
611
+ return ` (the SearXNG instance's reverse-proxy rejected the Bearer token; check ${SEARXNG_API_KEY_ENV_VAR} or apiKeys.searxng)`;
612
+ }
613
+ if (status === 403) {
614
+ return " (the SearXNG instance may have JSON output disabled; enable 'json' under 'search.formats' in its settings.yml)";
615
+ }
616
+ return "";
617
+ }
618
+ __name(hintForSearchStatus, "hintForSearchStatus");
619
+ var SearxngProvider = class {
620
+ static {
621
+ __name(this, "SearxngProvider");
622
+ }
623
+ name = "searxng";
624
+ label = "SearXNG";
625
+ envVar = SEARXNG_API_KEY_ENV_VAR;
626
+ apiKey;
627
+ baseUrl;
628
+ constructor(options) {
629
+ this.apiKey = options.apiKey?.trim() || void 0;
630
+ const trimmed = stripTrailingSlashes2(options.baseUrl?.trim() ?? "");
631
+ if (trimmed) assertHttpUrl2(trimmed);
632
+ this.baseUrl = trimmed;
633
+ }
634
+ async search(query, maxResults, signal) {
635
+ this.requireBaseUrl();
636
+ const res = await fetch(this.buildSearchUrl(query), {
637
+ method: "GET",
638
+ headers: this.buildAuthHeaders(),
639
+ signal
640
+ });
641
+ if (!res.ok) throw await this.searchApiError(res);
642
+ const raw = await res.json();
643
+ return { query, results: normalizeSearxngResults(raw, maxResults) };
644
+ }
645
+ requireBaseUrl() {
646
+ if (!this.baseUrl) {
647
+ throw new Error(`${SEARXNG_URL_ENV_VAR} is not set. Run /web-tools to configure, or export the env var.`);
648
+ }
649
+ }
650
+ // The SearXNG API exposes only `pageno` for pagination, not `count`/`limit`
651
+ // (https://docs.searxng.org/dev/search_api.html), so we ask for a single
652
+ // page and slice to maxResults client-side.
653
+ buildSearchUrl(query) {
654
+ const url = new URL(`${this.baseUrl}${SEARXNG_SEARCH_PATH}`);
655
+ url.searchParams.set("q", query);
656
+ url.searchParams.set("format", SEARXNG_FORMAT_JSON);
657
+ url.searchParams.set("safesearch", SEARXNG_SAFESEARCH_OFF);
658
+ return url.toString();
659
+ }
660
+ // SearXNG itself has no native auth; the optional Bearer key is for
661
+ // instances fronted by a reverse-proxy that gates on Authorization.
662
+ buildAuthHeaders() {
663
+ const headers = { Accept: "application/json" };
664
+ if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;
665
+ return headers;
666
+ }
667
+ async searchApiError(res) {
668
+ const body = await res.text();
669
+ return new Error(`${this.label} Search API error (${res.status})${hintForSearchStatus(res.status)}: ${body}`);
670
+ }
671
+ };
672
+ function maskKey2(key) {
673
+ const head = key.slice(0, MASK_VISIBLE_CHARS2);
674
+ const tail = key.slice(-MASK_VISIBLE_CHARS2);
675
+ return `${head}...${tail}`;
676
+ }
677
+ __name(maskKey2, "maskKey");
678
+ async function promptForBaseUrl2(ui, current) {
679
+ const existing = current?.trim();
680
+ const input = await ui.input(
681
+ "SearXNG base URL",
682
+ existing ? `Press Enter to keep current (${existing}), or type new URL` : `Press Enter for default (${SEARXNG_DEFAULT_URL}), or type instance URL`
683
+ );
684
+ if (isCancellation(input)) return void 0;
685
+ return input.trim() || existing || SEARXNG_DEFAULT_URL;
686
+ }
687
+ __name(promptForBaseUrl2, "promptForBaseUrl");
688
+ async function promptForOptionalKey2(ui, current) {
689
+ const existing = current?.trim() || void 0;
690
+ const input = await ui.input(
691
+ "SearXNG API key (optional \u2014 for instances behind a Bearer-auth proxy)",
692
+ existing ? `Press Enter to keep current (${maskKey2(existing)}), or type new key` : "Press Enter to leave unset, or type a key"
693
+ );
694
+ if (isCancellation(input)) return void 0;
695
+ return input.trim() || existing || null;
696
+ }
697
+ __name(promptForOptionalKey2, "promptForOptionalKey");
698
+ async function configureSearxng(ui, current) {
699
+ const baseUrl = await promptForBaseUrl2(ui, current.baseUrl);
700
+ if (baseUrl === void 0) return null;
701
+ const apiKey = await promptForOptionalKey2(ui, current.apiKey);
702
+ if (apiKey === void 0) return null;
703
+ return { baseUrl, apiKey };
704
+ }
705
+ __name(configureSearxng, "configureSearxng");
706
+
707
+ // node_modules/@juicesharp/rpiv-web-tools/providers/serper.ts?ext=privateer-web
708
+ var SERPER_API_URL = "https://google.serper.dev/search";
709
+ var SERPER_API_KEY_ENV_VAR = "SERPER_API_KEY";
710
+ var SERPER_PROVIDER_META = {
711
+ name: "serper",
712
+ label: "Serper",
713
+ envVar: SERPER_API_KEY_ENV_VAR,
714
+ roles: ["search"]
715
+ };
716
+ function normalizeSerperResults(results) {
717
+ return results.map((r) => ({
718
+ title: r.title ?? "",
719
+ url: r.link ?? "",
720
+ snippet: r.snippet ?? ""
721
+ }));
722
+ }
723
+ __name(normalizeSerperResults, "normalizeSerperResults");
724
+ var SerperProvider = class {
725
+ constructor(apiKey) {
726
+ this.apiKey = apiKey;
727
+ }
728
+ apiKey;
729
+ static {
730
+ __name(this, "SerperProvider");
731
+ }
732
+ name = SERPER_PROVIDER_META.name;
733
+ label = SERPER_PROVIDER_META.label;
734
+ envVar = SERPER_PROVIDER_META.envVar;
735
+ async search(query, maxResults, signal) {
736
+ if (!this.apiKey) {
737
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
738
+ }
739
+ const res = await fetch(SERPER_API_URL, {
740
+ method: "POST",
741
+ headers: {
742
+ "Content-Type": "application/json",
743
+ "X-API-KEY": this.apiKey
744
+ },
745
+ body: JSON.stringify({
746
+ q: query,
747
+ num: maxResults
748
+ }),
749
+ signal
750
+ });
751
+ if (!res.ok) {
752
+ const text = await res.text();
753
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
754
+ }
755
+ const raw = await res.json();
756
+ return { query, results: normalizeSerperResults(raw.organic ?? []) };
757
+ }
758
+ };
759
+
760
+ // node_modules/@juicesharp/rpiv-web-tools/providers/tavily.ts?ext=privateer-web
761
+ var TAVILY_API_URL = "https://api.tavily.com/search";
762
+ var TAVILY_EXTRACT_API_URL = "https://api.tavily.com/extract";
763
+ var TAVILY_API_KEY_ENV_VAR = "TAVILY_API_KEY";
764
+ var TAVILY_PROVIDER_META = {
765
+ name: "tavily",
766
+ label: "Tavily",
767
+ envVar: TAVILY_API_KEY_ENV_VAR,
768
+ roles: ["search", "fetch"]
769
+ };
770
+ function normalizeTavilyResults(results) {
771
+ return results.map((r) => ({
772
+ title: r.title ?? "",
773
+ url: r.url ?? "",
774
+ snippet: r.content ?? ""
775
+ }));
776
+ }
777
+ __name(normalizeTavilyResults, "normalizeTavilyResults");
778
+ var TavilyProvider = class {
779
+ constructor(apiKey) {
780
+ this.apiKey = apiKey;
781
+ }
782
+ apiKey;
783
+ static {
784
+ __name(this, "TavilyProvider");
785
+ }
786
+ name = TAVILY_PROVIDER_META.name;
787
+ label = TAVILY_PROVIDER_META.label;
788
+ envVar = TAVILY_PROVIDER_META.envVar;
789
+ async search(query, maxResults, signal) {
790
+ if (!this.apiKey) {
791
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
792
+ }
793
+ const res = await fetch(TAVILY_API_URL, {
794
+ method: "POST",
795
+ headers: { "Content-Type": "application/json" },
796
+ body: JSON.stringify({
797
+ api_key: this.apiKey,
798
+ query,
799
+ max_results: maxResults
800
+ }),
801
+ signal
802
+ });
803
+ if (!res.ok) {
804
+ const text = await res.text();
805
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
806
+ }
807
+ const raw = await res.json();
808
+ return { query, results: normalizeTavilyResults(raw.results ?? []) };
809
+ }
810
+ async fetch(url, _raw, signal) {
811
+ if (!this.apiKey) {
812
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
813
+ }
814
+ const res = await fetch(TAVILY_EXTRACT_API_URL, {
815
+ method: "POST",
816
+ headers: {
817
+ "Content-Type": "application/json",
818
+ Authorization: `Bearer ${this.apiKey}`
819
+ },
820
+ body: JSON.stringify({
821
+ urls: [url]
822
+ }),
823
+ signal
824
+ });
825
+ if (!res.ok) {
826
+ const text = await res.text();
827
+ throw new Error(`${this.label} Fetch API error (${res.status}): ${text}`);
828
+ }
829
+ const data = await res.json();
830
+ if (data.failed_results && data.failed_results.length > 0) {
831
+ const failed = data.failed_results[0];
832
+ throw new Error(
833
+ `${this.label} Fetch API error: extraction failed for ${failed.url ?? url}: ${failed.error ?? "unknown error"}`
834
+ );
835
+ }
836
+ const result = data.results?.[0];
837
+ if (!result?.raw_content) {
838
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
839
+ }
840
+ return {
841
+ text: result.raw_content,
842
+ contentType: "text/plain"
843
+ };
844
+ }
845
+ };
846
+
847
+ // node_modules/@juicesharp/rpiv-web-tools/providers/youcom.ts?ext=privateer-web
848
+ var YOUCOM_SEARCH_URL = "https://ydc-index.io/v1/search";
849
+ var YOUCOM_CONTENTS_URL = "https://ydc-index.io/v1/contents";
850
+ var YOUCOM_API_KEY_ENV_VAR = "YOUCOM_API_KEY";
851
+ var YOUCOM_PROVIDER_META = {
852
+ name: "youcom",
853
+ label: "You.com",
854
+ envVar: YOUCOM_API_KEY_ENV_VAR,
855
+ roles: ["search", "fetch"]
856
+ };
857
+ function normalizeYouComResults(results) {
858
+ return results.map((r) => ({
859
+ title: r.title ?? "",
860
+ url: r.url ?? "",
861
+ snippet: r.snippets?.[0] ?? r.description ?? ""
862
+ }));
863
+ }
864
+ __name(normalizeYouComResults, "normalizeYouComResults");
865
+ var YouComProvider = class {
866
+ constructor(apiKey) {
867
+ this.apiKey = apiKey;
868
+ }
869
+ apiKey;
870
+ static {
871
+ __name(this, "YouComProvider");
872
+ }
873
+ name = YOUCOM_PROVIDER_META.name;
874
+ label = YOUCOM_PROVIDER_META.label;
875
+ envVar = YOUCOM_API_KEY_ENV_VAR;
876
+ async search(query, maxResults, signal) {
877
+ if (!this.apiKey) {
878
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
879
+ }
880
+ const res = await fetch(YOUCOM_SEARCH_URL, {
881
+ method: "POST",
882
+ headers: {
883
+ "Content-Type": "application/json",
884
+ "X-API-Key": this.apiKey
885
+ },
886
+ body: JSON.stringify({
887
+ query,
888
+ count: maxResults
889
+ }),
890
+ signal
891
+ });
892
+ if (!res.ok) {
893
+ const text = await res.text();
894
+ throw new Error(`${this.label} Search API error (${res.status}): ${text}`);
895
+ }
896
+ const raw = await res.json();
897
+ return { query, results: normalizeYouComResults(raw.results?.web ?? []) };
898
+ }
899
+ async fetch(url, _raw, signal) {
900
+ if (!this.apiKey) {
901
+ throw new Error(`${this.envVar} is not set. Run /web-tools to configure, or export the env var.`);
902
+ }
903
+ const res = await fetch(YOUCOM_CONTENTS_URL, {
904
+ method: "POST",
905
+ headers: {
906
+ "Content-Type": "application/json",
907
+ "X-API-Key": this.apiKey
908
+ },
909
+ body: JSON.stringify({
910
+ urls: [url],
911
+ formats: ["markdown"]
912
+ }),
913
+ signal
914
+ });
915
+ if (!res.ok) {
916
+ const text = await res.text();
917
+ throw new Error(`${this.label} Fetch API error (${res.status}): ${text}`);
918
+ }
919
+ const raw = await res.json();
920
+ const item = raw[0];
921
+ if (!item?.markdown) {
922
+ throw new Error(`${this.label} Fetch API error: no content returned for ${url}`);
923
+ }
924
+ return {
925
+ text: item.markdown,
926
+ title: item.title || void 0,
927
+ contentType: "text/markdown"
928
+ };
929
+ }
930
+ };
931
+
932
+ // node_modules/@juicesharp/rpiv-web-tools/providers/factory.ts?ext=privateer-web
933
+ function createSearchProvider(name, creds) {
934
+ const apiKey = creds.apiKey ?? "";
935
+ switch (name) {
936
+ case "brave":
937
+ return new BraveProvider(apiKey);
938
+ case "tavily":
939
+ return new TavilyProvider(apiKey);
940
+ case "serper":
941
+ return new SerperProvider(apiKey);
942
+ case "exa":
943
+ return new ExaProvider(apiKey);
944
+ case "youcom":
945
+ return new YouComProvider(apiKey);
946
+ case "jina":
947
+ return new JinaProvider(apiKey);
948
+ case "firecrawl":
949
+ return new FirecrawlProvider(apiKey);
950
+ case "perplexity":
951
+ return new PerplexityProvider(apiKey);
952
+ case "searxng":
953
+ return new SearxngProvider({ apiKey: creds.apiKey, baseUrl: creds.baseUrl ?? "" });
954
+ case "ollama":
955
+ return new OllamaProvider({ apiKey: creds.apiKey, baseUrl: creds.baseUrl ?? "" });
956
+ default:
957
+ throw new Error(`Unknown search provider: "${name}"`);
958
+ }
959
+ }
960
+ __name(createSearchProvider, "createSearchProvider");
961
+
962
+ // node_modules/@juicesharp/rpiv-web-tools/providers/interceptors/github.ts?ext=privateer-web
963
+ import { execFile } from "node:child_process";
964
+ import {
965
+ closeSync,
966
+ existsSync as existsSync2,
967
+ openSync,
968
+ readdirSync,
969
+ readFileSync as readFileSync2,
970
+ readSync,
971
+ realpathSync,
972
+ rmSync,
973
+ statSync
974
+ } from "node:fs";
975
+ import { tmpdir } from "node:os";
976
+ import { extname, join as join2, sep as pathSep, resolve as resolvePath } from "node:path";
977
+
978
+ // node_modules/@juicesharp/rpiv-config/config.ts?ext=privateer-web
979
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
980
+ import { homedir } from "node:os";
981
+ import { dirname, isAbsolute, join } from "node:path";
982
+ function expandTilde(p) {
983
+ if (p === "~") return homedir();
984
+ if (p.startsWith("~/")) return join(homedir(), p.slice(2));
985
+ return p;
986
+ }
987
+ __name(expandTilde, "expandTilde");
988
+ function defaultConfigDir() {
989
+ return join(homedir(), ".config");
990
+ }
991
+ __name(defaultConfigDir, "defaultConfigDir");
992
+ function resolveConfigDir() {
993
+ const xdg = readEnvVar("XDG_CONFIG_HOME");
994
+ if (!xdg) return defaultConfigDir();
995
+ const expanded = expandTilde(xdg);
996
+ return isAbsolute(expanded) ? expanded : defaultConfigDir();
997
+ }
998
+ __name(resolveConfigDir, "resolveConfigDir");
999
+ function legacyConfigPath(name, file = "config.json") {
1000
+ return join(defaultConfigDir(), name, file);
1001
+ }
1002
+ __name(legacyConfigPath, "legacyConfigPath");
1003
+ function configPath(name, file = "config.json") {
1004
+ return join(resolveConfigDir(), name, file);
1005
+ }
1006
+ __name(configPath, "configPath");
1007
+ function loadJsonConfig(path) {
1008
+ if (!existsSync(path)) return {};
1009
+ try {
1010
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
1011
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
1012
+ return parsed;
1013
+ } catch (err) {
1014
+ console.warn(`rpiv-config: invalid JSON at ${path}, using default ({}) \u2014 ${err.message}`);
1015
+ return {};
1016
+ }
1017
+ }
1018
+ __name(loadJsonConfig, "loadJsonConfig");
1019
+ function loadJsonConfigWithLegacyFallback(name, file = "config.json") {
1020
+ const xdgPath = configPath(name, file);
1021
+ if (existsSync(xdgPath)) {
1022
+ return loadJsonConfig(xdgPath);
1023
+ }
1024
+ return loadJsonConfig(legacyConfigPath(name, file));
1025
+ }
1026
+ __name(loadJsonConfigWithLegacyFallback, "loadJsonConfigWithLegacyFallback");
1027
+ var CONFIG_FILE_MODE = 384;
1028
+ function saveJsonConfig(path, data) {
1029
+ try {
1030
+ mkdirSync(dirname(path), { recursive: true });
1031
+ writeFileSync(path, `${JSON.stringify(data, null, 2)}
1032
+ `, "utf-8");
1033
+ } catch {
1034
+ return false;
1035
+ }
1036
+ try {
1037
+ chmodSync(path, CONFIG_FILE_MODE);
1038
+ } catch {
1039
+ }
1040
+ return true;
1041
+ }
1042
+ __name(saveJsonConfig, "saveJsonConfig");
1043
+ var GuidanceFieldsSchema = typebox_exports.Object(
1044
+ {
1045
+ promptSnippet: typebox_exports.Optional(typebox_exports.String()),
1046
+ promptGuidelines: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String())),
1047
+ description: typebox_exports.Optional(typebox_exports.String())
1048
+ },
1049
+ { additionalProperties: true }
1050
+ );
1051
+ function validateGuidanceFields(fields) {
1052
+ if (!fields || typeof fields !== "object") return {};
1053
+ const g = fields;
1054
+ const result = {};
1055
+ if (typeof g.promptSnippet === "string" && g.promptSnippet.length > 0) {
1056
+ result.promptSnippet = g.promptSnippet;
1057
+ }
1058
+ if (Array.isArray(g.promptGuidelines) && g.promptGuidelines.length > 0 && g.promptGuidelines.every((s) => typeof s === "string" && s.length > 0)) {
1059
+ result.promptGuidelines = g.promptGuidelines;
1060
+ }
1061
+ if (typeof g.description === "string" && g.description.length > 0) {
1062
+ result.description = g.description;
1063
+ }
1064
+ return result;
1065
+ }
1066
+ __name(validateGuidanceFields, "validateGuidanceFields");
1067
+ function readEnvVar(key, fallback) {
1068
+ return process.env[key]?.trim() || fallback;
1069
+ }
1070
+ __name(readEnvVar, "readEnvVar");
1071
+
1072
+ // node_modules/@juicesharp/rpiv-web-tools/providers/config.ts?ext=privateer-web
1073
+ var WebToolsGuidanceSchema = typebox_exports.Object(
1074
+ {
1075
+ web_search: typebox_exports.Optional(GuidanceFieldsSchema),
1076
+ web_fetch: typebox_exports.Optional(GuidanceFieldsSchema)
1077
+ },
1078
+ { additionalProperties: true }
1079
+ );
1080
+ var GitHubInterceptorOptionsSchema = typebox_exports.Object(
1081
+ {
1082
+ enabled: typebox_exports.Optional(typebox_exports.Boolean()),
1083
+ maxRepoSizeMB: typebox_exports.Optional(typebox_exports.Number()),
1084
+ cloneTimeoutSeconds: typebox_exports.Optional(typebox_exports.Number()),
1085
+ clonePath: typebox_exports.Optional(typebox_exports.String())
1086
+ },
1087
+ { additionalProperties: true }
1088
+ );
1089
+ var InterceptorsConfigSchema = typebox_exports.Object(
1090
+ {
1091
+ // Boolean shorthand or per-field overrides. `enabled: false` inside the
1092
+ // object form is allowed but redundant — use the top-level `false`.
1093
+ github: typebox_exports.Optional(typebox_exports.Union([typebox_exports.Boolean(), GitHubInterceptorOptionsSchema]))
1094
+ },
1095
+ { additionalProperties: true }
1096
+ );
1097
+ var WebToolsConfigSchema = typebox_exports.Object(
1098
+ {
1099
+ provider: typebox_exports.Optional(typebox_exports.String()),
1100
+ apiKeys: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), typebox_exports.String())),
1101
+ baseUrls: typebox_exports.Optional(typebox_exports.Record(typebox_exports.String(), typebox_exports.String())),
1102
+ // Legacy top-level Brave key. Auto-migrated to `apiKeys.brave` by the
1103
+ // /web-tools save path — kept here for the load+rewrite round-trip.
1104
+ apiKey: typebox_exports.Optional(typebox_exports.String()),
1105
+ guidance: typebox_exports.Optional(WebToolsGuidanceSchema),
1106
+ interceptors: typebox_exports.Optional(InterceptorsConfigSchema)
1107
+ },
1108
+ { additionalProperties: true }
1109
+ );
1110
+ var CONFIG_PATH = configPath("rpiv-web-tools");
1111
+ function getConfigPath() {
1112
+ return CONFIG_PATH;
1113
+ }
1114
+ __name(getConfigPath, "getConfigPath");
1115
+ var pointerSegments = /* @__PURE__ */ __name((instancePath) => instancePath === "" ? [] : instancePath.split("/").slice(1).map((s) => s.replaceAll("~1", "/").replaceAll("~0", "~")), "pointerSegments");
1116
+ var deleteAtPointer = /* @__PURE__ */ __name((root, segs) => {
1117
+ let parent = root;
1118
+ for (let i = 0; i < segs.length - 1; i++) {
1119
+ const next = parent[segs[i]];
1120
+ if (next === null || typeof next !== "object") return false;
1121
+ if (Array.isArray(next)) {
1122
+ delete parent[segs[i]];
1123
+ return true;
1124
+ }
1125
+ parent = next;
1126
+ }
1127
+ const leaf = segs[segs.length - 1];
1128
+ if (!(leaf in parent)) return false;
1129
+ delete parent[leaf];
1130
+ return true;
1131
+ }, "deleteAtPointer");
1132
+ var salvageConfig = /* @__PURE__ */ __name((raw) => {
1133
+ const cfg = structuredClone(raw);
1134
+ for (let pass = 0; pass < 5; pass++) {
1135
+ const errors = [...value_exports.Errors(WebToolsConfigSchema, cfg)];
1136
+ if (errors.length === 0) return cfg;
1137
+ let deleted = false;
1138
+ for (const e of errors) {
1139
+ const segs = pointerSegments(e.instancePath);
1140
+ if (segs.length === 0) return void 0;
1141
+ if (deleteAtPointer(cfg, segs)) deleted = true;
1142
+ }
1143
+ if (!deleted) return void 0;
1144
+ }
1145
+ return value_exports.Check(WebToolsConfigSchema, cfg) ? cfg : void 0;
1146
+ }, "salvageConfig");
1147
+ function readConfig() {
1148
+ const raw = loadJsonConfigWithLegacyFallback("rpiv-web-tools");
1149
+ if (value_exports.Check(WebToolsConfigSchema, raw)) return raw;
1150
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return {};
1151
+ return salvageConfig(raw) ?? {};
1152
+ }
1153
+ __name(readConfig, "readConfig");
1154
+ function writeConfig(c) {
1155
+ return saveJsonConfig(CONFIG_PATH, c);
1156
+ }
1157
+ __name(writeConfig, "writeConfig");
1158
+
1159
+ // node_modules/@juicesharp/rpiv-web-tools/providers/interceptors/github.ts?ext=privateer-web
1160
+ var GITHUB_TOKEN_ENV_VAR = "GITHUB_TOKEN";
1161
+ var MAX_TREE_ENTRIES = 200;
1162
+ var MAX_INLINE_FILE_CHARS = 1e5;
1163
+ var BINARY_EXTENSIONS = /* @__PURE__ */ new Set([
1164
+ ".png",
1165
+ ".jpg",
1166
+ ".jpeg",
1167
+ ".gif",
1168
+ ".bmp",
1169
+ ".ico",
1170
+ ".webp",
1171
+ ".svg",
1172
+ ".tiff",
1173
+ ".tif",
1174
+ ".mp3",
1175
+ ".mp4",
1176
+ ".avi",
1177
+ ".mov",
1178
+ ".mkv",
1179
+ ".flv",
1180
+ ".wmv",
1181
+ ".wav",
1182
+ ".ogg",
1183
+ ".webm",
1184
+ ".flac",
1185
+ ".aac",
1186
+ ".zip",
1187
+ ".tar",
1188
+ ".gz",
1189
+ ".bz2",
1190
+ ".xz",
1191
+ ".7z",
1192
+ ".rar",
1193
+ ".zst",
1194
+ ".exe",
1195
+ ".dll",
1196
+ ".so",
1197
+ ".dylib",
1198
+ ".bin",
1199
+ ".o",
1200
+ ".a",
1201
+ ".lib",
1202
+ ".woff",
1203
+ ".woff2",
1204
+ ".ttf",
1205
+ ".otf",
1206
+ ".eot",
1207
+ ".pdf",
1208
+ ".doc",
1209
+ ".docx",
1210
+ ".xls",
1211
+ ".xlsx",
1212
+ ".ppt",
1213
+ ".pptx",
1214
+ ".sqlite",
1215
+ ".db",
1216
+ ".sqlite3",
1217
+ ".pyc",
1218
+ ".pyo",
1219
+ ".class",
1220
+ ".jar",
1221
+ ".war",
1222
+ ".iso",
1223
+ ".img",
1224
+ ".dmg"
1225
+ ]);
1226
+ var NOISE_DIRS = /* @__PURE__ */ new Set([
1227
+ "node_modules",
1228
+ "vendor",
1229
+ ".next",
1230
+ "dist",
1231
+ "build",
1232
+ "__pycache__",
1233
+ ".venv",
1234
+ "venv",
1235
+ ".tox",
1236
+ ".mypy_cache",
1237
+ ".pytest_cache",
1238
+ "target",
1239
+ ".gradle",
1240
+ ".idea",
1241
+ ".vscode"
1242
+ ]);
1243
+ var NON_CODE_SEGMENTS = /* @__PURE__ */ new Set([
1244
+ "issues",
1245
+ "pull",
1246
+ "pulls",
1247
+ "discussions",
1248
+ "releases",
1249
+ "wiki",
1250
+ "actions",
1251
+ "settings",
1252
+ "security",
1253
+ "projects",
1254
+ "graphs",
1255
+ "compare",
1256
+ "commits",
1257
+ "tags",
1258
+ "branches",
1259
+ "stargazers",
1260
+ "watchers",
1261
+ "network",
1262
+ "forks",
1263
+ "milestone",
1264
+ "labels",
1265
+ "packages",
1266
+ "codespaces",
1267
+ "contribute",
1268
+ "community",
1269
+ "sponsors",
1270
+ "invitations",
1271
+ "notifications",
1272
+ "insights"
1273
+ ]);
1274
+ function parseGitHubUrl(url) {
1275
+ let parsed;
1276
+ try {
1277
+ parsed = new URL(url);
1278
+ } catch {
1279
+ return null;
1280
+ }
1281
+ const host = parsed.hostname.toLowerCase();
1282
+ if (host !== "github.com" && host !== "www.github.com") return null;
1283
+ const segments = parsed.pathname.split("/").filter(Boolean).map((segment) => {
1284
+ try {
1285
+ return decodeURIComponent(segment);
1286
+ } catch {
1287
+ return segment;
1288
+ }
1289
+ });
1290
+ if (segments.length < 2) return null;
1291
+ const owner = segments[0];
1292
+ const repo = segments[1].replace(/\.git$/, "");
1293
+ if (NON_CODE_SEGMENTS.has(segments[2]?.toLowerCase())) return null;
1294
+ if (segments.length === 2) {
1295
+ return { owner, repo, refIsFullSha: false, type: "root" };
1296
+ }
1297
+ const action = segments[2];
1298
+ if (action !== "blob" && action !== "tree") return null;
1299
+ if (segments.length < 4) return null;
1300
+ const ref = segments[3];
1301
+ const refIsFullSha = /^[0-9a-f]{40}$/.test(ref);
1302
+ const pathParts = segments.slice(4);
1303
+ const path = pathParts.length > 0 ? pathParts.join("/") : "";
1304
+ return { owner, repo, ref, refIsFullSha, path, type: action };
1305
+ }
1306
+ __name(parseGitHubUrl, "parseGitHubUrl");
1307
+ var DEFAULTS = {
1308
+ enabled: false,
1309
+ maxRepoSizeMB: 350,
1310
+ cloneTimeoutSeconds: 30,
1311
+ clonePath: join2(tmpdir(), "pi-github-repos")
1312
+ };
1313
+ function resolveGitHubOptions(userConfig, consumerDefault) {
1314
+ if (userConfig === false) return { ...DEFAULTS, enabled: false };
1315
+ if (userConfig === true) return { ...DEFAULTS, enabled: true };
1316
+ if (userConfig && typeof userConfig === "object") {
1317
+ const enabled = userConfig.enabled ?? true;
1318
+ return {
1319
+ enabled,
1320
+ maxRepoSizeMB: userConfig.maxRepoSizeMB ?? DEFAULTS.maxRepoSizeMB,
1321
+ cloneTimeoutSeconds: userConfig.cloneTimeoutSeconds ?? DEFAULTS.cloneTimeoutSeconds,
1322
+ clonePath: userConfig.clonePath ?? DEFAULTS.clonePath
1323
+ };
1324
+ }
1325
+ if (consumerDefault === true) return { ...DEFAULTS, enabled: true };
1326
+ return { ...DEFAULTS };
1327
+ }
1328
+ __name(resolveGitHubOptions, "resolveGitHubOptions");
1329
+ function readUserGitHubConfig() {
1330
+ return readConfig().interceptors?.github;
1331
+ }
1332
+ __name(readUserGitHubConfig, "readUserGitHubConfig");
1333
+ function cacheKey(owner, repo, ref) {
1334
+ return ref ? `${owner}/${repo}@${ref}` : `${owner}/${repo}`;
1335
+ }
1336
+ __name(cacheKey, "cacheKey");
1337
+ function cloneDir(clonePath, owner, repo, ref) {
1338
+ const dirName = ref ? `${repo}@${ref}` : repo;
1339
+ return join2(clonePath, owner, dirName);
1340
+ }
1341
+ __name(cloneDir, "cloneDir");
1342
+ var GitHubInterceptor = class {
1343
+ static {
1344
+ __name(this, "GitHubInterceptor");
1345
+ }
1346
+ name = "github";
1347
+ options;
1348
+ ghAvailable = null;
1349
+ ghHintShown = false;
1350
+ cloneCache;
1351
+ constructor(opts = {}) {
1352
+ const { cloneCache, ...rest } = opts;
1353
+ this.options = resolveGitHubOptions(rest, void 0);
1354
+ this.cloneCache = cloneCache ?? /* @__PURE__ */ new Map();
1355
+ }
1356
+ get resolvedOptions() {
1357
+ return this.options;
1358
+ }
1359
+ async intercept(url, opts) {
1360
+ return this.fetchGitHub(url, opts.signal, opts.forceClone);
1361
+ }
1362
+ /** @internal — exposed for direct unit testing of the gh-availability probe. */
1363
+ async checkGhAvailable() {
1364
+ if (this.ghAvailable !== null) return this.ghAvailable;
1365
+ return new Promise((resolve) => {
1366
+ execFile("gh", ["--version"], { timeout: 5e3 }, (err) => {
1367
+ this.ghAvailable = !err;
1368
+ resolve(this.ghAvailable);
1369
+ });
1370
+ });
1371
+ }
1372
+ /** @internal — exposed for direct unit testing of the repo-size probe. */
1373
+ async checkRepoSize(owner, repo) {
1374
+ if (!await this.checkGhAvailable()) return null;
1375
+ return new Promise((resolve) => {
1376
+ execFile("gh", ["api", `repos/${owner}/${repo}`, "--jq", ".size"], { timeout: 1e4 }, (err, stdout) => {
1377
+ if (err) {
1378
+ resolve(null);
1379
+ return;
1380
+ }
1381
+ const kb = parseInt(stdout.trim(), 10);
1382
+ resolve(Number.isNaN(kb) ? null : kb);
1383
+ });
1384
+ });
1385
+ }
1386
+ /**
1387
+ * Injects an entry into the clone cache — for testing generateCloneContent
1388
+ * without running a real git clone. Never call in production.
1389
+ * @internal
1390
+ */
1391
+ _seedCache(key, entry) {
1392
+ this.cloneCache.set(key, entry);
1393
+ }
1394
+ /**
1395
+ * Clears the in-memory clone cache and removes all cloned directories.
1396
+ * Also resets the gh-availability probe so the next intercept re-checks.
1397
+ * @internal
1398
+ */
1399
+ reset() {
1400
+ for (const entry of this.cloneCache.values()) {
1401
+ try {
1402
+ rmSync(entry.localPath, { recursive: true, force: true });
1403
+ } catch {
1404
+ }
1405
+ }
1406
+ this.cloneCache.clear();
1407
+ this.ghAvailable = null;
1408
+ this.ghHintShown = false;
1409
+ }
1410
+ showGhHint() {
1411
+ if (!this.ghHintShown) {
1412
+ this.ghHintShown = true;
1413
+ console.error("[rpiv-web-tools] Install `gh` CLI for better GitHub repo access including private repos.");
1414
+ }
1415
+ }
1416
+ async getDefaultBranch(owner, repo) {
1417
+ if (!await this.checkGhAvailable()) return null;
1418
+ return new Promise((resolve) => {
1419
+ execFile(
1420
+ "gh",
1421
+ ["api", `repos/${owner}/${repo}`, "--jq", ".default_branch"],
1422
+ { timeout: 1e4 },
1423
+ (err, stdout) => {
1424
+ if (err) {
1425
+ resolve(null);
1426
+ return;
1427
+ }
1428
+ resolve(stdout.trim() || null);
1429
+ }
1430
+ );
1431
+ });
1432
+ }
1433
+ async fetchTreeViaApi(owner, repo, ref) {
1434
+ if (!await this.checkGhAvailable()) return null;
1435
+ return new Promise((resolve) => {
1436
+ execFile(
1437
+ "gh",
1438
+ ["api", `repos/${owner}/${repo}/git/trees/${ref}?recursive=1`, "--jq", ".tree[].path"],
1439
+ { timeout: 15e3, maxBuffer: 5 * 1024 * 1024 },
1440
+ (err, stdout) => {
1441
+ if (err) {
1442
+ resolve(null);
1443
+ return;
1444
+ }
1445
+ const paths = stdout.trim().split("\n").filter(Boolean);
1446
+ if (paths.length === 0) {
1447
+ resolve(null);
1448
+ return;
1449
+ }
1450
+ const truncated = paths.length > MAX_TREE_ENTRIES;
1451
+ const display = paths.slice(0, MAX_TREE_ENTRIES).join("\n");
1452
+ resolve(truncated ? `${display}
1453
+ ... (${paths.length} total entries)` : display);
1454
+ }
1455
+ );
1456
+ });
1457
+ }
1458
+ async fetchReadmeViaApi(owner, repo, ref) {
1459
+ if (!await this.checkGhAvailable()) return null;
1460
+ return new Promise((resolve) => {
1461
+ execFile(
1462
+ "gh",
1463
+ ["api", `repos/${owner}/${repo}/readme?ref=${ref}`, "--jq", ".content"],
1464
+ { timeout: 1e4 },
1465
+ (err, stdout) => {
1466
+ if (err) {
1467
+ resolve(null);
1468
+ return;
1469
+ }
1470
+ try {
1471
+ const decoded = Buffer.from(stdout.trim(), "base64").toString("utf-8");
1472
+ resolve(
1473
+ decoded.length > 8192 ? `${decoded.slice(0, 8192)}
1474
+
1475
+ [README truncated at 8K chars]` : decoded
1476
+ );
1477
+ } catch {
1478
+ resolve(null);
1479
+ }
1480
+ }
1481
+ );
1482
+ });
1483
+ }
1484
+ async fetchFileViaApi(owner, repo, path, ref) {
1485
+ if (!await this.checkGhAvailable()) return null;
1486
+ return new Promise((resolve) => {
1487
+ execFile(
1488
+ "gh",
1489
+ ["api", `repos/${owner}/${repo}/contents/${path}?ref=${ref}`, "--jq", ".content"],
1490
+ { timeout: 1e4, maxBuffer: 2 * 1024 * 1024 },
1491
+ (err, stdout) => {
1492
+ if (err) {
1493
+ resolve(null);
1494
+ return;
1495
+ }
1496
+ try {
1497
+ resolve(Buffer.from(stdout.trim(), "base64").toString("utf-8"));
1498
+ } catch {
1499
+ resolve(null);
1500
+ }
1501
+ }
1502
+ );
1503
+ });
1504
+ }
1505
+ async fetchViaApi(_url, owner, repo, info, sizeNote) {
1506
+ const ref = info.ref || await this.getDefaultBranch(owner, repo);
1507
+ if (!ref) return null;
1508
+ const lines = [];
1509
+ if (sizeNote) {
1510
+ lines.push(sizeNote);
1511
+ lines.push("");
1512
+ }
1513
+ if (info.type === "blob" && info.path) {
1514
+ const content = await this.fetchFileViaApi(owner, repo, info.path, ref);
1515
+ if (!content) return null;
1516
+ lines.push(`## ${info.path}`);
1517
+ if (content.length > MAX_INLINE_FILE_CHARS) {
1518
+ lines.push(content.slice(0, MAX_INLINE_FILE_CHARS));
1519
+ lines.push("\n[File truncated at 100K chars]");
1520
+ } else {
1521
+ lines.push(content);
1522
+ }
1523
+ const title2 = `${owner}/${repo} - ${info.path}`;
1524
+ return { text: lines.join("\n"), title: title2, contentType: "text/plain" };
1525
+ }
1526
+ const [tree, readme] = await Promise.all([
1527
+ this.fetchTreeViaApi(owner, repo, ref),
1528
+ this.fetchReadmeViaApi(owner, repo, ref)
1529
+ ]);
1530
+ if (!tree && !readme) return null;
1531
+ if (tree) {
1532
+ lines.push("## Structure");
1533
+ lines.push(tree);
1534
+ lines.push("");
1535
+ }
1536
+ if (readme) {
1537
+ lines.push("## README.md");
1538
+ lines.push(readme);
1539
+ lines.push("");
1540
+ }
1541
+ lines.push("This is an API-only view. Clone the repo or use `read`/`bash` for deeper exploration.");
1542
+ const title = info.path ? `${owner}/${repo} - ${info.path}` : `${owner}/${repo}`;
1543
+ return { text: lines.join("\n"), title, contentType: "text/plain" };
1544
+ }
1545
+ execClone(args, localPath, timeoutMs, signal) {
1546
+ return new Promise((resolve) => {
1547
+ const child = execFile(args[0], args.slice(1), { timeout: timeoutMs }, (err) => {
1548
+ if (err) {
1549
+ try {
1550
+ rmSync(localPath, { recursive: true, force: true });
1551
+ } catch {
1552
+ }
1553
+ resolve(null);
1554
+ return;
1555
+ }
1556
+ resolve(localPath);
1557
+ });
1558
+ if (signal) {
1559
+ const onAbort = /* @__PURE__ */ __name(() => child.kill(), "onAbort");
1560
+ signal.addEventListener("abort", onAbort, { once: true });
1561
+ child.on("exit", () => signal.removeEventListener("abort", onAbort));
1562
+ }
1563
+ });
1564
+ }
1565
+ async cloneRepo(owner, repo, ref, signal) {
1566
+ const localPath = cloneDir(this.options.clonePath, owner, repo, ref);
1567
+ try {
1568
+ rmSync(localPath, { recursive: true, force: true });
1569
+ } catch {
1570
+ }
1571
+ const timeoutMs = this.options.cloneTimeoutSeconds * 1e3;
1572
+ const hasGh = await this.checkGhAvailable();
1573
+ if (hasGh) {
1574
+ const args2 = ["gh", "repo", "clone", `${owner}/${repo}`, localPath, "--", "--depth", "1", "--single-branch"];
1575
+ if (ref) args2.push("--branch", ref);
1576
+ return this.execClone(args2, localPath, timeoutMs, signal);
1577
+ }
1578
+ this.showGhHint();
1579
+ const gitUrl = `https://github.com/${owner}/${repo}.git`;
1580
+ const args = ["git", "clone", "--depth", "1", "--single-branch"];
1581
+ if (ref) args.push("--branch", ref);
1582
+ args.push(gitUrl, localPath);
1583
+ return this.execClone(args, localPath, timeoutMs, signal);
1584
+ }
1585
+ async awaitCachedClone(cached, url, owner, repo, info, signal) {
1586
+ if (signal?.aborted) return null;
1587
+ const result = await cached.clonePromise;
1588
+ if (signal?.aborted) return null;
1589
+ if (result) {
1590
+ const text = generateCloneContent(result, info);
1591
+ const title = info.path ? `${owner}/${repo} - ${info.path}` : `${owner}/${repo}`;
1592
+ return { text, title, contentType: "text/plain" };
1593
+ }
1594
+ return this.fetchViaApi(url, owner, repo, info);
1595
+ }
1596
+ async fetchGitHub(url, signal, forceClone) {
1597
+ const info = parseGitHubUrl(url);
1598
+ if (!info) return null;
1599
+ if (signal?.aborted) return null;
1600
+ if (!this.options.enabled) return null;
1601
+ const { owner, repo } = info;
1602
+ const key = cacheKey(owner, repo, info.ref);
1603
+ const cached = this.cloneCache.get(key);
1604
+ if (cached) return this.awaitCachedClone(cached, url, owner, repo, info, signal);
1605
+ if (info.refIsFullSha) {
1606
+ if (signal?.aborted) return null;
1607
+ const sizeNote = "Note: Commit SHA URLs use the GitHub API instead of cloning.";
1608
+ return this.fetchViaApi(url, owner, repo, info, sizeNote);
1609
+ }
1610
+ if (!forceClone) {
1611
+ const sizeKB = await this.checkRepoSize(owner, repo);
1612
+ if (signal?.aborted) return null;
1613
+ if (sizeKB !== null) {
1614
+ const sizeMB = sizeKB / 1024;
1615
+ if (sizeMB > this.options.maxRepoSizeMB) {
1616
+ if (signal?.aborted) return null;
1617
+ const sizeNote = `Note: Repository is ${Math.round(sizeMB)}MB (threshold: ${this.options.maxRepoSizeMB}MB). Showing API-fetched content instead of full clone. Ask the user if they'd like to clone the full repo \u2014 if yes, call web_fetch again with the same URL.`;
1618
+ const apiView = await this.fetchViaApi(url, owner, repo, info, sizeNote);
1619
+ if (apiView) return apiView;
1620
+ return null;
1621
+ }
1622
+ }
1623
+ }
1624
+ if (signal?.aborted) return null;
1625
+ const cachedAfterCheck = this.cloneCache.get(key);
1626
+ if (cachedAfterCheck) return this.awaitCachedClone(cachedAfterCheck, url, owner, repo, info, signal);
1627
+ const clonePromise = this.cloneRepo(owner, repo, info.ref, signal);
1628
+ const localPath = cloneDir(this.options.clonePath, owner, repo, info.ref);
1629
+ this.cloneCache.set(key, { localPath, clonePromise });
1630
+ const result = await clonePromise;
1631
+ if (signal?.aborted) {
1632
+ if (!result) this.cloneCache.delete(key);
1633
+ return null;
1634
+ }
1635
+ if (!result) {
1636
+ this.cloneCache.delete(key);
1637
+ if (signal?.aborted) return null;
1638
+ return this.fetchViaApi(url, owner, repo, info);
1639
+ }
1640
+ const text = generateCloneContent(result, info);
1641
+ const title = info.path ? `${owner}/${repo} - ${info.path}` : `${owner}/${repo}`;
1642
+ return { text, title, contentType: "text/plain" };
1643
+ }
1644
+ };
1645
+ function isBinaryFile(filePath) {
1646
+ const ext = extname(filePath).toLowerCase();
1647
+ if (BINARY_EXTENSIONS.has(ext)) return true;
1648
+ let fd;
1649
+ try {
1650
+ fd = openSync(filePath, "r");
1651
+ } catch {
1652
+ return false;
1653
+ }
1654
+ try {
1655
+ const buf = Buffer.alloc(512);
1656
+ const bytesRead = readSync(fd, buf, 0, 512, 0);
1657
+ for (let i = 0; i < bytesRead; i++) {
1658
+ if (buf[i] === 0) return true;
1659
+ }
1660
+ } catch {
1661
+ return false;
1662
+ } finally {
1663
+ closeSync(fd);
1664
+ }
1665
+ return false;
1666
+ }
1667
+ __name(isBinaryFile, "isBinaryFile");
1668
+ function formatFileSize(bytes) {
1669
+ if (bytes < 1024) return `${bytes} B`;
1670
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
1671
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
1672
+ }
1673
+ __name(formatFileSize, "formatFileSize");
1674
+ function resolveWithinRepo(rootPath, relativePath) {
1675
+ const normalizedRoot = resolvePath(rootPath);
1676
+ const candidate = resolvePath(normalizedRoot, relativePath);
1677
+ if (candidate !== normalizedRoot) {
1678
+ const rootPrefix = normalizedRoot.endsWith(pathSep) ? normalizedRoot : normalizedRoot + pathSep;
1679
+ if (!candidate.startsWith(rootPrefix)) return null;
1680
+ }
1681
+ if (!existsSync2(candidate)) return candidate;
1682
+ try {
1683
+ const realRoot = realpathSync(normalizedRoot);
1684
+ const realCandidate = realpathSync(candidate);
1685
+ if (realCandidate === realRoot) return candidate;
1686
+ const realRootPrefix = realRoot.endsWith(pathSep) ? realRoot : realRoot + pathSep;
1687
+ return realCandidate.startsWith(realRootPrefix) ? candidate : null;
1688
+ } catch {
1689
+ return null;
1690
+ }
1691
+ }
1692
+ __name(resolveWithinRepo, "resolveWithinRepo");
1693
+ function buildTree(rootPath) {
1694
+ const entries = [];
1695
+ function walk(dir, relPath) {
1696
+ if (entries.length >= MAX_TREE_ENTRIES) return;
1697
+ let items;
1698
+ try {
1699
+ items = readdirSync(dir).sort();
1700
+ } catch {
1701
+ return;
1702
+ }
1703
+ for (const item of items) {
1704
+ if (entries.length >= MAX_TREE_ENTRIES) return;
1705
+ if (item === ".git") continue;
1706
+ const rel = relPath ? `${relPath}/${item}` : item;
1707
+ const safePath = resolveWithinRepo(rootPath, rel);
1708
+ if (!safePath) {
1709
+ entries.push(`${rel} [outside repo skipped]`);
1710
+ continue;
1711
+ }
1712
+ let stat;
1713
+ try {
1714
+ stat = statSync(safePath);
1715
+ } catch {
1716
+ continue;
1717
+ }
1718
+ if (stat.isDirectory()) {
1719
+ if (NOISE_DIRS.has(item)) {
1720
+ entries.push(`${rel}/ [skipped]`);
1721
+ continue;
1722
+ }
1723
+ entries.push(`${rel}/`);
1724
+ walk(safePath, rel);
1725
+ } else {
1726
+ entries.push(rel);
1727
+ }
1728
+ }
1729
+ }
1730
+ __name(walk, "walk");
1731
+ walk(rootPath, "");
1732
+ if (entries.length >= MAX_TREE_ENTRIES) {
1733
+ entries.push(`... (truncated at ${MAX_TREE_ENTRIES} entries)`);
1734
+ }
1735
+ return entries.join("\n");
1736
+ }
1737
+ __name(buildTree, "buildTree");
1738
+ function buildDirListing(rootPath, subPath) {
1739
+ const targetPath = resolveWithinRepo(rootPath, subPath);
1740
+ if (!targetPath) return "(path escapes repository root)";
1741
+ const lines = [];
1742
+ let items;
1743
+ try {
1744
+ items = readdirSync(targetPath).sort();
1745
+ } catch {
1746
+ return "(directory not readable)";
1747
+ }
1748
+ for (const item of items) {
1749
+ if (item === ".git") continue;
1750
+ const rel = subPath ? `${subPath}/${item}` : item;
1751
+ const safePath = resolveWithinRepo(rootPath, rel);
1752
+ if (!safePath) {
1753
+ lines.push(` ${item} (outside repo)`);
1754
+ continue;
1755
+ }
1756
+ try {
1757
+ const stat = statSync(safePath);
1758
+ lines.push(stat.isDirectory() ? ` ${item}/` : ` ${item} (${formatFileSize(stat.size)})`);
1759
+ } catch {
1760
+ lines.push(` ${item} (unreadable)`);
1761
+ }
1762
+ }
1763
+ return lines.join("\n");
1764
+ }
1765
+ __name(buildDirListing, "buildDirListing");
1766
+ function readReadme(localPath) {
1767
+ const candidates = ["README.md", "readme.md", "README", "README.txt", "README.rst"];
1768
+ for (const name of candidates) {
1769
+ const readmePath = join2(localPath, name);
1770
+ if (existsSync2(readmePath)) {
1771
+ try {
1772
+ const content = readFileSync2(readmePath, "utf-8");
1773
+ return content.length > 8192 ? `${content.slice(0, 8192)}
1774
+
1775
+ [README truncated at 8K chars]` : content;
1776
+ } catch {
1777
+ }
1778
+ }
1779
+ }
1780
+ return null;
1781
+ }
1782
+ __name(readReadme, "readReadme");
1783
+ function generateCloneContent(localPath, info) {
1784
+ const lines = [];
1785
+ lines.push(`Repository cloned to: ${localPath}`);
1786
+ lines.push("");
1787
+ if (info.type === "root") {
1788
+ lines.push("## Structure");
1789
+ lines.push(buildTree(localPath));
1790
+ lines.push("");
1791
+ const readme = readReadme(localPath);
1792
+ if (readme) {
1793
+ lines.push("## README.md");
1794
+ lines.push(readme);
1795
+ lines.push("");
1796
+ }
1797
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1798
+ return lines.join("\n");
1799
+ }
1800
+ if (info.type === "tree") {
1801
+ const dirPath = info.path || "";
1802
+ const fullDirPath = resolveWithinRepo(localPath, dirPath);
1803
+ if (!fullDirPath || !existsSync2(fullDirPath)) {
1804
+ lines.push(`Path \`${dirPath}\` not found in clone. Showing repository root instead.`);
1805
+ lines.push("");
1806
+ lines.push("## Structure");
1807
+ lines.push(buildTree(localPath));
1808
+ } else {
1809
+ lines.push(`## ${dirPath || "/"}`);
1810
+ lines.push(buildDirListing(localPath, dirPath));
1811
+ }
1812
+ lines.push("");
1813
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1814
+ return lines.join("\n");
1815
+ }
1816
+ const filePath = info.path || "";
1817
+ const fullFilePath = resolveWithinRepo(localPath, filePath);
1818
+ if (!fullFilePath || !existsSync2(fullFilePath)) {
1819
+ lines.push(`Path \`${filePath}\` not found in clone. Showing repository root instead.`);
1820
+ lines.push("");
1821
+ lines.push("## Structure");
1822
+ lines.push(buildTree(localPath));
1823
+ lines.push("");
1824
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1825
+ return lines.join("\n");
1826
+ }
1827
+ let stat;
1828
+ try {
1829
+ stat = statSync(fullFilePath);
1830
+ } catch (err) {
1831
+ const message = err instanceof Error ? err.message : String(err);
1832
+ lines.push(`Could not inspect \`${filePath}\`: ${message}`);
1833
+ lines.push("");
1834
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1835
+ return lines.join("\n");
1836
+ }
1837
+ if (stat.isDirectory()) {
1838
+ lines.push(`## ${filePath || "/"}`);
1839
+ lines.push(buildDirListing(localPath, filePath));
1840
+ lines.push("");
1841
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1842
+ return lines.join("\n");
1843
+ }
1844
+ if (isBinaryFile(fullFilePath)) {
1845
+ const ext = extname(filePath).replace(".", "");
1846
+ lines.push(`## ${filePath}`);
1847
+ lines.push(
1848
+ `Binary file (${ext}, ${formatFileSize(stat.size)}). Use \`read\` or \`bash\` tools at the path above to inspect.`
1849
+ );
1850
+ return lines.join("\n");
1851
+ }
1852
+ let content;
1853
+ try {
1854
+ content = readFileSync2(fullFilePath, "utf-8");
1855
+ } catch {
1856
+ lines.push(`Could not read \`${filePath}\` as UTF-8 text.`);
1857
+ lines.push("");
1858
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1859
+ return lines.join("\n");
1860
+ }
1861
+ lines.push(`## ${filePath}`);
1862
+ if (content.length > MAX_INLINE_FILE_CHARS) {
1863
+ lines.push(content.slice(0, MAX_INLINE_FILE_CHARS));
1864
+ lines.push(`
1865
+ [File truncated at 100K chars. Full file: ${fullFilePath}]`);
1866
+ } else {
1867
+ lines.push(content);
1868
+ }
1869
+ lines.push("");
1870
+ lines.push("Use `read` and `bash` tools at the path above to explore further.");
1871
+ return lines.join("\n");
1872
+ }
1873
+ __name(generateCloneContent, "generateCloneContent");
1874
+
1875
+ // node_modules/@juicesharp/rpiv-web-tools/providers/interceptors/index.ts?ext=privateer-web
1876
+ var activeInterceptors = [];
1877
+ var activeGitHubInterceptor = null;
1878
+ function buildInterceptors(consumer) {
1879
+ const userCfg = readUserGitHubConfig();
1880
+ const resolved = resolveGitHubOptions(userCfg, consumer?.github);
1881
+ if (resolved.enabled) {
1882
+ activeGitHubInterceptor = new GitHubInterceptor(resolved);
1883
+ activeInterceptors = [activeGitHubInterceptor];
1884
+ } else {
1885
+ activeGitHubInterceptor = null;
1886
+ activeInterceptors = [];
1887
+ }
1888
+ return activeInterceptors;
1889
+ }
1890
+ __name(buildInterceptors, "buildInterceptors");
1891
+ function getInterceptors() {
1892
+ return activeInterceptors;
1893
+ }
1894
+ __name(getInterceptors, "getInterceptors");
1895
+ function getActiveGitHubInterceptor() {
1896
+ return activeGitHubInterceptor;
1897
+ }
1898
+ __name(getActiveGitHubInterceptor, "getActiveGitHubInterceptor");
1899
+ function clearCloneCache() {
1900
+ activeGitHubInterceptor?.reset();
1901
+ }
1902
+ __name(clearCloneCache, "clearCloneCache");
1903
+
1904
+ // node_modules/@juicesharp/rpiv-web-tools/providers/index.ts?ext=privateer-web
1905
+ var PROVIDERS = [
1906
+ BRAVE_PROVIDER_META,
1907
+ TAVILY_PROVIDER_META,
1908
+ SERPER_PROVIDER_META,
1909
+ EXA_PROVIDER_META,
1910
+ YOUCOM_PROVIDER_META,
1911
+ JINA_PROVIDER_META,
1912
+ FIRECRAWL_PROVIDER_META,
1913
+ PERPLEXITY_PROVIDER_META,
1914
+ SEARXNG_PROVIDER_META,
1915
+ OLLAMA_PROVIDER_META
1916
+ ];
1917
+
1918
+ export {
1919
+ validateGuidanceFields,
1920
+ getConfigPath,
1921
+ readConfig,
1922
+ writeConfig,
1923
+ GITHUB_TOKEN_ENV_VAR,
1924
+ parseGitHubUrl,
1925
+ resolveGitHubOptions,
1926
+ GitHubInterceptor,
1927
+ buildInterceptors,
1928
+ getInterceptors,
1929
+ getActiveGitHubInterceptor,
1930
+ clearCloneCache,
1931
+ BRAVE_API_KEY_ENV_VAR,
1932
+ BRAVE_PROVIDER_META,
1933
+ BraveProvider,
1934
+ EXA_API_KEY_ENV_VAR,
1935
+ EXA_PROVIDER_META,
1936
+ ExaProvider,
1937
+ FIRECRAWL_API_KEY_ENV_VAR,
1938
+ FIRECRAWL_PROVIDER_META,
1939
+ FirecrawlProvider,
1940
+ JINA_API_KEY_ENV_VAR,
1941
+ JINA_PROVIDER_META,
1942
+ JinaProvider,
1943
+ OLLAMA_API_KEY_ENV_VAR,
1944
+ OLLAMA_HOST_ENV_VAR,
1945
+ OLLAMA_DEFAULT_URL,
1946
+ OLLAMA_PROVIDER_META,
1947
+ OllamaProvider,
1948
+ configureOllama,
1949
+ PERPLEXITY_API_KEY_ENV_VAR,
1950
+ PERPLEXITY_PROVIDER_META,
1951
+ PerplexityProvider,
1952
+ SEARXNG_API_KEY_ENV_VAR,
1953
+ SEARXNG_URL_ENV_VAR,
1954
+ SEARXNG_DEFAULT_URL,
1955
+ SEARXNG_PROVIDER_META,
1956
+ SearxngProvider,
1957
+ configureSearxng,
1958
+ SERPER_API_KEY_ENV_VAR,
1959
+ SERPER_PROVIDER_META,
1960
+ SerperProvider,
1961
+ TAVILY_API_KEY_ENV_VAR,
1962
+ TAVILY_PROVIDER_META,
1963
+ TavilyProvider,
1964
+ YOUCOM_API_KEY_ENV_VAR,
1965
+ YOUCOM_PROVIDER_META,
1966
+ YouComProvider,
1967
+ createSearchProvider,
1968
+ PROVIDERS
1969
+ };