remo-cli 4.0.1__tar.gz → 4.1.0__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.
- remo_cli-4.1.0/.release-please-manifest.json +3 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/AGENTS.md +3 -1
- {remo_cli-4.0.1 → remo_cli-4.1.0}/CHANGELOG.md +7 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/CLAUDE.md +3 -1
- {remo_cli-4.0.1 → remo_cli-4.1.0}/PKG-INFO +1 -1
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/web-session-interface.md +10 -1
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.tsx +45 -0
- remo_cli-4.1.0/frontend/src/components/WorkspacePane.css +139 -0
- remo_cli-4.1.0/frontend/src/components/WorkspacePane.test.tsx +175 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/WorkspacePane.tsx +120 -35
- remo_cli-4.1.0/frontend/src/components/masterLayout.test.ts +201 -0
- remo_cli-4.1.0/frontend/src/components/masterLayout.ts +190 -0
- remo_cli-4.1.0/frontend/src/state/workspace.test.ts +296 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/workspace.ts +156 -8
- {remo_cli-4.0.1 → remo_cli-4.1.0}/pyproject.toml +1 -1
- remo_cli-4.1.0/scripts/palette-check.sh +67 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_discovery.py +57 -18
- {remo_cli-4.0.1 → remo_cli-4.1.0}/uv.lock +1 -1
- remo_cli-4.0.1/.release-please-manifest.json +0 -3
- remo_cli-4.0.1/frontend/src/components/WorkspacePane.css +0 -70
- remo_cli-4.0.1/frontend/src/state/workspace.test.ts +0 -98
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/release/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-analyze/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-checklist/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-clarify/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-constitution/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-converge/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-git-commit/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-git-feature/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-git-initialize/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-git-remote/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-git-validate/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-implement/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-plan/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-specify/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-tasks/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.devcontainer/devcontainer.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.dockerignore +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/CODEOWNERS +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/dependabot.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/ci.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/codeql.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/dependency-review.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/dev-build.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/provision.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/release-please.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/release.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/smoke-test-cleanup.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/smoke-test.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.github/workflows/teardown.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.gitignore +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.maverick/checkpoints/feature/implementation_complete.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.maverick/checkpoints/feature/phase_${{ index }}_complete.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.maverick/checkpoints/feature/validation_complete.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/.registry +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/README.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.commit.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.feature.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.initialize.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.remote.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.validate.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/config-template.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/extension.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/git-config.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/auto-commit.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/create-new-feature.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/git-common.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/initialize-repo.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/create-new-feature.ps1 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/git-common.ps1 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/extensions.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/feature.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/init-options.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/integration.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/integrations/claude.manifest.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/integrations/speckit.manifest.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/memory/constitution.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/common.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/setup-plan.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/setup-tasks.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/agent-file-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/checklist-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/constitution-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/plan-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/spec-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/templates/tasks-template.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/workflows/speckit/workflow.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/.specify/workflows/workflow-registry.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/CONTRIBUTING.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/Dockerfile +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/LICENSE +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/README.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/SECURITY.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/.ansible-lint +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/README.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/ansible.cfg +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/aws_configure.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/aws_resize.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/aws_site.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/aws_teardown.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/group_vars/all.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/group_vars/incus_containers.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/group_vars/proxmox_containers.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/hetzner_configure.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/hetzner_provision.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/hetzner_resize.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/hetzner_site.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/hetzner_teardown.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_bootstrap.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_configure.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_provision.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_resize.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_site.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/incus_teardown.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/inventory/hosts.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/inventory/incus_containers.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_bootstrap.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_configure.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_provision.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_resize.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_site.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/proxmox_teardown.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/requirements.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/ebs.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/ec2.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/patch_manager.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/preflight.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/security_group.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/deacon/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/deacon/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/devcontainers/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/docker/handlers/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/docker/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/fzf/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/github_cli/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/hetzner_server/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/hetzner_server/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/handlers/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container/handlers/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container/meta/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container/tasks/preflight.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/meta/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/nodejs/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/nodejs/files/nodesource-repo.gpg.key +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/nodejs/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/meta/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container/handlers/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container/meta/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container/tasks/preflight.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/meta/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/devshell.sh.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/project-launch.sh.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/project-menu.sh.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/remo-host.sh.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/zellij/defaults/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/zellij/tasks/main.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/zellij/templates/config.kdl.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/roles/zellij/templates/layouts/minimal.kdl.j2 +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/tasks/configure_dev_tools.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/ansible/tasks/repair_apt_sources.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docker/Dockerfile +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docker/compose.example.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docker/entrypoint.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/aws.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/feature-history.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/hetzner.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/incus.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/install.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/maintaining-claude-md.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/maintaining-generated-types.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/providers.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/proxmox.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/remo-web-speckit-input.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/docs/remo-web.html +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/index.html +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/package-lock.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/package.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/scripts/check-types-fresh.mjs +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/scripts/generate-frame-types.mjs +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/scripts/generate-schema-types.mjs +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/client.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/client.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated/README.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated/openapi.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated/schema.d.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated/terminal-frames.d.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated/terminal-frames.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/api/generated.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/AppRoot.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/AppShell.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/AppShell.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/AwaitingAdoption.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/AwaitingAdoption.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/OfflineOverlay.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/OfflineOverlay.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/PairToSync.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/PairToSync.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/SessionRail.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/SessionRail.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/SettingsPage.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/SettingsPage.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/ShortcutsModal.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/ShortcutsModal.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.test.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/TopBar.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/TopBar.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/providerMeta.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/providerMeta.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/railModel.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/components/railModel.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/lib/clipboard.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/lib/fullscreen.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/main.tsx +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/discovery.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/discovery.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/fonts.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/health.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/health.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/latency.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/latency.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/settings.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/settings.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/state/useConsoleKeyboard.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/.gitkeep +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/RendererAdapter.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/TerminalConnection.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/TerminalConnection.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/XtermRenderer.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/defaultRenderer.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/keymap.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/terminal/keymap.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/test/setup.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/theme/fonts.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/theme/terminalThemes.test.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/theme/terminalThemes.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/src/theme/tokens.css +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/tsconfig.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/frontend/vite.config.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/install.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/maverick.yaml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/playwright.config.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/project-menu.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/release-please-config.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/remo +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/remo.svg +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/run.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/scripts/export_openapi.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/scripts/setup-aws-oidc.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/checklists/validation.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/contracts/playbook-interface.yaml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/contracts/role-interface.yaml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/contracts/playbook-interface.yaml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/contracts/role-interface.yaml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/002-incus-container-support/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/004-proxmox-container-support/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/005-provider-snapshots/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/remo-host-protocol.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/rest-api.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/terminal-websocket.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/010-web-session-interface/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/contracts/cli-web-adopt.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/contracts/setup-api.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/quickstart-results.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/011-web-adopt/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/cli-web-adopt.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/pairing-api.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/setup-api.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/contracts/cli-sync.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/contracts/marker-commands.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/013-managed-instance-tags/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/contracts/add-command.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/contracts/remove-command.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/014-register-ssh-host/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/mirror-payload-v2.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/registry-accessor-api.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/registry-file-v2.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/015-registry-v2/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/contracts/cli-sync.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/contracts/provider-probe.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/016-sync-reconcile/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/cli-web-push.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/cli-web-status.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/revocation.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/setup-status-marker.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/baseline-notes.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/errors.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/lifecycle-templates.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/provider-protocol.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/sync-merge.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/018-provider-abstraction/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/contracts/cli-surface-delta.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/contracts/docs-structure-check.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/checklists/requirements.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/contracts/drift-checks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/contracts/terminal-frames-v1.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/020-openapi-type-generation/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/contracts/descriptor-schema.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/data-model.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/plan.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/quickstart.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/research.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/spec.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/specs/021-cli-plane-separation/tasks.md +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/__main__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/added.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/cp.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/main.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/providers/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/providers/factory.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/shell.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/cli/web.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/ansible_runner.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/completion.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/config.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/errors.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/known_hosts.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/lifecycle.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/output.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/picker.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/provider_protocol.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/provider_registry.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/reconcile.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/registry.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/remo_host_client.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/rsync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/ssh.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/validation.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/version.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/web_adopt.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/core/web_drift.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/capability.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/discovery.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/host.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/session_target.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/models/snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/added.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/aws.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/aws_descriptor.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/builtin.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/hetzner.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/hetzner_descriptor.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/incus.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/incus_descriptor.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/proxmox.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/providers/proxmox_descriptor.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/api/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/api/hosts.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/api/pairing.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/api/setup.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/api/terminals.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/app.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/check.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/config.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/discovery.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/frames.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/health.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/logging_config.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/models.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/operator_auth.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/pairing.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/ssh_master.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/state.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/terminal.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/terminal_registry.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/src/remo_cli/web/tokens.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/ansible/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/ansible/test_apt_sources_repair.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/ansible/test_authorized_keys_bootstrap.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/ansible/test_remo_host_idempotency.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/conftest.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/fixtures.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/keyboard-routing.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/mobile.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/reconnect.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/terminal-shell-io.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/terminal-tui-compatibility.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/e2e/workspace-layout.spec.ts +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/image/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/image/test_docker_image.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/_nine_terminal_fixture.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/fish_completion.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/orbstack-cloud-init.yml +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/orbstack.sh +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_nine_terminals.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_nine_terminals_soak.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_registry_concurrency.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_remo_host_e2e.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_security_rejections.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_setup_payload_versions.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_sync_reconcile.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_terminal_attach.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_web_adopt_e2e.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/integration/test_web_cli_parity.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/perf/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/perf/test_latency.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/perf/test_registry_perf.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_aws_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_hetzner_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_incus_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_incus_sync_all.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_proxmox_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/providers/test_proxmox_sync_all.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/surface_baseline.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_add_cmd.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_cli_uniformity.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_cp.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_main.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_remove_cmd.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_shell.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_shell_added.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_startup_imports.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_surface_preservation.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/cli/test_web_adopt_cmd.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_ansible_runner.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_completion.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_config.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_errors.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_known_hosts.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_lifecycle.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_migration_tagging_notice.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_output.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_picker.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_provider_registry.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_reconcile.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_registry_format.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_registry_locking.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_registry_migration.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_remo_host_client.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_rsync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_ssh.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_ssh_added.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_ssh_controlpath.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_ssh_identity_opts.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_validation.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_version.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_authorize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_code.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_payload.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_trust.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_drift.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_push.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/core/test_web_push_self_heal.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/models/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/models/test_capability.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/models/test_discovery.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/models/test_session_target.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/fake_provider.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_added_add.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_added_provider_guard.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_added_update_remove.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_added_verify.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_aws_provider_protocol.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_aws_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_aws_sync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_aws_upgrade_resize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_entry_adapters.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_http.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_label.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_resize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_sync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_host_user_consistency.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_incus_entry_adapters.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_incus_marker.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_incus_resize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_incus_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_incus_sync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_missing_sdk.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_provider_conformance.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_provider_registry_entries.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_devcontainer_runtime.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_marker.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_provider_protocol.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_resize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_snapshot.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_sync.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_ansible_templates.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_architecture.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_docs_structure.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_host_model.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_host_ssh_type.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_lockfile_version.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/test_schema_drift.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/__init__.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/_pairing_support.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/conftest.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/fixtures/hosts_response.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/fixtures/sessions_response.json +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_backpressure.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_check.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_csp.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_discovery_refresh_force.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_frames.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_health_states.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_hosts_mapping.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_lazy_import.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_log_redaction.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_mint_gating.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_operator_auth.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_pairing.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_pairing_origin.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_payload_equivalence.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_registry_readonly.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_setup_api.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_setup_auth.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_setup_dormancy.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_state.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_terminal_resize.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_terminals_api.py +0 -0
- {remo_cli-4.0.1 → remo_cli-4.1.0}/tests/unit/web/test_tokens.py +0 -0
|
@@ -117,6 +117,7 @@ frontend/ # remo-web browser SPA (Vite + React + TypeScript)
|
|
|
117
117
|
├── src/
|
|
118
118
|
│ ├── api/client.ts # REST + WS terminal client (remo-terminal.v1 subprotocol)
|
|
119
119
|
│ ├── components/ # Dashboard, InstanceGroup, TargetCard, GridView, TabView, TerminalCard
|
|
120
|
+
│ │ # + masterLayout.ts (pure pane geometry: uniform grid + master/stack tiling)
|
|
120
121
|
│ ├── state/ # discovery.ts, workspace.ts (layout persisted to localStorage)
|
|
121
122
|
│ └── terminal/ # RendererAdapter (seam), XtermRenderer (the one engine), TerminalConnection, keymap
|
|
122
123
|
|
|
@@ -135,7 +136,8 @@ ansible/ # Ansible playbooks (invoked by Python via subprocess
|
|
|
135
136
|
└── requirements.yml
|
|
136
137
|
|
|
137
138
|
scripts/ # Repo-root utility scripts (not part of the installed package)
|
|
138
|
-
|
|
139
|
+
├── export_openapi.py # Exports frontend/src/api/generated/{openapi.json,terminal-frames.json} (feature 020)
|
|
140
|
+
└── palette-check.sh # Prints every ANSI colour x normal/bold/dim/bright in a live terminal — audits a theme's legibility where contrast maths can't
|
|
139
141
|
|
|
140
142
|
pyproject.toml # Build config, dependencies (incl. `web` extra), console_scripts entry point
|
|
141
143
|
```
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.1.0](https://github.com/get2knowio/remo/compare/v4.0.1...v4.1.0) (2026-08-04)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **web:** tile a terminal to a pane edge as a master area ([#137](https://github.com/get2knowio/remo/issues/137)) ([41802fb](https://github.com/get2knowio/remo/commit/41802fb17ae5741918a31ee9d662aa90808ebb9a))
|
|
9
|
+
|
|
3
10
|
## [4.0.1](https://github.com/get2knowio/remo/compare/v4.0.0...v4.0.1) (2026-08-03)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -117,6 +117,7 @@ frontend/ # remo-web browser SPA (Vite + React + TypeScript)
|
|
|
117
117
|
├── src/
|
|
118
118
|
│ ├── api/client.ts # REST + WS terminal client (remo-terminal.v1 subprotocol)
|
|
119
119
|
│ ├── components/ # Dashboard, InstanceGroup, TargetCard, GridView, TabView, TerminalCard
|
|
120
|
+
│ │ # + masterLayout.ts (pure pane geometry: uniform grid + master/stack tiling)
|
|
120
121
|
│ ├── state/ # discovery.ts, workspace.ts (layout persisted to localStorage), settings.ts (display prefs: site light/dark mode, accent, fonts, terminal theme + per-target overrides)
|
|
121
122
|
│ ├── terminal/ # RendererAdapter (seam), XtermRenderer (the one engine), TerminalConnection, keymap
|
|
122
123
|
│ └── theme/ # tokens.css (light-dark() palette, one pair per token), fonts.ts, terminalThemes.ts (8 terminal color schemes: a token-derived Remo Dark/Light pair the default 'auto' selection tracks, plus 6 curated third-party)
|
|
@@ -136,7 +137,8 @@ ansible/ # Ansible playbooks (invoked by Python via subprocess
|
|
|
136
137
|
└── requirements.yml
|
|
137
138
|
|
|
138
139
|
scripts/ # Repo-root utility scripts (not part of the installed package)
|
|
139
|
-
|
|
140
|
+
├── export_openapi.py # Exports frontend/src/api/generated/{openapi.json,terminal-frames.json} (feature 020)
|
|
141
|
+
└── palette-check.sh # Prints every ANSI colour x normal/bold/dim/bright in a live terminal — audits a theme's legibility where contrast maths can't
|
|
140
142
|
|
|
141
143
|
pyproject.toml # Build config, dependencies (incl. `web` extra), console_scripts entry point
|
|
142
144
|
```
|
|
@@ -108,7 +108,16 @@ The SPA is a two-pane **web console**:
|
|
|
108
108
|
row (or its `+` button) **adds** it to a responsive grid (1/2/3 columns by count). In a grid, **drag
|
|
109
109
|
a tile's header onto another to swap their positions** — a window outline follows the cursor and the
|
|
110
110
|
swap target shows a dashed outline (mouse or touch press-and-hold; keyboard-accessible via the
|
|
111
|
-
handle); the arrangement persists until the grid is rebuilt.
|
|
111
|
+
handle); the arrangement persists until the grid is rebuilt. **Drag a tile to a pane edge instead of
|
|
112
|
+
onto another tile** and it takes that whole side as a *master area* — full height on the left/right,
|
|
113
|
+
full width on the top/bottom — with the remaining tiles tiling the leftover strip (the dwm/xmonad
|
|
114
|
+
master+stack model). A translucent band marks each edge while dragging and fills in when the drop
|
|
115
|
+
would land there. The **▦** control in a tile's header cycles the same thing without a drag
|
|
116
|
+
(▌ left → ▀ top → ▐ right → ▄ bottom → back to the even grid), which is the practical path on a touch
|
|
117
|
+
device. The master takes 60% by default, closing it promotes the head of the stack rather than
|
|
118
|
+
un-tiling everything, and the arrangement persists across reload alongside the tile order. This is
|
|
119
|
+
what lets three terminals fill the pane without the empty fourth cell a 2x2 grid would leave. In a
|
|
120
|
+
grid, **resting the pointer on a
|
|
112
121
|
tile focuses it** (focus-follows-mouse, with a short dwell so passing through tiles doesn't steal
|
|
113
122
|
focus) — keystrokes go where the pointer is, no click needed. The **◻** control solos a tile; **Esc**
|
|
114
123
|
collapses the grid back to the focused terminal;
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
type TerminalFontOptions,
|
|
31
31
|
} from "../state/settings";
|
|
32
32
|
import { TERMINAL_THEMES, type TerminalThemeColors } from "../theme/terminalThemes";
|
|
33
|
+
import type { MasterSide } from "../state/workspace";
|
|
33
34
|
import { removeLatency, reportLatency } from "../state/latency";
|
|
34
35
|
import type { RendererAdapter } from "../terminal/RendererAdapter";
|
|
35
36
|
import { createDefaultRenderer } from "../terminal/defaultRenderer";
|
|
@@ -41,6 +42,16 @@ const DEFAULT_ROWS = 24;
|
|
|
41
42
|
/** How much to shrink the terminal font in a grid tile when "scale to fit". */
|
|
42
43
|
const GRID_FIT_SCALE = 0.8;
|
|
43
44
|
|
|
45
|
+
/** Glyph + label per tiling state. The glyph is a half block drawing where the
|
|
46
|
+
* master area sits, so the button reads as a picture of the layout. */
|
|
47
|
+
const MASTER_GLYPH: Record<MasterSide | "grid", { glyph: string; title: string }> = {
|
|
48
|
+
grid: { glyph: "▦", title: "Tile this terminal to the left" },
|
|
49
|
+
left: { glyph: "▌", title: "Mastering the left — tile to the top" },
|
|
50
|
+
top: { glyph: "▀", title: "Mastering the top — tile to the right" },
|
|
51
|
+
right: { glyph: "▐", title: "Mastering the right — tile to the bottom" },
|
|
52
|
+
bottom: { glyph: "▄", title: "Mastering the bottom — back to the even grid" },
|
|
53
|
+
};
|
|
54
|
+
|
|
44
55
|
const STATE_LABELS: Record<TerminalConnectionState, string> = {
|
|
45
56
|
connecting: "Connecting…",
|
|
46
57
|
ready: "Connected",
|
|
@@ -70,6 +81,16 @@ interface TerminalCardProps {
|
|
|
70
81
|
/** When true, the header acts as a dnd-kit drag handle and the tile is a drop
|
|
71
82
|
* target (grid reorder). The DndContext + swap live in WorkspacePane. */
|
|
72
83
|
reorderEnabled?: boolean;
|
|
84
|
+
/** This tile's slot in a master/stack tiling, as a CSS `grid-area`. Undefined
|
|
85
|
+
* in the uniform grid, where tiles auto-place exactly as they always have.
|
|
86
|
+
* Applied to the card's OWN root element — never a wrapper, see WorkspacePane. */
|
|
87
|
+
gridArea?: string;
|
|
88
|
+
/** Which side this tile masters, or null when it is a plain stack tile.
|
|
89
|
+
* Undefined hides the tiling control entirely (single view, fullscreen). */
|
|
90
|
+
masterSide?: MasterSide | null;
|
|
91
|
+
/** Advance this tile through the tiling cycle (left -> top -> right -> bottom
|
|
92
|
+
* -> uniform grid). */
|
|
93
|
+
onCycleTile?: () => void;
|
|
73
94
|
/** Window-control "Normal": solo this terminal into the single view. */
|
|
74
95
|
onNormal: () => void;
|
|
75
96
|
/** Window-control "Grid": show the grid — omitted when none is available. */
|
|
@@ -173,6 +194,9 @@ export function TerminalCard({
|
|
|
173
194
|
viewState,
|
|
174
195
|
onClose,
|
|
175
196
|
reorderEnabled,
|
|
197
|
+
gridArea,
|
|
198
|
+
masterSide,
|
|
199
|
+
onCycleTile,
|
|
176
200
|
onNormal,
|
|
177
201
|
onGrid,
|
|
178
202
|
onToggleFullscreen,
|
|
@@ -544,6 +568,7 @@ export function TerminalCard({
|
|
|
544
568
|
style={
|
|
545
569
|
{
|
|
546
570
|
display: isVisible ? undefined : "none",
|
|
571
|
+
gridArea,
|
|
547
572
|
"--bg-term": theme.colors.background,
|
|
548
573
|
} as CSSProperties
|
|
549
574
|
}
|
|
@@ -672,6 +697,26 @@ export function TerminalCard({
|
|
|
672
697
|
</div>
|
|
673
698
|
)}
|
|
674
699
|
</div>
|
|
700
|
+
{/* Tiling control. Cycles rather than opening a menu: it is one tap on
|
|
701
|
+
* a touch device, where dragging to a 64px edge band with a thumb is
|
|
702
|
+
* the awkward path. The half-block glyphs draw where the master area
|
|
703
|
+
* lands, so the current state is legible without the tooltip. */}
|
|
704
|
+
{onCycleTile && (
|
|
705
|
+
<button
|
|
706
|
+
type="button"
|
|
707
|
+
className={`tc-btn tc-btn--icon${masterSide ? " tc-btn--active" : ""}`}
|
|
708
|
+
data-testid={`terminal-tile-${target.id}`}
|
|
709
|
+
title={MASTER_GLYPH[masterSide ?? "grid"].title}
|
|
710
|
+
aria-label={MASTER_GLYPH[masterSide ?? "grid"].title}
|
|
711
|
+
aria-pressed={Boolean(masterSide)}
|
|
712
|
+
onClick={(e) => {
|
|
713
|
+
e.stopPropagation();
|
|
714
|
+
onCycleTile();
|
|
715
|
+
}}
|
|
716
|
+
>
|
|
717
|
+
{MASTER_GLYPH[masterSide ?? "grid"].glyph}
|
|
718
|
+
</button>
|
|
719
|
+
)}
|
|
675
720
|
{/* Window-control cluster: mutually-exclusive display modes ordered
|
|
676
721
|
* by how much space they take — Grid (smaller/tiled) → Normal (fills
|
|
677
722
|
* the app's main pane) → Fullscreen (whole window) — plus close. The
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
.workspace {
|
|
2
|
+
flex: 1;
|
|
3
|
+
min-width: 0;
|
|
4
|
+
min-height: 0;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
background: var(--bg-pane);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.workspace-body {
|
|
11
|
+
flex: 1;
|
|
12
|
+
min-height: 0;
|
|
13
|
+
padding: 12px;
|
|
14
|
+
gap: 10px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.workspace-body--single {
|
|
18
|
+
display: flex;
|
|
19
|
+
flex-direction: column;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.workspace-body--grid {
|
|
23
|
+
display: grid;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* Containing block for the snap zones below, and a stop for touch scroll
|
|
27
|
+
* chaining while dragging a tile around. */
|
|
28
|
+
.workspace-body {
|
|
29
|
+
position: relative;
|
|
30
|
+
overscroll-behavior: contain;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* --- edge drop targets (master/stack tiling) ---
|
|
34
|
+
*
|
|
35
|
+
* `pointer-events: none` is load-bearing, not a tidy-up: dnd-kit resolves drops
|
|
36
|
+
* from measured rects rather than hit-testing, so these can blanket the pane
|
|
37
|
+
* edges without intercepting anything — including the rail's resize handle,
|
|
38
|
+
* which overhangs 3px into this pane's left edge.
|
|
39
|
+
*
|
|
40
|
+
* z-index 20 sits in the free band between the rail divider (8) and the terminal
|
|
41
|
+
* theme popup (60). */
|
|
42
|
+
.workspace-snap {
|
|
43
|
+
position: absolute;
|
|
44
|
+
z-index: 20;
|
|
45
|
+
pointer-events: none;
|
|
46
|
+
opacity: 0;
|
|
47
|
+
border-radius: var(--radius-lg);
|
|
48
|
+
border: 2px dashed transparent;
|
|
49
|
+
background: color-mix(in oklch, var(--accent) 14%, transparent);
|
|
50
|
+
}
|
|
51
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
52
|
+
.workspace-snap {
|
|
53
|
+
transition: opacity 120ms ease;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/* Visible but quiet while a drag is in flight, solid once it would land here. */
|
|
57
|
+
.workspace-snap--armed {
|
|
58
|
+
opacity: 0.4;
|
|
59
|
+
}
|
|
60
|
+
.workspace-snap--over {
|
|
61
|
+
opacity: 1;
|
|
62
|
+
border-color: var(--accent-strong);
|
|
63
|
+
background: color-mix(in oklch, var(--accent) 28%, transparent);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.workspace-snap--left,
|
|
67
|
+
.workspace-snap--right {
|
|
68
|
+
top: 0;
|
|
69
|
+
bottom: 0;
|
|
70
|
+
width: min(64px, 18%);
|
|
71
|
+
}
|
|
72
|
+
.workspace-snap--left {
|
|
73
|
+
left: 0;
|
|
74
|
+
}
|
|
75
|
+
.workspace-snap--right {
|
|
76
|
+
right: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* Inset horizontally by the same band, so the CORNERS belong unambiguously to
|
|
80
|
+
* left/right — the vertical split is what this feature is for, and an overlap
|
|
81
|
+
* would resolve a corner by centre distance, i.e. arbitrarily. */
|
|
82
|
+
.workspace-snap--top,
|
|
83
|
+
.workspace-snap--bottom {
|
|
84
|
+
left: min(64px, 18%);
|
|
85
|
+
right: min(64px, 18%);
|
|
86
|
+
height: min(64px, 18%);
|
|
87
|
+
}
|
|
88
|
+
.workspace-snap--top {
|
|
89
|
+
top: 0;
|
|
90
|
+
}
|
|
91
|
+
.workspace-snap--bottom {
|
|
92
|
+
bottom: 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/* Empty state */
|
|
96
|
+
.workspace-empty {
|
|
97
|
+
flex: 1;
|
|
98
|
+
display: flex;
|
|
99
|
+
flex-direction: column;
|
|
100
|
+
align-items: center;
|
|
101
|
+
justify-content: center;
|
|
102
|
+
text-align: center;
|
|
103
|
+
padding: 24px;
|
|
104
|
+
color: var(--text-dim);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.workspace-empty-art {
|
|
108
|
+
font-family: var(--font-mono);
|
|
109
|
+
font-size: 13px;
|
|
110
|
+
line-height: 1.25;
|
|
111
|
+
color: color-mix(in oklch, var(--accent) 55%, var(--text-faint));
|
|
112
|
+
margin: 0 0 18px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.workspace-empty-title {
|
|
116
|
+
font-size: 15px;
|
|
117
|
+
font-weight: 600;
|
|
118
|
+
color: var(--text-1);
|
|
119
|
+
margin-bottom: 7px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.workspace-empty-text {
|
|
123
|
+
font-size: 12.5px;
|
|
124
|
+
max-width: 340px;
|
|
125
|
+
line-height: 1.6;
|
|
126
|
+
margin: 0 0 4px;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.workspace-empty-text kbd,
|
|
130
|
+
.workspace-empty-text span {
|
|
131
|
+
color: var(--text-1);
|
|
132
|
+
font-family: var(--font-mono);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.workspace-empty-hint {
|
|
136
|
+
font-size: 11.5px;
|
|
137
|
+
color: var(--text-faint);
|
|
138
|
+
font-family: var(--font-mono);
|
|
139
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// WorkspacePane's wiring: does the computed layout actually reach the DOM, and
|
|
2
|
+
// — the one that matters — can a layout change ever remount a TerminalCard?
|
|
3
|
+
//
|
|
4
|
+
// A remount re-runs the card's [target.id] effect, whose cleanup calls
|
|
5
|
+
// connection.close() and adapter.dispose(): the SSH connection drops and the
|
|
6
|
+
// scrollback goes with it. Master/stack changes which slot a tile occupies on
|
|
7
|
+
// every mastership change, so this is the feature's central structural risk.
|
|
8
|
+
// The guarantee is "one flat keyed child list; slots are grid-area styles on
|
|
9
|
+
// each card's own root, never wrapper elements", and the test below is what
|
|
10
|
+
// proves it rather than merely documenting it.
|
|
11
|
+
|
|
12
|
+
import { act, render, screen } from "@testing-library/react";
|
|
13
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
14
|
+
import type { SessionTarget } from "../api/client";
|
|
15
|
+
|
|
16
|
+
const adapters: { dispose: ReturnType<typeof vi.fn> }[] = [];
|
|
17
|
+
|
|
18
|
+
vi.mock("../terminal/defaultRenderer", () => ({
|
|
19
|
+
createDefaultRenderer: vi.fn(() => {
|
|
20
|
+
const adapter = {
|
|
21
|
+
open: vi.fn(),
|
|
22
|
+
write: vi.fn(),
|
|
23
|
+
onData: vi.fn().mockReturnValue(() => {}),
|
|
24
|
+
fit: vi.fn().mockReturnValue({ cols: 80, rows: 24 }),
|
|
25
|
+
resize: vi.fn(),
|
|
26
|
+
applyFont: vi.fn(),
|
|
27
|
+
applyTheme: vi.fn(),
|
|
28
|
+
focus: vi.fn(),
|
|
29
|
+
onTitleChange: vi.fn().mockReturnValue(() => {}),
|
|
30
|
+
onSelectionChange: vi.fn().mockReturnValue(() => {}),
|
|
31
|
+
getSelection: vi.fn().mockReturnValue(null),
|
|
32
|
+
copySelection: vi.fn().mockResolvedValue(false),
|
|
33
|
+
dispose: vi.fn(),
|
|
34
|
+
};
|
|
35
|
+
adapters.push(adapter);
|
|
36
|
+
return adapter;
|
|
37
|
+
}),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
vi.mock("../terminal/TerminalConnection", () => ({
|
|
41
|
+
TerminalConnection: class {
|
|
42
|
+
needsManualReconnect = false;
|
|
43
|
+
connect = vi.fn().mockResolvedValue(undefined);
|
|
44
|
+
close = vi.fn().mockResolvedValue(undefined);
|
|
45
|
+
sendInput = vi.fn();
|
|
46
|
+
sendResize = vi.fn();
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
// jsdom has neither; useDroppable and TerminalCard both observe their nodes.
|
|
51
|
+
class NoopResizeObserver {
|
|
52
|
+
observe(): void {}
|
|
53
|
+
unobserve(): void {}
|
|
54
|
+
disconnect(): void {}
|
|
55
|
+
}
|
|
56
|
+
globalThis.ResizeObserver = NoopResizeObserver as unknown as typeof ResizeObserver;
|
|
57
|
+
|
|
58
|
+
const target = (id: string): SessionTarget =>
|
|
59
|
+
({ id, project: id, instance_type: "incus", instance_name: "box" }) as unknown as SessionTarget;
|
|
60
|
+
|
|
61
|
+
async function mount(ids: string[]) {
|
|
62
|
+
vi.resetModules();
|
|
63
|
+
window.localStorage.clear();
|
|
64
|
+
adapters.length = 0;
|
|
65
|
+
const workspaceMod = await import("../state/workspace");
|
|
66
|
+
const { WorkspacePane } = await import("./WorkspacePane");
|
|
67
|
+
const targetsById = new Map(ids.map((id) => [id, target(id)]));
|
|
68
|
+
|
|
69
|
+
const view = render(
|
|
70
|
+
<WorkspacePane
|
|
71
|
+
targetsById={targetsById}
|
|
72
|
+
regionByKey={new Map()}
|
|
73
|
+
onTerminalEnded={() => {}}
|
|
74
|
+
onTerminalStarted={() => {}}
|
|
75
|
+
narrow={false}
|
|
76
|
+
/>,
|
|
77
|
+
);
|
|
78
|
+
// Drive the store directly: the rail isn't mounted here.
|
|
79
|
+
const store = renderStore(workspaceMod);
|
|
80
|
+
act(() => store.openMany(ids.map(target)));
|
|
81
|
+
return { view, store };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The store's actions, outside React. `useWorkspace` returns them, but this
|
|
85
|
+
* file never renders a consumer of its own. */
|
|
86
|
+
function renderStore(mod: typeof import("../state/workspace")) {
|
|
87
|
+
let api!: ReturnType<typeof mod.useWorkspace>;
|
|
88
|
+
function Probe(): null {
|
|
89
|
+
api = mod.useWorkspace();
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
render(<Probe />);
|
|
93
|
+
return new Proxy({} as ReturnType<typeof mod.useWorkspace>, {
|
|
94
|
+
get: (_t, key) => api[key as keyof typeof api],
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const body = (): HTMLElement => screen.getByTestId("workspace").querySelector(".workspace-body")!;
|
|
99
|
+
|
|
100
|
+
beforeEach(() => {
|
|
101
|
+
window.localStorage.clear();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe("WorkspacePane layout wiring", () => {
|
|
105
|
+
it("renders the uniform grid exactly as before when nothing is tiled", async () => {
|
|
106
|
+
await mount(["a", "b", "c"]);
|
|
107
|
+
expect(body().style.gridTemplateColumns).toBe("repeat(2, minmax(0, 1fr))");
|
|
108
|
+
expect(body().style.gridTemplateRows).toBe("repeat(2, minmax(0, 1fr))");
|
|
109
|
+
// No explicit placement: tiles auto-place, as they always have.
|
|
110
|
+
expect(screen.getByTestId("terminal-card-a").style.gridArea).toBe("");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("pushes the master template and every tile's slot into the DOM", async () => {
|
|
114
|
+
const { store } = await mount(["a", "b", "c"]);
|
|
115
|
+
act(() => store.setMaster("c", "right"));
|
|
116
|
+
|
|
117
|
+
expect(body().style.gridTemplateColumns).toBe("repeat(1, minmax(0, 40fr)) minmax(0, 60fr)");
|
|
118
|
+
expect(screen.getByTestId("terminal-card-c").style.gridArea).toBe("1 / 2 / 3 / 3");
|
|
119
|
+
expect(screen.getByTestId("terminal-card-a").style.gridArea).toBe("1 / 1 / 2 / 2");
|
|
120
|
+
expect(screen.getByTestId("terminal-card-b").style.gridArea).toBe("2 / 1 / 3 / 2");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("offers the four edge zones only while a reorder is possible", async () => {
|
|
124
|
+
const { store } = await mount(["a", "b", "c"]);
|
|
125
|
+
expect(screen.getAllByTestId(/^snap-zone-/)).toHaveLength(4);
|
|
126
|
+
|
|
127
|
+
// Single view: nothing to reorder, nothing to snap onto.
|
|
128
|
+
act(() => store.selectOnly(target("a")));
|
|
129
|
+
expect(screen.queryAllByTestId(/^snap-zone-/)).toHaveLength(0);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("hides the edge zones while a terminal is fullscreen", async () => {
|
|
133
|
+
const { store } = await mount(["a", "b"]);
|
|
134
|
+
act(() => store.maximize("a"));
|
|
135
|
+
expect(screen.queryAllByTestId(/^snap-zone-/)).toHaveLength(0);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// THE structural guarantee. Mutation: wrap the master (or the stack) in a
|
|
139
|
+
// slot <div> in WorkspacePane and this must fail — a card changing parent
|
|
140
|
+
// remounts, dropping its SSH connection and scrollback.
|
|
141
|
+
it("never remounts a terminal across layout changes", async () => {
|
|
142
|
+
const { store } = await mount(["a", "b", "c"]);
|
|
143
|
+
const surfaceBefore = screen.getByTestId("terminal-surface-a");
|
|
144
|
+
const buildsBefore = adapters.length;
|
|
145
|
+
|
|
146
|
+
act(() => store.setMaster("a", "left"));
|
|
147
|
+
act(() => store.setMaster("a", "top"));
|
|
148
|
+
act(() => store.setMaster("b", "right"));
|
|
149
|
+
act(() => store.clearMaster());
|
|
150
|
+
|
|
151
|
+
expect(Object.is(screen.getByTestId("terminal-surface-a"), surfaceBefore)).toBe(true);
|
|
152
|
+
expect(adapters).toHaveLength(buildsBefore);
|
|
153
|
+
for (const adapter of adapters) {
|
|
154
|
+
expect(adapter.dispose).not.toHaveBeenCalled();
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("cycles a tile through the sides from its header control", async () => {
|
|
159
|
+
const { store } = await mount(["a", "b"]);
|
|
160
|
+
const button = (): HTMLElement => screen.getByTestId("terminal-tile-a");
|
|
161
|
+
|
|
162
|
+
act(() => button().click());
|
|
163
|
+
expect(store.layout).toMatchObject({ kind: "master", id: "a", side: "left" });
|
|
164
|
+
expect(button().getAttribute("aria-pressed")).toBe("true");
|
|
165
|
+
|
|
166
|
+
act(() => button().click());
|
|
167
|
+
expect(store.layout).toMatchObject({ side: "top" });
|
|
168
|
+
|
|
169
|
+
act(() => button().click());
|
|
170
|
+
act(() => button().click());
|
|
171
|
+
act(() => button().click());
|
|
172
|
+
expect(store.layout).toEqual({ kind: "grid" });
|
|
173
|
+
expect(button().getAttribute("aria-pressed")).toBe("false");
|
|
174
|
+
});
|
|
175
|
+
});
|