remo-cli 4.0.0__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.0 → remo_cli-4.1.0}/AGENTS.md +3 -1
- {remo_cli-4.0.0 → remo_cli-4.1.0}/CHANGELOG.md +15 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/CLAUDE.md +3 -1
- {remo_cli-4.0.0 → remo_cli-4.1.0}/PKG-INFO +1 -1
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/web-session-interface.md +10 -1
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.css +11 -4
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.test.tsx +57 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/TerminalCard.tsx +157 -3
- 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.0 → 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.0 → remo_cli-4.1.0}/frontend/src/state/workspace.ts +156 -8
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/theme/terminalThemes.test.ts +51 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/theme/terminalThemes.ts +11 -2
- {remo_cli-4.0.0 → remo_cli-4.1.0}/pyproject.toml +1 -1
- remo_cli-4.1.0/scripts/palette-check.sh +67 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_discovery.py +57 -18
- {remo_cli-4.0.0 → remo_cli-4.1.0}/uv.lock +1 -1
- remo_cli-4.0.0/.release-please-manifest.json +0 -3
- remo_cli-4.0.0/frontend/src/components/WorkspacePane.css +0 -70
- remo_cli-4.0.0/frontend/src/state/workspace.test.ts +0 -98
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/release/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-analyze/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-checklist/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-clarify/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-constitution/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-converge/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-git-commit/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-git-feature/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-git-initialize/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-git-remote/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-git-validate/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-implement/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-plan/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-specify/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-tasks/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.claude/skills/speckit-taskstoissues/SKILL.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.devcontainer/devcontainer.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.dockerignore +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/CODEOWNERS +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/dependabot.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/ci.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/codeql.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/dependency-review.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/dev-build.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/provision.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/release-please.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/release.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/smoke-test-cleanup.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/smoke-test.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.github/workflows/teardown.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.gitignore +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.maverick/checkpoints/feature/implementation_complete.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.maverick/checkpoints/feature/phase_${{ index }}_complete.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.maverick/checkpoints/feature/validation_complete.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/.registry +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/README.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.commit.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.feature.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.initialize.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.remote.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/commands/speckit.git.validate.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/config-template.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/extension.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/git-config.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/auto-commit.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/create-new-feature.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/git-common.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/bash/initialize-repo.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/auto-commit.ps1 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/create-new-feature.ps1 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/git-common.ps1 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions/git/scripts/powershell/initialize-repo.ps1 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/extensions.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/feature.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/init-options.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/integration.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/integrations/claude.manifest.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/integrations/speckit.manifest.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/memory/constitution.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/check-prerequisites.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/common.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/create-new-feature.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/setup-plan.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/setup-tasks.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/scripts/bash/update-agent-context.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/agent-file-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/checklist-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/constitution-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/plan-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/spec-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/templates/tasks-template.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/workflows/speckit/workflow.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/.specify/workflows/workflow-registry.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/CONTRIBUTING.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/Dockerfile +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/LICENSE +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/README.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/SECURITY.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/.ansible-lint +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/README.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/ansible.cfg +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/aws_configure.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/aws_resize.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/aws_site.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/aws_teardown.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/group_vars/all.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/group_vars/incus_containers.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/group_vars/proxmox_containers.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/hetzner_configure.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/hetzner_provision.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/hetzner_resize.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/hetzner_site.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/hetzner_teardown.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_bootstrap.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_configure.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_provision.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_resize.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_site.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/incus_teardown.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/inventory/hosts.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/inventory/incus_containers.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_bootstrap.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_configure.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_provision.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_resize.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_site.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/proxmox_teardown.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/requirements.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/ebs.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/ec2.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/patch_manager.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/preflight.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/aws_server/tasks/security_group.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/deacon/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/deacon/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/devcontainers/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/docker/handlers/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/docker/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/fzf/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/github_cli/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/hetzner_server/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/hetzner_server/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/handlers/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_bootstrap/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container/handlers/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container/meta/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container/tasks/preflight.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/meta/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/incus_container_teardown/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/nodejs/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/nodejs/files/nodesource-repo.gpg.key +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/nodejs/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/meta/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_bootstrap/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container/handlers/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container/meta/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container/tasks/preflight.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/meta/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/proxmox_container_teardown/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/devshell.sh.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/project-launch.sh.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/project-menu.sh.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/user_setup/templates/remo-host.sh.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/zellij/defaults/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/zellij/tasks/main.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/zellij/templates/config.kdl.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/roles/zellij/templates/layouts/minimal.kdl.j2 +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/tasks/configure_dev_tools.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/ansible/tasks/repair_apt_sources.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docker/Dockerfile +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docker/compose.example.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docker/entrypoint.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/aws.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/feature-history.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/hetzner.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/incus.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/install.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/maintaining-claude-md.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/maintaining-generated-types.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/providers.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/proxmox.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/remo-web-speckit-input.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/docs/remo-web.html +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/index.html +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/package-lock.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/package.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/scripts/check-types-fresh.mjs +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/scripts/generate-frame-types.mjs +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/scripts/generate-schema-types.mjs +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/client.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/client.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated/README.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated/openapi.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated/schema.d.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated/terminal-frames.d.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated/terminal-frames.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/api/generated.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/AppRoot.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/AppShell.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/AppShell.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/AwaitingAdoption.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/AwaitingAdoption.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/OfflineOverlay.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/OfflineOverlay.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/PairToSync.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/PairToSync.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/SessionRail.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/SessionRail.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/SettingsPage.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/SettingsPage.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/ShortcutsModal.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/ShortcutsModal.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/TopBar.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/TopBar.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/providerMeta.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/providerMeta.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/railModel.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/components/railModel.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/lib/clipboard.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/lib/fullscreen.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/main.tsx +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/discovery.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/discovery.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/fonts.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/health.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/health.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/latency.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/latency.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/settings.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/settings.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/state/useConsoleKeyboard.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/.gitkeep +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/RendererAdapter.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/TerminalConnection.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/TerminalConnection.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/XtermRenderer.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/defaultRenderer.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/keymap.test.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/terminal/keymap.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/test/setup.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/theme/fonts.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/src/theme/tokens.css +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/tsconfig.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/frontend/vite.config.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/install.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/maverick.yaml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/playwright.config.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/project-menu.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/release-please-config.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/remo +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/remo.svg +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/run.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/scripts/export_openapi.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/scripts/setup-aws-oidc.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/checklists/validation.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/contracts/playbook-interface.yaml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/contracts/role-interface.yaml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/001-bootstrap-incus-host/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/contracts/playbook-interface.yaml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/contracts/role-interface.yaml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/002-incus-container-support/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/003-python-cli-rewrite/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/004-proxmox-container-support/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/005-provider-snapshots/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/remo-host-protocol.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/rest-api.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/contracts/terminal-websocket.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/010-web-session-interface/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/contracts/cli-web-adopt.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/contracts/setup-api.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/quickstart-results.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/011-web-adopt/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/cli-web-adopt.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/pairing-api.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/contracts/setup-api.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/012-web-adopt-pairing/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/contracts/cli-sync.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/contracts/marker-commands.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/013-managed-instance-tags/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/contracts/add-command.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/contracts/remove-command.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/014-register-ssh-host/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/mirror-payload-v2.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/registry-accessor-api.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/contracts/registry-file-v2.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/015-registry-v2/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/contracts/cli-sync.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/contracts/provider-probe.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/016-sync-reconcile/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/cli-web-push.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/cli-web-status.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/revocation.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/contracts/setup-status-marker.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/017-web-adopt-simplify/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/baseline-notes.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/errors.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/lifecycle-templates.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/provider-protocol.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/contracts/sync-merge.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/018-provider-abstraction/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/contracts/cli-surface-delta.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/contracts/docs-structure-check.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/019-hygiene-deps-docs/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/checklists/requirements.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/contracts/drift-checks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/contracts/terminal-frames-v1.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/020-openapi-type-generation/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/contracts/cli-surface.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/contracts/descriptor-schema.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/data-model.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/plan.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/quickstart.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/research.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/spec.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/specs/021-cli-plane-separation/tasks.md +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/__main__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/added.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/cp.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/main.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/providers/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/providers/factory.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/shell.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/cli/web.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/ansible_runner.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/completion.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/config.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/errors.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/known_hosts.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/lifecycle.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/output.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/picker.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/provider_protocol.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/provider_registry.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/reconcile.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/registry.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/remo_host_client.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/rsync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/ssh.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/validation.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/version.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/web_adopt.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/core/web_drift.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/capability.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/discovery.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/host.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/session_target.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/models/snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/added.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/aws.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/aws_descriptor.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/builtin.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/hetzner.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/hetzner_descriptor.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/incus.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/incus_descriptor.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/proxmox.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/providers/proxmox_descriptor.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/api/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/api/hosts.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/api/pairing.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/api/setup.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/api/terminals.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/app.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/check.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/config.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/discovery.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/frames.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/health.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/logging_config.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/models.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/operator_auth.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/pairing.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/ssh_master.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/state.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/terminal.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/terminal_registry.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/src/remo_cli/web/tokens.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/ansible/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/ansible/test_apt_sources_repair.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/ansible/test_authorized_keys_bootstrap.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/ansible/test_remo_host_idempotency.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/conftest.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/fixtures.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/keyboard-routing.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/mobile.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/reconnect.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/terminal-shell-io.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/terminal-tui-compatibility.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/e2e/workspace-layout.spec.ts +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/image/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/image/test_docker_image.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/_nine_terminal_fixture.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/fish_completion.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/orbstack-cloud-init.yml +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/orbstack.sh +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_nine_terminals.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_nine_terminals_soak.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_registry_concurrency.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_remo_host_e2e.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_security_rejections.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_setup_payload_versions.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_sync_reconcile.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_terminal_attach.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_web_adopt_e2e.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/integration/test_web_cli_parity.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/perf/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/perf/test_latency.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/perf/test_registry_perf.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_aws_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_hetzner_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_incus_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_incus_sync_all.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_proxmox_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/providers/test_proxmox_sync_all.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/surface_baseline.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_add_cmd.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_cli_uniformity.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_cp.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_main.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_remove_cmd.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_shell.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_shell_added.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_startup_imports.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_surface_preservation.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/cli/test_web_adopt_cmd.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_ansible_runner.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_completion.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_config.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_errors.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_known_hosts.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_lifecycle.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_migration_tagging_notice.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_output.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_picker.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_provider_registry.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_reconcile.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_registry_format.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_registry_locking.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_registry_migration.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_remo_host_client.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_rsync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_ssh.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_ssh_added.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_ssh_controlpath.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_ssh_identity_opts.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_validation.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_version.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_authorize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_code.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_payload.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_adopt_trust.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_drift.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_push.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/core/test_web_push_self_heal.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/models/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/models/test_capability.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/models/test_discovery.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/models/test_session_target.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/fake_provider.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_added_add.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_added_provider_guard.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_added_update_remove.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_added_verify.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_aws_provider_protocol.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_aws_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_aws_sync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_aws_upgrade_resize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_entry_adapters.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_http.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_label.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_resize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_hetzner_sync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_host_user_consistency.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_incus_entry_adapters.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_incus_marker.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_incus_resize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_incus_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_incus_sync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_missing_sdk.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_provider_conformance.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_provider_registry_entries.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_devcontainer_runtime.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_marker.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_provider_protocol.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_resize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_snapshot.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/providers/test_proxmox_sync.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_ansible_templates.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_architecture.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_docs_structure.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_host_model.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_host_ssh_type.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_lockfile_version.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/test_schema_drift.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/__init__.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/_pairing_support.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/conftest.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/fixtures/hosts_response.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/fixtures/sessions_response.json +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_backpressure.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_check.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_csp.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_discovery_refresh_force.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_frames.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_health_states.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_hosts_mapping.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_lazy_import.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_log_redaction.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_mint_gating.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_operator_auth.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_pairing.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_pairing_origin.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_payload_equivalence.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_registry_readonly.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_setup_api.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_setup_auth.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_setup_dormancy.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_state.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_terminal_resize.py +0 -0
- {remo_cli-4.0.0 → remo_cli-4.1.0}/tests/unit/web/test_terminals_api.py +0 -0
- {remo_cli-4.0.0 → 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,20 @@
|
|
|
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
|
+
|
|
10
|
+
## [4.0.1](https://github.com/get2knowio/remo/compare/v4.0.0...v4.0.1) (2026-08-03)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **web:** let the terminal-theme menu scroll instead of being clipped ([#134](https://github.com/get2knowio/remo/issues/134)) ([ffb34e7](https://github.com/get2knowio/remo/commit/ffb34e72cc9d1744130130934538d38af217ec73))
|
|
16
|
+
* **web:** make Remo Light's white family visible — `white` and `brightWhite` were 1.27:1 and 1.09:1 against the background, hiding dim and bold text ([#134](https://github.com/get2knowio/remo/issues/134)) ([c5bc07a](https://github.com/get2knowio/remo/commit/c5bc07a7))
|
|
17
|
+
|
|
3
18
|
## [4.0.0](https://github.com/get2knowio/remo/compare/v3.1.0...v4.0.0) (2026-08-03)
|
|
4
19
|
|
|
5
20
|
|
|
@@ -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;
|
|
@@ -228,16 +228,23 @@
|
|
|
228
228
|
border-color: var(--accent-strong);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
/* Positioned against the viewport from JS (themeMenuPosition) — `position`,
|
|
232
|
+
* `top`/`bottom`, `left` and `max-height` all arrive as inline styles. It has
|
|
233
|
+
* to escape `.terminal-card`'s `overflow: hidden`, which used to clip the list
|
|
234
|
+
* inside a short grid tile with no way to scroll to the rest. */
|
|
231
235
|
.tc-theme-menu {
|
|
232
|
-
position:
|
|
233
|
-
|
|
234
|
-
right: 0;
|
|
235
|
-
z-index: 20;
|
|
236
|
+
position: fixed;
|
|
237
|
+
z-index: 60;
|
|
236
238
|
min-width: 216px;
|
|
239
|
+
max-width: calc(100vw - 16px);
|
|
237
240
|
padding: 5px;
|
|
238
241
|
display: flex;
|
|
239
242
|
flex-direction: column;
|
|
240
243
|
gap: 2px;
|
|
244
|
+
overflow-y: auto;
|
|
245
|
+
/* Stop at the menu's own edges instead of scrolling the page behind it —
|
|
246
|
+
* the whole reported symptom was a swipe here moving the whole console. */
|
|
247
|
+
overscroll-behavior: contain;
|
|
241
248
|
background: var(--bg-elev);
|
|
242
249
|
border: 1px solid var(--border-strong);
|
|
243
250
|
border-radius: 10px;
|
|
@@ -7,6 +7,7 @@ import { act, render, screen } from "@testing-library/react";
|
|
|
7
7
|
import { DndContext } from "@dnd-kit/core";
|
|
8
8
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
9
9
|
import type { SessionTarget } from "../api/client";
|
|
10
|
+
import { themeMenuPosition } from "./TerminalCard";
|
|
10
11
|
import type { RendererAdapter } from "../terminal/RendererAdapter";
|
|
11
12
|
|
|
12
13
|
const adapters: RendererAdapter[] = [];
|
|
@@ -196,3 +197,59 @@ describe("TerminalCard terminal theme", () => {
|
|
|
196
197
|
expect(screen.queryByRole("menu")).not.toBeInTheDocument();
|
|
197
198
|
});
|
|
198
199
|
});
|
|
200
|
+
|
|
201
|
+
// The reported bug: in a 2x2 grid on a small display the theme list was cut off
|
|
202
|
+
// at the card's edge (`.terminal-card` sets `overflow: hidden`) and swiping it
|
|
203
|
+
// scrolled the whole page instead. The menu is now placed against the viewport
|
|
204
|
+
// with a computed max-height, which is what gives it something to scroll.
|
|
205
|
+
describe("themeMenuPosition", () => {
|
|
206
|
+
const VIEWPORT = { width: 1024, height: 768 };
|
|
207
|
+
|
|
208
|
+
it("opens below the swatch when there is room, right-aligned to it", () => {
|
|
209
|
+
const pos = themeMenuPosition({ top: 100, bottom: 126, right: 500 }, VIEWPORT);
|
|
210
|
+
expect(pos.placement).toBe("below");
|
|
211
|
+
expect(pos.style).toMatchObject({ position: "fixed", top: 132, left: 500 - 216 });
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("caps the height to the space available, so the list scrolls instead of overflowing", () => {
|
|
215
|
+
// Room below is 768 - 560 - 6 - 8 = 194: enough to stay below, but well
|
|
216
|
+
// short of the ~300px the nine-entry list wants. That gap is the scroll.
|
|
217
|
+
const pos = themeMenuPosition({ top: 534, bottom: 560, right: 500 }, VIEWPORT);
|
|
218
|
+
expect(pos.placement).toBe("below");
|
|
219
|
+
expect(pos.style.maxHeight).toBe(194);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("floors the height so a cramped anchor still shows a usable list", () => {
|
|
223
|
+
// Below is only 154 here, and above (560) is roomier — so it flips, rather
|
|
224
|
+
// than rendering a sliver.
|
|
225
|
+
const pos = themeMenuPosition({ top: 574, bottom: 600, right: 500 }, VIEWPORT);
|
|
226
|
+
expect(pos.placement).toBe("above");
|
|
227
|
+
expect(pos.style.maxHeight).toBe(560);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it("flips above the swatch when below is too cramped and above is roomier", () => {
|
|
231
|
+
const pos = themeMenuPosition({ top: 700, bottom: 726, right: 500 }, VIEWPORT);
|
|
232
|
+
expect(pos.placement).toBe("above");
|
|
233
|
+
// Anchored by its bottom edge, so it grows upward without needing its height.
|
|
234
|
+
expect(pos.style.bottom).toBe(768 - 700 + 6);
|
|
235
|
+
expect(pos.style.top).toBeUndefined();
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
it("never places the menu off the right edge", () => {
|
|
239
|
+
const pos = themeMenuPosition({ top: 40, bottom: 66, right: 1020 }, VIEWPORT);
|
|
240
|
+
expect(pos.style.left).toBe(1024 - 216 - 8);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("never places the menu off the left edge on a narrow screen", () => {
|
|
244
|
+
const pos = themeMenuPosition({ top: 40, bottom: 66, right: 120 }, { width: 380, height: 800 });
|
|
245
|
+
expect(pos.style.left).toBe(8);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
// A card mid-teardown (or jsdom, which reports zeroes) must not produce a
|
|
249
|
+
// negative max-height and an unusable sliver of a menu.
|
|
250
|
+
it("stays usable for a degenerate anchor", () => {
|
|
251
|
+
const pos = themeMenuPosition({ top: 0, bottom: 0, right: 0 }, { width: 0, height: 0 });
|
|
252
|
+
expect(pos.style.maxHeight as number).toBeGreaterThan(0);
|
|
253
|
+
expect(pos.style.left as number).toBeGreaterThanOrEqual(0);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
@@ -9,7 +9,14 @@
|
|
|
9
9
|
// single↔grid only re-renders the header chrome and never remounts the
|
|
10
10
|
// terminal surface (which would tear down the live connection).
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
useCallback,
|
|
14
|
+
useEffect,
|
|
15
|
+
useLayoutEffect,
|
|
16
|
+
useRef,
|
|
17
|
+
useState,
|
|
18
|
+
type CSSProperties,
|
|
19
|
+
} from "react";
|
|
13
20
|
import { useDraggable, useDroppable } from "@dnd-kit/core";
|
|
14
21
|
import type { SessionTarget, TypedError } from "../api/client";
|
|
15
22
|
import { providerMeta } from "./providerMeta";
|
|
@@ -23,6 +30,7 @@ import {
|
|
|
23
30
|
type TerminalFontOptions,
|
|
24
31
|
} from "../state/settings";
|
|
25
32
|
import { TERMINAL_THEMES, type TerminalThemeColors } from "../theme/terminalThemes";
|
|
33
|
+
import type { MasterSide } from "../state/workspace";
|
|
26
34
|
import { removeLatency, reportLatency } from "../state/latency";
|
|
27
35
|
import type { RendererAdapter } from "../terminal/RendererAdapter";
|
|
28
36
|
import { createDefaultRenderer } from "../terminal/defaultRenderer";
|
|
@@ -34,6 +42,16 @@ const DEFAULT_ROWS = 24;
|
|
|
34
42
|
/** How much to shrink the terminal font in a grid tile when "scale to fit". */
|
|
35
43
|
const GRID_FIT_SCALE = 0.8;
|
|
36
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
|
+
|
|
37
55
|
const STATE_LABELS: Record<TerminalConnectionState, string> = {
|
|
38
56
|
connecting: "Connecting…",
|
|
39
57
|
ready: "Connected",
|
|
@@ -63,6 +81,16 @@ interface TerminalCardProps {
|
|
|
63
81
|
/** When true, the header acts as a dnd-kit drag handle and the tile is a drop
|
|
64
82
|
* target (grid reorder). The DndContext + swap live in WorkspacePane. */
|
|
65
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;
|
|
66
94
|
/** Window-control "Normal": solo this terminal into the single view. */
|
|
67
95
|
onNormal: () => void;
|
|
68
96
|
/** Window-control "Grid": show the grid — omitted when none is available. */
|
|
@@ -84,6 +112,71 @@ interface TerminalCardProps {
|
|
|
84
112
|
onStarted?: () => void;
|
|
85
113
|
}
|
|
86
114
|
|
|
115
|
+
/** Where the terminal-theme popup goes, as viewport-relative inline styles. */
|
|
116
|
+
export interface ThemeMenuPosition {
|
|
117
|
+
style: CSSProperties;
|
|
118
|
+
/** Which side of the swatch the menu opened on (asserted in tests). */
|
|
119
|
+
placement: "below" | "above";
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Gap between the swatch and the menu, and the minimum breathing room kept
|
|
123
|
+
* against the viewport edges. */
|
|
124
|
+
const THEME_MENU_GAP = 6;
|
|
125
|
+
const THEME_MENU_MARGIN = 8;
|
|
126
|
+
/** Matches the menu's min-width in TerminalCard.css. */
|
|
127
|
+
const THEME_MENU_WIDTH = 216;
|
|
128
|
+
/** Below this, "below the swatch" is too cramped to be worth using. */
|
|
129
|
+
const THEME_MENU_MIN_USABLE = 160;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Place the theme popup against the VIEWPORT rather than the card.
|
|
133
|
+
*
|
|
134
|
+
* A grid tile on a small screen (a 2x2 layout on an iPad, say) is routinely
|
|
135
|
+
* shorter than the nine-entry theme list, and `.terminal-card` sets
|
|
136
|
+
* `overflow: hidden` — so an absolutely-positioned menu was silently clipped at
|
|
137
|
+
* the card's edge with no way to reach the rest. Fixed positioning escapes that
|
|
138
|
+
* clip, and the computed `maxHeight` is what gives the menu something to scroll
|
|
139
|
+
* (paired with `overscroll-behavior: contain` in CSS, so the scroll stops at the
|
|
140
|
+
* menu instead of running the page).
|
|
141
|
+
*
|
|
142
|
+
* Opens downward by default, flipping above the swatch when there is more room
|
|
143
|
+
* there, and clamps horizontally so the menu can never sit off-screen.
|
|
144
|
+
*/
|
|
145
|
+
export function themeMenuPosition(
|
|
146
|
+
anchor: { top: number; bottom: number; right: number },
|
|
147
|
+
viewport: { width: number; height: number } = {
|
|
148
|
+
width: window.innerWidth,
|
|
149
|
+
height: window.innerHeight,
|
|
150
|
+
},
|
|
151
|
+
): ThemeMenuPosition {
|
|
152
|
+
const roomBelow = viewport.height - anchor.bottom - THEME_MENU_GAP - THEME_MENU_MARGIN;
|
|
153
|
+
const roomAbove = anchor.top - THEME_MENU_GAP - THEME_MENU_MARGIN;
|
|
154
|
+
const placement: "below" | "above" =
|
|
155
|
+
roomBelow < THEME_MENU_MIN_USABLE && roomAbove > roomBelow ? "above" : "below";
|
|
156
|
+
|
|
157
|
+
// Right-align to the swatch, then clamp both edges into the viewport.
|
|
158
|
+
const left = Math.max(
|
|
159
|
+
THEME_MENU_MARGIN,
|
|
160
|
+
Math.min(anchor.right - THEME_MENU_WIDTH, viewport.width - THEME_MENU_WIDTH - THEME_MENU_MARGIN),
|
|
161
|
+
);
|
|
162
|
+
// Never negative: a zero-height anchor (jsdom, or a card mid-teardown) would
|
|
163
|
+
// otherwise ask for a negative max-height and render an unusable sliver.
|
|
164
|
+
const maxHeight = Math.max(THEME_MENU_MIN_USABLE, placement === "above" ? roomAbove : roomBelow);
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
placement,
|
|
168
|
+
style:
|
|
169
|
+
placement === "above"
|
|
170
|
+
? {
|
|
171
|
+
position: "fixed",
|
|
172
|
+
bottom: viewport.height - anchor.top + THEME_MENU_GAP,
|
|
173
|
+
left,
|
|
174
|
+
maxHeight,
|
|
175
|
+
}
|
|
176
|
+
: { position: "fixed", top: anchor.bottom + THEME_MENU_GAP, left, maxHeight },
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
87
180
|
function effectiveFont(settings: SettingsState, mode: TerminalCardMode): TerminalFontOptions {
|
|
88
181
|
const base = terminalFontOptions(settings);
|
|
89
182
|
if (mode === "grid" && settings.gridFit) {
|
|
@@ -101,6 +194,9 @@ export function TerminalCard({
|
|
|
101
194
|
viewState,
|
|
102
195
|
onClose,
|
|
103
196
|
reorderEnabled,
|
|
197
|
+
gridArea,
|
|
198
|
+
masterSide,
|
|
199
|
+
onCycleTile,
|
|
104
200
|
onNormal,
|
|
105
201
|
onGrid,
|
|
106
202
|
onToggleFullscreen,
|
|
@@ -142,6 +238,9 @@ export function TerminalCard({
|
|
|
142
238
|
const [copied, setCopied] = useState(false);
|
|
143
239
|
const [themeMenuOpen, setThemeMenuOpen] = useState(false);
|
|
144
240
|
const themeMenuRef = useRef<HTMLDivElement | null>(null);
|
|
241
|
+
const themeButtonRef = useRef<HTMLButtonElement | null>(null);
|
|
242
|
+
// Viewport-relative placement for the theme popup; null until measured.
|
|
243
|
+
const [themeMenuPos, setThemeMenuPos] = useState<ThemeMenuPosition | null>(null);
|
|
145
244
|
|
|
146
245
|
// dnd-kit reorder: the tile is both a draggable (handle = header grip, below)
|
|
147
246
|
// and a droppable (swap target). Disabled outside a reorderable grid. We use
|
|
@@ -336,6 +435,39 @@ export function TerminalCard({
|
|
|
336
435
|
}
|
|
337
436
|
}, [isFocused, isVisible]);
|
|
338
437
|
|
|
438
|
+
// Measure the popup's placement before paint, and keep it anchored while it
|
|
439
|
+
// is open. A grid tile can be far smaller than the list, so the menu is
|
|
440
|
+
// positioned against the VIEWPORT (see ThemeMenuPosition) rather than the
|
|
441
|
+
// card, which clips its overflow.
|
|
442
|
+
useLayoutEffect(() => {
|
|
443
|
+
if (!themeMenuOpen) {
|
|
444
|
+
setThemeMenuPos(null);
|
|
445
|
+
return undefined;
|
|
446
|
+
}
|
|
447
|
+
const measure = (): void => {
|
|
448
|
+
const button = themeButtonRef.current;
|
|
449
|
+
if (button) {
|
|
450
|
+
setThemeMenuPos(themeMenuPosition(button.getBoundingClientRect()));
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
measure();
|
|
454
|
+
// A rotate/resize moves the anchor; so does scrolling the pane under it.
|
|
455
|
+
// Scrolling INSIDE the menu must not re-anchor (it would fight the user),
|
|
456
|
+
// and element scrolls only reach window listeners in the capture phase.
|
|
457
|
+
const onScroll = (e: Event): void => {
|
|
458
|
+
if (themeMenuRef.current?.contains(e.target as Node)) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
measure();
|
|
462
|
+
};
|
|
463
|
+
window.addEventListener("resize", measure);
|
|
464
|
+
window.addEventListener("scroll", onScroll, true);
|
|
465
|
+
return () => {
|
|
466
|
+
window.removeEventListener("resize", measure);
|
|
467
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
468
|
+
};
|
|
469
|
+
}, [themeMenuOpen]);
|
|
470
|
+
|
|
339
471
|
// Dismiss the theme popup on Escape or a click anywhere outside it.
|
|
340
472
|
useEffect(() => {
|
|
341
473
|
if (!themeMenuOpen) {
|
|
@@ -436,6 +568,7 @@ export function TerminalCard({
|
|
|
436
568
|
style={
|
|
437
569
|
{
|
|
438
570
|
display: isVisible ? undefined : "none",
|
|
571
|
+
gridArea,
|
|
439
572
|
"--bg-term": theme.colors.background,
|
|
440
573
|
} as CSSProperties
|
|
441
574
|
}
|
|
@@ -501,6 +634,7 @@ export function TerminalCard({
|
|
|
501
634
|
<div className="tc-theme" ref={themeMenuRef}>
|
|
502
635
|
<button
|
|
503
636
|
type="button"
|
|
637
|
+
ref={themeButtonRef}
|
|
504
638
|
className="tc-btn tc-btn--swatch"
|
|
505
639
|
data-testid={`terminal-theme-${target.id}`}
|
|
506
640
|
title={`Terminal theme: ${theme.label}${hasThemeOverride ? "" : " (default)"}`}
|
|
@@ -515,8 +649,8 @@ export function TerminalCard({
|
|
|
515
649
|
>
|
|
516
650
|
A
|
|
517
651
|
</button>
|
|
518
|
-
{themeMenuOpen && (
|
|
519
|
-
<div className="tc-theme-menu" role="menu">
|
|
652
|
+
{themeMenuOpen && themeMenuPos && (
|
|
653
|
+
<div className="tc-theme-menu" role="menu" style={themeMenuPos.style}>
|
|
520
654
|
<button
|
|
521
655
|
type="button"
|
|
522
656
|
className={`tc-theme-item${hasThemeOverride ? "" : " tc-theme-item--on"}`}
|
|
@@ -563,6 +697,26 @@ export function TerminalCard({
|
|
|
563
697
|
</div>
|
|
564
698
|
)}
|
|
565
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
|
+
)}
|
|
566
720
|
{/* Window-control cluster: mutually-exclusive display modes ordered
|
|
567
721
|
* by how much space they take — Grid (smaller/tiled) → Normal (fills
|
|
568
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
|
+
}
|