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
package/lib/git-diff.cjs CHANGED
@@ -37,17 +37,113 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
37
37
  var getImportMetaUrl, importMetaUrl;
38
38
  var init_cjs_shims = __esm({
39
39
  "node_modules/tsup/assets/cjs_shims.js"() {
40
- getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
40
+ 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;
41
41
  importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
42
42
  }
43
43
  });
44
44
 
45
- // src/binary-collections-config.cjs
46
- var require_binary_collections_config = __commonJS({
47
- "src/binary-collections-config.cjs"(exports2, module2) {
45
+ // src/utils/findEnvFiles.cjs
46
+ var require_findEnvFiles = __commonJS({
47
+ "src/utils/findEnvFiles.cjs"(exports2, module2) {
48
48
  init_cjs_shims();
49
+ var fs3 = require("fs");
49
50
  var path3 = require("path");
50
- require("dotenv").config({ path: path3.join(process.cwd(), ".env") });
51
+ var glob = require("glob");
52
+ var DEFAULT_IGNORES = [
53
+ "**/node_modules/**",
54
+ "**/.git/**",
55
+ "**/.yarn/**",
56
+ "**/.pnpm/**",
57
+ "**/dist/**",
58
+ "**/build/**",
59
+ "**/coverage/**",
60
+ "**/vendor/**",
61
+ "**/tmp/**",
62
+ "**/.cache/**",
63
+ "**/assets/**",
64
+ "**/logs/**",
65
+ "**/output/**",
66
+ "**/public/**",
67
+ "**/static/**",
68
+ "**/temp/**",
69
+ "**/backup/**",
70
+ "**/backups/**",
71
+ "**/examples/**",
72
+ "**/docs/**",
73
+ "**/tests/**",
74
+ "**/__tests__/**",
75
+ "**/spec/**",
76
+ "**/__specs__/**",
77
+ "**/scripts/**",
78
+ "**/bin/**",
79
+ "**/hooks/**",
80
+ "**/config/**",
81
+ "**/configs/**",
82
+ "**/settings/**",
83
+ "**/.vscode/**",
84
+ "**/.idea/**"
85
+ ];
86
+ function findEnvFiles(startDir = process.cwd(), filter) {
87
+ const found = /* @__PURE__ */ new Set();
88
+ function addFile(file) {
89
+ const normalized = path3.normalize(file);
90
+ if (typeof filter === "function" && !filter(normalized)) {
91
+ return;
92
+ }
93
+ found.add(normalized);
94
+ }
95
+ let current = path3.resolve(startDir);
96
+ while (true) {
97
+ const envPath = path3.join(current, ".env");
98
+ if (fs3.existsSync(envPath)) {
99
+ addFile(envPath);
100
+ }
101
+ const parent = path3.dirname(current);
102
+ if (parent === current) {
103
+ break;
104
+ }
105
+ current = parent;
106
+ }
107
+ const files = glob.globSync("**/.env*", {
108
+ cwd: startDir,
109
+ absolute: true,
110
+ nodir: true,
111
+ ignore: DEFAULT_IGNORES
112
+ });
113
+ for (const file of files) {
114
+ addFile(file);
115
+ }
116
+ return [...found];
117
+ }
118
+ function findEnvWithToken(startDir = process.cwd(), tokenName = "GITHUB_TOKEN") {
119
+ const envFiles = findEnvFiles(startDir);
120
+ return envFiles.find((file) => {
121
+ try {
122
+ const content = fs3.readFileSync(file, "utf-8");
123
+ const regex = new RegExp(`^\\s*${tokenName}\\s*=`, "m");
124
+ return regex.test(content);
125
+ } catch (err) {
126
+ console.warn(`Failed to read ${file}: ${err instanceof Error ? err.message : String(err)}`);
127
+ return false;
128
+ }
129
+ });
130
+ }
131
+ module2.exports = {
132
+ DEFAULT_IGNORES,
133
+ findEnvFiles,
134
+ findEnvWithToken,
135
+ default: findEnvFiles
136
+ };
137
+ }
138
+ });
139
+
140
+ // src/binary-collections/config.cjs
141
+ var require_config = __commonJS({
142
+ "src/binary-collections/config.cjs"(exports2, module2) {
143
+ init_cjs_shims();
144
+ var path3 = require("path");
145
+ var { findEnvWithToken } = require_findEnvFiles();
146
+ require("dotenv").config({ path: findEnvWithToken(), quiet: true, overwrite: true });
51
147
  function getTempDir() {
52
148
  return process.env.TEMP_DIR || path3.join(process.cwd(), "tmp");
53
149
  }
@@ -118,31 +214,78 @@ var require_utils = __commonJS({
118
214
  }
119
215
  module2.exports.getArgs = getArgs2;
120
216
  function del(fullPath) {
121
- if (fs3.statSync(fullPath).isDirectory()) {
122
- const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
123
- for (let i = 0; i < subdir.length; i++) {
124
- del(subdir[i]);
217
+ try {
218
+ if (!fs3.existsSync(fullPath)) return;
219
+ const stat = fs3.lstatSync(fullPath);
220
+ if (stat.isSymbolicLink()) {
221
+ try {
222
+ fs3.unlinkSync(fullPath);
223
+ console.log("deleted symlink", fullPath);
224
+ } catch (e) {
225
+ console.log("failed delete symlink", fullPath, e && e.message);
226
+ }
227
+ return;
228
+ }
229
+ if (stat.isDirectory()) {
230
+ const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
231
+ for (let i = 0; i < subdir.length; i++) {
232
+ del(subdir[i]);
233
+ }
234
+ try {
235
+ fs3.rmdirSync(fullPath);
236
+ console.log("deleted", fullPath);
237
+ } catch (_e) {
238
+ try {
239
+ fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
240
+ console.log("deleted", fullPath);
241
+ } catch (ee) {
242
+ console.log("failed delete", fullPath, ee && ee.message);
243
+ }
244
+ }
245
+ return;
125
246
  }
126
- } else {
127
247
  try {
128
- fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
248
+ fs3.unlinkSync(fullPath);
129
249
  console.log("deleted", fullPath);
130
- } catch (_) {
131
- console.log("failed delete", fullPath);
250
+ } catch (_e) {
251
+ try {
252
+ fs3.rmSync(fullPath, { recursive: true, force: true, retryDelay: 7e3 });
253
+ console.log("deleted", fullPath);
254
+ } catch (ee) {
255
+ console.log("failed delete", fullPath, ee && ee.message);
256
+ }
132
257
  }
258
+ } catch (err) {
259
+ console.log("failed delete", fullPath, err && err.message);
133
260
  }
134
261
  }
135
262
  module2.exports.del = del;
136
263
  function delStream(globStream) {
137
264
  globStream.stream().on("data", (result) => {
138
265
  const fullPath = path3.resolve(process.cwd(), result);
139
- if (fs3.statSync(fullPath).isDirectory()) {
140
- const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
141
- for (let i = 0; i < subdir.length; i++) {
142
- del(subdir[i]);
266
+ try {
267
+ if (fs3.existsSync(fullPath)) {
268
+ const stat = fs3.lstatSync(fullPath);
269
+ if (stat.isSymbolicLink()) {
270
+ try {
271
+ fs3.unlinkSync(fullPath);
272
+ console.log("deleted symlink", fullPath);
273
+ } catch (e) {
274
+ console.log("failed delete symlink", fullPath, e && e.message);
275
+ }
276
+ return;
277
+ }
278
+ if (stat.isDirectory()) {
279
+ const subdir = fs3.readdirSync(fullPath).map((dirPath) => path3.resolve(fullPath, dirPath));
280
+ for (let i = 0; i < subdir.length; i++) {
281
+ del(subdir[i]);
282
+ }
283
+ }
143
284
  }
285
+ del(fullPath);
286
+ } catch (err) {
287
+ console.log("failed processing", fullPath, err && err.message);
144
288
  }
145
- del(fullPath);
146
289
  });
147
290
  }
148
291
  module2.exports.delStream = delStream;
@@ -202,11 +345,13 @@ __export(git_diff_exports, {
202
345
  });
203
346
  module.exports = __toCommonJS(git_diff_exports);
204
347
  init_cjs_shims();
348
+ var import_ansi_colors = __toESM(require("ansi-colors"), 1);
205
349
  var import_child_process = require("child_process");
206
350
  var import_fs_extra2 = __toESM(require("fs-extra"), 1);
351
+ var import_sbg_utility = require("sbg-utility");
207
352
  var import_upath2 = __toESM(require("upath"), 1);
208
353
  var import_url = require("url");
209
- var import_binary_collections_config = __toESM(require_binary_collections_config(), 1);
354
+ var import_config = __toESM(require_config(), 1);
210
355
 
211
356
  // src/utils/chatgpt.js
212
357
  init_cjs_shims();
@@ -216,7 +361,17 @@ var import_puppeteer_extra_plugin_stealth = __toESM(require("puppeteer-extra-plu
216
361
  var import_upath = __toESM(require("upath"), 1);
217
362
  var COOKIE_DIR = import_upath.default.join(process.cwd(), "tmp", "cookies");
218
363
  var DEFAULT_COOKIE_PATH = import_upath.default.join(COOKIE_DIR, "cookies.json");
364
+ var NAVIGATION_TIMEOUT_MS = 9e4;
365
+ var NETWORK_IDLE_TIMEOUT_MS = 15e3;
366
+ var MAX_INLINE_QUESTION_FILE_BYTES = 2 * 1024;
219
367
  import_fs_extra.default.ensureDirSync(COOKIE_DIR);
368
+ async function gotoWithFallback(page, url) {
369
+ await page.goto(url, { waitUntil: "domcontentloaded", timeout: NAVIGATION_TIMEOUT_MS });
370
+ try {
371
+ await page.waitForNetworkIdle({ idleTime: 1e3, timeout: NETWORK_IDLE_TIMEOUT_MS });
372
+ } catch {
373
+ }
374
+ }
220
375
  async function saveCookies(page, path3 = DEFAULT_COOKIE_PATH) {
221
376
  const cookies = await page.cookies();
222
377
  import_fs_extra.default.writeFileSync(path3, JSON.stringify(cookies, null, 2));
@@ -235,7 +390,7 @@ async function navigatePage(page, url) {
235
390
  if (cookies) {
236
391
  await page.setCookie(...cookies);
237
392
  }
238
- await page.goto(url, { waitUntil: "networkidle0" });
393
+ await gotoWithFallback(page, url);
239
394
  await page.evaluate(() => {
240
395
  window.__domStillUpdating = true;
241
396
  if (window.__domObserver) {
@@ -275,46 +430,157 @@ function loadCookies(cookieFilePath = DEFAULT_COOKIE_PATH) {
275
430
  return JSON.parse(import_fs_extra.default.readFileSync(cookieFilePath));
276
431
  }
277
432
  async function writeQuestion(page, question) {
278
- const questions = question.split("\n");
279
433
  const promptTextarea = await page.waitForSelector("#prompt-textarea", { timeout: 3e4 });
280
434
  if (!promptTextarea) {
281
435
  console.log(
282
436
  "Cannot find the prompt input on the webpage. Please check whether you have access to chat.openai.com without logging in via your browser."
283
437
  );
284
- }
285
- await page.evaluate(() => {
286
- document.querySelector("#prompt-textarea").innerHTML = `<p></p>`;
287
- });
288
- if (questions.length === 1) {
289
- await page.type("#prompt-textarea", questions[0], { delay: 100 });
290
438
  return;
291
439
  }
292
- for (const q of questions) {
293
- await page.type("#prompt-textarea", q, { delay: 100 });
294
- if (q !== questions[questions.length - 1]) {
295
- await page.keyboard.down("Shift");
296
- await page.keyboard.press("Enter");
297
- await page.keyboard.up("Shift");
440
+ await page.evaluate((text) => {
441
+ const promptEl = document.querySelector("#prompt-textarea");
442
+ if (!promptEl) {
443
+ return;
444
+ }
445
+ promptEl.focus();
446
+ promptEl.innerHTML = "";
447
+ const lines = String(text).split("\n");
448
+ for (const line of lines) {
449
+ const p = document.createElement("p");
450
+ p.textContent = line;
451
+ promptEl.appendChild(p);
298
452
  }
453
+ promptEl.dispatchEvent(new InputEvent("beforeinput", { bubbles: true, inputType: "insertFromPaste", data: text }));
454
+ promptEl.dispatchEvent(new InputEvent("input", { bubbles: true, inputType: "insertFromPaste", data: text }));
455
+ promptEl.dispatchEvent(new Event("change", { bubbles: true }));
456
+ }, question);
457
+ const hasPromptText = await page.evaluate(() => {
458
+ const promptEl = document.querySelector("#prompt-textarea");
459
+ return Boolean(promptEl && promptEl.textContent && promptEl.textContent.trim().length > 0);
460
+ });
461
+ if (!hasPromptText) {
462
+ console.log("Prompt state not updated by DOM injection. Falling back to keyboard insertText.");
463
+ await promptTextarea.click({ clickCount: 1 });
464
+ await page.keyboard.down("Control");
465
+ await page.keyboard.press("KeyA");
466
+ await page.keyboard.up("Control");
467
+ await page.keyboard.insertText(question);
299
468
  }
300
469
  }
301
470
  async function clickSubmitButton(page) {
471
+ console.log("Attempting to click the submit button...");
302
472
  try {
303
- const fruitjuiceSendButton = await page.evaluate(() => {
304
- return document.querySelector('[data-testid="fruitjuice-send-button"]') !== null;
473
+ const userMessageCountBefore = await page.$$eval(
474
+ '[data-message-author-role="user"]',
475
+ (elements) => elements.length
476
+ );
477
+ const waitForSubmit = async (timeout = 5e3) => {
478
+ try {
479
+ await page.waitForFunction(
480
+ (previousCount) => {
481
+ const currentCount = document.querySelectorAll('[data-message-author-role="user"]').length;
482
+ return currentCount > previousCount;
483
+ },
484
+ { timeout },
485
+ userMessageCountBefore
486
+ );
487
+ return true;
488
+ } catch {
489
+ return false;
490
+ }
491
+ };
492
+ await page.waitForFunction(
493
+ () => {
494
+ const candidates = [
495
+ document.querySelector('[data-testid="fruitjuice-send-button"]'),
496
+ document.querySelector("#composer-submit-button"),
497
+ document.querySelector('[data-testid="send-button"]')
498
+ ].filter(Boolean);
499
+ return candidates.some((button) => {
500
+ const isDisabled = button.disabled || button.getAttribute("aria-disabled") === "true";
501
+ const isVisible = button.offsetParent !== null;
502
+ return !isDisabled && isVisible;
503
+ });
504
+ },
505
+ { timeout: 5e3 }
506
+ ).catch(() => {
305
507
  });
306
- const sendButton = await page.evaluate(() => {
307
- return document.querySelector('[data-testid="send-button"]') !== null;
508
+ const buttonDetails = await page.evaluate(() => {
509
+ const selectors = [
510
+ '[data-testid="fruitjuice-send-button"]',
511
+ "#composer-submit-button",
512
+ '[data-testid="send-button"]'
513
+ ];
514
+ const details = selectors.map((selector) => {
515
+ const el = document.querySelector(selector);
516
+ const exists = Boolean(el);
517
+ const disabled = exists ? Boolean(el.disabled || el.getAttribute("aria-disabled") === "true") : null;
518
+ const visible = exists ? el.offsetParent !== null : null;
519
+ return { selector, exists, disabled, visible };
520
+ });
521
+ return details;
308
522
  });
309
- if (fruitjuiceSendButton) {
310
- await page.click('[data-testid="fruitjuice-send-button"]');
311
- } else if (sendButton) {
312
- await page.click('[data-testid="send-button"]');
313
- } else {
314
- console.log("Neither send button is present");
523
+ console.log(`Submit button details: ${JSON.stringify(buttonDetails)}`);
524
+ const clickable = buttonDetails.find((item) => item.exists && item.visible && item.disabled === false);
525
+ const selectedSelector = clickable ? clickable.selector : null;
526
+ if (selectedSelector) {
527
+ await page.click(selectedSelector);
528
+ console.log(`Clicked submit button selector: ${selectedSelector}`);
529
+ if (await waitForSubmit(5e3)) {
530
+ console.log("Submission detected after selector click.");
531
+ return true;
532
+ }
533
+ const forcedClickWorked = await page.evaluate((selector) => {
534
+ const el = document.querySelector(selector);
535
+ if (!el) {
536
+ return false;
537
+ }
538
+ el.click();
539
+ return true;
540
+ }, selectedSelector);
541
+ if (forcedClickWorked) {
542
+ console.log(`Forced DOM click on selector: ${selectedSelector}`);
543
+ if (await waitForSubmit(5e3)) {
544
+ console.log("Submission detected after forced DOM click.");
545
+ return true;
546
+ }
547
+ }
548
+ }
549
+ console.log("Submit button path did not submit. Trying Enter key fallback on prompt.");
550
+ await page.focus("#prompt-textarea");
551
+ await page.keyboard.press("Enter");
552
+ if (await waitForSubmit(5e3)) {
553
+ console.log("Submission detected after Enter key fallback.");
554
+ return true;
555
+ }
556
+ const didRequestSubmit = await page.evaluate(() => {
557
+ const prompt = document.querySelector("#prompt-textarea");
558
+ if (!prompt) {
559
+ return false;
560
+ }
561
+ const form = prompt.closest("form");
562
+ if (!form) {
563
+ return false;
564
+ }
565
+ if (typeof form.requestSubmit === "function") {
566
+ form.requestSubmit();
567
+ } else {
568
+ form.submit();
569
+ }
570
+ return true;
571
+ });
572
+ if (didRequestSubmit) {
573
+ console.log("Triggered form submit fallback.");
574
+ if (await waitForSubmit(5e3)) {
575
+ console.log("Submission detected after form submit fallback.");
576
+ return true;
577
+ }
315
578
  }
579
+ console.log("Failed to submit prompt after all strategies.");
580
+ return false;
316
581
  } catch (e) {
317
582
  console.log(`Failed to click the send button: ${e}`);
583
+ return false;
318
584
  }
319
585
  }
320
586
  var lastMessageId = null;
@@ -387,11 +653,15 @@ async function isLoggedIn(page) {
387
653
  return result === true;
388
654
  }
389
655
  async function createBrowser(browserOptions = {}) {
656
+ const windowsChromeExecutable = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
657
+ const hasWindowsChrome = process.platform === "win32" && import_fs_extra.default.existsSync(windowsChromeExecutable);
390
658
  const defaultOptions = {
391
659
  headless: false,
660
+ defaultViewport: null,
392
661
  userDataDir: import_upath.default.join(process.cwd(), "tmp/puppeteer-profile"),
393
662
  // Windows-specific options to handle browser launch issues
394
663
  args: [
664
+ "--start-maximized",
395
665
  "--no-sandbox",
396
666
  "--disable-setuid-sandbox",
397
667
  "--disable-dev-shm-usage",
@@ -404,10 +674,9 @@ async function createBrowser(browserOptions = {}) {
404
674
  "--disable-renderer-backgrounding"
405
675
  ],
406
676
  ignoreDefaultArgs: ["--disable-extensions"],
407
- ...process.platform === "win32" && {
408
- // Additional Windows-specific options
409
- executablePath: void 0
410
- // Let Puppeteer find Chrome automatically
677
+ ...hasWindowsChrome && {
678
+ // Prefer local Chrome installation when present on Windows.
679
+ executablePath: windowsChromeExecutable
411
680
  }
412
681
  };
413
682
  try {
@@ -417,8 +686,12 @@ async function createBrowser(browserOptions = {}) {
417
686
  try {
418
687
  return await import_puppeteer_extra.default.use((0, import_puppeteer_extra_plugin_stealth.default)()).launch({
419
688
  headless: browserOptions.headless || false,
420
- args: ["--no-sandbox", "--disable-setuid-sandbox"],
689
+ defaultViewport: null,
690
+ args: ["--start-maximized", "--no-sandbox", "--disable-setuid-sandbox"],
421
691
  ignoreDefaultArgs: false,
692
+ ...hasWindowsChrome && {
693
+ executablePath: windowsChromeExecutable
694
+ },
422
695
  ...browserOptions
423
696
  });
424
697
  } catch (fallbackError) {
@@ -443,7 +716,11 @@ async function loginToChatGpt() {
443
716
  if (loginButtonExists) {
444
717
  console.log("Login button found, clicking to log in...");
445
718
  await page.click('[data-testid="login-button"]');
446
- await page.waitForNavigation({ waitUntil: "networkidle0" });
719
+ await page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: NAVIGATION_TIMEOUT_MS });
720
+ try {
721
+ await page.waitForNetworkIdle({ idleTime: 1e3, timeout: NETWORK_IDLE_TIMEOUT_MS });
722
+ } catch {
723
+ }
447
724
  console.log("Login process completed.");
448
725
  } else {
449
726
  console.log("No login required - user appears to be already logged in.");
@@ -453,6 +730,7 @@ async function runChatGpt(chatgptOptions = {}) {
453
730
  const headless = chatgptOptions.headless !== void 0 ? chatgptOptions.headless : true;
454
731
  const questionFile = chatgptOptions.questionFile;
455
732
  let question = chatgptOptions.question;
733
+ let shouldUploadQuestionFile = Boolean(questionFile);
456
734
  const responseFile = chatgptOptions.responseFile || import_upath.default.join(process.cwd(), "tmp", "response.txt");
457
735
  const noInputProvided = !question && !questionFile;
458
736
  const questionIsEmpty = question && question.trim().length === 0;
@@ -460,6 +738,22 @@ async function runChatGpt(chatgptOptions = {}) {
460
738
  if (noInputProvided || questionIsEmpty || questionFileIsEmpty) {
461
739
  throw new Error("You must provide a question or a question file.");
462
740
  }
741
+ if (!question && questionFile) {
742
+ if (!import_fs_extra.default.existsSync(questionFile)) {
743
+ throw new Error(`Question file does not exist: ${questionFile}`);
744
+ }
745
+ const questionFileStats = import_fs_extra.default.statSync(questionFile);
746
+ if (questionFileStats.size <= MAX_INLINE_QUESTION_FILE_BYTES) {
747
+ question = import_fs_extra.default.readFileSync(questionFile, "utf8").trim();
748
+ if (!question) {
749
+ throw new Error("Question file is empty.");
750
+ }
751
+ shouldUploadQuestionFile = false;
752
+ console.log(
753
+ `Question file is ${questionFileStats.size} bytes (<= ${MAX_INLINE_QUESTION_FILE_BYTES}). Sending as text prompt.`
754
+ );
755
+ }
756
+ }
463
757
  let browser;
464
758
  try {
465
759
  browser = await createBrowser({ headless });
@@ -472,7 +766,16 @@ async function runChatGpt(chatgptOptions = {}) {
472
766
  console.error("4. Close any running Chrome instances and try again");
473
767
  throw error;
474
768
  }
475
- const page = (await browser.pages()).length > 0 ? (await browser.pages())[0] : await browser.newPage();
769
+ const allPages = await browser.pages();
770
+ const page = allPages.length > 0 ? allPages[0] : await browser.newPage();
771
+ await page.bringToFront();
772
+ if (allPages.length > 1) {
773
+ for (const p of allPages) {
774
+ if (p !== page) {
775
+ await p.close();
776
+ }
777
+ }
778
+ }
476
779
  try {
477
780
  const url = "https://chat.openai.com";
478
781
  const navigate = await navigatePage(page, url);
@@ -491,12 +794,15 @@ async function runChatGpt(chatgptOptions = {}) {
491
794
  }
492
795
  if (question) {
493
796
  await writeQuestion(page, question);
494
- await clickSubmitButton(page);
797
+ const didSubmit = await clickSubmitButton(page);
798
+ if (!didSubmit) {
799
+ throw new Error("Prompt was not submitted. The composer button may be disabled or blocked.");
800
+ }
495
801
  await navigate.waitForDomIdle(1e3, 3e4);
496
802
  await waitForInitialResponse(page);
497
803
  await handleStreamingResponse(page, responseFile);
498
804
  await saveCookies(page, getCookiePathForUrl(url));
499
- } else if (questionFile) {
805
+ } else if (shouldUploadQuestionFile && questionFile) {
500
806
  await navigate.waitForDomIdle(2e3, 1e4);
501
807
  const isUserLoggedIn = await isLoggedIn(page);
502
808
  console.log(`Login status: ${isUserLoggedIn ? "Logged in" : "Not logged in"}`);
@@ -535,7 +841,10 @@ async function runChatGpt(chatgptOptions = {}) {
535
841
  await fileInput.uploadFile(questionFile);
536
842
  await navigate.waitForDomIdle(2e3, 15e3);
537
843
  console.log("File uploaded successfully");
538
- await clickSubmitButton(page);
844
+ const didSubmit = await clickSubmitButton(page);
845
+ if (!didSubmit) {
846
+ throw new Error("Prompt was not submitted after file upload.");
847
+ }
539
848
  await navigate.waitForDomIdle(1e3, 3e4);
540
849
  await waitForInitialResponse(page);
541
850
  await handleStreamingResponse(page, responseFile);
@@ -560,20 +869,24 @@ async function runChatGpt(chatgptOptions = {}) {
560
869
  var import_utils = __toESM(require_utils(), 1);
561
870
  var __filename2 = (0, import_url.fileURLToPath)(importMetaUrl);
562
871
  var __dirname = import_upath2.default.dirname(__filename2);
563
- var DIFF_OUTPUT = (0, import_binary_collections_config.getTempPath)("git-diff.txt");
564
- var GPT_DIFF_OUTPUT = (0, import_binary_collections_config.getTempPath)("gpt-question.txt");
872
+ var args = (0, import_utils.getArgs)();
873
+ var positional = args._ || [];
874
+ var FILENAME = (0, import_sbg_utility.md5)((positional[0] || "default") + JSON.stringify(args));
875
+ var DIFF_OUTPUT = (0, import_config.getTempPath)(`git-diff/${FILENAME}.txt`);
876
+ var GPT_DIFF_OUTPUT = (0, import_config.getTempPath)(`git-diff/gpt-${FILENAME}.txt`);
565
877
  var CACHE_DIR = import_upath2.default.dirname(DIFF_OUTPUT);
566
878
  var DIFF_OUTPUT_RELATIVE = import_upath2.default.relative(process.cwd(), DIFF_OUTPUT);
567
879
  var GPT_DIFF_OUTPUT_RELATIVE = import_upath2.default.relative(process.cwd(), GPT_DIFF_OUTPUT);
568
- if (!import_fs_extra2.default.existsSync(CACHE_DIR)) {
569
- import_fs_extra2.default.mkdirSync(CACHE_DIR, { recursive: true });
570
- }
880
+ import_fs_extra2.default.ensureDirSync(CACHE_DIR, { mode: 493 });
571
881
  function showHelp() {
572
882
  console.log("\u{1F4DD} Git Diff Helper");
573
883
  console.log("\u{1F4C4} Usage:");
574
884
  console.log(" \u{1F4C2} git-diff FILE Show staged diff of specified file");
575
885
  console.log(" \u{1F4C2} git-diff --staged-only Show staged diff of all files");
576
886
  console.log(" \u{1F4C2} git-diff -s | -S Same as --staged-only");
887
+ console.log(" \u{1F4C2} git-diff --unstaged FILE Show unstaged diff of specified file");
888
+ console.log(" \u{1F4C2} git-diff --unstaged Show unstaged diff of all files");
889
+ console.log(" \u{1F4C2} git-diff -u Same as --unstaged");
577
890
  console.log(" \u{1F4C2} git-diff --ai Run ChatGPT automation for commit message");
578
891
  console.log(" \u{1F4C2} git-diff --help | -h Show this help message");
579
892
  console.log("");
@@ -590,13 +903,13 @@ function runGitDiff(command, successMessage, errorMessage) {
590
903
  // 10MB buffer to handle large diffs
591
904
  });
592
905
  if (!result || result.trim() === "") {
593
- console.log(`\u2139\uFE0F [i] No changes found for the specified criteria`);
594
- import_fs_extra2.default.writeFileSync(DIFF_OUTPUT, "# No changes found\n");
906
+ console.log(`\u2139\uFE0F [i] No changes found for the specified criteria`);
907
+ (0, import_sbg_utility.writefile)(DIFF_OUTPUT, "# No changes found\n");
595
908
  console.log(`\u2705 Empty diff saved to "${DIFF_OUTPUT_RELATIVE}"`);
596
- return;
909
+ return false;
597
910
  }
598
- import_fs_extra2.default.writeFileSync(DIFF_OUTPUT, result);
599
- import_fs_extra2.default.writeFileSync(
911
+ (0, import_sbg_utility.writefile)(DIFF_OUTPUT, result);
912
+ (0, import_sbg_utility.writefile)(
600
913
  GPT_DIFF_OUTPUT,
601
914
  `Hello, ChatGPT!
602
915
  Can you create a conventional commit message by diff content below:
@@ -609,7 +922,8 @@ Give me result as codeblock with language "text" only.
609
922
  Thank you!`
610
923
  );
611
924
  console.log(`\u2705 ${successMessage}`);
612
- console.log(`\u{1F4BE} GPT diff prompt saved to "${GPT_DIFF_OUTPUT_RELATIVE}"`);
925
+ console.log(`\u{1F4BE} GPT diff prompt saved to "${import_ansi_colors.default.green(GPT_DIFF_OUTPUT_RELATIVE)}"`);
926
+ return true;
613
927
  } catch (error) {
614
928
  console.error(`\u274C ${errorMessage}`);
615
929
  console.error(`\u{1F4DD} Command: ${command}`);
@@ -620,34 +934,71 @@ Thank you!`
620
934
  process.exit(1);
621
935
  }
622
936
  }
937
+ function fileHasChanges(file, mode) {
938
+ const command = mode === "staged" ? `git diff --cached --quiet -- "${file}"` : `git diff --quiet -- "${file}"`;
939
+ try {
940
+ (0, import_child_process.execSync)(command, { stdio: "ignore" });
941
+ return false;
942
+ } catch (error) {
943
+ if (error.status === 1) {
944
+ return true;
945
+ }
946
+ throw error;
947
+ }
948
+ }
623
949
  async function mainGitDiff() {
624
- const args = (0, import_utils.getArgs)();
625
- const positional = args._ || [];
626
950
  if (args.help || args.h) {
627
951
  showHelp();
628
952
  }
953
+ const useUnstaged = args.unstaged || args.u;
954
+ const fileFromFlag = typeof args.unstaged === "string" ? args.unstaged : typeof args.u === "string" ? args.u : null;
955
+ let hasDiff = false;
629
956
  if (args["staged-only"] || args.s || args.S) {
630
- runGitDiff(
957
+ hasDiff = runGitDiff(
631
958
  "git --no-pager diff --staged",
632
- `Full staged diff saved to "${DIFF_OUTPUT_RELATIVE}"`,
959
+ `Full staged diff saved to "${import_ansi_colors.default.green(DIFF_OUTPUT_RELATIVE)}"`,
633
960
  "Failed to save staged diff"
634
961
  );
635
962
  } else {
636
- const file = positional[0];
963
+ const file = positional[0] || fileFromFlag;
637
964
  if (!file) {
638
- runGitDiff(
965
+ const fullDiffModeLabel = useUnstaged ? "unstaged" : "unstaged";
966
+ hasDiff = runGitDiff(
639
967
  "git --no-pager diff",
640
- `Full staged diff saved to "${DIFF_OUTPUT_RELATIVE}"`,
968
+ `Full ${fullDiffModeLabel} diff saved to "${import_ansi_colors.default.green(DIFF_OUTPUT_RELATIVE)}"`,
641
969
  "Failed to save all diff's"
642
970
  );
643
971
  } else {
644
- runGitDiff(
645
- `git --no-pager diff --cached -- "${file}"`,
646
- `Staged diff of "${file}" saved to "${DIFF_OUTPUT_RELATIVE}"`,
647
- `Failed to generate diff for "${file}"`
972
+ let fileDiffMode = useUnstaged ? "unstaged" : "staged";
973
+ if (!useUnstaged && !fileHasChanges(file, "staged") && fileHasChanges(file, "unstaged")) {
974
+ fileDiffMode = "unstaged";
975
+ }
976
+ hasDiff = runGitDiff(
977
+ fileDiffMode === "unstaged" ? `git --no-pager diff -- "${file}"` : `git --no-pager diff --cached -- "${file}"`,
978
+ `${fileDiffMode[0].toUpperCase() + fileDiffMode.slice(1)} diff of "${file}" saved to "${import_ansi_colors.default.green(
979
+ DIFF_OUTPUT_RELATIVE
980
+ )}"`,
981
+ `Failed to generate ${fileDiffMode} diff for "${file}"`
648
982
  );
649
983
  }
650
984
  }
985
+ if (hasDiff) {
986
+ const opencodePrompt = [
987
+ "",
988
+ "\u{1F916} OpenCode Prompt Helper",
989
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500",
990
+ "",
991
+ "\u{1F4C4} App Prompt:",
992
+ ` Generate a conventional commit message from diff file: ${DIFF_OUTPUT}`,
993
+ "",
994
+ "\u{1F4BB} CLI Command:",
995
+ ` opencode run "Generate a conventional commit message from diff file ${DIFF_OUTPUT}"`,
996
+ ""
997
+ ];
998
+ const opencodePromptPath = (0, import_config.getTempPath)(`git-diff/opencode-${FILENAME}.txt`);
999
+ (0, import_sbg_utility.writefile)(opencodePromptPath, opencodePrompt.join("\n"));
1000
+ console.log(`\u{1F4A1} OpenCode prompt saved to "${import_ansi_colors.default.green(import_upath2.default.relative(process.cwd(), opencodePromptPath))}"`);
1001
+ }
651
1002
  if (args.ai) {
652
1003
  try {
653
1004
  await runChatGpt({ headless: true, questionFile: GPT_DIFF_OUTPUT });