binary-collections 2.0.10 → 2.0.12

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 (290) hide show
  1. package/.opencode/package.json +5 -0
  2. package/.puppeterrc.cjs +25 -0
  3. package/binaries/binary-executor.cjs +138 -3
  4. package/binaries/clean-nodemodule.cjs +138 -3
  5. package/binaries/clean-nodemodules.cjs +138 -3
  6. package/binaries/dev.cjs +138 -3
  7. package/binaries/empty.cjs +138 -3
  8. package/binaries/git-reduce-size.cjs +138 -3
  9. package/binaries/javakill.cjs +138 -3
  10. package/binaries/kill-night-crows.bat +7 -0
  11. package/binaries/kill-night-crows.ps1 +172 -0
  12. package/binaries/kill-process.cjs +138 -3
  13. package/binaries/nodekill.cjs +138 -3
  14. package/binaries/prod.cjs +138 -3
  15. package/binaries/py +111 -0
  16. package/binaries/py.cjs +178 -0
  17. package/binaries/py.cmd +49 -0
  18. package/binaries/rmfind.cjs +138 -3
  19. package/binaries/rmx +15 -1
  20. package/binaries/rmx.cjs +138 -3
  21. package/binaries/rmx.cmd +12 -0
  22. package/binaries/submodule-token.cjs +138 -3
  23. package/binaries/test-cjs +18 -0
  24. package/binaries/test-cjs.cjs +178 -0
  25. package/binaries/test-cjs.cmd +26 -0
  26. package/binaries/test-esm +16 -0
  27. package/binaries/test-esm.cjs +178 -0
  28. package/binaries/test-esm.cmd +23 -0
  29. package/binaries/yarn-clean +32 -0
  30. package/binaries/yarn-clean.cjs +178 -0
  31. package/binaries/yarn-clean.cmd +30 -0
  32. package/binaries/yarn-clean.py +166 -0
  33. package/binaries/yc +110 -0
  34. package/binaries/yc.cjs +178 -0
  35. package/lib/binary-collections/config.cjs +126 -0
  36. package/lib/binary-collections/config.mjs +7 -0
  37. package/lib/binary-collections/executeScript.cjs +19 -0
  38. package/lib/binary-collections/executeScript.d.cts +12 -0
  39. package/lib/binary-collections/executeScript.mjs +6 -0
  40. package/lib/binary-collections/findScript.cjs +284 -0
  41. package/lib/binary-collections/findScript.d.cts +12 -0
  42. package/lib/binary-collections/findScript.mjs +7 -0
  43. package/lib/binary-collections/listScript.cjs +266 -0
  44. package/lib/binary-collections/listScript.d.cts +19 -0
  45. package/lib/binary-collections/listScript.mjs +7 -0
  46. package/lib/binary-collections.cjs +342 -194
  47. package/lib/binary-collections.mjs +22 -268
  48. package/lib/changelog.cjs +61 -13
  49. package/lib/changelog.mjs +1 -1
  50. package/lib/{chunk-E6FDDAOO.mjs → chunk-2LSRSEXF.mjs} +2 -2
  51. package/lib/chunk-34IQDTLZ.mjs +27 -0
  52. package/lib/chunk-3HFFECCI.mjs +27 -0
  53. package/lib/{chunk-V3N3JEUF.mjs → chunk-5RTXZVCW.mjs} +60 -13
  54. package/lib/chunk-66KDU4TX.mjs +268 -0
  55. package/lib/chunk-6PU7BAHB.mjs +61 -0
  56. package/lib/{chunk-6HHJRKFB.mjs → chunk-BZWVHODJ.mjs} +4 -1
  57. package/lib/chunk-C6D2TTYU.mjs +32 -0
  58. package/lib/chunk-FB2WKVJD.mjs +158 -0
  59. package/lib/{chunk-66PAU5PS.mjs → chunk-G5UUEWUO.mjs} +9 -5
  60. package/lib/{chunk-HO6GHCOB.mjs → chunk-GAGABICI.mjs} +198 -63
  61. package/lib/chunk-H44UWUFY.mjs +105 -0
  62. package/lib/chunk-NCZPTKDV.mjs +79 -0
  63. package/lib/chunk-NGFK3EYW.mjs +28 -0
  64. package/lib/chunk-NVEG3LEZ.mjs +143 -0
  65. package/lib/chunk-OGXVGBRI.mjs +29 -0
  66. package/lib/chunk-OXV52GD5.mjs +62 -0
  67. package/lib/{chunk-PDSXF5HY.mjs → chunk-PDN26I7O.mjs} +1 -0
  68. package/lib/chunk-PXBMHE7O.mjs +35 -0
  69. package/lib/chunk-R5FJOR63.mjs +47 -0
  70. package/lib/chunk-SPTECFE5.mjs +180 -0
  71. package/lib/chunk-UXCFNAR6.mjs +55 -0
  72. package/lib/chunk-V2IBPCEV.mjs +39 -0
  73. package/lib/chunk-XPJGCDOD.mjs +14 -0
  74. package/lib/{chunk-AI4CVPJ7.mjs → chunk-ZDMWBSYF.mjs} +4 -4
  75. package/lib/chunk-ZOWVMII3.mjs +228 -0
  76. package/lib/clean-github-actions-caches-cli.cjs +465 -0
  77. package/lib/clean-github-actions-caches-cli.d.cts +1 -0
  78. package/lib/clean-github-actions-caches-cli.mjs +56 -0
  79. package/lib/clean-github-actions-caches.cjs +152 -160
  80. package/lib/clean-github-actions-caches.d.cts +15 -1
  81. package/lib/clean-github-actions-caches.mjs +4 -130
  82. package/lib/cross-env/command.cjs +63 -0
  83. package/lib/cross-env/command.d.ts +8 -0
  84. package/lib/cross-env/command.js +45 -0
  85. package/lib/cross-env/command.mjs +9 -0
  86. package/lib/cross-env/index.cjs +178 -0
  87. package/lib/cross-env/index.d.ts +8 -0
  88. package/lib/cross-env/index.js +102 -0
  89. package/lib/cross-env/index.mjs +101 -0
  90. package/lib/cross-env/variable.cjs +60 -0
  91. package/lib/cross-env/variable.d.ts +7 -0
  92. package/lib/cross-env/variable.js +59 -0
  93. package/lib/cross-env/variable.mjs +9 -0
  94. package/lib/del-gradle.cjs +61 -13
  95. package/lib/del-gradle.js +9 -8
  96. package/lib/del-gradle.mjs +1 -1
  97. package/lib/del-node-modules.cjs +143 -148
  98. package/lib/del-node-modules.js +210 -14
  99. package/lib/del-node-modules.mjs +148 -17
  100. package/lib/del-ps.cjs +61 -13
  101. package/lib/del-ps.js +9 -8
  102. package/lib/del-ps.mjs +1 -1
  103. package/lib/del-yarn-caches.cjs +61 -13
  104. package/lib/del-yarn-caches.js +2 -2
  105. package/lib/del-yarn-caches.mjs +1 -1
  106. package/lib/file/copy-cli.cjs +92 -0
  107. package/lib/file/copy-cli.d.mts +1 -0
  108. package/lib/file/copy-cli.mjs +55 -0
  109. package/lib/file/copy.cjs +56 -0
  110. package/lib/file/copy.d.mts +1 -0
  111. package/lib/file/copy.mjs +8 -0
  112. package/lib/file/move-cli.cjs +91 -0
  113. package/lib/file/move-cli.d.mts +1 -0
  114. package/lib/file/move-cli.mjs +55 -0
  115. package/lib/file/move.cjs +55 -0
  116. package/lib/file/move.d.mts +1 -0
  117. package/lib/file/move.mjs +8 -0
  118. package/lib/find-node-modules-cli.js +2 -1
  119. package/lib/free-chatgpt.cjs +259 -47
  120. package/lib/free-chatgpt.js +10 -10
  121. package/lib/free-chatgpt.mjs +2 -2
  122. package/lib/git/gitattributes.cjs +1 -0
  123. package/lib/git/gitattributes.d.cts +7 -2
  124. package/lib/git/gitattributes.mjs +1 -1
  125. package/lib/git/line-endings.cjs +2 -1
  126. package/lib/git/line-endings.mjs +2 -2
  127. package/lib/git/undo-commit-cli.cjs +110 -0
  128. package/lib/git/undo-commit-cli.d.ts +1 -0
  129. package/lib/git/undo-commit-cli.js +4 -0
  130. package/lib/git/undo-commit-cli.mjs +14 -0
  131. package/lib/git/undo-commit.cjs +81 -0
  132. package/lib/git/undo-commit.d.cts +1 -0
  133. package/lib/git/undo-commit.mjs +7 -0
  134. package/lib/git/undo-staged-cli.cjs +110 -0
  135. package/lib/git/undo-staged-cli.d.ts +1 -0
  136. package/lib/git/undo-staged-cli.js +4 -0
  137. package/lib/git/undo-staged-cli.mjs +14 -0
  138. package/lib/git/undo-staged.cjs +81 -0
  139. package/lib/git/undo-staged.d.cts +1 -0
  140. package/lib/git/undo-staged.mjs +7 -0
  141. package/lib/git/user-config.cjs +61 -14
  142. package/lib/git/user-config.mjs +2 -2
  143. package/lib/git-diff-cli.cjs +427 -75
  144. package/lib/git-diff-cli.d.ts +1 -0
  145. package/lib/git-diff-cli.js +1 -0
  146. package/lib/git-diff-cli.mjs +6 -4
  147. package/lib/git-diff.cjs +426 -75
  148. package/lib/git-diff.d.ts +2 -1
  149. package/lib/git-diff.js +91 -34
  150. package/lib/git-diff.mjs +5 -4
  151. package/lib/git-fix.cjs +64 -16
  152. package/lib/git-fix.mjs +10 -10
  153. package/lib/git-purge.cjs +61 -13
  154. package/lib/git-purge.mjs +1 -1
  155. package/lib/index.d.ts +1 -1
  156. package/lib/kill-night-crows.cjs +87 -0
  157. package/lib/kill-night-crows.d.mts +1 -0
  158. package/lib/kill-night-crows.mjs +65 -0
  159. package/lib/node-cache-cleaner/npm.cjs +65 -0
  160. package/lib/node-cache-cleaner/npm.d.ts +2 -0
  161. package/lib/node-cache-cleaner/npm.js +41 -0
  162. package/lib/node-cache-cleaner/npm.mjs +10 -0
  163. package/lib/node-cache-cleaner/npx.cjs +89 -0
  164. package/lib/node-cache-cleaner/npx.d.ts +4 -0
  165. package/lib/node-cache-cleaner/npx.js +82 -0
  166. package/lib/{ps/index.d.mjs → node-cache-cleaner/npx.mjs} +6 -5
  167. package/lib/node-cache-cleaner/yarn.cjs +73 -0
  168. package/lib/node-cache-cleaner/yarn.d.ts +2 -0
  169. package/lib/node-cache-cleaner/yarn.js +62 -0
  170. package/lib/node-cache-cleaner/yarn.mjs +10 -0
  171. package/lib/node-cache-cleaner-cli.cjs +182 -0
  172. package/lib/node-cache-cleaner-cli.d.ts +2 -0
  173. package/lib/node-cache-cleaner-cli.js +60 -0
  174. package/lib/node-cache-cleaner-cli.mjs +56 -0
  175. package/lib/node-executor.cjs +91 -0
  176. package/lib/node-executor.d.cts +2 -0
  177. package/lib/node-executor.mjs +103 -0
  178. package/lib/npm-run-series.cjs +79 -39
  179. package/lib/npm-run-series.mjs +20 -6
  180. package/lib/package-resolutions-updater-cli.cjs +645 -0
  181. package/lib/package-resolutions-updater-cli.d.mts +1 -0
  182. package/lib/package-resolutions-updater-cli.mjs +102 -0
  183. package/lib/package-resolutions-updater.cjs +259 -133
  184. package/lib/package-resolutions-updater.d.mts +51 -1
  185. package/lib/package-resolutions-updater.mjs +18 -294
  186. package/lib/php-cs-fixer-staged.cjs +105 -0
  187. package/lib/php-cs-fixer-staged.d.cts +2 -0
  188. package/lib/php-cs-fixer-staged.mjs +117 -0
  189. package/lib/print-directory-tree.cjs +62 -14
  190. package/lib/print-directory-tree.mjs +2 -2
  191. package/lib/ps/connected-domain.d.ts +1 -1
  192. package/lib/ps/connected-domain.js +10 -10
  193. package/lib/ps/index.cjs +1 -1
  194. package/lib/ps/index.mjs +177 -171
  195. package/lib/ps/isWin.js +1 -1
  196. package/lib/ps/table-parser.js +6 -6
  197. package/lib/remove-module.cjs +61 -13
  198. package/lib/remove-module.mjs +1 -1
  199. package/lib/rm-node-module-cli.cjs +222 -0
  200. package/lib/rm-node-module-cli.d.cts +1 -0
  201. package/lib/rm-node-module-cli.mjs +89 -0
  202. package/lib/rm-node-modules.cjs +127 -0
  203. package/lib/rm-node-modules.d.cts +35 -0
  204. package/lib/{binary-collections-config.mjs → rm-node-modules.mjs} +3 -3
  205. package/lib/rmpath.cjs +63 -15
  206. package/lib/rmpath.mjs +2 -2
  207. package/lib/submodule-install.cjs +107 -47
  208. package/lib/submodule-install.mjs +48 -35
  209. package/lib/submodule-remove-cli.cjs +6 -3
  210. package/lib/submodule-remove-cli.js +3 -3
  211. package/lib/submodule-remove-cli.mjs +2 -3
  212. package/lib/submodule-remove.cjs +4 -1
  213. package/lib/submodule-remove.mjs +1 -1
  214. package/lib/utils/chatgpt.cjs +198 -34
  215. package/lib/utils/chatgpt.js +260 -93
  216. package/lib/utils/chatgpt.mjs +1 -1
  217. package/lib/utils/findEnvFiles.cjs +89 -0
  218. package/lib/utils/findEnvFiles.d.cts +19 -0
  219. package/lib/utils/findEnvFiles.mjs +6 -0
  220. package/lib/utils/findWorkspaceRoot.cjs +70 -0
  221. package/lib/utils/findWorkspaceRoot.d.ts +9 -0
  222. package/lib/utils/findWorkspaceRoot.js +57 -0
  223. package/lib/utils/findWorkspaceRoot.mjs +40 -0
  224. package/lib/utils/index.cjs +60 -13
  225. package/lib/utils/index.mjs +1 -1
  226. package/lib/utils/isGithubTokenValid.cjs +64 -0
  227. package/lib/utils/isGithubTokenValid.d.ts +7 -0
  228. package/lib/utils/isGithubTokenValid.js +48 -0
  229. package/lib/utils/isGithubTokenValid.mjs +36 -0
  230. package/lib/{ps/index.d.cjs → utils/isWindows.cjs} +17 -3
  231. package/lib/utils/isWindows.d.ts +5 -0
  232. package/lib/utils/isWindows.js +10 -0
  233. package/lib/utils/isWindows.mjs +8 -0
  234. package/lib/utils/runBash.cjs +53 -0
  235. package/lib/utils/runBash.d.cts +12 -0
  236. package/lib/utils/runBash.mjs +66 -0
  237. package/lib/yarn-per-branch-lock-installer.cjs +97 -0
  238. package/lib/yarn-per-branch-lock-installer.d.cts +2 -0
  239. package/lib/yarn-per-branch-lock-installer.mjs +109 -0
  240. package/lib/yarn-reinstall.cjs +61 -13
  241. package/lib/yarn-reinstall.mjs +1 -1
  242. package/package.json +133 -110
  243. package/readme.html +784 -0
  244. package/readme.md +116 -229
  245. package/releases/readme.md +1 -1
  246. package/requirements.txt +1 -0
  247. package/test/README.md +2 -2
  248. package/test-project/package.json +8 -2
  249. package/test-project/workspaces/workspace-a/package.json +135 -0
  250. package/test-project/workspaces/workspace-a/readme.md +20 -0
  251. package/test-project/workspaces/workspace-a/release/readme.md +42 -0
  252. package/test-project/workspaces/workspace-a/test/demo/package.json +25 -0
  253. package/test-project/workspaces/workspace-a/test/readme.md +12 -0
  254. package/test-project/workspaces/workspace-b/package.json +139 -0
  255. package/test-project/workspaces/workspace-b/readme.md +94 -0
  256. package/test-project/workspaces/workspace-b/requirements.txt +1 -0
  257. package/test-project/workspaces/workspace-b/test/sample-project/package.json +7 -0
  258. package/test-project/workspaces/workspace-b/themes/hexo-theme-flowbite/package.json +96 -0
  259. package/test-project/workspaces/workspace-b/themes/hexo-theme-flowbite/readme.md +156 -0
  260. package/tmp/rm-node-modules-test-project/package.json +17 -0
  261. package/tmp/rm-node-modules-test-project/packages/workspace-a/package.json +16 -0
  262. package/tmp/rm-node-modules-test-project/packages/workspace-b/package.json +16 -0
  263. package/tmp/test-repo/README.md +2 -35
  264. package/tmp/test-repo/package.json +13 -3
  265. package/docs-src/clean-github-actions-caches.md +0 -26
  266. package/docs-src/free-chatgpt.md +0 -26
  267. package/lib/binary-collections-config.cjs +0 -15
  268. package/lib/chunk-4EWQC6GZ.mjs +0 -382
  269. package/lib/chunk-4ZI7BQKQ.mjs +0 -381
  270. package/lib/chunk-5J2BEPY5.mjs +0 -83
  271. package/lib/chunk-AGZYRDC2.mjs +0 -323
  272. package/lib/chunk-BDCHCWHD.mjs +0 -136
  273. package/lib/chunk-BEZKJ25G.mjs +0 -140
  274. package/lib/chunk-DI5MDPSN.mjs +0 -386
  275. package/lib/chunk-GJTGHXRA.mjs +0 -356
  276. package/lib/chunk-HMRMTYZM.mjs +0 -40
  277. package/lib/chunk-HN52G2YL.mjs +0 -305
  278. package/lib/chunk-LEM5OMRP.mjs +0 -384
  279. package/lib/chunk-O6SWBEOQ.mjs +0 -81
  280. package/lib/chunk-RCP7DHVY.mjs +0 -190
  281. package/lib/chunk-SBNDSKG5.mjs +0 -136
  282. package/lib/chunk-U6SO4QEV.mjs +0 -320
  283. package/lib/chunk-XD6BJK6Q.mjs +0 -351
  284. package/lib/chunk-YXSFGA2D.mjs +0 -383
  285. package/lib/git/gitattributes.d.ts +0 -33
  286. package/lib/git/gitattributes.js +0 -223
  287. package/lib/ps/index.d.ts +0 -2
  288. package/lib/ps/index.js +0 -253
  289. package/tmp/typedoc/readme.md +0 -320
  290. /package/lib/{binary-collections-config.d.cts → binary-collections/config.d.cts} +0 -0
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env node
1
2
  var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -31,17 +32,113 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
31
32
  var getImportMetaUrl, importMetaUrl;
32
33
  var init_cjs_shims = __esm({
33
34
  "node_modules/tsup/assets/cjs_shims.js"() {
34
- getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
35
+ getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
35
36
  importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
36
37
  }
37
38
  });
38
39
 
39
- // src/binary-collections-config.cjs
40
- var require_binary_collections_config = __commonJS({
41
- "src/binary-collections-config.cjs"(exports2, module2) {
40
+ // src/utils/findEnvFiles.cjs
41
+ var require_findEnvFiles = __commonJS({
42
+ "src/utils/findEnvFiles.cjs"(exports2, module2) {
42
43
  init_cjs_shims();
44
+ var fs3 = require("fs");
43
45
  var path3 = require("path");
44
- require("dotenv").config({ path: path3.join(process.cwd(), ".env") });
46
+ var glob = require("glob");
47
+ var DEFAULT_IGNORES = [
48
+ "**/node_modules/**",
49
+ "**/.git/**",
50
+ "**/.yarn/**",
51
+ "**/.pnpm/**",
52
+ "**/dist/**",
53
+ "**/build/**",
54
+ "**/coverage/**",
55
+ "**/vendor/**",
56
+ "**/tmp/**",
57
+ "**/.cache/**",
58
+ "**/assets/**",
59
+ "**/logs/**",
60
+ "**/output/**",
61
+ "**/public/**",
62
+ "**/static/**",
63
+ "**/temp/**",
64
+ "**/backup/**",
65
+ "**/backups/**",
66
+ "**/examples/**",
67
+ "**/docs/**",
68
+ "**/tests/**",
69
+ "**/__tests__/**",
70
+ "**/spec/**",
71
+ "**/__specs__/**",
72
+ "**/scripts/**",
73
+ "**/bin/**",
74
+ "**/hooks/**",
75
+ "**/config/**",
76
+ "**/configs/**",
77
+ "**/settings/**",
78
+ "**/.vscode/**",
79
+ "**/.idea/**"
80
+ ];
81
+ function findEnvFiles(startDir = process.cwd(), filter) {
82
+ const found = /* @__PURE__ */ new Set();
83
+ function addFile(file) {
84
+ const normalized = path3.normalize(file);
85
+ if (typeof filter === "function" && !filter(normalized)) {
86
+ return;
87
+ }
88
+ found.add(normalized);
89
+ }
90
+ let current = path3.resolve(startDir);
91
+ while (true) {
92
+ const envPath = path3.join(current, ".env");
93
+ if (fs3.existsSync(envPath)) {
94
+ addFile(envPath);
95
+ }
96
+ const parent = path3.dirname(current);
97
+ if (parent === current) {
98
+ break;
99
+ }
100
+ current = parent;
101
+ }
102
+ const files = glob.globSync("**/.env*", {
103
+ cwd: startDir,
104
+ absolute: true,
105
+ nodir: true,
106
+ ignore: DEFAULT_IGNORES
107
+ });
108
+ for (const file of files) {
109
+ addFile(file);
110
+ }
111
+ return [...found];
112
+ }
113
+ function findEnvWithToken(startDir = process.cwd(), tokenName = "GITHUB_TOKEN") {
114
+ const envFiles = findEnvFiles(startDir);
115
+ return envFiles.find((file) => {
116
+ try {
117
+ const content = fs3.readFileSync(file, "utf-8");
118
+ const regex = new RegExp(`^\\s*${tokenName}\\s*=`, "m");
119
+ return regex.test(content);
120
+ } catch (err) {
121
+ console.warn(`Failed to read ${file}: ${err instanceof Error ? err.message : String(err)}`);
122
+ return false;
123
+ }
124
+ });
125
+ }
126
+ module2.exports = {
127
+ DEFAULT_IGNORES,
128
+ findEnvFiles,
129
+ findEnvWithToken,
130
+ default: findEnvFiles
131
+ };
132
+ }
133
+ });
134
+
135
+ // src/binary-collections/config.cjs
136
+ var require_config = __commonJS({
137
+ "src/binary-collections/config.cjs"(exports2, module2) {
138
+ init_cjs_shims();
139
+ var path3 = require("path");
140
+ var { findEnvWithToken } = require_findEnvFiles();
141
+ require("dotenv").config({ path: findEnvWithToken(), quiet: true, overwrite: true });
45
142
  function getTempDir() {
46
143
  return process.env.TEMP_DIR || path3.join(process.cwd(), "tmp");
47
144
  }
@@ -112,31 +209,78 @@ var require_utils = __commonJS({
112
209
  }
113
210
  module2.exports.getArgs = getArgs2;
114
211
  function del(fullPath) {
115
- if (fs3.statSync(fullPath).isDirectory()) {
116
- const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
117
- for (let i = 0; i < subdir.length; i++) {
118
- del(subdir[i]);
212
+ try {
213
+ if (!fs3.existsSync(fullPath)) return;
214
+ const stat = fs3.lstatSync(fullPath);
215
+ if (stat.isSymbolicLink()) {
216
+ try {
217
+ fs3.unlinkSync(fullPath);
218
+ console.log("deleted symlink", fullPath);
219
+ } catch (e) {
220
+ console.log("failed delete symlink", fullPath, e && e.message);
221
+ }
222
+ return;
223
+ }
224
+ if (stat.isDirectory()) {
225
+ const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
226
+ for (let i = 0; i < subdir.length; i++) {
227
+ del(subdir[i]);
228
+ }
229
+ try {
230
+ fs3.rmdirSync(fullPath);
231
+ console.log("deleted", fullPath);
232
+ } catch (_e) {
233
+ try {
234
+ fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
235
+ console.log("deleted", fullPath);
236
+ } catch (ee) {
237
+ console.log("failed delete", fullPath, ee && ee.message);
238
+ }
239
+ }
240
+ return;
119
241
  }
120
- } else {
121
242
  try {
122
- fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
243
+ fs3.unlinkSync(fullPath);
123
244
  console.log("deleted", fullPath);
124
- } catch (_) {
125
- console.log("failed delete", fullPath);
245
+ } catch (_e) {
246
+ try {
247
+ fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
248
+ console.log("deleted", fullPath);
249
+ } catch (ee) {
250
+ console.log("failed delete", fullPath, ee && ee.message);
251
+ }
126
252
  }
253
+ } catch (err) {
254
+ console.log("failed delete", fullPath, err && err.message);
127
255
  }
128
256
  }
129
257
  module2.exports.del = del;
130
258
  function delStream(globStream) {
131
259
  globStream.stream().on("data", (result) => {
132
260
  const fullPath = path3.resolve(process.cwd(), result);
133
- if (fs3.statSync(fullPath).isDirectory()) {
134
- const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
135
- for (let i = 0; i < subdir.length; i++) {
136
- del(subdir[i]);
261
+ try {
262
+ if (fs3.existsSync(fullPath)) {
263
+ const stat = fs3.lstatSync(fullPath);
264
+ if (stat.isSymbolicLink()) {
265
+ try {
266
+ fs3.unlinkSync(fullPath);
267
+ console.log("deleted symlink", fullPath);
268
+ } catch (e) {
269
+ console.log("failed delete symlink", fullPath, e && e.message);
270
+ }
271
+ return;
272
+ }
273
+ if (stat.isDirectory()) {
274
+ const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
275
+ for (let i = 0; i < subdir.length; i++) {
276
+ del(subdir[i]);
277
+ }
278
+ }
137
279
  }
280
+ del(fullPath);
281
+ } catch (err) {
282
+ console.log("failed processing", fullPath, err && err.message);
138
283
  }
139
- del(fullPath);
140
284
  });
141
285
  }
142
286
  module2.exports.delStream = delStream;
@@ -187,11 +331,13 @@ init_cjs_shims();
187
331
 
188
332
  // src/git-diff.js
189
333
  init_cjs_shims();
334
+ var import_ansi_colors = __toESM(require("ansi-colors"), 1);
190
335
  var import_child_process = require("child_process");
191
336
  var import_fs_extra2 = __toESM(require("fs-extra"), 1);
337
+ var import_sbg_utility = require("sbg-utility");
192
338
  var import_upath2 = __toESM(require("upath"), 1);
193
339
  var import_url = require("url");
194
- var import_binary_collections_config = __toESM(require_binary_collections_config(), 1);
340
+ var import_config = __toESM(require_config(), 1);
195
341
 
196
342
  // src/utils/chatgpt.js
197
343
  init_cjs_shims();
@@ -201,7 +347,17 @@ var import_puppeteer_extra_plugin_stealth = __toESM(require("puppeteer-extra-plu
201
347
  var import_upath = __toESM(require("upath"), 1);
202
348
  var COOKIE_DIR = import_upath.default.join(process.cwd(), "tmp", "cookies");
203
349
  var DEFAULT_COOKIE_PATH = import_upath.default.join(COOKIE_DIR, "cookies.json");
350
+ var NAVIGATION_TIMEOUT_MS = 9e4;
351
+ var NETWORK_IDLE_TIMEOUT_MS = 15e3;
352
+ var MAX_INLINE_QUESTION_FILE_BYTES = 2 * 1024;
204
353
  import_fs_extra.default.ensureDirSync(COOKIE_DIR);
354
+ async function gotoWithFallback(page, url) {
355
+ await page.goto(url, { waitUntil: "domcontentloaded", timeout: NAVIGATION_TIMEOUT_MS });
356
+ try {
357
+ await page.waitForNetworkIdle({ idleTime: 1e3, timeout: NETWORK_IDLE_TIMEOUT_MS });
358
+ } catch {
359
+ }
360
+ }
205
361
  async function saveCookies(page, path3 = DEFAULT_COOKIE_PATH) {
206
362
  const cookies = await page.cookies();
207
363
  import_fs_extra.default.writeFileSync(path3, JSON.stringify(cookies, null, 2));
@@ -220,7 +376,7 @@ async function navigatePage(page, url) {
220
376
  if (cookies) {
221
377
  await page.setCookie(...cookies);
222
378
  }
223
- await page.goto(url, { waitUntil: "networkidle0" });
379
+ await gotoWithFallback(page, url);
224
380
  await page.evaluate(() => {
225
381
  window.__domStillUpdating = true;
226
382
  if (window.__domObserver) {
@@ -260,46 +416,157 @@ function loadCookies(cookieFilePath = DEFAULT_COOKIE_PATH) {
260
416
  return JSON.parse(import_fs_extra.default.readFileSync(cookieFilePath));
261
417
  }
262
418
  async function writeQuestion(page, question) {
263
- const questions = question.split("\n");
264
419
  const promptTextarea = await page.waitForSelector("#prompt-textarea", { timeout: 3e4 });
265
420
  if (!promptTextarea) {
266
421
  console.log(
267
422
  "Cannot find the prompt input on the webpage. Please check whether you have access to chat.openai.com without logging in via your browser."
268
423
  );
269
- }
270
- await page.evaluate(() => {
271
- document.querySelector("#prompt-textarea").innerHTML = `<p></p>`;
272
- });
273
- if (questions.length === 1) {
274
- await page.type("#prompt-textarea", questions[0], { delay: 100 });
275
424
  return;
276
425
  }
277
- for (const q of questions) {
278
- await page.type("#prompt-textarea", q, { delay: 100 });
279
- if (q !== questions[questions.length - 1]) {
280
- await page.keyboard.down("Shift");
281
- await page.keyboard.press("Enter");
282
- await page.keyboard.up("Shift");
426
+ await page.evaluate((text) => {
427
+ const promptEl = document.querySelector("#prompt-textarea");
428
+ if (!promptEl) {
429
+ return;
430
+ }
431
+ promptEl.focus();
432
+ promptEl.innerHTML = "";
433
+ const lines = String(text).split("\n");
434
+ for (const line of lines) {
435
+ const p = document.createElement("p");
436
+ p.textContent = line;
437
+ promptEl.appendChild(p);
283
438
  }
439
+ promptEl.dispatchEvent(new InputEvent("beforeinput", { bubbles: true, inputType: "insertFromPaste", data: text }));
440
+ promptEl.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertFromPaste", data: text }));
441
+ promptEl.dispatchEvent(new Event("change", { bubbles: true }));
442
+ }, question);
443
+ const hasPromptText = await page.evaluate(() => {
444
+ const promptEl = document.querySelector("#prompt-textarea");
445
+ return Boolean(promptEl && promptEl.textContent && promptEl.textContent.trim().length > 0);
446
+ });
447
+ if (!hasPromptText) {
448
+ console.log("Prompt state not updated by DOM injection. Falling back to keyboard insertText.");
449
+ await promptTextarea.click({ clickCount: 1 });
450
+ await page.keyboard.down("Control");
451
+ await page.keyboard.press("KeyA");
452
+ await page.keyboard.up("Control");
453
+ await page.keyboard.insertText(question);
284
454
  }
285
455
  }
286
456
  async function clickSubmitButton(page) {
457
+ console.log("Attempting to click the submit button...");
287
458
  try {
288
- const fruitjuiceSendButton = await page.evaluate(() => {
289
- return document.querySelector('[data-testid="fruitjuice-send-button"]') !== null;
459
+ const userMessageCountBefore = await page.$$eval(
460
+ '[data-message-author-role="user"]',
461
+ (elements) => elements.length
462
+ );
463
+ const waitForSubmit = async (timeout = 5e3) => {
464
+ try {
465
+ await page.waitForFunction(
466
+ (previousCount) => {
467
+ const currentCount = document.querySelectorAll('[data-message-author-role="user"]').length;
468
+ return currentCount > previousCount;
469
+ },
470
+ { timeout },
471
+ userMessageCountBefore
472
+ );
473
+ return true;
474
+ } catch {
475
+ return false;
476
+ }
477
+ };
478
+ await page.waitForFunction(
479
+ () => {
480
+ const candidates = [
481
+ document.querySelector('[data-testid="fruitjuice-send-button"]'),
482
+ document.querySelector("#composer-submit-button"),
483
+ document.querySelector('[data-testid="send-button"]')
484
+ ].filter(Boolean);
485
+ return candidates.some((button) => {
486
+ const isDisabled = button.disabled || button.getAttribute("aria-disabled") === "true";
487
+ const isVisible = button.offsetParent !== null;
488
+ return !isDisabled && isVisible;
489
+ });
490
+ },
491
+ { timeout: 5e3 }
492
+ ).catch(() => {
290
493
  });
291
- const sendButton = await page.evaluate(() => {
292
- return document.querySelector('[data-testid="send-button"]') !== null;
494
+ const buttonDetails = await page.evaluate(() => {
495
+ const selectors = [
496
+ '[data-testid="fruitjuice-send-button"]',
497
+ "#composer-submit-button",
498
+ '[data-testid="send-button"]'
499
+ ];
500
+ const details = selectors.map((selector) => {
501
+ const el = document.querySelector(selector);
502
+ const exists = Boolean(el);
503
+ const disabled = exists ? Boolean(el.disabled || el.getAttribute("aria-disabled") === "true") : null;
504
+ const visible = exists ? el.offsetParent !== null : null;
505
+ return { selector, exists, disabled, visible };
506
+ });
507
+ return details;
293
508
  });
294
- if (fruitjuiceSendButton) {
295
- await page.click('[data-testid="fruitjuice-send-button"]');
296
- } else if (sendButton) {
297
- await page.click('[data-testid="send-button"]');
298
- } else {
299
- console.log("Neither send button is present");
509
+ console.log(`Submit button details: ${JSON.stringify(buttonDetails)}`);
510
+ const clickable = buttonDetails.find((item) => item.exists && item.visible && item.disabled === false);
511
+ const selectedSelector = clickable ? clickable.selector : null;
512
+ if (selectedSelector) {
513
+ await page.click(selectedSelector);
514
+ console.log(`Clicked submit button selector: ${selectedSelector}`);
515
+ if (await waitForSubmit(5e3)) {
516
+ console.log("Submission detected after selector click.");
517
+ return true;
518
+ }
519
+ const forcedClickWorked = await page.evaluate((selector) => {
520
+ const el = document.querySelector(selector);
521
+ if (!el) {
522
+ return false;
523
+ }
524
+ el.click();
525
+ return true;
526
+ }, selectedSelector);
527
+ if (forcedClickWorked) {
528
+ console.log(`Forced DOM click on selector: ${selectedSelector}`);
529
+ if (await waitForSubmit(5e3)) {
530
+ console.log("Submission detected after forced DOM click.");
531
+ return true;
532
+ }
533
+ }
534
+ }
535
+ console.log("Submit button path did not submit. Trying Enter key fallback on prompt.");
536
+ await page.focus("#prompt-textarea");
537
+ await page.keyboard.press("Enter");
538
+ if (await waitForSubmit(5e3)) {
539
+ console.log("Submission detected after Enter key fallback.");
540
+ return true;
541
+ }
542
+ const didRequestSubmit = await page.evaluate(() => {
543
+ const prompt = document.querySelector("#prompt-textarea");
544
+ if (!prompt) {
545
+ return false;
546
+ }
547
+ const form = prompt.closest("form");
548
+ if (!form) {
549
+ return false;
550
+ }
551
+ if (typeof form.requestSubmit === "function") {
552
+ form.requestSubmit();
553
+ } else {
554
+ form.submit();
555
+ }
556
+ return true;
557
+ });
558
+ if (didRequestSubmit) {
559
+ console.log("Triggered form submit fallback.");
560
+ if (await waitForSubmit(5e3)) {
561
+ console.log("Submission detected after form submit fallback.");
562
+ return true;
563
+ }
300
564
  }
565
+ console.log("Failed to submit prompt after all strategies.");
566
+ return false;
301
567
  } catch (e) {
302
568
  console.log(`Failed to click the send button: ${e}`);
569
+ return false;
303
570
  }
304
571
  }
305
572
  var lastMessageId = null;
@@ -372,11 +639,15 @@ async function isLoggedIn(page) {
372
639
  return result === true;
373
640
  }
374
641
  async function createBrowser(browserOptions = {}) {
642
+ const windowsChromeExecutable = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
643
+ const hasWindowsChrome = process.platform === "win32" && import_fs_extra.default.existsSync(windowsChromeExecutable);
375
644
  const defaultOptions = {
376
645
  headless: false,
646
+ defaultViewport: null,
377
647
  userDataDir: import_upath.default.join(process.cwd(), "tmp/puppeteer-profile"),
378
648
  // Windows-specific options to handle browser launch issues
379
649
  args: [
650
+ "--start-maximized",
380
651
  "--no-sandbox",
381
652
  "--disable-setuid-sandbox",
382
653
  "--disable-dev-shm-usage",
@@ -389,10 +660,9 @@ async function createBrowser(browserOptions = {}) {
389
660
  "--disable-renderer-backgrounding"
390
661
  ],
391
662
  ignoreDefaultArgs: ["--disable-extensions"],
392
- ...process.platform === "win32" && {
393
- // Additional Windows-specific options
394
- executablePath: void 0
395
- // Let Puppeteer find Chrome automatically
663
+ ...hasWindowsChrome && {
664
+ // Prefer local Chrome installation when present on Windows.
665
+ executablePath: windowsChromeExecutable
396
666
  }
397
667
  };
398
668
  try {
@@ -402,8 +672,12 @@ async function createBrowser(browserOptions = {}) {
402
672
  try {
403
673
  return await import_puppeteer_extra.default.use((0, import_puppeteer_extra_plugin_stealth.default)()).launch({
404
674
  headless: browserOptions.headless || false,
405
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
675
+ defaultViewport: null,
676
+ args: ["--start-maximized", "--no-sandbox", "--disable-setuid-sandbox"],
406
677
  ignoreDefaultArgs: false,
678
+ ...hasWindowsChrome && {
679
+ executablePath: windowsChromeExecutable
680
+ },
407
681
  ...browserOptions
408
682
  });
409
683
  } catch (fallbackError) {
@@ -428,7 +702,11 @@ async function loginToChatGpt() {
428
702
  if (loginButtonExists) {
429
703
  console.log("Login button found, clicking to log in...");
430
704
  await page.click('[data-testid="login-button"]');
431
- await page.waitForNavigation({ waitUntil: "networkidle0" });
705
+ await page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: NAVIGATION_TIMEOUT_MS });
706
+ try {
707
+ await page.waitForNetworkIdle({ idleTime: 1e3, timeout: NETWORK_IDLE_TIMEOUT_MS });
708
+ } catch {
709
+ }
432
710
  console.log("Login process completed.");
433
711
  } else {
434
712
  console.log("No login required - user appears to be already logged in.");
@@ -438,6 +716,7 @@ async function runChatGpt(chatgptOptions = {}) {
438
716
  const headless = chatgptOptions.headless !== void 0 ? chatgptOptions.headless : true;
439
717
  const questionFile = chatgptOptions.questionFile;
440
718
  let question = chatgptOptions.question;
719
+ let shouldUploadQuestionFile = Boolean(questionFile);
441
720
  const responseFile = chatgptOptions.responseFile || import_upath.default.join(process.cwd(), "tmp", "response.txt");
442
721
  const noInputProvided = !question && !questionFile;
443
722
  const questionIsEmpty = question && question.trim().length === 0;
@@ -445,6 +724,22 @@ async function runChatGpt(chatgptOptions = {}) {
445
724
  if (noInputProvided || questionIsEmpty || questionFileIsEmpty) {
446
725
  throw new Error("You must provide a question or a question file.");
447
726
  }
727
+ if (!question && questionFile) {
728
+ if (!import_fs_extra.default.existsSync(questionFile)) {
729
+ throw new Error(`Question file does not exist: ${questionFile}`);
730
+ }
731
+ const questionFileStats = import_fs_extra.default.statSync(questionFile);
732
+ if (questionFileStats.size <= MAX_INLINE_QUESTION_FILE_BYTES) {
733
+ question = import_fs_extra.default.readFileSync(questionFile, "utf8").trim();
734
+ if (!question) {
735
+ throw new Error("Question file is empty.");
736
+ }
737
+ shouldUploadQuestionFile = false;
738
+ console.log(
739
+ `Question file is ${questionFileStats.size} bytes (<= ${MAX_INLINE_QUESTION_FILE_BYTES}). Sending as text prompt.`
740
+ );
741
+ }
742
+ }
448
743
  let browser;
449
744
  try {
450
745
  browser = await createBrowser({ headless });
@@ -457,7 +752,16 @@ async function runChatGpt(chatgptOptions = {}) {
457
752
  console.error("4. Close any running Chrome instances and try again");
458
753
  throw error;
459
754
  }
460
- const page = (await browser.pages()).length > 0 ? (await browser.pages())[0] : await browser.newPage();
755
+ const allPages = await browser.pages();
756
+ const page = allPages.length > 0 ? allPages[0] : await browser.newPage();
757
+ await page.bringToFront();
758
+ if (allPages.length > 1) {
759
+ for (const p of allPages) {
760
+ if (p !== page) {
761
+ await p.close();
762
+ }
763
+ }
764
+ }
461
765
  try {
462
766
  const url = "https://chat.openai.com";
463
767
  const navigate = await navigatePage(page, url);
@@ -476,12 +780,15 @@ async function runChatGpt(chatgptOptions = {}) {
476
780
  }
477
781
  if (question) {
478
782
  await writeQuestion(page, question);
479
- await clickSubmitButton(page);
783
+ const didSubmit = await clickSubmitButton(page);
784
+ if (!didSubmit) {
785
+ throw new Error("Prompt was not submitted. The composer button may be disabled or blocked.");
786
+ }
480
787
  await navigate.waitForDomIdle(1e3, 3e4);
481
788
  await waitForInitialResponse(page);
482
789
  await handleStreamingResponse(page, responseFile);
483
790
  await saveCookies(page, getCookiePathForUrl(url));
484
- } else if (questionFile) {
791
+ } else if (shouldUploadQuestionFile && questionFile) {
485
792
  await navigate.waitForDomIdle(2e3, 1e4);
486
793
  const isUserLoggedIn = await isLoggedIn(page);
487
794
  console.log(`Login status: ${isUserLoggedIn ? "Logged in" : "Not logged in"}`);
@@ -520,7 +827,10 @@ async function runChatGpt(chatgptOptions = {}) {
520
827
  await fileInput.uploadFile(questionFile);
521
828
  await navigate.waitForDomIdle(2e3, 15e3);
522
829
  console.log("File uploaded successfully");
523
- await clickSubmitButton(page);
830
+ const didSubmit = await clickSubmitButton(page);
831
+ if (!didSubmit) {
832
+ throw new Error("Prompt was not submitted after file upload.");
833
+ }
524
834
  await navigate.waitForDomIdle(1e3, 3e4);
525
835
  await waitForInitialResponse(page);
526
836
  await handleStreamingResponse(page, responseFile);
@@ -545,20 +855,24 @@ async function runChatGpt(chatgptOptions = {}) {
545
855
  var import_utils = __toESM(require_utils(), 1);
546
856
  var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
547
857
  var __dirname = import_upath2.default.dirname(__filename2);
548
- var DIFF_OUTPUT = (0, import_binary_collections_config.getTempPath)("git-diff.txt");
549
- var GPT_DIFF_OUTPUT = (0, import_binary_collections_config.getTempPath)("gpt-question.txt");
858
+ var args = (0, import_utils.getArgs)();
859
+ var positional = args._ || [];
860
+ var FILENAME = (0, import_sbg_utility.md5)((positional[0] || "default") + JSON.stringify(args));
861
+ var DIFF_OUTPUT = (0, import_config.getTempPath)(`git-diff/${FILENAME}.txt`);
862
+ var GPT_DIFF_OUTPUT = (0, import_config.getTempPath)(`git-diff/gpt-${FILENAME}.txt`);
550
863
  var CACHE_DIR = import_upath2.default.dirname(DIFF_OUTPUT);
551
864
  var DIFF_OUTPUT_RELATIVE = import_upath2.default.relative(process.cwd(), DIFF_OUTPUT);
552
865
  var GPT_DIFF_OUTPUT_RELATIVE = import_upath2.default.relative(process.cwd(), GPT_DIFF_OUTPUT);
553
- if (!import_fs_extra2.default.existsSync(CACHE_DIR)) {
554
- import_fs_extra2.default.mkdirSync(CACHE_DIR, { recursive: true });
555
- }
866
+ import_fs_extra2.default.ensureDirSync(CACHE_DIR, { mode: 493 });
556
867
  function showHelp() {
557
868
  console.log("\u{1F4DD} Git Diff Helper");
558
869
  console.log("\u{1F4C4} Usage:");
559
870
  console.log(" \u{1F4C2} git-diff FILE Show staged diff of specified file");
560
871
  console.log(" \u{1F4C2} git-diff --staged-only Show staged diff of all files");
561
872
  console.log(" \u{1F4C2} git-diff -s | -S Same as --staged-only");
873
+ console.log(" \u{1F4C2} git-diff --unstaged FILE Show unstaged diff of specified file");
874
+ console.log(" \u{1F4C2} git-diff --unstaged Show unstaged diff of all files");
875
+ console.log(" \u{1F4C2} git-diff -u Same as --unstaged");
562
876
  console.log(" \u{1F4C2} git-diff --ai Run ChatGPT automation for commit message");
563
877
  console.log(" \u{1F4C2} git-diff --help | -h Show this help message");
564
878
  console.log("");
@@ -575,13 +889,13 @@ function runGitDiff(command, successMessage, errorMessage) {
575
889
  // 10MB buffer to handle large diffs
576
890
  });
577
891
  if (!result || result.trim() === "") {
578
- console.log(`\u2139\uFE0F [i] No changes found for the specified criteria`);
579
- import_fs_extra2.default.writeFileSync(DIFF_OUTPUT, "# No changes found\n");
892
+ console.log(`\u2139\uFE0F [i] No changes found for the specified criteria`);
893
+ (0, import_sbg_utility.writefile)(DIFF_OUTPUT, "# No changes found\n");
580
894
  console.log(`\u2705 Empty diff saved to "${DIFF_OUTPUT_RELATIVE}"`);
581
- return;
895
+ return false;
582
896
  }
583
- import_fs_extra2.default.writeFileSync(DIFF_OUTPUT, result);
584
- import_fs_extra2.default.writeFileSync(
897
+ (0, import_sbg_utility.writefile)(DIFF_OUTPUT, result);
898
+ (0, import_sbg_utility.writefile)(
585
899
  GPT_DIFF_OUTPUT,
586
900
  `Hello, ChatGPT!
587
901
  Can you create a conventional commit message by diff content below:
@@ -594,7 +908,8 @@ Give me result as codeblock with language "text" only.
594
908
  Thank you!`
595
909
  );
596
910
  console.log(`\u2705 ${successMessage}`);
597
- console.log(`\u{1F4BE} GPT diff prompt saved to "${GPT_DIFF_OUTPUT_RELATIVE}"`);
911
+ console.log(`\u{1F4BE} GPT diff prompt saved to "${import_ansi_colors.default.green(GPT_DIFF_OUTPUT_RELATIVE)}"`);
912
+ return true;
598
913
  } catch (error) {
599
914
  console.error(`\u274C ${errorMessage}`);
600
915
  console.error(`\u{1F4DD} Command: ${command}`);
@@ -605,34 +920,71 @@ Thank you!`
605
920
  process.exit(1);
606
921
  }
607
922
  }
923
+ function fileHasChanges(file, mode) {
924
+ const command = mode === "staged" ? `git diff --cached --quiet -- "${file}"` : `git diff --quiet -- "${file}"`;
925
+ try {
926
+ (0, import_child_process.execSync)(command, { stdio: "ignore" });
927
+ return false;
928
+ } catch (error) {
929
+ if (error.status === 1) {
930
+ return true;
931
+ }
932
+ throw error;
933
+ }
934
+ }
608
935
  async function mainGitDiff() {
609
- const args = (0, import_utils.getArgs)();
610
- const positional = args._ || [];
611
936
  if (args.help || args.h) {
612
937
  showHelp();
613
938
  }
939
+ const useUnstaged = args.unstaged || args.u;
940
+ const fileFromFlag = typeof args.unstaged === "string" ? args.unstaged : typeof args.u === "string" ? args.u : null;
941
+ let hasDiff = false;
614
942
  if (args["staged-only"] || args.s || args.S) {
615
- runGitDiff(
943
+ hasDiff = runGitDiff(
616
944
  "git --no-pager diff --staged",
617
- `Full staged diff saved to "${DIFF_OUTPUT_RELATIVE}"`,
945
+ `Full staged diff saved to "${import_ansi_colors.default.green(DIFF_OUTPUT_RELATIVE)}"`,
618
946
  "Failed to save staged diff"
619
947
  );
620
948
  } else {
621
- const file = positional[0];
949
+ const file = positional[0] || fileFromFlag;
622
950
  if (!file) {
623
- runGitDiff(
951
+ const fullDiffModeLabel = useUnstaged ? "unstaged" : "unstaged";
952
+ hasDiff = runGitDiff(
624
953
  "git --no-pager diff",
625
- `Full staged diff saved to "${DIFF_OUTPUT_RELATIVE}"`,
954
+ `Full ${fullDiffModeLabel} diff saved to "${import_ansi_colors.default.green(DIFF_OUTPUT_RELATIVE)}"`,
626
955
  "Failed to save all diff's"
627
956
  );
628
957
  } else {
629
- runGitDiff(
630
- `git --no-pager diff --cached -- "${file}"`,
631
- `Staged diff of "${file}" saved to "${DIFF_OUTPUT_RELATIVE}"`,
632
- `Failed to generate diff for "${file}"`
958
+ let fileDiffMode = useUnstaged ? "unstaged" : "staged";
959
+ if (!useUnstaged && !fileHasChanges(file, "staged") && fileHasChanges(file, "unstaged")) {
960
+ fileDiffMode = "unstaged";
961
+ }
962
+ hasDiff = runGitDiff(
963
+ fileDiffMode === "unstaged" ? `git --no-pager diff -- "${file}"` : `git --no-pager diff --cached -- "${file}"`,
964
+ `${fileDiffMode[0].toUpperCase() + fileDiffMode.slice(1)} diff of "${file}" saved to "${import_ansi_colors.default.green(
965
+ DIFF_OUTPUT_RELATIVE
966
+ )}"`,
967
+ `Failed to generate ${fileDiffMode} diff for "${file}"`
633
968
  );
634
969
  }
635
970
  }
971
+ if (hasDiff) {
972
+ const opencodePrompt = [
973
+ "",
974
+ "\u{1F916} OpenCode Prompt Helper",
975
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
976
+ "",
977
+ "\u{1F4C4} App Prompt:",
978
+ ` Generate a conventional commit message from diff file: ${DIFF_OUTPUT}`,
979
+ "",
980
+ "\u{1F4BB} CLI Command:",
981
+ ` opencode run "Generate a conventional commit message from diff file ${DIFF_OUTPUT}"`,
982
+ ""
983
+ ];
984
+ const opencodePromptPath = (0, import_config.getTempPath)(`git-diff/opencode-${FILENAME}.txt`);
985
+ (0, import_sbg_utility.writefile)(opencodePromptPath, opencodePrompt.join("\n"));
986
+ console.log(`\u{1F4A1} OpenCode prompt saved to "${import_ansi_colors.default.green(import_upath2.default.relative(process.cwd(), opencodePromptPath))}"`);
987
+ }
636
988
  if (args.ai) {
637
989
  try {
638
990
  await runChatGpt({ headless: true, questionFile: GPT_DIFF_OUTPUT });