remo-cli 2.2.0rc9__tar.gz → 2.2.0rc11__tar.gz

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 (440) hide show
  1. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/PKG-INFO +1 -1
  2. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/web-session-interface.md +6 -2
  3. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/package-lock.json +46 -0
  4. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/package.json +1 -0
  5. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/TerminalCard.css +40 -6
  6. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/TerminalCard.tsx +64 -34
  7. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/WorkspacePane.tsx +94 -60
  8. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/pyproject.toml +1 -1
  9. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/uv.lock +1 -1
  10. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-analyze/SKILL.md +0 -0
  11. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-checklist/SKILL.md +0 -0
  12. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-clarify/SKILL.md +0 -0
  13. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-constitution/SKILL.md +0 -0
  14. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-converge/SKILL.md +0 -0
  15. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-git-commit/SKILL.md +0 -0
  16. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-git-feature/SKILL.md +0 -0
  17. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-git-initialize/SKILL.md +0 -0
  18. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-git-remote/SKILL.md +0 -0
  19. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-git-validate/SKILL.md +0 -0
  20. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-implement/SKILL.md +0 -0
  21. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-plan/SKILL.md +0 -0
  22. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-specify/SKILL.md +0 -0
  23. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-tasks/SKILL.md +0 -0
  24. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
  25. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.devcontainer/devcontainer.json +0 -0
  26. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.dockerignore +0 -0
  27. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/dependabot.yml +0 -0
  28. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/ci.yml +0 -0
  29. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/provision.yml +0 -0
  30. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/release.yml +0 -0
  31. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/smoke-test-cleanup.yml +0 -0
  32. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/smoke-test.yml +0 -0
  33. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.github/workflows/teardown.yml +0 -0
  34. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.gitignore +0 -0
  35. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.maverick/checkpoints/feature/implementation_complete.json +0 -0
  36. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.maverick/checkpoints/feature/phase_${{ index }}_complete.json +0 -0
  37. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.maverick/checkpoints/feature/validation_complete.json +0 -0
  38. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/.registry +0 -0
  39. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/README.md +0 -0
  40. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/commands/speckit.git.commit.md +0 -0
  41. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/commands/speckit.git.feature.md +0 -0
  42. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/commands/speckit.git.initialize.md +0 -0
  43. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/commands/speckit.git.remote.md +0 -0
  44. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/commands/speckit.git.validate.md +0 -0
  45. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/config-template.yml +0 -0
  46. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/extension.yml +0 -0
  47. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/git-config.yml +0 -0
  48. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/bash/auto-commit.sh +0 -0
  49. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/bash/create-new-feature.sh +0 -0
  50. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/bash/git-common.sh +0 -0
  51. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/bash/initialize-repo.sh +0 -0
  52. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
  53. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/powershell/create-new-feature.ps1 +0 -0
  54. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/powershell/git-common.ps1 +0 -0
  55. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
  56. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/extensions.yml +0 -0
  57. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/feature.json +0 -0
  58. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/init-options.json +0 -0
  59. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/integration.json +0 -0
  60. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/integrations/claude.manifest.json +0 -0
  61. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/integrations/speckit.manifest.json +0 -0
  62. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/memory/constitution.md +0 -0
  63. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/check-prerequisites.sh +0 -0
  64. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/common.sh +0 -0
  65. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/create-new-feature.sh +0 -0
  66. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/setup-plan.sh +0 -0
  67. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/setup-tasks.sh +0 -0
  68. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/scripts/bash/update-agent-context.sh +0 -0
  69. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/agent-file-template.md +0 -0
  70. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/checklist-template.md +0 -0
  71. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/constitution-template.md +0 -0
  72. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/plan-template.md +0 -0
  73. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/spec-template.md +0 -0
  74. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/templates/tasks-template.md +0 -0
  75. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/workflows/speckit/workflow.yml +0 -0
  76. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/.specify/workflows/workflow-registry.json +0 -0
  77. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/AGENTS.md +0 -0
  78. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/CLAUDE.md +0 -0
  79. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/CONTRIBUTING.md +0 -0
  80. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/Dockerfile +0 -0
  81. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/LICENSE +0 -0
  82. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/README.md +0 -0
  83. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/.ansible-lint +0 -0
  84. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/README.md +0 -0
  85. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/ansible.cfg +0 -0
  86. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/aws_configure.yml +0 -0
  87. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/aws_resize.yml +0 -0
  88. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/aws_site.yml +0 -0
  89. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/aws_teardown.yml +0 -0
  90. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/group_vars/all.yml +0 -0
  91. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/group_vars/incus_containers.yml +0 -0
  92. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/group_vars/proxmox_containers.yml +0 -0
  93. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/hetzner_configure.yml +0 -0
  94. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/hetzner_provision.yml +0 -0
  95. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/hetzner_resize.yml +0 -0
  96. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/hetzner_site.yml +0 -0
  97. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/hetzner_teardown.yml +0 -0
  98. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_bootstrap.yml +0 -0
  99. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_configure.yml +0 -0
  100. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_provision.yml +0 -0
  101. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_resize.yml +0 -0
  102. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_site.yml +0 -0
  103. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/incus_teardown.yml +0 -0
  104. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/inventory/hosts.yml +0 -0
  105. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/inventory/incus_containers.yml +0 -0
  106. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_bootstrap.yml +0 -0
  107. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_configure.yml +0 -0
  108. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_provision.yml +0 -0
  109. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_resize.yml +0 -0
  110. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_site.yml +0 -0
  111. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/proxmox_teardown.yml +0 -0
  112. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/requirements.yml +0 -0
  113. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/defaults/main.yml +0 -0
  114. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/ebs.yml +0 -0
  115. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/ec2.yml +0 -0
  116. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/main.yml +0 -0
  117. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/patch_manager.yml +0 -0
  118. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/preflight.yml +0 -0
  119. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/aws_server/tasks/security_group.yml +0 -0
  120. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/deacon/defaults/main.yml +0 -0
  121. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/deacon/tasks/main.yml +0 -0
  122. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/devcontainers/tasks/main.yml +0 -0
  123. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/docker/handlers/main.yml +0 -0
  124. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/docker/tasks/main.yml +0 -0
  125. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/fzf/tasks/main.yml +0 -0
  126. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/github_cli/tasks/main.yml +0 -0
  127. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/hetzner_server/defaults/main.yml +0 -0
  128. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/hetzner_server/tasks/main.yml +0 -0
  129. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_bootstrap/defaults/main.yml +0 -0
  130. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_bootstrap/handlers/main.yml +0 -0
  131. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_bootstrap/tasks/main.yml +0 -0
  132. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container/defaults/main.yml +0 -0
  133. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container/handlers/main.yml +0 -0
  134. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container/meta/main.yml +0 -0
  135. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container/tasks/main.yml +0 -0
  136. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container/tasks/preflight.yml +0 -0
  137. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container_teardown/defaults/main.yml +0 -0
  138. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container_teardown/meta/main.yml +0 -0
  139. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/incus_container_teardown/tasks/main.yml +0 -0
  140. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/nodejs/defaults/main.yml +0 -0
  141. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/nodejs/tasks/main.yml +0 -0
  142. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_bootstrap/defaults/main.yml +0 -0
  143. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_bootstrap/meta/main.yml +0 -0
  144. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_bootstrap/tasks/main.yml +0 -0
  145. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container/defaults/main.yml +0 -0
  146. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container/handlers/main.yml +0 -0
  147. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container/meta/main.yml +0 -0
  148. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container/tasks/main.yml +0 -0
  149. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container/tasks/preflight.yml +0 -0
  150. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container_teardown/defaults/main.yml +0 -0
  151. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container_teardown/meta/main.yml +0 -0
  152. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/proxmox_container_teardown/tasks/main.yml +0 -0
  153. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/defaults/main.yml +0 -0
  154. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/tasks/main.yml +0 -0
  155. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/templates/devshell.sh.j2 +0 -0
  156. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/templates/project-launch.sh.j2 +0 -0
  157. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/templates/project-menu.sh.j2 +0 -0
  158. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/user_setup/templates/remo-host.sh.j2 +0 -0
  159. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/zellij/defaults/main.yml +0 -0
  160. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/zellij/tasks/main.yml +0 -0
  161. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/zellij/templates/config.kdl.j2 +0 -0
  162. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/roles/zellij/templates/layouts/minimal.kdl.j2 +0 -0
  163. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/ansible/tasks/configure_dev_tools.yml +0 -0
  164. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docker/Dockerfile +0 -0
  165. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docker/compose.example.yml +0 -0
  166. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docker/entrypoint.sh +0 -0
  167. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/aws.md +0 -0
  168. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/hetzner.md +0 -0
  169. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/incus.md +0 -0
  170. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/install.sh +0 -0
  171. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/proxmox.md +0 -0
  172. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/remo-web-speckit-input.md +0 -0
  173. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/docs/remo-web.html +0 -0
  174. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/index.html +0 -0
  175. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/public/README.md +0 -0
  176. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/public/dist__ghostty-vt.wasm +0 -0
  177. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/public/ghostty-vt.wasm +0 -0
  178. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/scripts/copy-ghostty-wasm.mjs +0 -0
  179. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/api/client.ts +0 -0
  180. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/AppRoot.tsx +0 -0
  181. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/AppShell.css +0 -0
  182. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/AppShell.tsx +0 -0
  183. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/AwaitingAdoption.css +0 -0
  184. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/AwaitingAdoption.tsx +0 -0
  185. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/OfflineOverlay.css +0 -0
  186. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/OfflineOverlay.tsx +0 -0
  187. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/PairToSync.css +0 -0
  188. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/PairToSync.tsx +0 -0
  189. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/SessionRail.css +0 -0
  190. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/SessionRail.tsx +0 -0
  191. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/SettingsPage.css +0 -0
  192. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/SettingsPage.tsx +0 -0
  193. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/ShortcutsModal.css +0 -0
  194. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/ShortcutsModal.tsx +0 -0
  195. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/TopBar.css +0 -0
  196. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/TopBar.tsx +0 -0
  197. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/WorkspacePane.css +0 -0
  198. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/providerMeta.ts +0 -0
  199. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/components/railModel.ts +0 -0
  200. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/lib/clipboard.ts +0 -0
  201. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/lib/fullscreen.ts +0 -0
  202. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/main.tsx +0 -0
  203. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/discovery.ts +0 -0
  204. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/fonts.ts +0 -0
  205. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/health.ts +0 -0
  206. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/settings.ts +0 -0
  207. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/useConsoleKeyboard.ts +0 -0
  208. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/workspace.test.ts +0 -0
  209. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/state/workspace.ts +0 -0
  210. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/.gitkeep +0 -0
  211. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/GhosttyRenderer.ts +0 -0
  212. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/RendererAdapter.ts +0 -0
  213. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/TerminalConnection.test.ts +0 -0
  214. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/TerminalConnection.ts +0 -0
  215. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/XtermRenderer.ts +0 -0
  216. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/defaultRenderer.ts +0 -0
  217. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/keymap.test.ts +0 -0
  218. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/terminal/keymap.ts +0 -0
  219. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/test/setup.ts +0 -0
  220. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/theme/fonts.ts +0 -0
  221. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/src/theme/tokens.css +0 -0
  222. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/tsconfig.json +0 -0
  223. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/frontend/vite.config.ts +0 -0
  224. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/install.sh +0 -0
  225. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/maverick.yaml +0 -0
  226. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/playwright.config.ts +0 -0
  227. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/project-menu.sh +0 -0
  228. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/remo +0 -0
  229. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/run.sh +0 -0
  230. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/scripts/setup-aws-oidc.sh +0 -0
  231. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/checklists/requirements.md +0 -0
  232. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/checklists/validation.md +0 -0
  233. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/contracts/playbook-interface.yaml +0 -0
  234. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/contracts/role-interface.yaml +0 -0
  235. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/data-model.md +0 -0
  236. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/plan.md +0 -0
  237. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/quickstart.md +0 -0
  238. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/research.md +0 -0
  239. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/spec.md +0 -0
  240. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/001-bootstrap-incus-host/tasks.md +0 -0
  241. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/checklists/requirements.md +0 -0
  242. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/contracts/playbook-interface.yaml +0 -0
  243. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/contracts/role-interface.yaml +0 -0
  244. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/data-model.md +0 -0
  245. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/plan.md +0 -0
  246. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/quickstart.md +0 -0
  247. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/research.md +0 -0
  248. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/spec.md +0 -0
  249. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/002-incus-container-support/tasks.md +0 -0
  250. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/checklists/requirements.md +0 -0
  251. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/data-model.md +0 -0
  252. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/plan.md +0 -0
  253. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/quickstart.md +0 -0
  254. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/research.md +0 -0
  255. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/spec.md +0 -0
  256. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/003-python-cli-rewrite/tasks.md +0 -0
  257. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/004-proxmox-container-support/spec.md +0 -0
  258. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/checklists/requirements.md +0 -0
  259. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/contracts/cli-surface.md +0 -0
  260. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/data-model.md +0 -0
  261. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/plan.md +0 -0
  262. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/quickstart.md +0 -0
  263. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/research.md +0 -0
  264. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/spec.md +0 -0
  265. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/005-provider-snapshots/tasks.md +0 -0
  266. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/checklists/requirements.md +0 -0
  267. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/contracts/remo-host-protocol.md +0 -0
  268. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/contracts/rest-api.md +0 -0
  269. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/contracts/terminal-websocket.md +0 -0
  270. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/data-model.md +0 -0
  271. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/plan.md +0 -0
  272. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/quickstart.md +0 -0
  273. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/research.md +0 -0
  274. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/spec.md +0 -0
  275. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/010-web-session-interface/tasks.md +0 -0
  276. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/checklists/requirements.md +0 -0
  277. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/contracts/cli-web-adopt.md +0 -0
  278. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/contracts/setup-api.md +0 -0
  279. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/data-model.md +0 -0
  280. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/plan.md +0 -0
  281. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/quickstart-results.md +0 -0
  282. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/quickstart.md +0 -0
  283. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/research.md +0 -0
  284. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/spec.md +0 -0
  285. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/011-web-adopt/tasks.md +0 -0
  286. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/contracts/cli-web-adopt.md +0 -0
  287. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/contracts/pairing-api.md +0 -0
  288. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/contracts/setup-api.md +0 -0
  289. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/data-model.md +0 -0
  290. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/plan.md +0 -0
  291. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/quickstart.md +0 -0
  292. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/research.md +0 -0
  293. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/spec.md +0 -0
  294. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/specs/012-web-adopt-pairing/tasks.md +0 -0
  295. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/__init__.py +0 -0
  296. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/__main__.py +0 -0
  297. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/__init__.py +0 -0
  298. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/cp.py +0 -0
  299. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/main.py +0 -0
  300. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/providers/__init__.py +0 -0
  301. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/providers/aws.py +0 -0
  302. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/providers/hetzner.py +0 -0
  303. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/providers/incus.py +0 -0
  304. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/providers/proxmox.py +0 -0
  305. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/shell.py +0 -0
  306. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/cli/web.py +0 -0
  307. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/__init__.py +0 -0
  308. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/ansible_runner.py +0 -0
  309. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/completion.py +0 -0
  310. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/config.py +0 -0
  311. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/known_hosts.py +0 -0
  312. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/output.py +0 -0
  313. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/picker.py +0 -0
  314. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/remo_host_client.py +0 -0
  315. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/rsync.py +0 -0
  316. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/snapshot.py +0 -0
  317. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/ssh.py +0 -0
  318. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/validation.py +0 -0
  319. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/version.py +0 -0
  320. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/core/web_adopt.py +0 -0
  321. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/__init__.py +0 -0
  322. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/capability.py +0 -0
  323. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/discovery.py +0 -0
  324. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/host.py +0 -0
  325. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/session_target.py +0 -0
  326. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/models/snapshot.py +0 -0
  327. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/providers/__init__.py +0 -0
  328. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/providers/aws.py +0 -0
  329. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/providers/hetzner.py +0 -0
  330. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/providers/incus.py +0 -0
  331. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/providers/proxmox.py +0 -0
  332. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/__init__.py +0 -0
  333. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/api/__init__.py +0 -0
  334. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/api/hosts.py +0 -0
  335. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/api/pairing.py +0 -0
  336. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/api/setup.py +0 -0
  337. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/api/terminals.py +0 -0
  338. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/app.py +0 -0
  339. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/check.py +0 -0
  340. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/config.py +0 -0
  341. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/discovery.py +0 -0
  342. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/health.py +0 -0
  343. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/logging_config.py +0 -0
  344. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/models.py +0 -0
  345. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/operator_auth.py +0 -0
  346. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/pairing.py +0 -0
  347. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/ssh_master.py +0 -0
  348. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/state.py +0 -0
  349. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/terminal.py +0 -0
  350. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/terminal_registry.py +0 -0
  351. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/src/remo_cli/web/tokens.py +0 -0
  352. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/__init__.py +0 -0
  353. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/ansible/__init__.py +0 -0
  354. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/ansible/test_remo_host_idempotency.py +0 -0
  355. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/conftest.py +0 -0
  356. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/fixtures.ts +0 -0
  357. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/ghostty-shell-io.spec.ts +0 -0
  358. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/ghostty-tui-compatibility.spec.ts +0 -0
  359. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/keyboard-routing.spec.ts +0 -0
  360. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/mobile.spec.ts +0 -0
  361. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/reconnect.spec.ts +0 -0
  362. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/e2e/workspace-layout.spec.ts +0 -0
  363. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/image/__init__.py +0 -0
  364. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/image/test_docker_image.py +0 -0
  365. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/__init__.py +0 -0
  366. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/_nine_terminal_fixture.py +0 -0
  367. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/orbstack-cloud-init.yml +0 -0
  368. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/orbstack.sh +0 -0
  369. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_nine_terminals.py +0 -0
  370. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_nine_terminals_soak.py +0 -0
  371. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_remo_host_e2e.py +0 -0
  372. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_security_rejections.py +0 -0
  373. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_terminal_attach.py +0 -0
  374. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_web_adopt_e2e.py +0 -0
  375. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/integration/test_web_cli_parity.py +0 -0
  376. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/perf/__init__.py +0 -0
  377. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/perf/test_latency.py +0 -0
  378. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/__init__.py +0 -0
  379. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/__init__.py +0 -0
  380. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/providers/test_aws_snapshot.py +0 -0
  381. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/providers/test_hetzner_snapshot.py +0 -0
  382. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/providers/test_incus_snapshot.py +0 -0
  383. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/providers/test_proxmox_snapshot.py +0 -0
  384. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/test_cp.py +0 -0
  385. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/test_main.py +0 -0
  386. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/test_shell.py +0 -0
  387. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/cli/test_web_adopt_cmd.py +0 -0
  388. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/__init__.py +0 -0
  389. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_ansible_runner.py +0 -0
  390. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_config.py +0 -0
  391. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_known_hosts.py +0 -0
  392. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_output.py +0 -0
  393. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_picker.py +0 -0
  394. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_remo_host_client.py +0 -0
  395. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_rsync.py +0 -0
  396. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_snapshot.py +0 -0
  397. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_ssh.py +0 -0
  398. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_ssh_controlpath.py +0 -0
  399. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_ssh_identity_opts.py +0 -0
  400. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_validation.py +0 -0
  401. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_version.py +0 -0
  402. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_web_adopt_authorize.py +0 -0
  403. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_web_adopt_code.py +0 -0
  404. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_web_adopt_payload.py +0 -0
  405. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_web_adopt_trust.py +0 -0
  406. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/core/test_web_push.py +0 -0
  407. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/models/__init__.py +0 -0
  408. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/models/test_capability.py +0 -0
  409. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/models/test_discovery.py +0 -0
  410. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/models/test_session_target.py +0 -0
  411. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/__init__.py +0 -0
  412. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/test_aws_snapshot.py +0 -0
  413. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/test_hetzner_snapshot.py +0 -0
  414. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/test_incus_snapshot.py +0 -0
  415. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/test_proxmox_devcontainer_runtime.py +0 -0
  416. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/providers/test_proxmox_snapshot.py +0 -0
  417. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/test_ansible_templates.py +0 -0
  418. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/test_host_model.py +0 -0
  419. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/__init__.py +0 -0
  420. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/_pairing_support.py +0 -0
  421. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/conftest.py +0 -0
  422. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_backpressure.py +0 -0
  423. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_check.py +0 -0
  424. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_csp.py +0 -0
  425. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_discovery.py +0 -0
  426. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_health_states.py +0 -0
  427. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_hosts_mapping.py +0 -0
  428. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_lazy_import.py +0 -0
  429. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_log_redaction.py +0 -0
  430. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_mint_gating.py +0 -0
  431. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_operator_auth.py +0 -0
  432. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_pairing.py +0 -0
  433. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_pairing_origin.py +0 -0
  434. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_setup_api.py +0 -0
  435. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_setup_auth.py +0 -0
  436. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_setup_dormancy.py +0 -0
  437. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_state.py +0 -0
  438. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_terminal_resize.py +0 -0
  439. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_terminals_api.py +0 -0
  440. {remo_cli-2.2.0rc9 → remo_cli-2.2.0rc11}/tests/unit/web/test_tokens.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: remo-cli
3
- Version: 2.2.0rc9
3
+ Version: 2.2.0rc11
4
4
  Summary: Remote development environment CLI
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -100,8 +100,12 @@ The SPA is a two-pane **web console**:
100
100
  target as a grid.
101
101
  - **Terminal pane** (right). Clicking a row opens that target **solo** (single view); ⌘/Ctrl-click a
102
102
  row (or its `+` button) **adds** it to a responsive grid (1/2/3 columns by count). In a grid, **drag
103
- a tile's header onto another to swap their positions** (the arrangement persists until the grid is
104
- rebuilt); the **◻** control solos a tile; **Esc** collapses the grid back to the focused terminal;
103
+ a tile's header onto another to swap their positions** a window outline follows the cursor and the
104
+ swap target shows a dashed outline (mouse or touch press-and-hold; keyboard-accessible via the
105
+ handle); the arrangement persists until the grid is rebuilt. In a grid, **resting the pointer on a
106
+ tile focuses it** (focus-follows-mouse, with a short dwell so passing through tiles doesn't steal
107
+ focus) — keystrokes go where the pointer is, no click needed. The **◻** control solos a tile; **Esc**
108
+ collapses the grid back to the focused terminal;
105
109
  number keys **1–9** jump to the numbered sessions (⌘ 1–9 add to the grid). Hidden terminals stay
106
110
  connected and keep their scrollback. Each terminal header shows `provider · instance · region`
107
111
  (doubling as the drag handle), connection state, and a
@@ -8,6 +8,7 @@
8
8
  "name": "remo-web-frontend",
9
9
  "version": "0.0.0",
10
10
  "dependencies": {
11
+ "@dnd-kit/core": "^6.3.1",
11
12
  "@fontsource/fira-code": "^5.2.7",
12
13
  "@fontsource/ibm-plex-mono": "^5.2.7",
13
14
  "@fontsource/jetbrains-mono": "^5.2.8",
@@ -559,6 +560,45 @@
559
560
  "node": ">=20.19.0"
560
561
  }
561
562
  },
563
+ "node_modules/@dnd-kit/accessibility": {
564
+ "version": "3.1.1",
565
+ "resolved": "https://registry.npmjs.org/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz",
566
+ "integrity": "sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==",
567
+ "license": "MIT",
568
+ "dependencies": {
569
+ "tslib": "^2.0.0"
570
+ },
571
+ "peerDependencies": {
572
+ "react": ">=16.8.0"
573
+ }
574
+ },
575
+ "node_modules/@dnd-kit/core": {
576
+ "version": "6.3.1",
577
+ "resolved": "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz",
578
+ "integrity": "sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==",
579
+ "license": "MIT",
580
+ "dependencies": {
581
+ "@dnd-kit/accessibility": "^3.1.1",
582
+ "@dnd-kit/utilities": "^3.2.2",
583
+ "tslib": "^2.0.0"
584
+ },
585
+ "peerDependencies": {
586
+ "react": ">=16.8.0",
587
+ "react-dom": ">=16.8.0"
588
+ }
589
+ },
590
+ "node_modules/@dnd-kit/utilities": {
591
+ "version": "3.2.2",
592
+ "resolved": "https://registry.npmjs.org/@dnd-kit/utilities/-/utilities-3.2.2.tgz",
593
+ "integrity": "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==",
594
+ "license": "MIT",
595
+ "dependencies": {
596
+ "tslib": "^2.0.0"
597
+ },
598
+ "peerDependencies": {
599
+ "react": ">=16.8.0"
600
+ }
601
+ },
562
602
  "node_modules/@esbuild/aix-ppc64": {
563
603
  "version": "0.21.5",
564
604
  "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -3462,6 +3502,12 @@
3462
3502
  "node": ">=20"
3463
3503
  }
3464
3504
  },
3505
+ "node_modules/tslib": {
3506
+ "version": "2.8.1",
3507
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
3508
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
3509
+ "license": "0BSD"
3510
+ },
3465
3511
  "node_modules/typescript": {
3466
3512
  "version": "5.9.3",
3467
3513
  "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
@@ -15,6 +15,7 @@
15
15
  "test:e2e": "playwright test --config ../playwright.config.ts"
16
16
  },
17
17
  "dependencies": {
18
+ "@dnd-kit/core": "^6.3.1",
18
19
  "@fontsource/fira-code": "^5.2.7",
19
20
  "@fontsource/ibm-plex-mono": "^5.2.7",
20
21
  "@fontsource/jetbrains-mono": "^5.2.8",
@@ -53,20 +53,54 @@
53
53
  .terminal-card--grid .terminal-card-grip {
54
54
  gap: 8px;
55
55
  }
56
- .terminal-card-grip[draggable="true"] {
56
+ .terminal-card-grip--handle {
57
57
  cursor: grab;
58
+ touch-action: none; /* let the TouchSensor own press-and-hold drags */
58
59
  }
59
- .terminal-card-grip[draggable="true"]:active {
60
+ .terminal-card-grip--handle:active {
60
61
  cursor: grabbing;
61
62
  }
62
63
 
63
- /* Reorder drag feedback. */
64
+ /* Reorder drag feedback. The source tile dims; the tile the drop will land on
65
+ * (swap target) gets a bold dashed outline showing where the window will go. */
64
66
  .terminal-card--dragging {
65
- opacity: 0.5;
67
+ opacity: 0.4;
66
68
  }
67
69
  .terminal-card--drop-target {
68
- border-color: color-mix(in oklch, var(--accent) 65%, var(--border));
69
- box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 22%, transparent);
70
+ outline: 2px dashed color-mix(in oklch, var(--accent) 85%, white);
71
+ outline-offset: -3px;
72
+ background: color-mix(in oklch, var(--accent) 12%, var(--bg-term));
73
+ }
74
+
75
+ /* The floating window-outline ghost rendered in the dnd-kit DragOverlay while
76
+ * dragging. Fills the overlay box (sized to the dragged tile), so it reads as
77
+ * the window itself following the cursor. */
78
+ .terminal-drag-ghost {
79
+ width: 100%;
80
+ height: 100%;
81
+ box-sizing: border-box;
82
+ display: flex;
83
+ align-items: flex-start;
84
+ border-radius: var(--radius-lg);
85
+ border: 2px dashed color-mix(in oklch, var(--accent) 80%, white);
86
+ background: color-mix(in oklch, var(--accent) 16%, transparent);
87
+ box-shadow: 0 12px 30px oklch(0 0 0 / 0.35);
88
+ cursor: grabbing;
89
+ overflow: hidden;
90
+ }
91
+ .terminal-drag-ghost-title {
92
+ margin: 8px 12px;
93
+ padding: 3px 10px;
94
+ font-family: var(--font-mono);
95
+ font-weight: 600;
96
+ font-size: 12px;
97
+ color: var(--text);
98
+ background: color-mix(in oklch, var(--bg-header) 85%, transparent);
99
+ border-radius: 6px;
100
+ white-space: nowrap;
101
+ overflow: hidden;
102
+ text-overflow: ellipsis;
103
+ max-width: calc(100% - 24px);
70
104
  }
71
105
 
72
106
  .terminal-card-provider-dot {
@@ -10,6 +10,7 @@
10
10
  // terminal surface (which would tear down the live connection).
11
11
 
12
12
  import { useCallback, useEffect, useRef, useState } from "react";
13
+ import { useDraggable, useDroppable } from "@dnd-kit/core";
13
14
  import type { SessionTarget, TypedError } from "../api/client";
14
15
  import { providerMeta } from "./providerMeta";
15
16
  import {
@@ -27,6 +28,9 @@ const DEFAULT_COLS = 80;
27
28
  const DEFAULT_ROWS = 24;
28
29
  /** How much to shrink the terminal font in a grid tile when "scale to fit". */
29
30
  const GRID_FIT_SCALE = 0.8;
31
+ /** Focus-follows-mouse dwell: the pointer must REST on a tile this long before
32
+ * it takes focus, so passing through tiles (or a small drift) doesn't steal it. */
33
+ const HOVER_FOCUS_DELAY_MS = 220;
30
34
 
31
35
  const STATE_LABELS: Record<TerminalConnectionState, string> = {
32
36
  connecting: "Connecting…",
@@ -42,18 +46,6 @@ export type TerminalCardMode = "single" | "grid";
42
46
  * Drives the window-control cluster's active/disabled state. */
43
47
  export type TerminalViewState = "normal" | "grid" | "fullscreen";
44
48
 
45
- /** Drag-to-reorder wiring for a grid tile. Present only when reordering is
46
- * possible (a grid of two-plus); the header acts as the drag handle and the
47
- * whole tile is a drop target — dropping swaps the two tiles' positions. */
48
- export interface TerminalReorder {
49
- isDragging: boolean;
50
- isDropTarget: boolean;
51
- onDragStart: () => void;
52
- onDragEnter: () => void;
53
- onDrop: () => void;
54
- onDragEnd: () => void;
55
- }
56
-
57
49
  interface TerminalCardProps {
58
50
  target: SessionTarget;
59
51
  /** Registry region for this target's instance (badge only). */
@@ -66,8 +58,9 @@ interface TerminalCardProps {
66
58
  /** The display mode this card is currently in (window-control cluster state). */
67
59
  viewState: TerminalViewState;
68
60
  onClose: () => void;
69
- /** Drag-to-reorder wiring; present only for a reorderable grid tile. */
70
- reorder?: TerminalReorder;
61
+ /** When true, the header acts as a dnd-kit drag handle and the tile is a drop
62
+ * target (grid reorder). The DndContext + swap live in WorkspacePane. */
63
+ reorderEnabled?: boolean;
71
64
  /** Window-control "Normal": solo this terminal into the single view. */
72
65
  onNormal: () => void;
73
66
  /** Window-control "Grid": show the grid — omitted when none is available. */
@@ -76,6 +69,9 @@ interface TerminalCardProps {
76
69
  onToggleFullscreen: () => void;
77
70
  /** Called when the user clicks into the surface (focus this terminal). */
78
71
  onFocusRequest?: () => void;
72
+ /** Focus-follows-mouse: called when the pointer enters this tile (grid only),
73
+ * so hovering changes focus without a click. No-op'd mid-drag by the caller. */
74
+ onHoverFocus?: () => void;
79
75
  /** Called when output arrives while this card is hidden (rail activity dot). */
80
76
  onActivity?: () => void;
81
77
  /** Called when the remote process exits (session may have ended) or the
@@ -100,11 +96,12 @@ export function TerminalCard({
100
96
  isFocused,
101
97
  viewState,
102
98
  onClose,
103
- reorder,
99
+ reorderEnabled,
104
100
  onNormal,
105
101
  onGrid,
106
102
  onToggleFullscreen,
107
103
  onFocusRequest,
104
+ onHoverFocus,
108
105
  onActivity,
109
106
  onEnded,
110
107
  }: TerminalCardProps): JSX.Element {
@@ -125,11 +122,29 @@ export function TerminalCard({
125
122
  // (to skip redundant resize frames).
126
123
  const fitRafRef = useRef<number | null>(null);
127
124
  const lastSentDimsRef = useRef<{ cols: number; rows: number } | null>(null);
125
+ // Pending focus-follows-mouse dwell timer (cleared if the pointer leaves first).
126
+ const hoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
128
127
 
129
128
  const [connectionState, setConnectionState] = useState<TerminalConnectionState>("connecting");
130
129
  const [needsManualReconnect, setNeedsManualReconnect] = useState(false);
131
130
  const [error, setError] = useState<TypedError | null>(null);
132
131
 
132
+ // dnd-kit reorder: the tile is both a draggable (handle = header grip, below)
133
+ // and a droppable (swap target). Disabled outside a reorderable grid. We use
134
+ // the DragOverlay pattern (WorkspacePane), so the source stays put (dimmed)
135
+ // and we never apply `draggable.transform`.
136
+ const draggable = useDraggable({ id: target.id, disabled: !reorderEnabled });
137
+ const droppable = useDroppable({ id: target.id, disabled: !reorderEnabled });
138
+ const setDraggableRef = draggable.setNodeRef;
139
+ const setDroppableRef = droppable.setNodeRef;
140
+ const setTileRef = useCallback(
141
+ (node: HTMLDivElement | null) => {
142
+ setDraggableRef(node);
143
+ setDroppableRef(node);
144
+ },
145
+ [setDraggableRef, setDroppableRef],
146
+ );
147
+
133
148
  useEffect(() => {
134
149
  isFocusedRef.current = isFocused;
135
150
  }, [isFocused]);
@@ -296,41 +311,56 @@ export function TerminalCard({
296
311
  onFocusRequest?.();
297
312
  }, [onFocusRequest]);
298
313
 
314
+ const clearHoverTimer = useCallback(() => {
315
+ if (hoverTimerRef.current !== null) {
316
+ clearTimeout(hoverTimerRef.current);
317
+ hoverTimerRef.current = null;
318
+ }
319
+ }, []);
320
+
321
+ // Focus-follows-mouse with a dwell delay: arm a timer on enter, fire only if
322
+ // the pointer is still resting here after HOVER_FOCUS_DELAY_MS.
323
+ const handleMouseEnter = useCallback(() => {
324
+ if (!onHoverFocus) {
325
+ return;
326
+ }
327
+ clearHoverTimer();
328
+ hoverTimerRef.current = setTimeout(() => {
329
+ hoverTimerRef.current = null;
330
+ onHoverFocus();
331
+ }, HOVER_FOCUS_DELAY_MS);
332
+ }, [onHoverFocus, clearHoverTimer]);
333
+
334
+ // Cancel a pending dwell when the pointer leaves or the card unmounts.
335
+ useEffect(() => clearHoverTimer, [clearHoverTimer]);
336
+
299
337
  const prov = providerMeta(target.instance_type);
300
338
  const badge = [prov.label, target.instance_name, region].filter(Boolean).join(" · ");
301
339
 
302
- const dragClasses = reorder
303
- ? `${reorder.isDragging ? " terminal-card--dragging" : ""}${reorder.isDropTarget ? " terminal-card--drop-target" : ""}`
304
- : "";
340
+ const isDragging = draggable.isDragging;
341
+ // Highlight the tile the drop will land on (swap target) but not the source.
342
+ const isDropTarget = Boolean(reorderEnabled) && droppable.isOver && !isDragging;
343
+ const dragClasses = `${isDragging ? " terminal-card--dragging" : ""}${isDropTarget ? " terminal-card--drop-target" : ""}`;
305
344
 
306
345
  return (
307
346
  <div
347
+ ref={setTileRef}
308
348
  className={`terminal-card terminal-card--${mode}${isFocused ? " terminal-card--focused" : ""}${dragClasses}`}
309
349
  data-testid={`terminal-card-${target.id}`}
310
350
  data-focused={isFocused}
311
351
  data-connection-state={connectionState}
312
352
  style={{ display: isVisible ? undefined : "none" }}
313
- // Whole tile is the drop target for a reorder drag (see the header grip).
314
- onDragOver={reorder ? (e) => e.preventDefault() : undefined}
315
- onDragEnter={reorder ? (e) => { e.preventDefault(); reorder.onDragEnter(); } : undefined}
316
- onDrop={reorder ? (e) => { e.preventDefault(); reorder.onDrop(); } : undefined}
353
+ onMouseEnter={handleMouseEnter}
354
+ onMouseLeave={clearHoverTimer}
317
355
  >
318
356
  <header className="terminal-card-header">
319
357
  {/* The header (left of the controls) is the drag handle for reordering
320
358
  * grid tiles; it no longer solos on click — the ◻ control does that. */}
321
359
  <div
322
- className="terminal-card-grip"
323
- draggable={reorder ? true : undefined}
324
- onDragStart={
325
- reorder
326
- ? (e) => {
327
- e.dataTransfer.setData("text/plain", target.id);
328
- e.dataTransfer.effectAllowed = "move";
329
- reorder.onDragStart();
330
- }
331
- : undefined
332
- }
333
- onDragEnd={reorder ? () => reorder.onDragEnd() : undefined}
360
+ ref={reorderEnabled ? draggable.setActivatorNodeRef : undefined}
361
+ className={`terminal-card-grip${reorderEnabled ? " terminal-card-grip--handle" : ""}`}
362
+ {...(reorderEnabled ? draggable.listeners : {})}
363
+ {...(reorderEnabled ? draggable.attributes : {})}
334
364
  >
335
365
  <span className="terminal-card-provider-dot" style={{ background: prov.color }} />
336
366
  <div className="terminal-card-identity">
@@ -3,6 +3,18 @@
3
3
  // laid out as a single view (one visible) or a responsive grid (two-plus).
4
4
 
5
5
  import { useMemo, useState } from "react";
6
+ import {
7
+ DndContext,
8
+ DragOverlay,
9
+ KeyboardSensor,
10
+ PointerSensor,
11
+ TouchSensor,
12
+ closestCenter,
13
+ useSensor,
14
+ useSensors,
15
+ type DragEndEvent,
16
+ type DragStartEvent,
17
+ } from "@dnd-kit/core";
6
18
  import type { SessionTarget } from "../api/client";
7
19
  import { requestBrowserFullscreen } from "../lib/fullscreen";
8
20
  import { useWorkspace } from "../state/workspace";
@@ -46,10 +58,16 @@ export function WorkspacePane({
46
58
  const workspace = useWorkspace();
47
59
  const { attached, visible, focusedId, prevGrid, maximizedId } = workspace;
48
60
 
49
- // Transient drag-to-reorder state (which tile is being dragged, and which it's
50
- // hovering over). Not persisted — only the resulting order (`visible`) is.
51
- const [dragId, setDragId] = useState<string | null>(null);
52
- const [overId, setOverId] = useState<string | null>(null);
61
+ // dnd-kit reorder: `activeId` is the tile currently being dragged (drives the
62
+ // floating DragOverlay ghost). Only the resulting order (`visible`) persists.
63
+ const [activeId, setActiveId] = useState<string | null>(null);
64
+ const sensors = useSensors(
65
+ // A small move starts a drag, so plain clicks (buttons, focus) still work.
66
+ useSensor(PointerSensor, { activationConstraint: { distance: 6 } }),
67
+ // Touch: a short press-and-hold starts a drag, leaving taps/scroll intact.
68
+ useSensor(TouchSensor, { activationConstraint: { delay: 180, tolerance: 8 } }),
69
+ useSensor(KeyboardSensor),
70
+ );
53
71
 
54
72
  // Render visible tiles in `visible` order (so the grid layout follows the
55
73
  // reorderable order + the number badges), then the hidden-but-attached cards
@@ -111,69 +129,85 @@ export function WorkspacePane({
111
129
 
112
130
  // Reordering is possible only within a real grid (two-plus visible tiles).
113
131
  const reorderable = !maximized && mode === "grid" && visible.length > 1;
114
- const clearDrag = (): void => {
115
- setDragId(null);
116
- setOverId(null);
132
+ const activeTarget = activeId ? targetsById.get(activeId) : undefined;
133
+
134
+ const onDragStart = (e: DragStartEvent): void => setActiveId(String(e.active.id));
135
+ const onDragEnd = (e: DragEndEvent): void => {
136
+ const { active, over } = e;
137
+ setActiveId(null);
138
+ if (over && active.id !== over.id) {
139
+ workspace.swapVisible(String(active.id), String(over.id));
140
+ }
117
141
  };
118
142
 
119
143
  return (
120
144
  <main className="workspace" data-testid="workspace">
121
- <div
122
- className={`workspace-body workspace-body--${mode}${maximized ? " workspace-body--maximized" : ""}`}
123
- style={
124
- mode === "grid"
125
- ? {
126
- gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
127
- gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
128
- }
129
- : undefined
130
- }
145
+ <DndContext
146
+ sensors={sensors}
147
+ collisionDetection={closestCenter}
148
+ onDragStart={onDragStart}
149
+ onDragEnd={onDragEnd}
150
+ onDragCancel={() => setActiveId(null)}
131
151
  >
132
- {orderedTargets.map((target) => {
133
- const id = target.id;
134
- const isVisible = maximized ? id === maximized : visible.includes(id);
135
- const viewState = maximized === id ? "fullscreen" : mode === "grid" ? "grid" : "normal";
136
- const reorder =
137
- reorderable && isVisible
152
+ <div
153
+ className={`workspace-body workspace-body--${mode}${maximized ? " workspace-body--maximized" : ""}`}
154
+ style={
155
+ mode === "grid"
138
156
  ? {
139
- isDragging: dragId === id,
140
- isDropTarget: overId === id && dragId !== null && dragId !== id,
141
- onDragStart: () => setDragId(id),
142
- onDragEnter: () => {
143
- if (dragId && dragId !== id) {
144
- setOverId(id);
145
- }
146
- },
147
- onDrop: () => {
148
- if (dragId && dragId !== id) {
149
- workspace.swapVisible(dragId, id);
150
- }
151
- clearDrag();
152
- },
153
- onDragEnd: clearDrag,
157
+ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
158
+ gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
154
159
  }
155
- : undefined;
156
- return (
157
- <TerminalCard
158
- key={id}
159
- target={target}
160
- region={regionByKey.get(`${target.instance_type}::${target.instance_name}`)}
161
- mode={mode}
162
- isVisible={isVisible}
163
- isFocused={focusedId === id}
164
- viewState={viewState}
165
- reorder={reorder}
166
- onClose={() => workspace.closeTerm(id)}
167
- onNormal={() => workspace.soloTile(id)}
168
- onGrid={canGrid ? workspace.backToGrid : undefined}
169
- onToggleFullscreen={() => toggleFullscreen(id)}
170
- onFocusRequest={() => workspace.setFocused(id)}
171
- onActivity={() => workspace.markUnread(id)}
172
- onEnded={() => onTerminalEnded(target)}
173
- />
174
- );
175
- })}
176
- </div>
160
+ : undefined
161
+ }
162
+ >
163
+ {orderedTargets.map((target) => {
164
+ const id = target.id;
165
+ const isVisible = maximized ? id === maximized : visible.includes(id);
166
+ const viewState =
167
+ maximized === id ? "fullscreen" : mode === "grid" ? "grid" : "normal";
168
+ return (
169
+ <TerminalCard
170
+ key={id}
171
+ target={target}
172
+ region={regionByKey.get(`${target.instance_type}::${target.instance_name}`)}
173
+ mode={mode}
174
+ isVisible={isVisible}
175
+ isFocused={focusedId === id}
176
+ viewState={viewState}
177
+ reorderEnabled={reorderable && isVisible}
178
+ onClose={() => workspace.closeTerm(id)}
179
+ onNormal={() => workspace.soloTile(id)}
180
+ onGrid={canGrid ? workspace.backToGrid : undefined}
181
+ onToggleFullscreen={() => toggleFullscreen(id)}
182
+ onFocusRequest={() => workspace.setFocused(id)}
183
+ onHoverFocus={
184
+ mode === "grid" && !maximized
185
+ ? () => {
186
+ // Focus-follows-mouse: hovering a grid tile focuses it,
187
+ // but never while dragging (would fight the reorder).
188
+ if (!activeId && focusedId !== id) {
189
+ workspace.setFocused(id);
190
+ }
191
+ }
192
+ : undefined
193
+ }
194
+ onActivity={() => workspace.markUnread(id)}
195
+ onEnded={() => onTerminalEnded(target)}
196
+ />
197
+ );
198
+ })}
199
+ </div>
200
+
201
+ {/* Floating "window outline" ghost that follows the cursor while dragging
202
+ * a grid tile. dropAnimation off — the tiles swap instantly on drop. */}
203
+ <DragOverlay dropAnimation={null}>
204
+ {activeTarget ? (
205
+ <div className="terminal-drag-ghost" aria-hidden="true">
206
+ <span className="terminal-drag-ghost-title">{activeTarget.project}</span>
207
+ </div>
208
+ ) : null}
209
+ </DragOverlay>
210
+ </DndContext>
177
211
  </main>
178
212
  );
179
213
  }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "remo-cli"
7
- version = "2.2.0rc9"
7
+ version = "2.2.0rc11"
8
8
  description = "Remote development environment CLI"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1038,7 +1038,7 @@ wheels = [
1038
1038
 
1039
1039
  [[package]]
1040
1040
  name = "remo-cli"
1041
- version = "2.2.0rc9"
1041
+ version = "2.2.0rc11"
1042
1042
  source = { editable = "." }
1043
1043
  dependencies = [
1044
1044
  { name = "ansible-core" },
File without changes
File without changes