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,717 @@
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
+ GITHUB_TOKEN_ENV_VAR,
4
+ GitHubInterceptor,
5
+ PROVIDERS,
6
+ buildInterceptors,
7
+ createSearchProvider,
8
+ getActiveGitHubInterceptor,
9
+ getConfigPath,
10
+ getInterceptors,
11
+ parseGitHubUrl,
12
+ readConfig,
13
+ resolveGitHubOptions,
14
+ validateGuidanceFields,
15
+ writeConfig
16
+ } from "./c-6FUXKHOK.mjs";
17
+ import "./c-B2Y7VNHU.mjs";
18
+ import "./c-SKMK3PEE.mjs";
19
+ import "./c-I54OKQHW.mjs";
20
+ import "./c-UPBH5AXY.mjs";
21
+ import {
22
+ DEFAULT_MAX_BYTES,
23
+ DEFAULT_MAX_LINES,
24
+ formatSize,
25
+ truncateHead
26
+ } from "./c-7UOG7POX.mjs";
27
+ import "./c-E4Z3Y5B5.mjs";
28
+ import "./c-6ZO2SADQ.mjs";
29
+ import "./c-JKTFXTGF.mjs";
30
+ import "./c-CRBXNKFO.mjs";
31
+ import "./c-KP6CRIP4.mjs";
32
+ import "./c-RSKCUPJF.mjs";
33
+ import "./c-PTN4S6G2.mjs";
34
+ import "./c-P6N5DQGZ.mjs";
35
+ import "./c-6LOBR4I6.mjs";
36
+ import "./c-3STKRSVO.mjs";
37
+ import "./c-YRDO2WEF.mjs";
38
+ import "./c-BHNIF2AR.mjs";
39
+ import "./c-ABXULAFL.mjs";
40
+ import "./c-2G3BBHRJ.mjs";
41
+ import "./c-O5PP6CTX.mjs";
42
+ import "./c-CDBEJSBF.mjs";
43
+ import "./c-DEE67DJO.mjs";
44
+ import "./c-WO3QSZUU.mjs";
45
+ import "./c-S2RVHR3M.mjs";
46
+ import {
47
+ Text
48
+ } from "./c-EQBKXWNX.mjs";
49
+ import {
50
+ typebox_exports
51
+ } from "./c-RQJJ26T4.mjs";
52
+ import "./c-L5GHWG5G.mjs";
53
+ import {
54
+ __name
55
+ } from "./c-CN77DCGF.mjs";
56
+
57
+ // node_modules/@juicesharp/rpiv-web-tools/web-tools.ts?ext=privateer-web
58
+ import { mkdtemp, writeFile } from "node:fs/promises";
59
+ import { tmpdir } from "node:os";
60
+ import { join } from "node:path";
61
+
62
+ // node_modules/@juicesharp/rpiv-web-tools/providers/fetch-helpers.ts?ext=privateer-web
63
+ var USER_AGENT = "Mozilla/5.0 (compatible; rpiv-pi/1.0)";
64
+ var FETCH_ACCEPT_HEADER = "text/html,application/xhtml+xml,application/xml;q=0.9,text/plain;q=0.8,*/*;q=0.5";
65
+ var BINARY_CONTENT_TYPE_PREFIXES = ["image/", "video/", "audio/"];
66
+ var HTML_CONTENT_TYPE_TOKEN = "text/html";
67
+ var SCRIPT_BLOCK_REGEX = /<script[\s\S]*?<\/script>/gi;
68
+ var STYLE_BLOCK_REGEX = /<style[\s\S]*?<\/style>/gi;
69
+ var NOSCRIPT_BLOCK_REGEX = /<noscript[\s\S]*?<\/noscript>/gi;
70
+ var BLOCK_CLOSER_REGEX = /<\/(p|div|h[1-6]|li|tr|br|blockquote|pre|section|article|header|footer|nav|details|summary)>/gi;
71
+ var SELF_CLOSING_BR_REGEX = /<br\s*\/?>/gi;
72
+ var ANY_REMAINING_TAG_REGEX = /<[^>]+>/g;
73
+ var TITLE_TAG_REGEX = /<title[^>]*>([\s\S]*?)<\/title>/i;
74
+ var NUMERIC_HTML_ENTITY_REGEX = /&#(\d+);/g;
75
+ var HORIZONTAL_WHITESPACE_RUN = /[ \t]+/g;
76
+ var BLANK_LINE_RUN = /\n{3,}/g;
77
+ function stripNonContentBlocks(html) {
78
+ return html.replace(SCRIPT_BLOCK_REGEX, "").replace(STYLE_BLOCK_REGEX, "").replace(NOSCRIPT_BLOCK_REGEX, "");
79
+ }
80
+ __name(stripNonContentBlocks, "stripNonContentBlocks");
81
+ function convertBlockTagsToNewlines(text) {
82
+ return text.replace(BLOCK_CLOSER_REGEX, "\n").replace(SELF_CLOSING_BR_REGEX, "\n");
83
+ }
84
+ __name(convertBlockTagsToNewlines, "convertBlockTagsToNewlines");
85
+ function stripRemainingTags(text) {
86
+ return text.replace(ANY_REMAINING_TAG_REGEX, " ");
87
+ }
88
+ __name(stripRemainingTags, "stripRemainingTags");
89
+ function decodeHtmlEntities(text) {
90
+ return text.replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&nbsp;/g, " ").replace(NUMERIC_HTML_ENTITY_REGEX, (_, code) => String.fromCharCode(Number(code)));
91
+ }
92
+ __name(decodeHtmlEntities, "decodeHtmlEntities");
93
+ function collapseWhitespace(text) {
94
+ return text.replace(HORIZONTAL_WHITESPACE_RUN, " ").replace(BLANK_LINE_RUN, "\n\n");
95
+ }
96
+ __name(collapseWhitespace, "collapseWhitespace");
97
+ function htmlToText(html) {
98
+ let text = stripNonContentBlocks(html);
99
+ text = convertBlockTagsToNewlines(text);
100
+ text = stripRemainingTags(text);
101
+ text = decodeHtmlEntities(text);
102
+ text = collapseWhitespace(text);
103
+ return text.trim();
104
+ }
105
+ __name(htmlToText, "htmlToText");
106
+ function extractTitle(html) {
107
+ const match = html.match(TITLE_TAG_REGEX);
108
+ if (!match) return void 0;
109
+ return match[1].replace(ANY_REMAINING_TAG_REGEX, "").trim() || void 0;
110
+ }
111
+ __name(extractTitle, "extractTitle");
112
+ function isHtmlContentType(contentType) {
113
+ return contentType.includes(HTML_CONTENT_TYPE_TOKEN);
114
+ }
115
+ __name(isHtmlContentType, "isHtmlContentType");
116
+ function assertTextContentType(contentType) {
117
+ if (BINARY_CONTENT_TYPE_PREFIXES.some((prefix) => contentType.includes(prefix))) {
118
+ throw new Error(`Unsupported content type: ${contentType}. web_fetch supports text pages only.`);
119
+ }
120
+ }
121
+ __name(assertTextContentType, "assertTextContentType");
122
+ function buildFetchRequestInit(signal) {
123
+ return {
124
+ signal,
125
+ redirect: "follow",
126
+ headers: { "User-Agent": USER_AGENT, Accept: FETCH_ACCEPT_HEADER }
127
+ };
128
+ }
129
+ __name(buildFetchRequestInit, "buildFetchRequestInit");
130
+ async function fetchUrlOrThrow(url, signal) {
131
+ const res = await fetch(url, buildFetchRequestInit(signal));
132
+ if (!res.ok) {
133
+ throw new Error(`HTTP ${res.status} ${res.statusText} for ${url}`);
134
+ }
135
+ return res;
136
+ }
137
+ __name(fetchUrlOrThrow, "fetchUrlOrThrow");
138
+ async function extractBodyAsText(res, contentType, raw) {
139
+ const body = await res.text();
140
+ if (!raw && isHtmlContentType(contentType)) {
141
+ return { text: htmlToText(body), title: extractTitle(body) };
142
+ }
143
+ return { text: body };
144
+ }
145
+ __name(extractBodyAsText, "extractBodyAsText");
146
+ async function fetchViaGenericHtml(url, raw, signal) {
147
+ const res = await fetchUrlOrThrow(url, signal);
148
+ const contentType = res.headers.get("content-type") ?? "";
149
+ assertTextContentType(contentType);
150
+ const { text, title } = await extractBodyAsText(res, contentType, raw);
151
+ const contentLengthHeader = res.headers.get("content-length");
152
+ return {
153
+ text,
154
+ title,
155
+ contentType: contentType || void 0,
156
+ contentLength: contentLengthHeader ? Number(contentLengthHeader) : void 0
157
+ };
158
+ }
159
+ __name(fetchViaGenericHtml, "fetchViaGenericHtml");
160
+
161
+ // node_modules/@juicesharp/rpiv-web-tools/web-tools.ts?ext=privateer-web
162
+ var MIN_SEARCH_RESULTS = 1;
163
+ var MAX_SEARCH_RESULTS = 10;
164
+ var DEFAULT_SEARCH_RESULTS = 5;
165
+ var SEARCH_RESULT_PREVIEW_LIMIT = 5;
166
+ var FETCH_PREVIEW_LINE_LIMIT = 15;
167
+ var API_KEY_MASK_VISIBLE_CHARS = 4;
168
+ var FETCH_TEMP_DIR_PREFIX = "rpiv-fetch-";
169
+ var FETCH_TEMP_FILE_NAME = "content.txt";
170
+ var CONFIG_PATH = getConfigPath();
171
+ var SUPPORTED_HTTP_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
172
+ var WEB_TOOLS_COMMAND_NAME = "web-tools";
173
+ var SHOW_FLAG = "--show";
174
+ var UNSET_LABEL = "(not set)";
175
+ var DEFAULT_PROVIDER_NAME = "brave";
176
+ var LEGACY_TOP_LEVEL_KEY_PROVIDER = "brave";
177
+ var loadConfig = readConfig;
178
+ var saveConfig = writeConfig;
179
+ var DEFAULT_WEB_SEARCH_SNIPPET = "Search the web for up-to-date information";
180
+ var DEFAULT_WEB_SEARCH_GUIDELINES = [
181
+ "Use web_search for information beyond your training data \u2014 recent events, current library versions, live API documentation.",
182
+ 'Use the current year from "Current date:" in your context when searching for recent information or documentation.',
183
+ 'After answering using search results, include a "Sources:" section listing relevant URLs as markdown hyperlinks: [Title](URL). Never skip this.',
184
+ "Domain filtering is supported to include or block specific websites.",
185
+ "If no API key is configured, ask the user to run /web-tools before proceeding."
186
+ ];
187
+ var DEFAULT_WEB_FETCH_SNIPPET = "Fetch and read content from a specific URL";
188
+ var DEFAULT_WEB_FETCH_GUIDELINES = [
189
+ "Use web_fetch to read the full content of a specific URL \u2014 documentation pages, blog posts, API references found via web_search.",
190
+ "web_fetch is complementary to web_search: search finds URLs, fetch reads them.",
191
+ 'After answering using fetched content, include a "Sources:" section with a markdown hyperlink to the fetched URL.',
192
+ "Large responses are truncated and spilled to a temp file \u2014 the temp path is reported in the result details."
193
+ ];
194
+ function resolveProviderApiKey(providerName, config) {
195
+ const meta = PROVIDERS.find((p) => p.name === providerName);
196
+ if (!meta) return void 0;
197
+ const envKey = meta.envVar ? process.env[meta.envVar]?.trim() : void 0;
198
+ if (envKey) return envKey;
199
+ const configKey = config.apiKeys?.[providerName]?.trim();
200
+ if (configKey) return configKey;
201
+ if (providerName === LEGACY_TOP_LEVEL_KEY_PROVIDER) {
202
+ return config.apiKey?.trim() || void 0;
203
+ }
204
+ return void 0;
205
+ }
206
+ __name(resolveProviderApiKey, "resolveProviderApiKey");
207
+ function resolveProviderBaseUrl(meta, config) {
208
+ if (!meta.baseUrlEnvVar) return "";
209
+ const envUrl = process.env[meta.baseUrlEnvVar]?.trim();
210
+ if (envUrl) return envUrl;
211
+ const configUrl = config.baseUrls?.[meta.name]?.trim();
212
+ if (configUrl) return configUrl;
213
+ return meta.defaultBaseUrl ?? "";
214
+ }
215
+ __name(resolveProviderBaseUrl, "resolveProviderBaseUrl");
216
+ var KNOWN_PROVIDER_NAMES = PROVIDERS.map((p) => p.name);
217
+ function isProviderConfigured(meta, config) {
218
+ if (meta.baseUrlEnvVar) {
219
+ return Boolean(process.env[meta.baseUrlEnvVar]?.trim() || config.baseUrls?.[meta.name]?.trim());
220
+ }
221
+ return resolveProviderApiKey(meta.name, config) !== void 0;
222
+ }
223
+ __name(isProviderConfigured, "isProviderConfigured");
224
+ function getVisibleProviderNames(config) {
225
+ const active = resolveActiveProviderName(config);
226
+ const configured = PROVIDERS.filter((meta) => isProviderConfigured(meta, config)).map((meta) => meta.name);
227
+ const names = configured.filter((name) => name !== active.name);
228
+ if (KNOWN_PROVIDER_NAMES.includes(active.name)) names.unshift(active.name);
229
+ if (names.length === 0) names.push(DEFAULT_PROVIDER_NAME);
230
+ return { active, names };
231
+ }
232
+ __name(getVisibleProviderNames, "getVisibleProviderNames");
233
+ function providerSelectionDescription(names, active) {
234
+ return `Search provider to use for this call only, overriding the active provider set via /web-tools. Configured providers: ${names.join(", ")}. Default provider: ${active.name} (source: ${active.source}). Omit to use the configured active provider. The named provider must have its API key/URL configured or the call throws.`;
235
+ }
236
+ __name(providerSelectionDescription, "providerSelectionDescription");
237
+ function assertKnownProvider(name) {
238
+ if (!KNOWN_PROVIDER_NAMES.includes(name)) {
239
+ throw new Error(`Unknown web_search provider: "${name}". Valid providers: ${KNOWN_PROVIDER_NAMES.join(", ")}.`);
240
+ }
241
+ }
242
+ __name(assertKnownProvider, "assertKnownProvider");
243
+ function resolveActiveProviderName(config) {
244
+ const envProvider = process.env.WEB_SEARCH_PROVIDER?.trim();
245
+ if (envProvider) return { name: envProvider, source: "env" };
246
+ if (config.provider) return { name: config.provider, source: "config" };
247
+ return { name: DEFAULT_PROVIDER_NAME, source: "default" };
248
+ }
249
+ __name(resolveActiveProviderName, "resolveActiveProviderName");
250
+ function instantiateProvider(config, override) {
251
+ let providerName;
252
+ if (override !== void 0) {
253
+ assertKnownProvider(override);
254
+ providerName = override;
255
+ } else {
256
+ const active = resolveActiveProviderName(config);
257
+ if (active.source === "env") assertKnownProvider(active.name);
258
+ providerName = active.name;
259
+ }
260
+ const apiKey = resolveProviderApiKey(providerName, config);
261
+ const meta = PROVIDERS.find((p) => p.name === providerName);
262
+ const baseUrl = meta?.baseUrlEnvVar ? resolveProviderBaseUrl(meta, config) : void 0;
263
+ const provider = createSearchProvider(providerName, { apiKey: apiKey ?? "", baseUrl });
264
+ return { providerName, provider };
265
+ }
266
+ __name(instantiateProvider, "instantiateProvider");
267
+ function maskApiKey(key) {
268
+ if (!key) return UNSET_LABEL;
269
+ const head = key.slice(0, API_KEY_MASK_VISIBLE_CHARS);
270
+ const tail = key.slice(-API_KEY_MASK_VISIBLE_CHARS);
271
+ return `${head}...${tail}`;
272
+ }
273
+ __name(maskApiKey, "maskApiKey");
274
+ function clampSearchResultCount(requested) {
275
+ const value = requested ?? DEFAULT_SEARCH_RESULTS;
276
+ return Math.min(Math.max(value, MIN_SEARCH_RESULTS), MAX_SEARCH_RESULTS);
277
+ }
278
+ __name(clampSearchResultCount, "clampSearchResultCount");
279
+ function isPrivateOrLoopbackHostname(hostname) {
280
+ const h = hostname.toLowerCase().replace(/^\[|\]$/g, "");
281
+ if (h === "localhost" || h.endsWith(".localhost")) return true;
282
+ if (h === "::1" || h === "::" || h.startsWith("fe80:") || h.startsWith("fc") || h.startsWith("fd")) return true;
283
+ const v4 = h.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
284
+ if (!v4) return false;
285
+ const [a, b] = [Number(v4[1]), Number(v4[2])];
286
+ if (a === 0 || a === 127 || a === 10) return true;
287
+ if (a === 169 && b === 254) return true;
288
+ if (a === 172 && b >= 16 && b <= 31) return true;
289
+ if (a === 192 && b === 168) return true;
290
+ return false;
291
+ }
292
+ __name(isPrivateOrLoopbackHostname, "isPrivateOrLoopbackHostname");
293
+ function parseAndAssertHttpUrl(raw) {
294
+ let parsed;
295
+ try {
296
+ parsed = new URL(raw);
297
+ } catch {
298
+ throw new Error(`Invalid URL: ${raw}`);
299
+ }
300
+ if (!SUPPORTED_HTTP_PROTOCOLS.has(parsed.protocol)) {
301
+ throw new Error(`Unsupported URL protocol: ${parsed.protocol}. Only http and https are supported.`);
302
+ }
303
+ if (isPrivateOrLoopbackHostname(parsed.hostname)) {
304
+ throw new Error(`Refusing to fetch private/loopback address: ${parsed.hostname}`);
305
+ }
306
+ return parsed;
307
+ }
308
+ __name(parseAndAssertHttpUrl, "parseAndAssertHttpUrl");
309
+ async function spillFullContentToTempFile(content) {
310
+ const tempDir = await mkdtemp(join(tmpdir(), FETCH_TEMP_DIR_PREFIX));
311
+ const tempFile = join(tempDir, FETCH_TEMP_FILE_NAME);
312
+ await writeFile(tempFile, content, "utf8");
313
+ return tempFile;
314
+ }
315
+ __name(spillFullContentToTempFile, "spillFullContentToTempFile");
316
+ function formatTruncationFooter(truncation, tempFile) {
317
+ const truncatedLines = truncation.totalLines - truncation.outputLines;
318
+ const truncatedBytes = truncation.totalBytes - truncation.outputBytes;
319
+ return `
320
+
321
+ [Content truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${formatSize(truncation.outputBytes)} of ${formatSize(truncation.totalBytes)}). ${truncatedLines} lines (${formatSize(truncatedBytes)}) omitted. Full content saved to: ${tempFile}]`;
322
+ }
323
+ __name(formatTruncationFooter, "formatTruncationFooter");
324
+ function formatFetchHeader(url, title, contentType) {
325
+ const lines = [`**Fetched:** ${url}`];
326
+ if (title) lines.push(`**Title:** ${title}`);
327
+ if (contentType) lines.push(`**Content-Type:** ${contentType}`);
328
+ return `${lines.join("\n")}
329
+
330
+ `;
331
+ }
332
+ __name(formatFetchHeader, "formatFetchHeader");
333
+ function formatSearchResultsBody(response) {
334
+ let text = `**Search results for "${response.query}":**
335
+
336
+ `;
337
+ response.results.forEach((r, i) => {
338
+ text += `${i + 1}. **${r.title}**
339
+ ${r.url}
340
+ ${r.snippet}
341
+
342
+ `;
343
+ });
344
+ return text.trimEnd();
345
+ }
346
+ __name(formatSearchResultsBody, "formatSearchResultsBody");
347
+ function buildEmptyResultsEnvelope(query, providerName) {
348
+ return {
349
+ content: [{ type: "text", text: `No results found for "${query}".` }],
350
+ details: { query, backend: providerName, resultCount: 0 }
351
+ };
352
+ }
353
+ __name(buildEmptyResultsEnvelope, "buildEmptyResultsEnvelope");
354
+ function registerWebSearchTool(pi) {
355
+ const config = loadConfig();
356
+ const guidance = validateGuidanceFields(config.guidance?.web_search);
357
+ const visibleProviders = getVisibleProviderNames(config);
358
+ pi.registerTool({
359
+ name: "web_search",
360
+ label: "Web Search",
361
+ description: "Search the web for information. Returns a list of results with titles, URLs, and snippets. Use when you need current information not in your training data.",
362
+ promptSnippet: guidance.promptSnippet ?? DEFAULT_WEB_SEARCH_SNIPPET,
363
+ promptGuidelines: guidance.promptGuidelines ?? DEFAULT_WEB_SEARCH_GUIDELINES,
364
+ parameters: typebox_exports.Object({
365
+ query: typebox_exports.String({
366
+ description: "The search query. Be specific and use natural language."
367
+ }),
368
+ max_results: typebox_exports.Optional(
369
+ typebox_exports.Number({
370
+ description: `Maximum number of results to return (${MIN_SEARCH_RESULTS}-${MAX_SEARCH_RESULTS}). Default: ${DEFAULT_SEARCH_RESULTS}.`,
371
+ default: DEFAULT_SEARCH_RESULTS,
372
+ minimum: MIN_SEARCH_RESULTS,
373
+ maximum: MAX_SEARCH_RESULTS
374
+ })
375
+ ),
376
+ provider: typebox_exports.Optional(
377
+ typebox_exports.Union(
378
+ visibleProviders.names.map((name) => typebox_exports.Literal(name)),
379
+ { description: providerSelectionDescription(visibleProviders.names, visibleProviders.active) }
380
+ )
381
+ )
382
+ }),
383
+ async execute(_toolCallId, params, signal, onUpdate, _ctx) {
384
+ const maxResults = clampSearchResultCount(params.max_results);
385
+ const config2 = loadConfig();
386
+ const { providerName, provider } = instantiateProvider(config2, params.provider);
387
+ onUpdate?.({
388
+ content: [{ type: "text", text: `Searching ${provider.label} for: "${params.query}"...` }],
389
+ details: { query: params.query, backend: providerName, resultCount: 0 }
390
+ });
391
+ const response = await provider.search(params.query, maxResults, signal);
392
+ if (response.results.length === 0) {
393
+ return buildEmptyResultsEnvelope(params.query, providerName);
394
+ }
395
+ return {
396
+ content: [{ type: "text", text: formatSearchResultsBody(response) }],
397
+ details: {
398
+ query: params.query,
399
+ backend: providerName,
400
+ resultCount: response.results.length,
401
+ results: response.results
402
+ }
403
+ };
404
+ },
405
+ renderCall(args, theme, _context) {
406
+ let text = theme.fg("toolTitle", theme.bold("WebSearch "));
407
+ text += theme.fg("accent", `"${args.query}"`);
408
+ if (args.provider) {
409
+ text += theme.fg("dim", ` via ${args.provider}`);
410
+ }
411
+ return new Text(text, 0, 0);
412
+ },
413
+ renderResult(result, { expanded, isPartial }, theme, _context) {
414
+ if (isPartial) {
415
+ return new Text(theme.fg("warning", "Searching..."), 0, 0);
416
+ }
417
+ const details = result.details;
418
+ const count = details?.resultCount ?? 0;
419
+ let text = theme.fg("success", `\u2713 ${count} result${count !== 1 ? "s" : ""}`);
420
+ if (expanded && details?.results) {
421
+ text += renderSearchResultsPreview(details.results, theme);
422
+ }
423
+ return new Text(text, 0, 0);
424
+ }
425
+ });
426
+ }
427
+ __name(registerWebSearchTool, "registerWebSearchTool");
428
+ function renderSearchResultsPreview(results, theme) {
429
+ let text = "";
430
+ for (const r of results.slice(0, SEARCH_RESULT_PREVIEW_LIMIT)) {
431
+ text += `
432
+ ${theme.fg("dim", `\u2022 ${r.title}`)}`;
433
+ }
434
+ if (results.length > SEARCH_RESULT_PREVIEW_LIMIT) {
435
+ text += `
436
+ ${theme.fg("dim", `... and ${results.length - SEARCH_RESULT_PREVIEW_LIMIT} more`)}`;
437
+ }
438
+ return text;
439
+ }
440
+ __name(renderSearchResultsPreview, "renderSearchResultsPreview");
441
+ function registerWebFetchTool(pi) {
442
+ const guidance = validateGuidanceFields(loadConfig().guidance?.web_fetch);
443
+ pi.registerTool({
444
+ name: "web_fetch",
445
+ label: "Web Fetch",
446
+ description: "Fetch the content of a specific URL. Returns text content for HTML pages (tags stripped), raw text for plain text or JSON. Supports http and https only. Content is truncated to avoid overwhelming the context window.",
447
+ promptSnippet: guidance.promptSnippet ?? DEFAULT_WEB_FETCH_SNIPPET,
448
+ promptGuidelines: guidance.promptGuidelines ?? DEFAULT_WEB_FETCH_GUIDELINES,
449
+ parameters: typebox_exports.Object({
450
+ url: typebox_exports.String({
451
+ description: "The URL to fetch. Must be http or https."
452
+ }),
453
+ raw: typebox_exports.Optional(
454
+ typebox_exports.Boolean({
455
+ description: "If true, return the raw HTML instead of extracted text. Default: false.",
456
+ default: false
457
+ })
458
+ )
459
+ }),
460
+ async execute(_toolCallId, params, signal, onUpdate, _ctx) {
461
+ const { url, raw = false } = params;
462
+ parseAndAssertHttpUrl(url);
463
+ onUpdate?.({
464
+ content: [{ type: "text", text: `Fetching: ${url}...` }],
465
+ details: { url }
466
+ });
467
+ const config = loadConfig();
468
+ const { provider } = instantiateProvider(config);
469
+ let fetchResponse;
470
+ for (const interceptor of getInterceptors()) {
471
+ const r = await interceptor.intercept(url, { raw, signal });
472
+ if (r) {
473
+ fetchResponse = r;
474
+ break;
475
+ }
476
+ }
477
+ if (!fetchResponse && "fetch" in provider) {
478
+ fetchResponse = await provider.fetch(url, raw, signal);
479
+ }
480
+ if (!fetchResponse) {
481
+ fetchResponse = await fetchViaGenericHtml(url, raw, signal);
482
+ }
483
+ const { text: bodyText, title, contentType, contentLength } = fetchResponse;
484
+ const truncation = truncateHead(bodyText, {
485
+ maxLines: DEFAULT_MAX_LINES,
486
+ maxBytes: DEFAULT_MAX_BYTES
487
+ });
488
+ const details = {
489
+ url,
490
+ title,
491
+ contentType,
492
+ contentLength
493
+ };
494
+ let output = truncation.content;
495
+ if (truncation.truncated) {
496
+ const tempFile = await spillFullContentToTempFile(bodyText);
497
+ details.truncation = truncation;
498
+ details.fullOutputPath = tempFile;
499
+ output += formatTruncationFooter(truncation, tempFile);
500
+ }
501
+ return {
502
+ content: [{ type: "text", text: formatFetchHeader(url, title, contentType ?? "") + output }],
503
+ details
504
+ };
505
+ },
506
+ renderCall(args, theme, _context) {
507
+ let text = theme.fg("toolTitle", theme.bold("WebFetch "));
508
+ text += theme.fg("accent", args.url);
509
+ return new Text(text, 0, 0);
510
+ },
511
+ renderResult(result, { expanded, isPartial }, theme, _context) {
512
+ if (isPartial) {
513
+ return new Text(theme.fg("warning", "Fetching..."), 0, 0);
514
+ }
515
+ const details = result.details;
516
+ let text = theme.fg("success", "\u2713 Fetched");
517
+ if (details?.title) text += theme.fg("muted", `: ${details.title}`);
518
+ if (details?.truncation?.truncated) text += theme.fg("warning", " (truncated)");
519
+ if (expanded) {
520
+ const content = result.content[0];
521
+ if (content?.type === "text") {
522
+ text += renderFetchedContentPreview(content.text, theme);
523
+ }
524
+ }
525
+ return new Text(text, 0, 0);
526
+ }
527
+ });
528
+ }
529
+ __name(registerWebFetchTool, "registerWebFetchTool");
530
+ function renderFetchedContentPreview(content, theme) {
531
+ const lines = content.split("\n");
532
+ const visible = lines.slice(0, FETCH_PREVIEW_LINE_LIMIT);
533
+ let text = "";
534
+ for (const line of visible) {
535
+ text += `
536
+ ${theme.fg("dim", line)}`;
537
+ }
538
+ if (lines.length > FETCH_PREVIEW_LINE_LIMIT) {
539
+ text += `
540
+ ${theme.fg("muted", "... (use read tool to see full content)")}`;
541
+ }
542
+ return text;
543
+ }
544
+ __name(renderFetchedContentPreview, "renderFetchedContentPreview");
545
+ function formatShowConfigMessage(current) {
546
+ const lines = ["Web search config:", ` config file: ${CONFIG_PATH}`];
547
+ const { name: providerName, source: providerSource } = resolveActiveProviderName(current);
548
+ lines.push(` active provider: ${providerName} (source: ${providerSource})`);
549
+ for (const meta of PROVIDERS) {
550
+ const envKey = meta.envVar ? process.env[meta.envVar]?.trim() : void 0;
551
+ const configKey = current.apiKeys?.[meta.name]?.trim();
552
+ const legacyKey = meta.name === LEGACY_TOP_LEVEL_KEY_PROVIDER ? current.apiKey?.trim() : void 0;
553
+ const resolved = envKey ?? configKey ?? legacyKey;
554
+ lines.push(
555
+ ` ${meta.name}: ${maskApiKey(resolved)} (env: ${maskApiKey(envKey)}, config: ${maskApiKey(configKey ?? legacyKey)})`
556
+ );
557
+ }
558
+ for (const meta of PROVIDERS) {
559
+ if (!meta.baseUrlEnvVar) continue;
560
+ const envUrl = process.env[meta.baseUrlEnvVar]?.trim();
561
+ const configUrl = current.baseUrls?.[meta.name]?.trim();
562
+ const resolvedUrl = envUrl || configUrl || meta.defaultBaseUrl || "";
563
+ const urlSource = envUrl ? "env" : configUrl ? "config" : "default";
564
+ lines.push(` ${meta.name} url: ${resolvedUrl} (source: ${urlSource})`);
565
+ }
566
+ lines.push("");
567
+ lines.push("URL interceptors:");
568
+ const githubInterceptor = getActiveGitHubInterceptor();
569
+ if (githubInterceptor) {
570
+ const opts = githubInterceptor.resolvedOptions;
571
+ const token = process.env[GITHUB_TOKEN_ENV_VAR]?.trim();
572
+ lines.push(
573
+ ` github: enabled (${GITHUB_TOKEN_ENV_VAR}: ${maskApiKey(token)}, maxRepoSizeMB: ${opts.maxRepoSizeMB}, clonePath: ${opts.clonePath})`
574
+ );
575
+ } else {
576
+ lines.push(" github: disabled");
577
+ lines.push(' \u21B3 enable: add "interceptors": { "github": true } to config.json');
578
+ lines.push(' \u21B3 disable: set "interceptors": { "github": false } to override a consumer-enabled default');
579
+ }
580
+ return lines.join("\n");
581
+ }
582
+ __name(formatShowConfigMessage, "formatShowConfigMessage");
583
+ function refreshWebSearchSchema(pi) {
584
+ registerWebSearchTool(pi);
585
+ }
586
+ __name(refreshWebSearchSchema, "refreshWebSearchSchema");
587
+ function registerWebSearchConfigCommand(pi) {
588
+ pi.registerCommand(WEB_TOOLS_COMMAND_NAME, {
589
+ description: "Configure the search provider and API key used by web_search",
590
+ handler: /* @__PURE__ */ __name(async (args, ctx) => {
591
+ if (!ctx.hasUI) {
592
+ ctx.ui?.notify?.(`/${WEB_TOOLS_COMMAND_NAME} requires interactive mode`, "error");
593
+ return;
594
+ }
595
+ const current = loadConfig();
596
+ if (typeof args === "string" && args.includes(SHOW_FLAG)) {
597
+ ctx.ui.notify(formatShowConfigMessage(current), "info");
598
+ return;
599
+ }
600
+ const activeProvider = resolveActiveProviderName(current).name;
601
+ const orderedMetas = [
602
+ ...PROVIDERS.filter((p) => p.name === activeProvider),
603
+ ...PROVIDERS.filter((p) => p.name !== activeProvider)
604
+ ];
605
+ const hasKey = /* @__PURE__ */ __name((p) => isProviderConfigured(p, current), "hasKey");
606
+ const labelOf = /* @__PURE__ */ __name((p) => {
607
+ const markers = [];
608
+ if (p.name === activeProvider) markers.push("\u2713");
609
+ if (hasKey(p)) markers.push("(configured)");
610
+ return markers.length > 0 ? `${p.label} ${markers.join(" ")}` : p.label;
611
+ }, "labelOf");
612
+ const selectedLabel = await ctx.ui.select("Search provider", orderedMetas.map(labelOf), {});
613
+ if (selectedLabel === void 0 || selectedLabel === null) {
614
+ ctx.ui.notify("Web search config unchanged", "info");
615
+ return;
616
+ }
617
+ const selectedMeta = PROVIDERS.find(
618
+ (p) => selectedLabel === p.label || selectedLabel.startsWith(`${p.label} `)
619
+ );
620
+ if (!selectedMeta) {
621
+ ctx.ui.notify("Web search config unchanged", "info");
622
+ return;
623
+ }
624
+ const selectedProvider = selectedMeta.name;
625
+ if (selectedMeta.configure) {
626
+ const result = await selectedMeta.configure(ctx.ui, {
627
+ baseUrl: current.baseUrls?.[selectedProvider],
628
+ apiKey: current.apiKeys?.[selectedProvider]
629
+ });
630
+ if (!result) {
631
+ ctx.ui.notify("Web search config unchanged", "info");
632
+ return;
633
+ }
634
+ const toSave2 = {
635
+ ...current,
636
+ provider: selectedProvider,
637
+ ...result.baseUrl !== void 0 && {
638
+ baseUrls: { ...current.baseUrls, [selectedProvider]: result.baseUrl }
639
+ },
640
+ ...result.apiKey ? { apiKeys: { ...current.apiKeys, [selectedProvider]: result.apiKey } } : {}
641
+ };
642
+ delete toSave2.apiKey;
643
+ if (!saveConfig(toSave2)) {
644
+ ctx.ui.notify(
645
+ `Failed to save ${selectedMeta.label} config to ${CONFIG_PATH} \u2014 disk write failed`,
646
+ "error"
647
+ );
648
+ return;
649
+ }
650
+ refreshWebSearchSchema(pi);
651
+ ctx.ui.notify(
652
+ result.baseUrl ? `Saved ${selectedMeta.label} config (url: ${result.baseUrl}) to ${CONFIG_PATH}` : `Saved ${selectedMeta.label} config to ${CONFIG_PATH}`,
653
+ "info"
654
+ );
655
+ return;
656
+ }
657
+ const existingKey = current.apiKeys?.[selectedProvider] ?? (selectedProvider === LEGACY_TOP_LEVEL_KEY_PROVIDER ? current.apiKey : void 0);
658
+ const input = await ctx.ui.input(
659
+ `${selectedMeta.label} API key`,
660
+ existingKey ? `Press Enter to keep current (${maskApiKey(existingKey)}), or type new key` : "..."
661
+ );
662
+ if (input === void 0 || input === null) {
663
+ ctx.ui.notify("Web search config unchanged", "info");
664
+ return;
665
+ }
666
+ const trimmed = input.trim();
667
+ const keyToWrite = trimmed || existingKey;
668
+ if (!keyToWrite) {
669
+ ctx.ui.notify("Web search config unchanged", "info");
670
+ return;
671
+ }
672
+ const toSave = {
673
+ ...current,
674
+ provider: selectedProvider,
675
+ apiKeys: { ...current.apiKeys, [selectedProvider]: keyToWrite }
676
+ };
677
+ delete toSave.apiKey;
678
+ if (!saveConfig(toSave)) {
679
+ ctx.ui.notify(
680
+ `Failed to save ${selectedMeta.label} API key to ${CONFIG_PATH} \u2014 disk write failed`,
681
+ "error"
682
+ );
683
+ return;
684
+ }
685
+ refreshWebSearchSchema(pi);
686
+ ctx.ui.notify(
687
+ trimmed ? `Saved ${selectedMeta.label} API key to ${CONFIG_PATH}` : `Active provider set to ${selectedMeta.label}; existing key kept`,
688
+ "info"
689
+ );
690
+ }, "handler")
691
+ });
692
+ }
693
+ __name(registerWebSearchConfigCommand, "registerWebSearchConfigCommand");
694
+
695
+ // node_modules/@juicesharp/rpiv-web-tools/index.ts?ext=privateer-web
696
+ function registerWebTools(pi, opts) {
697
+ buildInterceptors(opts?.interceptors);
698
+ registerWebSearchTool(pi);
699
+ registerWebFetchTool(pi);
700
+ registerWebSearchConfigCommand(pi);
701
+ }
702
+ __name(registerWebTools, "registerWebTools");
703
+ export {
704
+ DEFAULT_WEB_FETCH_GUIDELINES,
705
+ DEFAULT_WEB_FETCH_SNIPPET,
706
+ DEFAULT_WEB_SEARCH_GUIDELINES,
707
+ DEFAULT_WEB_SEARCH_SNIPPET,
708
+ GITHUB_TOKEN_ENV_VAR,
709
+ GitHubInterceptor,
710
+ createSearchProvider,
711
+ registerWebTools as default,
712
+ parseGitHubUrl,
713
+ registerWebFetchTool,
714
+ registerWebSearchConfigCommand,
715
+ registerWebSearchTool,
716
+ resolveGitHubOptions
717
+ };