remo-cli 2.2.0rc8__tar.gz → 2.2.0rc10__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.0rc8 → remo_cli-2.2.0rc10}/PKG-INFO +1 -1
  2. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/web-session-interface.md +5 -2
  3. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/package-lock.json +46 -0
  4. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/package.json +1 -0
  5. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/SessionRail.css +0 -8
  6. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/SessionRail.tsx +0 -4
  7. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/TerminalCard.css +37 -9
  8. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/TerminalCard.tsx +35 -40
  9. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/WorkspacePane.tsx +94 -64
  10. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/pyproject.toml +1 -1
  11. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/uv.lock +1 -1
  12. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-analyze/SKILL.md +0 -0
  13. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-checklist/SKILL.md +0 -0
  14. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-clarify/SKILL.md +0 -0
  15. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-constitution/SKILL.md +0 -0
  16. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-converge/SKILL.md +0 -0
  17. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-git-commit/SKILL.md +0 -0
  18. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-git-feature/SKILL.md +0 -0
  19. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-git-initialize/SKILL.md +0 -0
  20. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-git-remote/SKILL.md +0 -0
  21. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-git-validate/SKILL.md +0 -0
  22. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-implement/SKILL.md +0 -0
  23. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-plan/SKILL.md +0 -0
  24. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-specify/SKILL.md +0 -0
  25. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-tasks/SKILL.md +0 -0
  26. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
  27. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.devcontainer/devcontainer.json +0 -0
  28. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.dockerignore +0 -0
  29. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/dependabot.yml +0 -0
  30. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/ci.yml +0 -0
  31. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/provision.yml +0 -0
  32. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/release.yml +0 -0
  33. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/smoke-test-cleanup.yml +0 -0
  34. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/smoke-test.yml +0 -0
  35. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.github/workflows/teardown.yml +0 -0
  36. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.gitignore +0 -0
  37. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.maverick/checkpoints/feature/implementation_complete.json +0 -0
  38. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.maverick/checkpoints/feature/phase_${{ index }}_complete.json +0 -0
  39. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.maverick/checkpoints/feature/validation_complete.json +0 -0
  40. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/.registry +0 -0
  41. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/README.md +0 -0
  42. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/commands/speckit.git.commit.md +0 -0
  43. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/commands/speckit.git.feature.md +0 -0
  44. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/commands/speckit.git.initialize.md +0 -0
  45. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/commands/speckit.git.remote.md +0 -0
  46. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/commands/speckit.git.validate.md +0 -0
  47. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/config-template.yml +0 -0
  48. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/extension.yml +0 -0
  49. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/git-config.yml +0 -0
  50. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/bash/auto-commit.sh +0 -0
  51. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/bash/create-new-feature.sh +0 -0
  52. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/bash/git-common.sh +0 -0
  53. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/bash/initialize-repo.sh +0 -0
  54. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
  55. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/powershell/create-new-feature.ps1 +0 -0
  56. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/powershell/git-common.ps1 +0 -0
  57. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
  58. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/extensions.yml +0 -0
  59. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/feature.json +0 -0
  60. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/init-options.json +0 -0
  61. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/integration.json +0 -0
  62. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/integrations/claude.manifest.json +0 -0
  63. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/integrations/speckit.manifest.json +0 -0
  64. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/memory/constitution.md +0 -0
  65. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/check-prerequisites.sh +0 -0
  66. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/common.sh +0 -0
  67. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/create-new-feature.sh +0 -0
  68. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/setup-plan.sh +0 -0
  69. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/setup-tasks.sh +0 -0
  70. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/scripts/bash/update-agent-context.sh +0 -0
  71. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/agent-file-template.md +0 -0
  72. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/checklist-template.md +0 -0
  73. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/constitution-template.md +0 -0
  74. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/plan-template.md +0 -0
  75. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/spec-template.md +0 -0
  76. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/templates/tasks-template.md +0 -0
  77. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/workflows/speckit/workflow.yml +0 -0
  78. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/.specify/workflows/workflow-registry.json +0 -0
  79. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/AGENTS.md +0 -0
  80. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/CLAUDE.md +0 -0
  81. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/CONTRIBUTING.md +0 -0
  82. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/Dockerfile +0 -0
  83. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/LICENSE +0 -0
  84. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/README.md +0 -0
  85. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/.ansible-lint +0 -0
  86. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/README.md +0 -0
  87. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/ansible.cfg +0 -0
  88. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/aws_configure.yml +0 -0
  89. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/aws_resize.yml +0 -0
  90. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/aws_site.yml +0 -0
  91. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/aws_teardown.yml +0 -0
  92. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/group_vars/all.yml +0 -0
  93. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/group_vars/incus_containers.yml +0 -0
  94. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/group_vars/proxmox_containers.yml +0 -0
  95. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/hetzner_configure.yml +0 -0
  96. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/hetzner_provision.yml +0 -0
  97. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/hetzner_resize.yml +0 -0
  98. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/hetzner_site.yml +0 -0
  99. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/hetzner_teardown.yml +0 -0
  100. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_bootstrap.yml +0 -0
  101. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_configure.yml +0 -0
  102. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_provision.yml +0 -0
  103. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_resize.yml +0 -0
  104. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_site.yml +0 -0
  105. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/incus_teardown.yml +0 -0
  106. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/inventory/hosts.yml +0 -0
  107. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/inventory/incus_containers.yml +0 -0
  108. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_bootstrap.yml +0 -0
  109. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_configure.yml +0 -0
  110. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_provision.yml +0 -0
  111. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_resize.yml +0 -0
  112. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_site.yml +0 -0
  113. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/proxmox_teardown.yml +0 -0
  114. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/requirements.yml +0 -0
  115. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/defaults/main.yml +0 -0
  116. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/ebs.yml +0 -0
  117. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/ec2.yml +0 -0
  118. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/main.yml +0 -0
  119. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/patch_manager.yml +0 -0
  120. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/preflight.yml +0 -0
  121. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/aws_server/tasks/security_group.yml +0 -0
  122. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/deacon/defaults/main.yml +0 -0
  123. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/deacon/tasks/main.yml +0 -0
  124. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/devcontainers/tasks/main.yml +0 -0
  125. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/docker/handlers/main.yml +0 -0
  126. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/docker/tasks/main.yml +0 -0
  127. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/fzf/tasks/main.yml +0 -0
  128. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/github_cli/tasks/main.yml +0 -0
  129. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/hetzner_server/defaults/main.yml +0 -0
  130. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/hetzner_server/tasks/main.yml +0 -0
  131. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_bootstrap/defaults/main.yml +0 -0
  132. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_bootstrap/handlers/main.yml +0 -0
  133. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_bootstrap/tasks/main.yml +0 -0
  134. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container/defaults/main.yml +0 -0
  135. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container/handlers/main.yml +0 -0
  136. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container/meta/main.yml +0 -0
  137. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container/tasks/main.yml +0 -0
  138. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container/tasks/preflight.yml +0 -0
  139. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container_teardown/defaults/main.yml +0 -0
  140. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container_teardown/meta/main.yml +0 -0
  141. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/incus_container_teardown/tasks/main.yml +0 -0
  142. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/nodejs/defaults/main.yml +0 -0
  143. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/nodejs/tasks/main.yml +0 -0
  144. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_bootstrap/defaults/main.yml +0 -0
  145. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_bootstrap/meta/main.yml +0 -0
  146. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_bootstrap/tasks/main.yml +0 -0
  147. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container/defaults/main.yml +0 -0
  148. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container/handlers/main.yml +0 -0
  149. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container/meta/main.yml +0 -0
  150. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container/tasks/main.yml +0 -0
  151. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container/tasks/preflight.yml +0 -0
  152. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container_teardown/defaults/main.yml +0 -0
  153. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container_teardown/meta/main.yml +0 -0
  154. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/proxmox_container_teardown/tasks/main.yml +0 -0
  155. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/defaults/main.yml +0 -0
  156. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/tasks/main.yml +0 -0
  157. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/templates/devshell.sh.j2 +0 -0
  158. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/templates/project-launch.sh.j2 +0 -0
  159. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/templates/project-menu.sh.j2 +0 -0
  160. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/user_setup/templates/remo-host.sh.j2 +0 -0
  161. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/zellij/defaults/main.yml +0 -0
  162. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/zellij/tasks/main.yml +0 -0
  163. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/zellij/templates/config.kdl.j2 +0 -0
  164. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/roles/zellij/templates/layouts/minimal.kdl.j2 +0 -0
  165. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/ansible/tasks/configure_dev_tools.yml +0 -0
  166. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docker/Dockerfile +0 -0
  167. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docker/compose.example.yml +0 -0
  168. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docker/entrypoint.sh +0 -0
  169. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/aws.md +0 -0
  170. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/hetzner.md +0 -0
  171. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/incus.md +0 -0
  172. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/install.sh +0 -0
  173. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/proxmox.md +0 -0
  174. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/remo-web-speckit-input.md +0 -0
  175. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/docs/remo-web.html +0 -0
  176. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/index.html +0 -0
  177. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/public/README.md +0 -0
  178. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/public/dist__ghostty-vt.wasm +0 -0
  179. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/public/ghostty-vt.wasm +0 -0
  180. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/scripts/copy-ghostty-wasm.mjs +0 -0
  181. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/api/client.ts +0 -0
  182. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/AppRoot.tsx +0 -0
  183. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/AppShell.css +0 -0
  184. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/AppShell.tsx +0 -0
  185. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/AwaitingAdoption.css +0 -0
  186. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/AwaitingAdoption.tsx +0 -0
  187. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/OfflineOverlay.css +0 -0
  188. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/OfflineOverlay.tsx +0 -0
  189. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/PairToSync.css +0 -0
  190. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/PairToSync.tsx +0 -0
  191. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/SettingsPage.css +0 -0
  192. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/SettingsPage.tsx +0 -0
  193. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/ShortcutsModal.css +0 -0
  194. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/ShortcutsModal.tsx +0 -0
  195. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/TopBar.css +0 -0
  196. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/TopBar.tsx +0 -0
  197. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/WorkspacePane.css +0 -0
  198. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/providerMeta.ts +0 -0
  199. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/components/railModel.ts +0 -0
  200. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/lib/clipboard.ts +0 -0
  201. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/lib/fullscreen.ts +0 -0
  202. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/main.tsx +0 -0
  203. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/discovery.ts +0 -0
  204. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/fonts.ts +0 -0
  205. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/health.ts +0 -0
  206. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/settings.ts +0 -0
  207. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/useConsoleKeyboard.ts +0 -0
  208. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/workspace.test.ts +0 -0
  209. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/state/workspace.ts +0 -0
  210. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/.gitkeep +0 -0
  211. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/GhosttyRenderer.ts +0 -0
  212. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/RendererAdapter.ts +0 -0
  213. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/TerminalConnection.test.ts +0 -0
  214. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/TerminalConnection.ts +0 -0
  215. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/XtermRenderer.ts +0 -0
  216. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/defaultRenderer.ts +0 -0
  217. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/keymap.test.ts +0 -0
  218. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/terminal/keymap.ts +0 -0
  219. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/test/setup.ts +0 -0
  220. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/theme/fonts.ts +0 -0
  221. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/src/theme/tokens.css +0 -0
  222. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/tsconfig.json +0 -0
  223. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/frontend/vite.config.ts +0 -0
  224. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/install.sh +0 -0
  225. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/maverick.yaml +0 -0
  226. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/playwright.config.ts +0 -0
  227. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/project-menu.sh +0 -0
  228. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/remo +0 -0
  229. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/run.sh +0 -0
  230. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/scripts/setup-aws-oidc.sh +0 -0
  231. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/checklists/requirements.md +0 -0
  232. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/checklists/validation.md +0 -0
  233. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/contracts/playbook-interface.yaml +0 -0
  234. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/contracts/role-interface.yaml +0 -0
  235. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/data-model.md +0 -0
  236. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/plan.md +0 -0
  237. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/quickstart.md +0 -0
  238. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/research.md +0 -0
  239. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/spec.md +0 -0
  240. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/001-bootstrap-incus-host/tasks.md +0 -0
  241. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/checklists/requirements.md +0 -0
  242. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/contracts/playbook-interface.yaml +0 -0
  243. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/contracts/role-interface.yaml +0 -0
  244. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/data-model.md +0 -0
  245. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/plan.md +0 -0
  246. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/quickstart.md +0 -0
  247. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/research.md +0 -0
  248. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/spec.md +0 -0
  249. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/002-incus-container-support/tasks.md +0 -0
  250. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/checklists/requirements.md +0 -0
  251. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/data-model.md +0 -0
  252. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/plan.md +0 -0
  253. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/quickstart.md +0 -0
  254. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/research.md +0 -0
  255. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/spec.md +0 -0
  256. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/003-python-cli-rewrite/tasks.md +0 -0
  257. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/004-proxmox-container-support/spec.md +0 -0
  258. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/checklists/requirements.md +0 -0
  259. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/contracts/cli-surface.md +0 -0
  260. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/data-model.md +0 -0
  261. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/plan.md +0 -0
  262. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/quickstart.md +0 -0
  263. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/research.md +0 -0
  264. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/spec.md +0 -0
  265. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/005-provider-snapshots/tasks.md +0 -0
  266. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/checklists/requirements.md +0 -0
  267. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/contracts/remo-host-protocol.md +0 -0
  268. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/contracts/rest-api.md +0 -0
  269. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/contracts/terminal-websocket.md +0 -0
  270. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/data-model.md +0 -0
  271. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/plan.md +0 -0
  272. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/quickstart.md +0 -0
  273. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/research.md +0 -0
  274. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/spec.md +0 -0
  275. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/010-web-session-interface/tasks.md +0 -0
  276. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/checklists/requirements.md +0 -0
  277. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/contracts/cli-web-adopt.md +0 -0
  278. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/contracts/setup-api.md +0 -0
  279. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/data-model.md +0 -0
  280. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/plan.md +0 -0
  281. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/quickstart-results.md +0 -0
  282. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/quickstart.md +0 -0
  283. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/research.md +0 -0
  284. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/spec.md +0 -0
  285. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/011-web-adopt/tasks.md +0 -0
  286. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/contracts/cli-web-adopt.md +0 -0
  287. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/contracts/pairing-api.md +0 -0
  288. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/contracts/setup-api.md +0 -0
  289. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/data-model.md +0 -0
  290. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/plan.md +0 -0
  291. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/quickstart.md +0 -0
  292. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/research.md +0 -0
  293. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/spec.md +0 -0
  294. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/specs/012-web-adopt-pairing/tasks.md +0 -0
  295. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/__init__.py +0 -0
  296. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/__main__.py +0 -0
  297. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/__init__.py +0 -0
  298. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/cp.py +0 -0
  299. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/main.py +0 -0
  300. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/providers/__init__.py +0 -0
  301. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/providers/aws.py +0 -0
  302. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/providers/hetzner.py +0 -0
  303. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/providers/incus.py +0 -0
  304. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/providers/proxmox.py +0 -0
  305. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/shell.py +0 -0
  306. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/cli/web.py +0 -0
  307. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/__init__.py +0 -0
  308. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/ansible_runner.py +0 -0
  309. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/completion.py +0 -0
  310. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/config.py +0 -0
  311. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/known_hosts.py +0 -0
  312. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/output.py +0 -0
  313. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/picker.py +0 -0
  314. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/remo_host_client.py +0 -0
  315. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/rsync.py +0 -0
  316. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/snapshot.py +0 -0
  317. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/ssh.py +0 -0
  318. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/validation.py +0 -0
  319. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/version.py +0 -0
  320. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/core/web_adopt.py +0 -0
  321. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/__init__.py +0 -0
  322. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/capability.py +0 -0
  323. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/discovery.py +0 -0
  324. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/host.py +0 -0
  325. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/session_target.py +0 -0
  326. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/models/snapshot.py +0 -0
  327. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/providers/__init__.py +0 -0
  328. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/providers/aws.py +0 -0
  329. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/providers/hetzner.py +0 -0
  330. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/providers/incus.py +0 -0
  331. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/providers/proxmox.py +0 -0
  332. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/__init__.py +0 -0
  333. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/api/__init__.py +0 -0
  334. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/api/hosts.py +0 -0
  335. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/api/pairing.py +0 -0
  336. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/api/setup.py +0 -0
  337. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/api/terminals.py +0 -0
  338. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/app.py +0 -0
  339. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/check.py +0 -0
  340. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/config.py +0 -0
  341. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/discovery.py +0 -0
  342. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/health.py +0 -0
  343. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/logging_config.py +0 -0
  344. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/models.py +0 -0
  345. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/operator_auth.py +0 -0
  346. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/pairing.py +0 -0
  347. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/ssh_master.py +0 -0
  348. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/state.py +0 -0
  349. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/terminal.py +0 -0
  350. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/terminal_registry.py +0 -0
  351. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/src/remo_cli/web/tokens.py +0 -0
  352. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/__init__.py +0 -0
  353. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/ansible/__init__.py +0 -0
  354. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/ansible/test_remo_host_idempotency.py +0 -0
  355. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/conftest.py +0 -0
  356. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/fixtures.ts +0 -0
  357. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/ghostty-shell-io.spec.ts +0 -0
  358. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/ghostty-tui-compatibility.spec.ts +0 -0
  359. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/keyboard-routing.spec.ts +0 -0
  360. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/mobile.spec.ts +0 -0
  361. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/reconnect.spec.ts +0 -0
  362. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/e2e/workspace-layout.spec.ts +0 -0
  363. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/image/__init__.py +0 -0
  364. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/image/test_docker_image.py +0 -0
  365. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/__init__.py +0 -0
  366. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/_nine_terminal_fixture.py +0 -0
  367. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/orbstack-cloud-init.yml +0 -0
  368. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/orbstack.sh +0 -0
  369. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_nine_terminals.py +0 -0
  370. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_nine_terminals_soak.py +0 -0
  371. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_remo_host_e2e.py +0 -0
  372. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_security_rejections.py +0 -0
  373. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_terminal_attach.py +0 -0
  374. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_web_adopt_e2e.py +0 -0
  375. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/integration/test_web_cli_parity.py +0 -0
  376. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/perf/__init__.py +0 -0
  377. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/perf/test_latency.py +0 -0
  378. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/__init__.py +0 -0
  379. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/__init__.py +0 -0
  380. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/providers/test_aws_snapshot.py +0 -0
  381. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/providers/test_hetzner_snapshot.py +0 -0
  382. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/providers/test_incus_snapshot.py +0 -0
  383. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/providers/test_proxmox_snapshot.py +0 -0
  384. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/test_cp.py +0 -0
  385. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/test_main.py +0 -0
  386. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/test_shell.py +0 -0
  387. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/cli/test_web_adopt_cmd.py +0 -0
  388. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/__init__.py +0 -0
  389. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_ansible_runner.py +0 -0
  390. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_config.py +0 -0
  391. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_known_hosts.py +0 -0
  392. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_output.py +0 -0
  393. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_picker.py +0 -0
  394. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_remo_host_client.py +0 -0
  395. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_rsync.py +0 -0
  396. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_snapshot.py +0 -0
  397. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_ssh.py +0 -0
  398. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_ssh_controlpath.py +0 -0
  399. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_ssh_identity_opts.py +0 -0
  400. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_validation.py +0 -0
  401. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_version.py +0 -0
  402. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_web_adopt_authorize.py +0 -0
  403. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_web_adopt_code.py +0 -0
  404. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_web_adopt_payload.py +0 -0
  405. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_web_adopt_trust.py +0 -0
  406. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/core/test_web_push.py +0 -0
  407. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/models/__init__.py +0 -0
  408. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/models/test_capability.py +0 -0
  409. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/models/test_discovery.py +0 -0
  410. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/models/test_session_target.py +0 -0
  411. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/__init__.py +0 -0
  412. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/test_aws_snapshot.py +0 -0
  413. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/test_hetzner_snapshot.py +0 -0
  414. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/test_incus_snapshot.py +0 -0
  415. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/test_proxmox_devcontainer_runtime.py +0 -0
  416. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/providers/test_proxmox_snapshot.py +0 -0
  417. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/test_ansible_templates.py +0 -0
  418. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/test_host_model.py +0 -0
  419. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/__init__.py +0 -0
  420. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/_pairing_support.py +0 -0
  421. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/conftest.py +0 -0
  422. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_backpressure.py +0 -0
  423. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_check.py +0 -0
  424. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_csp.py +0 -0
  425. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_discovery.py +0 -0
  426. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_health_states.py +0 -0
  427. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_hosts_mapping.py +0 -0
  428. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_lazy_import.py +0 -0
  429. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_log_redaction.py +0 -0
  430. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_mint_gating.py +0 -0
  431. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_operator_auth.py +0 -0
  432. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_pairing.py +0 -0
  433. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_pairing_origin.py +0 -0
  434. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_setup_api.py +0 -0
  435. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_setup_auth.py +0 -0
  436. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_setup_dormancy.py +0 -0
  437. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_state.py +0 -0
  438. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_terminal_resize.py +0 -0
  439. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/tests/unit/web/test_terminals_api.py +0 -0
  440. {remo_cli-2.2.0rc8 → remo_cli-2.2.0rc10}/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.0rc8
3
+ Version: 2.2.0rc10
4
4
  Summary: Remote development environment CLI
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -100,8 +100,11 @@ 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, **hovering a tile focuses it**
106
+ (focus-follows-mouse) so keystrokes go where the pointer is — no click needed. The **◻** control solos
107
+ a tile; **Esc** collapses the grid back to the focused terminal;
105
108
  number keys **1–9** jump to the numbered sessions (⌘ 1–9 add to the grid). Hidden terminals stay
106
109
  connected and keep their scrollback. Each terminal header shows `provider · instance · region`
107
110
  (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",
@@ -244,14 +244,6 @@
244
244
  color: var(--accent);
245
245
  flex: none;
246
246
  }
247
- .rail-row-num {
248
- font-family: var(--font-mono);
249
- font-size: 10px;
250
- color: var(--text-faint);
251
- width: 12px;
252
- text-align: right;
253
- flex: none;
254
- }
255
247
  .rail-row-name {
256
248
  font-family: var(--font-mono);
257
249
  font-size: 12.5px;
@@ -228,7 +228,6 @@ function RailInstance({
228
228
  <RailSessionRow
229
229
  key={row.target.id}
230
230
  target={row.target}
231
- num={row.num}
232
231
  providerColor={meta.color}
233
232
  attached={attached.includes(row.target.id)}
234
233
  visible={visible.includes(row.target.id)}
@@ -243,7 +242,6 @@ function RailInstance({
243
242
 
244
243
  interface RailSessionRowProps {
245
244
  target: SessionTarget;
246
- num: number | null;
247
245
  providerColor: string;
248
246
  attached: boolean;
249
247
  visible: boolean;
@@ -254,7 +252,6 @@ interface RailSessionRowProps {
254
252
 
255
253
  function RailSessionRow({
256
254
  target,
257
- num,
258
255
  attached,
259
256
  visible,
260
257
  focused,
@@ -282,7 +279,6 @@ function RailSessionRow({
282
279
  onClick={(e) => onSelect(target, e)}
283
280
  >
284
281
  <span className="rail-row-mark">{mark}</span>
285
- <span className="rail-row-num">{num ?? ""}</span>
286
282
  <span className="rail-row-name">{target.project}</span>
287
283
  <span className="rail-row-glyphs">
288
284
  {target.git_dirty && (
@@ -53,26 +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));
70
73
  }
71
74
 
72
- .terminal-card-num {
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;
73
94
  font-family: var(--font-mono);
74
- font-size: 9px;
75
- color: var(--text-faint);
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);
76
104
  }
77
105
 
78
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 {
@@ -42,18 +43,6 @@ export type TerminalCardMode = "single" | "grid";
42
43
  * Drives the window-control cluster's active/disabled state. */
43
44
  export type TerminalViewState = "normal" | "grid" | "fullscreen";
44
45
 
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
46
  interface TerminalCardProps {
58
47
  target: SessionTarget;
59
48
  /** Registry region for this target's instance (badge only). */
@@ -63,13 +52,12 @@ interface TerminalCardProps {
63
52
  isVisible: boolean;
64
53
  /** Whether this card currently receives keyboard input + the focus ring. */
65
54
  isFocused: boolean;
66
- /** 1-based position label shown on a grid tile. */
67
- num?: number;
68
55
  /** The display mode this card is currently in (window-control cluster state). */
69
56
  viewState: TerminalViewState;
70
57
  onClose: () => void;
71
- /** Drag-to-reorder wiring; present only for a reorderable grid tile. */
72
- reorder?: TerminalReorder;
58
+ /** When true, the header acts as a dnd-kit drag handle and the tile is a drop
59
+ * target (grid reorder). The DndContext + swap live in WorkspacePane. */
60
+ reorderEnabled?: boolean;
73
61
  /** Window-control "Normal": solo this terminal into the single view. */
74
62
  onNormal: () => void;
75
63
  /** Window-control "Grid": show the grid — omitted when none is available. */
@@ -78,6 +66,9 @@ interface TerminalCardProps {
78
66
  onToggleFullscreen: () => void;
79
67
  /** Called when the user clicks into the surface (focus this terminal). */
80
68
  onFocusRequest?: () => void;
69
+ /** Focus-follows-mouse: called when the pointer enters this tile (grid only),
70
+ * so hovering changes focus without a click. No-op'd mid-drag by the caller. */
71
+ onHoverFocus?: () => void;
81
72
  /** Called when output arrives while this card is hidden (rail activity dot). */
82
73
  onActivity?: () => void;
83
74
  /** Called when the remote process exits (session may have ended) or the
@@ -100,14 +91,14 @@ export function TerminalCard({
100
91
  mode,
101
92
  isVisible,
102
93
  isFocused,
103
- num,
104
94
  viewState,
105
95
  onClose,
106
- reorder,
96
+ reorderEnabled,
107
97
  onNormal,
108
98
  onGrid,
109
99
  onToggleFullscreen,
110
100
  onFocusRequest,
101
+ onHoverFocus,
111
102
  onActivity,
112
103
  onEnded,
113
104
  }: TerminalCardProps): JSX.Element {
@@ -133,6 +124,22 @@ export function TerminalCard({
133
124
  const [needsManualReconnect, setNeedsManualReconnect] = useState(false);
134
125
  const [error, setError] = useState<TypedError | null>(null);
135
126
 
127
+ // dnd-kit reorder: the tile is both a draggable (handle = header grip, below)
128
+ // and a droppable (swap target). Disabled outside a reorderable grid. We use
129
+ // the DragOverlay pattern (WorkspacePane), so the source stays put (dimmed)
130
+ // and we never apply `draggable.transform`.
131
+ const draggable = useDraggable({ id: target.id, disabled: !reorderEnabled });
132
+ const droppable = useDroppable({ id: target.id, disabled: !reorderEnabled });
133
+ const setDraggableRef = draggable.setNodeRef;
134
+ const setDroppableRef = droppable.setNodeRef;
135
+ const setTileRef = useCallback(
136
+ (node: HTMLDivElement | null) => {
137
+ setDraggableRef(node);
138
+ setDroppableRef(node);
139
+ },
140
+ [setDraggableRef, setDroppableRef],
141
+ );
142
+
136
143
  useEffect(() => {
137
144
  isFocusedRef.current = isFocused;
138
145
  }, [isFocused]);
@@ -302,42 +309,30 @@ export function TerminalCard({
302
309
  const prov = providerMeta(target.instance_type);
303
310
  const badge = [prov.label, target.instance_name, region].filter(Boolean).join(" · ");
304
311
 
305
- const dragClasses = reorder
306
- ? `${reorder.isDragging ? " terminal-card--dragging" : ""}${reorder.isDropTarget ? " terminal-card--drop-target" : ""}`
307
- : "";
312
+ const isDragging = draggable.isDragging;
313
+ // Highlight the tile the drop will land on (swap target) but not the source.
314
+ const isDropTarget = Boolean(reorderEnabled) && droppable.isOver && !isDragging;
315
+ const dragClasses = `${isDragging ? " terminal-card--dragging" : ""}${isDropTarget ? " terminal-card--drop-target" : ""}`;
308
316
 
309
317
  return (
310
318
  <div
319
+ ref={setTileRef}
311
320
  className={`terminal-card terminal-card--${mode}${isFocused ? " terminal-card--focused" : ""}${dragClasses}`}
312
321
  data-testid={`terminal-card-${target.id}`}
313
322
  data-focused={isFocused}
314
323
  data-connection-state={connectionState}
315
324
  style={{ display: isVisible ? undefined : "none" }}
316
- // Whole tile is the drop target for a reorder drag (see the header grip).
317
- onDragOver={reorder ? (e) => e.preventDefault() : undefined}
318
- onDragEnter={reorder ? (e) => { e.preventDefault(); reorder.onDragEnter(); } : undefined}
319
- onDrop={reorder ? (e) => { e.preventDefault(); reorder.onDrop(); } : undefined}
325
+ onMouseEnter={onHoverFocus}
320
326
  >
321
327
  <header className="terminal-card-header">
322
328
  {/* The header (left of the controls) is the drag handle for reordering
323
329
  * grid tiles; it no longer solos on click — the ◻ control does that. */}
324
330
  <div
325
- className="terminal-card-grip"
326
- draggable={reorder ? true : undefined}
327
- onDragStart={
328
- reorder
329
- ? (e) => {
330
- e.dataTransfer.setData("text/plain", target.id);
331
- e.dataTransfer.effectAllowed = "move";
332
- reorder.onDragStart();
333
- }
334
- : undefined
335
- }
336
- onDragEnd={reorder ? () => reorder.onDragEnd() : undefined}
331
+ ref={reorderEnabled ? draggable.setActivatorNodeRef : undefined}
332
+ className={`terminal-card-grip${reorderEnabled ? " terminal-card-grip--handle" : ""}`}
333
+ {...(reorderEnabled ? draggable.listeners : {})}
334
+ {...(reorderEnabled ? draggable.attributes : {})}
337
335
  >
338
- {mode === "grid" && num !== undefined && (
339
- <span className="terminal-card-num">{num}</span>
340
- )}
341
336
  <span className="terminal-card-provider-dot" style={{ background: prov.color }} />
342
337
  <div className="terminal-card-identity">
343
338
  <span className="terminal-card-project">{target.project}</span>
@@ -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
@@ -99,9 +117,6 @@ export function WorkspacePane({
99
117
  visible.filter((id) => attached.includes(id)).length > 1 ||
100
118
  (prevGrid ?? []).filter((id) => attached.includes(id)).length > 1;
101
119
 
102
- // 1-based position for each visible id (grid tile number badge).
103
- const visibleIndex = new Map(visible.map((id, i) => [id, i + 1]));
104
-
105
120
  const toggleFullscreen = (id: string): void => {
106
121
  if (maximized === id) {
107
122
  workspace.restore();
@@ -114,70 +129,85 @@ export function WorkspacePane({
114
129
 
115
130
  // Reordering is possible only within a real grid (two-plus visible tiles).
116
131
  const reorderable = !maximized && mode === "grid" && visible.length > 1;
117
- const clearDrag = (): void => {
118
- setDragId(null);
119
- 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
+ }
120
141
  };
121
142
 
122
143
  return (
123
144
  <main className="workspace" data-testid="workspace">
124
- <div
125
- className={`workspace-body workspace-body--${mode}${maximized ? " workspace-body--maximized" : ""}`}
126
- style={
127
- mode === "grid"
128
- ? {
129
- gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
130
- gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
131
- }
132
- : undefined
133
- }
145
+ <DndContext
146
+ sensors={sensors}
147
+ collisionDetection={closestCenter}
148
+ onDragStart={onDragStart}
149
+ onDragEnd={onDragEnd}
150
+ onDragCancel={() => setActiveId(null)}
134
151
  >
135
- {orderedTargets.map((target) => {
136
- const id = target.id;
137
- const isVisible = maximized ? id === maximized : visible.includes(id);
138
- const viewState = maximized === id ? "fullscreen" : mode === "grid" ? "grid" : "normal";
139
- const reorder =
140
- reorderable && isVisible
152
+ <div
153
+ className={`workspace-body workspace-body--${mode}${maximized ? " workspace-body--maximized" : ""}`}
154
+ style={
155
+ mode === "grid"
141
156
  ? {
142
- isDragging: dragId === id,
143
- isDropTarget: overId === id && dragId !== null && dragId !== id,
144
- onDragStart: () => setDragId(id),
145
- onDragEnter: () => {
146
- if (dragId && dragId !== id) {
147
- setOverId(id);
148
- }
149
- },
150
- onDrop: () => {
151
- if (dragId && dragId !== id) {
152
- workspace.swapVisible(dragId, id);
153
- }
154
- clearDrag();
155
- },
156
- onDragEnd: clearDrag,
157
+ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,
158
+ gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
157
159
  }
158
- : undefined;
159
- return (
160
- <TerminalCard
161
- key={id}
162
- target={target}
163
- region={regionByKey.get(`${target.instance_type}::${target.instance_name}`)}
164
- mode={mode}
165
- isVisible={isVisible}
166
- isFocused={focusedId === id}
167
- num={visibleIndex.get(id)}
168
- viewState={viewState}
169
- reorder={reorder}
170
- onClose={() => workspace.closeTerm(id)}
171
- onNormal={() => workspace.soloTile(id)}
172
- onGrid={canGrid ? workspace.backToGrid : undefined}
173
- onToggleFullscreen={() => toggleFullscreen(id)}
174
- onFocusRequest={() => workspace.setFocused(id)}
175
- onActivity={() => workspace.markUnread(id)}
176
- onEnded={() => onTerminalEnded(target)}
177
- />
178
- );
179
- })}
180
- </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>
181
211
  </main>
182
212
  );
183
213
  }
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "remo-cli"
7
- version = "2.2.0rc8"
7
+ version = "2.2.0rc10"
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.0rc8"
1041
+ version = "2.2.0rc10"
1042
1042
  source = { editable = "." }
1043
1043
  dependencies = [
1044
1044
  { name = "ansible-core" },
File without changes
File without changes