@camerontaylor/paseo-server 0.8.0-fork.1

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 (928) hide show
  1. package/.env.example +31 -0
  2. package/README.md +111 -0
  3. package/dist/scripts/dev-runner.js +37 -0
  4. package/dist/scripts/mcp-stdio-socket-bridge-cli.mjs +62 -0
  5. package/dist/scripts/supervisor-entrypoint.js +160 -0
  6. package/dist/scripts/supervisor-log-config.js +31 -0
  7. package/dist/scripts/supervisor.js +313 -0
  8. package/dist/server/executable-resolution/executable-resolution.d.ts +10 -0
  9. package/dist/server/executable-resolution/executable-resolution.js +121 -0
  10. package/dist/server/executable-resolution/windows.d.ts +18 -0
  11. package/dist/server/executable-resolution/windows.js +65 -0
  12. package/dist/server/server/agent/activity-curator.d.ts +40 -0
  13. package/dist/server/server/agent/activity-curator.js +243 -0
  14. package/dist/server/server/agent/agent-archive.d.ts +11 -0
  15. package/dist/server/server/agent/agent-archive.js +16 -0
  16. package/dist/server/server/agent/agent-configuration-validator.d.ts +18 -0
  17. package/dist/server/server/agent/agent-configuration-validator.js +42 -0
  18. package/dist/server/server/agent/agent-loading.d.ts +17 -0
  19. package/dist/server/server/agent/agent-loading.js +88 -0
  20. package/dist/server/server/agent/agent-manager.d.ts +555 -0
  21. package/dist/server/server/agent/agent-manager.js +3930 -0
  22. package/dist/server/server/agent/agent-owner.d.ts +12 -0
  23. package/dist/server/server/agent/agent-owner.js +12 -0
  24. package/dist/server/server/agent/agent-projections.d.ts +26 -0
  25. package/dist/server/server/agent/agent-projections.js +414 -0
  26. package/dist/server/server/agent/agent-prompt.d.ts +91 -0
  27. package/dist/server/server/agent/agent-prompt.js +359 -0
  28. package/dist/server/server/agent/agent-response-loop.d.ts +72 -0
  29. package/dist/server/server/agent/agent-response-loop.js +336 -0
  30. package/dist/server/server/agent/agent-run-state.d.ts +76 -0
  31. package/dist/server/server/agent/agent-run-state.js +212 -0
  32. package/dist/server/server/agent/agent-sdk-types.d.ts +742 -0
  33. package/dist/server/server/agent/agent-sdk-types.js +25 -0
  34. package/dist/server/server/agent/agent-storage.d.ts +148 -0
  35. package/dist/server/server/agent/agent-storage.js +401 -0
  36. package/dist/server/server/agent/agent-stream-coalescer.d.ts +43 -0
  37. package/dist/server/server/agent/agent-stream-coalescer.js +187 -0
  38. package/dist/server/server/agent/agent-timeline-content.d.ts +6 -0
  39. package/dist/server/server/agent/agent-timeline-content.js +62 -0
  40. package/dist/server/server/agent/agent-timeline-store-types.d.ts +54 -0
  41. package/dist/server/server/agent/agent-timeline-store-types.js +2 -0
  42. package/dist/server/server/agent/agent-timeline-store.d.ts +31 -0
  43. package/dist/server/server/agent/agent-timeline-store.js +249 -0
  44. package/dist/server/server/agent/audio-utils.d.ts +3 -0
  45. package/dist/server/server/agent/audio-utils.js +19 -0
  46. package/dist/server/server/agent/create-agent/create.d.ts +102 -0
  47. package/dist/server/server/agent/create-agent/create.js +362 -0
  48. package/dist/server/server/agent/create-agent/intent.d.ts +25 -0
  49. package/dist/server/server/agent/create-agent/intent.js +30 -0
  50. package/dist/server/server/agent/create-agent-lifecycle-dispatch.d.ts +65 -0
  51. package/dist/server/server/agent/create-agent-lifecycle-dispatch.js +166 -0
  52. package/dist/server/server/agent/create-agent-mode.d.ts +13 -0
  53. package/dist/server/server/agent/create-agent-mode.js +65 -0
  54. package/dist/server/server/agent/create-agent-title.d.ts +10 -0
  55. package/dist/server/server/agent/create-agent-title.js +34 -0
  56. package/dist/server/server/agent/dictation-debug.d.ts +13 -0
  57. package/dist/server/server/agent/dictation-debug.js +50 -0
  58. package/dist/server/server/agent/import-sessions.d.ts +57 -0
  59. package/dist/server/server/agent/import-sessions.js +240 -0
  60. package/dist/server/server/agent/lifecycle-command.d.ts +73 -0
  61. package/dist/server/server/agent/lifecycle-command.js +99 -0
  62. package/dist/server/server/agent/mcp-server.d.ts +5 -0
  63. package/dist/server/server/agent/mcp-server.js +31 -0
  64. package/dist/server/server/agent/mcp-shared.d.ts +181 -0
  65. package/dist/server/server/agent/mcp-shared.js +199 -0
  66. package/dist/server/server/agent/mutable-provider-config-owner.d.ts +8 -0
  67. package/dist/server/server/agent/mutable-provider-config-owner.js +35 -0
  68. package/dist/server/server/agent/paseo-tool-policy.d.ts +9 -0
  69. package/dist/server/server/agent/paseo-tool-policy.js +16 -0
  70. package/dist/server/server/agent/pcm16-resampler.d.ts +14 -0
  71. package/dist/server/server/agent/pcm16-resampler.js +63 -0
  72. package/dist/server/server/agent/permission-response.d.ts +15 -0
  73. package/dist/server/server/agent/permission-response.js +14 -0
  74. package/dist/server/server/agent/plugin-provider.d.ts +16 -0
  75. package/dist/server/server/agent/plugin-provider.js +1356 -0
  76. package/dist/server/server/agent/prompt-attachments.d.ts +12 -0
  77. package/dist/server/server/agent/prompt-attachments.js +182 -0
  78. package/dist/server/server/agent/provider-history-timestamps.d.ts +2 -0
  79. package/dist/server/server/agent/provider-history-timestamps.js +16 -0
  80. package/dist/server/server/agent/provider-launch-config.d.ts +43 -0
  81. package/dist/server/server/agent/provider-launch-config.js +167 -0
  82. package/dist/server/server/agent/provider-notices.d.ts +4 -0
  83. package/dist/server/server/agent/provider-notices.js +9 -0
  84. package/dist/server/server/agent/provider-options.d.ts +19 -0
  85. package/dist/server/server/agent/provider-options.js +53 -0
  86. package/dist/server/server/agent/provider-refresh-deadline.d.ts +11 -0
  87. package/dist/server/server/agent/provider-refresh-deadline.js +65 -0
  88. package/dist/server/server/agent/provider-registry.d.ts +72 -0
  89. package/dist/server/server/agent/provider-registry.js +604 -0
  90. package/dist/server/server/agent/provider-runtime.d.ts +16 -0
  91. package/dist/server/server/agent/provider-runtime.js +35 -0
  92. package/dist/server/server/agent/provider-session-import.d.ts +10 -0
  93. package/dist/server/server/agent/provider-session-import.js +55 -0
  94. package/dist/server/server/agent/provider-snapshot-manager.d.ts +166 -0
  95. package/dist/server/server/agent/provider-snapshot-manager.js +843 -0
  96. package/dist/server/server/agent/provider-subagents/store.d.ts +68 -0
  97. package/dist/server/server/agent/provider-subagents/store.js +111 -0
  98. package/dist/server/server/agent/providers/acp-agent.d.ts +703 -0
  99. package/dist/server/server/agent/providers/acp-agent.js +3412 -0
  100. package/dist/server/server/agent/providers/claude/agent.d.ts +74 -0
  101. package/dist/server/server/agent/providers/claude/agent.js +5236 -0
  102. package/dist/server/server/agent/providers/claude/feature-definitions.d.ts +8 -0
  103. package/dist/server/server/agent/providers/claude/feature-definitions.js +24 -0
  104. package/dist/server/server/agent/providers/claude/hooks.d.ts +12 -0
  105. package/dist/server/server/agent/providers/claude/hooks.js +20 -0
  106. package/dist/server/server/agent/providers/claude/model-manifest.d.ts +147 -0
  107. package/dist/server/server/agent/providers/claude/model-manifest.js +342 -0
  108. package/dist/server/server/agent/providers/claude/models.d.ts +28 -0
  109. package/dist/server/server/agent/providers/claude/models.js +141 -0
  110. package/dist/server/server/agent/providers/claude/options.d.ts +85 -0
  111. package/dist/server/server/agent/providers/claude/options.js +93 -0
  112. package/dist/server/server/agent/providers/claude/partial-json.d.ts +5 -0
  113. package/dist/server/server/agent/providers/claude/partial-json.js +306 -0
  114. package/dist/server/server/agent/providers/claude/project-dir.d.ts +6 -0
  115. package/dist/server/server/agent/providers/claude/project-dir.js +57 -0
  116. package/dist/server/server/agent/providers/claude/query.d.ts +17 -0
  117. package/dist/server/server/agent/providers/claude/query.js +86 -0
  118. package/dist/server/server/agent/providers/claude/rewind.d.ts +30 -0
  119. package/dist/server/server/agent/providers/claude/rewind.js +30 -0
  120. package/dist/server/server/agent/providers/claude/side-question.d.ts +16 -0
  121. package/dist/server/server/agent/providers/claude/side-question.js +57 -0
  122. package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts +35 -0
  123. package/dist/server/server/agent/providers/claude/sidechain-tracker.js +392 -0
  124. package/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +161 -0
  125. package/dist/server/server/agent/providers/claude/subagents/live-source.js +415 -0
  126. package/dist/server/server/agent/providers/claude/subagents/observation.d.ts +53 -0
  127. package/dist/server/server/agent/providers/claude/subagents/observation.js +57 -0
  128. package/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +12 -0
  129. package/dist/server/server/agent/providers/claude/subagents/presentation.js +41 -0
  130. package/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +70 -0
  131. package/dist/server/server/agent/providers/claude/subagents/replay-source.js +305 -0
  132. package/dist/server/server/agent/providers/claude/subagents/workflow-output.d.ts +4 -0
  133. package/dist/server/server/agent/providers/claude/subagents/workflow-output.js +86 -0
  134. package/dist/server/server/agent/providers/claude/subagents/workflow-replay-source.d.ts +38 -0
  135. package/dist/server/server/agent/providers/claude/subagents/workflow-replay-source.js +225 -0
  136. package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +37 -0
  137. package/dist/server/server/agent/providers/claude/task-notification-tool-call.js +296 -0
  138. package/dist/server/server/agent/providers/claude/task-state.d.ts +18 -0
  139. package/dist/server/server/agent/providers/claude/task-state.js +185 -0
  140. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.d.ts +24 -0
  141. package/dist/server/server/agent/providers/claude/test-rewind-claude-sdk.js +23 -0
  142. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.d.ts +3 -0
  143. package/dist/server/server/agent/providers/claude/tool-call-detail-parser.js +130 -0
  144. package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts +16 -0
  145. package/dist/server/server/agent/providers/claude/tool-call-mapper.js +129 -0
  146. package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +101 -0
  147. package/dist/server/server/agent/providers/codex/app-server-transport.js +290 -0
  148. package/dist/server/server/agent/providers/codex/async-questions.d.ts +18 -0
  149. package/dist/server/server/agent/providers/codex/async-questions.js +135 -0
  150. package/dist/server/server/agent/providers/codex/options.d.ts +59 -0
  151. package/dist/server/server/agent/providers/codex/options.js +82 -0
  152. package/dist/server/server/agent/providers/codex/rewind.d.ts +24 -0
  153. package/dist/server/server/agent/providers/codex/rewind.js +77 -0
  154. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.d.ts +12 -0
  155. package/dist/server/server/agent/providers/codex/tool-call-detail-parser.js +104 -0
  156. package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts +24 -0
  157. package/dist/server/server/agent/providers/codex/tool-call-mapper.js +909 -0
  158. package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +384 -0
  159. package/dist/server/server/agent/providers/codex-app-server-agent.js +5877 -0
  160. package/dist/server/server/agent/providers/codex-feature-definitions.d.ts +11 -0
  161. package/dist/server/server/agent/providers/codex-feature-definitions.js +55 -0
  162. package/dist/server/server/agent/providers/copilot-acp-agent.d.ts +26 -0
  163. package/dist/server/server/agent/providers/copilot-acp-agent.js +187 -0
  164. package/dist/server/server/agent/providers/cursor-acp-agent.d.ts +17 -0
  165. package/dist/server/server/agent/providers/cursor-acp-agent.js +31 -0
  166. package/dist/server/server/agent/providers/diagnostic-utils.d.ts +36 -0
  167. package/dist/server/server/agent/providers/diagnostic-utils.js +356 -0
  168. package/dist/server/server/agent/providers/generic-acp-agent.d.ts +55 -0
  169. package/dist/server/server/agent/providers/generic-acp-agent.js +178 -0
  170. package/dist/server/server/agent/providers/gjc-acp-agent.d.ts +155 -0
  171. package/dist/server/server/agent/providers/gjc-acp-agent.js +588 -0
  172. package/dist/server/server/agent/providers/jsonl-frame-decoder.d.ts +17 -0
  173. package/dist/server/server/agent/providers/jsonl-frame-decoder.js +149 -0
  174. package/dist/server/server/agent/providers/jsonl-rpc-process.d.ts +63 -0
  175. package/dist/server/server/agent/providers/jsonl-rpc-process.js +207 -0
  176. package/dist/server/server/agent/providers/kimi-acp-agent.d.ts +35 -0
  177. package/dist/server/server/agent/providers/kimi-acp-agent.js +65 -0
  178. package/dist/server/server/agent/providers/kiro-acp-agent.d.ts +17 -0
  179. package/dist/server/server/agent/providers/kiro-acp-agent.js +78 -0
  180. package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +111 -0
  181. package/dist/server/server/agent/providers/mock-load-test-agent.js +1340 -0
  182. package/dist/server/server/agent/providers/mock-slow-provider.d.ts +14 -0
  183. package/dist/server/server/agent/providers/mock-slow-provider.js +40 -0
  184. package/dist/server/server/agent/providers/omp/advisor-message.d.ts +11 -0
  185. package/dist/server/server/agent/providers/omp/advisor-message.js +80 -0
  186. package/dist/server/server/agent/providers/omp/agent.d.ts +178 -0
  187. package/dist/server/server/agent/providers/omp/agent.js +1952 -0
  188. package/dist/server/server/agent/providers/omp/cli-runtime.d.ts +22 -0
  189. package/dist/server/server/agent/providers/omp/cli-runtime.js +208 -0
  190. package/dist/server/server/agent/providers/omp/commands.d.ts +8 -0
  191. package/dist/server/server/agent/providers/omp/commands.js +62 -0
  192. package/dist/server/server/agent/providers/omp/custom-message.d.ts +7 -0
  193. package/dist/server/server/agent/providers/omp/custom-message.js +4 -0
  194. package/dist/server/server/agent/providers/omp/event-mapper.d.ts +13 -0
  195. package/dist/server/server/agent/providers/omp/event-mapper.js +267 -0
  196. package/dist/server/server/agent/providers/omp/history-hooks.d.ts +3 -0
  197. package/dist/server/server/agent/providers/omp/history-hooks.js +13 -0
  198. package/dist/server/server/agent/providers/omp/history.d.ts +19 -0
  199. package/dist/server/server/agent/providers/omp/history.js +306 -0
  200. package/dist/server/server/agent/providers/omp/host-tools.d.ts +14 -0
  201. package/dist/server/server/agent/providers/omp/host-tools.js +196 -0
  202. package/dist/server/server/agent/providers/omp/map-omp-model.d.ts +11 -0
  203. package/dist/server/server/agent/providers/omp/map-omp-model.js +67 -0
  204. package/dist/server/server/agent/providers/omp/message-history.d.ts +38 -0
  205. package/dist/server/server/agent/providers/omp/message-history.js +216 -0
  206. package/dist/server/server/agent/providers/omp/protocol-session.d.ts +13 -0
  207. package/dist/server/server/agent/providers/omp/protocol-session.js +39 -0
  208. package/dist/server/server/agent/providers/omp/provider-config.d.ts +43 -0
  209. package/dist/server/server/agent/providers/omp/provider-config.js +120 -0
  210. package/dist/server/server/agent/providers/omp/rpc-types.d.ts +2040 -0
  211. package/dist/server/server/agent/providers/omp/rpc-types.js +551 -0
  212. package/dist/server/server/agent/providers/omp/rpc-ui-permission-mapper.d.ts +24 -0
  213. package/dist/server/server/agent/providers/omp/rpc-ui-permission-mapper.js +156 -0
  214. package/dist/server/server/agent/providers/omp/runtime.d.ts +85 -0
  215. package/dist/server/server/agent/providers/omp/runtime.js +62 -0
  216. package/dist/server/server/agent/providers/omp/session-descriptor.d.ts +16 -0
  217. package/dist/server/server/agent/providers/omp/session-descriptor.js +389 -0
  218. package/dist/server/server/agent/providers/omp/subagent-card-tracker.d.ts +33 -0
  219. package/dist/server/server/agent/providers/omp/subagent-card-tracker.js +264 -0
  220. package/dist/server/server/agent/providers/omp/subagent-index.d.ts +13 -0
  221. package/dist/server/server/agent/providers/omp/subagent-index.js +111 -0
  222. package/dist/server/server/agent/providers/omp/subagent-title.d.ts +2 -0
  223. package/dist/server/server/agent/providers/omp/subagent-title.js +14 -0
  224. package/dist/server/server/agent/providers/omp/system-notice.d.ts +8 -0
  225. package/dist/server/server/agent/providers/omp/system-notice.js +68 -0
  226. package/dist/server/server/agent/providers/omp/todo-mapper.d.ts +9 -0
  227. package/dist/server/server/agent/providers/omp/todo-mapper.js +52 -0
  228. package/dist/server/server/agent/providers/omp/tool-call-detail.d.ts +110 -0
  229. package/dist/server/server/agent/providers/omp/tool-call-detail.js +288 -0
  230. package/dist/server/server/agent/providers/omp/tool-call-id.d.ts +4 -0
  231. package/dist/server/server/agent/providers/omp/tool-call-id.js +34 -0
  232. package/dist/server/server/agent/providers/omp/tool-call-mapper.d.ts +7 -0
  233. package/dist/server/server/agent/providers/omp/tool-call-mapper.js +98 -0
  234. package/dist/server/server/agent/providers/omp/usage-poller.d.ts +32 -0
  235. package/dist/server/server/agent/providers/omp/usage-poller.js +141 -0
  236. package/dist/server/server/agent/providers/opencode/bridge-plugin.bundle.mjs +14678 -0
  237. package/dist/server/server/agent/providers/opencode/bridge.d.ts +39 -0
  238. package/dist/server/server/agent/providers/opencode/bridge.js +249 -0
  239. package/dist/server/server/agent/providers/opencode/event-consumer.d.ts +60 -0
  240. package/dist/server/server/agent/providers/opencode/event-consumer.js +221 -0
  241. package/dist/server/server/agent/providers/opencode/options.d.ts +156 -0
  242. package/dist/server/server/agent/providers/opencode/options.js +62 -0
  243. package/dist/server/server/agent/providers/opencode/paths.d.ts +2 -0
  244. package/dist/server/server/agent/providers/opencode/paths.js +7 -0
  245. package/dist/server/server/agent/providers/opencode/rewind.d.ts +18 -0
  246. package/dist/server/server/agent/providers/opencode/rewind.js +14 -0
  247. package/dist/server/server/agent/providers/opencode/server-manager.d.ts +101 -0
  248. package/dist/server/server/agent/providers/opencode/server-manager.js +513 -0
  249. package/dist/server/server/agent/providers/opencode/side-question.d.ts +78 -0
  250. package/dist/server/server/agent/providers/opencode/side-question.js +172 -0
  251. package/dist/server/server/agent/providers/opencode/subagent-presentation.d.ts +36 -0
  252. package/dist/server/server/agent/providers/opencode/subagent-presentation.js +62 -0
  253. package/dist/server/server/agent/providers/opencode/test-server-manager.d.ts +22 -0
  254. package/dist/server/server/agent/providers/opencode/test-server-manager.js +43 -0
  255. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +3 -0
  256. package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +256 -0
  257. package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts +13 -0
  258. package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +53 -0
  259. package/dist/server/server/agent/providers/opencode-agent.d.ts +393 -0
  260. package/dist/server/server/agent/providers/opencode-agent.js +4106 -0
  261. package/dist/server/server/agent/providers/pi/agent.d.ts +164 -0
  262. package/dist/server/server/agent/providers/pi/agent.js +2236 -0
  263. package/dist/server/server/agent/providers/pi/cli-runtime.d.ts +21 -0
  264. package/dist/server/server/agent/providers/pi/cli-runtime.js +177 -0
  265. package/dist/server/server/agent/providers/pi/history-mapper.d.ts +36 -0
  266. package/dist/server/server/agent/providers/pi/history-mapper.js +212 -0
  267. package/dist/server/server/agent/providers/pi/rewind.d.ts +8 -0
  268. package/dist/server/server/agent/providers/pi/rewind.js +8 -0
  269. package/dist/server/server/agent/providers/pi/rpc-types.d.ts +252 -0
  270. package/dist/server/server/agent/providers/pi/rpc-types.js +2 -0
  271. package/dist/server/server/agent/providers/pi/runtime.d.ts +77 -0
  272. package/dist/server/server/agent/providers/pi/runtime.js +65 -0
  273. package/dist/server/server/agent/providers/pi/session-descriptor.d.ts +16 -0
  274. package/dist/server/server/agent/providers/pi/session-descriptor.js +355 -0
  275. package/dist/server/server/agent/providers/pi/tool-call-mapper.d.ts +113 -0
  276. package/dist/server/server/agent/providers/pi/tool-call-mapper.js +340 -0
  277. package/dist/server/server/agent/providers/pi/usage-poller.d.ts +32 -0
  278. package/dist/server/server/agent/providers/pi/usage-poller.js +141 -0
  279. package/dist/server/server/agent/providers/provider-image-output.d.ts +25 -0
  280. package/dist/server/server/agent/providers/provider-image-output.js +165 -0
  281. package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
  282. package/dist/server/server/agent/providers/provider-runner.js +81 -0
  283. package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +884 -0
  284. package/dist/server/server/agent/providers/tool-call-detail-primitives.js +778 -0
  285. package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +25 -0
  286. package/dist/server/server/agent/providers/tool-call-mapper-utils.js +208 -0
  287. package/dist/server/server/agent/providers/trae-acp-agent.d.ts +15 -0
  288. package/dist/server/server/agent/providers/trae-acp-agent.js +18 -0
  289. package/dist/server/server/agent/recordings-debug.d.ts +3 -0
  290. package/dist/server/server/agent/recordings-debug.js +19 -0
  291. package/dist/server/server/agent/rewind/rewind.d.ts +10 -0
  292. package/dist/server/server/agent/rewind/rewind.js +29 -0
  293. package/dist/server/server/agent/rewind/test-rewind-session.d.ts +48 -0
  294. package/dist/server/server/agent/rewind/test-rewind-session.js +88 -0
  295. package/dist/server/server/agent/runtime-mcp-config.d.ts +14 -0
  296. package/dist/server/server/agent/runtime-mcp-config.js +53 -0
  297. package/dist/server/server/agent/side-conversations/store.d.ts +33 -0
  298. package/dist/server/server/agent/side-conversations/store.js +62 -0
  299. package/dist/server/server/agent/stale-provider-session-error.d.ts +6 -0
  300. package/dist/server/server/agent/stale-provider-session-error.js +11 -0
  301. package/dist/server/server/agent/structured-generation-providers.d.ts +29 -0
  302. package/dist/server/server/agent/structured-generation-providers.js +193 -0
  303. package/dist/server/server/agent/stt-debug.d.ts +10 -0
  304. package/dist/server/server/agent/stt-debug.js +33 -0
  305. package/dist/server/server/agent/stt-manager.d.ts +38 -0
  306. package/dist/server/server/agent/stt-manager.js +246 -0
  307. package/dist/server/server/agent/system-prompt.d.ts +2 -0
  308. package/dist/server/server/agent/system-prompt.js +8 -0
  309. package/dist/server/server/agent/timeline-append.d.ts +10 -0
  310. package/dist/server/server/agent/timeline-append.js +27 -0
  311. package/dist/server/server/agent/timeline-page-bounds.d.ts +19 -0
  312. package/dist/server/server/agent/timeline-page-bounds.js +37 -0
  313. package/dist/server/server/agent/timeline-projection.d.ts +74 -0
  314. package/dist/server/server/agent/timeline-projection.js +467 -0
  315. package/dist/server/server/agent/timeline-prompt-index.d.ts +12 -0
  316. package/dist/server/server/agent/timeline-prompt-index.js +23 -0
  317. package/dist/server/server/agent/tools/paseo-tool-serialization.d.ts +4 -0
  318. package/dist/server/server/agent/tools/paseo-tool-serialization.js +58 -0
  319. package/dist/server/server/agent/tools/paseo-tools.d.ts +62 -0
  320. package/dist/server/server/agent/tools/paseo-tools.js +2445 -0
  321. package/dist/server/server/agent/tools/types.d.ts +39 -0
  322. package/dist/server/server/agent/tools/types.js +2 -0
  323. package/dist/server/server/agent/tts-debug.d.ts +8 -0
  324. package/dist/server/server/agent/tts-debug.js +24 -0
  325. package/dist/server/server/agent/tts-manager.d.ts +41 -0
  326. package/dist/server/server/agent/tts-manager.js +375 -0
  327. package/dist/server/server/agent-attention-policy.d.ts +29 -0
  328. package/dist/server/server/agent-attention-policy.js +36 -0
  329. package/dist/server/server/agent-history-search.d.ts +48 -0
  330. package/dist/server/server/agent-history-search.js +129 -0
  331. package/dist/server/server/atomic-file.d.ts +3 -0
  332. package/dist/server/server/atomic-file.js +19 -0
  333. package/dist/server/server/auth.d.ts +38 -0
  334. package/dist/server/server/auth.js +122 -0
  335. package/dist/server/server/authorization/index.d.ts +18 -0
  336. package/dist/server/server/authorization/index.js +47 -0
  337. package/dist/server/server/authorization/operation-permissions.d.ts +8 -0
  338. package/dist/server/server/authorization/operation-permissions.js +438 -0
  339. package/dist/server/server/auto-archive-on-merge/archive-if-safe.d.ts +40 -0
  340. package/dist/server/server/auto-archive-on-merge/archive-if-safe.js +64 -0
  341. package/dist/server/server/auto-archive-on-merge/index.d.ts +13 -0
  342. package/dist/server/server/auto-archive-on-merge/index.js +77 -0
  343. package/dist/server/server/bootstrap.d.ts +166 -0
  344. package/dist/server/server/bootstrap.js +1388 -0
  345. package/dist/server/server/browser-tools/broker.d.ts +45 -0
  346. package/dist/server/server/browser-tools/broker.js +390 -0
  347. package/dist/server/server/browser-tools/errors.d.ts +22 -0
  348. package/dist/server/server/browser-tools/errors.js +27 -0
  349. package/dist/server/server/browser-tools/policy.d.ts +10 -0
  350. package/dist/server/server/browser-tools/policy.js +16 -0
  351. package/dist/server/server/browser-tools/tools.d.ts +16 -0
  352. package/dist/server/server/browser-tools/tools.js +796 -0
  353. package/dist/server/server/checkout/status-projection.d.ts +19 -0
  354. package/dist/server/server/checkout/status-projection.js +127 -0
  355. package/dist/server/server/checkout-diff-manager.d.ts +48 -0
  356. package/dist/server/server/checkout-diff-manager.js +284 -0
  357. package/dist/server/server/checkout-git-utils.d.ts +11 -0
  358. package/dist/server/server/checkout-git-utils.js +34 -0
  359. package/dist/server/server/client-message-id.d.ts +3 -0
  360. package/dist/server/server/client-message-id.js +12 -0
  361. package/dist/server/server/config.d.ts +26 -0
  362. package/dist/server/server/config.js +594 -0
  363. package/dist/server/server/connection-offer.d.ts +20 -0
  364. package/dist/server/server/connection-offer.js +59 -0
  365. package/dist/server/server/creation/index.d.ts +41 -0
  366. package/dist/server/server/creation/index.js +250 -0
  367. package/dist/server/server/daemon-config-store.d.ts +63 -0
  368. package/dist/server/server/daemon-config-store.js +524 -0
  369. package/dist/server/server/daemon-keypair.d.ts +8 -0
  370. package/dist/server/server/daemon-keypair.js +42 -0
  371. package/dist/server/server/daemon-version.d.ts +5 -0
  372. package/dist/server/server/daemon-version.js +22 -0
  373. package/dist/server/server/daemon-worker.d.ts +2 -0
  374. package/dist/server/server/daemon-worker.js +287 -0
  375. package/dist/server/server/dictation/dictation-stream-manager.d.ts +88 -0
  376. package/dist/server/server/dictation/dictation-stream-manager.js +578 -0
  377. package/dist/server/server/directory-sync/index.d.ts +45 -0
  378. package/dist/server/server/directory-sync/index.js +98 -0
  379. package/dist/server/server/directory-sync/internal/versioned-collection.d.ts +56 -0
  380. package/dist/server/server/directory-sync/internal/versioned-collection.js +94 -0
  381. package/dist/server/server/exports.d.ts +24 -0
  382. package/dist/server/server/exports.js +24 -0
  383. package/dist/server/server/file-download/token-store.d.ts +24 -0
  384. package/dist/server/server/file-download/token-store.js +40 -0
  385. package/dist/server/server/file-explorer/observer.d.ts +32 -0
  386. package/dist/server/server/file-explorer/observer.js +130 -0
  387. package/dist/server/server/file-explorer/service.d.ts +125 -0
  388. package/dist/server/server/file-explorer/service.js +663 -0
  389. package/dist/server/server/file-observer/index.d.ts +43 -0
  390. package/dist/server/server/file-observer/index.js +114 -0
  391. package/dist/server/server/file-observer/internal/contracts.d.ts +26 -0
  392. package/dist/server/server/file-observer/internal/contracts.js +2 -0
  393. package/dist/server/server/file-observer/internal/linux.d.ts +4 -0
  394. package/dist/server/server/file-observer/internal/linux.js +260 -0
  395. package/dist/server/server/file-observer/internal/native-recursive.d.ts +9 -0
  396. package/dist/server/server/file-observer/internal/native-recursive.js +577 -0
  397. package/dist/server/server/file-observer/internal/observation.d.ts +21 -0
  398. package/dist/server/server/file-observer/internal/observation.js +129 -0
  399. package/dist/server/server/file-observer/internal/paths.d.ts +10 -0
  400. package/dist/server/server/file-observer/internal/paths.js +43 -0
  401. package/dist/server/server/file-upload/index.d.ts +27 -0
  402. package/dist/server/server/file-upload/index.js +158 -0
  403. package/dist/server/server/git-metadata-event-rules.d.ts +123 -0
  404. package/dist/server/server/git-metadata-event-rules.js +152 -0
  405. package/dist/server/server/hostnames.d.ts +13 -0
  406. package/dist/server/server/hostnames.js +94 -0
  407. package/dist/server/server/hub/daemon-executions.d.ts +89 -0
  408. package/dist/server/server/hub/daemon-executions.js +287 -0
  409. package/dist/server/server/hub/execution-controller.d.ts +30 -0
  410. package/dist/server/server/hub/execution-controller.js +220 -0
  411. package/dist/server/server/hub/relationship-controller.d.ts +116 -0
  412. package/dist/server/server/hub/relationship-controller.js +534 -0
  413. package/dist/server/server/hub/relationship-remote.d.ts +68 -0
  414. package/dist/server/server/hub/relationship-remote.js +159 -0
  415. package/dist/server/server/hub/relationship-retry.d.ts +7 -0
  416. package/dist/server/server/hub/relationship-retry.js +15 -0
  417. package/dist/server/server/json-utils.d.ts +11 -0
  418. package/dist/server/server/json-utils.js +45 -0
  419. package/dist/server/server/lifecycle-reasons.d.ts +4 -0
  420. package/dist/server/server/lifecycle-reasons.js +6 -0
  421. package/dist/server/server/logger.d.ts +29 -0
  422. package/dist/server/server/logger.js +127 -0
  423. package/dist/server/server/managed-processes/managed-processes.d.ts +76 -0
  424. package/dist/server/server/managed-processes/managed-processes.js +326 -0
  425. package/dist/server/server/messages.d.ts +9 -0
  426. package/dist/server/server/messages.js +29 -0
  427. package/dist/server/server/migrations/backfill-workspace-id.migration.d.ts +9 -0
  428. package/dist/server/server/migrations/backfill-workspace-id.migration.js +64 -0
  429. package/dist/server/server/orchestration-skills/index.d.ts +18 -0
  430. package/dist/server/server/orchestration-skills/index.js +18 -0
  431. package/dist/server/server/orchestration-skills/internal/controller.d.ts +39 -0
  432. package/dist/server/server/orchestration-skills/internal/controller.js +108 -0
  433. package/dist/server/server/orchestration-skills/internal/operations.d.ts +43 -0
  434. package/dist/server/server/orchestration-skills/internal/operations.js +178 -0
  435. package/dist/server/server/orchestration-skills/internal/paths.d.ts +4 -0
  436. package/dist/server/server/orchestration-skills/internal/paths.js +21 -0
  437. package/dist/server/server/orchestration-skills/internal/selection-store.d.ts +12 -0
  438. package/dist/server/server/orchestration-skills/internal/selection-store.js +39 -0
  439. package/dist/server/server/orchestration-skills/internal/sync.d.ts +21 -0
  440. package/dist/server/server/orchestration-skills/internal/sync.js +177 -0
  441. package/dist/server/server/orchestration-skills/internal/transaction.d.ts +22 -0
  442. package/dist/server/server/orchestration-skills/internal/transaction.js +483 -0
  443. package/dist/server/server/package-version.d.ts +19 -0
  444. package/dist/server/server/package-version.js +60 -0
  445. package/dist/server/server/pagination/cursor.d.ts +16 -0
  446. package/dist/server/server/pagination/cursor.js +62 -0
  447. package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
  448. package/dist/server/server/pagination/sortable-pager.js +68 -0
  449. package/dist/server/server/pairing-offer.d.ts +18 -0
  450. package/dist/server/server/pairing-offer.js +47 -0
  451. package/dist/server/server/pairing-qr.d.ts +2 -0
  452. package/dist/server/server/pairing-qr.js +15 -0
  453. package/dist/server/server/paseo-env.d.ts +13 -0
  454. package/dist/server/server/paseo-env.js +54 -0
  455. package/dist/server/server/paseo-home.d.ts +2 -0
  456. package/dist/server/server/paseo-home.js +19 -0
  457. package/dist/server/server/paseo-worktree-service.d.ts +45 -0
  458. package/dist/server/server/paseo-worktree-service.js +191 -0
  459. package/dist/server/server/path-utils.d.ts +5 -0
  460. package/dist/server/server/path-utils.js +34 -0
  461. package/dist/server/server/persisted-config.d.ts +397 -0
  462. package/dist/server/server/persisted-config.js +411 -0
  463. package/dist/server/server/persistence-hooks.d.ts +32 -0
  464. package/dist/server/server/persistence-hooks.js +96 -0
  465. package/dist/server/server/pid-lock.d.ts +44 -0
  466. package/dist/server/server/pid-lock.js +285 -0
  467. package/dist/server/server/plugins/compiler-imports.d.ts +13 -0
  468. package/dist/server/server/plugins/compiler-imports.js +90 -0
  469. package/dist/server/server/plugins/compiler.d.ts +10 -0
  470. package/dist/server/server/plugins/compiler.js +354 -0
  471. package/dist/server/server/plugins/daemon-transport.d.ts +9 -0
  472. package/dist/server/server/plugins/daemon-transport.js +68 -0
  473. package/dist/server/server/plugins/index.d.ts +102 -0
  474. package/dist/server/server/plugins/index.js +575 -0
  475. package/dist/server/server/plugins/lifecycle/index.d.ts +40 -0
  476. package/dist/server/server/plugins/lifecycle/index.js +200 -0
  477. package/dist/server/server/plugins/managed-source.d.ts +50 -0
  478. package/dist/server/server/plugins/managed-source.js +327 -0
  479. package/dist/server/server/plugins/manifest.d.ts +12 -0
  480. package/dist/server/server/plugins/manifest.js +26 -0
  481. package/dist/server/server/plugins/plugin-process-protocol.d.ts +120 -0
  482. package/dist/server/server/plugins/plugin-process-protocol.js +154 -0
  483. package/dist/server/server/plugins/plugin-process.d.ts +2 -0
  484. package/dist/server/server/plugins/plugin-process.js +419 -0
  485. package/dist/server/server/plugins/plugin-sdk-specifiers.d.ts +5 -0
  486. package/dist/server/server/plugins/plugin-sdk-specifiers.js +23 -0
  487. package/dist/server/server/plugins/plugin-session-identity.d.ts +4 -0
  488. package/dist/server/server/plugins/plugin-session-identity.js +11 -0
  489. package/dist/server/server/plugins/preparation.d.ts +4 -0
  490. package/dist/server/server/plugins/preparation.js +49 -0
  491. package/dist/server/server/plugins/provider-icon.d.ts +2 -0
  492. package/dist/server/server/plugins/provider-icon.js +55 -0
  493. package/dist/server/server/plugins/runtime.d.ts +83 -0
  494. package/dist/server/server/plugins/runtime.js +836 -0
  495. package/dist/server/server/plugins/session-socket.d.ts +23 -0
  496. package/dist/server/server/plugins/session-socket.js +82 -0
  497. package/dist/server/server/plugins/settings/index.d.ts +96 -0
  498. package/dist/server/server/plugins/settings/index.js +115 -0
  499. package/dist/server/server/private-files.d.ts +6 -0
  500. package/dist/server/server/private-files.js +37 -0
  501. package/dist/server/server/process-diagnostics.d.ts +17 -0
  502. package/dist/server/server/process-diagnostics.js +22 -0
  503. package/dist/server/server/project-directory-service.d.ts +30 -0
  504. package/dist/server/server/project-directory-service.js +120 -0
  505. package/dist/server/server/project-key.d.ts +14 -0
  506. package/dist/server/server/project-key.js +44 -0
  507. package/dist/server/server/push/index.d.ts +16 -0
  508. package/dist/server/server/push/index.js +26 -0
  509. package/dist/server/server/push/push-service.d.ts +19 -0
  510. package/dist/server/server/push/push-service.js +66 -0
  511. package/dist/server/server/push/token-store.d.ts +22 -0
  512. package/dist/server/server/push/token-store.js +125 -0
  513. package/dist/server/server/relay-runtime.d.ts +27 -0
  514. package/dist/server/server/relay-runtime.js +46 -0
  515. package/dist/server/server/relay-transport.d.ts +33 -0
  516. package/dist/server/server/relay-transport.js +481 -0
  517. package/dist/server/server/request-receipts/index.d.ts +33 -0
  518. package/dist/server/server/request-receipts/index.js +131 -0
  519. package/dist/server/server/resolve-workspace-id-for-path.d.ts +3 -0
  520. package/dist/server/server/resolve-workspace-id-for-path.js +41 -0
  521. package/dist/server/server/resolve-worktree-creation-intent.d.ts +44 -0
  522. package/dist/server/server/resolve-worktree-creation-intent.js +186 -0
  523. package/dist/server/server/schedule/cron.d.ts +4 -0
  524. package/dist/server/server/schedule/cron.js +83 -0
  525. package/dist/server/server/schedule/service.d.ts +75 -0
  526. package/dist/server/server/schedule/service.js +810 -0
  527. package/dist/server/server/schedule/store.d.ts +27 -0
  528. package/dist/server/server/schedule/store.js +190 -0
  529. package/dist/server/server/script-health-monitor.d.ts +39 -0
  530. package/dist/server/server/script-health-monitor.js +159 -0
  531. package/dist/server/server/script-proxy.d.ts +3 -0
  532. package/dist/server/server/script-proxy.js +2 -0
  533. package/dist/server/server/script-route-branch-handler.d.ts +10 -0
  534. package/dist/server/server/script-route-branch-handler.js +11 -0
  535. package/dist/server/server/script-status-projection.d.ts +36 -0
  536. package/dist/server/server/script-status-projection.js +200 -0
  537. package/dist/server/server/server-id.d.ts +17 -0
  538. package/dist/server/server/server-id.js +68 -0
  539. package/dist/server/server/service-proxy.d.ts +237 -0
  540. package/dist/server/server/service-proxy.js +679 -0
  541. package/dist/server/server/session/agent-config/agent-config-session.d.ts +75 -0
  542. package/dist/server/server/session/agent-config/agent-config-session.js +151 -0
  543. package/dist/server/server/session/agent-updates/agent-updates-service.d.ts +65 -0
  544. package/dist/server/server/session/agent-updates/agent-updates-service.js +266 -0
  545. package/dist/server/server/session/checkout/checkout-session.d.ts +150 -0
  546. package/dist/server/server/session/checkout/checkout-session.js +1187 -0
  547. package/dist/server/server/session/checkout/git-metadata-generator.d.ts +53 -0
  548. package/dist/server/server/session/checkout/git-metadata-generator.js +159 -0
  549. package/dist/server/server/session/daemon/daemon-self-update-session-controller.d.ts +34 -0
  550. package/dist/server/server/session/daemon/daemon-self-update-session-controller.js +90 -0
  551. package/dist/server/server/session/daemon/daemon-self-updater.d.ts +33 -0
  552. package/dist/server/server/session/daemon/daemon-self-updater.js +60 -0
  553. package/dist/server/server/session/daemon/daemon-session.d.ts +90 -0
  554. package/dist/server/server/session/daemon/daemon-session.js +224 -0
  555. package/dist/server/server/session/daemon/diagnostics.d.ts +41 -0
  556. package/dist/server/server/session/daemon/diagnostics.js +431 -0
  557. package/dist/server/server/session/daemon/install-origin.d.ts +7 -0
  558. package/dist/server/server/session/daemon/install-origin.js +64 -0
  559. package/dist/server/server/session/daemon/npm-global-cli.d.ts +29 -0
  560. package/dist/server/server/session/daemon/npm-global-cli.js +98 -0
  561. package/dist/server/server/session/files/workspace-files-session.d.ts +55 -0
  562. package/dist/server/server/session/files/workspace-files-session.js +359 -0
  563. package/dist/server/server/session/git-mutation/git-mutation-service.d.ts +32 -0
  564. package/dist/server/server/session/git-mutation/git-mutation-service.js +74 -0
  565. package/dist/server/server/session/project-config/project-config-session.d.ts +35 -0
  566. package/dist/server/server/session/project-config/project-config-session.js +143 -0
  567. package/dist/server/server/session/project-config/worktree-setup-commit-status.d.ts +6 -0
  568. package/dist/server/server/session/project-config/worktree-setup-commit-status.js +38 -0
  569. package/dist/server/server/session/provider/provider-catalog-session.d.ts +78 -0
  570. package/dist/server/server/session/provider/provider-catalog-session.js +388 -0
  571. package/dist/server/server/session/schedule/schedule-session.d.ts +47 -0
  572. package/dist/server/server/session/schedule/schedule-session.js +188 -0
  573. package/dist/server/server/session/voice/voice-session.d.ts +166 -0
  574. package/dist/server/server/session/voice/voice-session.js +904 -0
  575. package/dist/server/server/session/voice/voice-turn-controller.d.ts +38 -0
  576. package/dist/server/server/session/voice/voice-turn-controller.js +393 -0
  577. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.d.ts +42 -0
  578. package/dist/server/server/session/workspace-git-observer/workspace-git-observer-service.js +170 -0
  579. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.d.ts +59 -0
  580. package/dist/server/server/session/workspace-provisioning/workspace-provisioning-service.js +326 -0
  581. package/dist/server/server/session/workspace-recovery/workspace-recovery-service.d.ts +30 -0
  582. package/dist/server/server/session/workspace-recovery/workspace-recovery-service.js +178 -0
  583. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.d.ts +54 -0
  584. package/dist/server/server/session/workspace-scripts/workspace-scripts-service.js +156 -0
  585. package/dist/server/server/session.d.ts +555 -0
  586. package/dist/server/server/session.js +6540 -0
  587. package/dist/server/server/speech/audio.d.ts +10 -0
  588. package/dist/server/server/speech/audio.js +101 -0
  589. package/dist/server/server/speech/provider-resolver.d.ts +3 -0
  590. package/dist/server/server/speech/provider-resolver.js +7 -0
  591. package/dist/server/server/speech/providers/local/config.d.ts +30 -0
  592. package/dist/server/server/speech/providers/local/config.js +134 -0
  593. package/dist/server/server/speech/providers/local/models.d.ts +12 -0
  594. package/dist/server/server/speech/providers/local/models.js +18 -0
  595. package/dist/server/server/speech/providers/local/runtime.d.ts +31 -0
  596. package/dist/server/server/speech/providers/local/runtime.js +135 -0
  597. package/dist/server/server/speech/providers/local/sherpa/assets/silero_vad.onnx +0 -0
  598. package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +56 -0
  599. package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +74 -0
  600. package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts +17 -0
  601. package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +145 -0
  602. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.d.ts +49 -0
  603. package/dist/server/server/speech/providers/local/sherpa/sherpa-offline-recognizer.js +73 -0
  604. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.d.ts +9 -0
  605. package/dist/server/server/speech/providers/local/sherpa/sherpa-onnx-node-loader.js +107 -0
  606. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.d.ts +28 -0
  607. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-realtime-session.js +137 -0
  608. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.d.ts +21 -0
  609. package/dist/server/server/speech/providers/local/sherpa/sherpa-parakeet-stt.js +133 -0
  610. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.d.ts +18 -0
  611. package/dist/server/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  612. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.d.ts +21 -0
  613. package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js +101 -0
  614. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.d.ts +19 -0
  615. package/dist/server/server/speech/providers/local/sherpa/silero-vad-provider.js +49 -0
  616. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.d.ts +38 -0
  617. package/dist/server/server/speech/providers/local/sherpa/silero-vad-session.js +176 -0
  618. package/dist/server/server/speech/providers/local/worker-bytes.d.ts +4 -0
  619. package/dist/server/server/speech/providers/local/worker-bytes.js +9 -0
  620. package/dist/server/server/speech/providers/local/worker-client.d.ts +93 -0
  621. package/dist/server/server/speech/providers/local/worker-client.js +590 -0
  622. package/dist/server/server/speech/providers/local/worker-process.d.ts +2 -0
  623. package/dist/server/server/speech/providers/local/worker-process.js +270 -0
  624. package/dist/server/server/speech/providers/local/worker-protocol.d.ts +95 -0
  625. package/dist/server/server/speech/providers/local/worker-protocol.js +2 -0
  626. package/dist/server/server/speech/providers/openai/config.d.ts +19 -0
  627. package/dist/server/server/speech/providers/openai/config.js +148 -0
  628. package/dist/server/server/speech/providers/openai/runtime.d.ts +29 -0
  629. package/dist/server/server/speech/providers/openai/runtime.js +102 -0
  630. package/dist/server/server/speech/providers/openai/stt.d.ts +23 -0
  631. package/dist/server/server/speech/providers/openai/stt.js +209 -0
  632. package/dist/server/server/speech/providers/openai/tts.d.ts +19 -0
  633. package/dist/server/server/speech/providers/openai/tts.js +48 -0
  634. package/dist/server/server/speech/speech-config-resolver.d.ts +11 -0
  635. package/dist/server/server/speech/speech-config-resolver.js +132 -0
  636. package/dist/server/server/speech/speech-provider.d.ts +59 -0
  637. package/dist/server/server/speech/speech-provider.js +2 -0
  638. package/dist/server/server/speech/speech-runtime.d.ts +45 -0
  639. package/dist/server/server/speech/speech-runtime.js +571 -0
  640. package/dist/server/server/speech/speech-types.d.ts +22 -0
  641. package/dist/server/server/speech/speech-types.js +8 -0
  642. package/dist/server/server/speech/turn-detection-provider.d.ts +23 -0
  643. package/dist/server/server/speech/turn-detection-provider.js +2 -0
  644. package/dist/server/server/utils/diff-highlighter.d.ts +57 -0
  645. package/dist/server/server/utils/diff-highlighter.js +304 -0
  646. package/dist/server/server/voice-config.d.ts +15 -0
  647. package/dist/server/server/voice-config.js +54 -0
  648. package/dist/server/server/voice-permission-policy.d.ts +4 -0
  649. package/dist/server/server/voice-permission-policy.js +13 -0
  650. package/dist/server/server/voice-types.d.ts +12 -0
  651. package/dist/server/server/voice-types.js +2 -0
  652. package/dist/server/server/watcher-liveness-canary.d.ts +11 -0
  653. package/dist/server/server/watcher-liveness-canary.js +53 -0
  654. package/dist/server/server/web-ui.d.ts +10 -0
  655. package/dist/server/server/web-ui.js +205 -0
  656. package/dist/server/server/websocket/encrypted-relay-socket.d.ts +23 -0
  657. package/dist/server/server/websocket/encrypted-relay-socket.js +64 -0
  658. package/dist/server/server/websocket/physical-socket.d.ts +36 -0
  659. package/dist/server/server/websocket/physical-socket.js +95 -0
  660. package/dist/server/server/websocket/runtime-metrics.d.ts +95 -0
  661. package/dist/server/server/websocket/runtime-metrics.js +148 -0
  662. package/dist/server/server/websocket-server.d.ts +214 -0
  663. package/dist/server/server/websocket-server.js +2258 -0
  664. package/dist/server/server/workspace-archive-service.d.ts +63 -0
  665. package/dist/server/server/workspace-archive-service.js +355 -0
  666. package/dist/server/server/workspace-auto-name.d.ts +55 -0
  667. package/dist/server/server/workspace-auto-name.js +127 -0
  668. package/dist/server/server/workspace-automation-gate.d.ts +16 -0
  669. package/dist/server/server/workspace-automation-gate.js +35 -0
  670. package/dist/server/server/workspace-bootstrap-dedupe.d.ts +34 -0
  671. package/dist/server/server/workspace-bootstrap-dedupe.js +23 -0
  672. package/dist/server/server/workspace-directory.d.ts +99 -0
  673. package/dist/server/server/workspace-directory.js +467 -0
  674. package/dist/server/server/workspace-git-fetch.d.ts +33 -0
  675. package/dist/server/server/workspace-git-fetch.js +108 -0
  676. package/dist/server/server/workspace-git-metadata.d.ts +8 -0
  677. package/dist/server/server/workspace-git-metadata.js +24 -0
  678. package/dist/server/server/workspace-git-service.d.ts +348 -0
  679. package/dist/server/server/workspace-git-service.js +2534 -0
  680. package/dist/server/server/workspace-labels/index.d.ts +14 -0
  681. package/dist/server/server/workspace-labels/index.js +10 -0
  682. package/dist/server/server/workspace-labels/internal/catalog-store.d.ts +50 -0
  683. package/dist/server/server/workspace-labels/internal/catalog-store.js +203 -0
  684. package/dist/server/server/workspace-labels/internal/sequence.d.ts +43 -0
  685. package/dist/server/server/workspace-labels/internal/sequence.js +80 -0
  686. package/dist/server/server/workspace-labels/internal/service.d.ts +57 -0
  687. package/dist/server/server/workspace-labels/internal/service.js +224 -0
  688. package/dist/server/server/workspace-reconciliation-service.d.ts +103 -0
  689. package/dist/server/server/workspace-reconciliation-service.js +379 -0
  690. package/dist/server/server/workspace-registry-bootstrap-legacy.d.ts +21 -0
  691. package/dist/server/server/workspace-registry-bootstrap-legacy.js +57 -0
  692. package/dist/server/server/workspace-registry-bootstrap.d.ts +14 -0
  693. package/dist/server/server/workspace-registry-bootstrap.js +155 -0
  694. package/dist/server/server/workspace-registry-model.d.ts +56 -0
  695. package/dist/server/server/workspace-registry-model.js +150 -0
  696. package/dist/server/server/workspace-registry.d.ts +228 -0
  697. package/dist/server/server/workspace-registry.js +468 -0
  698. package/dist/server/server/workspace-script-runtime-store.d.ts +28 -0
  699. package/dist/server/server/workspace-script-runtime-store.js +78 -0
  700. package/dist/server/server/workspace-service-env.d.ts +18 -0
  701. package/dist/server/server/workspace-service-env.js +85 -0
  702. package/dist/server/server/workspace-service-port-allocator.d.ts +11 -0
  703. package/dist/server/server/workspace-service-port-allocator.js +89 -0
  704. package/dist/server/server/workspace-service-port-registry.d.ts +24 -0
  705. package/dist/server/server/workspace-service-port-registry.js +172 -0
  706. package/dist/server/server/workspace-setup-runtime.d.ts +7 -0
  707. package/dist/server/server/workspace-setup-runtime.js +30 -0
  708. package/dist/server/server/workspace-source.d.ts +7 -0
  709. package/dist/server/server/workspace-source.js +15 -0
  710. package/dist/server/server/worktree/commands.d.ts +55 -0
  711. package/dist/server/server/worktree/commands.js +99 -0
  712. package/dist/server/server/worktree-bootstrap.d.ts +86 -0
  713. package/dist/server/server/worktree-bootstrap.js +753 -0
  714. package/dist/server/server/worktree-branch-name-generator.d.ts +35 -0
  715. package/dist/server/server/worktree-branch-name-generator.js +89 -0
  716. package/dist/server/server/worktree-core.d.ts +32 -0
  717. package/dist/server/server/worktree-core.js +114 -0
  718. package/dist/server/server/worktree-errors.d.ts +12 -0
  719. package/dist/server/server/worktree-errors.js +28 -0
  720. package/dist/server/server/worktree-session.d.ts +165 -0
  721. package/dist/server/server/worktree-session.js +594 -0
  722. package/dist/server/services/forge-cli-command.d.ts +128 -0
  723. package/dist/server/services/forge-cli-command.js +212 -0
  724. package/dist/server/services/forge-registry.d.ts +25 -0
  725. package/dist/server/services/forge-registry.js +155 -0
  726. package/dist/server/services/forge-resolver.d.ts +38 -0
  727. package/dist/server/services/forge-resolver.js +191 -0
  728. package/dist/server/services/forge-service.d.ts +430 -0
  729. package/dist/server/services/forge-service.js +50 -0
  730. package/dist/server/services/gitea-facts.d.ts +11 -0
  731. package/dist/server/services/gitea-facts.js +4 -0
  732. package/dist/server/services/gitea-service.d.ts +62 -0
  733. package/dist/server/services/gitea-service.js +1844 -0
  734. package/dist/server/services/github-facts.d.ts +27 -0
  735. package/dist/server/services/github-facts.js +4 -0
  736. package/dist/server/services/github-service.d.ts +76 -0
  737. package/dist/server/services/github-service.js +3297 -0
  738. package/dist/server/services/gitlab-facts.d.ts +26 -0
  739. package/dist/server/services/gitlab-facts.js +4 -0
  740. package/dist/server/services/gitlab-service.d.ts +43 -0
  741. package/dist/server/services/gitlab-service.js +1092 -0
  742. package/dist/server/services/quota-fetcher/manifest.d.ts +5 -0
  743. package/dist/server/services/quota-fetcher/manifest.js +118 -0
  744. package/dist/server/services/quota-fetcher/provider.d.ts +18 -0
  745. package/dist/server/services/quota-fetcher/provider.js +2 -0
  746. package/dist/server/services/quota-fetcher/providers/claude.d.ts +40 -0
  747. package/dist/server/services/quota-fetcher/providers/claude.js +389 -0
  748. package/dist/server/services/quota-fetcher/providers/codex.d.ts +23 -0
  749. package/dist/server/services/quota-fetcher/providers/codex.js +167 -0
  750. package/dist/server/services/quota-fetcher/providers/copilot.d.ts +21 -0
  751. package/dist/server/services/quota-fetcher/providers/copilot.js +77 -0
  752. package/dist/server/services/quota-fetcher/providers/cursor.d.ts +19 -0
  753. package/dist/server/services/quota-fetcher/providers/cursor.js +185 -0
  754. package/dist/server/services/quota-fetcher/providers/grok.d.ts +23 -0
  755. package/dist/server/services/quota-fetcher/providers/grok.js +137 -0
  756. package/dist/server/services/quota-fetcher/providers/kimi.d.ts +23 -0
  757. package/dist/server/services/quota-fetcher/providers/kimi.js +260 -0
  758. package/dist/server/services/quota-fetcher/providers/minimax.d.ts +29 -0
  759. package/dist/server/services/quota-fetcher/providers/minimax.js +227 -0
  760. package/dist/server/services/quota-fetcher/providers/zai.d.ts +17 -0
  761. package/dist/server/services/quota-fetcher/providers/zai.js +58 -0
  762. package/dist/server/services/quota-fetcher/service.d.ts +34 -0
  763. package/dist/server/services/quota-fetcher/service.js +74 -0
  764. package/dist/server/services/quota-fetcher/usage.d.ts +39 -0
  765. package/dist/server/services/quota-fetcher/usage.js +78 -0
  766. package/dist/server/skills/paseo/SKILL.md +129 -0
  767. package/dist/server/skills/paseo-advisor/SKILL.md +63 -0
  768. package/dist/server/skills/paseo-committee/SKILL.md +46 -0
  769. package/dist/server/skills/paseo-handoff/SKILL.md +65 -0
  770. package/dist/server/skills/paseo-help/SKILL.md +92 -0
  771. package/dist/server/skills/paseo-plugin/SKILL.md +639 -0
  772. package/dist/server/terminal/activity/terminal-activity-tracker.d.ts +21 -0
  773. package/dist/server/terminal/activity/terminal-activity-tracker.js +65 -0
  774. package/dist/server/terminal/agent-hooks/agent-hook-installer.d.ts +62 -0
  775. package/dist/server/terminal/agent-hooks/agent-hook-installer.js +117 -0
  776. package/dist/server/terminal/agent-hooks/claude/claude-settings.d.ts +7 -0
  777. package/dist/server/terminal/agent-hooks/claude/claude-settings.js +88 -0
  778. package/dist/server/terminal/agent-hooks/claude/claude.d.ts +4 -0
  779. package/dist/server/terminal/agent-hooks/claude/claude.js +47 -0
  780. package/dist/server/terminal/agent-hooks/codex/codex-settings.d.ts +7 -0
  781. package/dist/server/terminal/agent-hooks/codex/codex-settings.js +99 -0
  782. package/dist/server/terminal/agent-hooks/codex/codex.d.ts +4 -0
  783. package/dist/server/terminal/agent-hooks/codex/codex.js +30 -0
  784. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.d.ts +4 -0
  785. package/dist/server/terminal/agent-hooks/opencode/opencode-plugin.js +81 -0
  786. package/dist/server/terminal/agent-hooks/opencode/opencode.d.ts +3 -0
  787. package/dist/server/terminal/agent-hooks/opencode/opencode.js +23 -0
  788. package/dist/server/terminal/agent-hooks/provider-registry.d.ts +24 -0
  789. package/dist/server/terminal/agent-hooks/provider-registry.js +36 -0
  790. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.d.ts +10 -0
  791. package/dist/server/terminal/agent-hooks/terminal-agent-hook-setting.js +26 -0
  792. package/dist/server/terminal/shell-integration/zsh/.zshenv +17 -0
  793. package/dist/server/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  794. package/dist/server/terminal/terminal-capture.d.ts +12 -0
  795. package/dist/server/terminal/terminal-capture.js +43 -0
  796. package/dist/server/terminal/terminal-manager-factory.d.ts +6 -0
  797. package/dist/server/terminal/terminal-manager-factory.js +5 -0
  798. package/dist/server/terminal/terminal-manager.d.ts +80 -0
  799. package/dist/server/terminal/terminal-manager.js +321 -0
  800. package/dist/server/terminal/terminal-output-coalescer.d.ts +34 -0
  801. package/dist/server/terminal/terminal-output-coalescer.js +73 -0
  802. package/dist/server/terminal/terminal-restore.d.ts +18 -0
  803. package/dist/server/terminal/terminal-restore.js +52 -0
  804. package/dist/server/terminal/terminal-session-controller.d.ts +90 -0
  805. package/dist/server/terminal/terminal-session-controller.js +849 -0
  806. package/dist/server/terminal/terminal-size-ownership.d.ts +9 -0
  807. package/dist/server/terminal/terminal-size-ownership.js +23 -0
  808. package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
  809. package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
  810. package/dist/server/terminal/terminal-worker-process.js +308 -0
  811. package/dist/server/terminal/terminal-worker-protocol.d.ts +121 -0
  812. package/dist/server/terminal/terminal-worker-protocol.js +2 -0
  813. package/dist/server/terminal/terminal.d.ts +151 -0
  814. package/dist/server/terminal/terminal.js +1234 -0
  815. package/dist/server/terminal/worker-terminal-manager.d.ts +20 -0
  816. package/dist/server/terminal/worker-terminal-manager.js +688 -0
  817. package/dist/server/utils/build-metadata-prompt.d.ts +19 -0
  818. package/dist/server/utils/build-metadata-prompt.js +29 -0
  819. package/dist/server/utils/checkout-git.d.ts +317 -0
  820. package/dist/server/utils/checkout-git.js +2886 -0
  821. package/dist/server/utils/directory-suggestions.d.ts +29 -0
  822. package/dist/server/utils/directory-suggestions.js +596 -0
  823. package/dist/server/utils/git-command-runtime-metrics.d.ts +67 -0
  824. package/dist/server/utils/git-command-runtime-metrics.js +126 -0
  825. package/dist/server/utils/git-command-trace.d.ts +29 -0
  826. package/dist/server/utils/git-command-trace.js +74 -0
  827. package/dist/server/utils/git-process-scheduler.d.ts +34 -0
  828. package/dist/server/utils/git-process-scheduler.js +112 -0
  829. package/dist/server/utils/git-rev-parse-path.d.ts +3 -0
  830. package/dist/server/utils/git-rev-parse-path.js +21 -0
  831. package/dist/server/utils/paseo-config-file.d.ts +30 -0
  832. package/dist/server/utils/paseo-config-file.js +90 -0
  833. package/dist/server/utils/path.d.ts +27 -0
  834. package/dist/server/utils/path.js +156 -0
  835. package/dist/server/utils/project-custom-icon.d.ts +40 -0
  836. package/dist/server/utils/project-custom-icon.js +144 -0
  837. package/dist/server/utils/project-icon.d.ts +54 -0
  838. package/dist/server/utils/project-icon.js +445 -0
  839. package/dist/server/utils/promise-timeout.d.ts +9 -0
  840. package/dist/server/utils/promise-timeout.js +25 -0
  841. package/dist/server/utils/run-git-command.d.ts +59 -0
  842. package/dist/server/utils/run-git-command.js +393 -0
  843. package/dist/server/utils/spawn.d.ts +26 -0
  844. package/dist/server/utils/spawn.js +60 -0
  845. package/dist/server/utils/ssh-hostname.d.ts +8 -0
  846. package/dist/server/utils/ssh-hostname.js +60 -0
  847. package/dist/server/utils/string-command-shell.d.ts +13 -0
  848. package/dist/server/utils/string-command-shell.js +37 -0
  849. package/dist/server/utils/tree-kill.d.ts +19 -0
  850. package/dist/server/utils/tree-kill.js +77 -0
  851. package/dist/server/utils/windows-command.d.ts +15 -0
  852. package/dist/server/utils/windows-command.js +41 -0
  853. package/dist/server/utils/worktree-metadata.d.ts +77 -0
  854. package/dist/server/utils/worktree-metadata.js +280 -0
  855. package/dist/server/utils/worktree.d.ts +232 -0
  856. package/dist/server/utils/worktree.js +1193 -0
  857. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css +1 -0
  858. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.br +0 -0
  859. package/dist/server/web-ui/_expo/static/css/xterm-3bb1704bf6cb0876640973dc0244b4cb.css.gz +0 -0
  860. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js +1 -0
  861. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js.br +0 -0
  862. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-29f33408b1a3c5b435c5202d62a36719.js.gz +0 -0
  863. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js +1 -0
  864. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js.br +0 -0
  865. package/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-41547ee520dfff946caa727824742a5c.js.gz +0 -0
  866. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js +16819 -0
  867. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js.br +0 -0
  868. package/dist/server/web-ui/_expo/static/js/web/index-03b99be4265ac4a2bc5a6d602fd59cc4.js.gz +0 -0
  869. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js +1 -0
  870. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js.br +0 -0
  871. package/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-5444610146b0794f1e7d9edad4522d41.js.gz +0 -0
  872. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js +3 -0
  873. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js.br +0 -0
  874. package/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-88b083190031a44788be59103814f511.js.gz +0 -0
  875. package/dist/server/web-ui/apple-touch-icon.png +0 -0
  876. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon-mask.0a328cd9c1afd0afe8e3b1ec5165b1b4.png +0 -0
  877. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/back-icon.35ba0eaec5a4f5ed12ca16fabeae451d.png +0 -0
  878. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55.png +0 -0
  879. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@2x.png +0 -0
  880. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@3x.png +0 -0
  881. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/clear-icon.c94f6478e7ae0cdd9f15de1fcb9e5e55@4x.png +0 -0
  882. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7.png +0 -0
  883. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@2x.png +0 -0
  884. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@3x.png +0 -0
  885. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/close-icon.808e1b1b9b53114ec2838071a7e6daa7@4x.png +0 -0
  886. package/dist/server/web-ui/assets/__node_modules/@react-navigation/elements/lib/module/assets/search-icon.286d67d3f74808a60a78d3ebf1a5fb57.png +0 -0
  887. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/arrow_down.017bc6ba3fc25503e5eb5e53826d48a8.png +0 -0
  888. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/error.d1ea1496f9057eb392d5bbf3732a61b7.png +0 -0
  889. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/file.19eeb73b9593a38f8e9f418337fc7d10.png +0 -0
  890. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/forward.d8b800c443b8972542883e0b9de2bdc6.png +0 -0
  891. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/pkg.ab19f4cbc543357183a20571f68380a3.png +0 -0
  892. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/sitemap.412dd9275b6b48ad28f5e3d81bb1f626.png +0 -0
  893. package/dist/server/web-ui/assets/__node_modules/expo-router/assets/unmatched.20e71bdf79e3a97bf55fd9e164041578.png +0 -0
  894. package/dist/server/web-ui/assets/assets/images/favicon-dark-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  895. package/dist/server/web-ui/assets/assets/images/favicon-dark-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  896. package/dist/server/web-ui/assets/assets/images/favicon-dark.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  897. package/dist/server/web-ui/assets/assets/images/favicon-light-attention.882b3a27dcb2073e9e31b334f9ed9728.png +0 -0
  898. package/dist/server/web-ui/assets/assets/images/favicon-light-running.8112342ff0d39e047a7f8d4fad9402f3.png +0 -0
  899. package/dist/server/web-ui/assets/assets/images/favicon-light.8005ed36ac07a5a7c60de25780897bd4.png +0 -0
  900. package/dist/server/web-ui/assets/assets/images/notification-icon.3bf81d33ddbf380606bdd248ba83e158.png +0 -0
  901. package/dist/server/web-ui/favicon.ico +0 -0
  902. package/dist/server/web-ui/index.html +90 -0
  903. package/dist/server/web-ui/index.html.br +0 -0
  904. package/dist/server/web-ui/index.html.gz +0 -0
  905. package/dist/server/web-ui/manifest.json +27 -0
  906. package/dist/server/web-ui/manifest.json.br +0 -0
  907. package/dist/server/web-ui/manifest.json.gz +0 -0
  908. package/dist/server/web-ui/metadata.json +1 -0
  909. package/dist/server/web-ui/metadata.json.br +1 -0
  910. package/dist/server/web-ui/metadata.json.gz +0 -0
  911. package/dist/server/web-ui/pwa-icon-192.png +0 -0
  912. package/dist/server/web-ui/pwa-icon-512.png +0 -0
  913. package/dist/server/web-ui/robots.txt +2 -0
  914. package/dist/src/executable-resolution/executable-resolution.js +121 -0
  915. package/dist/src/executable-resolution/windows.js +65 -0
  916. package/dist/src/server/agent/provider-launch-config.js +167 -0
  917. package/dist/src/server/paseo-env.js +54 -0
  918. package/dist/src/server/paseo-home.js +19 -0
  919. package/dist/src/server/persisted-config.js +411 -0
  920. package/dist/src/server/pid-lock.js +285 -0
  921. package/dist/src/server/private-files.js +37 -0
  922. package/dist/src/server/speech/providers/local/sherpa/sherpa-runtime-env.js +84 -0
  923. package/dist/src/terminal/shell-integration/zsh/.zshenv +17 -0
  924. package/dist/src/terminal/shell-integration/zsh/paseo-integration.zsh +32 -0
  925. package/dist/src/utils/spawn.js +60 -0
  926. package/dist/src/utils/tree-kill.js +77 -0
  927. package/dist/src/utils/windows-command.js +41 -0
  928. package/package.json +125 -0
@@ -0,0 +1,2886 @@
1
+ import { resolve, dirname, basename } from "path";
2
+ import { existsSync, realpathSync } from "fs";
3
+ import { open as openFile, readFile, stat as statFile } from "fs/promises";
4
+ import { TTLCache } from "@isaacs/ttlcache";
5
+ import { parseGitHubRemoteIdentity, parseGitRemoteLocation } from "@camerontaylor/paseo-protocol/git-remote";
6
+ import { maxBase64EncryptedPlaintextByteLength } from "@camerontaylor/paseo-relay";
7
+ import { highlightDiffWithFileContent, parseAndHighlightDiff, parseDiff, } from "../server/utils/diff-highlighter.js";
8
+ import { parseGitHubRepoFromRemote } from "../server/workspace-git-metadata.js";
9
+ import { createGitHubService } from "../services/github-service.js";
10
+ import { ForgeAuthenticationError, ForgeCliMissingError, ForgeCommandError, } from "../services/forge-cli-command.js";
11
+ import { parseGitRevParsePath, resolveGitRevParsePath } from "./git-rev-parse-path.js";
12
+ import { runGitCommand } from "./run-git-command.js";
13
+ import { isPaseoOwnedWorktreeCwd, resolvePaseoWorktreesBaseRoot } from "./worktree.js";
14
+ import { branchNameFromRef, getPaseoWorktreeChangeRequestHintForBranch, readPaseoWorktreeMetadata, rebindPaseoWorktreeChangeRequestHint, } from "./worktree-metadata.js";
15
+ const READ_ONLY_GIT_ENV = {
16
+ GIT_OPTIONAL_LOCKS: "0",
17
+ LC_ALL: "C",
18
+ };
19
+ const DISCARD_CHANGES_TIMEOUT_MS = 120000;
20
+ const DEFAULT_PULL_REQUEST_STATUS_CACHE_TTL_MS = 30000;
21
+ const PULL_REQUEST_STATUS_CACHE_MAX = 1000;
22
+ const DEFAULT_SHORTSTAT_CACHE_TTL_MS = 15000;
23
+ const SHORTSTAT_CACHE_MAX = 1000;
24
+ let pullRequestStatusCacheTtlMs = DEFAULT_PULL_REQUEST_STATUS_CACHE_TTL_MS;
25
+ let pullRequestStatusCache = createPullRequestStatusCache(pullRequestStatusCacheTtlMs);
26
+ const pullRequestStatusInFlight = new Map();
27
+ const lastSuccessfulPullRequestStatus = new Map();
28
+ let shortstatCacheTtlMs = DEFAULT_SHORTSTAT_CACHE_TTL_MS;
29
+ let shortstatCache = createShortstatCache(shortstatCacheTtlMs);
30
+ const shortstatInFlight = new Map();
31
+ function getErrorStderr(error) {
32
+ return "stderr" in error && typeof error.stderr === "string" ? error.stderr : "";
33
+ }
34
+ function getErrorStdout(error) {
35
+ return "stdout" in error && typeof error.stdout === "string" ? error.stdout : "";
36
+ }
37
+ function throwBranchNotFound(branch) {
38
+ throw new Error(`Branch not found: ${branch ?? "unknown"}`);
39
+ }
40
+ function createPullRequestStatusCache(ttlMs) {
41
+ return new TTLCache({
42
+ ttl: ttlMs,
43
+ max: PULL_REQUEST_STATUS_CACHE_MAX,
44
+ checkAgeOnGet: true,
45
+ });
46
+ }
47
+ function createShortstatCache(ttlMs) {
48
+ return new TTLCache({
49
+ ttl: ttlMs,
50
+ max: SHORTSTAT_CACHE_MAX,
51
+ checkAgeOnGet: true,
52
+ });
53
+ }
54
+ function getPullRequestStatusCacheKey(cwd, headSha) {
55
+ return `${resolve(cwd)}\u0000${headSha ?? ""}`;
56
+ }
57
+ function rememberPullRequestStatus(cacheKey, status) {
58
+ lastSuccessfulPullRequestStatus.set(cacheKey, status);
59
+ if (lastSuccessfulPullRequestStatus.size <= PULL_REQUEST_STATUS_CACHE_MAX) {
60
+ return;
61
+ }
62
+ const oldest = lastSuccessfulPullRequestStatus.keys().next();
63
+ if (!oldest.done) {
64
+ lastSuccessfulPullRequestStatus.delete(oldest.value);
65
+ }
66
+ }
67
+ function getShortstatCacheKey(cwd) {
68
+ return resolve(cwd);
69
+ }
70
+ export function __resetPullRequestStatusCacheForTests() {
71
+ pullRequestStatusCache.clear();
72
+ pullRequestStatusCache.cancelTimer();
73
+ pullRequestStatusCacheTtlMs = DEFAULT_PULL_REQUEST_STATUS_CACHE_TTL_MS;
74
+ pullRequestStatusCache = createPullRequestStatusCache(pullRequestStatusCacheTtlMs);
75
+ pullRequestStatusInFlight.clear();
76
+ lastSuccessfulPullRequestStatus.clear();
77
+ }
78
+ export function __setPullRequestStatusCacheTtlForTests(ttlMs) {
79
+ pullRequestStatusCache.clear();
80
+ pullRequestStatusCache.cancelTimer();
81
+ pullRequestStatusCacheTtlMs = ttlMs;
82
+ pullRequestStatusCache = createPullRequestStatusCache(ttlMs);
83
+ pullRequestStatusInFlight.clear();
84
+ lastSuccessfulPullRequestStatus.clear();
85
+ }
86
+ export function __resetCheckoutShortstatCacheForTests() {
87
+ shortstatCache.clear();
88
+ shortstatCache.cancelTimer();
89
+ shortstatCacheTtlMs = DEFAULT_SHORTSTAT_CACHE_TTL_MS;
90
+ shortstatCache = createShortstatCache(shortstatCacheTtlMs);
91
+ shortstatInFlight.clear();
92
+ }
93
+ export function __setCheckoutShortstatCacheTtlForTests(ttlMs) {
94
+ shortstatCache.clear();
95
+ shortstatCache.cancelTimer();
96
+ shortstatCacheTtlMs = ttlMs;
97
+ shortstatCache = createShortstatCache(ttlMs);
98
+ shortstatInFlight.clear();
99
+ }
100
+ function getCheckoutDiffRefArgs(refs) {
101
+ return [refs.baseRef, ...(refs.targetRef ? [refs.targetRef] : [])];
102
+ }
103
+ function normalizeBranchSuggestionName(raw) {
104
+ const trimmed = raw.trim();
105
+ if (!trimmed) {
106
+ return null;
107
+ }
108
+ let normalized = trimmed;
109
+ if (normalized.startsWith("refs/heads/")) {
110
+ normalized = normalized.slice("refs/heads/".length);
111
+ }
112
+ else if (normalized.startsWith("refs/remotes/")) {
113
+ normalized = normalized.slice("refs/remotes/".length);
114
+ }
115
+ if (normalized.startsWith("origin/")) {
116
+ normalized = normalized.slice("origin/".length);
117
+ }
118
+ if (!normalized || normalized === "HEAD" || normalized === "origin") {
119
+ return null;
120
+ }
121
+ return normalized;
122
+ }
123
+ async function listGitRefs(cwd, refPrefix) {
124
+ const { stdout } = await runGitCommand([
125
+ "for-each-ref",
126
+ "--sort=-committerdate",
127
+ "--format=%(refname)%09%(committerdate:unix)%09%(objectname)",
128
+ refPrefix,
129
+ ], { cwd, envOverlay: READ_ONLY_GIT_ENV });
130
+ return stdout
131
+ .split("\n")
132
+ .map((line) => {
133
+ const trimmed = line.trim();
134
+ if (!trimmed)
135
+ return null;
136
+ const [name, dateStr, oid] = trimmed.split("\t");
137
+ if (!name || !oid)
138
+ return null;
139
+ return { name, committerDate: Number(dateStr) || 0, oid };
140
+ })
141
+ .filter((ref) => ref !== null);
142
+ }
143
+ function sortBranchSuggestions(branchNames, branchMeta, query) {
144
+ const normalizedQuery = query.trim().toLowerCase();
145
+ const hasQuery = normalizedQuery.length > 0;
146
+ return branchNames.sort((a, b) => {
147
+ if (hasQuery) {
148
+ const aPrefix = a.toLowerCase().startsWith(normalizedQuery);
149
+ const bPrefix = b.toLowerCase().startsWith(normalizedQuery);
150
+ if (aPrefix !== bPrefix) {
151
+ return aPrefix ? -1 : 1;
152
+ }
153
+ }
154
+ const aMeta = branchMeta.get(a);
155
+ const bMeta = branchMeta.get(b);
156
+ const aDate = aMeta?.committerDate ?? 0;
157
+ const bDate = bMeta?.committerDate ?? 0;
158
+ if (aDate !== bDate) {
159
+ return bDate - aDate;
160
+ }
161
+ return a.localeCompare(b);
162
+ });
163
+ }
164
+ export async function listBranchSuggestions(cwd, options) {
165
+ await requireGitRepo(cwd);
166
+ const requestedLimit = options?.limit ?? 50;
167
+ const limit = Math.max(1, Math.min(200, requestedLimit));
168
+ const rawQuery = options?.query?.trim().toLowerCase() ?? "";
169
+ const query = normalizeBranchSuggestionName(rawQuery) ?? rawQuery;
170
+ const [localRefs, remoteRefs] = await Promise.all([
171
+ listGitRefs(cwd, "refs/heads"),
172
+ listGitRefs(cwd, "refs/remotes/origin"),
173
+ ]);
174
+ const branchMeta = new Map();
175
+ for (const ref of localRefs) {
176
+ const normalized = normalizeBranchSuggestionName(ref.name);
177
+ if (!normalized)
178
+ continue;
179
+ const existing = branchMeta.get(normalized);
180
+ branchMeta.set(normalized, {
181
+ hasLocal: true,
182
+ hasRemote: existing?.hasRemote ?? false,
183
+ localOid: ref.oid,
184
+ ...(existing?.remoteOid ? { remoteOid: existing.remoteOid } : {}),
185
+ committerDate: Math.max(ref.committerDate, existing?.committerDate ?? 0),
186
+ });
187
+ }
188
+ for (const ref of remoteRefs) {
189
+ const normalized = normalizeBranchSuggestionName(ref.name);
190
+ if (!normalized)
191
+ continue;
192
+ const existing = branchMeta.get(normalized);
193
+ if (!existing) {
194
+ branchMeta.set(normalized, {
195
+ hasLocal: false,
196
+ hasRemote: true,
197
+ remoteOid: ref.oid,
198
+ committerDate: ref.committerDate,
199
+ });
200
+ }
201
+ else {
202
+ branchMeta.set(normalized, {
203
+ ...existing,
204
+ hasRemote: true,
205
+ remoteOid: ref.oid,
206
+ committerDate: Math.max(ref.committerDate, existing.committerDate),
207
+ });
208
+ }
209
+ }
210
+ const filteredNames = Array.from(branchMeta.keys()).filter((name) => query ? name.toLowerCase().includes(query) : true);
211
+ if (filteredNames.length === 0) {
212
+ return [];
213
+ }
214
+ const ordered = sortBranchSuggestions(filteredNames, branchMeta, query);
215
+ return Promise.all(ordered.slice(0, limit).map(async (name) => {
216
+ const meta = branchMeta.get(name);
217
+ const suggestion = {
218
+ name,
219
+ committerDate: meta?.committerDate ?? 0,
220
+ hasLocal: meta?.hasLocal ?? false,
221
+ hasRemote: meta?.hasRemote ?? false,
222
+ };
223
+ if (!suggestion.hasLocal || !suggestion.hasRemote) {
224
+ return suggestion;
225
+ }
226
+ if (meta?.localOid && meta.localOid === meta.remoteOid) {
227
+ suggestion.localAhead = 0;
228
+ suggestion.localBehind = 0;
229
+ return suggestion;
230
+ }
231
+ try {
232
+ const { stdout } = await runGitCommand([
233
+ "rev-list",
234
+ "--left-right",
235
+ "--count",
236
+ `refs/heads/${name}...refs/remotes/origin/${name}`,
237
+ ], { cwd, envOverlay: READ_ONLY_GIT_ENV });
238
+ const [localAhead, localBehind] = stdout.trim().split(/\s+/).map(Number);
239
+ if (Number.isFinite(localAhead) && Number.isFinite(localBehind)) {
240
+ suggestion.localAhead = localAhead;
241
+ suggestion.localBehind = localBehind;
242
+ }
243
+ }
244
+ catch {
245
+ // A ref may disappear between listing and comparison. Keep the branch
246
+ // available without divergence metadata and let creation re-resolve it.
247
+ }
248
+ return suggestion;
249
+ }));
250
+ }
251
+ export async function resolveBranchCheckout(cwd, name) {
252
+ await requireGitRepo(cwd);
253
+ const normalized = normalizeBranchSuggestionName(name);
254
+ if (!normalized) {
255
+ return { kind: "not-found" };
256
+ }
257
+ const localRef = `refs/heads/${normalized}`;
258
+ const localResult = await runGitCommand(["rev-parse", "--verify", "--quiet", localRef], {
259
+ cwd,
260
+ envOverlay: READ_ONLY_GIT_ENV,
261
+ acceptExitCodes: [0, 1],
262
+ });
263
+ const hasLocal = localResult.exitCode === 0;
264
+ if (hasLocal) {
265
+ return { kind: "local", name: normalized };
266
+ }
267
+ const remoteRef = `origin/${normalized}`;
268
+ const remoteRefPath = `refs/remotes/${remoteRef}`;
269
+ const remoteResult = await runGitCommand(["rev-parse", "--verify", "--quiet", remoteRefPath], {
270
+ cwd,
271
+ envOverlay: READ_ONLY_GIT_ENV,
272
+ acceptExitCodes: [0, 1],
273
+ });
274
+ const hasRemote = remoteResult.exitCode === 0;
275
+ if (hasRemote) {
276
+ return { kind: "remote-only", name: normalized, remoteRef };
277
+ }
278
+ return { kind: "not-found" };
279
+ }
280
+ export async function checkoutResolvedBranch(input) {
281
+ const { cwd, resolution } = input;
282
+ switch (resolution.kind) {
283
+ case "local": {
284
+ const { stdout } = await runGitCommand(["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
285
+ const current = stdout.trim();
286
+ if (current === resolution.name) {
287
+ return { source: "local" };
288
+ }
289
+ await runGitCommand(["checkout", resolution.name], { cwd });
290
+ return { source: "local" };
291
+ }
292
+ case "remote-only":
293
+ await runGitCommand(["checkout", "-b", resolution.name, "--track", resolution.remoteRef], {
294
+ cwd,
295
+ });
296
+ return { source: "remote" };
297
+ default:
298
+ return throwBranchNotFound(input.requestedBranch);
299
+ }
300
+ }
301
+ async function listCheckoutFileChanges(cwd, refs, ignoreWhitespace = false) {
302
+ const changes = [];
303
+ const { stdout: nameStatusOut } = await runGitCommand(buildGitDiffArgs({
304
+ ignoreWhitespace,
305
+ extra: ["--name-status", ...getCheckoutDiffRefArgs(refs)],
306
+ }), { cwd, envOverlay: READ_ONLY_GIT_ENV });
307
+ for (const line of nameStatusOut
308
+ .split("\n")
309
+ .map((l) => l.trim())
310
+ .filter(Boolean)) {
311
+ // `--name-status` uses TAB separators, which preserves filenames with spaces.
312
+ const tabParts = line.split("\t");
313
+ const rawStatus = (tabParts[0] ?? "").trim();
314
+ if (!rawStatus)
315
+ continue;
316
+ if (rawStatus.startsWith("R") || rawStatus.startsWith("C")) {
317
+ const oldPath = tabParts[1];
318
+ const newPath = tabParts[2];
319
+ if (newPath) {
320
+ changes.push({
321
+ path: newPath,
322
+ ...(oldPath ? { oldPath } : {}),
323
+ status: rawStatus,
324
+ isNew: false,
325
+ isDeleted: false,
326
+ });
327
+ }
328
+ continue;
329
+ }
330
+ const path = tabParts[1];
331
+ if (!path)
332
+ continue;
333
+ const code = rawStatus[0];
334
+ changes.push({
335
+ path,
336
+ status: rawStatus,
337
+ isNew: code === "A",
338
+ isDeleted: code === "D",
339
+ });
340
+ }
341
+ if (refs.includeUntracked) {
342
+ const { stdout: untrackedOut } = await runGitCommand(["ls-files", "--others", "--exclude-standard"], {
343
+ cwd,
344
+ envOverlay: READ_ONLY_GIT_ENV,
345
+ });
346
+ for (const file of untrackedOut
347
+ .split("\n")
348
+ .map((l) => l.trim())
349
+ .filter(Boolean)) {
350
+ changes.push({
351
+ path: file,
352
+ status: "U",
353
+ isNew: true,
354
+ isDeleted: false,
355
+ isUntracked: true,
356
+ });
357
+ }
358
+ }
359
+ // Deduplicate by path (prefer tracked status over untracked marker if both appear).
360
+ const byPath = new Map();
361
+ for (const change of changes) {
362
+ const existing = byPath.get(change.path);
363
+ if (!existing) {
364
+ byPath.set(change.path, change);
365
+ continue;
366
+ }
367
+ if (existing.isUntracked && !change.isUntracked) {
368
+ byPath.set(change.path, change);
369
+ }
370
+ }
371
+ return Array.from(byPath.values());
372
+ }
373
+ async function readGitFileContentAtRef(cwd, ref, path) {
374
+ try {
375
+ const { stdout } = await runGitCommand(["show", `${ref}:${path}`], {
376
+ cwd,
377
+ envOverlay: READ_ONLY_GIT_ENV,
378
+ });
379
+ return stdout;
380
+ }
381
+ catch {
382
+ return null;
383
+ }
384
+ }
385
+ async function tryResolveMergeBase(cwd, baseRef) {
386
+ try {
387
+ const { stdout } = await runGitCommand(["merge-base", baseRef, "HEAD"], {
388
+ cwd,
389
+ envOverlay: READ_ONLY_GIT_ENV,
390
+ });
391
+ const sha = stdout.trim();
392
+ return sha.length > 0 ? sha : null;
393
+ }
394
+ catch {
395
+ return null;
396
+ }
397
+ }
398
+ function normalizeNumstatPath(pathField) {
399
+ const braceRenameMatch = pathField.match(/^(.*)\{(.*) => (.*)\}(.*)$/);
400
+ if (braceRenameMatch) {
401
+ const [, prefix, , renamed, suffix] = braceRenameMatch;
402
+ return `${prefix}${renamed}${suffix}`;
403
+ }
404
+ const inlineRenameMatch = pathField.match(/^(.*) => (.*)$/);
405
+ if (inlineRenameMatch) {
406
+ return inlineRenameMatch[2] ?? pathField;
407
+ }
408
+ return pathField;
409
+ }
410
+ function buildGitDiffArgs(args) {
411
+ return ["diff", ...(args.ignoreWhitespace ? ["-w"] : []), ...args.extra];
412
+ }
413
+ const TRACKED_DIFF_NUMSTAT_MAX_BYTES = 2 * 1024 * 1024; // 2MB
414
+ const TRACKED_DIFF_BATCH_SIZE = 8;
415
+ const EMPTY_TREE_OBJECT_ID = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
416
+ function isUnbornHeadDiffError(error) {
417
+ return (error instanceof Error &&
418
+ error.message.includes("--name-status HEAD") &&
419
+ error.message.includes("ambiguous argument 'HEAD'"));
420
+ }
421
+ async function getTrackedNumstatByPath(cwd, refs, ignoreWhitespace = false) {
422
+ const result = await runGitCommand(buildGitDiffArgs({
423
+ ignoreWhitespace,
424
+ extra: ["--numstat", ...getCheckoutDiffRefArgs(refs)],
425
+ }), {
426
+ cwd,
427
+ envOverlay: READ_ONLY_GIT_ENV,
428
+ maxOutputBytes: TRACKED_DIFF_NUMSTAT_MAX_BYTES,
429
+ acceptExitCodes: [0],
430
+ });
431
+ const stats = new Map();
432
+ const lines = result.stdout
433
+ .split("\n")
434
+ .map((line) => line.trim())
435
+ .filter(Boolean);
436
+ for (const line of lines) {
437
+ const parts = line.split("\t");
438
+ if (parts.length < 3) {
439
+ continue;
440
+ }
441
+ const additionsField = parts[0] ?? "";
442
+ const deletionsField = parts[1] ?? "";
443
+ const rawPath = parts.slice(2).join("\t");
444
+ const path = normalizeNumstatPath(rawPath);
445
+ if (!path) {
446
+ continue;
447
+ }
448
+ if (additionsField === "-" || deletionsField === "-") {
449
+ stats.set(path, { additions: 0, deletions: 0, isBinary: true });
450
+ continue;
451
+ }
452
+ const additions = Number.parseInt(additionsField, 10);
453
+ const deletions = Number.parseInt(deletionsField, 10);
454
+ if (Number.isNaN(additions) || Number.isNaN(deletions)) {
455
+ stats.set(path, null);
456
+ continue;
457
+ }
458
+ stats.set(path, { additions, deletions, isBinary: false });
459
+ }
460
+ return stats;
461
+ }
462
+ async function getTrackedDiffTextForPath(input) {
463
+ const result = await runGitCommand(buildGitDiffArgs({
464
+ ignoreWhitespace: input.ignoreWhitespace,
465
+ extra: [...getCheckoutDiffRefArgs(input.refsForDiff), "--", input.path],
466
+ }), {
467
+ cwd: input.cwd,
468
+ envOverlay: READ_ONLY_GIT_ENV,
469
+ maxOutputBytes: PER_FILE_DIFF_MAX_BYTES,
470
+ });
471
+ return {
472
+ path: input.path,
473
+ text: result.stdout,
474
+ truncated: result.truncated,
475
+ };
476
+ }
477
+ export class NotGitRepoError extends Error {
478
+ constructor(cwd) {
479
+ super(`Not a git repository: ${cwd}`);
480
+ this.code = "NOT_GIT_REPO";
481
+ this.name = "NotGitRepoError";
482
+ this.cwd = cwd;
483
+ }
484
+ }
485
+ export class MergeConflictError extends Error {
486
+ constructor(options) {
487
+ super(`Merge conflict while merging ${options.currentBranch} into ${options.baseRef}`);
488
+ this.name = "MergeConflictError";
489
+ this.baseRef = options.baseRef;
490
+ this.currentBranch = options.currentBranch;
491
+ this.conflictFiles = options.conflictFiles;
492
+ }
493
+ }
494
+ export class MergeFromBaseConflictError extends Error {
495
+ constructor(options) {
496
+ super(`Merge conflict while merging ${options.baseRef} into ${options.currentBranch}. Please merge manually.`);
497
+ this.name = "MergeFromBaseConflictError";
498
+ this.baseRef = options.baseRef;
499
+ this.currentBranch = options.currentBranch;
500
+ this.conflictFiles = options.conflictFiles;
501
+ }
502
+ }
503
+ function isNotGitRepositoryError(error) {
504
+ return error instanceof Error && /not a git repository/i.test(error.message);
505
+ }
506
+ function getRunGitCommand(context) {
507
+ return context?.runGitCommand ?? runGitCommand;
508
+ }
509
+ async function requireGitRepo(cwd, context) {
510
+ try {
511
+ await getRunGitCommand(context)(["rev-parse", "--git-dir"], {
512
+ cwd,
513
+ envOverlay: READ_ONLY_GIT_ENV,
514
+ });
515
+ }
516
+ catch {
517
+ throw new NotGitRepoError(cwd);
518
+ }
519
+ }
520
+ async function requireGitWorktreeRoot(cwd) {
521
+ try {
522
+ const { stdout } = await runGitCommand(["rev-parse", "--show-toplevel"], {
523
+ cwd,
524
+ envOverlay: READ_ONLY_GIT_ENV,
525
+ });
526
+ const worktreeRoot = parseGitRevParsePath(stdout);
527
+ if (!worktreeRoot) {
528
+ throw new Error("Git returned no worktree root");
529
+ }
530
+ return worktreeRoot;
531
+ }
532
+ catch {
533
+ throw new NotGitRepoError(cwd);
534
+ }
535
+ }
536
+ export async function getCurrentBranch(cwd, context) {
537
+ try {
538
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "--abbrev-ref", "HEAD"], {
539
+ cwd,
540
+ envOverlay: READ_ONLY_GIT_ENV,
541
+ });
542
+ const branch = stdout.trim();
543
+ if (branch === "HEAD") {
544
+ return await getRebaseHeadBranch(cwd, context);
545
+ }
546
+ return branch.length > 0 ? branch : null;
547
+ }
548
+ catch {
549
+ return null;
550
+ }
551
+ }
552
+ async function getCurrentHeadSha(cwd, context) {
553
+ const knownSha = context?.facts?.isGit
554
+ ? context.facts.pullRequestLookupTarget?.headSha
555
+ : undefined;
556
+ if (knownSha) {
557
+ return knownSha;
558
+ }
559
+ try {
560
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "HEAD"], {
561
+ cwd,
562
+ envOverlay: READ_ONLY_GIT_ENV,
563
+ logger: context?.logger,
564
+ });
565
+ const sha = stdout.trim();
566
+ return sha.length > 0 ? sha : null;
567
+ }
568
+ catch {
569
+ return null;
570
+ }
571
+ }
572
+ async function addHeadShaToPullRequestLookupTarget(cwd, target, context) {
573
+ if (!target) {
574
+ return null;
575
+ }
576
+ const headSha = await getCurrentHeadSha(cwd, context);
577
+ return headSha ? { ...target, headSha } : target;
578
+ }
579
+ async function getRebaseHeadBranch(cwd, context) {
580
+ const paths = ["rebase-merge/head-name", "rebase-apply/head-name"];
581
+ const results = await Promise.all(paths.map(async (path) => {
582
+ try {
583
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "--git-path", path], {
584
+ cwd,
585
+ envOverlay: READ_ONLY_GIT_ENV,
586
+ });
587
+ const headName = (await readFile(resolve(cwd, stdout.trim()), "utf8")).trim();
588
+ if (headName.startsWith("refs/heads/")) {
589
+ return headName.slice("refs/heads/".length) || null;
590
+ }
591
+ return headName || null;
592
+ }
593
+ catch {
594
+ return null;
595
+ }
596
+ }));
597
+ return results.find((result) => result !== null) ?? null;
598
+ }
599
+ async function getWorktreeRoot(cwd, context) {
600
+ try {
601
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "--show-toplevel"], {
602
+ cwd,
603
+ envOverlay: READ_ONLY_GIT_ENV,
604
+ logger: context?.logger,
605
+ });
606
+ return parseGitRevParsePath(stdout);
607
+ }
608
+ catch (error) {
609
+ if (!isNotGitRepositoryError(error)) {
610
+ context?.logger?.warn({ err: error, cwd }, "Git worktree discovery failed; treating directory as non-Git");
611
+ }
612
+ return null;
613
+ }
614
+ }
615
+ export async function getMainRepoRoot(cwd, context) {
616
+ const { stdout: commonDirOut } = await getRunGitCommand(context)(["rev-parse", "--git-common-dir"], {
617
+ cwd,
618
+ envOverlay: READ_ONLY_GIT_ENV,
619
+ });
620
+ return getMainRepoRootFromCommonDir(cwd, resolveGitRevParsePath(cwd, commonDirOut), context);
621
+ }
622
+ async function getMainRepoRootFromCommonDir(cwd, commonDir, context) {
623
+ if (!commonDir) {
624
+ throw new Error("Not in a git repository");
625
+ }
626
+ const normalized = realpathSync(commonDir);
627
+ if (basename(normalized) === ".git") {
628
+ return dirname(normalized);
629
+ }
630
+ const { stdout: worktreeOut } = await getRunGitCommand(context)(["worktree", "list", "--porcelain"], {
631
+ cwd,
632
+ envOverlay: READ_ONLY_GIT_ENV,
633
+ });
634
+ const worktrees = parseWorktreeList(worktreeOut);
635
+ const nonBareNonPaseo = worktrees.filter((wt) => !wt.isBare &&
636
+ !isPaseoWorktreePath(wt.path, {
637
+ paseoHome: context?.paseoHome,
638
+ worktreesRoot: context?.worktreesRoot,
639
+ }));
640
+ const childrenOfBareRepo = nonBareNonPaseo.filter((wt) => isDescendantPath(wt.path, normalized));
641
+ const mainChild = childrenOfBareRepo.find((wt) => basename(wt.path) === "main");
642
+ return mainChild?.path ?? childrenOfBareRepo[0]?.path ?? nonBareNonPaseo[0]?.path ?? normalized;
643
+ }
644
+ /** Check whether a path is under Paseo's worktree root. */
645
+ export function isPaseoWorktreePath(p, options) {
646
+ if (options?.worktreesRoot || options?.paseoHome) {
647
+ return isDescendantPath(p, resolvePaseoWorktreesBaseRoot(options));
648
+ }
649
+ return /[/\\]\.paseo[/\\]worktrees[/\\]/.test(p);
650
+ }
651
+ /** True when `child` is strictly inside `parent` (handles both `/` and `\`). */
652
+ export function isDescendantPath(child, parent) {
653
+ let c = child.replace(/\\/g, "/").replace(/\/+$/, "");
654
+ let p = parent.replace(/\\/g, "/").replace(/\/+$/, "");
655
+ // Case-insensitive on Windows (drive letter like C: or D:)
656
+ if (/^[A-Za-z]:/.test(c) || /^[A-Za-z]:/.test(p)) {
657
+ c = c.toLowerCase();
658
+ p = p.toLowerCase();
659
+ }
660
+ if (!c.startsWith(p))
661
+ return false;
662
+ if (c.length === p.length)
663
+ return false;
664
+ return c[p.length] === "/";
665
+ }
666
+ export function parseWorktreeList(output) {
667
+ const entries = [];
668
+ let current = null;
669
+ for (const line of output.split("\n")) {
670
+ const trimmed = line.trim();
671
+ if (!trimmed) {
672
+ continue;
673
+ }
674
+ if (trimmed.startsWith("worktree ")) {
675
+ if (current) {
676
+ entries.push(current);
677
+ }
678
+ current = { path: trimmed.slice("worktree ".length).trim() };
679
+ continue;
680
+ }
681
+ if (current && trimmed.startsWith("branch ")) {
682
+ current.branchRef = trimmed.slice("branch ".length).trim();
683
+ }
684
+ if (current && trimmed === "bare") {
685
+ current.isBare = true;
686
+ }
687
+ }
688
+ if (current) {
689
+ entries.push(current);
690
+ }
691
+ return entries;
692
+ }
693
+ async function getWorktreePathForBranch(cwd, branchName) {
694
+ try {
695
+ const { stdout } = await runGitCommand(["worktree", "list", "--porcelain"], {
696
+ cwd,
697
+ envOverlay: READ_ONLY_GIT_ENV,
698
+ });
699
+ const entries = parseWorktreeList(stdout);
700
+ const ref = branchName.startsWith("refs/heads/") ? branchName : `refs/heads/${branchName}`;
701
+ return entries.find((entry) => entry.branchRef === ref)?.path ?? null;
702
+ }
703
+ catch {
704
+ return null;
705
+ }
706
+ }
707
+ export async function localBranchExists(cwd, branchName) {
708
+ return doesGitRefExist(cwd, `refs/heads/${branchName}`);
709
+ }
710
+ export async function renameCurrentBranch(cwd, newName) {
711
+ const worktreeRoot = await requireGitWorktreeRoot(cwd);
712
+ const previousBranch = await getCurrentBranch(cwd);
713
+ if (!previousBranch || previousBranch === "HEAD") {
714
+ throw new Error("Cannot rename branch in detached HEAD state");
715
+ }
716
+ await runGitCommand(["branch", "-m", newName], {
717
+ cwd,
718
+ timeout: 120000,
719
+ });
720
+ const currentBranch = await getCurrentBranch(cwd);
721
+ if (currentBranch) {
722
+ rebindPaseoWorktreeChangeRequestHint(worktreeRoot, previousBranch, currentBranch);
723
+ }
724
+ return { previousBranch, currentBranch };
725
+ }
726
+ async function getPaseoWorktreeForCwd(cwd, options = {}) {
727
+ // Fast-path reject: non-worktree paths do not need expensive ownership checks.
728
+ if (!/[\\/]worktrees[\\/]/.test(cwd)) {
729
+ return { isPaseoOwnedWorktree: false };
730
+ }
731
+ const ownership = await isPaseoOwnedWorktreeCwd(cwd, {
732
+ paseoHome: options.context?.paseoHome,
733
+ worktreesRoot: options.context?.worktreesRoot,
734
+ knownGitCommonDir: options.knownGitCommonDir,
735
+ });
736
+ if (!ownership.allowed) {
737
+ return { isPaseoOwnedWorktree: false };
738
+ }
739
+ return {
740
+ isPaseoOwnedWorktree: true,
741
+ worktreeRoot: options.knownWorktreeRoot ?? (await getWorktreeRoot(cwd, options.context)) ?? cwd,
742
+ };
743
+ }
744
+ // Worktrees created before baseRef existed only stored the stripped name; it resolves
745
+ // local-first, which is the base they were actually cut from.
746
+ function storedBaseRefFromMetadata(metadata) {
747
+ return metadata?.baseRef ?? metadata?.baseRefName ?? null;
748
+ }
749
+ function readPaseoWorktreeBaseRef(worktreeRoot) {
750
+ return storedBaseRefFromMetadata(readPaseoWorktreeMetadata(worktreeRoot));
751
+ }
752
+ async function getStoredBaseRefForCwd(cwd, context) {
753
+ if (context?.facts?.isGit) {
754
+ return context.facts.storedBaseRef;
755
+ }
756
+ const paseoWorktree = await getPaseoWorktreeForCwd(cwd, { context });
757
+ if (!paseoWorktree.isPaseoOwnedWorktree) {
758
+ return null;
759
+ }
760
+ return readPaseoWorktreeBaseRef(paseoWorktree.worktreeRoot);
761
+ }
762
+ async function getResolvedBaseRefForCwd(cwd, context) {
763
+ if (context?.facts?.isGit) {
764
+ return context.facts.resolvedBaseRef;
765
+ }
766
+ const { resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
767
+ return resolvedBaseRef;
768
+ }
769
+ async function resolveBaseRefForCwd(cwd, context) {
770
+ if (context?.facts?.isGit) {
771
+ return {
772
+ storedBaseRef: context.facts.storedBaseRef,
773
+ resolvedBaseRef: context.facts.resolvedBaseRef,
774
+ };
775
+ }
776
+ const storedBaseRef = await getStoredBaseRefForCwd(cwd, context);
777
+ return {
778
+ storedBaseRef,
779
+ resolvedBaseRef: storedBaseRef ?? (await resolveBaseRef(cwd, context)),
780
+ };
781
+ }
782
+ // The worktree stores the exact ref it was cut from ("refs/remotes/upstream/main") while
783
+ // callers still send its display name ("main"). A different qualified ref retains its own
784
+ // identity even when it has the same branch name.
785
+ function isSameBaseRef(stored, requested) {
786
+ return stored === requested || branchNameFromRef(stored) === requested;
787
+ }
788
+ // Names both refs rather than labelling either one correct: a caller's ref can be stale, but the
789
+ // stored ref can equally be wrong, so the message states the two facts and leaves the diagnosis open.
790
+ function baseRefMismatchError(refs) {
791
+ return new Error(`Base ref mismatch: stored ${refs.stored}, requested ${refs.requested}`);
792
+ }
793
+ function resolveOperationBaseRef(input) {
794
+ if (input.storedBaseRef &&
795
+ input.requestedBaseRef &&
796
+ !isSameBaseRef(input.storedBaseRef, input.requestedBaseRef)) {
797
+ throw baseRefMismatchError({
798
+ stored: input.storedBaseRef,
799
+ requested: input.requestedBaseRef,
800
+ });
801
+ }
802
+ return input.storedBaseRef ?? input.requestedBaseRef ?? input.resolvedBaseRef;
803
+ }
804
+ async function isWorkingTreeDirty(cwd, context) {
805
+ const { stdout } = await getRunGitCommand(context)(["status", "--porcelain"], {
806
+ cwd,
807
+ envOverlay: READ_ONLY_GIT_ENV,
808
+ logger: context?.logger,
809
+ });
810
+ return stdout.trim().length > 0;
811
+ }
812
+ export async function getOriginRemoteUrl(cwd, context) {
813
+ try {
814
+ const { stdout } = await getRunGitCommand(context)(["config", "--get", "remote.origin.url"], {
815
+ cwd,
816
+ envOverlay: READ_ONLY_GIT_ENV,
817
+ });
818
+ const url = stdout.trim();
819
+ return url.length > 0 ? url : null;
820
+ }
821
+ catch {
822
+ return null;
823
+ }
824
+ }
825
+ export async function hasOriginRemote(cwd) {
826
+ const url = await getOriginRemoteUrl(cwd);
827
+ return url !== null;
828
+ }
829
+ async function getGitConfigValue(cwd, key, context) {
830
+ try {
831
+ const { stdout } = await getRunGitCommand(context)(["config", "--get", key], {
832
+ cwd,
833
+ envOverlay: READ_ONLY_GIT_ENV,
834
+ logger: context?.logger,
835
+ });
836
+ const value = stdout.trim();
837
+ return value.length > 0 ? value : null;
838
+ }
839
+ catch {
840
+ return null;
841
+ }
842
+ }
843
+ async function getGitRemotePushUrl(cwd, remoteName, context) {
844
+ try {
845
+ const { stdout } = await getRunGitCommand(context)(["remote", "get-url", "--push", remoteName], {
846
+ cwd,
847
+ envOverlay: READ_ONLY_GIT_ENV,
848
+ logger: context?.logger,
849
+ });
850
+ const value = stdout.trim();
851
+ return value.length > 0 ? value : null;
852
+ }
853
+ catch {
854
+ return null;
855
+ }
856
+ }
857
+ function parseBranchMergeHeadRef(mergeRef) {
858
+ const prefix = "refs/heads/";
859
+ if (!mergeRef?.startsWith(prefix)) {
860
+ return null;
861
+ }
862
+ const headRef = mergeRef.slice(prefix.length).trim();
863
+ return headRef.length > 0 ? headRef : null;
864
+ }
865
+ async function resolvePullRequestStatusLookupTarget(cwd, currentBranch, context) {
866
+ if (context?.facts?.isGit && context.facts.pullRequestLookupTarget) {
867
+ return context.facts.pullRequestLookupTarget;
868
+ }
869
+ const branchRemoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`, context);
870
+ let branchMergeRef = null;
871
+ if (branchRemoteName) {
872
+ branchMergeRef = await getGitConfigValue(cwd, `branch.${currentBranch}.merge`, context);
873
+ }
874
+ const localBranchTarget = buildPullRequestLookupTargetFromBranchConfig({
875
+ currentBranch,
876
+ branchRemoteName,
877
+ branchMergeRef,
878
+ branchRemoteUrl: null,
879
+ originRemoteUrl: null,
880
+ resolvedBaseRef: null,
881
+ });
882
+ if (localBranchTarget.headRef === currentBranch) {
883
+ const pushTarget = await resolvePullRequestLookupTargetFromPushConfig(cwd, currentBranch, null, null, context);
884
+ return pushTarget ?? localBranchTarget;
885
+ }
886
+ const [branchRemoteUrl, originRemoteUrl, resolvedBaseRef] = await Promise.all([
887
+ branchRemoteName ? getGitConfigValue(cwd, `remote.${branchRemoteName}.url`, context) : null,
888
+ getGitConfigValue(cwd, "remote.origin.url", context),
889
+ getResolvedBaseRefForCwd(cwd, context),
890
+ ]);
891
+ const branchTarget = buildPullRequestLookupTargetFromBranchConfig({
892
+ currentBranch,
893
+ branchRemoteName,
894
+ branchMergeRef,
895
+ branchRemoteUrl,
896
+ originRemoteUrl,
897
+ resolvedBaseRef,
898
+ });
899
+ if (branchTarget.headRef !== currentBranch || branchTarget.headRepositoryOwner) {
900
+ return branchTarget;
901
+ }
902
+ const pushTarget = await resolvePullRequestLookupTargetFromPushConfig(cwd, currentBranch, originRemoteUrl, resolvedBaseRef, context);
903
+ return pushTarget ?? branchTarget;
904
+ }
905
+ export async function resolveAbsoluteGitDir(cwd, context) {
906
+ try {
907
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "--absolute-git-dir"], {
908
+ cwd,
909
+ envOverlay: READ_ONLY_GIT_ENV,
910
+ });
911
+ const gitDir = stdout.trim();
912
+ return gitDir.length > 0 ? gitDir : null;
913
+ }
914
+ catch {
915
+ return null;
916
+ }
917
+ }
918
+ async function resolveGitCommonDir(cwd, context) {
919
+ try {
920
+ const { stdout } = await getRunGitCommand(context)(["rev-parse", "--git-common-dir"], {
921
+ cwd,
922
+ envOverlay: READ_ONLY_GIT_ENV,
923
+ });
924
+ return resolveGitRevParsePath(cwd, stdout);
925
+ }
926
+ catch {
927
+ return null;
928
+ }
929
+ }
930
+ async function abortGitPullConflictState(cwd) {
931
+ const gitDir = await resolveAbsoluteGitDir(cwd);
932
+ if (!gitDir) {
933
+ return;
934
+ }
935
+ const mergeHeadPath = resolve(gitDir, "MERGE_HEAD");
936
+ const rebaseMergePath = resolve(gitDir, "rebase-merge");
937
+ const rebaseApplyPath = resolve(gitDir, "rebase-apply");
938
+ if (existsSync(mergeHeadPath)) {
939
+ try {
940
+ await runGitCommand(["merge", "--abort"], { cwd, timeout: 120000 });
941
+ }
942
+ catch {
943
+ // ignore
944
+ }
945
+ }
946
+ if (existsSync(rebaseMergePath) || existsSync(rebaseApplyPath)) {
947
+ try {
948
+ await runGitCommand(["rebase", "--abort"], { cwd, timeout: 120000 });
949
+ }
950
+ catch {
951
+ // ignore
952
+ }
953
+ }
954
+ }
955
+ export async function resolveRepositoryDefaultBranch(repoRoot, context) {
956
+ try {
957
+ const { stdout } = await getRunGitCommand(context)(["symbolic-ref", "--quiet", "refs/remotes/origin/HEAD"], {
958
+ cwd: repoRoot,
959
+ envOverlay: READ_ONLY_GIT_ENV,
960
+ });
961
+ const ref = stdout.trim();
962
+ if (ref) {
963
+ // Prefer a local branch name (e.g. "main") over the remote-tracking ref (e.g. "origin/main")
964
+ // so that status/diff/merge all operate against the same base ref.
965
+ const remoteShort = ref.replace(/^refs\/remotes\//, "");
966
+ const localName = remoteShort.startsWith("origin/")
967
+ ? remoteShort.slice("origin/".length)
968
+ : remoteShort;
969
+ try {
970
+ await getRunGitCommand(context)(["show-ref", "--verify", "--quiet", `refs/heads/${localName}`], {
971
+ cwd: repoRoot,
972
+ envOverlay: READ_ONLY_GIT_ENV,
973
+ });
974
+ return localName;
975
+ }
976
+ catch {
977
+ return remoteShort;
978
+ }
979
+ }
980
+ }
981
+ catch {
982
+ // ignore
983
+ }
984
+ const { stdout } = await getRunGitCommand(context)(["branch", "--format=%(refname:short)"], {
985
+ cwd: repoRoot,
986
+ envOverlay: READ_ONLY_GIT_ENV,
987
+ });
988
+ const branches = new Set(stdout
989
+ .split("\n")
990
+ .map((line) => line.trim())
991
+ .filter((line) => line.length > 0));
992
+ if (branches.has("main")) {
993
+ return "main";
994
+ }
995
+ if (branches.has("master")) {
996
+ return "master";
997
+ }
998
+ return null;
999
+ }
1000
+ async function resolveBaseRef(repoRoot, context) {
1001
+ return resolveRepositoryDefaultBranch(repoRoot, context);
1002
+ }
1003
+ function normalizeComparisonBaseRefName(input) {
1004
+ const localName = branchNameFromRef(input);
1005
+ return { localName, originRef: `origin/${localName}` };
1006
+ }
1007
+ function resolveMergeTargetBranch(baseRef) {
1008
+ const remotePrefix = "refs/remotes/";
1009
+ const originPrefix = `${remotePrefix}origin/`;
1010
+ if (baseRef.startsWith(remotePrefix) && !baseRef.startsWith(originPrefix)) {
1011
+ throw new Error(`No local merge target is recorded for base ref ${baseRef}`);
1012
+ }
1013
+ return branchNameFromRef(baseRef);
1014
+ }
1015
+ async function doesGitRefExist(cwd, fullRef, context) {
1016
+ const result = await getRunGitCommand(context)(["show-ref", "--verify", "--quiet", fullRef], {
1017
+ cwd,
1018
+ envOverlay: READ_ONLY_GIT_ENV,
1019
+ acceptExitCodes: [0, 1],
1020
+ logger: context?.logger,
1021
+ });
1022
+ return result.exitCode === 0;
1023
+ }
1024
+ function isQualifiedBranchRef(ref) {
1025
+ return ref.startsWith("refs/heads/") || ref.startsWith("refs/remotes/");
1026
+ }
1027
+ async function resolveBestComparisonBaseRef(cwd, baseRef, context) {
1028
+ // A fully qualified branch ref names the exact commit stream to compare against. Bare names
1029
+ // keep going through the local-vs-origin heuristic below for legacy worktree metadata.
1030
+ if (isQualifiedBranchRef(baseRef)) {
1031
+ if (await doesGitRefExist(cwd, baseRef, context)) {
1032
+ return baseRef;
1033
+ }
1034
+ throw new Error(`Base ref not found: ${baseRef}`);
1035
+ }
1036
+ const normalized = normalizeComparisonBaseRefName(baseRef);
1037
+ const [hasLocal, hasOrigin] = await Promise.all([
1038
+ doesGitRefExist(cwd, `refs/heads/${normalized.localName}`, context),
1039
+ doesGitRefExist(cwd, `refs/remotes/origin/${normalized.localName}`, context),
1040
+ ]);
1041
+ if (hasOrigin) {
1042
+ return normalized.originRef;
1043
+ }
1044
+ if (hasLocal) {
1045
+ return normalized.localName;
1046
+ }
1047
+ const refName = baseRef.startsWith("origin/") || baseRef.startsWith("refs/remotes/origin/")
1048
+ ? normalized.originRef
1049
+ : normalized.localName;
1050
+ throw new Error(`Base branch not found locally or on origin: ${refName}`);
1051
+ }
1052
+ async function resolveMostAheadBaseRef(cwd, baseRef) {
1053
+ if (isQualifiedBranchRef(baseRef)) {
1054
+ if (await doesGitRefExist(cwd, baseRef)) {
1055
+ return baseRef;
1056
+ }
1057
+ throw new Error(`Base ref not found: ${baseRef}`);
1058
+ }
1059
+ const normalizedBaseRef = branchNameFromRef(baseRef);
1060
+ const [hasLocal, hasOrigin] = await Promise.all([
1061
+ doesGitRefExist(cwd, `refs/heads/${normalizedBaseRef}`),
1062
+ doesGitRefExist(cwd, `refs/remotes/origin/${normalizedBaseRef}`),
1063
+ ]);
1064
+ if (hasLocal && !hasOrigin) {
1065
+ return normalizedBaseRef;
1066
+ }
1067
+ if (!hasLocal && hasOrigin) {
1068
+ return `origin/${normalizedBaseRef}`;
1069
+ }
1070
+ if (!hasLocal && !hasOrigin) {
1071
+ throw new Error(`Base branch not found locally or on origin: ${normalizedBaseRef}`);
1072
+ }
1073
+ const { stdout } = await runGitCommand(["rev-list", "--left-right", "--count", `${normalizedBaseRef}...origin/${normalizedBaseRef}`], { cwd, envOverlay: READ_ONLY_GIT_ENV });
1074
+ const [localOnlyRaw, originOnlyRaw] = stdout.trim().split(/\s+/);
1075
+ const localOnly = Number.parseInt(localOnlyRaw ?? "0", 10);
1076
+ const originOnly = Number.parseInt(originOnlyRaw ?? "0", 10);
1077
+ if (Number.isNaN(localOnly) || Number.isNaN(originOnly)) {
1078
+ return normalizedBaseRef;
1079
+ }
1080
+ if (originOnly > localOnly) {
1081
+ return `origin/${normalizedBaseRef}`;
1082
+ }
1083
+ return normalizedBaseRef;
1084
+ }
1085
+ async function getAheadBehind(cwd, baseRef, currentBranch, context) {
1086
+ const normalizedBaseRef = branchNameFromRef(baseRef);
1087
+ if (!normalizedBaseRef || !currentBranch || normalizedBaseRef === currentBranch) {
1088
+ return null;
1089
+ }
1090
+ const comparisonBaseRef = context?.facts?.isGit && context.facts.resolvedBaseRef === baseRef
1091
+ ? context.facts.comparisonBaseRef
1092
+ : await resolveBestComparisonBaseRef(cwd, baseRef, context);
1093
+ if (!comparisonBaseRef) {
1094
+ return null;
1095
+ }
1096
+ return getAheadBehindForComparisonRef(cwd, comparisonBaseRef, currentBranch, context);
1097
+ }
1098
+ async function getAheadBehindForComparisonRef(cwd, comparisonRef, currentBranch, context) {
1099
+ const { stdout } = await getRunGitCommand(context)(["rev-list", "--left-right", "--count", `${comparisonRef}...${currentBranch}`], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
1100
+ const [behindRaw, aheadRaw] = stdout.trim().split(/\s+/);
1101
+ const behind = Number.parseInt(behindRaw ?? "0", 10);
1102
+ const ahead = Number.parseInt(aheadRaw ?? "0", 10);
1103
+ if (Number.isNaN(behind) || Number.isNaN(ahead)) {
1104
+ return null;
1105
+ }
1106
+ return { ahead, behind };
1107
+ }
1108
+ async function getUpstreamStatus(cwd, currentBranch, context) {
1109
+ try {
1110
+ const { stdout } = await getRunGitCommand(context)([
1111
+ "for-each-ref",
1112
+ "--format=%(upstream)%00%(upstream:track,nobracket)",
1113
+ `refs/heads/${currentBranch}`,
1114
+ ], { cwd, envOverlay: READ_ONLY_GIT_ENV, logger: context?.logger });
1115
+ const [ref = "", track = ""] = stdout.trim().split("\0", 2);
1116
+ if (!ref || track === "gone") {
1117
+ return null;
1118
+ }
1119
+ const ahead = Number.parseInt(track.match(/ahead (\d+)/)?.[1] ?? "0", 10);
1120
+ const behind = Number.parseInt(track.match(/behind (\d+)/)?.[1] ?? "0", 10);
1121
+ return { ref, aheadBehind: { ahead, behind } };
1122
+ }
1123
+ catch {
1124
+ return null;
1125
+ }
1126
+ }
1127
+ async function inspectCheckoutContext(cwd, context) {
1128
+ const root = await getWorktreeRoot(cwd, context);
1129
+ if (!root) {
1130
+ return null;
1131
+ }
1132
+ const [currentBranch, remoteUrl, absoluteGitDir, gitCommonDir] = await Promise.all([
1133
+ getCurrentBranch(cwd, context),
1134
+ getOriginRemoteUrl(cwd, context),
1135
+ resolveAbsoluteGitDir(cwd, context),
1136
+ resolveGitCommonDir(cwd, context),
1137
+ ]);
1138
+ const paseoWorktree = await getPaseoWorktreeForCwd(cwd, {
1139
+ context,
1140
+ knownWorktreeRoot: root,
1141
+ knownGitCommonDir: gitCommonDir,
1142
+ });
1143
+ return {
1144
+ worktreeRoot: root,
1145
+ currentBranch,
1146
+ remoteUrl,
1147
+ absoluteGitDir,
1148
+ gitCommonDir,
1149
+ paseoWorktree,
1150
+ };
1151
+ }
1152
+ function buildPullRequestLookupTargetFromBranchConfig(input) {
1153
+ const trackedHeadRef = parseBranchMergeHeadRef(input.branchMergeRef);
1154
+ if (!input.branchRemoteName || !trackedHeadRef) {
1155
+ return { headRef: input.currentBranch };
1156
+ }
1157
+ const remoteRepo = parseRepositoryIdentityFromRemote(input.branchRemoteUrl);
1158
+ const originRepo = parseRepositoryIdentityFromRemote(input.originRemoteUrl);
1159
+ const isSameRepo = areSameGitHubRepository(remoteRepo, originRepo);
1160
+ const headRepositoryOwner = remoteRepo && !isSameRepo ? remoteRepo.split("/")[0] : null;
1161
+ const normalizedBaseRef = input.resolvedBaseRef ? branchNameFromRef(input.resolvedBaseRef) : null;
1162
+ if (trackedHeadRef === normalizedBaseRef &&
1163
+ !doesLocalBranchNameIdentifyTrackedHead(input.currentBranch, trackedHeadRef, headRepositoryOwner)) {
1164
+ return { headRef: input.currentBranch };
1165
+ }
1166
+ if (isSameRepo) {
1167
+ return { headRef: trackedHeadRef };
1168
+ }
1169
+ return {
1170
+ headRef: trackedHeadRef,
1171
+ ...(headRepositoryOwner ? { headRepositoryOwner } : {}),
1172
+ };
1173
+ }
1174
+ function parseRepositoryIdentityFromRemote(remoteUrl) {
1175
+ if (!remoteUrl) {
1176
+ return null;
1177
+ }
1178
+ const location = parseGitRemoteLocation(remoteUrl);
1179
+ return location ? (parseGitHubRemoteIdentity(location.path)?.repo ?? null) : null;
1180
+ }
1181
+ function areSameGitHubRepository(left, right) {
1182
+ return Boolean(left && right && left.toLowerCase() === right.toLowerCase());
1183
+ }
1184
+ function doesLocalBranchNameIdentifyTrackedHead(currentBranch, trackedHeadRef, headRepositoryOwner) {
1185
+ if (currentBranch === trackedHeadRef) {
1186
+ return true;
1187
+ }
1188
+ if (!headRepositoryOwner) {
1189
+ return false;
1190
+ }
1191
+ return [headRepositoryOwner, headRepositoryOwner.toLowerCase()].some((owner) => currentBranch === `${owner}/${trackedHeadRef}`);
1192
+ }
1193
+ function buildPullRequestLookupTargetFromPushConfig(input) {
1194
+ const pushedHeadRef = parseHeadPushRefspec(input.pushRefspec);
1195
+ if (!input.pushRemoteName || !pushedHeadRef || pushedHeadRef === input.currentBranch) {
1196
+ return null;
1197
+ }
1198
+ const remoteRepo = input.pushRemoteUrl ? parseGitHubRepoFromRemote(input.pushRemoteUrl) : null;
1199
+ const originRepo = input.originRemoteUrl
1200
+ ? parseGitHubRepoFromRemote(input.originRemoteUrl)
1201
+ : null;
1202
+ const isSameRepo = areSameGitHubRepository(remoteRepo, originRepo);
1203
+ const headRepositoryOwner = remoteRepo && !isSameRepo ? remoteRepo.split("/")[0] : null;
1204
+ const normalizedBaseRef = input.resolvedBaseRef ? branchNameFromRef(input.resolvedBaseRef) : null;
1205
+ if (pushedHeadRef === normalizedBaseRef && !headRepositoryOwner) {
1206
+ return null;
1207
+ }
1208
+ return {
1209
+ headRef: pushedHeadRef,
1210
+ ...(headRepositoryOwner ? { headRepositoryOwner } : {}),
1211
+ };
1212
+ }
1213
+ function buildPullRequestLookupTargetFromMetadata(metadata, currentBranch) {
1214
+ const target = getPaseoWorktreeChangeRequestHintForBranch(metadata, currentBranch);
1215
+ if (!target) {
1216
+ return null;
1217
+ }
1218
+ return {
1219
+ headRef: target.headRef,
1220
+ ...(target.headRepositoryOwner ? { headRepositoryOwner: target.headRepositoryOwner } : {}),
1221
+ };
1222
+ }
1223
+ function buildInitialPullRequestLookupTarget(input) {
1224
+ if (!input.currentBranch) {
1225
+ return null;
1226
+ }
1227
+ const hasConfiguredBranchTarget = Boolean(input.branchRemoteName && parseBranchMergeHeadRef(input.branchMergeRef));
1228
+ if (hasConfiguredBranchTarget) {
1229
+ return buildPullRequestLookupTargetFromBranchConfig({
1230
+ currentBranch: input.currentBranch,
1231
+ branchRemoteName: input.branchRemoteName,
1232
+ branchMergeRef: input.branchMergeRef,
1233
+ branchRemoteUrl: input.branchRemoteUrl,
1234
+ originRemoteUrl: input.originRemoteUrl,
1235
+ resolvedBaseRef: input.resolvedBaseRef,
1236
+ });
1237
+ }
1238
+ return buildPullRequestLookupTargetFromBranchConfig({
1239
+ currentBranch: input.currentBranch,
1240
+ branchRemoteName: input.branchRemoteName,
1241
+ branchMergeRef: input.branchMergeRef,
1242
+ branchRemoteUrl: input.branchRemoteUrl,
1243
+ originRemoteUrl: input.originRemoteUrl,
1244
+ resolvedBaseRef: input.resolvedBaseRef,
1245
+ });
1246
+ }
1247
+ async function resolvePullRequestLookupTargetFromPushConfig(cwd, currentBranch, knownOriginRemoteUrl, knownResolvedBaseRef, context) {
1248
+ const pushRemoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.pushRemote`, context);
1249
+ if (!pushRemoteName) {
1250
+ return null;
1251
+ }
1252
+ const [pushRefspec, pushRemoteUrl, originRemoteUrl, resolvedBaseRef] = await Promise.all([
1253
+ getGitConfigValue(cwd, `remote.${pushRemoteName}.push`, context),
1254
+ getGitConfigValue(cwd, `remote.${pushRemoteName}.url`, context),
1255
+ knownOriginRemoteUrl === null ? getGitConfigValue(cwd, "remote.origin.url", context) : null,
1256
+ knownResolvedBaseRef === null ? getResolvedBaseRefForCwd(cwd, context) : null,
1257
+ ]);
1258
+ return buildPullRequestLookupTargetFromPushConfig({
1259
+ currentBranch,
1260
+ pushRemoteName,
1261
+ pushRefspec,
1262
+ pushRemoteUrl,
1263
+ originRemoteUrl: knownOriginRemoteUrl ?? originRemoteUrl,
1264
+ resolvedBaseRef: knownResolvedBaseRef ?? resolvedBaseRef,
1265
+ });
1266
+ }
1267
+ async function resolveFactsPullRequestLookupTarget(input) {
1268
+ const { cwd, inspected, metadata, context } = input;
1269
+ const metadataTarget = inspected.currentBranch
1270
+ ? buildPullRequestLookupTargetFromMetadata(metadata, inspected.currentBranch)
1271
+ : null;
1272
+ if (metadataTarget) {
1273
+ return metadataTarget;
1274
+ }
1275
+ let target = buildInitialPullRequestLookupTarget({
1276
+ currentBranch: inspected.currentBranch,
1277
+ branchRemoteName: input.branchRemoteName,
1278
+ branchMergeRef: input.branchMergeRef,
1279
+ branchRemoteUrl: input.branchRemoteUrl,
1280
+ originRemoteUrl: inspected.remoteUrl,
1281
+ resolvedBaseRef: input.resolvedBaseRef,
1282
+ });
1283
+ if (inspected.currentBranch &&
1284
+ target?.headRef === inspected.currentBranch &&
1285
+ !target.headRepositoryOwner) {
1286
+ target =
1287
+ (await resolvePullRequestLookupTargetFromPushConfig(cwd, inspected.currentBranch, inspected.remoteUrl, input.resolvedBaseRef, context)) ?? target;
1288
+ }
1289
+ return target;
1290
+ }
1291
+ export async function getCheckoutSnapshotFacts(cwd, context) {
1292
+ if (context?.facts) {
1293
+ return context.facts;
1294
+ }
1295
+ const inspected = await inspectCheckoutContext(cwd, context);
1296
+ if (!inspected) {
1297
+ return { isGit: false };
1298
+ }
1299
+ const paseoWorktreeMetadata = inspected.paseoWorktree.isPaseoOwnedWorktree
1300
+ ? readPaseoWorktreeMetadata(inspected.paseoWorktree.worktreeRoot)
1301
+ : null;
1302
+ const storedBaseRef = storedBaseRefFromMetadata(paseoWorktreeMetadata);
1303
+ const resolvedBaseRef = storedBaseRef ?? (await resolveBaseRef(cwd, context));
1304
+ const mainRepoRoot = await getMainRepoRootFromCommonDir(cwd, inspected.gitCommonDir, context).catch(() => null);
1305
+ let comparisonBaseRef = null;
1306
+ if (resolvedBaseRef &&
1307
+ inspected.currentBranch &&
1308
+ branchNameFromRef(resolvedBaseRef) !== inspected.currentBranch) {
1309
+ comparisonBaseRef = await resolveBestComparisonBaseRef(cwd, resolvedBaseRef, context).catch(() => null);
1310
+ }
1311
+ let branchRemoteName = null;
1312
+ let branchMergeRef = null;
1313
+ let branchRemoteUrl = null;
1314
+ const upstreamStatusPromise = inspected.currentBranch
1315
+ ? getUpstreamStatus(cwd, inspected.currentBranch, context)
1316
+ : Promise.resolve(null);
1317
+ if (inspected.currentBranch) {
1318
+ branchRemoteName = await getGitConfigValue(cwd, `branch.${inspected.currentBranch}.remote`, context);
1319
+ if (branchRemoteName) {
1320
+ [branchMergeRef, branchRemoteUrl] = await Promise.all([
1321
+ getGitConfigValue(cwd, `branch.${inspected.currentBranch}.merge`, context),
1322
+ branchRemoteName === "origin"
1323
+ ? inspected.remoteUrl
1324
+ : getGitConfigValue(cwd, `remote.${branchRemoteName}.url`, context),
1325
+ ]);
1326
+ }
1327
+ }
1328
+ let pullRequestLookupTarget = await resolveFactsPullRequestLookupTarget({
1329
+ cwd,
1330
+ inspected,
1331
+ metadata: paseoWorktreeMetadata,
1332
+ branchRemoteName,
1333
+ branchMergeRef,
1334
+ branchRemoteUrl,
1335
+ resolvedBaseRef,
1336
+ context,
1337
+ });
1338
+ pullRequestLookupTarget = await addHeadShaToPullRequestLookupTarget(cwd, pullRequestLookupTarget, context);
1339
+ const upstreamStatus = await upstreamStatusPromise;
1340
+ return {
1341
+ isGit: true,
1342
+ worktreeRoot: inspected.worktreeRoot,
1343
+ currentBranch: inspected.currentBranch,
1344
+ remoteUrl: inspected.remoteUrl,
1345
+ absoluteGitDir: inspected.absoluteGitDir,
1346
+ gitCommonDir: inspected.gitCommonDir,
1347
+ paseoWorktree: inspected.paseoWorktree,
1348
+ storedBaseRef,
1349
+ resolvedBaseRef,
1350
+ mainRepoRoot,
1351
+ comparisonBaseRef,
1352
+ branchRemoteName,
1353
+ branchMergeRef,
1354
+ upstreamStatus,
1355
+ pullRequestLookupTarget,
1356
+ };
1357
+ }
1358
+ const PER_FILE_DIFF_MAX_BYTES = 1024 * 1024; // 1MB
1359
+ const TOTAL_DIFF_MAX_BYTES = 2 * 1024 * 1024; // 2MB
1360
+ const RELAY_MAX_FRAME_BYTES = 32 * 1024 * 1024;
1361
+ const CHECKOUT_DIFF_FRAME_HEADROOM_BYTES = 1024 * 1024;
1362
+ // Temporary until diffs load lazily per file. The Paseo relay's 32 MiB frame limit is
1363
+ // binding: string frames are encrypted and base64-encoded. Reserve 1 MiB plaintext for
1364
+ // the surrounding WebSocket JSON envelope after inverting that exact wire expansion.
1365
+ export const CHECKOUT_DIFF_MAX_STRUCTURED_BYTES = maxBase64EncryptedPlaintextByteLength(RELAY_MAX_FRAME_BYTES) - CHECKOUT_DIFF_FRAME_HEADROOM_BYTES;
1366
+ function createStructuredDiffAccumulator() {
1367
+ return { files: [], serializedBytes: Buffer.byteLength("[]", "utf8") };
1368
+ }
1369
+ function appendStructuredFile(structured, file) {
1370
+ const separatorBytes = structured.files.length > 0 ? 1 : 0;
1371
+ const fileBytes = Buffer.byteLength(JSON.stringify(file), "utf8");
1372
+ const nextBytes = structured.serializedBytes + separatorBytes + fileBytes;
1373
+ if (nextBytes > CHECKOUT_DIFF_MAX_STRUCTURED_BYTES) {
1374
+ return false;
1375
+ }
1376
+ structured.files.push(file);
1377
+ structured.serializedBytes = nextBytes;
1378
+ return true;
1379
+ }
1380
+ const UNTRACKED_BINARY_SNIFF_BYTES = 16 * 1024;
1381
+ async function isLikelyBinaryFile(absolutePath) {
1382
+ const handle = await openFile(absolutePath, "r");
1383
+ try {
1384
+ const buffer = Buffer.allocUnsafe(UNTRACKED_BINARY_SNIFF_BYTES);
1385
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
1386
+ if (bytesRead === 0) {
1387
+ return false;
1388
+ }
1389
+ let suspicious = 0;
1390
+ for (let i = 0; i < bytesRead; i += 1) {
1391
+ const byte = buffer[i];
1392
+ if (byte === 0) {
1393
+ return true;
1394
+ }
1395
+ // Treat control bytes as suspicious while allowing common whitespace.
1396
+ if (byte < 7 || (byte > 14 && byte < 32) || byte === 127) {
1397
+ suspicious += 1;
1398
+ }
1399
+ }
1400
+ return suspicious / bytesRead > 0.3;
1401
+ }
1402
+ finally {
1403
+ await handle.close();
1404
+ }
1405
+ }
1406
+ async function inspectUntrackedFile(cwd, relativePath) {
1407
+ const absolutePath = resolve(cwd, relativePath);
1408
+ const metadata = await statFile(absolutePath);
1409
+ if (!metadata.isFile()) {
1410
+ return { stat: null, truncated: false };
1411
+ }
1412
+ if (await isLikelyBinaryFile(absolutePath)) {
1413
+ return {
1414
+ stat: { additions: 0, deletions: 0, isBinary: true },
1415
+ truncated: false,
1416
+ };
1417
+ }
1418
+ if (metadata.size > PER_FILE_DIFF_MAX_BYTES) {
1419
+ return {
1420
+ stat: { additions: 0, deletions: 0, isBinary: false },
1421
+ truncated: true,
1422
+ };
1423
+ }
1424
+ return {
1425
+ stat: { additions: 0, deletions: 0, isBinary: false },
1426
+ truncated: false,
1427
+ };
1428
+ }
1429
+ function buildPlaceholderParsedDiffFile(change, options) {
1430
+ return {
1431
+ path: change.path,
1432
+ ...(change.oldPath ? { oldPath: change.oldPath } : {}),
1433
+ isNew: change.isNew,
1434
+ isDeleted: change.isDeleted,
1435
+ additions: options.stat?.additions ?? 0,
1436
+ deletions: options.stat?.deletions ?? 0,
1437
+ hunks: [],
1438
+ status: options.status,
1439
+ };
1440
+ }
1441
+ async function getUntrackedDiffText(cwd, change, ignoreWhitespace = false) {
1442
+ try {
1443
+ const inspected = await inspectUntrackedFile(cwd, change.path);
1444
+ if (inspected.stat?.isBinary || inspected.truncated) {
1445
+ return { text: "", truncated: inspected.truncated, stat: inspected.stat };
1446
+ }
1447
+ }
1448
+ catch {
1449
+ // Fall through to git diff path if metadata probing fails.
1450
+ }
1451
+ const result = await runGitCommand(buildGitDiffArgs({
1452
+ ignoreWhitespace,
1453
+ extra: ["--no-index", "/dev/null", "--", change.path],
1454
+ }), {
1455
+ cwd,
1456
+ envOverlay: READ_ONLY_GIT_ENV,
1457
+ maxOutputBytes: PER_FILE_DIFF_MAX_BYTES,
1458
+ acceptExitCodes: [0, 1],
1459
+ });
1460
+ return {
1461
+ text: result.stdout,
1462
+ truncated: result.truncated,
1463
+ stat: { additions: 0, deletions: 0, isBinary: false },
1464
+ };
1465
+ }
1466
+ export async function getCheckoutStatus(cwd, context) {
1467
+ const facts = await getCheckoutSnapshotFacts(cwd, context);
1468
+ if (!facts.isGit) {
1469
+ return { isGit: false };
1470
+ }
1471
+ const worktreeRoot = facts.worktreeRoot;
1472
+ const currentBranch = facts.currentBranch;
1473
+ const remoteUrl = facts.remoteUrl;
1474
+ const paseoWorktree = facts.paseoWorktree;
1475
+ const isDirty = await isWorkingTreeDirty(cwd, context);
1476
+ const hasRemote = remoteUrl !== null;
1477
+ const baseRef = facts.resolvedBaseRef;
1478
+ const mainRepoRoot = facts.mainRepoRoot;
1479
+ const factsContext = { ...context, facts };
1480
+ const aheadBehind = baseRef && currentBranch
1481
+ ? await getAheadBehind(cwd, baseRef, currentBranch, factsContext)
1482
+ : null;
1483
+ const upstreamStatus = facts.upstreamStatus;
1484
+ // The wire carries the display name: clients label the base with it and send it back to
1485
+ // request diffs and merges. The exact ref stays in worktree.json and in facts, where the
1486
+ // comparisons and actions read it.
1487
+ const displayBaseRef = baseRef ? branchNameFromRef(baseRef) : null;
1488
+ const upstreamRef = upstreamStatus?.ref ?? null;
1489
+ const aheadOfOrigin = upstreamStatus?.aheadBehind.ahead ?? null;
1490
+ const behindOfOrigin = upstreamStatus?.aheadBehind.behind ?? null;
1491
+ if (paseoWorktree.isPaseoOwnedWorktree && baseRef) {
1492
+ return {
1493
+ isGit: true,
1494
+ repoRoot: worktreeRoot,
1495
+ mainRepoRoot: mainRepoRoot ?? worktreeRoot,
1496
+ currentBranch,
1497
+ isDirty,
1498
+ baseRef: displayBaseRef ?? baseRef,
1499
+ aheadBehind,
1500
+ upstreamRef,
1501
+ aheadOfOrigin,
1502
+ behindOfOrigin,
1503
+ hasRemote,
1504
+ remoteUrl,
1505
+ isPaseoOwnedWorktree: true,
1506
+ };
1507
+ }
1508
+ return {
1509
+ isGit: true,
1510
+ repoRoot: worktreeRoot,
1511
+ mainRepoRoot: mainRepoRoot && resolve(mainRepoRoot) !== resolve(worktreeRoot) ? mainRepoRoot : null,
1512
+ currentBranch,
1513
+ isDirty,
1514
+ baseRef: displayBaseRef,
1515
+ aheadBehind,
1516
+ upstreamRef,
1517
+ aheadOfOrigin,
1518
+ behindOfOrigin,
1519
+ hasRemote,
1520
+ remoteUrl,
1521
+ isPaseoOwnedWorktree: false,
1522
+ };
1523
+ }
1524
+ // Workspace history stays complete; base history is bounded context until the
1525
+ // commits list supports paging older base commits.
1526
+ const CHECKOUT_BASE_COMMIT_LIMIT = 10;
1527
+ // Bytes git emits between fields/records. We split parsed output on these.
1528
+ const COMMIT_FIELD_SEPARATOR = "\x00";
1529
+ const COMMIT_RECORD_SEPARATOR = "\x1e";
1530
+ // Record-separated, NUL-field-separated so arbitrary subject text stays parseable.
1531
+ // `%x1e`/`%x00` are git placeholders (literal text in the arg, real bytes in the
1532
+ // output) — passing actual NUL bytes as a process arg is rejected by Node.
1533
+ const COMMIT_LOG_FORMAT = "%x1e%H%x00%h%x00%an%x00%aI%x00%s";
1534
+ function mapNameStatusLetter(letter) {
1535
+ switch (letter) {
1536
+ case "A":
1537
+ return "added";
1538
+ case "C":
1539
+ return "added";
1540
+ case "M":
1541
+ return "modified";
1542
+ case "T":
1543
+ return "modified";
1544
+ case "D":
1545
+ return "deleted";
1546
+ case "R":
1547
+ return "renamed";
1548
+ default:
1549
+ return undefined;
1550
+ }
1551
+ }
1552
+ // A `--raw` line: `:<srcmode> <dstmode> <srcsha> <dstsha> <STATUS>\t<path>`
1553
+ // (rename/copy add a second path: `R100\t<old>\t<new>`). The status token is the
1554
+ // last space-separated field before the first tab. Keyed on the destination path.
1555
+ function parseRawStatusLine(line, statuses) {
1556
+ const tabParts = line.split("\t");
1557
+ const meta = tabParts[0] ?? "";
1558
+ const statusToken = meta.slice(meta.lastIndexOf(" ") + 1);
1559
+ const letter = statusToken.charAt(0);
1560
+ const status = mapNameStatusLetter(letter);
1561
+ if (!status) {
1562
+ return;
1563
+ }
1564
+ const path = letter === "R" || letter === "C" ? (tabParts[tabParts.length - 1] ?? "") : (tabParts[1] ?? "");
1565
+ if (!path) {
1566
+ return;
1567
+ }
1568
+ statuses.set(path, status);
1569
+ }
1570
+ // A `--numstat` line: `<adds>\t<dels>\t<path>` (renames use `old => new`, binary
1571
+ // files report `-` for both counts). Keyed on the (normalized) destination path.
1572
+ function parseNumstatLine(line, stats) {
1573
+ const parts = line.split("\t");
1574
+ if (parts.length < 3) {
1575
+ return;
1576
+ }
1577
+ const additionsField = parts[0] ?? "";
1578
+ const deletionsField = parts[1] ?? "";
1579
+ const path = normalizeNumstatPath(parts.slice(2).join("\t"));
1580
+ if (!path) {
1581
+ return;
1582
+ }
1583
+ if (additionsField === "-" || deletionsField === "-") {
1584
+ stats.set(path, { additions: 0, deletions: 0 });
1585
+ return;
1586
+ }
1587
+ const additions = Number.parseInt(additionsField, 10);
1588
+ const deletions = Number.parseInt(deletionsField, 10);
1589
+ if (Number.isNaN(additions) || Number.isNaN(deletions)) {
1590
+ return;
1591
+ }
1592
+ stats.set(path, { additions, deletions });
1593
+ }
1594
+ // Parses the single combined `git log ... --raw --numstat -M` stream. Each record
1595
+ // (split on the record separator) starts with the NUL-field-separated header line,
1596
+ // then a blank line, then the interleaved `--raw` (status) and `--numstat` (counts)
1597
+ // blocks. We merge both by destination path so each file carries counts + status.
1598
+ function parseCheckoutCommitRecords(stdout) {
1599
+ const records = stdout.split(COMMIT_RECORD_SEPARATOR).filter((record) => record.length > 0);
1600
+ const commits = [];
1601
+ for (const record of records) {
1602
+ const lines = record.split("\n");
1603
+ const fields = (lines[0] ?? "").split(COMMIT_FIELD_SEPARATOR);
1604
+ if (fields.length < 5) {
1605
+ continue;
1606
+ }
1607
+ const sha = (fields[0] ?? "").trim();
1608
+ if (!sha) {
1609
+ continue;
1610
+ }
1611
+ const stats = new Map();
1612
+ const statuses = new Map();
1613
+ for (let index = 1; index < lines.length; index += 1) {
1614
+ const line = lines[index] ?? "";
1615
+ if (!line) {
1616
+ continue;
1617
+ }
1618
+ if (line.startsWith(":")) {
1619
+ parseRawStatusLine(line, statuses);
1620
+ }
1621
+ else {
1622
+ parseNumstatLine(line, stats);
1623
+ }
1624
+ }
1625
+ const files = [];
1626
+ for (const [path, stat] of stats) {
1627
+ const status = statuses.get(path);
1628
+ files.push({
1629
+ path,
1630
+ additions: stat.additions,
1631
+ deletions: stat.deletions,
1632
+ ...(status ? { status } : {}),
1633
+ });
1634
+ }
1635
+ commits.push({
1636
+ sha,
1637
+ shortSha: (fields[1] ?? "").trim(),
1638
+ authorName: fields[2] ?? "",
1639
+ authorDate: (fields[3] ?? "").trim(),
1640
+ subject: fields[4] ?? "",
1641
+ files,
1642
+ });
1643
+ }
1644
+ return commits;
1645
+ }
1646
+ // Returns commits reachable from HEAD that are not reachable from any remote ref.
1647
+ async function getUnpushedCommitShas(cwd, context) {
1648
+ const { stdout } = await runGitCommand(["rev-list", "HEAD", "--not", "--remotes"], {
1649
+ cwd,
1650
+ envOverlay: READ_ONLY_GIT_ENV,
1651
+ logger: context?.logger,
1652
+ });
1653
+ return new Set(stdout
1654
+ .split("\n")
1655
+ .map((line) => line.trim())
1656
+ .filter(Boolean));
1657
+ }
1658
+ async function getCheckoutCommitRecords({ cwd, revision, maxCount, }) {
1659
+ const args = [
1660
+ "log",
1661
+ revision,
1662
+ "--diff-merges=first-parent",
1663
+ `--format=${COMMIT_LOG_FORMAT}`,
1664
+ "--raw",
1665
+ "--numstat",
1666
+ "-M",
1667
+ ];
1668
+ if (maxCount !== undefined) {
1669
+ args.splice(2, 0, `--max-count=${maxCount}`);
1670
+ }
1671
+ const result = await runGitCommand(args, { cwd, envOverlay: READ_ONLY_GIT_ENV });
1672
+ if (result.truncated) {
1673
+ throw new Error("Commit history exceeded the git output limit");
1674
+ }
1675
+ return parseCheckoutCommitRecords(result.stdout);
1676
+ }
1677
+ async function tryResolveCheckoutCommitsBaseRef(cwd, baseRef, currentBranch) {
1678
+ if (!baseRef) {
1679
+ return null;
1680
+ }
1681
+ const normalizedBaseRef = branchNameFromRef(baseRef);
1682
+ if (!normalizedBaseRef || normalizedBaseRef === currentBranch) {
1683
+ return null;
1684
+ }
1685
+ try {
1686
+ return await resolveMostAheadBaseRef(cwd, baseRef);
1687
+ }
1688
+ catch (error) {
1689
+ if (isQualifiedBranchRef(baseRef)) {
1690
+ throw error;
1691
+ }
1692
+ return null;
1693
+ }
1694
+ }
1695
+ export async function listCheckoutCommits({ cwd, context, }) {
1696
+ const currentBranch = await getCurrentBranch(cwd);
1697
+ if (!currentBranch) {
1698
+ return { baseRef: null, commits: [] };
1699
+ }
1700
+ const { resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
1701
+ const normalizedBaseRef = resolvedBaseRef ? branchNameFromRef(resolvedBaseRef) : null;
1702
+ let comparisonBaseRef = await tryResolveCheckoutCommitsBaseRef(cwd, resolvedBaseRef, currentBranch);
1703
+ if (!comparisonBaseRef && normalizedBaseRef && normalizedBaseRef !== currentBranch) {
1704
+ // Saved worktree metadata can outlive a renamed or deleted base branch.
1705
+ comparisonBaseRef = await tryResolveCheckoutCommitsBaseRef(cwd, await resolveBaseRef(cwd), currentBranch);
1706
+ }
1707
+ let workspaceRecords = [];
1708
+ let baseRevision = "HEAD";
1709
+ if (comparisonBaseRef) {
1710
+ const [records, mergeBase] = await Promise.all([
1711
+ getCheckoutCommitRecords({ cwd, revision: `${comparisonBaseRef}..HEAD` }),
1712
+ tryResolveMergeBase(cwd, comparisonBaseRef),
1713
+ ]);
1714
+ workspaceRecords = records;
1715
+ baseRevision = mergeBase ?? "";
1716
+ }
1717
+ const baseRecords = baseRevision
1718
+ ? await getCheckoutCommitRecords({
1719
+ cwd,
1720
+ revision: baseRevision,
1721
+ maxCount: CHECKOUT_BASE_COMMIT_LIMIT,
1722
+ })
1723
+ : [];
1724
+ const records = [...workspaceRecords, ...baseRecords];
1725
+ if (records.length === 0) {
1726
+ return { baseRef: comparisonBaseRef, commits: [] };
1727
+ }
1728
+ const unpushedShas = await getUnpushedCommitShas(cwd);
1729
+ const workspaceShas = new Set(workspaceRecords.map((record) => record.sha));
1730
+ const commits = records.map((record) => ({
1731
+ sha: record.sha,
1732
+ shortSha: record.shortSha,
1733
+ subject: record.subject,
1734
+ authorName: record.authorName,
1735
+ authorDate: record.authorDate,
1736
+ isOnRemote: !unpushedShas.has(record.sha),
1737
+ isOnBase: !workspaceShas.has(record.sha),
1738
+ files: record.files,
1739
+ }));
1740
+ return { baseRef: comparisonBaseRef, commits };
1741
+ }
1742
+ /**
1743
+ * Fetches the unified diff of a single file as introduced by one commit and
1744
+ * parses it into the same {@link ParsedDiffFile} shape the diff subscription
1745
+ * emits (so the client can reuse its existing renderer).
1746
+ *
1747
+ * Compares merge commits to their first parent, matching the linear history shown
1748
+ * in the explorer. The text is parsed and highlighted by
1749
+ * {@link parseAndHighlightDiff} — the exact parser the diff subscription uses.
1750
+ * Returns `null` when the file is absent from the commit or the change is
1751
+ * binary-only (no textual hunks). Throws on git failure (e.g. an unknown sha),
1752
+ * which the caller maps to a typed checkout error.
1753
+ */
1754
+ export async function getCommitFileDiff({ cwd, sha, path, }) {
1755
+ const { stdout } = await runGitCommand(["show", sha, "--format=", "--diff-merges=first-parent", "--", path], {
1756
+ cwd,
1757
+ envOverlay: READ_ONLY_GIT_ENV,
1758
+ });
1759
+ if (stdout.trim().length === 0) {
1760
+ return null;
1761
+ }
1762
+ const parsedFiles = await parseAndHighlightDiff(stdout, cwd, {
1763
+ getOldFileContent: (file) => readGitFileContentAtRef(cwd, `${sha}^`, file.path),
1764
+ getNewFileContent: (file) => readGitFileContentAtRef(cwd, sha, file.path),
1765
+ });
1766
+ // `--` scopes the diff to a single pathspec, so there is at most one real
1767
+ // entry. Pick by path to drop any stray header-only section the parser emits.
1768
+ const file = parsedFiles.find((candidate) => candidate.path === path) ?? null;
1769
+ if (!file) {
1770
+ return null;
1771
+ }
1772
+ // Binary changes carry a "Binary files ... differ" marker and no hunks; there
1773
+ // is nothing textual to render, so report them as absent.
1774
+ if (file.hunks.length === 0 && /^Binary files .* differ$/m.test(stdout)) {
1775
+ return null;
1776
+ }
1777
+ return file;
1778
+ }
1779
+ function parseCheckoutShortstat(text) {
1780
+ const trimmed = text.trim();
1781
+ if (!trimmed) {
1782
+ return null;
1783
+ }
1784
+ let additions = 0;
1785
+ let deletions = 0;
1786
+ const addMatch = trimmed.match(/(\d+)\s+insertion/);
1787
+ if (addMatch) {
1788
+ additions = Number.parseInt(addMatch[1], 10);
1789
+ }
1790
+ const delMatch = trimmed.match(/(\d+)\s+deletion/);
1791
+ if (delMatch) {
1792
+ deletions = Number.parseInt(delMatch[1], 10);
1793
+ }
1794
+ if (additions === 0 && deletions === 0) {
1795
+ return null;
1796
+ }
1797
+ return { additions, deletions };
1798
+ }
1799
+ const UNTRACKED_SHORTSTAT_MAX_FILES = 500;
1800
+ async function countUntrackedAdditions(cwd, context, throwOnGitError = false) {
1801
+ try {
1802
+ const { stdout } = await getRunGitCommand(context)(["ls-files", "--others", "--exclude-standard"], {
1803
+ cwd,
1804
+ envOverlay: READ_ONLY_GIT_ENV,
1805
+ });
1806
+ const files = stdout
1807
+ .split("\n")
1808
+ .map((l) => l.trim())
1809
+ .filter(Boolean);
1810
+ let additions = 0;
1811
+ for (const file of files.slice(0, UNTRACKED_SHORTSTAT_MAX_FILES)) {
1812
+ const absolutePath = resolve(cwd, file);
1813
+ try {
1814
+ const metadata = await statFile(absolutePath);
1815
+ if (metadata.size > PER_FILE_DIFF_MAX_BYTES)
1816
+ continue;
1817
+ if (await isLikelyBinaryFile(absolutePath))
1818
+ continue;
1819
+ const content = await readFile(absolutePath, "utf-8");
1820
+ if (content.length === 0)
1821
+ continue;
1822
+ const normalized = content.replace(/\r\n/g, "\n");
1823
+ const lineCount = normalized.split("\n").length;
1824
+ additions += normalized.endsWith("\n") ? lineCount - 1 : lineCount;
1825
+ }
1826
+ catch {
1827
+ // Skip unreadable files.
1828
+ }
1829
+ }
1830
+ return additions;
1831
+ }
1832
+ catch (error) {
1833
+ if (throwOnGitError) {
1834
+ throw error;
1835
+ }
1836
+ return 0;
1837
+ }
1838
+ }
1839
+ function handleShortstatGitError(error, throwOnGitError = false) {
1840
+ if (throwOnGitError) {
1841
+ throw error;
1842
+ }
1843
+ return null;
1844
+ }
1845
+ async function getCheckoutShortstatUncached(cwd, context, options) {
1846
+ if (context?.facts?.isGit === false) {
1847
+ return null;
1848
+ }
1849
+ if (!context?.facts?.isGit) {
1850
+ try {
1851
+ await requireGitRepo(cwd, context);
1852
+ }
1853
+ catch {
1854
+ return null;
1855
+ }
1856
+ }
1857
+ const facts = context?.facts;
1858
+ const localBaseRef = facts?.isGit
1859
+ ? facts.resolvedBaseRef
1860
+ : await getResolvedBaseRefForCwd(cwd, context);
1861
+ const currentBranch = facts?.isGit ? facts.currentBranch : await getCurrentBranch(cwd, context);
1862
+ const comparisonRef = await resolveShortstatComparisonRef({
1863
+ cwd,
1864
+ currentBranch,
1865
+ localBaseRef,
1866
+ facts,
1867
+ context,
1868
+ });
1869
+ if (!comparisonRef) {
1870
+ return null;
1871
+ }
1872
+ try {
1873
+ const { stdout: mergeBaseOut } = await getRunGitCommand(context)(["merge-base", "HEAD", comparisonRef], {
1874
+ cwd,
1875
+ envOverlay: READ_ONLY_GIT_ENV,
1876
+ });
1877
+ const mergeBase = mergeBaseOut.trim();
1878
+ if (!mergeBase) {
1879
+ return null;
1880
+ }
1881
+ const [{ stdout }, untrackedAdditions] = await Promise.all([
1882
+ getRunGitCommand(context)(["diff", "--shortstat", mergeBase], {
1883
+ cwd,
1884
+ envOverlay: READ_ONLY_GIT_ENV,
1885
+ }),
1886
+ countUntrackedAdditions(cwd, context, options?.throwOnGitError),
1887
+ ]);
1888
+ const tracked = parseCheckoutShortstat(stdout);
1889
+ if (tracked) {
1890
+ return { additions: tracked.additions + untrackedAdditions, deletions: tracked.deletions };
1891
+ }
1892
+ if (untrackedAdditions > 0) {
1893
+ return { additions: untrackedAdditions, deletions: 0 };
1894
+ }
1895
+ return null;
1896
+ }
1897
+ catch (error) {
1898
+ return handleShortstatGitError(error, options?.throwOnGitError);
1899
+ }
1900
+ }
1901
+ async function resolveShortstatComparisonRef(input) {
1902
+ const { cwd, currentBranch, localBaseRef, facts, context } = input;
1903
+ if (!currentBranch) {
1904
+ return null;
1905
+ }
1906
+ if (localBaseRef && currentBranch !== localBaseRef) {
1907
+ try {
1908
+ return facts?.isGit && facts.resolvedBaseRef === localBaseRef && facts.comparisonBaseRef
1909
+ ? facts.comparisonBaseRef
1910
+ : await resolveBestComparisonBaseRef(cwd, localBaseRef, context);
1911
+ }
1912
+ catch {
1913
+ return null;
1914
+ }
1915
+ }
1916
+ const hasOrigin = await doesGitRefExist(cwd, `refs/remotes/origin/${currentBranch}`, context);
1917
+ return hasOrigin ? `origin/${currentBranch}` : null;
1918
+ }
1919
+ function getOrLoadCheckoutShortstat(cwd, context, options) {
1920
+ const cacheKey = getShortstatCacheKey(cwd);
1921
+ if (!options?.force) {
1922
+ const cached = shortstatCache.get(cacheKey);
1923
+ if (cached !== undefined) {
1924
+ return Promise.resolve(cached);
1925
+ }
1926
+ const existing = shortstatInFlight.get(cacheKey);
1927
+ if (existing) {
1928
+ return existing;
1929
+ }
1930
+ }
1931
+ const load = getCheckoutShortstatUncached(cwd, context)
1932
+ .then((shortstat) => {
1933
+ shortstatCache.set(cacheKey, shortstat);
1934
+ return shortstat;
1935
+ })
1936
+ .finally(() => {
1937
+ shortstatInFlight.delete(cacheKey);
1938
+ });
1939
+ shortstatInFlight.set(cacheKey, load);
1940
+ return load;
1941
+ }
1942
+ export async function getCheckoutShortstat(cwd, context, options) {
1943
+ return getOrLoadCheckoutShortstat(cwd, context, options);
1944
+ }
1945
+ function normalizeRemoteTrackingRef(ref) {
1946
+ return ref.startsWith("refs/remotes/") ? ref.slice("refs/remotes/".length) : ref;
1947
+ }
1948
+ function checkoutFactsConfiguredRemoteRef(facts) {
1949
+ const trackedBranch = facts.branchMergeRef?.startsWith("refs/heads/")
1950
+ ? facts.branchMergeRef.slice("refs/heads/".length)
1951
+ : null;
1952
+ return facts.branchRemoteName && facts.branchRemoteName !== "." && trackedBranch
1953
+ ? `${facts.branchRemoteName}/${trackedBranch}`
1954
+ : null;
1955
+ }
1956
+ function getCheckoutRefMovement(facts, movedRemoteRefs) {
1957
+ const currentBranch = facts.currentBranch;
1958
+ const comparisonRef = facts.comparisonBaseRef;
1959
+ const normalizedMoves = new Set([...movedRemoteRefs].map(normalizeRemoteTrackingRef));
1960
+ const normalizedResolvedBase = facts.resolvedBaseRef
1961
+ ? branchNameFromRef(facts.resolvedBaseRef)
1962
+ : null;
1963
+ const shortstatRemoteRef = currentBranch && (!normalizedResolvedBase || normalizedResolvedBase === currentBranch)
1964
+ ? `origin/${currentBranch}`
1965
+ : null;
1966
+ const baseMoved = [facts.storedBaseRef, facts.resolvedBaseRef, comparisonRef, shortstatRemoteRef]
1967
+ .filter((ref) => Boolean(ref))
1968
+ .map(normalizeRemoteTrackingRef)
1969
+ .some((ref) => normalizedMoves.has(ref));
1970
+ const upstreamRef = facts.upstreamStatus?.ref ?? checkoutFactsConfiguredRemoteRef(facts);
1971
+ const upstreamMoved = upstreamRef
1972
+ ? normalizedMoves.has(normalizeRemoteTrackingRef(upstreamRef))
1973
+ : false;
1974
+ return {
1975
+ baseMoved,
1976
+ comparisonRef,
1977
+ currentBranch,
1978
+ normalizedResolvedBase,
1979
+ upstreamMoved,
1980
+ upstreamRef,
1981
+ };
1982
+ }
1983
+ export async function getCheckoutRefDerivedState(cwd, facts, current, movedRemoteRefs, context) {
1984
+ const { baseMoved, comparisonRef, currentBranch, normalizedResolvedBase, upstreamMoved, upstreamRef, } = getCheckoutRefMovement(facts, movedRemoteRefs);
1985
+ let aheadBehind = current.aheadBehind;
1986
+ let diffStat = current.diffStat;
1987
+ if (baseMoved && currentBranch && facts.resolvedBaseRef) {
1988
+ aheadBehind = await getAheadBehind(cwd, facts.resolvedBaseRef, currentBranch, {
1989
+ ...context,
1990
+ facts,
1991
+ });
1992
+ }
1993
+ if (baseMoved || (upstreamMoved && currentBranch === normalizedResolvedBase)) {
1994
+ diffStat = await getCheckoutShortstatUncached(cwd, { ...context, facts }, { throwOnGitError: true });
1995
+ }
1996
+ let upstreamStatus = facts.upstreamStatus;
1997
+ if (upstreamMoved && currentBranch && upstreamRef) {
1998
+ const normalizedUpstream = normalizeRemoteTrackingRef(upstreamRef);
1999
+ const normalizedComparison = comparisonRef ? normalizeRemoteTrackingRef(comparisonRef) : null;
2000
+ const upstreamAheadBehind = baseMoved && normalizedComparison === normalizedUpstream
2001
+ ? aheadBehind
2002
+ : await getAheadBehindForComparisonRef(cwd, upstreamRef, currentBranch, context);
2003
+ upstreamStatus = upstreamAheadBehind
2004
+ ? {
2005
+ ref: facts.upstreamStatus?.ref ?? `refs/remotes/${normalizedUpstream}`,
2006
+ aheadBehind: upstreamAheadBehind,
2007
+ }
2008
+ : null;
2009
+ }
2010
+ return { aheadBehind, diffStat, upstreamStatus };
2011
+ }
2012
+ export async function getCheckoutWorktreeState(cwd, context) {
2013
+ const [isDirty, diffStat] = await Promise.all([
2014
+ isWorkingTreeDirty(cwd, context),
2015
+ getCheckoutShortstat(cwd, context, { force: true }),
2016
+ ]);
2017
+ return { isDirty, diffStat };
2018
+ }
2019
+ export function getCachedCheckoutShortstat(cwd) {
2020
+ return shortstatCache.get(getShortstatCacheKey(cwd));
2021
+ }
2022
+ export function warmCheckoutShortstatInBackground(cwd, context, onComplete) {
2023
+ const cacheKey = getShortstatCacheKey(cwd);
2024
+ if (shortstatCache.get(cacheKey) !== undefined || shortstatInFlight.has(cacheKey)) {
2025
+ return;
2026
+ }
2027
+ void getOrLoadCheckoutShortstat(cwd, context)
2028
+ .then(() => {
2029
+ onComplete?.();
2030
+ return;
2031
+ })
2032
+ .catch(() => {
2033
+ // Non-critical: keep listing path resilient even if git commands fail.
2034
+ });
2035
+ }
2036
+ async function buildHighlightedTrackedDiffFile(input) {
2037
+ const { cwd, change, parsedFile, refsForDiff } = input;
2038
+ const refPath = change.oldPath ?? change.path;
2039
+ const [oldFileContent, newFileContent] = await Promise.all([
2040
+ change.isNew ? null : readGitFileContentAtRef(cwd, refsForDiff.baseRef, refPath),
2041
+ refsForDiff.targetRef ? readGitFileContentAtRef(cwd, refsForDiff.targetRef, change.path) : null,
2042
+ ]);
2043
+ const highlightedFile = await highlightDiffWithFileContent(parsedFile, cwd, {
2044
+ oldFileContent,
2045
+ newFileContent,
2046
+ });
2047
+ return {
2048
+ ...highlightedFile,
2049
+ path: change.path,
2050
+ ...(change.oldPath ? { oldPath: change.oldPath } : {}),
2051
+ isNew: change.isNew,
2052
+ isDeleted: change.isDeleted,
2053
+ status: "ok",
2054
+ };
2055
+ }
2056
+ function isWhitespaceOnlyTrackedChange(input) {
2057
+ const { change, stat, ignoreWhitespace } = input;
2058
+ return (ignoreWhitespace &&
2059
+ change.status.startsWith("M") &&
2060
+ (!stat || (!stat.isBinary && stat.additions === 0 && stat.deletions === 0)));
2061
+ }
2062
+ async function appendStructuredTrackedDiffs(input) {
2063
+ const { cwd, trackedChanges, trackedNumstatByPath, trackedPlaceholderByPath, trackedDiffText, refsForDiff, ignoreWhitespace, structured, appendTrackedPlaceholderComment, } = input;
2064
+ const parsedTrackedFiles = trackedDiffText.length > 0 ? parseDiff(trackedDiffText) : [];
2065
+ const parsedTrackedByPath = new Map(parsedTrackedFiles.map((file) => [file.path, file]));
2066
+ for (const change of trackedChanges) {
2067
+ const placeholder = trackedPlaceholderByPath.get(change.path);
2068
+ if (placeholder) {
2069
+ const file = buildPlaceholderParsedDiffFile(change, {
2070
+ status: placeholder.status,
2071
+ stat: placeholder.stat,
2072
+ });
2073
+ if (!appendStructuredFile(structured, file)) {
2074
+ return false;
2075
+ }
2076
+ appendTrackedPlaceholderComment(change, placeholder.status);
2077
+ continue;
2078
+ }
2079
+ const stat = trackedNumstatByPath.get(change.path) ?? null;
2080
+ const parsedFile = parsedTrackedByPath.get(change.path);
2081
+ if (parsedFile) {
2082
+ const file = await buildHighlightedTrackedDiffFile({
2083
+ cwd,
2084
+ change,
2085
+ parsedFile,
2086
+ refsForDiff,
2087
+ });
2088
+ if (!appendStructuredFile(structured, file)) {
2089
+ return false;
2090
+ }
2091
+ continue;
2092
+ }
2093
+ // `git diff -w --name-status` can still report a modified path even when the
2094
+ // whitespace-filtered patch and numstat are both empty. Skip emitting a
2095
+ // structured placeholder in that case so whitespace-only edits truly disappear.
2096
+ if (isWhitespaceOnlyTrackedChange({ change, stat, ignoreWhitespace })) {
2097
+ continue;
2098
+ }
2099
+ const file = {
2100
+ path: change.path,
2101
+ ...(change.oldPath ? { oldPath: change.oldPath } : {}),
2102
+ isNew: change.isNew,
2103
+ isDeleted: change.isDeleted,
2104
+ additions: stat?.additions ?? 0,
2105
+ deletions: stat?.deletions ?? 0,
2106
+ hunks: [],
2107
+ status: "ok",
2108
+ };
2109
+ if (!appendStructuredFile(structured, file)) {
2110
+ return false;
2111
+ }
2112
+ }
2113
+ return true;
2114
+ }
2115
+ async function processUntrackedChange(input) {
2116
+ const { cwd, change, ignoreWhitespace, includeStructured, structured, appendDiff } = input;
2117
+ const { text, truncated, stat } = await getUntrackedDiffText(cwd, change, ignoreWhitespace);
2118
+ if (!includeStructured) {
2119
+ if (stat?.isBinary) {
2120
+ appendDiff(`# ${change.path}: binary diff omitted\n`);
2121
+ }
2122
+ else if (truncated) {
2123
+ appendDiff(`# ${change.path}: diff too large omitted\n`);
2124
+ }
2125
+ else {
2126
+ appendDiff(text);
2127
+ }
2128
+ return true;
2129
+ }
2130
+ if (stat?.isBinary) {
2131
+ if (!appendStructuredFile(structured, buildPlaceholderParsedDiffFile(change, { status: "binary", stat }))) {
2132
+ return false;
2133
+ }
2134
+ appendDiff(`# ${change.path}: binary diff omitted\n`);
2135
+ return true;
2136
+ }
2137
+ if (truncated) {
2138
+ if (!appendStructuredFile(structured, buildPlaceholderParsedDiffFile(change, { status: "too_large", stat }))) {
2139
+ return false;
2140
+ }
2141
+ appendDiff(`# ${change.path}: diff too large omitted\n`);
2142
+ return true;
2143
+ }
2144
+ appendDiff(text);
2145
+ const parsed = await parseAndHighlightDiff(text, cwd);
2146
+ const parsedFile = parsed[0] ??
2147
+ {
2148
+ path: change.path,
2149
+ isNew: change.isNew,
2150
+ isDeleted: change.isDeleted,
2151
+ additions: stat?.additions ?? 0,
2152
+ deletions: stat?.deletions ?? 0,
2153
+ hunks: [],
2154
+ };
2155
+ const file = {
2156
+ ...parsedFile,
2157
+ path: change.path,
2158
+ isNew: change.isNew,
2159
+ isDeleted: change.isDeleted,
2160
+ status: "ok",
2161
+ };
2162
+ return appendStructuredFile(structured, file);
2163
+ }
2164
+ async function processTrackedChanges(input) {
2165
+ const { cwd, refsForDiff, trackedChanges, ignoreWhitespace, appendDiff } = input;
2166
+ const trackedNumstatByPath = trackedChanges.length > 0
2167
+ ? await getTrackedNumstatByPath(cwd, refsForDiff, ignoreWhitespace)
2168
+ : new Map();
2169
+ const trackedDiffPaths = [];
2170
+ const trackedPlaceholderByPath = new Map();
2171
+ for (const change of trackedChanges) {
2172
+ const stat = trackedNumstatByPath.get(change.path) ?? null;
2173
+ if (stat?.isBinary) {
2174
+ trackedPlaceholderByPath.set(change.path, { status: "binary", stat });
2175
+ continue;
2176
+ }
2177
+ trackedDiffPaths.push(change.path);
2178
+ }
2179
+ let trackedDiffText = "";
2180
+ let trackedDiffBytes = 0;
2181
+ for (let start = 0; start < trackedDiffPaths.length; start += TRACKED_DIFF_BATCH_SIZE) {
2182
+ const paths = trackedDiffPaths.slice(start, start + TRACKED_DIFF_BATCH_SIZE);
2183
+ const trackedDiffs = await Promise.all(paths.map((path) => getTrackedDiffTextForPath({
2184
+ cwd,
2185
+ refsForDiff,
2186
+ path,
2187
+ ignoreWhitespace,
2188
+ })));
2189
+ for (const fileDiff of trackedDiffs) {
2190
+ if (fileDiff.truncated) {
2191
+ trackedPlaceholderByPath.set(fileDiff.path, {
2192
+ status: "too_large",
2193
+ stat: trackedNumstatByPath.get(fileDiff.path) ?? null,
2194
+ });
2195
+ continue;
2196
+ }
2197
+ const diffBytes = Buffer.byteLength(fileDiff.text, "utf8");
2198
+ if (trackedDiffBytes + diffBytes > TOTAL_DIFF_MAX_BYTES) {
2199
+ trackedPlaceholderByPath.set(fileDiff.path, {
2200
+ status: "too_large",
2201
+ stat: trackedNumstatByPath.get(fileDiff.path) ?? null,
2202
+ });
2203
+ continue;
2204
+ }
2205
+ trackedDiffBytes += diffBytes;
2206
+ trackedDiffText += fileDiff.text;
2207
+ }
2208
+ }
2209
+ appendDiff(trackedDiffText);
2210
+ return {
2211
+ trackedNumstatByPath,
2212
+ trackedPlaceholderByPath,
2213
+ trackedDiffText,
2214
+ };
2215
+ }
2216
+ async function resolveCheckoutDiffRefs(cwd, compare, context) {
2217
+ if (compare.mode === "uncommitted") {
2218
+ return { baseRef: "HEAD", includeUntracked: true };
2219
+ }
2220
+ const { storedBaseRef, resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
2221
+ const baseRef = resolveOperationBaseRef({
2222
+ storedBaseRef,
2223
+ resolvedBaseRef,
2224
+ requestedBaseRef: compare.baseRef,
2225
+ });
2226
+ if (!baseRef) {
2227
+ return null;
2228
+ }
2229
+ const bestBaseRef = await resolveBestComparisonBaseRef(cwd, baseRef);
2230
+ return {
2231
+ baseRef: (await tryResolveMergeBase(cwd, bestBaseRef)) ?? bestBaseRef,
2232
+ targetRef: "HEAD",
2233
+ includeUntracked: false,
2234
+ };
2235
+ }
2236
+ export async function getCheckoutDiff(cwd, compare, context) {
2237
+ await requireGitRepo(cwd);
2238
+ const refsForDiff = await resolveCheckoutDiffRefs(cwd, compare, context);
2239
+ if (!refsForDiff) {
2240
+ return { diff: "" };
2241
+ }
2242
+ const ignoreWhitespace = compare.ignoreWhitespace === true;
2243
+ let effectiveRefsForDiff = refsForDiff;
2244
+ let changes;
2245
+ try {
2246
+ changes = await listCheckoutFileChanges(cwd, effectiveRefsForDiff, ignoreWhitespace);
2247
+ }
2248
+ catch (error) {
2249
+ if (!isUnbornHeadDiffError(error)) {
2250
+ throw error;
2251
+ }
2252
+ effectiveRefsForDiff = { ...refsForDiff, baseRef: EMPTY_TREE_OBJECT_ID };
2253
+ changes = await listCheckoutFileChanges(cwd, effectiveRefsForDiff, ignoreWhitespace);
2254
+ }
2255
+ changes.sort((a, b) => {
2256
+ if (a.path === b.path)
2257
+ return 0;
2258
+ return a.path < b.path ? -1 : 1;
2259
+ });
2260
+ const structured = createStructuredDiffAccumulator();
2261
+ let diffText = "";
2262
+ let diffBytes = 0;
2263
+ const appendDiff = (text) => {
2264
+ if (!text)
2265
+ return;
2266
+ if (diffBytes >= TOTAL_DIFF_MAX_BYTES)
2267
+ return;
2268
+ const buf = Buffer.from(text, "utf8");
2269
+ if (diffBytes + buf.length <= TOTAL_DIFF_MAX_BYTES) {
2270
+ diffText += text;
2271
+ diffBytes += buf.length;
2272
+ return;
2273
+ }
2274
+ const remaining = TOTAL_DIFF_MAX_BYTES - diffBytes;
2275
+ if (remaining > 0) {
2276
+ diffText += buf.subarray(0, remaining).toString("utf8");
2277
+ diffBytes = TOTAL_DIFF_MAX_BYTES;
2278
+ }
2279
+ };
2280
+ const trackedChanges = changes.filter((change) => !change.isUntracked);
2281
+ const untrackedChanges = changes.filter((change) => change.isUntracked === true);
2282
+ const trackedDiff = await processTrackedChanges({
2283
+ cwd,
2284
+ refsForDiff: effectiveRefsForDiff,
2285
+ trackedChanges,
2286
+ ignoreWhitespace,
2287
+ appendDiff,
2288
+ });
2289
+ const appendTrackedPlaceholderComment = (change, status) => {
2290
+ if (status === "binary") {
2291
+ appendDiff(`# ${change.path}: binary diff omitted\n`);
2292
+ return;
2293
+ }
2294
+ appendDiff(`# ${change.path}: diff too large omitted\n`);
2295
+ };
2296
+ if (compare.includeStructured) {
2297
+ const didAppendTrackedDiffs = await appendStructuredTrackedDiffs({
2298
+ cwd,
2299
+ trackedChanges,
2300
+ trackedNumstatByPath: trackedDiff.trackedNumstatByPath,
2301
+ trackedPlaceholderByPath: trackedDiff.trackedPlaceholderByPath,
2302
+ trackedDiffText: trackedDiff.trackedDiffText,
2303
+ refsForDiff: effectiveRefsForDiff,
2304
+ ignoreWhitespace,
2305
+ structured,
2306
+ appendTrackedPlaceholderComment,
2307
+ });
2308
+ if (!didAppendTrackedDiffs) {
2309
+ return { diff: "", structured: [], diffTooLarge: true };
2310
+ }
2311
+ }
2312
+ else {
2313
+ for (const change of trackedChanges) {
2314
+ const placeholder = trackedDiff.trackedPlaceholderByPath.get(change.path);
2315
+ if (placeholder) {
2316
+ appendTrackedPlaceholderComment(change, placeholder.status);
2317
+ }
2318
+ }
2319
+ }
2320
+ for (const change of untrackedChanges) {
2321
+ if (diffBytes >= TOTAL_DIFF_MAX_BYTES) {
2322
+ break;
2323
+ }
2324
+ const didAppendUntrackedDiff = await processUntrackedChange({
2325
+ cwd,
2326
+ change,
2327
+ ignoreWhitespace,
2328
+ includeStructured: compare.includeStructured === true,
2329
+ structured,
2330
+ appendDiff,
2331
+ });
2332
+ if (!didAppendUntrackedDiff) {
2333
+ return { diff: "", structured: [], diffTooLarge: true };
2334
+ }
2335
+ }
2336
+ if (compare.includeStructured) {
2337
+ return { diff: diffText, structured: structured.files };
2338
+ }
2339
+ return { diff: diffText };
2340
+ }
2341
+ export async function commitChanges(cwd, options) {
2342
+ await requireGitRepo(cwd);
2343
+ if (options.addAll ?? true) {
2344
+ await runGitCommand(["add", "-A"], { cwd, timeout: 120000 });
2345
+ }
2346
+ await runGitCommand(["commit", "-m", options.message], {
2347
+ cwd,
2348
+ timeout: 120000,
2349
+ });
2350
+ }
2351
+ export async function commitAll(cwd, message) {
2352
+ await commitChanges(cwd, { message, addAll: true });
2353
+ }
2354
+ export async function discardChanges(cwd, pathspecs) {
2355
+ await requireGitRepo(cwd);
2356
+ if (pathspecs.length === 0) {
2357
+ return;
2358
+ }
2359
+ try {
2360
+ await runGitCommand(["--literal-pathspecs", "reset", "-q", "HEAD", "--", ...pathspecs], {
2361
+ cwd,
2362
+ timeout: DISCARD_CHANGES_TIMEOUT_MS,
2363
+ });
2364
+ }
2365
+ catch {
2366
+ // Why: unborn HEAD has no commit for reset, so remove the paths directly from the index.
2367
+ await runGitCommand(["--literal-pathspecs", "rm", "--cached", "-r", "-q", "--ignore-unmatch", "--", ...pathspecs], {
2368
+ cwd,
2369
+ timeout: DISCARD_CHANGES_TIMEOUT_MS,
2370
+ });
2371
+ }
2372
+ // With everything unstaged, the remaining state is only worktree
2373
+ // modifications/deletions (restore from the index) and untracked files
2374
+ // (clean). Classify from porcelain so each path gets the command that
2375
+ // actually applies to it.
2376
+ const status = await runGitCommand(["--literal-pathspecs", "status", "--porcelain=v1", "-z", "--", ...pathspecs], {
2377
+ cwd,
2378
+ timeout: DISCARD_CHANGES_TIMEOUT_MS,
2379
+ });
2380
+ const tracked = [];
2381
+ const untracked = [];
2382
+ const tokens = status.stdout.split("\0");
2383
+ for (let index = 0; index < tokens.length; index++) {
2384
+ const token = tokens[index];
2385
+ if (token.length < 4) {
2386
+ continue;
2387
+ }
2388
+ const state = token.slice(0, 2);
2389
+ const filePath = token.slice(3);
2390
+ if (state.startsWith("R") || state.startsWith("C")) {
2391
+ // Rename/copy entries carry the source path as the next NUL token.
2392
+ index += 1;
2393
+ }
2394
+ if (state === "??") {
2395
+ untracked.push(filePath);
2396
+ continue;
2397
+ }
2398
+ tracked.push(filePath);
2399
+ }
2400
+ if (tracked.length > 0) {
2401
+ await runGitCommand(["--literal-pathspecs", "checkout", "-q", "--", ...tracked], {
2402
+ cwd,
2403
+ timeout: DISCARD_CHANGES_TIMEOUT_MS,
2404
+ });
2405
+ }
2406
+ if (untracked.length > 0) {
2407
+ await runGitCommand(["--literal-pathspecs", "clean", "-fd", "-q", "--", ...untracked], {
2408
+ cwd,
2409
+ timeout: DISCARD_CHANGES_TIMEOUT_MS,
2410
+ });
2411
+ }
2412
+ }
2413
+ async function detectAndThrowMergeToBaseConflict(input) {
2414
+ const { operationCwd, error, baseRef, currentBranch } = input;
2415
+ const errorDetails = error instanceof Error
2416
+ ? `${error.message}\n${getErrorStderr(error)}\n${getErrorStdout(error)}`
2417
+ : String(error);
2418
+ try {
2419
+ const [unmergedOutput, lsFilesOutput, statusOutput] = await Promise.all([
2420
+ runGitCommand(["diff", "--name-only", "--diff-filter=U"], { cwd: operationCwd }),
2421
+ runGitCommand(["ls-files", "-u"], { cwd: operationCwd }),
2422
+ runGitCommand(["status", "--porcelain"], { cwd: operationCwd }),
2423
+ ]);
2424
+ const statusConflicts = statusOutput.stdout
2425
+ .split("\n")
2426
+ .map((line) => line.trim())
2427
+ .filter(Boolean)
2428
+ .filter((line) => /^(UU|AA|DD|AU|UA|UD|DU)\s/.test(line))
2429
+ .map((line) => line.slice(3).trim());
2430
+ const conflicts = [
2431
+ ...unmergedOutput.stdout
2432
+ .split("\n")
2433
+ .map((line) => line.trim())
2434
+ .filter(Boolean),
2435
+ ...lsFilesOutput.stdout
2436
+ .split("\n")
2437
+ .map((line) => line.trim())
2438
+ .filter(Boolean)
2439
+ .map((line) => line.split("\t").at(-1) ?? ""),
2440
+ ...statusConflicts,
2441
+ ].filter(Boolean);
2442
+ const conflictDetected = conflicts.length > 0 || /CONFLICT|Automatic merge failed/i.test(errorDetails);
2443
+ if (conflictDetected) {
2444
+ try {
2445
+ await runGitCommand(["merge", "--abort"], { cwd: operationCwd, timeout: 120000 });
2446
+ }
2447
+ catch {
2448
+ // ignore
2449
+ }
2450
+ throw new MergeConflictError({
2451
+ baseRef,
2452
+ currentBranch,
2453
+ conflictFiles: conflicts.length > 0 ? conflicts : [],
2454
+ });
2455
+ }
2456
+ }
2457
+ catch (innerError) {
2458
+ if (innerError instanceof MergeConflictError) {
2459
+ throw innerError;
2460
+ }
2461
+ // ignore detection failures
2462
+ }
2463
+ }
2464
+ export async function mergeToBase(cwd, options = {}, context) {
2465
+ await requireGitRepo(cwd);
2466
+ const currentBranch = await getCurrentBranch(cwd);
2467
+ const { storedBaseRef, resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
2468
+ const baseRef = resolveOperationBaseRef({
2469
+ storedBaseRef,
2470
+ resolvedBaseRef,
2471
+ requestedBaseRef: options.baseRef,
2472
+ });
2473
+ if (!baseRef) {
2474
+ throw new Error("Unable to determine base branch for merge");
2475
+ }
2476
+ if (!currentBranch) {
2477
+ throw new Error("Unable to determine current branch for merge");
2478
+ }
2479
+ const normalizedBaseRef = resolveMergeTargetBranch(baseRef);
2480
+ const currentWorktreeRoot = (await getWorktreeRoot(cwd, context)) ?? cwd;
2481
+ if (normalizedBaseRef === currentBranch) {
2482
+ return currentWorktreeRoot;
2483
+ }
2484
+ const baseWorktree = await getWorktreePathForBranch(cwd, normalizedBaseRef);
2485
+ const operationCwd = baseWorktree ?? currentWorktreeRoot;
2486
+ const isSameCheckout = resolve(operationCwd) === resolve(currentWorktreeRoot);
2487
+ const originalBranch = await getCurrentBranch(operationCwd);
2488
+ const mode = options.mode ?? "merge";
2489
+ try {
2490
+ await runGitCommand(["checkout", normalizedBaseRef], {
2491
+ cwd: operationCwd,
2492
+ timeout: 120000,
2493
+ });
2494
+ if (mode === "squash") {
2495
+ await runGitCommand(["merge", "--squash", currentBranch], {
2496
+ cwd: operationCwd,
2497
+ timeout: 120000,
2498
+ });
2499
+ const message = options.commitMessage ?? `Squash merge ${currentBranch} into ${normalizedBaseRef}`;
2500
+ await runGitCommand(["commit", "-m", message], {
2501
+ cwd: operationCwd,
2502
+ timeout: 120000,
2503
+ });
2504
+ }
2505
+ else {
2506
+ await runGitCommand(["merge", currentBranch], { cwd: operationCwd, timeout: 120000 });
2507
+ }
2508
+ }
2509
+ catch (error) {
2510
+ await detectAndThrowMergeToBaseConflict({
2511
+ operationCwd,
2512
+ error,
2513
+ baseRef: normalizedBaseRef,
2514
+ currentBranch,
2515
+ });
2516
+ throw error;
2517
+ }
2518
+ finally {
2519
+ if (isSameCheckout && originalBranch && originalBranch !== normalizedBaseRef) {
2520
+ try {
2521
+ await runGitCommand(["checkout", originalBranch], {
2522
+ cwd: operationCwd,
2523
+ timeout: 120000,
2524
+ });
2525
+ }
2526
+ catch {
2527
+ // ignore
2528
+ }
2529
+ }
2530
+ }
2531
+ return operationCwd;
2532
+ }
2533
+ export async function mergeFromBase(cwd, options = {}, context) {
2534
+ await requireGitRepo(cwd);
2535
+ const currentBranch = await getCurrentBranch(cwd);
2536
+ if (!currentBranch || currentBranch === "HEAD") {
2537
+ throw new Error("Unable to determine current branch for merge");
2538
+ }
2539
+ const { storedBaseRef, resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
2540
+ const baseRef = resolveOperationBaseRef({
2541
+ storedBaseRef,
2542
+ resolvedBaseRef,
2543
+ requestedBaseRef: options.baseRef,
2544
+ });
2545
+ if (!baseRef) {
2546
+ throw new Error("Unable to determine base branch for merge");
2547
+ }
2548
+ const requireCleanTarget = options.requireCleanTarget ?? true;
2549
+ if (requireCleanTarget) {
2550
+ const { stdout } = await runGitCommand(["status", "--porcelain"], {
2551
+ cwd,
2552
+ envOverlay: READ_ONLY_GIT_ENV,
2553
+ });
2554
+ if (stdout.trim().length > 0) {
2555
+ throw new Error("Working directory has uncommitted changes.");
2556
+ }
2557
+ }
2558
+ const bestBaseRef = await resolveMostAheadBaseRef(cwd, baseRef);
2559
+ if (bestBaseRef === currentBranch) {
2560
+ return;
2561
+ }
2562
+ try {
2563
+ await runGitCommand(["merge", bestBaseRef], { cwd, timeout: 120000 });
2564
+ }
2565
+ catch (error) {
2566
+ await detectAndThrowMergeFromBaseConflict({
2567
+ cwd,
2568
+ error,
2569
+ baseRef: bestBaseRef,
2570
+ currentBranch,
2571
+ });
2572
+ throw error;
2573
+ }
2574
+ }
2575
+ async function detectAndThrowMergeFromBaseConflict(input) {
2576
+ const { cwd, error, baseRef, currentBranch } = input;
2577
+ const errorDetails = error instanceof Error
2578
+ ? `${error.message}\n${getErrorStderr(error)}\n${getErrorStdout(error)}`
2579
+ : String(error);
2580
+ try {
2581
+ const [unmergedOutput, lsFilesOutput, statusOutput] = await Promise.all([
2582
+ runGitCommand(["diff", "--name-only", "--diff-filter=U"], { cwd }),
2583
+ runGitCommand(["ls-files", "-u"], { cwd }),
2584
+ runGitCommand(["status", "--porcelain"], { cwd }),
2585
+ ]);
2586
+ const statusConflicts = statusOutput.stdout
2587
+ .split("\n")
2588
+ .map((line) => line.trim())
2589
+ .filter(Boolean)
2590
+ .filter((line) => /^(UU|AA|DD|AU|UA|UD|DU)\s/.test(line))
2591
+ .map((line) => line.slice(3).trim());
2592
+ const conflicts = [
2593
+ ...unmergedOutput.stdout
2594
+ .split("\n")
2595
+ .map((line) => line.trim())
2596
+ .filter(Boolean),
2597
+ ...lsFilesOutput.stdout
2598
+ .split("\n")
2599
+ .map((line) => line.trim())
2600
+ .filter(Boolean)
2601
+ .map((line) => line.split("\t").at(-1) ?? ""),
2602
+ ...statusConflicts,
2603
+ ].filter(Boolean);
2604
+ const conflictDetected = conflicts.length > 0 || /CONFLICT|Automatic merge failed/i.test(errorDetails);
2605
+ if (conflictDetected) {
2606
+ try {
2607
+ await runGitCommand(["merge", "--abort"], { cwd, timeout: 120000 });
2608
+ }
2609
+ catch {
2610
+ // ignore
2611
+ }
2612
+ throw new MergeFromBaseConflictError({
2613
+ baseRef,
2614
+ currentBranch,
2615
+ conflictFiles: conflicts.length > 0 ? conflicts : [],
2616
+ });
2617
+ }
2618
+ }
2619
+ catch (innerError) {
2620
+ if (innerError instanceof MergeFromBaseConflictError) {
2621
+ throw innerError;
2622
+ }
2623
+ // ignore detection failures
2624
+ }
2625
+ }
2626
+ export async function pullCurrentBranch(cwd, forgeService) {
2627
+ await requireGitRepo(cwd);
2628
+ const currentBranch = await getCurrentBranch(cwd);
2629
+ if (!currentBranch || currentBranch === "HEAD") {
2630
+ throw new Error("Unable to determine current branch for pull");
2631
+ }
2632
+ const hasRemote = await hasOriginRemote(cwd);
2633
+ if (!hasRemote) {
2634
+ throw new Error("Remote 'origin' is not configured.");
2635
+ }
2636
+ try {
2637
+ await runGitCommand(["pull"], { cwd, timeout: 120000 });
2638
+ forgeService?.invalidate({ cwd });
2639
+ }
2640
+ catch (error) {
2641
+ await abortGitPullConflictState(cwd);
2642
+ throw error;
2643
+ }
2644
+ }
2645
+ export async function pushCurrentBranch(cwd, forgeService) {
2646
+ await requireGitRepo(cwd);
2647
+ const currentBranch = await getCurrentBranch(cwd);
2648
+ if (!currentBranch || currentBranch === "HEAD") {
2649
+ throw new Error("Unable to determine current branch for push");
2650
+ }
2651
+ const configuredPushTarget = await getCurrentBranchConfiguredPushTarget(cwd, currentBranch);
2652
+ if (configuredPushTarget) {
2653
+ await runGitCommand(["push", configuredPushTarget.remoteName, `HEAD:refs/heads/${configuredPushTarget.headRef}`], { cwd, timeout: 120000 });
2654
+ await refreshCurrentBranchTrackedRefAfterPush(cwd, currentBranch, configuredPushTarget);
2655
+ forgeService?.invalidate({ cwd });
2656
+ return;
2657
+ }
2658
+ const upstreamTarget = await getCurrentBranchUpstreamPushTarget(cwd, currentBranch);
2659
+ if (upstreamTarget) {
2660
+ await runGitCommand(["push", "-u", upstreamTarget.remoteName, `HEAD:refs/heads/${upstreamTarget.headRef}`], { cwd, timeout: 120000 });
2661
+ forgeService?.invalidate({ cwd });
2662
+ return;
2663
+ }
2664
+ const hasRemote = await hasOriginRemote(cwd);
2665
+ if (!hasRemote) {
2666
+ throw new Error("Remote 'origin' is not configured.");
2667
+ }
2668
+ await runGitCommand(["push", "-u", "origin", currentBranch], { cwd, timeout: 120000 });
2669
+ forgeService?.invalidate({ cwd });
2670
+ }
2671
+ async function getCurrentBranchConfiguredPushTarget(cwd, currentBranch) {
2672
+ const remoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.pushRemote`);
2673
+ const pushRefspec = remoteName ? await getGitConfigValue(cwd, `remote.${remoteName}.push`) : null;
2674
+ const headRef = parseHeadPushRefspec(pushRefspec);
2675
+ if (!remoteName || !headRef) {
2676
+ return null;
2677
+ }
2678
+ const remoteUrl = await getGitConfigValue(cwd, `remote.${remoteName}.url`);
2679
+ return remoteUrl ? { remoteName, headRef } : null;
2680
+ }
2681
+ async function refreshCurrentBranchTrackedRefAfterPush(cwd, currentBranch, pushedTarget) {
2682
+ const trackingRemoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`);
2683
+ const trackingMergeRef = await getGitConfigValue(cwd, `branch.${currentBranch}.merge`);
2684
+ const trackingHeadRef = parseBranchMergeHeadRef(trackingMergeRef);
2685
+ if (!trackingRemoteName && !trackingMergeRef) {
2686
+ const updated = await updateRemoteTrackingRef(cwd, pushedTarget.remoteName, pushedTarget.headRef);
2687
+ if (!updated) {
2688
+ return;
2689
+ }
2690
+ await runGitCommand(["config", `branch.${currentBranch}.remote`, pushedTarget.remoteName], {
2691
+ cwd,
2692
+ });
2693
+ await runGitCommand(["config", `branch.${currentBranch}.merge`, `refs/heads/${pushedTarget.headRef}`], {
2694
+ cwd,
2695
+ });
2696
+ return;
2697
+ }
2698
+ if (!trackingRemoteName || trackingHeadRef !== pushedTarget.headRef) {
2699
+ return;
2700
+ }
2701
+ const [trackingRemotePushUrl, pushedRemotePushUrl] = await Promise.all([
2702
+ getGitRemotePushUrl(cwd, trackingRemoteName),
2703
+ getGitRemotePushUrl(cwd, pushedTarget.remoteName),
2704
+ ]);
2705
+ if (!trackingRemotePushUrl || trackingRemotePushUrl !== pushedRemotePushUrl) {
2706
+ return;
2707
+ }
2708
+ await updateRemoteTrackingRef(cwd, trackingRemoteName, trackingHeadRef);
2709
+ }
2710
+ async function updateRemoteTrackingRef(cwd, remoteName, headRef) {
2711
+ const trackingRef = `refs/remotes/${remoteName}/${headRef}`;
2712
+ const checkRef = await runGitCommand(["check-ref-format", trackingRef], {
2713
+ cwd,
2714
+ acceptExitCodes: [0, 1],
2715
+ });
2716
+ if (checkRef.exitCode !== 0) {
2717
+ return false;
2718
+ }
2719
+ await runGitCommand(["update-ref", trackingRef, "HEAD"], { cwd, timeout: 120000 });
2720
+ return true;
2721
+ }
2722
+ async function getCurrentBranchUpstreamPushTarget(cwd, currentBranch) {
2723
+ const remoteName = await getGitConfigValue(cwd, `branch.${currentBranch}.remote`);
2724
+ const mergeRef = remoteName
2725
+ ? await getGitConfigValue(cwd, `branch.${currentBranch}.merge`)
2726
+ : null;
2727
+ const headRef = parseBranchMergeHeadRef(mergeRef);
2728
+ if (!remoteName || !headRef) {
2729
+ return null;
2730
+ }
2731
+ const remoteUrl = await getGitConfigValue(cwd, `remote.${remoteName}.url`);
2732
+ return remoteUrl ? { remoteName, headRef } : null;
2733
+ }
2734
+ function parseHeadPushRefspec(refspec) {
2735
+ const prefix = "HEAD:refs/heads/";
2736
+ const normalized = refspec?.trim().replace(/^\+/, "");
2737
+ if (!normalized?.startsWith(prefix)) {
2738
+ return null;
2739
+ }
2740
+ const headRef = normalized.slice(prefix.length).trim();
2741
+ return headRef.length > 0 ? headRef : null;
2742
+ }
2743
+ function buildPullRequestStatusResult(status, authState) {
2744
+ return { status, authState, githubFeaturesEnabled: authState === "authenticated" };
2745
+ }
2746
+ /** True for the CLI-missing / authentication errors of any supported forge. */
2747
+ export function isForgeAuthError(error) {
2748
+ return error instanceof ForgeCliMissingError || error instanceof ForgeAuthenticationError;
2749
+ }
2750
+ /**
2751
+ * Map a forge CLI failure to an auth state. A missing-CLI error means the user
2752
+ * must install the tool; anything else surfaced as an auth probe failure means
2753
+ * they must sign in.
2754
+ */
2755
+ export function forgeAuthStateFromError(error) {
2756
+ if (error instanceof ForgeCliMissingError) {
2757
+ return "cli_missing";
2758
+ }
2759
+ return "unauthenticated";
2760
+ }
2761
+ export async function createPullRequest(cwd, options, forgeService = createGitHubService(), context) {
2762
+ await requireGitRepo(cwd);
2763
+ const head = options.head ?? (await getCurrentBranch(cwd));
2764
+ const { storedBaseRef, resolvedBaseRef } = await resolveBaseRefForCwd(cwd, context);
2765
+ const base = resolveOperationBaseRef({
2766
+ storedBaseRef,
2767
+ resolvedBaseRef,
2768
+ requestedBaseRef: options.base,
2769
+ });
2770
+ if (!head) {
2771
+ throw new Error("Unable to determine head branch for PR");
2772
+ }
2773
+ if (!base) {
2774
+ throw new Error("Unable to determine base branch for PR");
2775
+ }
2776
+ const normalizedBase = branchNameFromRef(base);
2777
+ // The push deliberately happens before the adapter resolves the target
2778
+ // repository: slug resolution is adapter-internal (e.g. `gh repo view`, which
2779
+ // handles GHES and renamed repos), and the RPC path only reaches here after
2780
+ // the forge resolver has already matched the origin remote to a forge. If the
2781
+ // adapter still fails after the push, retrying is safe — the non-force push
2782
+ // of the head branch is idempotent.
2783
+ await runGitCommand(["push", "-u", "origin", head], { cwd, timeout: 120000 });
2784
+ const result = await forgeService.createPullRequest({
2785
+ cwd,
2786
+ title: options.title,
2787
+ body: options.body,
2788
+ head,
2789
+ base: normalizedBase,
2790
+ });
2791
+ forgeService.invalidate({ cwd });
2792
+ return result;
2793
+ }
2794
+ export async function getPullRequestStatus(cwd, forgeService = createGitHubService(), options, context) {
2795
+ const headSha = await getCurrentHeadSha(cwd, context);
2796
+ const cacheKey = getPullRequestStatusCacheKey(cwd, headSha);
2797
+ if (!options?.force) {
2798
+ const cached = pullRequestStatusCache.get(cacheKey);
2799
+ if (cached) {
2800
+ return cached;
2801
+ }
2802
+ const existing = pullRequestStatusInFlight.get(cacheKey);
2803
+ if (existing) {
2804
+ return existing;
2805
+ }
2806
+ }
2807
+ const lookup = getPullRequestStatusUncached(cwd, forgeService, options, context, headSha)
2808
+ .then((status) => {
2809
+ pullRequestStatusCache.set(cacheKey, status);
2810
+ rememberPullRequestStatus(cacheKey, status);
2811
+ return status;
2812
+ })
2813
+ .catch((error) => {
2814
+ if (!options?.force && error instanceof ForgeCommandError) {
2815
+ const stale = lastSuccessfulPullRequestStatus.get(cacheKey);
2816
+ if (stale) {
2817
+ return stale;
2818
+ }
2819
+ }
2820
+ throw error;
2821
+ })
2822
+ .finally(() => {
2823
+ pullRequestStatusInFlight.delete(cacheKey);
2824
+ });
2825
+ pullRequestStatusInFlight.set(cacheKey, lookup);
2826
+ return lookup;
2827
+ }
2828
+ async function getPullRequestStatusUncached(cwd, forgeService, options, context, headSha) {
2829
+ const unavailable = getUnavailablePullRequestStatus(context?.facts);
2830
+ if (unavailable)
2831
+ return unavailable;
2832
+ if (!context?.facts?.isGit) {
2833
+ await requireGitRepo(cwd, context);
2834
+ }
2835
+ const head = context?.facts?.isGit
2836
+ ? context.facts.currentBranch
2837
+ : await getCurrentBranch(cwd, context);
2838
+ if (!head) {
2839
+ return buildPullRequestStatusResult(null, "no_remote");
2840
+ }
2841
+ try {
2842
+ const resolvedLookupTarget = await resolvePullRequestStatusLookupTarget(cwd, head, context);
2843
+ const lookupTarget = headSha && !resolvedLookupTarget.headSha
2844
+ ? { ...resolvedLookupTarget, headSha }
2845
+ : resolvedLookupTarget;
2846
+ let status;
2847
+ if (options?.force) {
2848
+ const reason = options.reason;
2849
+ if (!reason) {
2850
+ throw new Error("Forced PR status read requires a reason");
2851
+ }
2852
+ status = await forgeService.getCurrentPullRequestStatus({
2853
+ cwd,
2854
+ ...lookupTarget,
2855
+ force: true,
2856
+ reason,
2857
+ });
2858
+ }
2859
+ else {
2860
+ status = await forgeService.getCurrentPullRequestStatus({
2861
+ cwd,
2862
+ ...lookupTarget,
2863
+ reason: options?.reason,
2864
+ });
2865
+ }
2866
+ return buildPullRequestStatusResult(status, "authenticated");
2867
+ }
2868
+ catch (error) {
2869
+ if (isForgeAuthError(error)) {
2870
+ return buildPullRequestStatusResult(null, forgeAuthStateFromError(error));
2871
+ }
2872
+ throw error;
2873
+ }
2874
+ }
2875
+ function getUnavailablePullRequestStatus(facts) {
2876
+ if (facts?.isGit === false) {
2877
+ return buildPullRequestStatusResult(null, "no_remote");
2878
+ }
2879
+ if (facts?.isGit === true &&
2880
+ facts.paseoWorktree.isPaseoOwnedWorktree &&
2881
+ facts.pullRequestLookupTarget === null) {
2882
+ return buildPullRequestStatusResult(null, "authenticated");
2883
+ }
2884
+ return null;
2885
+ }
2886
+ //# sourceMappingURL=checkout-git.js.map