runlayer 0.31.0__tar.gz → 0.31.2__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.
- {runlayer-0.31.0 → runlayer-0.31.2}/AGENTS.md +2 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/Makefile +1 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/PKG-INFO +1 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/pyproject.toml +1 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch.py +2 -3
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_checkin.py +178 -29
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/api.py +16 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_setup.py +6 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/scan.py +10 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/setup.py +6 -7
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/clients.py +30 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/daemon_protocol.py +3 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/dispatch.py +31 -1
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/hook_io.py +39 -2
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/mcp_lookup.py +31 -3
- runlayer-0.31.2/runlayer_cli/hook/plugin_context.py +172 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/clients.py +170 -79
- runlayer-0.31.2/runlayer_cli/hook_install/config_backup.py +106 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/console_user.py +48 -16
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/llm_routing.py +91 -29
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/launcher_inspection.py +31 -19
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/service.py +34 -13
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/conftest.py +32 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan_submit.py +50 -0
- runlayer-0.31.2/tests/test_aiwatch_checkin_batch.py +191 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_daemon_dispatch.py +27 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli.py +14 -3
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_client_presence_evasion.py +1 -1
- runlayer-0.31.2/tests/test_config_backup.py +210 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_console_user.py +103 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_mdm_scope.py +118 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_module.py +177 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_io.py +100 -1
- runlayer-0.31.2/tests/test_hook_plugin_context.py +314 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_python.py +92 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hooks_relay.py +0 -14
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_launcher_inspection.py +136 -5
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_llm_routing.py +32 -0
- runlayer-0.31.2/tests/test_llm_routing_probe.py +116 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_llm_routing_reconcile.py +135 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_logging.py +8 -41
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_service.py +64 -4
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_hooks.py +22 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/.gitignore +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/.python-version +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/CLAUDE.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/LICENSE +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/development.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/hooks/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/hooks/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/hooks/debug_hook_binary.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/hooks/runlayer-hook.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/DEPLOYMENT.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/_version_file.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/aiwatch.spec +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/aiwatch_uninstall.spec +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/assets/aiwatch-icon-512.png +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/assets/aiwatch.ico +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/Dockerfile +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/Dockerfile.dockerignore +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/configmap.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/cronjob.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/daemonset.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/kustomization.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/namespace.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/secret.example.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/scan-host-users.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/assert_inside_container.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/run_smoke_test.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/stub-aiwatch.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/install.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/install.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/Install.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/fixtures/targets-glibc2.17.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/fixtures/targets.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/test_install_sh.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/aiwatch-config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/aiwatch-credentials.example +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_aiwatch_packages.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_onedir_manylinux.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_packages.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/cron.d-runlayer-aiwatch +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/cron.d-runlayer-cli +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/nfpm-aiwatch.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/nfpm.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-aiwatch-scan.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-aiwatch-update.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-cli-schedule.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-cli-update.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/pillar.example.sls +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/init.sls +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/templates/config.json.jinja +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/templates/credentials.jinja +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/assert_inside_container.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/build_stub_packages.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/check_package_markers.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/ensure_host_nfpm.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/run_smoke_tests.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/test_variant_suffix.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/adopt_keychain.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_pkg.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_pkg_runlayer.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_uninstall_pkg.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.bootstrap.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.daemon.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.enroll.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.firefox-native-messaging-host.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.jamf.schema.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.mobileconfig +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.native-messaging-host.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.update.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.ws1.mobileconfig +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.mobileconfig +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.schedule.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.update.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/distribution.runlayer.xml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/distribution.xml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/entitlements.plist +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/postinstall +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/postinstall-runlayer +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/preinstall +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/preinstall-runlayer +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall-pkg/postinstall +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall-runlayer.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/py2exe/setup_py2exe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/runlayer.spec +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/aiwatch-native-messaging-host.bat +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/aiwatch.wxs +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_hook_shim.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_intunewin.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_intunewin_runlayer.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_msi.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_msi_runlayer.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-schedule-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-schedule-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-update-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-update-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/detect-install.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/tests/DetectInstall.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/handoff-exec-test/emit_handoff_script.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/handoff-exec-test/run-handoff-exec-test.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/native-host-chromium.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/native-host-firefox.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/runlayer.wxs +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/RunlayerTaskCommon.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/register-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/remove-hooks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/CliScheduleTasks.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/CliUpdateTasks.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/Invoke-Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/RemoveHooks.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/ScheduledTasks.Tests.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/unregister-tasks.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scripts/bootstrap.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/regex-engine-allowlist.txt +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_config_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_config_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_credential.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_uninstall.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/catalog_client.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/catalog_enrichment.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/cli_persistence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/command_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/command_metrics.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_update.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/auth.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/bootstrap.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/display.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/kinds.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/resolve.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/cli_update.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/credentials.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/decide_approval.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/deploy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/doctor.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/enroll.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/hooks.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/interactive_find.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/keychain.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/logs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/org_api_key.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/reconnect_account.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/reject_access_request.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/schedule.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/skills.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/status.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/terraform.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update_privilege.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update_scheduler.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/url_handler.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/console.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/credential_store.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/runtime.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/server.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/status.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_pipe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_scm.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_service.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/docker_builder.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/schema_validation.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/service.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/enrollment.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/env_substitution.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/error_classification.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_delivery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_spool.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_summary.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_trace.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/__main__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/_transcript_stream_worker.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/copilot_cli_mcp_lookup.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/credential_state.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/daemon_client.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/failure.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/file_policy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/host_override.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/log_silence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/mcp_types.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/messages.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/relay.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/transcript_stream.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/windsurf_payload.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/artifact_paths.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_extension.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_policy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/check.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/chromium_profile_health.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/credential_gate.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/daemon_lifecycle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/edge_extension.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/firefox_extension.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/paths.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/safe_fs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/windows_browser_policy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/http_error_utils.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/identity_forward.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/index.html +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/install_window.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/installer_common.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/linux_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/logging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/macos_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/macos_test_device_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/main.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/managed_policy_publication.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/mdm_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/metrics.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/metrics_flush.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/middleware.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models_api.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models_mcp.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/native_messaging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth_callback.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth_guidance.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/paths.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/platform_installers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/claude_manifest.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/constants.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/discovery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/layouts.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/models.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/sync_engine.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/product.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/regex_safe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/runtime.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/safe_parse.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agent_definition_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agent_scan.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/detect.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/discover.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/install.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/languages.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/_common.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/cargo.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/dotnet.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/go.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/jvm.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/npm.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/python.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/openclaw_detector.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/registry.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/report.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/signatures.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/artifact_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/bin_shims.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/claude_code_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/cli_binaries.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/client_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/clients.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/codex_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/completeness.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/concurrency.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/config_parser.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/config_redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/container_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/container_limits.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/collect.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/collector.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/docker_cli.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/docker_socket.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/inspect_parse.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/k3s_cli.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/proc_walk.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/tar_walk.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/windows_named_pipe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/copilot_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/cursor_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/device.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/disguised_skills.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/file_collector.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/gemini_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/hidden_space_sweep.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/jetbrains_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/npm_global.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/opencode_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/orchestrator.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/pip_global.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/plugin_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/classify.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/enumerate.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/models.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/probes.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/settings_override.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/windows_owner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/project_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/project_tree_match.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/renamed_plugin_caches.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/resource_governor.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/run_lock.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/scan_state.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/scanner_primitives.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skill_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skill_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skip_dirs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/symlink_follow.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/symlink_identity.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/timing.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/vscode_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/warp_sqlite.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/windows_users.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_exec.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_limits.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_paths.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_projects.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_runtime_signals.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/AGENTS.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/CLAUDE.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/hashing.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/merkle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/skill_id.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/types.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/device_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/discovery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/frontmatter.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/installer_core.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/marker.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/models.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/names.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/scan_summary.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/sync_engine.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/symbols.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/telemetry.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/terraform_export.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/tls.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/tolerant_json.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/truststore_init.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/update_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/update_source.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/updater.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/uuid_utils.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/uv_tool_cleanup.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/variant.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/exceptions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/proxy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/base.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/macos.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/windows.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_installer_verifier.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_update_handoff.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/scripts/check_published_hook_transport.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/scripts/check_regex_engine.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/scripts/smoke_installed_hooks.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/daemon_frame_helpers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/cache/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/cache/test_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/conftest.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/credentials/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/credentials/test_credentials.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/test_lifecycle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/test_validate.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/antigravity.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/claude_code.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/claude_desktop.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cline.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cline_cli.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/codex.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cursor.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/gemini_cli.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/github_copilot_cli.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/goose.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/opencode.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/vscode.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/windsurf.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/zed.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.claude-plugin/marketplace.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.claude-plugin/plugin.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.lsp.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.mcp.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/agents/README.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/agents/code-reviewer.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/commands/review.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/hooks/hooks.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/hooks/validate.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/notes.txt +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/scripts/deploy.sh +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/settings.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/code-review/SKILL.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/code-review/prompts.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/SKILL.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/helper.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills-v2/notes.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skillsets/reference.md +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/tool.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/test_install_hooks.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/test_relay.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/org_api_key/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/org_api_key/test_org_api_key.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_add.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_mcp_fallback.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_push.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/run/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/run/test_run.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/conftest.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan_lock_isolation.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/setup/test_install_opencode.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/skills/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/skills/test_lifecycle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/terraform/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/test_help_matrix.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/version/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/version/test_version.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/labels.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/debug_adapter/adapter.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/debug_adapter/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/flask_api/app.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/flask_api/requirements.txt +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/go_cli/go.mod +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/go_cli/main.go +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/node_web/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/node_web/server.js +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_01/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_01/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_02/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_02/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_03/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_03/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_04/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_04/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_05/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_05/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_06/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_06/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_07/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_07/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_08/agent.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_08/pyproject.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_09/agent.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_09/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_10/agent.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_10/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_11/agent.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_11/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_12/agent.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_12/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_13/Cargo.toml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_13/main.rs +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_14/go.mod +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_14/main.go +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_15/Main.java +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_15/pom.xml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_16/Main.java +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_16/pom.xml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_17/Program.cs +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_17/SemanticKernelAgent.csproj +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_18/package.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_18/server.ts +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/claude_code_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/claude_desktop_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/container_command_cases.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/container_label_normalization_cases.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/cursor_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/devin_cli_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/empty_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/goose_config.yaml +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/imported_claude_hook_guard.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/lifecycle_events.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_exec.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_file_tools.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_mcp.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/event_hooks_matrix.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_failure_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_failure_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_output_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_read_env_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/user_prompt_submit_event.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/event_hooks_matrix.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/permission_request_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/permission_request_env_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_event_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_failure_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_failure_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/after_file_edit_event.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_direct_url_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_local_stdio_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_managed_proxy_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_read_file_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_read_file_env_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_shell_execution_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_shell_execution_env_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_tab_file_read_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_tab_file_read_mcp_config_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/event_hooks_matrix.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_allow.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_output_block.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_allow_modified.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_deny.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/stop_session_end_event.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/invalid_json.txt +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/junie_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/kilo_code_config.jsonc +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/kimi_code_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/macos_policy_reader.c +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/pi_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/roo_code_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/sse_server_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/vscode_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/warp_config.json +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/conftest.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_credential.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_install.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_policy_publication.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_runlayer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/hostile_inputs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/macos_installer_helpers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/platform_installer_helpers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/plugin_installer_helpers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/harness.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_agent_scan.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_detect.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_discover.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_eval.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_manifests.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_registry.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_report.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/conftest.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_classify.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_discovery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_enumerate.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_probes.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_settings_override.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_agent_definition_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_agent_scan.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_completeness.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_config_redact.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_container_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_containers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_docker_socket.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_k3s.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_phase_isolation.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_presence_decode_hardening.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_runtime_decode_hardening.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_skip_dirs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_windows_named_pipe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_exec.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_paths.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_projects.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_runtime_signals.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/sign_shards_smoke.ps1 +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/test_merkle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/test_skill_id.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_basename_dispatch.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_bootstrap.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_checkin.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_isolation.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_credential.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_hook_shim_packaging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_hook_version.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_imports.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_setup_hooks.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_uninstall.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_uninstall_packaging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_update_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_api.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_artifact_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_auth.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_backwards_compatibility.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_bin_shims.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_browser_extension_install.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_browser_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cache.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_catalog_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_catalog_enrichment.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_chromium_profile_health.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_code_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_json_integration.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_output_replacement.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_backwards_compat.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_binaries.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_linux_schedule_assets.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_update_schedule_assets.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_client_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_command_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_command_metrics.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_container_label_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_copilot_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credential_store.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credential_store_macos.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credentials_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cursor_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_client.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_lifecycle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_protocol.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_runtime.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_server.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_status.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_windows_pipe.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_debug_hook_binary.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_decide_approval.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_deploy_service.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_desktop_release_workflow.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_disguised_skills.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_dispatch_decode_hardening.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_docker_builder.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_docs_client_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_doctor.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_edge_extension_install.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_endpoint_modes.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enroll_checkins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enroll_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enrollment.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_env_substitution.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_error_classification.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_firefox_extension_install.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_delivery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_spool.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_trace.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_gemini_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hidden_space_sweep.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_binary_convergence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_credential_rejection.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_dispatch_replay.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_departed_harness.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_harness_closed_stdout.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_operations.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_host_override.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_safe_fs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_windows_safe_fs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_messages.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_replay_fixtures.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_script.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_shim_protocol.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_identity_forward.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_install_window.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_interactive_find.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_jetbrains_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_keychain_adopt.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_keychain_guard.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_lazy_enrollment.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_legacy_re2_tag_coupling.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_linux_cron_assets.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_linux_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_logs.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_config_profile_assets.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_managed_policy_publication.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_mdm_mode_compatibility.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_plists.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_main_hook_dispatch.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_managed_policy_publication.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_manual_oauth.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_manylinux2014_lock_floor.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_mcp_lookup_decode_hardening.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_mdm_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_metrics.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_middleware.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_native_messaging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_npm_global.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_browser_lock.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_callback_lifecycle.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_callback_port.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_error_guidance.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_sibling_wait.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_token_storage.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_opencode_plugins.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_org_api_key_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_pip_global.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_platform_installers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugin_layouts.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugin_scanner.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_discovery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_installer_cursor_layout.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_product.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_published_hook_transport.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_py310_compat.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_regex_parity.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_regex_safe_mirror_drift.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_renamed_plugin_caches.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_resource_governor.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_safe_parse.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_clients.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_concurrency.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_detect_error_checkin.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_device.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_memory_caps.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_no_findings.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_openclaw.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_parser.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_project.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_run_lock.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_skills.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_summary.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_timing.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_verbose.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_windows_profile.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scanner_primitives.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_schedule_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_claude_desktop.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_config_formats.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_local_servers.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_names.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_presence.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_sync_credentials.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_device_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_discovery.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_installer_core.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_marker.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_sync_command.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_status.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_symbols.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_sync.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_telemetry.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_terraform_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_test_device_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_tls.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_transcript_decode_hardening.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_truststore_init.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_commands.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_privilege.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_source.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_updater.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_url_handler.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_uv_tool_cleanup.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_variant.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_variant_packaging_contract.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_version_file.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_vscode_extensions.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_warp_sqlite.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_browser_policy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_daemon_service.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_installer.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_installer_verifier.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_msi_sequencing.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_native_messaging_packaging.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_ps1_gates.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_scan_all_users.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_sign_shards.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_update_handoff.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_config.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_proxy.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/__init__.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_base.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_macos.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_windows.py +0 -0
- {runlayer-0.31.0 → runlayer-0.31.2}/tests/windows_installer_helpers.py +0 -0
|
@@ -59,6 +59,8 @@ The AI Watch onedir bundle contains one PyInstaller `aiwatch` exe (`packaging/ai
|
|
|
59
59
|
|
|
60
60
|
**Install scope** — `aiwatch setup hooks install` and `aiwatch bootstrap` default to `--mdm` (enterprise config dirs: `/Library/Application Support/Cursor`, `/Library/Application Support/Windsurf`, `/etc/codex/managed_config.toml`, Windows equivalents). Codex's Windows target is the System layer `C:\ProgramData\OpenAI\Codex\{hooks.json,config.toml}` — never SYSTEM's `~/.codex` (systemprofile, read by nobody) and never `managed_config.toml` there (Windows only reads that from `~/.codex`); `_codex_features_toml_file` picks the file, so hooks flag and LLM routing land in the same TOML. Windows MDM also strips Runlayer entries from the console user's legacy `~/.codex/hooks.json` (best-effort, reparse-point preflight). AI Watch scopes wire `"<aiwatch-hook>" hook --client <name>` only when the daemon gate is open and the co-located shim exists; otherwise they wire `"<aiwatch>" hook --client <name>`. On Windows, both install paths emit Claude Code's shell-free exec form (`command` executable + `args`) because shell-form hooks may run under Git Bash or PowerShell. Gemini CLI, VS Code, Windsurf, and Codex get the call-operator form `& "<aiwatch>" hook --client <name>` — a bare quoted string is a PowerShell expression, not an invocation; Copilot CLI's `powershell` field likewise (its `bash` field stays plain). There is no per-client symlink. Windsurf has a real root-owned enterprise dir and Cascade merges system → user → workspace hooks, so MDM scope writes the system `hooks.json` and leaves the user's own file alone. Three clients have no usable enterprise hook dir and instead resolve the console user's home (via `find_console_user_home`): Hermes has no native enterprise dir, Goose hook plugins are user-level (`~/.agents/plugins/runlayer-hooks/hooks/hooks.json`), and Claude Code's enterprise `managed-settings.json` hooks regressed (ENG-3204, hooks don't fire) so MDM-scope writes its user-scope `~/.claude/settings.json` (user hooks still fire) — same as `~/.hermes/config.yaml`. Same auto-install pipeline, just a per-user destination. Revert Claude Code to `managed-settings.json` once the regression is fixed. **Presence gate is scope- and client-dependent** (`hook_install.clients.presence_gates_install`): in MDM scope, enterprise-dir clients (`ENTERPRISE_DIR_CLIENTS`: Cursor, Codex, Copilot CLI, Windsurf, Qwen Code, Gemini CLI) are written and checked unconditionally — the root-owned file is harmless for an absent client, and the executable probe can miss a real install (Cursor.app outside `/Applications`, no `cursor` CLI), which left devices unmonitored (ENG-6643). Console-home clients (`CONSOLE_HOME_CLIENTS`) and every `--user` install still skip when `presence.client_is_installed` fails. Every supported client must be in exactly one of the two sets. Pass `--user` to write per-user `~/.<client>` dirs instead (dev / manual one-shot use). The MDM-scope path is the steady-state contract: macOS bootstrap LaunchDaemon (root) + the Windows `AIWatchHooks` scheduled task (SYSTEM) drive it. **Credential gate** still guards install — `credential_gate.credential_present` must be satisfied before install wires AI clients at the hook. Scan-only removal skips the credential gate so stale hooks can be removed after config changes. A managed `OrgApiKey` satisfies the gate directly (hooks authenticate with the org key; no per-user enroll needed). The legacy enroll-marker path remains for `EnrollmentKey` fleets: in MDM scope the gate also accepts the console user's per-host enrollment marker file `~/.runlayer/.enrolled-<host_key>` (`runlayer_cli/hook_install/console_user.py:has_enrolled_credential_for_host`) — proof the enroll agent ran, even when the actual secret lives in a keychain root can't read. The marker is empty so root can `stat()` it without keychain access.
|
|
61
61
|
|
|
62
|
+
**Config backups.** Every writer that rewrites a third-party client config (`hook_install/clients.py` writers via `_write_config_with_backup`, `llm_routing._apply_prepared_write`, operator `commands/setup.py::_backup_file`) keeps the previous content beside it as `<stem>.backup_<YYYYMMDD_HHMMSS_ffffff><suffix>` and then prunes to the newest `BACKUP_KEEP` (5) recognized copies (`hook_install/config_backup.py`). AI Watch backups are change-gated — an unchanged reconcile writes nothing — but pruning runs on every successful write so piles left by older builds (which also used a second-only stamp) drain on the next reconcile. Pruning matches only the exact backup name shape, skips anything that is not a regular file, unlinks descriptor-relatively under the console-home anchor in MDM scope, and is best-effort (never fails the install). Runlayer-owned files (Cline scripts, Goose `plugin.json`, the routing credential) are never backed up.
|
|
63
|
+
|
|
62
64
|
**LLM routing credential.** Reconcile writes helper-based Claude Code / Codex configs (`apiKeyHelper` / `[model_providers.runlayer.auth]`, no secret; see `hook_install/llm_routing.py`) plus the console user's `~/.runlayer/aiwatch/llm-routing-credential` (0600, user-owned, symlinks refused, never backed up, deleted on unroute). `aiwatch credential <client>` (`runlayer_cli/aiwatch_credential.py`, stdlib + `mdm_config` only, pre-typer like `hook`) exchanges it at `POST /api/v1/llm-gateway/device-tokens` within 5 s and one retry, prints the token, and exits 1 with one stderr line on failure. It caches the token in `~/.runlayer/aiwatch/llm-routing-token` (0600, temp file + rename, shared by both clients), re-mints below one 240 s client refresh interval, and deletes the cache on unroute. Clients refresh every 4 min and after a 401.
|
|
63
65
|
|
|
64
66
|
**aiwatch never reads `~/.runlayer/config.yaml`.** The aiwatch binary resolves host from MDM managed config (`mdm_config.read_managed_config`) and per-user secrets from the keychain only. `config.load_config` / `save_config` / `clear_config` gate on `runtime.is_aiwatch_runtime()` (process flag set at the aiwatch/hook entrypoints, plus the frozen-aiwatch bundle idiom): for aiwatch, `load_config` synthesizes a `Config` from the MDM `Host` (one host entry, url only — keeps `get_secret_for_host`'s keychain lookup live) and `save_config`/`clear_config` are no-ops. `save_config` **returns a `bool`** (`True` persisted, `False` aiwatch no-op) so credential-writing callers (`enroll`, `auth.login`, `bootstrap._enroll_step`, hook lazy enrollment) can detect the case where the keychain write *also* failed (`set_host_credentials` → `False`): then the secret only lives in the in-memory `Config` and is lost. Those callers must warn / fail instead of claiming success, and must not drop the enrollment marker (which would falsely satisfy the bootstrap credential gate). The full `runlayer` CLI is unaffected and reads/writes the YAML as before.
|
|
@@ -339,7 +339,7 @@ def _relay_daemon_response(response: "HookResult") -> NoReturn:
|
|
|
339
339
|
|
|
340
340
|
def _run_hook_daemon_first() -> None:
|
|
341
341
|
"""Use daemon IPC when gated on; preserve consumed stdin for inline fallback."""
|
|
342
|
-
from runlayer_cli.hook import daemon_client # noqa: PLC0415 - stdlib-only
|
|
342
|
+
from runlayer_cli.hook import daemon_client, hook_io # noqa: PLC0415 - stdlib-only
|
|
343
343
|
|
|
344
344
|
client_start_ms = _client_start_ms()
|
|
345
345
|
stdin_text: str | None = None
|
|
@@ -351,7 +351,7 @@ def _run_hook_daemon_first() -> None:
|
|
|
351
351
|
daemon_enabled = False
|
|
352
352
|
if daemon_enabled:
|
|
353
353
|
try:
|
|
354
|
-
stdin_text =
|
|
354
|
+
stdin_text = hook_io.read_process_stdin()
|
|
355
355
|
except Exception as exc:
|
|
356
356
|
stdin_error = exc
|
|
357
357
|
else:
|
|
@@ -365,7 +365,6 @@ def _run_hook_daemon_first() -> None:
|
|
|
365
365
|
_relay_daemon_response(response)
|
|
366
366
|
|
|
367
367
|
_inject_truststore()
|
|
368
|
-
from runlayer_cli.hook import hook_io # noqa: PLC0415
|
|
369
368
|
from runlayer_cli.hook.dispatch import run_hook # noqa: PLC0415
|
|
370
369
|
|
|
371
370
|
if stdin_text is None and stdin_error is None:
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import sys
|
|
6
6
|
import time
|
|
7
7
|
from collections.abc import Callable, Mapping
|
|
8
|
+
from typing import Any, Protocol
|
|
8
9
|
|
|
9
10
|
import httpx
|
|
10
11
|
import structlog
|
|
@@ -39,6 +40,65 @@ _SYNC_DETAIL_MAX_ITEM_LEN = 200
|
|
|
39
40
|
_CHECKIN_RETRY_DELAYS_SECONDS = (0.1, 0.2)
|
|
40
41
|
_CHECKIN_REJECTED_RESPONSE_BODY_MAX_LEN = 500
|
|
41
42
|
|
|
43
|
+
# Single-form payload keys that describe the device rather than one feature.
|
|
44
|
+
# The batch body carries them once at the top level; everything else in a
|
|
45
|
+
# single-form payload is that feature's entry. Mirrored by the backend's
|
|
46
|
+
# ``AIWatchCheckInDeviceFields`` (contract test on the backend side).
|
|
47
|
+
BATCH_CHECKIN_DEVICE_KEYS: frozenset[str] = frozenset(
|
|
48
|
+
{
|
|
49
|
+
"device_id",
|
|
50
|
+
"hostname",
|
|
51
|
+
"os",
|
|
52
|
+
"os_version",
|
|
53
|
+
"username",
|
|
54
|
+
"org_device_id",
|
|
55
|
+
"serial_number",
|
|
56
|
+
"windows_user_sid",
|
|
57
|
+
"tools",
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Failure log event per scan-tick feature. The builders and the batch
|
|
62
|
+
# fallback replay both read from here, so the replay cannot log a different
|
|
63
|
+
# event than the direct single-form path would have.
|
|
64
|
+
_SCAN_LOG_EVENTS: dict[str, str] = {
|
|
65
|
+
"protect": "aiwatch_protect_checkin_failed",
|
|
66
|
+
"enforce": "aiwatch_enforce_checkin_failed",
|
|
67
|
+
"sessions": "aiwatch_sessions_checkin_failed",
|
|
68
|
+
"daemon": "aiwatch_daemon_checkin_failed",
|
|
69
|
+
"detect": "aiwatch_detect_checkin_failed",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class CheckInSubmitter(Protocol):
|
|
74
|
+
"""The slice of ``RunlayerClient`` the check-in builders depend on."""
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def base_url(self) -> str: ...
|
|
78
|
+
|
|
79
|
+
def submit_aiwatch_checkin(self, payload: dict[str, Any]) -> dict[str, Any]: ...
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class _CheckInCollector:
|
|
83
|
+
"""Stand-in submitter that captures single-form payloads instead of sending.
|
|
84
|
+
|
|
85
|
+
Lets the scan path reuse every existing check-in builder unchanged and ship
|
|
86
|
+
the captured payloads in one batch request afterwards.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
def __init__(self, client: RunlayerClient) -> None:
|
|
90
|
+
self._client = client
|
|
91
|
+
self.payloads: list[dict[str, object]] = []
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def base_url(self) -> str:
|
|
95
|
+
return self._client.base_url
|
|
96
|
+
|
|
97
|
+
def submit_aiwatch_checkin(self, payload: dict[str, Any]) -> dict[str, Any]:
|
|
98
|
+
self.payloads.append(payload)
|
|
99
|
+
return {}
|
|
100
|
+
|
|
101
|
+
|
|
42
102
|
_PRIVILEGED_USERNAMES = frozenset(
|
|
43
103
|
{
|
|
44
104
|
"system",
|
|
@@ -123,7 +183,7 @@ def _base_payload(
|
|
|
123
183
|
|
|
124
184
|
|
|
125
185
|
def _submit_payload_for_response(
|
|
126
|
-
client:
|
|
186
|
+
client: CheckInSubmitter,
|
|
127
187
|
payload: dict[str, object],
|
|
128
188
|
*,
|
|
129
189
|
log_event: str,
|
|
@@ -157,7 +217,7 @@ def _submit_payload_for_response(
|
|
|
157
217
|
|
|
158
218
|
|
|
159
219
|
def _submit_payload(
|
|
160
|
-
client:
|
|
220
|
+
client: CheckInSubmitter,
|
|
161
221
|
payload: dict[str, object],
|
|
162
222
|
*,
|
|
163
223
|
log_event: str,
|
|
@@ -206,7 +266,7 @@ def submit_llm_routing_checkin(
|
|
|
206
266
|
|
|
207
267
|
|
|
208
268
|
def _submit_simple_checkin(
|
|
209
|
-
client:
|
|
269
|
+
client: CheckInSubmitter,
|
|
210
270
|
*,
|
|
211
271
|
feature: str,
|
|
212
272
|
status: str,
|
|
@@ -233,7 +293,7 @@ def _submit_simple_checkin(
|
|
|
233
293
|
_submit_payload(client, payload, log_event=log_event)
|
|
234
294
|
|
|
235
295
|
|
|
236
|
-
def submit_detect_checkin(client:
|
|
296
|
+
def submit_detect_checkin(client: CheckInSubmitter, result: ScanResult) -> None:
|
|
237
297
|
"""Record that a scan ran, even when no findings were submitted."""
|
|
238
298
|
payload = _base_payload(
|
|
239
299
|
device_context_dict(result),
|
|
@@ -255,10 +315,10 @@ def submit_detect_checkin(client: RunlayerClient, result: ScanResult) -> None:
|
|
|
255
315
|
# full-CLI hook host deviation: ``None`` (no fresh marker) clears the
|
|
256
316
|
# tenant-side record, so a fixed ``default_host`` self-heals within a scan.
|
|
257
317
|
payload["hook_host_detail"] = _hook_host_detail(client)
|
|
258
|
-
_submit_payload(client, payload, log_event="
|
|
318
|
+
_submit_payload(client, payload, log_event=_SCAN_LOG_EVENTS["detect"])
|
|
259
319
|
|
|
260
320
|
|
|
261
|
-
def _hook_host_detail(client:
|
|
321
|
+
def _hook_host_detail(client: CheckInSubmitter) -> host_override.HostOverride | None:
|
|
262
322
|
"""Fresh ``hook_host_override`` marker for the user this scan reports on.
|
|
263
323
|
|
|
264
324
|
Hooks write it under the user's ``~/.runlayer/state``, and every scan path
|
|
@@ -276,16 +336,13 @@ def _hook_host_detail(client: RunlayerClient) -> host_override.HostOverride | No
|
|
|
276
336
|
marker = host_override.read_marker()
|
|
277
337
|
if marker is None:
|
|
278
338
|
return None
|
|
279
|
-
|
|
280
|
-
if not isinstance(destination, str):
|
|
281
|
-
return None
|
|
282
|
-
if destination.rstrip("/") != marker["managed_host"].rstrip("/"):
|
|
339
|
+
if client.base_url.rstrip("/") != marker["managed_host"].rstrip("/"):
|
|
283
340
|
return None
|
|
284
341
|
return marker
|
|
285
342
|
|
|
286
343
|
|
|
287
344
|
def _submit_hook_validation_checkin(
|
|
288
|
-
client:
|
|
345
|
+
client: CheckInSubmitter,
|
|
289
346
|
*,
|
|
290
347
|
feature: str,
|
|
291
348
|
include_pipeline: bool,
|
|
@@ -351,7 +408,7 @@ def submit_detect_error_checkin(
|
|
|
351
408
|
|
|
352
409
|
|
|
353
410
|
def submit_enforce_validation_checkin(
|
|
354
|
-
client:
|
|
411
|
+
client: CheckInSubmitter,
|
|
355
412
|
*,
|
|
356
413
|
ctx: DeviceContext,
|
|
357
414
|
tools: list[InstalledTool],
|
|
@@ -373,12 +430,11 @@ def submit_enforce_validation_checkin(
|
|
|
373
430
|
status="disabled",
|
|
374
431
|
ctx=ctx,
|
|
375
432
|
tools=tools,
|
|
376
|
-
log_event=
|
|
433
|
+
log_event=_SCAN_LOG_EVENTS[feature],
|
|
377
434
|
)
|
|
378
435
|
return
|
|
379
436
|
|
|
380
437
|
feature = "enforce"
|
|
381
|
-
log_event = "aiwatch_enforce_checkin_failed"
|
|
382
438
|
if mode is AIWatchMode.PROTECT:
|
|
383
439
|
# Clear any formerly-active Enforce state before reporting Protect.
|
|
384
440
|
_submit_simple_checkin(
|
|
@@ -387,10 +443,9 @@ def submit_enforce_validation_checkin(
|
|
|
387
443
|
status="disabled",
|
|
388
444
|
ctx=ctx,
|
|
389
445
|
tools=tools,
|
|
390
|
-
log_event="
|
|
446
|
+
log_event=_SCAN_LOG_EVENTS["enforce"],
|
|
391
447
|
)
|
|
392
448
|
feature = "protect"
|
|
393
|
-
log_event = "aiwatch_protect_checkin_failed"
|
|
394
449
|
else:
|
|
395
450
|
# Enforce and Protect are mutually exclusive endpoint modes. Clear a
|
|
396
451
|
# formerly-active Protect row before reporting current Enforce health.
|
|
@@ -400,7 +455,7 @@ def submit_enforce_validation_checkin(
|
|
|
400
455
|
status="disabled",
|
|
401
456
|
ctx=ctx,
|
|
402
457
|
tools=tools,
|
|
403
|
-
log_event="
|
|
458
|
+
log_event=_SCAN_LOG_EVENTS["protect"],
|
|
404
459
|
)
|
|
405
460
|
|
|
406
461
|
_submit_hook_validation_checkin(
|
|
@@ -409,12 +464,12 @@ def submit_enforce_validation_checkin(
|
|
|
409
464
|
include_pipeline=resolve_include_pipeline(False, managed),
|
|
410
465
|
ctx=ctx,
|
|
411
466
|
tools=tools,
|
|
412
|
-
log_event=
|
|
467
|
+
log_event=_SCAN_LOG_EVENTS[feature],
|
|
413
468
|
)
|
|
414
469
|
|
|
415
470
|
|
|
416
471
|
def submit_sessions_validation_checkin(
|
|
417
|
-
client:
|
|
472
|
+
client: CheckInSubmitter,
|
|
418
473
|
*,
|
|
419
474
|
ctx: DeviceContext,
|
|
420
475
|
tools: list[InstalledTool],
|
|
@@ -430,7 +485,7 @@ def submit_sessions_validation_checkin(
|
|
|
430
485
|
status="disabled",
|
|
431
486
|
ctx=ctx,
|
|
432
487
|
tools=tools,
|
|
433
|
-
log_event="
|
|
488
|
+
log_event=_SCAN_LOG_EVENTS["sessions"],
|
|
434
489
|
)
|
|
435
490
|
return
|
|
436
491
|
_submit_hook_validation_checkin(
|
|
@@ -439,7 +494,7 @@ def submit_sessions_validation_checkin(
|
|
|
439
494
|
include_pipeline=True,
|
|
440
495
|
ctx=ctx,
|
|
441
496
|
tools=tools,
|
|
442
|
-
log_event="
|
|
497
|
+
log_event=_SCAN_LOG_EVENTS["sessions"],
|
|
443
498
|
)
|
|
444
499
|
|
|
445
500
|
|
|
@@ -581,7 +636,7 @@ def _daemon_degraded_message(detail: Mapping[str, object]) -> str:
|
|
|
581
636
|
|
|
582
637
|
|
|
583
638
|
def submit_daemon_checkin(
|
|
584
|
-
client:
|
|
639
|
+
client: CheckInSubmitter,
|
|
585
640
|
*,
|
|
586
641
|
ctx: DeviceContext,
|
|
587
642
|
tools: list[InstalledTool],
|
|
@@ -622,7 +677,7 @@ def submit_daemon_checkin(
|
|
|
622
677
|
error_message=error_message,
|
|
623
678
|
)
|
|
624
679
|
payload["daemon_detail"] = detail
|
|
625
|
-
_submit_payload(client, payload, log_event="
|
|
680
|
+
_submit_payload(client, payload, log_event=_SCAN_LOG_EVENTS["daemon"])
|
|
626
681
|
|
|
627
682
|
|
|
628
683
|
def _run_isolated(feature: str, run: Callable[[], None]) -> None:
|
|
@@ -645,7 +700,7 @@ def _run_isolated(feature: str, run: Callable[[], None]) -> None:
|
|
|
645
700
|
|
|
646
701
|
|
|
647
702
|
def submit_validation_checkins(
|
|
648
|
-
client:
|
|
703
|
+
client: CheckInSubmitter,
|
|
649
704
|
*,
|
|
650
705
|
ctx: DeviceContext,
|
|
651
706
|
tools: list[InstalledTool],
|
|
@@ -666,20 +721,114 @@ def submit_validation_checkins(
|
|
|
666
721
|
)
|
|
667
722
|
|
|
668
723
|
|
|
724
|
+
def build_batch_checkin_payload(
|
|
725
|
+
ctx: DeviceContext,
|
|
726
|
+
tools: list[InstalledTool],
|
|
727
|
+
payloads: list[dict[str, object]],
|
|
728
|
+
) -> dict[str, object]:
|
|
729
|
+
"""Fold single-form payloads into one batch body.
|
|
730
|
+
|
|
731
|
+
Every captured payload was built from the same ``ctx`` + ``tools``, so the
|
|
732
|
+
device half goes out once and each entry keeps only its feature half.
|
|
733
|
+
"""
|
|
734
|
+
return {
|
|
735
|
+
**ctx,
|
|
736
|
+
"tools": tools,
|
|
737
|
+
"features": [
|
|
738
|
+
{
|
|
739
|
+
key: value
|
|
740
|
+
for key, value in payload.items()
|
|
741
|
+
if key not in BATCH_CHECKIN_DEVICE_KEYS
|
|
742
|
+
}
|
|
743
|
+
for payload in payloads
|
|
744
|
+
],
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
def _submit_batch(client: RunlayerClient, payload: dict[str, object]) -> bool:
|
|
749
|
+
"""Send one batch; True when the single-form path should run instead.
|
|
750
|
+
|
|
751
|
+
Falling back covers a backend without the batch route (the client maps
|
|
752
|
+
that 404 to ``{"unsupported": True}``) and a rejected body (422): one
|
|
753
|
+
refused feature must not cost the others their liveness, which the
|
|
754
|
+
sequential path guarantees by construction. Any other failure is final for
|
|
755
|
+
this tick — replaying five requests against a struggling backend would
|
|
756
|
+
defeat the batching.
|
|
757
|
+
"""
|
|
758
|
+
for attempt in range(len(_CHECKIN_RETRY_DELAYS_SECONDS) + 1):
|
|
759
|
+
try:
|
|
760
|
+
response = client.submit_aiwatch_checkin_batch(payload)
|
|
761
|
+
except httpx.HTTPStatusError as exc:
|
|
762
|
+
status_code = exc.response.status_code
|
|
763
|
+
logger.warning(
|
|
764
|
+
"aiwatch_checkin_batch_rejected",
|
|
765
|
+
status_code=status_code,
|
|
766
|
+
response_body=exc.response.text[
|
|
767
|
+
:_CHECKIN_REJECTED_RESPONSE_BODY_MAX_LEN
|
|
768
|
+
],
|
|
769
|
+
)
|
|
770
|
+
return status_code == 422
|
|
771
|
+
except (httpx.TransportError, OSError) as exc:
|
|
772
|
+
if attempt == len(_CHECKIN_RETRY_DELAYS_SECONDS):
|
|
773
|
+
logger.warning("aiwatch_checkin_batch_failed", error=str(exc))
|
|
774
|
+
return False
|
|
775
|
+
time.sleep(_CHECKIN_RETRY_DELAYS_SECONDS[attempt])
|
|
776
|
+
except (httpx.HTTPError, ValueError) as exc:
|
|
777
|
+
logger.warning("aiwatch_checkin_batch_failed", error=str(exc))
|
|
778
|
+
return False
|
|
779
|
+
else:
|
|
780
|
+
if response.get("unsupported"):
|
|
781
|
+
logger.debug("aiwatch_checkin_batch_unsupported")
|
|
782
|
+
return True
|
|
783
|
+
return False
|
|
784
|
+
return False
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
def _flush_scan_checkins(
|
|
788
|
+
client: RunlayerClient,
|
|
789
|
+
*,
|
|
790
|
+
ctx: DeviceContext,
|
|
791
|
+
tools: list[InstalledTool],
|
|
792
|
+
payloads: list[dict[str, object]],
|
|
793
|
+
) -> None:
|
|
794
|
+
if not payloads:
|
|
795
|
+
return
|
|
796
|
+
should_fall_back = _submit_batch(
|
|
797
|
+
client, build_batch_checkin_payload(ctx, tools, payloads)
|
|
798
|
+
)
|
|
799
|
+
if not should_fall_back:
|
|
800
|
+
return
|
|
801
|
+
for payload in payloads:
|
|
802
|
+
_submit_payload(
|
|
803
|
+
client,
|
|
804
|
+
payload,
|
|
805
|
+
log_event=_SCAN_LOG_EVENTS.get(
|
|
806
|
+
str(payload.get("feature")), "aiwatch_checkin_failed"
|
|
807
|
+
),
|
|
808
|
+
)
|
|
809
|
+
|
|
810
|
+
|
|
669
811
|
def submit_all_scan_checkins(client: RunlayerClient, result: ScanResult) -> None:
|
|
670
812
|
"""Submit every best-effort AI Watch check-in for a completed scan.
|
|
671
813
|
|
|
672
814
|
Owns all scan check-in policy: the enforce + sessions hook-validation
|
|
673
815
|
check-ins, the daemon fleet-health check-in, plus the final detect check-in.
|
|
674
816
|
Detect runs last so its current container health wins over MCP ingestion,
|
|
675
|
-
including when the scan found servers. Each is independently guarded so a
|
|
676
|
-
failure — corrupt MDM config, a network blip — never interrupts
|
|
817
|
+
including when the scan found servers. Each is independently guarded so a
|
|
818
|
+
transient failure — corrupt MDM config, a network blip — never interrupts
|
|
819
|
+
the scan. The builders write into a collector and the captured payloads go
|
|
820
|
+
out as one batch request (one request per feature on backends without the
|
|
821
|
+
batch route), so the per-feature ordering above is preserved either way.
|
|
677
822
|
Callers just hand over the client + scan result.
|
|
678
823
|
"""
|
|
679
824
|
ctx = device_context_dict(result)
|
|
680
|
-
|
|
825
|
+
collector = _CheckInCollector(client)
|
|
826
|
+
submit_validation_checkins(collector, ctx=ctx, tools=result.tools)
|
|
681
827
|
_run_isolated(
|
|
682
828
|
"daemon",
|
|
683
|
-
lambda: submit_daemon_checkin(
|
|
829
|
+
lambda: submit_daemon_checkin(collector, ctx=ctx, tools=result.tools),
|
|
830
|
+
)
|
|
831
|
+
_run_isolated("detect", lambda: submit_detect_checkin(collector, result))
|
|
832
|
+
_flush_scan_checkins(
|
|
833
|
+
client, ctx=ctx, tools=result.tools, payloads=collector.payloads
|
|
684
834
|
)
|
|
685
|
-
_run_isolated("detect", lambda: submit_detect_checkin(client, result))
|
|
@@ -448,6 +448,22 @@ class RunlayerClient(CatalogClientMixin):
|
|
|
448
448
|
response.raise_for_status()
|
|
449
449
|
return response.json()
|
|
450
450
|
|
|
451
|
+
def submit_aiwatch_checkin_batch(self, payload: dict[str, Any]) -> dict[str, Any]:
|
|
452
|
+
"""Submit several feature check-ins for one device in a single request.
|
|
453
|
+
|
|
454
|
+
Returns {"unsupported": True} when the backend predates the batch route
|
|
455
|
+
so the caller can fall back to one request per feature.
|
|
456
|
+
"""
|
|
457
|
+
with self._client(timeout=_AIWATCH_CHECKIN_TIMEOUT) as client:
|
|
458
|
+
response = client.post(
|
|
459
|
+
f"{self.base_url}/api/v1/ai-watch/check-in/batch",
|
|
460
|
+
json=payload,
|
|
461
|
+
)
|
|
462
|
+
if response.status_code == 404:
|
|
463
|
+
return {"unsupported": True}
|
|
464
|
+
response.raise_for_status()
|
|
465
|
+
return response.json()
|
|
466
|
+
|
|
451
467
|
def get_aiwatch_config(
|
|
452
468
|
self, *, device_id: str | None = None
|
|
453
469
|
) -> SyncedAIWatchConfig | None:
|
|
@@ -38,7 +38,11 @@ from runlayer_cli.hook_install.daemon_lifecycle import (
|
|
|
38
38
|
ensure_daemon_unit,
|
|
39
39
|
ensure_scan_unit,
|
|
40
40
|
)
|
|
41
|
-
from runlayer_cli.hook_install.llm_routing import
|
|
41
|
+
from runlayer_cli.hook_install.llm_routing import (
|
|
42
|
+
probe_gateway,
|
|
43
|
+
reconcile_routing,
|
|
44
|
+
unroute,
|
|
45
|
+
)
|
|
42
46
|
from runlayer_cli.install_window import InstallWindowState, install_window_state
|
|
43
47
|
from runlayer_cli.mdm_config import (
|
|
44
48
|
ManagedConfig,
|
|
@@ -352,6 +356,7 @@ def _llm_routing_step(
|
|
|
352
356
|
base_url=_configured_llm_routing_base_url(managed),
|
|
353
357
|
scope=scope,
|
|
354
358
|
fetch_decision=fetch_decision,
|
|
359
|
+
probe=probe_gateway,
|
|
355
360
|
)
|
|
356
361
|
if outcome is None:
|
|
357
362
|
typer.secho(
|
|
@@ -727,6 +727,16 @@ def _run_scan(
|
|
|
727
727
|
fg=typer.colors.YELLOW,
|
|
728
728
|
)
|
|
729
729
|
|
|
730
|
+
if submission.backend_incomplete and not quiet:
|
|
731
|
+
detail = ", ".join(
|
|
732
|
+
f"{category}/{surface} ({reason})"
|
|
733
|
+
for category, surface, reason in submission.backend_incomplete
|
|
734
|
+
)
|
|
735
|
+
typer.secho(
|
|
736
|
+
f"{WARN} Submitted; server marked surfaces incomplete: {detail}",
|
|
737
|
+
fg=typer.colors.YELLOW,
|
|
738
|
+
)
|
|
739
|
+
|
|
730
740
|
# The WARN lines above already told the user what happened; here we only
|
|
731
741
|
# act on the exit-code policy the orchestrator computed.
|
|
732
742
|
exit_code = submission.exit_code
|
|
@@ -6,7 +6,6 @@ import platform as plat
|
|
|
6
6
|
import sys
|
|
7
7
|
from collections.abc import MutableMapping
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
-
from datetime import datetime
|
|
10
9
|
from enum import Enum
|
|
11
10
|
from pathlib import Path
|
|
12
11
|
from typing import Any, Callable, cast
|
|
@@ -54,6 +53,7 @@ from runlayer_cli.hook_install.clients import (
|
|
|
54
53
|
from runlayer_cli.hook_install.clients import (
|
|
55
54
|
uninstall_client as _hook_install_uninstall_client,
|
|
56
55
|
)
|
|
56
|
+
from runlayer_cli.hook_install.config_backup import backup_path_for, prune_backups
|
|
57
57
|
from runlayer_cli.hook_install.console_user import reown_to_console_user
|
|
58
58
|
from runlayer_cli.hook_install.paths import (
|
|
59
59
|
InstallScope,
|
|
@@ -323,17 +323,16 @@ def _backup_file(file_path: Path, *, home: Path | None = None) -> Path | None:
|
|
|
323
323
|
With *home* set the read/write are link-safe (root MDM writes into the
|
|
324
324
|
user-controlled home can't be redirected by a planted symlink, nor leak a
|
|
325
325
|
root-only file into a user-readable backup — ENG-3217); otherwise plain path
|
|
326
|
-
ops are used.
|
|
327
|
-
|
|
326
|
+
ops are used. Older backups beyond the retention cap are pruned so repeated
|
|
327
|
+
installs never pile up. Returns the backup path, or ``None`` when there is
|
|
328
|
+
no real file to back up.
|
|
328
329
|
"""
|
|
329
330
|
data = maybe_safe_read_bytes(file_path, home=home)
|
|
330
331
|
if data is None:
|
|
331
332
|
return None
|
|
332
|
-
|
|
333
|
-
backup_path = file_path.with_name(
|
|
334
|
-
f"{file_path.stem}.backup_{timestamp}{file_path.suffix}"
|
|
335
|
-
)
|
|
333
|
+
backup_path = backup_path_for(file_path)
|
|
336
334
|
maybe_safe_write_bytes(backup_path, data, home=home)
|
|
335
|
+
prune_backups(file_path, home=home)
|
|
337
336
|
return backup_path
|
|
338
337
|
|
|
339
338
|
|
|
@@ -123,6 +123,10 @@ def normalize_event_name(event: str) -> str:
|
|
|
123
123
|
# output can carry sensitive data just like a successful tool's result.
|
|
124
124
|
_POST_TOOL_EVENTS = frozenset({"PostToolUse", "PostToolUseFailure"})
|
|
125
125
|
|
|
126
|
+
# Session events whose hook output may add model-visible context.
|
|
127
|
+
_CONTEXT_EVENTS = frozenset({"SessionStart", "UserPromptSubmit"})
|
|
128
|
+
_CONTEXT_CLIENTS = frozenset({Client.CLAUDE_CODE, Client.CODEX})
|
|
129
|
+
|
|
126
130
|
# Cline parses stdout by scanning for lines prefixed ``HOOK_CONTROL\t`` (last one
|
|
127
131
|
# wins). If NO prefixed line exists it instead requires the entire trimmed stdout
|
|
128
132
|
# to be valid JSON, so any incidental logging would corrupt the decision. Always
|
|
@@ -489,7 +493,16 @@ def should_noop_for_devin(client: Client, *, tool_name: str = "") -> bool:
|
|
|
489
493
|
return False
|
|
490
494
|
if tool_name in _CLAUDE_CODE_BUILTIN_TOOLS:
|
|
491
495
|
return False
|
|
492
|
-
|
|
496
|
+
# ``CLAUDECODE`` is a per-invocation marker Claude Code exports to the
|
|
497
|
+
# subprocesses it spawns; its absence in the forwarded request env means
|
|
498
|
+
# "this request did not come from a nested Claude Code host." Read it
|
|
499
|
+
# forwarded-only so a daemon that inherited ``CLAUDECODE`` into its own
|
|
500
|
+
# long-lived ``os.environ`` cannot poison every daemon-served request for
|
|
501
|
+
# its lifetime -- the inline path (no ``HookIO`` or not daemon-served)
|
|
502
|
+
# still falls through to ``os.environ`` for a real nested host.
|
|
503
|
+
if tool_name not in _DEVIN_BUILTIN_TOOLS and hook_io.getenv(
|
|
504
|
+
"CLAUDECODE", forwarded_only=True
|
|
505
|
+
):
|
|
493
506
|
return False
|
|
494
507
|
return True
|
|
495
508
|
|
|
@@ -745,6 +758,22 @@ class HookResponse:
|
|
|
745
758
|
return _cline_control({"overrideInput": tool_input})
|
|
746
759
|
return None
|
|
747
760
|
|
|
761
|
+
def allow_with_context(self, context: str) -> str | None:
|
|
762
|
+
"""Allow a session event and add model-visible context.
|
|
763
|
+
|
|
764
|
+
Claude Code and Codex share the ``hookSpecificOutput.additionalContext``
|
|
765
|
+
contract on session start and prompt submit.
|
|
766
|
+
"""
|
|
767
|
+
if self._client in _CONTEXT_CLIENTS and self._event in _CONTEXT_EVENTS:
|
|
768
|
+
return json.dumps(
|
|
769
|
+
{
|
|
770
|
+
"hookSpecificOutput": {
|
|
771
|
+
"hookEventName": self._event,
|
|
772
|
+
"additionalContext": context,
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
)
|
|
776
|
+
|
|
748
777
|
def allow_with_notice(self, notice: str) -> str | None:
|
|
749
778
|
"""Allow carrying a user-visible one-liner, or ``None`` when this client
|
|
750
779
|
has no such channel (Claude Code documents ``systemMessage`` as a common
|
|
@@ -60,6 +60,9 @@ HOOK_ENV_ALLOWLIST = frozenset(
|
|
|
60
60
|
# Retry kill switch: read at send time in relay._post; must ride the
|
|
61
61
|
# request env or daemon-served hooks silently keep the default retries.
|
|
62
62
|
"RUNLAYER_HOOK_RETRIES",
|
|
63
|
+
# Plugin routing-context kill switch (hook/plugin_context.py): same
|
|
64
|
+
# reason as the gzip switch above.
|
|
65
|
+
"RUNLAYER_PLUGIN_CONTEXT",
|
|
63
66
|
"USERPROFILE",
|
|
64
67
|
}
|
|
65
68
|
)
|
|
@@ -66,6 +66,7 @@ from runlayer_cli.hook.relay import (
|
|
|
66
66
|
uses_managed_credential,
|
|
67
67
|
)
|
|
68
68
|
from runlayer_cli.hook.windsurf_payload import adapt_windsurf_payload
|
|
69
|
+
from runlayer_cli.hook.plugin_context import build_plugin_context
|
|
69
70
|
from runlayer_cli.mdm_config import (
|
|
70
71
|
AIWatchMode,
|
|
71
72
|
resolve_install_hooks,
|
|
@@ -1144,6 +1145,34 @@ def _handle_permission_request(ctx: _DispatchCtx) -> None:
|
|
|
1144
1145
|
_write(ctx.resp.allow())
|
|
1145
1146
|
|
|
1146
1147
|
|
|
1148
|
+
_PLUGIN_CONTEXT_CLIENTS = frozenset({Client.CLAUDE_CODE, Client.CODEX})
|
|
1149
|
+
|
|
1150
|
+
|
|
1151
|
+
def _plugin_context_output(ctx: _DispatchCtx) -> str | None:
|
|
1152
|
+
"""Session/prompt output carrying Runlayer Plugin routing rules.
|
|
1153
|
+
|
|
1154
|
+
None when the client or event has no context slot, or the built-in plugin
|
|
1155
|
+
is not configured for this session, so callers fall back to plain allow.
|
|
1156
|
+
"""
|
|
1157
|
+
if ctx.client not in _PLUGIN_CONTEXT_CLIENTS or ctx.hook_type not in (
|
|
1158
|
+
"SessionStart",
|
|
1159
|
+
"UserPromptSubmit",
|
|
1160
|
+
):
|
|
1161
|
+
return None
|
|
1162
|
+
cwd = ctx.input_data.get("cwd", "") or hook_io.getcwd()
|
|
1163
|
+
context = build_plugin_context(ctx.client, cwd)
|
|
1164
|
+
if context is None:
|
|
1165
|
+
return None
|
|
1166
|
+
return ctx.resp.allow_with_context(context)
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
def _handle_session_start(ctx: _DispatchCtx) -> None:
|
|
1170
|
+
forward_event(
|
|
1171
|
+
ctx.client.value, ctx.original_hook_type, ctx.input_data, debug=ctx.debug
|
|
1172
|
+
)
|
|
1173
|
+
_write(_plugin_context_output(ctx) or ctx.resp.observational())
|
|
1174
|
+
|
|
1175
|
+
|
|
1147
1176
|
def _handle_session_event(ctx: _DispatchCtx) -> None:
|
|
1148
1177
|
if ctx.hook_type == "UserPromptSubmit" and ctx.client in (
|
|
1149
1178
|
Client.CLAUDE_CODE,
|
|
@@ -1153,7 +1182,7 @@ def _handle_session_event(ctx: _DispatchCtx) -> None:
|
|
|
1153
1182
|
forward_event(
|
|
1154
1183
|
ctx.client.value, ctx.original_hook_type, ctx.input_data, debug=ctx.debug
|
|
1155
1184
|
)
|
|
1156
|
-
_write(ctx.resp.allow())
|
|
1185
|
+
_write(_plugin_context_output(ctx) or ctx.resp.allow())
|
|
1157
1186
|
|
|
1158
1187
|
|
|
1159
1188
|
def _handle_post_tool_use(ctx: _DispatchCtx) -> None:
|
|
@@ -1359,6 +1388,7 @@ _DISPATCH_TABLE: dict[str, Callable[[_DispatchCtx], None]] = {
|
|
|
1359
1388
|
"beforeShellExecution": _handle_shell_execution,
|
|
1360
1389
|
"BeforeShellExecution": _handle_shell_execution,
|
|
1361
1390
|
"PermissionRequest": _handle_permission_request,
|
|
1391
|
+
"SessionStart": _handle_session_start,
|
|
1362
1392
|
"SubagentStart": _handle_session_event,
|
|
1363
1393
|
"UserPromptSubmit": _handle_session_event,
|
|
1364
1394
|
"PostToolUse": _handle_post_tool_use,
|