aicodeman 1.44.0 → 1.46.0

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 (351) hide show
  1. package/README.md +32 -8
  2. package/dist/agent-codex-identity.d.ts +26 -0
  3. package/dist/agent-codex-identity.d.ts.map +1 -0
  4. package/dist/agent-codex-identity.js +253 -0
  5. package/dist/agent-codex-identity.js.map +1 -0
  6. package/dist/agent-inspection.d.ts +32 -0
  7. package/dist/agent-inspection.d.ts.map +1 -0
  8. package/dist/agent-inspection.js +196 -0
  9. package/dist/agent-inspection.js.map +1 -0
  10. package/dist/agent-staging.d.ts +130 -0
  11. package/dist/agent-staging.d.ts.map +1 -0
  12. package/dist/agent-staging.js +312 -0
  13. package/dist/agent-staging.js.map +1 -0
  14. package/dist/case-rename.d.ts +65 -0
  15. package/dist/case-rename.d.ts.map +1 -0
  16. package/dist/case-rename.js +198 -0
  17. package/dist/case-rename.js.map +1 -0
  18. package/dist/cli-agent.d.ts +91 -3
  19. package/dist/cli-agent.d.ts.map +1 -1
  20. package/dist/cli-agent.js +501 -44
  21. package/dist/cli-agent.js.map +1 -1
  22. package/dist/cli-history.d.ts +20 -0
  23. package/dist/cli-history.d.ts.map +1 -0
  24. package/dist/cli-history.js +61 -0
  25. package/dist/cli-history.js.map +1 -0
  26. package/dist/cli.d.ts.map +1 -1
  27. package/dist/cli.js +6 -1
  28. package/dist/cli.js.map +1 -1
  29. package/dist/codex-rollout-format.d.ts +66 -0
  30. package/dist/codex-rollout-format.d.ts.map +1 -0
  31. package/dist/codex-rollout-format.js +111 -0
  32. package/dist/codex-rollout-format.js.map +1 -0
  33. package/dist/codex-transcript.d.ts +3 -0
  34. package/dist/codex-transcript.d.ts.map +1 -1
  35. package/dist/codex-transcript.js +13 -41
  36. package/dist/codex-transcript.js.map +1 -1
  37. package/dist/config/auth-config.d.ts +16 -1
  38. package/dist/config/auth-config.d.ts.map +1 -1
  39. package/dist/config/auth-config.js +16 -1
  40. package/dist/config/auth-config.js.map +1 -1
  41. package/dist/config/cli-registry/schema.d.ts +12 -7
  42. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  43. package/dist/config/cli-registry/schema.js +26 -0
  44. package/dist/config/cli-registry/schema.js.map +1 -1
  45. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  46. package/dist/config/cli-registry/stock.js +40 -1
  47. package/dist/config/cli-registry/stock.js.map +1 -1
  48. package/dist/config/cli-registry/types.d.ts +57 -0
  49. package/dist/config/cli-registry/types.d.ts.map +1 -1
  50. package/dist/config/server-timing.d.ts +6 -0
  51. package/dist/config/server-timing.d.ts.map +1 -1
  52. package/dist/config/server-timing.js +9 -0
  53. package/dist/config/server-timing.js.map +1 -1
  54. package/dist/daemon-control.d.ts +1 -0
  55. package/dist/daemon-control.d.ts.map +1 -1
  56. package/dist/daemon-control.js +2 -0
  57. package/dist/daemon-control.js.map +1 -1
  58. package/dist/deepseek-transcript.d.ts +9 -7
  59. package/dist/deepseek-transcript.d.ts.map +1 -1
  60. package/dist/deepseek-transcript.js +9 -7
  61. package/dist/deepseek-transcript.js.map +1 -1
  62. package/dist/docker-hosts.d.ts +8 -0
  63. package/dist/docker-hosts.d.ts.map +1 -1
  64. package/dist/docker-hosts.js +29 -0
  65. package/dist/docker-hosts.js.map +1 -1
  66. package/dist/git-fetch-scheduler.d.ts +124 -0
  67. package/dist/git-fetch-scheduler.d.ts.map +1 -0
  68. package/dist/git-fetch-scheduler.js +249 -0
  69. package/dist/git-fetch-scheduler.js.map +1 -0
  70. package/dist/git-fetch.d.ts +241 -0
  71. package/dist/git-fetch.d.ts.map +1 -0
  72. package/dist/git-fetch.js +392 -0
  73. package/dist/git-fetch.js.map +1 -0
  74. package/dist/git-workspace-status.d.ts +36 -1
  75. package/dist/git-workspace-status.d.ts.map +1 -1
  76. package/dist/git-workspace-status.js +42 -5
  77. package/dist/git-workspace-status.js.map +1 -1
  78. package/dist/hooks-config.d.ts +14 -2
  79. package/dist/hooks-config.d.ts.map +1 -1
  80. package/dist/hooks-config.js +39 -3
  81. package/dist/hooks-config.js.map +1 -1
  82. package/dist/host-sensors.d.ts +115 -0
  83. package/dist/host-sensors.d.ts.map +1 -0
  84. package/dist/host-sensors.js +457 -0
  85. package/dist/host-sensors.js.map +1 -0
  86. package/dist/local-history.d.ts +71 -0
  87. package/dist/local-history.d.ts.map +1 -0
  88. package/dist/local-history.js +750 -0
  89. package/dist/local-history.js.map +1 -0
  90. package/dist/mcp-server.d.ts.map +1 -1
  91. package/dist/mcp-server.js +2 -2
  92. package/dist/mcp-server.js.map +1 -1
  93. package/dist/mux-interface.d.ts +5 -2
  94. package/dist/mux-interface.d.ts.map +1 -1
  95. package/dist/prompt-cache-keepwarm.d.ts.map +1 -1
  96. package/dist/prompt-cache-keepwarm.js +5 -3
  97. package/dist/prompt-cache-keepwarm.js.map +1 -1
  98. package/dist/remote-hosts.d.ts +7 -0
  99. package/dist/remote-hosts.d.ts.map +1 -1
  100. package/dist/remote-hosts.js +17 -3
  101. package/dist/remote-hosts.js.map +1 -1
  102. package/dist/remote-pane-history.d.ts.map +1 -1
  103. package/dist/remote-pane-history.js +2 -2
  104. package/dist/remote-pane-history.js.map +1 -1
  105. package/dist/session.d.ts +113 -0
  106. package/dist/session.d.ts.map +1 -1
  107. package/dist/session.js +354 -13
  108. package/dist/session.js.map +1 -1
  109. package/dist/terminal-input-classifier.d.ts +8 -0
  110. package/dist/terminal-input-classifier.d.ts.map +1 -0
  111. package/dist/terminal-input-classifier.js +60 -0
  112. package/dist/terminal-input-classifier.js.map +1 -0
  113. package/dist/tmux-manager.d.ts +30 -4
  114. package/dist/tmux-manager.d.ts.map +1 -1
  115. package/dist/tmux-manager.js +101 -21
  116. package/dist/tmux-manager.js.map +1 -1
  117. package/dist/tmux-prefix-table.d.ts +37 -5
  118. package/dist/tmux-prefix-table.d.ts.map +1 -1
  119. package/dist/tmux-prefix-table.js +40 -5
  120. package/dist/tmux-prefix-table.js.map +1 -1
  121. package/dist/tui/tui-app.d.ts +8 -1
  122. package/dist/tui/tui-app.d.ts.map +1 -1
  123. package/dist/tui/tui-app.js +49 -12
  124. package/dist/tui/tui-app.js.map +1 -1
  125. package/dist/tui/tui-client.d.ts +90 -3
  126. package/dist/tui/tui-client.d.ts.map +1 -1
  127. package/dist/tui/tui-client.js +195 -26
  128. package/dist/tui/tui-client.js.map +1 -1
  129. package/dist/types/session.d.ts +15 -0
  130. package/dist/types/session.d.ts.map +1 -1
  131. package/dist/types/session.js.map +1 -1
  132. package/dist/web/agent-inbox-persistence.d.ts +52 -0
  133. package/dist/web/agent-inbox-persistence.d.ts.map +1 -0
  134. package/dist/web/agent-inbox-persistence.js +139 -0
  135. package/dist/web/agent-inbox-persistence.js.map +1 -0
  136. package/dist/web/agent-inbox.d.ts +140 -0
  137. package/dist/web/agent-inbox.d.ts.map +1 -0
  138. package/dist/web/agent-inbox.js +258 -0
  139. package/dist/web/agent-inbox.js.map +1 -0
  140. package/dist/web/middleware/auth.d.ts +2 -0
  141. package/dist/web/middleware/auth.d.ts.map +1 -1
  142. package/dist/web/middleware/auth.js +145 -52
  143. package/dist/web/middleware/auth.js.map +1 -1
  144. package/dist/web/network-auth-policy.d.ts +13 -3
  145. package/dist/web/network-auth-policy.d.ts.map +1 -1
  146. package/dist/web/network-auth-policy.js +15 -3
  147. package/dist/web/network-auth-policy.js.map +1 -1
  148. package/dist/web/ports/infra-port.d.ts +2 -0
  149. package/dist/web/ports/infra-port.d.ts.map +1 -1
  150. package/dist/web/public/admin-ui.js.gz +0 -0
  151. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  152. package/dist/web/public/app.3093527f.js +43 -0
  153. package/dist/web/public/app.3093527f.js.br +0 -0
  154. package/dist/web/public/app.3093527f.js.gz +0 -0
  155. package/dist/web/public/approvals-ui.js.gz +0 -0
  156. package/dist/web/public/{constants.4866ecc3.js → constants.affcdde6.js} +622 -12
  157. package/dist/web/public/constants.affcdde6.js.br +0 -0
  158. package/dist/web/public/constants.affcdde6.js.gz +0 -0
  159. package/dist/web/public/cron-ui.js.gz +0 -0
  160. package/dist/web/public/entrance-animations.js.gz +0 -0
  161. package/dist/web/public/git-status-ui.js +88 -5
  162. package/dist/web/public/git-status-ui.js.br +0 -0
  163. package/dist/web/public/git-status-ui.js.gz +0 -0
  164. package/dist/web/public/header-divider.eb2d2463.js +1 -0
  165. package/dist/web/public/header-divider.eb2d2463.js.br +0 -0
  166. package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
  167. package/dist/web/public/home-sessions.js.gz +0 -0
  168. package/dist/web/public/host-wake-ui.js.gz +0 -0
  169. package/dist/web/public/i18n.70265257.js +2 -0
  170. package/dist/web/public/i18n.70265257.js.br +0 -0
  171. package/dist/web/public/i18n.70265257.js.gz +0 -0
  172. package/dist/web/public/image-input.941386e7.js.gz +0 -0
  173. package/dist/web/public/index.html +170 -16
  174. package/dist/web/public/index.html.br +0 -0
  175. package/dist/web/public/index.html.gz +0 -0
  176. package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
  177. package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
  178. package/dist/web/public/{mobile-handlers.44adaa07.js → mobile-handlers.f7c3f692.js} +26 -2
  179. package/dist/web/public/mobile-handlers.f7c3f692.js.br +0 -0
  180. package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
  181. package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
  182. package/dist/web/public/mobile-overview.js.gz +0 -0
  183. package/dist/web/public/mobile.1bbd2d67.css +1 -0
  184. package/dist/web/public/mobile.1bbd2d67.css.br +0 -0
  185. package/dist/web/public/mobile.1bbd2d67.css.gz +0 -0
  186. package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
  187. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  188. package/dist/web/public/{panels-ui.cbb24ba1.js → panels-ui.4a56ee63.js} +76 -70
  189. package/dist/web/public/panels-ui.4a56ee63.js.br +0 -0
  190. package/dist/web/public/panels-ui.4a56ee63.js.gz +0 -0
  191. package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
  192. package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
  193. package/dist/web/public/readmymind-ui.js.gz +0 -0
  194. package/dist/web/public/reboot-restore-ui.js.gz +0 -0
  195. package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
  196. package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
  197. package/dist/web/public/session-lineage.js.gz +0 -0
  198. package/dist/web/public/session-ui.186f9419.js +106 -0
  199. package/dist/web/public/session-ui.186f9419.js.br +0 -0
  200. package/dist/web/public/session-ui.186f9419.js.gz +0 -0
  201. package/dist/web/public/settings-ui.a191154e.js +106 -0
  202. package/dist/web/public/settings-ui.a191154e.js.br +0 -0
  203. package/dist/web/public/settings-ui.a191154e.js.gz +0 -0
  204. package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
  205. package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
  206. package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
  207. package/dist/web/public/styles.7238eae8.css +1 -0
  208. package/dist/web/public/styles.7238eae8.css.br +0 -0
  209. package/dist/web/public/styles.7238eae8.css.gz +0 -0
  210. package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
  211. package/dist/web/public/sw.js +2 -2
  212. package/dist/web/public/sw.js.br +0 -0
  213. package/dist/web/public/sw.js.gz +0 -0
  214. package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
  215. package/dist/web/public/{tab-rail-resize.7157e0bd.js → tab-rail-resize.b5cdceaf.js} +1 -1
  216. package/dist/web/public/tab-rail-resize.b5cdceaf.js.br +0 -0
  217. package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
  218. package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
  219. package/dist/web/public/terminal-split.js.gz +0 -0
  220. package/dist/web/public/terminal-tile.js +10 -1
  221. package/dist/web/public/terminal-tile.js.br +0 -0
  222. package/dist/web/public/terminal-tile.js.gz +0 -0
  223. package/dist/web/public/terminal-ui.7e787829.js +4 -0
  224. package/dist/web/public/terminal-ui.7e787829.js.br +0 -0
  225. package/dist/web/public/terminal-ui.7e787829.js.gz +0 -0
  226. package/dist/web/public/tile-grid.js.gz +0 -0
  227. package/dist/web/public/ultracode-panel.js.gz +0 -0
  228. package/dist/web/public/ultracode-windows.js.gz +0 -0
  229. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  230. package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
  231. package/dist/web/public/vendor/fflate.min.js.gz +0 -0
  232. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  233. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  234. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  235. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  236. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  237. package/dist/web/public/vendor/{xterm-predictive-echo.ae5e3d5d.js → xterm-predictive-echo.276b11d9.js} +1 -1
  238. package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.br +0 -0
  239. package/dist/web/public/vendor/xterm-predictive-echo.276b11d9.js.gz +0 -0
  240. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js +5 -0
  241. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.br +0 -0
  242. package/dist/web/public/vendor/xterm-zerolag-input.1be42307.js.gz +0 -0
  243. package/dist/web/public/vendor/xterm.css.gz +0 -0
  244. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  245. package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
  246. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  247. package/dist/web/public/webview-tabs.js.gz +0 -0
  248. package/dist/web/public/whats-new.json +9 -9
  249. package/dist/web/route-helpers.d.ts +57 -6
  250. package/dist/web/route-helpers.d.ts.map +1 -1
  251. package/dist/web/route-helpers.js +72 -4
  252. package/dist/web/route-helpers.js.map +1 -1
  253. package/dist/web/routes/agent-session-routes.d.ts +20 -0
  254. package/dist/web/routes/agent-session-routes.d.ts.map +1 -0
  255. package/dist/web/routes/agent-session-routes.js +160 -0
  256. package/dist/web/routes/agent-session-routes.js.map +1 -0
  257. package/dist/web/routes/case-routes.d.ts.map +1 -1
  258. package/dist/web/routes/case-routes.js +203 -16
  259. package/dist/web/routes/case-routes.js.map +1 -1
  260. package/dist/web/routes/config-backup-routes.js +2 -2
  261. package/dist/web/routes/config-backup-routes.js.map +1 -1
  262. package/dist/web/routes/git-status-routes.d.ts +21 -7
  263. package/dist/web/routes/git-status-routes.d.ts.map +1 -1
  264. package/dist/web/routes/git-status-routes.js +78 -12
  265. package/dist/web/routes/git-status-routes.js.map +1 -1
  266. package/dist/web/routes/inbox-routes.d.ts +43 -0
  267. package/dist/web/routes/inbox-routes.d.ts.map +1 -0
  268. package/dist/web/routes/inbox-routes.js +148 -0
  269. package/dist/web/routes/inbox-routes.js.map +1 -0
  270. package/dist/web/routes/index.d.ts +2 -0
  271. package/dist/web/routes/index.d.ts.map +1 -1
  272. package/dist/web/routes/index.js +2 -0
  273. package/dist/web/routes/index.js.map +1 -1
  274. package/dist/web/routes/ralph-routes.d.ts.map +1 -1
  275. package/dist/web/routes/ralph-routes.js +7 -16
  276. package/dist/web/routes/ralph-routes.js.map +1 -1
  277. package/dist/web/routes/session-routes.d.ts.map +1 -1
  278. package/dist/web/routes/session-routes.js +120 -74
  279. package/dist/web/routes/session-routes.js.map +1 -1
  280. package/dist/web/routes/system-routes.d.ts.map +1 -1
  281. package/dist/web/routes/system-routes.js +107 -59
  282. package/dist/web/routes/system-routes.js.map +1 -1
  283. package/dist/web/routes/ws-routes.d.ts +5 -0
  284. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  285. package/dist/web/routes/ws-routes.js +84 -47
  286. package/dist/web/routes/ws-routes.js.map +1 -1
  287. package/dist/web/schemas.d.ts +56 -7
  288. package/dist/web/schemas.d.ts.map +1 -1
  289. package/dist/web/schemas.js +88 -1
  290. package/dist/web/schemas.js.map +1 -1
  291. package/dist/web/sensitive-path.d.ts.map +1 -1
  292. package/dist/web/sensitive-path.js +2 -0
  293. package/dist/web/sensitive-path.js.map +1 -1
  294. package/dist/web/server.d.ts +7 -2
  295. package/dist/web/server.d.ts.map +1 -1
  296. package/dist/web/server.js +144 -16
  297. package/dist/web/server.js.map +1 -1
  298. package/dist/web/session-wait-registry.d.ts +48 -4
  299. package/dist/web/session-wait-registry.d.ts.map +1 -1
  300. package/dist/web/session-wait-registry.js +144 -6
  301. package/dist/web/session-wait-registry.js.map +1 -1
  302. package/dist/web/settings-writer.d.ts +47 -0
  303. package/dist/web/settings-writer.d.ts.map +1 -0
  304. package/dist/web/settings-writer.js +110 -0
  305. package/dist/web/settings-writer.js.map +1 -0
  306. package/dist/web/sse-events.d.ts +4 -1
  307. package/dist/web/sse-events.d.ts.map +1 -1
  308. package/dist/web/sse-events.js +4 -1
  309. package/dist/web/sse-events.js.map +1 -1
  310. package/package.json +1 -1
  311. package/skills/codeman/SKILL.md +30 -8
  312. package/skills/codeman/preamble.sh +3 -3
  313. package/skills/codeman/reference/endpoints.md +24 -3
  314. package/skills/codeman/reference/history.md +84 -0
  315. package/skills/codeman/reference/inspection-and-staging.md +152 -0
  316. package/skills/codeman/reference/messaging.md +1 -1
  317. package/skills/codeman/reference/verbs.md +65 -3
  318. package/dist/web/public/app.9314ee60.js +0 -43
  319. package/dist/web/public/app.9314ee60.js.br +0 -0
  320. package/dist/web/public/app.9314ee60.js.gz +0 -0
  321. package/dist/web/public/constants.4866ecc3.js.br +0 -0
  322. package/dist/web/public/constants.4866ecc3.js.gz +0 -0
  323. package/dist/web/public/i18n.22ca902b.js +0 -2
  324. package/dist/web/public/i18n.22ca902b.js.br +0 -0
  325. package/dist/web/public/i18n.22ca902b.js.gz +0 -0
  326. package/dist/web/public/mobile-handlers.44adaa07.js.br +0 -0
  327. package/dist/web/public/mobile-handlers.44adaa07.js.gz +0 -0
  328. package/dist/web/public/mobile.12fb18de.css +0 -1
  329. package/dist/web/public/mobile.12fb18de.css.br +0 -0
  330. package/dist/web/public/mobile.12fb18de.css.gz +0 -0
  331. package/dist/web/public/panels-ui.cbb24ba1.js.br +0 -0
  332. package/dist/web/public/panels-ui.cbb24ba1.js.gz +0 -0
  333. package/dist/web/public/session-ui.9c1f009b.js +0 -104
  334. package/dist/web/public/session-ui.9c1f009b.js.br +0 -0
  335. package/dist/web/public/session-ui.9c1f009b.js.gz +0 -0
  336. package/dist/web/public/settings-ui.fea9ddae.js +0 -106
  337. package/dist/web/public/settings-ui.fea9ddae.js.br +0 -0
  338. package/dist/web/public/settings-ui.fea9ddae.js.gz +0 -0
  339. package/dist/web/public/styles.e096fcd6.css +0 -1
  340. package/dist/web/public/styles.e096fcd6.css.br +0 -0
  341. package/dist/web/public/styles.e096fcd6.css.gz +0 -0
  342. package/dist/web/public/tab-rail-resize.7157e0bd.js.br +0 -0
  343. package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
  344. package/dist/web/public/terminal-ui.68dbd352.js +0 -2
  345. package/dist/web/public/terminal-ui.68dbd352.js.br +0 -0
  346. package/dist/web/public/terminal-ui.68dbd352.js.gz +0 -0
  347. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.br +0 -0
  348. package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
  349. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js +0 -4
  350. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.br +0 -0
  351. package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
@@ -0,0 +1,392 @@
1
+ /**
2
+ * @fileoverview `git fetch` for the repositories the Git panel shows, on the user's click
3
+ * (`POST /api/sessions/:id/git-fetch`) or on an interval the user turned on
4
+ * (`src/git-fetch-scheduler.ts`).
5
+ *
6
+ * The status module (src/git-workspace-status.ts) is deliberately offline: "behind" is as of the last
7
+ * fetch, so a number that is stale can only be made current by fetching. This is the only git command the
8
+ * Git panel runs that writes, and the only git command Codeman runs on a timer. Cloning a repository and
9
+ * managing worktrees write too, but those are things the user asked for at the moment they asked; this is
10
+ * the one that can happen later, by itself. Nothing here commits, checks out, merges or touches the working
11
+ * tree: `git fetch` updates remote-tracking
12
+ * refs and nothing else, and `FETCH_CONFIG_ARGS` keeps it from starting a gc in a repository an agent is
13
+ * already using. It is not harmless in the way a read is: a fetch holds git's ref lock, so an agent's own
14
+ * `git pull` in the same clone can collide with it (`cannot lock ref`), which is why one folder is fetched
15
+ * by at most one run at a time (`fetchWorkspaceOnce`).
16
+ *
17
+ * Same split as git-clone.ts: the pure half (`buildFetchArgs`, `describeFetchFailure`, `fetchEnvFor`,
18
+ * `gitFetchSettingsFrom`, `gitFetchStatusFrom`) holds every decision and tests without spawning, and the IO
19
+ * half runs one bounded `git fetch --quiet` per repository.
20
+ *
21
+ * Rules the code keeps and the tests pin:
22
+ * - The repository set is `resolveWorkspaceRepos`, the single source the panel and the diff route
23
+ * already use, so Fetch cannot reach a repository the panel would not show. The Docker rule is
24
+ * checked before any git runs: a repository a container can write to is refused outright, because a
25
+ * planted config would run on the host, and `git fetch` is exactly the command that can run a
26
+ * repository's own hooks (`reference-transaction`, and `pre-auto-gc` through the automatic maintenance
27
+ * that follows a fetch) and its config commands such as `credential.helper`, which is why a timer only
28
+ * runs it after the user opts in.
29
+ * - One run per folder at a time: `fetchWorkspaceOnce` joins a run already going for the same folder
30
+ * instead of starting a second one, because two fetches in one clone collide on the ref lock.
31
+ * - Bounded: the git timeout from Settings → Bottom bar per repository, `MAX_REPOS_LIMIT` repositories at
32
+ * most, a hard wall-clock bound on each spawn, and `FETCH_CONCURRENCY` git processes at a time for the
33
+ * whole run: one `Limiter`, shared by the scheduler's tick, not one bound per folder.
34
+ * - Non-interactive: `GIT_TERMINAL_PROMPT=0` and BatchMode ssh, so a private repository that needs a
35
+ * login fails fast instead of hanging the request on an invisible username prompt. Codeman collects
36
+ * no credentials; a repository the user's own git is already signed in to works because that is the
37
+ * user's existing setup, so unlike a clone no credential helper is disabled here. That BatchMode ssh is
38
+ * a default, never an override: `fetchEnvFor` keeps whatever the repository's `core.sshCommand`, the
39
+ * user's own `GIT_SSH_COMMAND` or a `GIT_SSH` already says, because on a machine with several ssh setups
40
+ * that choice is usually the one that works. ⚠️ The default still leaves a record: `StrictHostKeyChecking=accept-new`
41
+ * writes an unknown host key into `~/.ssh/known_hosts` without asking: BatchMode stops a prompt, not a
42
+ * write.
43
+ * - The timeout kills the PROCESS GROUP, not just the `git` parent. A fetch over http spawns
44
+ * `git-remote-http` children, and `execFile`'s `timeout` signals the parent only, so the answer can go
45
+ * out while a helper is still running, and on a timer that repeats every tick with nobody watching.
46
+ * `spawn` with `detached: true` puts the tree in its own group so the escalation (SIGTERM, then SIGKILL
47
+ * `FETCH_KILL_ESCALATION_MS` later) reaches the children too, which is why the negative pid is used
48
+ * rather than `child.kill()`. Same shape as `runGit` in git-clone.ts, without that module's slot queue:
49
+ * fetch is bounded by `FETCH_CONCURRENCY`, not by a clone queue.
50
+ * - Failure text reaching a client is control-stripped and credential-redacted (`sanitizeGitOutput`),
51
+ * and the browser writes it with `textContent` only.
52
+ *
53
+ * @module git-fetch
54
+ */
55
+ import { execFile, spawn } from 'node:child_process';
56
+ import { basename, relative, resolve } from 'node:path';
57
+ import { promisify } from 'node:util';
58
+ import { classifyGitFailure, gitNonInteractiveEnv, sanitizeGitOutput } from './git-clone.js';
59
+ import { createLimiter, DEFAULT_GIT_TIMEOUT_MS, resolveOverviewLimits, resolveWorkspaceRepos, } from './git-workspace-status.js';
60
+ const execFileAsync = promisify(execFile);
61
+ /**
62
+ * Git processes in flight at once, for one run, and for a whole scheduler tick, because the tick hands ONE
63
+ * bound to every run (see `createLimiter`): each fetch is one git process, and a folder can hold up to
64
+ * `MAX_REPOS_LIMIT`. The tick bounds its folders separately, because the same semaphore cannot serve both
65
+ * levels: a folder holding a slot would then wait for a slot its own fetch needs.
66
+ */
67
+ export const FETCH_CONCURRENCY = 4;
68
+ /** A fetch on a busy remote can print a lot; a bound on what we will hold. */
69
+ const MAX_FETCH_OUTPUT_BYTES = 2 * 1024 * 1024;
70
+ /** git's stderr is kept as a bounded tail (as in git-clone.ts): enough for the reason, not the whole stream. */
71
+ const MAX_FETCH_STDERR_BYTES = 8_192;
72
+ /** A `git config --get` answer is one line; this is a sanity cap, not an expected size. */
73
+ const MAX_SSH_COMMAND_BYTES = 4_096;
74
+ /**
75
+ * How long the process group gets to answer SIGTERM before the same escalation goes to SIGKILL. Kept as a
76
+ * const so a test can say how long it is willing to wait for the group to actually die.
77
+ */
78
+ export const FETCH_KILL_ESCALATION_MS = 3_000;
79
+ /**
80
+ * Config overrides set ahead of the argv, so an unattended fetch cannot do more than move refs: no
81
+ * fsmonitor hook, and no automatic maintenance or gc. A fetch is the git command that can run a
82
+ * repository's own hooks (`reference-transaction`, and `pre-auto-gc` through the maintenance that follows a
83
+ * fetch), and a gc started by a timer in a repository an agent is working in is exactly the kind of extra
84
+ * write this module must not do. Kept as a const so a test can pin it without spawning git.
85
+ */
86
+ export const FETCH_CONFIG_ARGS = ['-c', 'core.fsmonitor=false', '-c', 'maintenance.auto=false', '-c', 'gc.auto=0'];
87
+ /** The interval the user can turn on (Settings → Bottom bar, and Session Options → Git): bounds and default. */
88
+ export const DEFAULT_GIT_FETCH_INTERVAL_SECONDS = 300;
89
+ export const MIN_GIT_FETCH_INTERVAL_SECONDS = 30;
90
+ export const MAX_GIT_FETCH_INTERVAL_SECONDS = 3600;
91
+ /**
92
+ * A settings object as the scheduler should read it: absent means OFF, because nothing runs on a timer
93
+ * until the user turns this on, and a number outside the schema's bounds is clamped rather than trusted.
94
+ * Pure, so the reading itself is testable without a settings file.
95
+ */
96
+ export function gitFetchSettingsFrom(settings) {
97
+ const raw = settings?.gitFetchIntervalSeconds;
98
+ const seconds = typeof raw === 'number' && Number.isFinite(raw) ? Math.round(raw) : DEFAULT_GIT_FETCH_INTERVAL_SECONDS;
99
+ return {
100
+ enabled: settings?.gitFetchEnabled === true,
101
+ intervalSeconds: Math.min(MAX_GIT_FETCH_INTERVAL_SECONDS, Math.max(MIN_GIT_FETCH_INTERVAL_SECONDS, seconds)),
102
+ };
103
+ }
104
+ /**
105
+ * The only git command this module runs. Kept as a function so a test can pin the verb: nothing here
106
+ * commits, checks out, merges or prunes, and no operand is interpolated: the repository is the process
107
+ * `cwd` and the argv is fixed.
108
+ */
109
+ export function buildFetchArgs() {
110
+ return ['fetch', '--quiet'];
111
+ }
112
+ /**
113
+ * A thrown git error as the panel should show it. `classifyGitFailure` (git-clone.ts) already knows the
114
+ * network reasons (auth, an unreachable host, a missing git), so they are reused here; only its timeout
115
+ * wording is written for clones, so the fetch path replaces it with what the user can actually do.
116
+ */
117
+ export function describeFetchFailure(err) {
118
+ const e = err;
119
+ const stderr = typeof e.stderr === 'string' ? e.stderr : '';
120
+ const spawnError = typeof e.message === 'string' ? e.message : undefined;
121
+ const clean = sanitizeGitOutput(stderr);
122
+ const lower = `${clean}\n${spawnError ?? ''}`.toLowerCase();
123
+ if (/no default remote repository|no remote configured|nothing to fetch/.test(lower)) {
124
+ return {
125
+ code: 'NO_REMOTE',
126
+ message: 'This repository has no remote, so there is nothing to fetch.',
127
+ stderr: clean,
128
+ };
129
+ }
130
+ const timedOut = e.code === 'ETIMEDOUT' || e.killed === true;
131
+ const failure = classifyGitFailure(stderr, timedOut, spawnError);
132
+ if (failure.code === 'TIMEOUT')
133
+ failure.message = 'Git timed out. Raise “Git status: git timeout” in Settings → Bottom bar, or fetch from a shell.';
134
+ return failure;
135
+ }
136
+ /**
137
+ * The environment a fetch gets, as a pure decision so it can be pinned without spawning git.
138
+ *
139
+ * `gitNonInteractiveEnv` supplies the BatchMode default, and the default is only a default: git reads
140
+ * `GIT_SSH_COMMAND` from the environment ahead of the repository's `core.sshCommand`, so setting it would
141
+ * override a repository that already chose its own ssh (an alternative host, an identity file, a jump box)
142
+ * and break a setup that works today. The server's own `GIT_SSH` is the same kind of answer: git reads it
143
+ * after both of those (`GIT_SSH_COMMAND`, then `core.sshCommand`, then `GIT_SSH`), so a written default would
144
+ * hide it too. That is the only case where this module makes an ssh choice on the user's behalf, so it is the
145
+ * whole decision here: the caller supplies the value it read, and this decides between the user's
146
+ * environment and the repository's own answer.
147
+ */
148
+ export function fetchEnvFor(base, repoSshCommand) {
149
+ const env = gitNonInteractiveEnv(base);
150
+ // `gitNonInteractiveEnv` only writes the default when the environment had nothing, so this is exactly the
151
+ // case where it was a choice rather than a pass-through, and the repository's own answer, or a `GIT_SSH` in
152
+ // the environment, wins over it.
153
+ if (!base.GIT_SSH_COMMAND && (repoSshCommand || base.GIT_SSH))
154
+ delete env.GIT_SSH_COMMAND;
155
+ return env;
156
+ }
157
+ /**
158
+ * The repository's own `core.sshCommand`, or null. One bounded, read-only `git config --get` per fetch:
159
+ * git would honour that config itself if we did not write `GIT_SSH_COMMAND` over it, so honouring it means
160
+ * not writing one. `--get` reads local and global config, which is the value git would have used, and no
161
+ * hook or filter runs on the way to it.
162
+ *
163
+ * The read happens inside the same slot and the same wall-clock bound as the fetch it serves, so it cannot
164
+ * add a fifth git process or push a fetch past the user's timeout: it spends part of it.
165
+ */
166
+ export async function readRepoSshCommand(cwd, timeoutMs) {
167
+ try {
168
+ const { stdout } = await execFileAsync('git', ['config', '--get', 'core.sshCommand'], {
169
+ cwd,
170
+ timeout: timeoutMs,
171
+ maxBuffer: MAX_SSH_COMMAND_BYTES,
172
+ env: gitNonInteractiveEnv(),
173
+ });
174
+ return stdout.trim() || null;
175
+ }
176
+ catch {
177
+ // A repository with no such setting, or a read that could not finish: the default is what git would have
178
+ // used anyway, and a fetch must not fail because the check for a config value failed.
179
+ return null;
180
+ }
181
+ }
182
+ /**
183
+ * Fetch is allowed to write refs, so this runner does not carry `--no-optional-locks`: fetch takes a
184
+ * required lock anyway.
185
+ *
186
+ * `spawn`, not `execFile`, because the bound has to reach the whole tree (see the fileoverview): the
187
+ * caller is answered at the timeout, and the SIGTERM → SIGKILL escalation is deliberately NOT cancelled
188
+ * when the answer goes out, because the promise is a promise about the answer while the group still has to
189
+ * die. That is the difference from `runGit` in git-clone.ts, which disarms the escalation at `finish` and so
190
+ * can leave a `git-remote-http` child running after a timed-out call.
191
+ *
192
+ * The thrown error keeps the shape `describeFetchFailure` reads: `stderr` for the reason, `message` for a
193
+ * spawn failure (`spawn git ENOENT` → GIT_MISSING), `killed` and `code` for the timeout. A non-zero exit
194
+ * rejects the way `execFile` would (`code` is then the exit code), because resolving it would report a real
195
+ * failure as a clean run with an empty reason.
196
+ *
197
+ * `timeoutMs` bounds the `core.sshCommand` read and the fetch TOGETHER: the spawn is armed with what the read
198
+ * left, so a `git` that never answers costs one timeout, not two. A read that used the whole bound answers
199
+ * as a timeout without starting the fetch.
200
+ */
201
+ export const runFetch = async (cwd, args, opts) => {
202
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_GIT_TIMEOUT_MS;
203
+ const startedAt = Date.now();
204
+ const env = fetchEnvFor(process.env, await readRepoSshCommand(cwd, timeoutMs));
205
+ const remainingMs = timeoutMs - (Date.now() - startedAt);
206
+ if (remainingMs <= 0) {
207
+ throw Object.assign(new Error(`Command failed: git ${args.join(' ')}`), {
208
+ stderr: '',
209
+ killed: true,
210
+ code: 'ETIMEDOUT',
211
+ });
212
+ }
213
+ return new Promise((resolve, reject) => {
214
+ let child;
215
+ try {
216
+ child = spawn('git', [...FETCH_CONFIG_ARGS, ...args], {
217
+ cwd,
218
+ env,
219
+ stdio: ['ignore', 'pipe', 'pipe'],
220
+ detached: true,
221
+ });
222
+ }
223
+ catch (err) {
224
+ reject(err);
225
+ return;
226
+ }
227
+ let stdout = '';
228
+ let stderr = '';
229
+ let stdoutBytes = 0;
230
+ let timedOut = false;
231
+ let settled = false;
232
+ let killTimer;
233
+ const killTree = (signal) => {
234
+ try {
235
+ if (child.pid)
236
+ process.kill(-child.pid, signal);
237
+ }
238
+ catch {
239
+ try {
240
+ child.kill(signal);
241
+ }
242
+ catch {
243
+ /* already gone */
244
+ }
245
+ }
246
+ };
247
+ const fail = (spawnError, exitCode) => {
248
+ if (settled)
249
+ return;
250
+ settled = true;
251
+ // Only the timeout timer is disarmed here. On a timeout the escalation is what the caller is waiting
252
+ // for, and cancelling it is the bug this runner exists to fix.
253
+ clearTimeout(timeoutTimer);
254
+ reject(Object.assign(new Error(spawnError ?? `Command failed: git ${args.join(' ')}`), {
255
+ stderr,
256
+ killed: timedOut,
257
+ code: timedOut ? 'ETIMEDOUT' : (exitCode ?? undefined),
258
+ }));
259
+ };
260
+ const timeoutTimer = setTimeout(() => {
261
+ timedOut = true;
262
+ killTree('SIGTERM');
263
+ killTimer = setTimeout(() => killTree('SIGKILL'), FETCH_KILL_ESCALATION_MS);
264
+ fail();
265
+ }, remainingMs);
266
+ child.stdout?.on('data', (chunk) => {
267
+ stdoutBytes += chunk.length;
268
+ if (stdoutBytes <= MAX_FETCH_OUTPUT_BYTES)
269
+ stdout += chunk.toString('utf-8');
270
+ });
271
+ child.stderr?.on('data', (chunk) => {
272
+ stderr += chunk.toString('utf-8');
273
+ if (stderr.length > MAX_FETCH_STDERR_BYTES * 2)
274
+ stderr = stderr.slice(-MAX_FETCH_STDERR_BYTES);
275
+ });
276
+ const finish = (code) => {
277
+ if (settled)
278
+ return;
279
+ // execFile's contract, which `describeFetchFailure` depends on: a non-zero exit rejects, so a real
280
+ // git failure keeps its reason in `stderr` instead of becoming a green row with an empty one. `null`
281
+ // means a signal, reachable only when something outside this runner killed the group: our own timeout
282
+ // has already answered by then, and `settled` above is what keeps that answer the answer.
283
+ if (code !== 0)
284
+ return fail(undefined, code);
285
+ settled = true;
286
+ clearTimeout(timeoutTimer);
287
+ if (killTimer)
288
+ clearTimeout(killTimer);
289
+ resolve(stdout);
290
+ };
291
+ child.on('error', (err) => fail(String(err)));
292
+ child.on('close', (code) => finish(code));
293
+ });
294
+ };
295
+ export function gitFetchStatusFrom(report, trigger) {
296
+ const failed = report.repos.filter((r) => !r.ok);
297
+ const status = {
298
+ ranAt: report.fetchedAt,
299
+ trigger,
300
+ state: report.state,
301
+ repos: report.repos.length,
302
+ failed: failed.length,
303
+ };
304
+ const first = failed[0];
305
+ if (first?.failure)
306
+ status.firstFailure = { name: first.name, code: first.failure.code };
307
+ return status;
308
+ }
309
+ export const emptyReport = (state, extra = {}) => ({
310
+ state,
311
+ repos: [],
312
+ reposTruncated: false,
313
+ fetchedAt: Date.now(),
314
+ ...extra,
315
+ });
316
+ async function fetchOne(dir, git, timeoutMs) {
317
+ try {
318
+ await git(dir, buildFetchArgs(), { timeoutMs });
319
+ return null;
320
+ }
321
+ catch (err) {
322
+ return describeFetchFailure(err);
323
+ }
324
+ }
325
+ /**
326
+ * Fetch every repository the panel would show for `cwd`, through the same resolver so the two cannot
327
+ * disagree. A repository that failed keeps its row with the reason, exactly as an unreadable repository
328
+ * stays in the status list: the panel must show that something was not fetched rather than quietly skip it.
329
+ */
330
+ export async function fetchGitWorkspaceOverview(cwd, opts = {}) {
331
+ const where = await resolveWorkspaceRepos(cwd, opts);
332
+ if (where.kind === 'docker')
333
+ return emptyReport('unsupported', { reason: 'docker' });
334
+ if (where.kind === 'error')
335
+ return emptyReport('error', { error: where.error });
336
+ const dirs = where.kind === 'enclosing' ? [where.root] : where.dirs;
337
+ if (!dirs.length)
338
+ return emptyReport('not-a-repo');
339
+ const { timeoutMs } = resolveOverviewLimits(opts);
340
+ const runner = opts.git ?? runFetch;
341
+ const run = opts.limiter ?? createLimiter(FETCH_CONCURRENCY);
342
+ const failures = await run(dirs, (dir) => fetchOne(dir, runner, timeoutMs));
343
+ const repos = dirs.map((dir, i) => {
344
+ const base = { name: basename(dir), path: relative(cwd, dir) || '.' };
345
+ const failure = failures[i];
346
+ return failure ? { ...base, ok: false, failure } : { ...base, ok: true };
347
+ });
348
+ return {
349
+ state: 'ok',
350
+ repos,
351
+ reposTruncated: where.kind === 'children' ? where.truncated : false,
352
+ repoLimit: resolveOverviewLimits(opts).maxRepos,
353
+ fetchedAt: Date.now(),
354
+ };
355
+ }
356
+ /**
357
+ * Runs already going, keyed by the resolved folder. A request for a folder another run is already working on
358
+ * JOINS that run instead of starting a second `git fetch` in the same clone: two fetches there collide on
359
+ * git's ref lock (`cannot lock ref 'refs/remotes/origin/main'`), which is what a click during a tick would
360
+ * otherwise do. A joiner gets the run already going's answer, including its limits and its trigger: the point
361
+ * is not to fetch twice, not to fetch with the freshest options, and a click that fetched nothing cannot
362
+ * report itself as the fetch.
363
+ *
364
+ * Keyed by `resolve`, not `realpath`, because `realpath` is itself one of the unbounded fs calls rule #516
365
+ * bounds for user-chosen paths; the scheduler probes the folder bounded and calls this. Two paths that
366
+ * resolve the same are the same folder here; a workspace reached through a symlink resolves to the link, so
367
+ * a link and its target can be fetched by two runs, the accepted trade for keeping the probe bounded.
368
+ */
369
+ const lane = new Map();
370
+ export async function fetchWorkspaceOnce(folder, opts = {}, trigger) {
371
+ const key = resolve(folder);
372
+ const going = lane.get(key);
373
+ // The joiner is handed the run already going as it is, trigger included: it did not cause that fetch, so it
374
+ // must not report itself as having.
375
+ if (going)
376
+ return going;
377
+ const run = fetchGitWorkspaceOverview(key, opts)
378
+ .then((report) => ({ report, trigger }))
379
+ .finally(() => {
380
+ // Only the run that is still the lane's own: a later run for the same folder must not be dropped by an
381
+ // earlier one finishing late.
382
+ if (lane.get(key) === run)
383
+ lane.delete(key);
384
+ });
385
+ lane.set(key, run);
386
+ return run;
387
+ }
388
+ /** Test seam: an in-memory lane is not cleared by stopping the scheduler, so a test has to clear it itself. */
389
+ export function clearGitFetchLane() {
390
+ lane.clear();
391
+ }
392
+ //# sourceMappingURL=git-fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-fetch.js","sourceRoot":"","sources":["../src/git-fetch.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,8 @@
22
22
  *
23
23
  * Rules the code keeps and the tests pin:
24
24
  * - READ-ONLY and OFFLINE. It never fetches, pulls, commits or writes. "Behind" therefore reflects
25
- * the last fetch (the UI says so); "ahead" and the unpushed list are exact against the
25
+ * the last fetch (the UI says so, and the Fetch button is a separate user-triggered path in
26
+ * `src/git-fetch.ts`, never a poll); "ahead" and the unpushed list are exact against the
26
27
  * remote-tracking refs already on disk. `--no-optional-locks` keeps `git status` from even
27
28
  * refreshing the index, so polling cannot contend with the agent's own git commands.
28
29
  * - Every call is async (`execFile`), bounded by a timeout, and never interpolates a path into a
@@ -187,6 +188,19 @@ export declare function discoverChildRepos(cwd: string, excludeRealRoots?: strin
187
188
  dirs: string[];
188
189
  truncated: boolean;
189
190
  }>;
191
+ /**
192
+ * A slot count fixed ONCE, so callers share it instead of each getting its own bound (see the fetch path):
193
+ * the count lives in the closure, so `limit` is the ceiling for everything going through THIS limiter at
194
+ * once, not for each call to it, which is what makes a scheduler tick's bound honest.
195
+ * ⚠️ One limiter cannot bound two levels of the same work: a caller that holds a slot and then waits for
196
+ * another slot for the work IT starts cannot get one, because the holders are exactly the ones waiting. The
197
+ * outer level needs its own bound (`mapLimited`), which is why the tick shares one for fetches and keeps a
198
+ * separate one for folders.
199
+ */
200
+ export type Limiter = <T, R>(items: T[], fn: (item: T) => Promise<R>) => Promise<R[]>;
201
+ export declare function createLimiter(limit: number): Limiter;
202
+ /** Run `fn` over `items` with at most `limit` in flight, keeping the input order. Per call; `createLimiter` shares one bound across calls. */
203
+ export declare function mapLimited<T, R>(items: T[], limit: number, fn: (item: T) => Promise<R>): Promise<R[]>;
190
204
  export interface GitOverviewOptions {
191
205
  git?: GitRunner;
192
206
  now?: () => number;
@@ -207,6 +221,27 @@ export declare function resolveOverviewLimits(opts: {
207
221
  maxRepos: number;
208
222
  timeoutMs: number;
209
223
  };
224
+ export type WorkspaceRepos = {
225
+ kind: 'docker';
226
+ } | {
227
+ kind: 'error';
228
+ error: string;
229
+ } | {
230
+ kind: 'enclosing';
231
+ root: string;
232
+ } | {
233
+ kind: 'children';
234
+ dirs: string[];
235
+ truncated: boolean;
236
+ limit: number;
237
+ };
238
+ /**
239
+ * WHICH repositories belong to the workspace (the module header has the rules), without a full
240
+ * status of any of them: one cached `rev-parse` for the enclosing repository, else the cached scan
241
+ * below the folder. The overview, the fetch route and the diff route all go through here, so they cannot
242
+ * disagree about which repositories belong to a workspace.
243
+ */
244
+ export declare function resolveWorkspaceRepos(cwd: string, opts: GitOverviewOptions): Promise<WorkspaceRepos>;
210
245
  /**
211
246
  * Everything git knows about the session's workspace: the enclosing repository when there is one,
212
247
  * otherwise each repository found below the working directory. See the module header for the rules.
@@ -1 +1 @@
1
- {"version":3,"file":"git-workspace-status.d.ts","sourceRoot":"","sources":["../src/git-workspace-status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-workspace-status.d.ts","sourceRoot":"","sources":["../src/git-workspace-status.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,8 @@
22
22
  *
23
23
  * Rules the code keeps and the tests pin:
24
24
  * - READ-ONLY and OFFLINE. It never fetches, pulls, commits or writes. "Behind" therefore reflects
25
- * the last fetch (the UI says so); "ahead" and the unpushed list are exact against the
25
+ * the last fetch (the UI says so, and the Fetch button is a separate user-triggered path in
26
+ * `src/git-fetch.ts`, never a poll); "ahead" and the unpushed list are exact against the
26
27
  * remote-tracking refs already on disk. `--no-optional-locks` keeps `git status` from even
27
28
  * refreshing the index, so polling cannot contend with the agent's own git commands.
28
29
  * - Every call is async (`execFile`), bounded by a timeout, and never interpolates a path into a
@@ -451,8 +452,43 @@ export async function discoverChildRepos(cwd, excludeRealRoots = [], maxRepos =
451
452
  return { dirs: found.slice(0, maxRepos), truncated: found.length > maxRepos };
452
453
  }
453
454
  const discoveryCache = new Map();
454
- /** Run `fn` over `items` with at most `limit` in flight, keeping the input order. */
455
- async function mapLimited(items, limit, fn) {
455
+ export function createLimiter(limit) {
456
+ let inUse = 0;
457
+ const waiting = [];
458
+ const acquire = () => {
459
+ if (inUse < limit) {
460
+ inUse++;
461
+ return Promise.resolve();
462
+ }
463
+ return new Promise((done) => {
464
+ waiting.push(() => {
465
+ inUse++;
466
+ done();
467
+ });
468
+ });
469
+ };
470
+ const release = () => {
471
+ inUse--;
472
+ const next = waiting.shift();
473
+ if (next)
474
+ next();
475
+ };
476
+ return async (items, fn) => {
477
+ const out = new Array(items.length);
478
+ await Promise.all(items.map(async (item, i) => {
479
+ await acquire();
480
+ try {
481
+ out[i] = await fn(item);
482
+ }
483
+ finally {
484
+ release();
485
+ }
486
+ }));
487
+ return out;
488
+ };
489
+ }
490
+ /** Run `fn` over `items` with at most `limit` in flight, keeping the input order. Per call; `createLimiter` shares one bound across calls. */
491
+ export async function mapLimited(items, limit, fn) {
456
492
  const out = new Array(items.length);
457
493
  let next = 0;
458
494
  const worker = async () => {
@@ -474,9 +510,10 @@ export function resolveOverviewLimits(opts) {
474
510
  /**
475
511
  * WHICH repositories belong to the workspace (the module header has the rules), without a full
476
512
  * status of any of them: one cached `rev-parse` for the enclosing repository, else the cached scan
477
- * below the folder. The overview and the diff route both go through here, so they cannot disagree.
513
+ * below the folder. The overview, the fetch route and the diff route all go through here, so they cannot
514
+ * disagree about which repositories belong to a workspace.
478
515
  */
479
- async function resolveWorkspaceRepos(cwd, opts) {
516
+ export async function resolveWorkspaceRepos(cwd, opts) {
480
517
  const now = opts.now ?? Date.now;
481
518
  const { maxRepos, timeoutMs } = resolveOverviewLimits(opts);
482
519
  const dockerRoots = await realAll(opts.dockerWorkspaces ?? []);