binary-collections 2.0.8 → 2.0.10

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 (250) hide show
  1. package/binaries/binary-executor.cjs +43 -0
  2. package/{bin → binaries}/clean-nodemodule +0 -0
  3. package/binaries/clean-nodemodule.cjs +43 -0
  4. package/binaries/clean-nodemodule.cmd +4 -0
  5. package/{bin → binaries}/clean-nodemodules +0 -0
  6. package/binaries/clean-nodemodules.cjs +43 -0
  7. package/binaries/clean-nodemodules.cmd +5 -0
  8. package/{bin → binaries}/dev +0 -0
  9. package/binaries/dev.cjs +43 -0
  10. package/{bin → binaries}/empty +0 -0
  11. package/binaries/empty.cjs +43 -0
  12. package/{bin → binaries}/git-reduce-size +0 -0
  13. package/binaries/git-reduce-size.cjs +43 -0
  14. package/binaries/javakill.cjs +43 -0
  15. package/{bin → binaries}/javakill.cmd +0 -0
  16. package/{bin → binaries}/kill-process +0 -0
  17. package/binaries/kill-process.cjs +43 -0
  18. package/binaries/nodekill.cjs +43 -0
  19. package/{bin → binaries}/nodekill.ps1 +0 -0
  20. package/{bin → binaries}/prod +0 -0
  21. package/binaries/prod.cjs +43 -0
  22. package/{bin → binaries}/rmfind +0 -0
  23. package/binaries/rmfind.cjs +43 -0
  24. package/{bin → binaries}/rmx +0 -0
  25. package/binaries/rmx.cjs +43 -0
  26. package/{bin → binaries}/submodule-token +0 -0
  27. package/binaries/submodule-token.cjs +43 -0
  28. package/docs-src/clean-github-actions-caches.md +26 -0
  29. package/docs-src/free-chatgpt.md +26 -0
  30. package/lib/binary-collections-config.cjs +3 -2
  31. package/lib/binary-collections-config.mjs +2 -2
  32. package/lib/binary-collections.cjs +452 -87
  33. package/lib/binary-collections.mjs +247 -8
  34. package/lib/changelog.cjs +328 -0
  35. package/lib/changelog.mjs +205 -0
  36. package/lib/chunk-4EWQC6GZ.mjs +382 -0
  37. package/lib/chunk-4ZI7BQKQ.mjs +381 -0
  38. package/lib/chunk-5J2BEPY5.mjs +83 -0
  39. package/lib/{chunk-4BYBVEYC.mjs → chunk-66PAU5PS.mjs} +5 -4
  40. package/lib/chunk-6HHJRKFB.mjs +59 -0
  41. package/lib/chunk-6S4NXESK.mjs +26 -0
  42. package/lib/{chunk-ZYAQRPUL.mjs → chunk-7YD7IPFF.mjs} +2 -2
  43. package/lib/{chunk-SH3L6HHV.mjs → chunk-A2JQXI5Z.mjs} +2 -2
  44. package/lib/{chunk-EGSSKVDH.mjs → chunk-A3VUZEJK.mjs} +1 -1
  45. package/lib/chunk-AGZYRDC2.mjs +323 -0
  46. package/lib/{chunk-VVEZVNIV.mjs → chunk-AI4CVPJ7.mjs} +6 -6
  47. package/lib/chunk-BDCHCWHD.mjs +136 -0
  48. package/lib/chunk-BEZKJ25G.mjs +140 -0
  49. package/lib/chunk-DI5MDPSN.mjs +386 -0
  50. package/lib/{chunk-ONIBBBQ3.mjs → chunk-E6FDDAOO.mjs} +4 -3
  51. package/lib/chunk-FKI7IEB5.mjs +172 -0
  52. package/lib/chunk-GJTGHXRA.mjs +356 -0
  53. package/lib/{chunk-YV7DO3YV.mjs → chunk-HLGOWBEO.mjs} +1 -1
  54. package/lib/chunk-HMRMTYZM.mjs +40 -0
  55. package/lib/chunk-HN52G2YL.mjs +305 -0
  56. package/lib/chunk-HO6GHCOB.mjs +385 -0
  57. package/lib/chunk-LEM5OMRP.mjs +384 -0
  58. package/lib/{chunk-YX5U7XDR.mjs → chunk-M3YIYRHT.mjs} +6 -5
  59. package/lib/chunk-O6SWBEOQ.mjs +81 -0
  60. package/lib/{chunk-JGR2NW6D.mjs → chunk-PDSXF5HY.mjs} +3 -3
  61. package/lib/{chunk-AASHBCRW.mjs → chunk-QQ4A6DLD.mjs} +8 -0
  62. package/lib/chunk-RCP7DHVY.mjs +190 -0
  63. package/lib/chunk-SBNDSKG5.mjs +136 -0
  64. package/lib/chunk-U6SO4QEV.mjs +320 -0
  65. package/lib/{chunk-APBWENF6.mjs → chunk-V3N3JEUF.mjs} +3 -3
  66. package/lib/chunk-XD6BJK6Q.mjs +351 -0
  67. package/lib/chunk-XVBFFVCJ.mjs +209 -0
  68. package/lib/chunk-YXSFGA2D.mjs +383 -0
  69. package/lib/clean-github-actions-caches.cjs +243 -148
  70. package/lib/clean-github-actions-caches.mjs +4 -3
  71. package/lib/del-gradle.cjs +2 -2
  72. package/lib/del-gradle.js +1 -1
  73. package/lib/del-gradle.mjs +2 -2
  74. package/lib/del-node-modules.cjs +2 -2
  75. package/lib/del-node-modules.js +1 -1
  76. package/lib/del-node-modules.mjs +2 -2
  77. package/lib/del-ps.cjs +29 -8
  78. package/lib/del-ps.js +2 -2
  79. package/lib/del-ps.mjs +7 -5
  80. package/lib/del-yarn-caches.cjs +26 -5
  81. package/lib/del-yarn-caches.js +38 -3
  82. package/lib/del-yarn-caches.mjs +6 -6
  83. package/lib/find-node-modules-cli.cjs +5 -4
  84. package/lib/find-node-modules-cli.js +1 -1
  85. package/lib/find-node-modules-cli.mjs +2 -2
  86. package/lib/find-node-modules.cjs +4 -3
  87. package/lib/{find-node-modules.d.ts → find-node-modules.d.cts} +1 -1
  88. package/lib/find-node-modules.mjs +2 -2
  89. package/lib/free-chatgpt.cjs +548 -0
  90. package/lib/free-chatgpt.d.ts +1 -0
  91. package/lib/free-chatgpt.js +51 -0
  92. package/lib/free-chatgpt.mjs +50 -0
  93. package/lib/git/gitattributes.cjs +1 -1
  94. package/lib/git/{gitattributes.d.mts → gitattributes.d.cts} +5 -7
  95. package/lib/git/gitattributes.mjs +2 -2
  96. package/lib/git/line-endings.cjs +297 -64
  97. package/lib/git/line-endings.mjs +4 -4
  98. package/lib/git/normalize.cjs +26 -36
  99. package/lib/git/normalize.mjs +2 -2
  100. package/lib/git/permissions.cjs +77 -11
  101. package/lib/git/permissions.mjs +3 -3
  102. package/lib/git/pull-strategy.cjs +76 -9
  103. package/lib/git/pull-strategy.mjs +3 -3
  104. package/lib/git/user-config.cjs +266 -83
  105. package/lib/git/user-config.mjs +4 -4
  106. package/lib/git/utils.cjs +40 -60
  107. package/lib/git/utils.mjs +2 -2
  108. package/lib/git-diff-cli.cjs +651 -0
  109. package/lib/git-diff-cli.d.ts +1 -0
  110. package/lib/git-diff-cli.js +15 -0
  111. package/lib/git-diff-cli.mjs +16 -0
  112. package/lib/git-diff.cjs +657 -58
  113. package/lib/git-diff.d.ts +38 -83
  114. package/lib/git-diff.js +152 -0
  115. package/lib/git-diff.mjs +23 -85
  116. package/lib/git-fix.cjs +685 -97
  117. package/lib/git-fix.mjs +12 -11
  118. package/lib/git-purge.cjs +3 -3
  119. package/lib/git-purge.d.cts +1 -0
  120. package/lib/git-purge.mjs +43 -37
  121. package/lib/index.cjs +7 -6
  122. package/lib/index.d.ts +1 -1
  123. package/lib/index.js +2 -5
  124. package/lib/index.mjs +4 -4
  125. package/lib/npm-run-series.cjs +3 -3
  126. package/lib/npm-run-series.mjs +42 -36
  127. package/lib/package-resolutions-updater.cjs +174 -1
  128. package/lib/package-resolutions-updater.mjs +270 -290
  129. package/lib/print-directory-tree.cjs +275 -210
  130. package/lib/print-directory-tree.mjs +2 -2
  131. package/lib/ps/connected-domain.cjs +25 -2
  132. package/lib/ps/connected-domain.d.ts +10 -2
  133. package/lib/ps/connected-domain.js +5 -2
  134. package/lib/ps/connected-domain.mjs +8 -4
  135. package/lib/ps/index.cjs +345 -322
  136. package/lib/ps/index.d.mjs +1 -1
  137. package/lib/ps/index.js +1 -1
  138. package/lib/ps/index.mjs +179 -182
  139. package/lib/ps/isWin.cjs +24 -1
  140. package/lib/ps/isWin.d.ts +1 -1
  141. package/lib/ps/isWin.js +3 -1
  142. package/lib/ps/isWin.mjs +8 -4
  143. package/lib/ps/table-parser.cjs +167 -159
  144. package/lib/ps/table-parser.d.ts +5 -0
  145. package/lib/ps/table-parser.js +10 -4
  146. package/lib/ps/table-parser.mjs +9 -5
  147. package/lib/remove-module.cjs +262 -0
  148. package/lib/remove-module.d.mts +1 -0
  149. package/lib/remove-module.mjs +111 -0
  150. package/lib/rmpath.cjs +274 -0
  151. package/lib/rmpath.d.mts +3 -0
  152. package/lib/rmpath.mjs +108 -0
  153. package/lib/submodule-install.cjs +264 -85
  154. package/lib/submodule-install.mjs +56 -7
  155. package/lib/submodule-remove-cli.cjs +103 -0
  156. package/lib/submodule-remove-cli.d.ts +1 -0
  157. package/lib/submodule-remove-cli.js +31 -0
  158. package/lib/submodule-remove-cli.mjs +28 -0
  159. package/lib/submodule-remove.cjs +43 -0
  160. package/lib/submodule-remove.d.cts +2 -0
  161. package/lib/submodule-remove.mjs +6 -0
  162. package/lib/utils/chatgpt.cjs +383 -0
  163. package/lib/utils/chatgpt.d.ts +31 -0
  164. package/lib/utils/chatgpt.js +541 -0
  165. package/lib/utils/chatgpt.mjs +8 -0
  166. package/lib/{utils.cjs → utils/index.cjs} +1 -1
  167. package/lib/{utils.mjs → utils/index.mjs} +2 -2
  168. package/lib/yarn-reinstall.cjs +172 -38
  169. package/lib/yarn-reinstall.mjs +2 -2
  170. package/package.json +91 -71
  171. package/readme.md +43 -69
  172. package/releases/readme.md +36 -0
  173. package/test/README.md +101 -0
  174. package/test/package.json +2 -1
  175. package/test-project/readme.md +26 -0
  176. package/tmp/test-repo/README.md +35 -0
  177. package/tmp/typedoc/readme.md +320 -0
  178. package/bin/bash-dummy +0 -56
  179. package/bin/bash-dummy.cmd +0 -25
  180. package/bin/dir-tree.cmd +0 -7
  181. package/bin/git-diff +0 -4
  182. package/bin/git-diff.cmd +0 -7
  183. package/bin/git-fix +0 -36
  184. package/bin/git-fix.cmd +0 -7
  185. package/bin/rmpath +0 -70
  186. package/bin/submodule-install.txt +0 -118
  187. package/bin/submodule-remove +0 -46
  188. package/bin/submodule.txt +0 -172
  189. package/lib/binary-collections-config.d.mts +0 -18
  190. package/lib/binary-collections-config.js +0 -39
  191. package/lib/binary-collections.d.mts +0 -121
  192. package/lib/binary-collections.d.ts +0 -121
  193. package/lib/chunk-DPKAJKFO.mjs +0 -171
  194. package/lib/chunk-G3THLIDT.mjs +0 -200
  195. package/lib/chunk-W3ENOM53.mjs +0 -18
  196. package/lib/clean-github-actions-caches.d.mts +0 -169
  197. package/lib/clean-github-actions-caches.d.ts +0 -169
  198. package/lib/del-gradle.d.mts +0 -2
  199. package/lib/del-node-modules.d.mts +0 -2
  200. package/lib/del-ps.d.mts +0 -2
  201. package/lib/del-yarn-caches.d.mts +0 -2
  202. package/lib/find-node-modules-cli.d.mts +0 -1
  203. package/lib/find-node-modules.d.mts +0 -13
  204. package/lib/find-node-modules.js +0 -53
  205. package/lib/git/line-endings.d.mts +0 -83
  206. package/lib/git/line-endings.d.ts +0 -83
  207. package/lib/git/normalize.d.mts +0 -43
  208. package/lib/git/normalize.d.ts +0 -43
  209. package/lib/git/permissions.d.mts +0 -17
  210. package/lib/git/permissions.d.ts +0 -17
  211. package/lib/git/pull-strategy.d.mts +0 -15
  212. package/lib/git/pull-strategy.d.ts +0 -15
  213. package/lib/git/user-config.d.mts +0 -105
  214. package/lib/git/user-config.d.ts +0 -105
  215. package/lib/git/utils.d.mts +0 -69
  216. package/lib/git/utils.d.ts +0 -69
  217. package/lib/git-diff.d.mts +0 -84
  218. package/lib/git-fix.d.mts +0 -141
  219. package/lib/git-fix.d.ts +0 -141
  220. package/lib/git-purge.d.mts +0 -2
  221. package/lib/git-purge.js +0 -59
  222. package/lib/index.d.mts +0 -1
  223. package/lib/npm-run-series.d.mts +0 -1
  224. package/lib/npm-run-series.d.ts +0 -2
  225. package/lib/npm-run-series.js +0 -86
  226. package/lib/package-resolutions-updater.d.ts +0 -326
  227. package/lib/print-directory-tree.d.mts +0 -234
  228. package/lib/print-directory-tree.d.ts +0 -234
  229. package/lib/ps/connected-domain.d.mts +0 -3
  230. package/lib/ps/index.d.d.mts +0 -26
  231. package/lib/ps/index.d.d.ts +0 -26
  232. package/lib/ps/index.d.mts +0 -26
  233. package/lib/ps/isWin.d.mts +0 -3
  234. package/lib/ps/table-parser.d.mts +0 -3
  235. package/lib/submodule-install.d.mts +0 -121
  236. package/lib/submodule-install.d.ts +0 -121
  237. package/lib/utils.d.mts +0 -40
  238. package/lib/utils.js +0 -181
  239. package/lib/yarn-reinstall.d.mts +0 -49
  240. package/lib/yarn-reinstall.d.ts +0 -49
  241. package/src/package-resolutions-updater.mjs +0 -325
  242. package/src/print-directory-tree.cjs +0 -234
  243. package/src/ps/index.js +0 -286
  244. package/src/yarn-reinstall.cjs +0 -49
  245. /package/{bin → binaries}/nodekill +0 -0
  246. /package/{bin → binaries}/nodekill.cmd +0 -0
  247. /package/lib/{binary-collections-config.d.ts → binary-collections-config.d.cts} +0 -0
  248. /package/lib/{git-purge.d.ts → changelog.d.cts} +0 -0
  249. /package/lib/{git-diff.d.cts → npm-run-series.d.cts} +0 -0
  250. /package/lib/{utils.d.ts → utils/index.d.cts} +0 -0
@@ -0,0 +1,541 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.runChatGpt = runChatGpt;
16
+ const fs_extra_1 = __importDefault(require("fs-extra"));
17
+ const puppeteer_extra_1 = __importDefault(require("puppeteer-extra"));
18
+ const puppeteer_extra_plugin_stealth_1 = __importDefault(require("puppeteer-extra-plugin-stealth"));
19
+ const upath_1 = __importDefault(require("upath"));
20
+ const COOKIE_DIR = upath_1.default.join(process.cwd(), "tmp", "cookies");
21
+ const DEFAULT_COOKIE_PATH = upath_1.default.join(COOKIE_DIR, "cookies.json");
22
+ fs_extra_1.default.ensureDirSync(COOKIE_DIR);
23
+ /**
24
+ * Saves cookies from a Puppeteer page to a specified file path.
25
+ *
26
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
27
+ * @param {string} [path=DEFAULT_COOKIE_PATH] - Path to save the cookies file.
28
+ * @returns {Promise<void>} Resolves when cookies are saved.
29
+ */
30
+ function saveCookies(page_1) {
31
+ return __awaiter(this, arguments, void 0, function* (page, path = DEFAULT_COOKIE_PATH) {
32
+ const cookies = yield page.cookies();
33
+ fs_extra_1.default.writeFileSync(path, JSON.stringify(cookies, null, 2));
34
+ });
35
+ }
36
+ /**
37
+ * Returns the cookie file path for a given URL's hostname.
38
+ *
39
+ * @param {string} url - The URL to extract the hostname from.
40
+ * @returns {string} The path to the cookie file for the hostname, or the default cookie path if invalid.
41
+ */
42
+ function getCookiePathForUrl(url) {
43
+ try {
44
+ const { hostname } = new URL(url);
45
+ return upath_1.default.join(COOKIE_DIR, `cookies_${hostname}.json`);
46
+ }
47
+ catch (_a) {
48
+ return DEFAULT_COOKIE_PATH;
49
+ }
50
+ }
51
+ /**
52
+ * Navigates to a URL using Puppeteer, loading cookies for the host and injecting a DOM mutation observer.
53
+ *
54
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
55
+ * @param {string} url - The URL to navigate to.
56
+ * @returns {Promise<{ waitForDomIdle: (idleMs?: number, timeout?: number) => Promise<boolean> }>} An object containing a function to wait for DOM stability.
57
+ */
58
+ function navigatePage(page, url) {
59
+ return __awaiter(this, void 0, void 0, function* () {
60
+ const cookiePath = getCookiePathForUrl(url);
61
+ // Load cookies for the host
62
+ const cookies = loadCookies(cookiePath);
63
+ if (cookies) {
64
+ yield page.setCookie(...cookies);
65
+ }
66
+ // Navigate and wait until fully loaded
67
+ yield page.goto(url, { waitUntil: "networkidle0" });
68
+ // Inject DOM mutation observer to handle dynamic content
69
+ yield page.evaluate(() => {
70
+ window.__domStillUpdating = true;
71
+ if (window.__domObserver) {
72
+ window.__domObserver.disconnect();
73
+ }
74
+ window.__domObserver = new MutationObserver(() => {
75
+ window.__lastDomMutation = Date.now();
76
+ });
77
+ window.__lastDomMutation = Date.now();
78
+ window.__domObserver.observe(document.body, {
79
+ childList: true,
80
+ subtree: true,
81
+ attributes: true,
82
+ characterData: true
83
+ });
84
+ // Stop tracking after a while (optional)
85
+ setTimeout(() => {
86
+ window.__domStillUpdating = false;
87
+ window.__domObserver.disconnect();
88
+ }, 30000); // e.g. 30 seconds max
89
+ });
90
+ /**
91
+ * Waits until the DOM has been stable (no mutations) for a specified number of milliseconds.
92
+ *
93
+ * @param {number} [idleMs=1000] - The number of milliseconds the DOM must be stable.
94
+ * @param {number} [timeout=10000] - The maximum time to wait for the DOM to stabilize.
95
+ * @returns {Promise<boolean>} Resolves to true if the DOM was stable for idleMs within timeout, otherwise throws an error.
96
+ */
97
+ const waitForDomIdle = (...args_1) => __awaiter(this, [...args_1], void 0, function* (idleMs = 1000, timeout = 10000) {
98
+ const start = Date.now();
99
+ while (Date.now() - start < timeout) {
100
+ const lastMutation = yield page.evaluate(() => window.__lastDomMutation);
101
+ const idle = Date.now() - lastMutation;
102
+ if (idle >= idleMs) {
103
+ return true; // DOM has been stable for idleMs
104
+ }
105
+ yield new Promise((r) => setTimeout(r, 200)); // poll every 200ms
106
+ }
107
+ throw new Error("DOM did not stabilize within timeout");
108
+ });
109
+ return { waitForDomIdle };
110
+ });
111
+ }
112
+ /**
113
+ * Loads cookies from a specified file path.
114
+ *
115
+ * @param {string} [cookieFilePath=DEFAULT_COOKIE_PATH] - Path to the cookie file.
116
+ * @returns {Array|Null} Parsed cookies array, or null if file does not exist.
117
+ */
118
+ function loadCookies(cookieFilePath = DEFAULT_COOKIE_PATH) {
119
+ if (!fs_extra_1.default.existsSync(cookieFilePath))
120
+ return null;
121
+ return JSON.parse(fs_extra_1.default.readFileSync(cookieFilePath));
122
+ }
123
+ /**
124
+ * Restores cookies from a file to a Puppeteer page.
125
+ *
126
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
127
+ * @param {string} [cookieFilePath=DEFAULT_COOKIE_PATH] - Path to the cookie file.
128
+ * @returns {Promise<void>} Resolves when cookies are restored.
129
+ */
130
+ function _restoreCookies(page_1) {
131
+ return __awaiter(this, arguments, void 0, function* (page, cookieFilePath = DEFAULT_COOKIE_PATH) {
132
+ const cookies = loadCookies(cookieFilePath);
133
+ if (cookies) {
134
+ yield page.setCookie(...cookies);
135
+ }
136
+ });
137
+ }
138
+ /**
139
+ * Writes a question to the ChatGPT prompt textarea, handling multi-line questions.
140
+ *
141
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
142
+ * @param {string} question - The question text to write.
143
+ * @returns {Promise<void>} Resolves when the question is written.
144
+ */
145
+ function writeQuestion(page, question) {
146
+ return __awaiter(this, void 0, void 0, function* () {
147
+ const questions = question.split("\n");
148
+ const promptTextarea = yield page.waitForSelector("#prompt-textarea", { timeout: 30000 });
149
+ if (!promptTextarea) {
150
+ console.log("Cannot find the prompt input on the webpage. Please check whether you have access to chat.openai.com without logging in via your browser.");
151
+ }
152
+ // Clear the prompt textarea
153
+ yield page.evaluate(() => {
154
+ document.querySelector("#prompt-textarea").innerHTML = `<p></p>`;
155
+ });
156
+ // Check if the question has newlines
157
+ if (questions.length === 1) {
158
+ // If there's only one line, type it directly
159
+ yield page.type("#prompt-textarea", questions[0], { delay: 100 });
160
+ return;
161
+ }
162
+ // Type each question line by line
163
+ for (const q of questions) {
164
+ yield page.type("#prompt-textarea", q, { delay: 100 });
165
+ // Check if the line is not the last one
166
+ if (q !== questions[questions.length - 1]) {
167
+ // Simulate pressing Shift + Enter to add a new line
168
+ yield page.keyboard.down("Shift");
169
+ yield page.keyboard.press("Enter");
170
+ yield page.keyboard.up("Shift");
171
+ }
172
+ }
173
+ });
174
+ }
175
+ /**
176
+ * Clicks the submit button in ChatGPT interface, trying different button variants.
177
+ *
178
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
179
+ * @returns {Promise<void>} Resolves when the submit button is clicked or attempt is made.
180
+ */
181
+ function clickSubmitButton(page) {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ try {
184
+ const fruitjuiceSendButton = yield page.evaluate(() => {
185
+ return document.querySelector('[data-testid="fruitjuice-send-button"]') !== null;
186
+ });
187
+ const sendButton = yield page.evaluate(() => {
188
+ return document.querySelector('[data-testid="send-button"]') !== null;
189
+ });
190
+ if (fruitjuiceSendButton) {
191
+ yield page.click('[data-testid="fruitjuice-send-button"]');
192
+ }
193
+ else if (sendButton) {
194
+ yield page.click('[data-testid="send-button"]');
195
+ }
196
+ else {
197
+ console.log("Neither send button is present");
198
+ }
199
+ }
200
+ catch (e) {
201
+ console.log(`Failed to click the send button: ${e}`);
202
+ }
203
+ });
204
+ }
205
+ let lastMessageId = null;
206
+ let messageCount = 0;
207
+ const is_streaming = false; // Set to true if you want to stream the response
208
+ /**
209
+ * Creates a promise that resolves after a specified number of milliseconds.
210
+ *
211
+ * @param {number} ms - The number of milliseconds to wait.
212
+ * @returns {Promise<void>} A promise that resolves after the specified delay.
213
+ */
214
+ function sleep(ms) {
215
+ return new Promise((resolve) => setTimeout(resolve, ms));
216
+ }
217
+ /**
218
+ * Waits for the initial assistant response to appear and finish thinking.
219
+ *
220
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
221
+ * @param {number} [timeout=30000] - Maximum time to wait for the response (ms).
222
+ * @returns {Promise<void>} Resolves when the initial response is ready.
223
+ */
224
+ function waitForInitialResponse(page_1) {
225
+ return __awaiter(this, arguments, void 0, function* (page, timeout = 30000) {
226
+ const startTime = Date.now();
227
+ while (Date.now() - startTime < timeout) {
228
+ const assistantMessages = yield page.$$('[data-message-author-role="assistant"]');
229
+ const currentMessageCount = assistantMessages.length;
230
+ if (currentMessageCount > messageCount) {
231
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
232
+ const isThinking = yield lastMessage.$(".result-thinking");
233
+ if (!isThinking) {
234
+ lastMessageId = yield page.evaluate((element) => element.getAttribute("data-message-id"), lastMessage);
235
+ messageCount = currentMessageCount;
236
+ return;
237
+ }
238
+ }
239
+ yield sleep(100);
240
+ }
241
+ console.log("Timed out waiting for the initial response.");
242
+ });
243
+ }
244
+ /**
245
+ * Handles streaming response from the assistant, printing output as it arrives.
246
+ *
247
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
248
+ * @param {string} [outputFile] - Path to save the response. Defaults to tmp/response.txt.
249
+ * @returns {Promise<void>} Resolves when streaming is complete.
250
+ */
251
+ function handleStreamingResponse(page_1) {
252
+ return __awaiter(this, arguments, void 0, function* (page, outputFile = upath_1.default.join(process.cwd(), "tmp/response.txt")) {
253
+ let previousText = "";
254
+ let completeResponse = "";
255
+ let newContentDetected = false;
256
+ while (!newContentDetected) {
257
+ const assistantMessages = yield page.$$('[data-message-author-role="assistant"]');
258
+ if (assistantMessages.length > 0) {
259
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
260
+ const currentMessageId = yield page.evaluate((element) => element.getAttribute("data-message-id"), lastMessage);
261
+ if (currentMessageId === lastMessageId) {
262
+ const currentText = yield page.evaluate((element) => element.textContent, lastMessage);
263
+ console.log(`Current text: ${currentText}`);
264
+ if (currentText !== previousText) {
265
+ if (is_streaming) {
266
+ process.stdout.write(currentText.slice(previousText.length));
267
+ }
268
+ else {
269
+ completeResponse += currentText.slice(previousText.length);
270
+ }
271
+ }
272
+ previousText = currentText;
273
+ const isStreaming = yield lastMessage.$(".result-streaming");
274
+ if (!isStreaming) {
275
+ newContentDetected = true;
276
+ }
277
+ }
278
+ else {
279
+ lastMessageId = currentMessageId;
280
+ }
281
+ }
282
+ yield sleep(100);
283
+ }
284
+ if (!is_streaming) {
285
+ console.log(completeResponse.trim());
286
+ console.log("\n\n");
287
+ fs_extra_1.default.ensureDirSync(upath_1.default.dirname(outputFile));
288
+ fs_extra_1.default.writeFileSync(outputFile, completeResponse.trim());
289
+ console.log(`Response saved to ${outputFile}`);
290
+ }
291
+ });
292
+ }
293
+ /**
294
+ * Checks if the user is logged into ChatGPT by checking if login button exists and is visible.
295
+ *
296
+ * @param {import('puppeteer').Page} page - Puppeteer page instance.
297
+ * @returns {Promise<boolean>} True if logged in (no visible login button), false if not logged in.
298
+ */
299
+ function isLoggedIn(page) {
300
+ return __awaiter(this, void 0, void 0, function* () {
301
+ const result = yield page.evaluate(() => {
302
+ const loginButton = document.querySelector('[data-testid="login-button"]');
303
+ // User is NOT logged in if login button exists and is visible
304
+ return !(loginButton && loginButton.offsetParent !== null);
305
+ });
306
+ // Ensure we always return a boolean
307
+ return result === true;
308
+ });
309
+ }
310
+ /**
311
+ * Creates a new Puppeteer browser instance with StealthPlugin enabled.
312
+ *
313
+ * @param {Parameters<import("puppeteer-extra").VanillaPuppeteer["launch"]>[0]} [browserOptions={}] - Browser launch options.
314
+ * @returns {Promise<import("puppeteer-extra").Browser>} The created browser instance.
315
+ */
316
+ function createBrowser() {
317
+ return __awaiter(this, arguments, void 0, function* (browserOptions = {}) {
318
+ /**
319
+ * @type {Parameters<import("puppeteer-extra").VanillaPuppeteer["launch"]>[0]}
320
+ */
321
+ const defaultOptions = Object.assign({ headless: false, userDataDir: upath_1.default.join(process.cwd(), "tmp/puppeteer-profile"),
322
+ // Windows-specific options to handle browser launch issues
323
+ args: [
324
+ "--no-sandbox",
325
+ "--disable-setuid-sandbox",
326
+ "--disable-dev-shm-usage",
327
+ "--disable-accelerated-2d-canvas",
328
+ "--no-first-run",
329
+ "--no-zygote",
330
+ "--disable-gpu",
331
+ "--disable-background-timer-throttling",
332
+ "--disable-backgrounding-occluded-windows",
333
+ "--disable-renderer-backgrounding"
334
+ ], ignoreDefaultArgs: ["--disable-extensions"] }, (process.platform === "win32" && {
335
+ // Additional Windows-specific options
336
+ executablePath: undefined // Let Puppeteer find Chrome automatically
337
+ }));
338
+ try {
339
+ return yield puppeteer_extra_1.default.use((0, puppeteer_extra_plugin_stealth_1.default)()).launch(Object.assign(Object.assign({}, defaultOptions), browserOptions));
340
+ }
341
+ catch (_error) {
342
+ console.error("Failed to launch browser with default options. Trying fallback options...");
343
+ // Fallback: Try with minimal options
344
+ try {
345
+ return yield puppeteer_extra_1.default.use((0, puppeteer_extra_plugin_stealth_1.default)()).launch(Object.assign({ headless: browserOptions.headless || false, args: ["--no-sandbox", "--disable-setuid-sandbox"], ignoreDefaultArgs: false }, browserOptions));
346
+ }
347
+ catch (fallbackError) {
348
+ console.error("Browser launch failed completely. Common solutions:");
349
+ console.error("1. Install Google Chrome if not installed");
350
+ console.error("2. Update Node.js to the latest version");
351
+ console.error("3. Try running: npm install puppeteer --force");
352
+ console.error("4. Check if antivirus is blocking browser launch");
353
+ throw new Error(`Browser launch failed: ${fallbackError.message}`);
354
+ }
355
+ }
356
+ });
357
+ }
358
+ /**
359
+ * Handles the login process for ChatGPT by launching a browser and clicking the login button if needed.
360
+ *
361
+ * @returns {Promise<void>} Resolves when the login process is complete.
362
+ */
363
+ function loginToChatGpt() {
364
+ return __awaiter(this, void 0, void 0, function* () {
365
+ const browser = yield createBrowser({ headless: false });
366
+ const page = (yield browser.pages()).length > 0 ? (yield browser.pages())[0] : yield browser.newPage();
367
+ const url = "https://chat.openai.com";
368
+ const navigate = yield navigatePage(page, url);
369
+ // Wait for page to fully load before checking login status
370
+ yield navigate.waitForDomIdle(2000, 10000);
371
+ // Check if the login button exists
372
+ const loginButtonExists = yield page.evaluate(() => {
373
+ return document.querySelector('[data-testid="login-button"]') !== null;
374
+ });
375
+ if (loginButtonExists) {
376
+ console.log("Login button found, clicking to log in...");
377
+ yield page.click('[data-testid="login-button"]');
378
+ // Wait for the login process to complete
379
+ yield page.waitForNavigation({ waitUntil: "networkidle0" });
380
+ console.log("Login process completed.");
381
+ }
382
+ else {
383
+ console.log("No login required - user appears to be already logged in.");
384
+ }
385
+ });
386
+ }
387
+ /**
388
+ * Automates ChatGPT interactions using Puppeteer. Can send text questions or upload files to ChatGPT.
389
+ *
390
+ * @param {Object} [chatgptOptions={}] - Configuration options for ChatGPT automation.
391
+ * @param {boolean} [chatgptOptions.headless=true] - Whether to run the browser in headless mode.
392
+ * @param {string} [chatgptOptions.question] - Text question to send to ChatGPT. Either question or questionFile must be provided.
393
+ * @param {string} [chatgptOptions.questionFile] - Path to a file to upload to ChatGPT. Either question or questionFile must be provided.
394
+ * @param {string} [chatgptOptions.responseFile] - Path to save the response. Defaults to tmp/response.txt.
395
+ * @returns {Promise<void>} Resolves when the ChatGPT interaction is complete. Responses are logged to console and saved to specified file.
396
+ * @throws {Error} Throws an error if neither question nor questionFile is provided.
397
+ *
398
+ * @example
399
+ * // Send a text question
400
+ * await runChatGpt({
401
+ * headless: false,
402
+ * question: "What is the capital of France?"
403
+ * });
404
+ *
405
+ * @example
406
+ * // Upload a file for analysis
407
+ * await runChatGpt({
408
+ * headless: false,
409
+ * questionFile: "./path/to/document.txt"
410
+ * });
411
+ */
412
+ function runChatGpt() {
413
+ return __awaiter(this, arguments, void 0, function* (chatgptOptions = {}) {
414
+ const headless = chatgptOptions.headless !== undefined ? chatgptOptions.headless : true;
415
+ const questionFile = chatgptOptions.questionFile;
416
+ let question = chatgptOptions.question;
417
+ const responseFile = chatgptOptions.responseFile || upath_1.default.join(process.cwd(), "tmp", "response.txt");
418
+ // Validate input parameters
419
+ const noInputProvided = !question && !questionFile;
420
+ const questionIsEmpty = question && question.trim().length === 0;
421
+ const questionFileIsEmpty = questionFile && questionFile.trim().length === 0;
422
+ if (noInputProvided || questionIsEmpty || questionFileIsEmpty) {
423
+ throw new Error("You must provide a question or a question file.");
424
+ }
425
+ let browser;
426
+ try {
427
+ browser = yield createBrowser({ headless });
428
+ }
429
+ catch (error) {
430
+ console.error("Error running ChatGPT:", error);
431
+ console.error("\nTroubleshooting steps:");
432
+ console.error("1. Make sure Google Chrome is installed");
433
+ console.error("2. Try running: yarn add puppeteer --force");
434
+ console.error("3. Check if your antivirus is blocking the browser");
435
+ console.error("4. Close any running Chrome instances and try again");
436
+ throw error;
437
+ }
438
+ /** @type {import('puppeteer').Page} */
439
+ const page = (yield browser.pages()).length > 0 ? (yield browser.pages())[0] : yield browser.newPage();
440
+ try {
441
+ const url = "https://chat.openai.com";
442
+ const navigate = yield navigatePage(page, url);
443
+ // Check temporary chat - wait for page to load and try to click temporary chat button
444
+ yield navigate.waitForDomIdle(2000, 15000);
445
+ try {
446
+ const tempChatButton = yield page.$('button[aria-label="Turn on temporary chat"]');
447
+ if (tempChatButton) {
448
+ yield page.evaluate((el) => el.click(), tempChatButton);
449
+ console.log("Successfully clicked temporary chat button");
450
+ yield navigate.waitForDomIdle(1000, 10000);
451
+ }
452
+ else {
453
+ console.log("Temporary chat button not found, proceeding without it.");
454
+ }
455
+ }
456
+ catch (error) {
457
+ console.log(`Failed to click temporary chat button: ${error.message}`);
458
+ }
459
+ if (question) {
460
+ yield writeQuestion(page, question);
461
+ // Submit the question
462
+ yield clickSubmitButton(page);
463
+ yield navigate.waitForDomIdle(1000, 30000); // Wait for DOM to stabilize
464
+ // Wait for the initial response
465
+ yield waitForInitialResponse(page);
466
+ // Handle the streaming response
467
+ yield handleStreamingResponse(page, responseFile);
468
+ // Save cookies for this host at the end
469
+ yield saveCookies(page, getCookiePathForUrl(url));
470
+ }
471
+ else if (questionFile) {
472
+ // Wait for page to fully load before checking login status
473
+ yield navigate.waitForDomIdle(2000, 10000);
474
+ // Check if logged in
475
+ const isUserLoggedIn = yield isLoggedIn(page);
476
+ console.log(`Login status: ${isUserLoggedIn ? "Logged in" : "Not logged in"}`);
477
+ if (!isUserLoggedIn) {
478
+ console.log("Not logged in. Please log in to ChatGPT in the browser window, then close it and run the command again.");
479
+ return loginToChatGpt();
480
+ }
481
+ // Upload the question file
482
+ const plusButtonExists = yield page.evaluate(() => {
483
+ const button = document.querySelector('[data-testid="composer-plus-btn"]');
484
+ return button !== null;
485
+ });
486
+ if (plusButtonExists) {
487
+ yield page.click('[data-testid="composer-plus-btn"]');
488
+ yield sleep(500); // Wait for the menu to open
489
+ const menuItems = yield page.$$('[role="menuitem"]');
490
+ let clicked = false;
491
+ for (const item of menuItems) {
492
+ const text = yield page.evaluate((el) => el.innerText, item);
493
+ if (text && text.includes("Add photos") && text.includes("files")) {
494
+ yield item.hover();
495
+ clicked = true;
496
+ break;
497
+ }
498
+ }
499
+ if (!clicked) {
500
+ console.log('Could not find the "Add photos & files" menu item.');
501
+ return;
502
+ }
503
+ // Wait for file input to appear and upload the file
504
+ try {
505
+ yield sleep(1000); // Wait for file dialog to be ready
506
+ // Look for the file input element
507
+ const fileInput = yield page.waitForSelector('input[type="file"]', { timeout: 10000 });
508
+ if (fileInput) {
509
+ console.log(`Uploading file: ${questionFile}`);
510
+ yield fileInput.uploadFile(questionFile);
511
+ // Wait for the file to be processed
512
+ yield navigate.waitForDomIdle(2000, 15000);
513
+ console.log("File uploaded successfully");
514
+ // Optionally submit after file upload
515
+ yield clickSubmitButton(page);
516
+ yield navigate.waitForDomIdle(1000, 30000);
517
+ // Wait for and handle response
518
+ yield waitForInitialResponse(page);
519
+ yield handleStreamingResponse(page, responseFile);
520
+ }
521
+ else {
522
+ console.log("Could not find file input element");
523
+ }
524
+ }
525
+ catch (error) {
526
+ console.log(`Error uploading file: ${error.message}`);
527
+ }
528
+ }
529
+ else {
530
+ console.log('Could not find the [data-testid="composer-plus-btn"] button.');
531
+ }
532
+ }
533
+ }
534
+ finally {
535
+ // Always close the browser, even if an error occurred
536
+ if (browser) {
537
+ yield browser.close();
538
+ }
539
+ }
540
+ });
541
+ }
@@ -0,0 +1,8 @@
1
+ import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
+ import {
3
+ runChatGpt
4
+ } from "../chunk-GJTGHXRA.mjs";
5
+ import "../chunk-QQ4A6DLD.mjs";
6
+ export {
7
+ runChatGpt
8
+ };
@@ -1,4 +1,4 @@
1
- // src/utils.js
1
+ // src/utils/index.cjs
2
2
  var fs = require("fs");
3
3
  var path = require("upath");
4
4
  var argv = require("minimist")(process.argv.slice(2));
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  require_utils
4
- } from "./chunk-APBWENF6.mjs";
5
- import "./chunk-AASHBCRW.mjs";
4
+ } from "../chunk-V3N3JEUF.mjs";
5
+ import "../chunk-QQ4A6DLD.mjs";
6
6
  export default require_utils();