devchain-cli 0.24.1 → 0.24.2

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 (343) hide show
  1. package/dist/build-info.json +2 -2
  2. package/dist/cli.js +40 -10
  3. package/dist/host-install/devchain-host-bootstrap.tgz +0 -0
  4. package/dist/host-install/pins.json +31 -2
  5. package/dist/lib/exclusive-run.js +51 -3
  6. package/dist/lib/git-owner.js +284 -0
  7. package/dist/lib/host-install.js +19 -151
  8. package/dist/lib/local-api.js +175 -0
  9. package/dist/server/common/config/env.config.d.ts +3 -0
  10. package/dist/server/common/config/env.config.js +1 -0
  11. package/dist/server/common/config/env.config.js.map +1 -1
  12. package/dist/server/common/config/host-image.json +3 -3
  13. package/dist/server/common/constants/syncthing-markers.d.ts +1 -0
  14. package/dist/server/common/constants/syncthing-markers.js +6 -1
  15. package/dist/server/common/constants/syncthing-markers.js.map +1 -1
  16. package/dist/server/common/filesystem/vm-home-path.d.ts +11 -0
  17. package/dist/server/common/filesystem/vm-home-path.js +48 -0
  18. package/dist/server/common/filesystem/vm-home-path.js.map +1 -0
  19. package/dist/server/common/process-ids-env.d.ts +1 -0
  20. package/dist/server/common/process-ids-env.js +13 -0
  21. package/dist/server/common/process-ids-env.js.map +1 -0
  22. package/dist/server/common/test/api-test-app.d.ts +12 -0
  23. package/dist/server/common/test/api-test-app.js +76 -0
  24. package/dist/server/common/test/api-test-app.js.map +1 -0
  25. package/dist/server/common/test/app-bootstrap.helper.js +8 -1
  26. package/dist/server/common/test/app-bootstrap.helper.js.map +1 -1
  27. package/dist/server/common/test/fake-bootstrap.server.js +3 -2
  28. package/dist/server/common/test/fake-bootstrap.server.js.map +1 -1
  29. package/dist/server/common/test/fake-docker-engine.server.d.ts +17 -6
  30. package/dist/server/common/test/fake-docker-engine.server.js +77 -33
  31. package/dist/server/common/test/fake-docker-engine.server.js.map +1 -1
  32. package/dist/server/common/test/fake-proxmox.server.js +4 -4
  33. package/dist/server/common/test/fake-ssh.server.js +6 -6
  34. package/dist/server/common/test/fake-ssh.server.js.map +1 -1
  35. package/dist/server/common/test/test-database.helper.d.ts +6 -0
  36. package/dist/server/common/test/test-database.helper.js +29 -0
  37. package/dist/server/common/test/test-database.helper.js.map +1 -0
  38. package/dist/server/modules/core/controllers/docker-archive.js +1 -1
  39. package/dist/server/modules/core/controllers/docker-archive.js.map +1 -1
  40. package/dist/server/modules/core/controllers/docker-engine.client.d.ts +2 -1
  41. package/dist/server/modules/core/controllers/docker-engine.client.js +8 -4
  42. package/dist/server/modules/core/controllers/docker-engine.client.js.map +1 -1
  43. package/dist/server/modules/core/controllers/docker-image-metadata.d.ts +248 -0
  44. package/dist/server/modules/core/controllers/docker-image-metadata.js +161 -0
  45. package/dist/server/modules/core/controllers/docker-image-metadata.js.map +1 -0
  46. package/dist/server/modules/core/controllers/docker-settings.d.ts +13 -2
  47. package/dist/server/modules/core/controllers/docker-settings.js +49 -11
  48. package/dist/server/modules/core/controllers/docker-settings.js.map +1 -1
  49. package/dist/server/modules/core/controllers/host-user-identity.d.ts +34 -0
  50. package/dist/server/modules/core/controllers/host-user-identity.js +23 -0
  51. package/dist/server/modules/core/controllers/host-user-identity.js.map +1 -0
  52. package/dist/server/modules/core/controllers/runtime.controller.d.ts +11 -4
  53. package/dist/server/modules/core/controllers/runtime.controller.js +2 -0
  54. package/dist/server/modules/core/controllers/runtime.controller.js.map +1 -1
  55. package/dist/server/modules/file-sync/build-exclusion-suggestions.d.ts +15 -0
  56. package/dist/server/modules/file-sync/build-exclusion-suggestions.js +402 -0
  57. package/dist/server/modules/file-sync/build-exclusion-suggestions.js.map +1 -0
  58. package/dist/server/modules/file-sync/file-sync-auto-fix.dto.d.ts +102 -0
  59. package/dist/server/modules/file-sync/file-sync-auto-fix.dto.js +22 -0
  60. package/dist/server/modules/file-sync/file-sync-auto-fix.dto.js.map +1 -0
  61. package/dist/server/modules/file-sync/file-sync-auto-fix.store.d.ts +12 -0
  62. package/dist/server/modules/file-sync/file-sync-auto-fix.store.js +73 -0
  63. package/dist/server/modules/file-sync/file-sync-auto-fix.store.js.map +1 -0
  64. package/dist/server/modules/file-sync/file-sync-conflicts.d.ts +3 -0
  65. package/dist/server/modules/file-sync/file-sync-conflicts.js +191 -0
  66. package/dist/server/modules/file-sync/file-sync-conflicts.js.map +1 -0
  67. package/dist/server/modules/file-sync/file-sync-ignores.store.d.ts +5 -1
  68. package/dist/server/modules/file-sync/file-sync-ignores.store.js +39 -8
  69. package/dist/server/modules/file-sync/file-sync-ignores.store.js.map +1 -1
  70. package/dist/server/modules/file-sync/file-sync.controller.d.ts +1 -3
  71. package/dist/server/modules/file-sync/file-sync.controller.js +5 -14
  72. package/dist/server/modules/file-sync/file-sync.controller.js.map +1 -1
  73. package/dist/server/modules/file-sync/file-sync.dto.d.ts +220 -1
  74. package/dist/server/modules/file-sync/file-sync.dto.js +70 -4
  75. package/dist/server/modules/file-sync/file-sync.dto.js.map +1 -1
  76. package/dist/server/modules/file-sync/file-sync.module.js +16 -1
  77. package/dist/server/modules/file-sync/file-sync.module.js.map +1 -1
  78. package/dist/server/modules/file-sync/file-sync.service.d.ts +18 -4
  79. package/dist/server/modules/file-sync/file-sync.service.js +166 -34
  80. package/dist/server/modules/file-sync/file-sync.service.js.map +1 -1
  81. package/dist/server/modules/file-sync/git-guard.dto.d.ts +61 -0
  82. package/dist/server/modules/file-sync/git-guard.dto.js +26 -0
  83. package/dist/server/modules/file-sync/git-guard.dto.js.map +1 -0
  84. package/dist/server/modules/file-sync/home-git-guard.service.d.ts +4 -2
  85. package/dist/server/modules/file-sync/home-git-guard.service.js +50 -25
  86. package/dist/server/modules/file-sync/home-git-guard.service.js.map +1 -1
  87. package/dist/server/modules/file-sync/host-git-guard.controller.d.ts +10 -0
  88. package/dist/server/modules/file-sync/host-git-guard.controller.js +64 -0
  89. package/dist/server/modules/file-sync/host-git-guard.controller.js.map +1 -0
  90. package/dist/server/modules/file-sync/host-git-index.controller.d.ts +9 -0
  91. package/dist/server/modules/file-sync/host-git-index.controller.js +67 -0
  92. package/dist/server/modules/file-sync/host-git-index.controller.js.map +1 -0
  93. package/dist/server/modules/file-sync/host-sync.controller.d.ts +15 -2
  94. package/dist/server/modules/file-sync/host-sync.controller.js +122 -14
  95. package/dist/server/modules/file-sync/host-sync.controller.js.map +1 -1
  96. package/dist/server/modules/file-sync/ignore-pattern-matcher.d.ts +30 -0
  97. package/dist/server/modules/file-sync/ignore-pattern-matcher.js +183 -0
  98. package/dist/server/modules/file-sync/ignore-pattern-matcher.js.map +1 -0
  99. package/dist/server/modules/file-sync/project-repository.d.ts +2 -0
  100. package/dist/server/modules/file-sync/project-repository.js +20 -0
  101. package/dist/server/modules/file-sync/project-repository.js.map +1 -0
  102. package/dist/server/modules/file-sync/sync-chown.dto.d.ts +99 -0
  103. package/dist/server/modules/file-sync/sync-chown.dto.js +46 -0
  104. package/dist/server/modules/file-sync/sync-chown.dto.js.map +1 -0
  105. package/dist/server/modules/file-sync/sync-chown.service.d.ts +12 -0
  106. package/dist/server/modules/file-sync/sync-chown.service.js +230 -0
  107. package/dist/server/modules/file-sync/sync-chown.service.js.map +1 -0
  108. package/dist/server/modules/file-sync/sync-path-inspection.dto.d.ts +626 -0
  109. package/dist/server/modules/file-sync/sync-path-inspection.dto.js +108 -0
  110. package/dist/server/modules/file-sync/sync-path-inspection.dto.js.map +1 -0
  111. package/dist/server/modules/file-sync/sync-path-inspector.d.ts +12 -0
  112. package/dist/server/modules/file-sync/sync-path-inspector.js +413 -0
  113. package/dist/server/modules/file-sync/sync-path-inspector.js.map +1 -0
  114. package/dist/server/modules/file-sync/testing/fake-file-sync.service.d.ts +27 -4
  115. package/dist/server/modules/file-sync/testing/fake-file-sync.service.js +66 -4
  116. package/dist/server/modules/file-sync/testing/fake-file-sync.service.js.map +1 -1
  117. package/dist/server/modules/file-sync/translate-git-ignore-rule.d.ts +3 -0
  118. package/dist/server/modules/file-sync/translate-git-ignore-rule.js +30 -0
  119. package/dist/server/modules/file-sync/translate-git-ignore-rule.js.map +1 -0
  120. package/dist/server/modules/mcp/services/handlers/skill-tools.js +2 -2
  121. package/dist/server/modules/mcp/services/handlers/skill-tools.js.map +1 -1
  122. package/dist/server/modules/remotes/connect-choices.controller.d.ts +9 -0
  123. package/dist/server/modules/remotes/connect-choices.controller.js +54 -0
  124. package/dist/server/modules/remotes/connect-choices.controller.js.map +1 -0
  125. package/dist/server/modules/remotes/connect-choices.dto.d.ts +52 -0
  126. package/dist/server/modules/remotes/connect-choices.dto.js +19 -0
  127. package/dist/server/modules/remotes/connect-choices.dto.js.map +1 -0
  128. package/dist/server/modules/remotes/connect-choices.store.d.ts +12 -0
  129. package/dist/server/modules/remotes/connect-choices.store.js +95 -0
  130. package/dist/server/modules/remotes/connect-choices.store.js.map +1 -0
  131. package/dist/server/modules/remotes/controllers/remotes.controller.d.ts +3 -0
  132. package/dist/server/modules/remotes/controllers/remotes.controller.js +9 -1
  133. package/dist/server/modules/remotes/controllers/remotes.controller.js.map +1 -1
  134. package/dist/server/modules/remotes/docker/docker-copy-back.js +40 -16
  135. package/dist/server/modules/remotes/docker/docker-copy-back.js.map +1 -1
  136. package/dist/server/modules/remotes/docker/docker-handoff.d.ts +5 -3
  137. package/dist/server/modules/remotes/docker/docker-handoff.js +146 -42
  138. package/dist/server/modules/remotes/docker/docker-handoff.js.map +1 -1
  139. package/dist/server/modules/remotes/docker/docker-handoff.store.d.ts +3 -0
  140. package/dist/server/modules/remotes/docker/docker-handoff.store.js.map +1 -1
  141. package/dist/server/modules/remotes/docker/docker-plan-fit.d.ts +4 -1
  142. package/dist/server/modules/remotes/docker/docker-plan-fit.js +19 -6
  143. package/dist/server/modules/remotes/docker/docker-plan-fit.js.map +1 -1
  144. package/dist/server/modules/remotes/docker/docker-plan-policy.d.ts +6 -2
  145. package/dist/server/modules/remotes/docker/docker-plan-policy.js +191 -38
  146. package/dist/server/modules/remotes/docker/docker-plan-policy.js.map +1 -1
  147. package/dist/server/modules/remotes/docker/docker-plan-source.service.d.ts +52 -8
  148. package/dist/server/modules/remotes/docker/docker-plan-source.service.js +273 -50
  149. package/dist/server/modules/remotes/docker/docker-plan-source.service.js.map +1 -1
  150. package/dist/server/modules/remotes/docker/docker-plan.controller.d.ts +2 -1
  151. package/dist/server/modules/remotes/docker/docker-plan.controller.js +14 -0
  152. package/dist/server/modules/remotes/docker/docker-plan.controller.js.map +1 -1
  153. package/dist/server/modules/remotes/docker/docker-plan.dto.d.ts +46 -1
  154. package/dist/server/modules/remotes/docker/docker-plan.dto.js +1 -0
  155. package/dist/server/modules/remotes/docker/docker-plan.dto.js.map +1 -1
  156. package/dist/server/modules/remotes/docker/docker-plan.service.d.ts +13 -7
  157. package/dist/server/modules/remotes/docker/docker-plan.service.js +57 -13
  158. package/dist/server/modules/remotes/docker/docker-plan.service.js.map +1 -1
  159. package/dist/server/modules/remotes/docker/docker-project-compose.d.ts +7 -0
  160. package/dist/server/modules/remotes/docker/docker-project-compose.js +30 -0
  161. package/dist/server/modules/remotes/docker/docker-project-compose.js.map +1 -0
  162. package/dist/server/modules/remotes/dtos/remote.dto.d.ts +2 -0
  163. package/dist/server/modules/remotes/dtos/remote.dto.js.map +1 -1
  164. package/dist/server/modules/remotes/git-owner.store.d.ts +13 -0
  165. package/dist/server/modules/remotes/git-owner.store.js +69 -0
  166. package/dist/server/modules/remotes/git-owner.store.js.map +1 -0
  167. package/dist/server/modules/remotes/host/host-docker.controller.d.ts +8 -0
  168. package/dist/server/modules/remotes/host/host-docker.controller.js +22 -6
  169. package/dist/server/modules/remotes/host/host-docker.controller.js.map +1 -1
  170. package/dist/server/modules/remotes/host/host-docker.dto.d.ts +606 -0
  171. package/dist/server/modules/remotes/host/host-docker.dto.js +47 -7
  172. package/dist/server/modules/remotes/host/host-docker.dto.js.map +1 -1
  173. package/dist/server/modules/remotes/host/host-docker.service.d.ts +16 -4
  174. package/dist/server/modules/remotes/host/host-docker.service.js +157 -82
  175. package/dist/server/modules/remotes/host/host-docker.service.js.map +1 -1
  176. package/dist/server/modules/remotes/host/host-ipv4-routes.d.ts +4 -0
  177. package/dist/server/modules/remotes/host/host-ipv4-routes.js +43 -0
  178. package/dist/server/modules/remotes/host/host-ipv4-routes.js.map +1 -0
  179. package/dist/server/modules/remotes/host-image.d.ts +1 -1
  180. package/dist/server/modules/remotes/host-image.js +1 -1
  181. package/dist/server/modules/remotes/host-install/host-install-block.d.ts +1 -0
  182. package/dist/server/modules/remotes/host-install/host-install-block.js +76 -2
  183. package/dist/server/modules/remotes/host-install/host-install-block.js.map +1 -1
  184. package/dist/server/modules/remotes/host-install/host-install.service.d.ts +0 -1
  185. package/dist/server/modules/remotes/host-install/host-install.service.js +9 -26
  186. package/dist/server/modules/remotes/host-install/host-install.service.js.map +1 -1
  187. package/dist/server/modules/remotes/operations/attach.operation.d.ts +5 -1
  188. package/dist/server/modules/remotes/operations/attach.operation.js +40 -5
  189. package/dist/server/modules/remotes/operations/attach.operation.js.map +1 -1
  190. package/dist/server/modules/remotes/operations/claim.operation.d.ts +1 -0
  191. package/dist/server/modules/remotes/operations/claim.operation.js +6 -1
  192. package/dist/server/modules/remotes/operations/claim.operation.js.map +1 -1
  193. package/dist/server/modules/remotes/operations/detach.operation.d.ts +4 -1
  194. package/dist/server/modules/remotes/operations/detach.operation.js +10 -2
  195. package/dist/server/modules/remotes/operations/detach.operation.js.map +1 -1
  196. package/dist/server/modules/remotes/operations/docker-import-inventory.store.d.ts +4 -0
  197. package/dist/server/modules/remotes/operations/docker-import-inventory.store.js +11 -0
  198. package/dist/server/modules/remotes/operations/docker-import-inventory.store.js.map +1 -1
  199. package/dist/server/modules/remotes/operations/file-sync-handoff.d.ts +29 -3
  200. package/dist/server/modules/remotes/operations/file-sync-handoff.js +477 -50
  201. package/dist/server/modules/remotes/operations/file-sync-handoff.js.map +1 -1
  202. package/dist/server/modules/remotes/operations/force-sync.operation.d.ts +39 -0
  203. package/dist/server/modules/remotes/operations/force-sync.operation.js +177 -0
  204. package/dist/server/modules/remotes/operations/force-sync.operation.js.map +1 -0
  205. package/dist/server/modules/remotes/operations/git-owner.dto.d.ts +83 -0
  206. package/dist/server/modules/remotes/operations/git-owner.dto.js +25 -0
  207. package/dist/server/modules/remotes/operations/git-owner.dto.js.map +1 -0
  208. package/dist/server/modules/remotes/operations/git-owner.operation.d.ts +35 -0
  209. package/dist/server/modules/remotes/operations/git-owner.operation.js +216 -0
  210. package/dist/server/modules/remotes/operations/git-owner.operation.js.map +1 -0
  211. package/dist/server/modules/remotes/operations/remote-host.client.d.ts +71 -7
  212. package/dist/server/modules/remotes/operations/remote-host.client.js +141 -11
  213. package/dist/server/modules/remotes/operations/remote-host.client.js.map +1 -1
  214. package/dist/server/modules/remotes/operations/remote-operation.dto.d.ts +19 -0
  215. package/dist/server/modules/remotes/operations/remote-operation.dto.js +5 -1
  216. package/dist/server/modules/remotes/operations/remote-operation.dto.js.map +1 -1
  217. package/dist/server/modules/remotes/operations/remote-operation.runner.d.ts +3 -1
  218. package/dist/server/modules/remotes/operations/remote-operation.runner.js +52 -21
  219. package/dist/server/modules/remotes/operations/remote-operation.runner.js.map +1 -1
  220. package/dist/server/modules/remotes/operations/remote-operation.types.d.ts +4 -1
  221. package/dist/server/modules/remotes/operations/remote-operation.types.js.map +1 -1
  222. package/dist/server/modules/remotes/operations/remote-operations.controller.d.ts +5 -0
  223. package/dist/server/modules/remotes/operations/remote-operations.controller.js +56 -0
  224. package/dist/server/modules/remotes/operations/remote-operations.controller.js.map +1 -1
  225. package/dist/server/modules/remotes/operations/remote-operations.service.d.ts +16 -1
  226. package/dist/server/modules/remotes/operations/remote-operations.service.js +155 -5
  227. package/dist/server/modules/remotes/operations/remote-operations.service.js.map +1 -1
  228. package/dist/server/modules/remotes/operations/update-logins.operation.d.ts +1 -3
  229. package/dist/server/modules/remotes/operations/update-logins.operation.js +3 -18
  230. package/dist/server/modules/remotes/operations/update-logins.operation.js.map +1 -1
  231. package/dist/server/modules/remotes/ports/remote-health.port.d.ts +2 -0
  232. package/dist/server/modules/remotes/ports/remote-health.port.js.map +1 -1
  233. package/dist/server/modules/remotes/remotes.module.js +18 -0
  234. package/dist/server/modules/remotes/remotes.module.js.map +1 -1
  235. package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.d.ts +2 -2
  236. package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.js +2 -13
  237. package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.js.map +1 -1
  238. package/dist/server/modules/remotes/services/remote-health.service.js +5 -0
  239. package/dist/server/modules/remotes/services/remote-health.service.js.map +1 -1
  240. package/dist/server/modules/remotes/sync/file-sync-failures.service.d.ts +18 -0
  241. package/dist/server/modules/remotes/sync/file-sync-failures.service.js +157 -0
  242. package/dist/server/modules/remotes/sync/file-sync-failures.service.js.map +1 -0
  243. package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.d.ts +14 -0
  244. package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.js +99 -0
  245. package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.js.map +1 -0
  246. package/dist/server/modules/remotes/sync/file-sync-suggestions.service.d.ts +15 -0
  247. package/dist/server/modules/remotes/sync/file-sync-suggestions.service.js +90 -0
  248. package/dist/server/modules/remotes/sync/file-sync-suggestions.service.js.map +1 -0
  249. package/dist/server/modules/remotes/sync/project-file-sync.controller.d.ts +29 -0
  250. package/dist/server/modules/remotes/sync/project-file-sync.controller.js +160 -0
  251. package/dist/server/modules/remotes/sync/project-file-sync.controller.js.map +1 -0
  252. package/dist/server/modules/remotes/sync/remote-file-sync.dto.d.ts +72 -0
  253. package/dist/server/modules/remotes/sync/remote-file-sync.dto.js +16 -0
  254. package/dist/server/modules/remotes/sync/remote-file-sync.dto.js.map +1 -0
  255. package/dist/server/modules/remotes/sync/remote-file-sync.service.d.ts +32 -1
  256. package/dist/server/modules/remotes/sync/remote-file-sync.service.js +499 -38
  257. package/dist/server/modules/remotes/sync/remote-file-sync.service.js.map +1 -1
  258. package/dist/server/modules/remotes/sync/remote-live-sync.service.d.ts +2 -0
  259. package/dist/server/modules/remotes/sync/remote-live-sync.service.js +26 -12
  260. package/dist/server/modules/remotes/sync/remote-live-sync.service.js.map +1 -1
  261. package/dist/server/modules/remotes/vm-user-identity.d.ts +29 -0
  262. package/dist/server/modules/remotes/vm-user-identity.js +45 -0
  263. package/dist/server/modules/remotes/vm-user-identity.js.map +1 -0
  264. package/dist/server/modules/runtime-context-capture/codex-plugin-profile-materializer.service.js +5 -1
  265. package/dist/server/modules/runtime-context-capture/codex-plugin-profile-materializer.service.js.map +1 -1
  266. package/dist/server/modules/session-reader/data/pricing.json +55 -7
  267. package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js +5 -0
  268. package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js.map +1 -1
  269. package/dist/server/modules/settings/local/delegates/skills-settings.delegate.d.ts +6 -0
  270. package/dist/server/modules/settings/local/delegates/skills-settings.delegate.js +26 -0
  271. package/dist/server/modules/settings/local/delegates/skills-settings.delegate.js.map +1 -1
  272. package/dist/server/modules/settings/services/settings.service.d.ts +3 -1
  273. package/dist/server/modules/settings/services/settings.service.js +6 -0
  274. package/dist/server/modules/settings/services/settings.service.js.map +1 -1
  275. package/dist/server/modules/skills/adapters/anthropic-skill-source.adapter.js +5 -5
  276. package/dist/server/modules/skills/adapters/anthropic-skill-source.adapter.js.map +1 -1
  277. package/dist/server/modules/skills/adapters/github-directory-skill-source.adapter.js +5 -5
  278. package/dist/server/modules/skills/adapters/github-directory-skill-source.adapter.js.map +1 -1
  279. package/dist/server/modules/skills/adapters/github-skill-source.base.js +4 -3
  280. package/dist/server/modules/skills/adapters/github-skill-source.base.js.map +1 -1
  281. package/dist/server/modules/skills/adapters/local-skill-source.adapter.js +5 -5
  282. package/dist/server/modules/skills/adapters/local-skill-source.adapter.js.map +1 -1
  283. package/dist/server/modules/skills/adapters/microsoft-skill-source.adapter.js +5 -5
  284. package/dist/server/modules/skills/adapters/microsoft-skill-source.adapter.js.map +1 -1
  285. package/dist/server/modules/skills/adapters/openai-skill-source.adapter.js +5 -5
  286. package/dist/server/modules/skills/adapters/openai-skill-source.adapter.js.map +1 -1
  287. package/dist/server/modules/skills/adapters/skill-source.adapter.d.ts +5 -0
  288. package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.d.ts +5 -0
  289. package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.js +75 -0
  290. package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.js.map +1 -0
  291. package/dist/server/modules/skills/adapters/trailofbits-skill-source.adapter.js +5 -5
  292. package/dist/server/modules/skills/adapters/trailofbits-skill-source.adapter.js.map +1 -1
  293. package/dist/server/modules/skills/adapters/vercel-skill-source.adapter.js +5 -5
  294. package/dist/server/modules/skills/adapters/vercel-skill-source.adapter.js.map +1 -1
  295. package/dist/server/modules/skills/controllers/skills.controller.js +2 -2
  296. package/dist/server/modules/skills/controllers/skills.controller.js.map +1 -1
  297. package/dist/server/modules/skills/services/skill-source-lifecycle.service.d.ts +3 -3
  298. package/dist/server/modules/skills/services/skill-source-lifecycle.service.js +9 -4
  299. package/dist/server/modules/skills/services/skill-source-lifecycle.service.js.map +1 -1
  300. package/dist/server/modules/skills/services/skill-sync.service.d.ts +3 -3
  301. package/dist/server/modules/skills/services/skill-sync.service.js +32 -6
  302. package/dist/server/modules/skills/services/skill-sync.service.js.map +1 -1
  303. package/dist/server/modules/skills/services/skill-sync.types.d.ts +3 -0
  304. package/dist/server/modules/storage/db/schema.d.ts +2 -2
  305. package/dist/server/modules/storage/db/schema.js +2 -0
  306. package/dist/server/modules/storage/db/schema.js.map +1 -1
  307. package/dist/server/modules/storage/models/domain.models.d.ts +1 -1
  308. package/dist/server/modules/storage/models/domain.models.js +2 -0
  309. package/dist/server/modules/storage/models/domain.models.js.map +1 -1
  310. package/dist/server/modules/terminal/gateways/terminal.gateway.d.ts +3 -1
  311. package/dist/server/modules/terminal/gateways/terminal.gateway.js +9 -4
  312. package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
  313. package/dist/server/modules/terminal/services/terminal-activity.service.d.ts +0 -1
  314. package/dist/server/modules/terminal/services/terminal-activity.service.js +0 -3
  315. package/dist/server/modules/terminal/services/terminal-activity.service.js.map +1 -1
  316. package/dist/server/modules/terminal/services/terminal-io/lifecycle.js +15 -3
  317. package/dist/server/modules/terminal/services/terminal-io/lifecycle.js.map +1 -1
  318. package/dist/server/modules/terminal/utils/ansi-sanitizer.d.ts +0 -1
  319. package/dist/server/modules/terminal/utils/ansi-sanitizer.js +0 -4
  320. package/dist/server/modules/terminal/utils/ansi-sanitizer.js.map +1 -1
  321. package/dist/server/templates/teams-dev.json +11 -11
  322. package/dist/server/test-setup-node.js +4 -3
  323. package/dist/server/test-setup-node.js.map +1 -1
  324. package/dist/server/test-setup.js +7 -0
  325. package/dist/server/test-setup.js.map +1 -1
  326. package/dist/server/tsconfig.tsbuildinfo +1 -1
  327. package/dist/server/ui/assets/{ExternalRichEditor-DtNvrV0F.js → ExternalRichEditor-CIZPhssf.js} +24 -24
  328. package/dist/server/ui/assets/ReviewDetailPage-winyLSQ7.js +6 -0
  329. package/dist/server/ui/assets/ReviewsPage-BYKBReMp.js +6 -0
  330. package/dist/server/ui/assets/index-CiDJX6Hn.js +1191 -0
  331. package/dist/server/ui/assets/index-f1WOAqXB.css +32 -0
  332. package/dist/server/ui/assets/useReviewSubscription-v3Cto0y4.js +69 -0
  333. package/dist/server/ui/index.html +2 -2
  334. package/dist/templates/teams-dev.json +11 -11
  335. package/package.json +8 -1
  336. package/dist/server/modules/reviews/utils/notification-formatter.d.ts +0 -12
  337. package/dist/server/modules/reviews/utils/notification-formatter.js +0 -60
  338. package/dist/server/modules/reviews/utils/notification-formatter.js.map +0 -1
  339. package/dist/server/ui/assets/ReviewDetailPage-DJzEoM0x.js +0 -6
  340. package/dist/server/ui/assets/ReviewsPage-z2O8MNEw.js +0 -6
  341. package/dist/server/ui/assets/index-CC4P3V8L.js +0 -994
  342. package/dist/server/ui/assets/index-LsJe1ZTS.css +0 -32
  343. package/dist/server/ui/assets/useReviewSubscription-B7AdJBO2.js +0 -69
@@ -11,13 +11,17 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.FileSyncHandoff = exports.FileSyncNotConnectedError = void 0;
13
13
  const common_1 = require("@nestjs/common");
14
+ const git_owner_store_1 = require("../git-owner.store");
15
+ const node_os_1 = require("node:os");
14
16
  const error_types_1 = require("../../../common/errors/error-types");
15
17
  const logger_1 = require("../../../common/logging/logger");
16
18
  const file_sync_dto_1 = require("../../file-sync/file-sync.dto");
17
19
  const file_sync_service_1 = require("../../file-sync/file-sync.service");
18
20
  const file_sync_managed_exclusions_store_1 = require("../../file-sync/file-sync-managed-exclusions.store");
19
21
  const home_git_guard_service_1 = require("../../file-sync/home-git-guard.service");
22
+ const project_repository_1 = require("../../file-sync/project-repository");
20
23
  const syncthing_rest_client_1 = require("../../file-sync/syncthing-rest.client");
24
+ const process_executor_port_1 = require("../../terminal/services/process-executor/process-executor.port");
21
25
  const remote_host_client_1 = require("./remote-host.client");
22
26
  const syncthing_temp_cleanup_1 = require("./syncthing-temp-cleanup");
23
27
  const logger = (0, logger_1.createLogger)('FileSyncHandoff');
@@ -30,20 +34,34 @@ class FileSyncNotConnectedError extends error_types_1.AppError {
30
34
  }
31
35
  }
32
36
  exports.FileSyncNotConnectedError = FileSyncNotConnectedError;
37
+ const SIDE_NAMES = { home: 'this PC', host: 'the VM' };
38
+ function forceErrors(status) {
39
+ const failures = (status.fileErrors ?? []).filter((file) => !(0, file_sync_dto_1.isTransientSyncError)(file.error));
40
+ return {
41
+ failures,
42
+ failed: failures.length > 0 ||
43
+ (status.errors ?? 0) > (status.fileErrors?.length ?? 0) ||
44
+ (!!status.error && !(0, file_sync_dto_1.isTransientSyncError)(status.error)),
45
+ };
46
+ }
33
47
  let FileSyncHandoff = class FileSyncHandoff {
34
48
  fileSync;
35
49
  host;
36
50
  managedExclusions;
37
51
  guard;
52
+ processExecutor;
53
+ gitOwner;
38
54
  active = new Map();
39
- constructor(fileSync, host, managedExclusions, guard) {
55
+ constructor(fileSync, host, managedExclusions, guard, processExecutor, gitOwner) {
40
56
  this.fileSync = fileSync;
41
57
  this.host = host;
42
58
  this.managedExclusions = managedExclusions;
43
59
  this.guard = guard;
60
+ this.processExecutor = processExecutor;
61
+ this.gitOwner = gitOwner;
44
62
  }
45
- interrupt(operationId) {
46
- this.active.get(operationId)?.abort(new Error('The Connect was cancelled.'));
63
+ interrupt(operationId, reason = 'The Connect was cancelled.') {
64
+ this.active.get(operationId)?.abort(new Error(reason));
47
65
  }
48
66
  async initial(run, projectId) {
49
67
  const controller = new AbortController();
@@ -51,6 +69,22 @@ let FileSyncHandoff = class FileSyncHandoff {
51
69
  try {
52
70
  const { remoteId } = run.operation;
53
71
  const ignores = this.syncIgnores(projectId);
72
+ const { removed } = await this.host.removeGitGuard(remoteId, projectId);
73
+ if (removed)
74
+ await run.progress({ vmGuardRemoved: true });
75
+ controller.signal.throwIfAborted();
76
+ const codeId = (0, file_sync_service_1.codeFolderId)(projectId);
77
+ if (run.details.fileSyncMode !== 'merge' && run.details.fileSyncMode !== 'reset') {
78
+ const [homeFolders, hostExists] = await Promise.all([
79
+ this.fileSync.projectFolders(projectId),
80
+ this.host.syncFolderExists(remoteId, codeId),
81
+ ]);
82
+ await run.progress({
83
+ fileSyncMode: hostExists && homeFolders.some((folder) => folder.id === codeId) ? 'merge' : 'reset',
84
+ }, { durable: true });
85
+ }
86
+ controller.signal.throwIfAborted();
87
+ const merge = run.details.fileSyncMode === 'merge';
54
88
  const devices = await this.pair(remoteId, controller.signal);
55
89
  const folders = await this.fileSync.initialFolders(projectId);
56
90
  for (const folder of folders) {
@@ -60,19 +94,65 @@ let FileSyncHandoff = class FileSyncHandoff {
60
94
  ignores: folder.kind === 'code' ? ignores : (0, file_sync_dto_1.gitIgnores)(false),
61
95
  paused: true,
62
96
  };
63
- await this.fileSync.ensureFolder({
64
- ...request,
65
- type: 'sendonly',
66
- peerDeviceId: devices.host,
67
- });
97
+ const mergeCode = merge && folder.kind === 'code';
98
+ if (mergeCode)
99
+ await this.fileSync.updateFolder(folder.id, { paused: true });
100
+ else
101
+ await this.fileSync.ensureFolder({
102
+ ...request,
103
+ type: 'sendonly',
104
+ peerDeviceId: devices.host,
105
+ });
68
106
  await this.host.syncFolders(remoteId, {
69
107
  ...request,
70
- type: 'receiveonly',
108
+ type: mergeCode ? 'sendreceive' : 'receiveonly',
71
109
  peerDeviceId: devices.home,
72
110
  });
73
111
  }
112
+ if (merge) {
113
+ await this.host.syncFolderType(remoteId, codeId, { paused: false });
114
+ await this.host.syncScan(remoteId, codeId);
115
+ await this.waitHostIdle(remoteId, codeId, controller.signal);
116
+ if (run.details.vmEdits === undefined &&
117
+ run.details.fileSyncConflictBaseline === undefined) {
118
+ const vmEdits = await this.host.syncRemoteNeed(remoteId, codeId, devices.home);
119
+ const homeBaseline = await this.fileSync.conflictBaseline(projectId, ignores, controller.signal);
120
+ const paths = new Set([
121
+ ...vmEdits.conflictPaths,
122
+ ...(homeBaseline.baselineOverCap ? [] : homeBaseline.paths),
123
+ ]);
124
+ const fileSyncConflictBaseline = homeBaseline.baselineOverCap ||
125
+ vmEdits.conflictsOverCap ||
126
+ paths.size > file_sync_dto_1.CONFLICT_BASELINE_MAX
127
+ ? { baselineOverCap: true }
128
+ : { baselineOverCap: false, paths: [...paths] };
129
+ await run.progress({ vmEdits, fileSyncConflictBaseline }, { durable: true });
130
+ }
131
+ else {
132
+ file_sync_dto_1.RemoteNeedSchema.parse(run.details.vmEdits);
133
+ file_sync_dto_1.ConflictBaselineSchema.parse(run.details.fileSyncConflictBaseline);
134
+ }
135
+ controller.signal.throwIfAborted();
136
+ await this.fileSync.ensureFolder({
137
+ projectId,
138
+ kind: 'code',
139
+ ignores,
140
+ paused: true,
141
+ type: 'sendreceive',
142
+ peerDeviceId: devices.host,
143
+ });
144
+ }
74
145
  await this.unpauseAll(remoteId, folders);
75
- await this.waitAll(run, folders, { sender: 'home', devices, signal: controller.signal });
146
+ await this.waitAll(run, folders, {
147
+ sender: 'home',
148
+ devices,
149
+ symmetricCode: merge,
150
+ signal: controller.signal,
151
+ });
152
+ if (merge) {
153
+ const fileSyncConflicts = await this.fileSync.conflicts(projectId, file_sync_dto_1.ConflictBaselineSchema.parse(run.details.fileSyncConflictBaseline), ignores, controller.signal);
154
+ await run.progress({ fileSyncConflicts });
155
+ }
76
156
  }
77
157
  finally {
78
158
  if (this.active.get(run.operation.id) === controller)
@@ -82,18 +162,278 @@ let FileSyncHandoff = class FileSyncHandoff {
82
162
  async ensureAvailable() {
83
163
  await this.fileSync.ensureAvailable();
84
164
  }
165
+ async ensureRepository(projectId) {
166
+ const root = await this.fileSync.folderPath(projectId);
167
+ if ((await (0, project_repository_1.projectRepository)(root)) !== 'missing')
168
+ return false;
169
+ const result = await this.processExecutor.run({
170
+ argv: ['git', 'init'],
171
+ mode: 'pipe',
172
+ cwd: root,
173
+ timeout: 30_000,
174
+ });
175
+ if (!result.success) {
176
+ throw new error_types_1.AppError(result.stderr.trim() ||
177
+ result.stdout.trim() ||
178
+ 'Could not create a Git repository on this PC.', 'GIT_INIT_FAILED', 500);
179
+ }
180
+ return true;
181
+ }
85
182
  async flipToHost(run, projectId) {
86
183
  const { remoteId } = run.operation;
87
184
  const folders = await this.fileSync.projectFolders(projectId);
88
- await this.hostDirections(remoteId, folders, false);
185
+ await this.hostDirections(remoteId, folders, 'vm', false);
89
186
  if (folders.some((folder) => folder.kind === 'git')) {
90
187
  const guardWarning = await this.guard.install(projectId, remoteId);
91
188
  if (guardWarning)
92
189
  await run.progress({ guardWarning });
93
190
  }
94
191
  }
192
+ async settleGit(run, projectId, owner) {
193
+ const controller = new AbortController();
194
+ const { remoteId, id } = run.operation;
195
+ this.active.set(id, controller);
196
+ try {
197
+ const devices = await this.pair(remoteId, controller.signal);
198
+ const folders = (0, file_sync_service_1.projectFolderList)(projectId, ['git']);
199
+ const config = owner === 'vm'
200
+ ? await this.fileSync.folderConfiguration(folders[0].id)
201
+ : await this.host.syncFolderConfiguration(remoteId, folders[0].id);
202
+ controller.signal.throwIfAborted();
203
+ if (config.type !== 'receiveonly' || config.paused)
204
+ throw new error_types_1.AppError('The receiving Git folder is not ready. Retry the switch.', 'GIT_SWITCH_RECEIVER_NOT_READY', 409);
205
+ await this.waitAll(run, folders, {
206
+ sender: owner === 'vm' ? 'host' : 'home',
207
+ devices,
208
+ requireNoReceiveOnlyChanges: true,
209
+ revertAfterComplete: true,
210
+ signal: controller.signal,
211
+ });
212
+ }
213
+ finally {
214
+ if (this.active.get(id) === controller)
215
+ this.active.delete(id);
216
+ }
217
+ }
218
+ async flipGit(run, projectId, owner) {
219
+ const { remoteId } = run.operation;
220
+ const folderId = (0, file_sync_service_1.projectFolderId)(projectId, 'git');
221
+ const ignores = (0, file_sync_dto_1.gitIgnores)(true);
222
+ if (owner === 'home') {
223
+ await this.host.syncFolderType(remoteId, folderId, { type: 'receiveonly', ignores });
224
+ await this.fileSync.updateFolder(folderId, { type: 'sendonly', ignores });
225
+ }
226
+ else {
227
+ await this.fileSync.updateFolder(folderId, { type: 'receiveonly', ignores });
228
+ await this.host.syncFolderType(remoteId, folderId, { type: 'sendonly', ignores });
229
+ }
230
+ this.gitOwner.set(projectId, owner);
231
+ await this.host.syncFolderType(remoteId, folderId, { paused: false });
232
+ await this.fileSync.updateFolder(folderId, { paused: false });
233
+ }
234
+ async forceCopy(run, projectId, source, kinds) {
235
+ const { remoteId, id: operationId } = run.operation;
236
+ const folders = (0, file_sync_service_1.projectFolderList)(projectId, kinds);
237
+ const sender = source === 'home' ? 'home' : 'host';
238
+ const receiver = sender === 'home' ? 'host' : 'home';
239
+ const backups = [];
240
+ for (const folder of folders) {
241
+ const request = { projectId, kind: folder.kind, forceCopy: { operationId } };
242
+ const { path } = receiver === 'home'
243
+ ? await this.fileSync.forceCopyBackup(request)
244
+ : await this.host.syncForceCopyBackup(remoteId, request);
245
+ backups.push({ side: receiver === 'home' ? 'home' : 'vm', kind: folder.kind, path });
246
+ }
247
+ await this.forceProgress(run, { backups, verified: false });
248
+ await this.guard.remove(projectId, { refreshIndex: false });
249
+ await this.host.removeGitGuard(remoteId, projectId);
250
+ for (const folder of folders) {
251
+ for (const side of ['home', 'host']) {
252
+ try {
253
+ if (side === 'home')
254
+ await this.fileSync.removeFolder(folder.id);
255
+ else
256
+ await this.host.syncRemoveFolder(remoteId, folder.id);
257
+ }
258
+ catch (error) {
259
+ if (!((error instanceof syncthing_rest_client_1.SyncthingRestError || error instanceof remote_host_client_1.RemoteHostRequestError) &&
260
+ error.status === 404))
261
+ throw error;
262
+ }
263
+ }
264
+ }
265
+ const devices = await this.pair(remoteId);
266
+ const ignores = this.syncIgnores(projectId);
267
+ for (const folder of folders) {
268
+ const request = {
269
+ projectId,
270
+ kind: folder.kind,
271
+ ignores: folder.kind === 'code' ? ignores : (0, file_sync_dto_1.gitIgnores)(false),
272
+ paused: true,
273
+ };
274
+ await this.fileSync.ensureFolder({
275
+ ...request,
276
+ type: sender === 'home' ? 'sendonly' : 'receiveonly',
277
+ peerDeviceId: devices.host,
278
+ ...(receiver === 'home' && { forceCopy: { operationId } }),
279
+ });
280
+ await this.host.syncFolders(remoteId, {
281
+ ...request,
282
+ type: sender === 'host' ? 'sendonly' : 'receiveonly',
283
+ peerDeviceId: devices.home,
284
+ ...(receiver === 'host' && { forceCopy: { operationId } }),
285
+ });
286
+ }
287
+ await this.unpauseAll(remoteId, folders);
288
+ for (const folder of folders) {
289
+ await Promise.all([
290
+ this.scan(sender, remoteId, folder.id),
291
+ this.scan(receiver, remoteId, folder.id),
292
+ ]);
293
+ }
294
+ for (const folder of folders) {
295
+ await this.waitBarrier(remoteId, folder.id, sender);
296
+ if (sender === 'home')
297
+ await this.fileSync.override(folder.id);
298
+ else
299
+ await this.host.syncOverride(remoteId, folder.id);
300
+ }
301
+ const replaced = { count: 0, sample: [] };
302
+ for (const folder of folders) {
303
+ const changed = receiver === 'home'
304
+ ? await this.fileSync.localChanges(folder.id)
305
+ : await this.host.syncLocalChanges(remoteId, folder.id);
306
+ replaced.count += changed.count;
307
+ replaced.sample.push(...changed.sample
308
+ .slice(0, file_sync_dto_1.RECEIVE_ONLY_SAMPLE_MAX - replaced.sample.length)
309
+ .map((name) => (folder.kind === 'git' ? `.git/${name}` : name)));
310
+ }
311
+ const earlier = this.forceDetails(run).replaced;
312
+ if (earlier) {
313
+ replaced.count = Math.max(replaced.count, earlier.count);
314
+ replaced.sample = [...new Set([...earlier.sample, ...replaced.sample])].slice(0, file_sync_dto_1.RECEIVE_ONLY_SAMPLE_MAX);
315
+ }
316
+ await this.forceProgress(run, { replaced });
317
+ let waitError;
318
+ try {
319
+ await this.waitAll(run, folders, {
320
+ sender,
321
+ devices,
322
+ symmetricCode: false,
323
+ requireNoReceiveOnlyChanges: true,
324
+ });
325
+ }
326
+ catch (error) {
327
+ waitError = error;
328
+ }
329
+ await this.verifyForceCopy(remoteId, folders, sender, devices);
330
+ if (waitError)
331
+ throw waitError;
332
+ await this.forceProgress(run, { verified: true });
333
+ }
334
+ async restoreConnected(run, projectId, kinds) {
335
+ if (this.forceDetails(run).verified !== true)
336
+ throw new error_types_1.AppError('Force sync has not verified the copy.', 'FORCE_SYNC_NOT_VERIFIED', 409);
337
+ const { remoteId } = run.operation;
338
+ const owner = this.gitOwner.get(projectId);
339
+ const devices = await this.pair(remoteId);
340
+ const folders = (0, file_sync_service_1.projectFolderList)(projectId, kinds);
341
+ const ignores = this.syncIgnores(projectId);
342
+ for (const folder of folders) {
343
+ const request = {
344
+ projectId,
345
+ kind: folder.kind,
346
+ ignores: folder.kind === 'code' ? ignores : (0, file_sync_dto_1.gitIgnores)(true),
347
+ paused: true,
348
+ };
349
+ const ensureHome = () => this.fileSync.ensureFolder({
350
+ ...request,
351
+ type: folder.kind === 'code' ? 'sendreceive' : owner === 'home' ? 'sendonly' : 'receiveonly',
352
+ peerDeviceId: devices.host,
353
+ });
354
+ const ensureHost = () => this.host.syncFolders(remoteId, {
355
+ ...request,
356
+ type: folder.kind === 'code' ? 'sendreceive' : owner === 'vm' ? 'sendonly' : 'receiveonly',
357
+ peerDeviceId: devices.home,
358
+ });
359
+ if (folder.kind === 'git' && owner === 'home') {
360
+ await ensureHost();
361
+ await ensureHome();
362
+ }
363
+ else {
364
+ await ensureHome();
365
+ await ensureHost();
366
+ }
367
+ }
368
+ await this.unpauseAll(remoteId, folders);
369
+ if (kinds.includes('git')) {
370
+ if (owner === 'vm') {
371
+ const guardWarning = await this.guard.install(projectId, remoteId);
372
+ if (guardWarning)
373
+ await run.progress({ guardWarning });
374
+ }
375
+ else {
376
+ const { warning } = await this.host.installGitGuard(remoteId, projectId, {
377
+ homeName: (0, node_os_1.hostname)(),
378
+ reason: 'pc-git',
379
+ });
380
+ await run.progress({ vmGuardWarning: warning });
381
+ }
382
+ }
383
+ }
384
+ forceDetails(run) {
385
+ const value = run.details.forceSync;
386
+ return value && typeof value === 'object' && !Array.isArray(value)
387
+ ? value
388
+ : {};
389
+ }
390
+ forceProgress(run, patch) {
391
+ return run.progress({ forceSync: { ...this.forceDetails(run), ...patch } }, { durable: true });
392
+ }
393
+ async waitBarrier(remoteId, folderId, sender) {
394
+ const receiver = sender === 'home' ? 'host' : 'home';
395
+ const deadline = Date.now() + SYNC_TIMEOUT_MS;
396
+ for (;;) {
397
+ const [source, target] = await Promise.all([
398
+ this.status(sender, remoteId, folderId),
399
+ this.status(receiver, remoteId, folderId),
400
+ ]);
401
+ if ((0, file_sync_service_1.senderIndexReached)(source, target))
402
+ return;
403
+ if (Date.now() >= deadline)
404
+ throw new file_sync_service_1.FileSyncTimeoutError(folderId, null, 'The source index did not reach the receiver.');
405
+ await sleep(POLL_MS);
406
+ }
407
+ }
408
+ async verifyForceCopy(remoteId, folders, sender, devices) {
409
+ const receiver = sender === 'home' ? 'host' : 'home';
410
+ const problems = [];
411
+ const failedFiles = [];
412
+ for (const folder of folders) {
413
+ const [source, target] = await Promise.all([
414
+ this.status(sender, remoteId, folder.id, devices[receiver], { allErrors: true }),
415
+ this.status(receiver, remoteId, folder.id, undefined, { allErrors: true }),
416
+ ]);
417
+ const targetErrors = forceErrors(target);
418
+ failedFiles.push(...targetErrors.failures
419
+ .slice(0, 3 - failedFiles.length)
420
+ .map((file) => `${folder.id}/${file.path}: ${file.error}`));
421
+ if (!(0, file_sync_service_1.evaluateCompletion)(source, target).done ||
422
+ target.receiveOnlyChangedFiles !== 0 ||
423
+ forceErrors(source).failed ||
424
+ targetErrors.failed) {
425
+ const reason = target.error ||
426
+ source.error ||
427
+ 'The copies are not in sync or still have receive-only changes.';
428
+ problems.push(`${folder.id}: ${reason}`);
429
+ }
430
+ }
431
+ if (problems.length)
432
+ throw new error_types_1.AppError(`Force sync failed: ${[...problems, ...failedFiles].join('; ')}`, 'FORCE_SYNC_INCOMPLETE', 500);
433
+ }
95
434
  async final(run, projectId) {
96
435
  const { remoteId } = run.operation;
436
+ const owner = this.gitOwner.get(projectId);
97
437
  const ignores = this.syncIgnores(projectId);
98
438
  const devices = await this.pair(remoteId);
99
439
  const folders = await this.fileSync.projectFolders(projectId);
@@ -105,19 +445,31 @@ let FileSyncHandoff = class FileSyncHandoff {
105
445
  ignores: folder.kind === 'code' ? ignores : (0, file_sync_dto_1.gitIgnores)(true),
106
446
  paused: true,
107
447
  };
108
- await this.host.syncFolders(remoteId, {
448
+ const ensureHost = () => this.host.syncFolders(remoteId, {
109
449
  ...request,
110
- type: folder.kind === 'code' ? 'sendreceive' : 'sendonly',
450
+ type: folder.kind === 'code' ? 'sendreceive' : owner === 'vm' ? 'sendonly' : 'receiveonly',
111
451
  peerDeviceId: devices.home,
112
452
  });
113
- await this.fileSync.ensureFolder({
453
+ const ensureHome = () => this.fileSync.ensureFolder({
114
454
  ...request,
115
- type: folder.kind === 'code' ? 'sendreceive' : 'receiveonly',
455
+ type: folder.kind === 'code' ? 'sendreceive' : owner === 'home' ? 'sendonly' : 'receiveonly',
116
456
  peerDeviceId: devices.host,
117
457
  });
458
+ if (folder.kind === 'git' && owner === 'vm') {
459
+ await ensureHome();
460
+ await ensureHost();
461
+ }
462
+ else {
463
+ await ensureHost();
464
+ await ensureHome();
465
+ }
118
466
  }
119
467
  await this.unpauseAll(remoteId, folders);
120
- await this.waitAll(run, folders, { sender: 'host', devices, symmetricCode: true });
468
+ await this.waitAll(run, folders, {
469
+ sender: (folder) => (folder.kind === 'git' && owner === 'home' ? 'home' : 'host'),
470
+ devices,
471
+ symmetricCode: true,
472
+ });
121
473
  }
122
474
  async flipToHome(run, projectId, force) {
123
475
  const { remoteId } = run.operation;
@@ -127,8 +479,25 @@ let FileSyncHandoff = class FileSyncHandoff {
127
479
  }
128
480
  await this.update('home', remoteId, folder.id, { type: 'sendonly', paused: true });
129
481
  }
482
+ if (force) {
483
+ await run.progress({
484
+ vmGuardSkipped: 'VM guard skipped: the forced Disconnect cannot reach the VM.',
485
+ });
486
+ }
487
+ else {
488
+ await run.progress({ vmGuardInstalled: true }, { durable: true });
489
+ const { warning } = await this.host.installGitGuard(remoteId, projectId, {
490
+ homeName: (0, node_os_1.hostname)(),
491
+ reason: 'disconnect',
492
+ });
493
+ await run.progress({ vmGuardWarning: warning, vmGuardInstalled: warning === null });
494
+ }
130
495
  await this.deleteHomeTempFiles(projectId);
131
- await this.guard.remove(projectId, { refreshIndex: true });
496
+ const { warning } = await this.guard.remove(projectId, {
497
+ refreshIndex: this.gitOwner.get(projectId) === 'vm',
498
+ });
499
+ if (warning)
500
+ await run.progress({ guardWarning: warning });
132
501
  }
133
502
  async removeFolders(remoteId, projectId) {
134
503
  const folders = (0, file_sync_service_1.projectFolderList)(projectId);
@@ -148,23 +517,38 @@ let FileSyncHandoff = class FileSyncHandoff {
148
517
  }
149
518
  }
150
519
  async flipBackToHost(remoteId, projectId, force) {
520
+ const owner = this.gitOwner.get(projectId);
151
521
  const folders = await this.fileSync.projectFolders(projectId);
152
- await this.hostDirections(remoteId, folders, force, false);
522
+ await this.hostDirections(remoteId, folders, owner, force, false);
153
523
  if (folders.some((folder) => folder.kind === 'git')) {
154
- const guardWarning = await this.guard.reinstall(projectId, remoteId);
524
+ const guardWarning = owner === 'vm'
525
+ ? await this.guard.reinstall(projectId, remoteId)
526
+ : force
527
+ ? null
528
+ : (await this.host.installGitGuard(remoteId, projectId, {
529
+ homeName: (0, node_os_1.hostname)(),
530
+ reason: 'pc-git',
531
+ })).warning;
155
532
  if (guardWarning) {
156
533
  logger.warn({ projectId, remoteId, guardWarning }, 'Remote git guard not reinstalled');
157
534
  }
158
535
  }
159
536
  }
160
- async hostDirections(remoteId, folders, force, paused) {
537
+ async hostDirections(remoteId, folders, owner, force, paused) {
161
538
  for (const folder of folders) {
162
539
  const pause = paused === undefined ? {} : { paused };
163
540
  if (folder.kind === 'git') {
164
541
  const ignores = (0, file_sync_dto_1.gitIgnores)(true);
165
- await this.update('home', remoteId, folder.id, { type: 'receiveonly', ignores, ...pause });
166
- if (!force)
167
- await this.update('host', remoteId, folder.id, { type: 'sendonly', ignores, ...pause });
542
+ const receiver = owner === 'vm' ? 'home' : 'host';
543
+ const sender = owner === 'vm' ? 'host' : 'home';
544
+ if (receiver === 'home' || !force)
545
+ await this.update(receiver, remoteId, folder.id, {
546
+ type: 'receiveonly',
547
+ ignores,
548
+ ...pause,
549
+ });
550
+ if (sender === 'home' || !force)
551
+ await this.update(sender, remoteId, folder.id, { type: 'sendonly', ignores, ...pause });
168
552
  }
169
553
  else {
170
554
  if (!force)
@@ -208,40 +592,77 @@ let FileSyncHandoff = class FileSyncHandoff {
208
592
  await this.update('home', remoteId, folder.id, { paused: false });
209
593
  }
210
594
  }
595
+ async waitHostIdle(remoteId, folderId, signal) {
596
+ const deadline = Date.now() + SYNC_TIMEOUT_MS;
597
+ for (;;) {
598
+ signal.throwIfAborted();
599
+ const status = await this.host.syncStatus(remoteId, folderId);
600
+ signal.throwIfAborted();
601
+ if (status.error || status.errors)
602
+ throw new file_sync_service_1.FileSyncTimeoutError(folderId, null, status.error ?? 'VM scan failed');
603
+ if (status.state === 'idle')
604
+ return;
605
+ if (Date.now() >= deadline)
606
+ throw new file_sync_service_1.FileSyncTimeoutError(folderId, null, 'The VM scan did not become idle.');
607
+ await sleep(POLL_MS);
608
+ }
609
+ }
211
610
  async waitAll(run, folders, options) {
212
611
  const { remoteId } = run.operation;
213
- const receiver = options.sender === 'home' ? 'host' : 'home';
214
- const receiverDevice = receiver === 'home' ? options.devices.home : options.devices.host;
215
612
  const progress = {};
216
613
  const report = () => run.progress({ fileSync: { folders: { ...progress } } });
217
614
  for (const folder of folders) {
218
615
  progress[folder.id] = { completion: 0, needItems: 0, needBytes: 0 };
219
616
  }
220
617
  await report();
221
- await Promise.all(folders.map(async (folder) => {
222
- const symmetric = options.symmetricCode === true && folder.kind === 'code';
223
- await Promise.all([
224
- this.scan(options.sender, remoteId, folder.id, options.signal),
225
- ...(symmetric ? [this.scan(receiver, remoteId, folder.id)] : []),
226
- ]);
227
- progress[folder.id] = await this.fileSync.waitForComplete(folder.id, {
228
- symmetric,
229
- sender: () => this.status(options.sender, remoteId, folder.id, receiverDevice),
230
- receiver: async () => {
231
- const status = await this.status(receiver, remoteId, folder.id, symmetric ? options.devices[options.sender] : undefined);
232
- if (!symmetric && status.receiveOnlyChangedFiles > 0 && status.state === 'idle') {
233
- await this.revert(receiver, remoteId, folder.id);
234
- }
235
- return status;
236
- },
237
- timeoutMs: SYNC_TIMEOUT_MS,
238
- onProgress: (current) => {
239
- progress[folder.id] = current;
240
- void report();
241
- },
242
- signal: options.signal,
243
- });
618
+ const stop = new AbortController();
619
+ const signal = options.signal ? AbortSignal.any([options.signal, stop.signal]) : stop.signal;
620
+ await Promise.allSettled(folders.map(async (folder) => {
621
+ try {
622
+ const sender = typeof options.sender === 'function' ? options.sender(folder) : options.sender;
623
+ const receiver = sender === 'home' ? 'host' : 'home';
624
+ const receiverDevice = options.devices[receiver];
625
+ const symmetric = options.symmetricCode === true && folder.kind === 'code';
626
+ await Promise.all([
627
+ this.scan(sender, remoteId, folder.id, options.signal),
628
+ ...(symmetric ? [this.scan(receiver, remoteId, folder.id)] : []),
629
+ ]);
630
+ progress[folder.id] = await this.fileSync.waitForComplete(folder.id, {
631
+ symmetric,
632
+ requireNoReceiveOnlyChanges: options.requireNoReceiveOnlyChanges,
633
+ sender: () => this.status(sender, remoteId, folder.id, receiverDevice),
634
+ receiver: async () => {
635
+ const status = await this.status(receiver, remoteId, folder.id, symmetric ? options.devices[sender] : undefined);
636
+ if (!symmetric && status.receiveOnlyChangedFiles > 0) {
637
+ signal.throwIfAborted();
638
+ const source = await this.status(sender, remoteId, folder.id, options.revertAfterComplete ? receiverDevice : undefined);
639
+ signal.throwIfAborted();
640
+ const transferred = (0, file_sync_service_1.senderIndexReached)(source, status) &&
641
+ source.peer?.completion === 100 &&
642
+ source.peer.needItems === 0 &&
643
+ source.peer.remoteState === 'valid' &&
644
+ status.needTotalItems === 0;
645
+ if (options.revertAfterComplete ? transferred : (0, file_sync_service_1.senderIndexReached)(source, status))
646
+ await this.revert(receiver, remoteId, folder.id);
647
+ }
648
+ return status;
649
+ },
650
+ timeoutMs: SYNC_TIMEOUT_MS,
651
+ sides: { sender: SIDE_NAMES[sender], receiver: SIDE_NAMES[receiver] },
652
+ onProgress: (current) => {
653
+ progress[folder.id] = current;
654
+ void report();
655
+ },
656
+ signal,
657
+ });
658
+ }
659
+ catch (error) {
660
+ stop.abort(error);
661
+ throw error;
662
+ }
244
663
  }));
664
+ if (stop.signal.aborted)
665
+ throw stop.signal.reason;
245
666
  await report();
246
667
  }
247
668
  async update(side, remoteId, folderId, patch) {
@@ -258,7 +679,11 @@ let FileSyncHandoff = class FileSyncHandoff {
258
679
  throw error;
259
680
  }
260
681
  }
261
- status(side, remoteId, folderId, peerDeviceId) {
682
+ status(side, remoteId, folderId, peerDeviceId, options) {
683
+ if (options)
684
+ return side === 'home'
685
+ ? this.fileSync.status(folderId, peerDeviceId, options)
686
+ : this.host.syncStatus(remoteId, folderId, peerDeviceId, options);
262
687
  return side === 'home'
263
688
  ? this.fileSync.status(folderId, peerDeviceId)
264
689
  : this.host.syncStatus(remoteId, folderId, peerDeviceId);
@@ -280,7 +705,9 @@ exports.FileSyncHandoff = FileSyncHandoff = __decorate([
280
705
  __metadata("design:paramtypes", [file_sync_service_1.FileSyncService,
281
706
  remote_host_client_1.RemoteHostClient,
282
707
  file_sync_managed_exclusions_store_1.FileSyncManagedExclusionsStore,
283
- home_git_guard_service_1.HomeGitGuardService])
708
+ home_git_guard_service_1.HomeGitGuardService,
709
+ process_executor_port_1.ProcessExecutor,
710
+ git_owner_store_1.GitOwnerStore])
284
711
  ], FileSyncHandoff);
285
712
  function sleep(ms) {
286
713
  return new Promise((resolve) => setTimeout(resolve, ms));