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.
Files changed (866) hide show
  1. {runlayer-0.31.0 → runlayer-0.31.2}/AGENTS.md +2 -0
  2. {runlayer-0.31.0 → runlayer-0.31.2}/Makefile +1 -1
  3. {runlayer-0.31.0 → runlayer-0.31.2}/PKG-INFO +1 -1
  4. {runlayer-0.31.0 → runlayer-0.31.2}/pyproject.toml +1 -1
  5. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch.py +2 -3
  6. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_checkin.py +178 -29
  7. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/api.py +16 -0
  8. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_setup.py +6 -1
  9. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/scan.py +10 -0
  10. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/setup.py +6 -7
  11. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/clients.py +30 -1
  12. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/daemon_protocol.py +3 -0
  13. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/dispatch.py +31 -1
  14. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/hook_io.py +39 -2
  15. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/mcp_lookup.py +31 -3
  16. runlayer-0.31.2/runlayer_cli/hook/plugin_context.py +172 -0
  17. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/clients.py +170 -79
  18. runlayer-0.31.2/runlayer_cli/hook_install/config_backup.py +106 -0
  19. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/console_user.py +48 -16
  20. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/llm_routing.py +91 -29
  21. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/launcher_inspection.py +31 -19
  22. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/service.py +34 -13
  23. {runlayer-0.31.0 → runlayer-0.31.2}/tests/conftest.py +32 -0
  24. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan_submit.py +50 -0
  25. runlayer-0.31.2/tests/test_aiwatch_checkin_batch.py +191 -0
  26. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_daemon_dispatch.py +27 -0
  27. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli.py +14 -3
  28. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_client_presence_evasion.py +1 -1
  29. runlayer-0.31.2/tests/test_config_backup.py +210 -0
  30. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_console_user.py +103 -0
  31. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_mdm_scope.py +118 -0
  32. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_module.py +177 -0
  33. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_io.py +100 -1
  34. runlayer-0.31.2/tests/test_hook_plugin_context.py +314 -0
  35. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_python.py +92 -0
  36. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hooks_relay.py +0 -14
  37. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_launcher_inspection.py +136 -5
  38. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_llm_routing.py +32 -0
  39. runlayer-0.31.2/tests/test_llm_routing_probe.py +116 -0
  40. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_llm_routing_reconcile.py +135 -0
  41. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_logging.py +8 -41
  42. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_service.py +64 -4
  43. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_hooks.py +22 -0
  44. {runlayer-0.31.0 → runlayer-0.31.2}/.gitignore +0 -0
  45. {runlayer-0.31.0 → runlayer-0.31.2}/.python-version +0 -0
  46. {runlayer-0.31.0 → runlayer-0.31.2}/CLAUDE.md +0 -0
  47. {runlayer-0.31.0 → runlayer-0.31.2}/LICENSE +0 -0
  48. {runlayer-0.31.0 → runlayer-0.31.2}/README.md +0 -0
  49. {runlayer-0.31.0 → runlayer-0.31.2}/development.md +0 -0
  50. {runlayer-0.31.0 → runlayer-0.31.2}/hooks/README.md +0 -0
  51. {runlayer-0.31.0 → runlayer-0.31.2}/hooks/__init__.py +0 -0
  52. {runlayer-0.31.0 → runlayer-0.31.2}/hooks/debug_hook_binary.py +0 -0
  53. {runlayer-0.31.0 → runlayer-0.31.2}/hooks/runlayer-hook.sh +0 -0
  54. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/DEPLOYMENT.md +0 -0
  55. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/README.md +0 -0
  56. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/_version_file.py +0 -0
  57. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/aiwatch.spec +0 -0
  58. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/aiwatch_uninstall.spec +0 -0
  59. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/assets/aiwatch-icon-512.png +0 -0
  60. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/assets/aiwatch.ico +0 -0
  61. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/Dockerfile +0 -0
  62. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/Dockerfile.dockerignore +0 -0
  63. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/README.md +0 -0
  64. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/configmap.yaml +0 -0
  65. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/cronjob.yaml +0 -0
  66. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/daemonset.yaml +0 -0
  67. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/kustomization.yaml +0 -0
  68. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/namespace.yaml +0 -0
  69. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/k8s/secret.example.yaml +0 -0
  70. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/scan-host-users.sh +0 -0
  71. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/README.md +0 -0
  72. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/assert_inside_container.sh +0 -0
  73. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/run_smoke_test.sh +0 -0
  74. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/container/tests/stub-aiwatch.sh +0 -0
  75. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/install.ps1 +0 -0
  76. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/install.sh +0 -0
  77. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/Install.Tests.ps1 +0 -0
  78. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/Invoke-Tests.ps1 +0 -0
  79. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/fixtures/targets-glibc2.17.json +0 -0
  80. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/fixtures/targets.json +0 -0
  81. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/install/tests/test_install_sh.sh +0 -0
  82. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/aiwatch-config.json +0 -0
  83. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/aiwatch-credentials.example +0 -0
  84. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_aiwatch_packages.sh +0 -0
  85. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_onedir_manylinux.sh +0 -0
  86. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/build_packages.sh +0 -0
  87. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/cron.d-runlayer-aiwatch +0 -0
  88. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/cron.d-runlayer-cli +0 -0
  89. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/nfpm-aiwatch.yaml +0 -0
  90. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/nfpm.yaml +0 -0
  91. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-aiwatch-scan.sh +0 -0
  92. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-aiwatch-update.sh +0 -0
  93. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-cli-schedule.sh +0 -0
  94. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/run-cli-update.sh +0 -0
  95. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/README.md +0 -0
  96. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/pillar.example.sls +0 -0
  97. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/init.sls +0 -0
  98. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/templates/config.json.jinja +0 -0
  99. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/salt/runlayer-aiwatch/templates/credentials.jinja +0 -0
  100. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/README.md +0 -0
  101. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/assert_inside_container.sh +0 -0
  102. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/build_stub_packages.sh +0 -0
  103. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/check_package_markers.sh +0 -0
  104. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/ensure_host_nfpm.sh +0 -0
  105. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/run_smoke_tests.sh +0 -0
  106. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/linux/tests/test_variant_suffix.sh +0 -0
  107. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/adopt_keychain.sh +0 -0
  108. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_pkg.sh +0 -0
  109. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_pkg_runlayer.sh +0 -0
  110. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/build_uninstall_pkg.sh +0 -0
  111. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.bootstrap.plist +0 -0
  112. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.daemon.plist +0 -0
  113. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.enroll.plist +0 -0
  114. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.firefox-native-messaging-host.json +0 -0
  115. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.jamf.schema.json +0 -0
  116. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.mobileconfig +0 -0
  117. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.native-messaging-host.json +0 -0
  118. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.plist +0 -0
  119. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.update.plist +0 -0
  120. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.aiwatch.ws1.mobileconfig +0 -0
  121. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.mobileconfig +0 -0
  122. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.schedule.plist +0 -0
  123. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/com.runlayer.cli.update.plist +0 -0
  124. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/distribution.runlayer.xml +0 -0
  125. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/distribution.xml +0 -0
  126. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/entitlements.plist +0 -0
  127. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/postinstall +0 -0
  128. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/postinstall-runlayer +0 -0
  129. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/preinstall +0 -0
  130. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/scripts/preinstall-runlayer +0 -0
  131. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall-pkg/postinstall +0 -0
  132. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall-runlayer.sh +0 -0
  133. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/macos/uninstall.sh +0 -0
  134. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/py2exe/setup_py2exe.py +0 -0
  135. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/runlayer.spec +0 -0
  136. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/aiwatch-native-messaging-host.bat +0 -0
  137. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/aiwatch.wxs +0 -0
  138. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_hook_shim.ps1 +0 -0
  139. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_intunewin.ps1 +0 -0
  140. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_intunewin_runlayer.ps1 +0 -0
  141. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_msi.ps1 +0 -0
  142. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/build_msi_runlayer.ps1 +0 -0
  143. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-schedule-task/register-tasks.ps1 +0 -0
  144. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-schedule-task/unregister-tasks.ps1 +0 -0
  145. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-update-task/register-tasks.ps1 +0 -0
  146. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/cli-update-task/unregister-tasks.ps1 +0 -0
  147. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/detect-install.ps1 +0 -0
  148. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/tests/DetectInstall.Tests.ps1 +0 -0
  149. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/custom-detection/tests/Invoke-Tests.ps1 +0 -0
  150. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/handoff-exec-test/emit_handoff_script.py +0 -0
  151. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/handoff-exec-test/run-handoff-exec-test.ps1 +0 -0
  152. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/native-host-chromium.json +0 -0
  153. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/native-host-firefox.json +0 -0
  154. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/runlayer.wxs +0 -0
  155. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/RunlayerTaskCommon.ps1 +0 -0
  156. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/register-tasks.ps1 +0 -0
  157. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/remove-hooks.ps1 +0 -0
  158. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/CliScheduleTasks.Tests.ps1 +0 -0
  159. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/CliUpdateTasks.Tests.ps1 +0 -0
  160. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/Invoke-Tests.ps1 +0 -0
  161. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/RemoveHooks.Tests.ps1 +0 -0
  162. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/tests/ScheduledTasks.Tests.ps1 +0 -0
  163. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scheduled-task/unregister-tasks.ps1 +0 -0
  164. {runlayer-0.31.0 → runlayer-0.31.2}/packaging/windows/scripts/bootstrap.ps1 +0 -0
  165. {runlayer-0.31.0 → runlayer-0.31.2}/regex-engine-allowlist.txt +0 -0
  166. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/__init__.py +0 -0
  167. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_config_cache.py +0 -0
  168. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_config_sync.py +0 -0
  169. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_credential.py +0 -0
  170. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/aiwatch_uninstall.py +0 -0
  171. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/catalog_client.py +0 -0
  172. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/catalog_enrichment.py +0 -0
  173. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/cli_persistence.py +0 -0
  174. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/command_contract.py +0 -0
  175. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/command_metrics.py +0 -0
  176. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/__init__.py +0 -0
  177. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_config.py +0 -0
  178. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/aiwatch_update.py +0 -0
  179. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/auth.py +0 -0
  180. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/bootstrap.py +0 -0
  181. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/cache.py +0 -0
  182. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/__init__.py +0 -0
  183. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/commands.py +0 -0
  184. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/display.py +0 -0
  185. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/kinds.py +0 -0
  186. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/catalog/resolve.py +0 -0
  187. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/cli_update.py +0 -0
  188. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/credentials.py +0 -0
  189. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/decide_approval.py +0 -0
  190. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/deploy.py +0 -0
  191. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/doctor.py +0 -0
  192. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/enroll.py +0 -0
  193. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/hooks.py +0 -0
  194. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/interactive_find.py +0 -0
  195. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/keychain.py +0 -0
  196. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/logs.py +0 -0
  197. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/org_api_key.py +0 -0
  198. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/plugins.py +0 -0
  199. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/reconnect_account.py +0 -0
  200. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/reject_access_request.py +0 -0
  201. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/schedule.py +0 -0
  202. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/skills.py +0 -0
  203. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/status.py +0 -0
  204. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/terraform.py +0 -0
  205. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update.py +0 -0
  206. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update_privilege.py +0 -0
  207. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/update_scheduler.py +0 -0
  208. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/commands/url_handler.py +0 -0
  209. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/config.py +0 -0
  210. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/console.py +0 -0
  211. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/credential_store.py +0 -0
  212. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/__init__.py +0 -0
  213. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/runtime.py +0 -0
  214. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/server.py +0 -0
  215. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/status.py +0 -0
  216. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_pipe.py +0 -0
  217. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_scm.py +0 -0
  218. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/daemon/windows_service.py +0 -0
  219. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/__init__.py +0 -0
  220. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/config.py +0 -0
  221. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/docker_builder.py +0 -0
  222. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/schema_validation.py +0 -0
  223. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/deploy/service.py +0 -0
  224. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/enrollment.py +0 -0
  225. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/env_substitution.py +0 -0
  226. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/error_classification.py +0 -0
  227. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_contract.py +0 -0
  228. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_delivery.py +0 -0
  229. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_spool.py +0 -0
  230. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_summary.py +0 -0
  231. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/flow_trace.py +0 -0
  232. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/__init__.py +0 -0
  233. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/__main__.py +0 -0
  234. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/_transcript_stream_worker.py +0 -0
  235. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/copilot_cli_mcp_lookup.py +0 -0
  236. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/credential_state.py +0 -0
  237. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/daemon_client.py +0 -0
  238. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/failure.py +0 -0
  239. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/file_policy.py +0 -0
  240. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/host_override.py +0 -0
  241. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/log_silence.py +0 -0
  242. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/mcp_types.py +0 -0
  243. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/messages.py +0 -0
  244. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/relay.py +0 -0
  245. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/transcript_stream.py +0 -0
  246. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook/windsurf_payload.py +0 -0
  247. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/__init__.py +0 -0
  248. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/artifact_paths.py +0 -0
  249. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_extension.py +0 -0
  250. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_extensions.py +0 -0
  251. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/browser_policy.py +0 -0
  252. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/check.py +0 -0
  253. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/chromium_profile_health.py +0 -0
  254. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/credential_gate.py +0 -0
  255. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/daemon_lifecycle.py +0 -0
  256. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/edge_extension.py +0 -0
  257. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/firefox_extension.py +0 -0
  258. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/paths.py +0 -0
  259. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/presence.py +0 -0
  260. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/safe_fs.py +0 -0
  261. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/hook_install/windows_browser_policy.py +0 -0
  262. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/http_error_utils.py +0 -0
  263. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/identity_forward.py +0 -0
  264. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/index.html +0 -0
  265. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/install_window.py +0 -0
  266. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/installer_common.py +0 -0
  267. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/linux_installer.py +0 -0
  268. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/logging.py +0 -0
  269. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/macos_installer.py +0 -0
  270. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/macos_test_device_config.py +0 -0
  271. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/main.py +0 -0
  272. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/managed_policy_publication.py +0 -0
  273. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/mdm_config.py +0 -0
  274. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/metrics.py +0 -0
  275. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/metrics_flush.py +0 -0
  276. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/middleware.py +0 -0
  277. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models.py +0 -0
  278. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models_api.py +0 -0
  279. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/models_mcp.py +0 -0
  280. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/native_messaging.py +0 -0
  281. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth.py +0 -0
  282. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth_callback.py +0 -0
  283. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/oauth_guidance.py +0 -0
  284. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/paths.py +0 -0
  285. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/platform_installers.py +0 -0
  286. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/__init__.py +0 -0
  287. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/claude_manifest.py +0 -0
  288. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/constants.py +0 -0
  289. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/discovery.py +0 -0
  290. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/installer.py +0 -0
  291. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/layouts.py +0 -0
  292. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/models.py +0 -0
  293. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/plugins/sync_engine.py +0 -0
  294. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/product.py +0 -0
  295. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/regex_safe.py +0 -0
  296. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/runtime.py +0 -0
  297. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/safe_parse.py +0 -0
  298. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/__init__.py +0 -0
  299. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agent_definition_scanner.py +0 -0
  300. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agent_scan.py +0 -0
  301. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/__init__.py +0 -0
  302. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/detect.py +0 -0
  303. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/discover.py +0 -0
  304. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/install.py +0 -0
  305. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/languages.py +0 -0
  306. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/__init__.py +0 -0
  307. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/_common.py +0 -0
  308. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/cargo.py +0 -0
  309. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/dotnet.py +0 -0
  310. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/go.py +0 -0
  311. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/jvm.py +0 -0
  312. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/npm.py +0 -0
  313. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/manifests/python.py +0 -0
  314. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/openclaw_detector.py +0 -0
  315. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/redact.py +0 -0
  316. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/registry.py +0 -0
  317. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/report.py +0 -0
  318. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/agents/signatures.json +0 -0
  319. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/artifact_cache.py +0 -0
  320. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/bin_shims.py +0 -0
  321. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/claude_code_plugins.py +0 -0
  322. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/cli_binaries.py +0 -0
  323. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/client_presence.py +0 -0
  324. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/clients.py +0 -0
  325. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/codex_plugins.py +0 -0
  326. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/completeness.py +0 -0
  327. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/concurrency.py +0 -0
  328. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/config_parser.py +0 -0
  329. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/config_redact.py +0 -0
  330. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/container_command.py +0 -0
  331. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/container_limits.py +0 -0
  332. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/__init__.py +0 -0
  333. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/collect.py +0 -0
  334. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/collector.py +0 -0
  335. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/docker_cli.py +0 -0
  336. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/docker_socket.py +0 -0
  337. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/inspect_parse.py +0 -0
  338. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/k3s_cli.py +0 -0
  339. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/proc_walk.py +0 -0
  340. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/tar_walk.py +0 -0
  341. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/containers/windows_named_pipe.py +0 -0
  342. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/copilot_plugins.py +0 -0
  343. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/cursor_plugins.py +0 -0
  344. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/device.py +0 -0
  345. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/disguised_skills.py +0 -0
  346. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/file_collector.py +0 -0
  347. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/gemini_extensions.py +0 -0
  348. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/hidden_space_sweep.py +0 -0
  349. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/jetbrains_plugins.py +0 -0
  350. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/npm_global.py +0 -0
  351. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/opencode_plugins.py +0 -0
  352. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/orchestrator.py +0 -0
  353. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/pip_global.py +0 -0
  354. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/plugin_scanner.py +0 -0
  355. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/__init__.py +0 -0
  356. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/classify.py +0 -0
  357. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/enumerate.py +0 -0
  358. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/models.py +0 -0
  359. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/probes.py +0 -0
  360. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/redact.py +0 -0
  361. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/settings_override.py +0 -0
  362. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/processes/windows_owner.py +0 -0
  363. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/project_scanner.py +0 -0
  364. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/project_tree_match.py +0 -0
  365. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/renamed_plugin_caches.py +0 -0
  366. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/resource_governor.py +0 -0
  367. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/run_lock.py +0 -0
  368. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/scan_state.py +0 -0
  369. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/scanner_primitives.py +0 -0
  370. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skill_presence.py +0 -0
  371. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skill_scanner.py +0 -0
  372. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/skip_dirs.py +0 -0
  373. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/symlink_follow.py +0 -0
  374. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/symlink_identity.py +0 -0
  375. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/timing.py +0 -0
  376. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/vscode_extensions.py +0 -0
  377. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/warp_sqlite.py +0 -0
  378. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/windows_users.py +0 -0
  379. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_exec.py +0 -0
  380. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_limits.py +0 -0
  381. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_paths.py +0 -0
  382. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_presence.py +0 -0
  383. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_projects.py +0 -0
  384. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/scan/wsl_runtime_signals.py +0 -0
  385. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/AGENTS.md +0 -0
  386. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/CLAUDE.md +0 -0
  387. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/README.md +0 -0
  388. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/__init__.py +0 -0
  389. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/hashing.py +0 -0
  390. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/merkle.py +0 -0
  391. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/skill_id.py +0 -0
  392. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skill_identifier/types.py +0 -0
  393. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/__init__.py +0 -0
  394. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/device_sync.py +0 -0
  395. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/discovery.py +0 -0
  396. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/frontmatter.py +0 -0
  397. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/installer.py +0 -0
  398. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/installer_core.py +0 -0
  399. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/marker.py +0 -0
  400. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/models.py +0 -0
  401. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/names.py +0 -0
  402. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/scan_summary.py +0 -0
  403. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/skills/sync_engine.py +0 -0
  404. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/symbols.py +0 -0
  405. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/sync.py +0 -0
  406. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/telemetry.py +0 -0
  407. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/terraform_export.py +0 -0
  408. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/tls.py +0 -0
  409. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/tolerant_json.py +0 -0
  410. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/truststore_init.py +0 -0
  411. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/update_contract.py +0 -0
  412. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/update_source.py +0 -0
  413. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/updater.py +0 -0
  414. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/uuid_utils.py +0 -0
  415. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/uv_tool_cleanup.py +0 -0
  416. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/variant.py +0 -0
  417. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/README.md +0 -0
  418. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/__init__.py +0 -0
  419. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/config.py +0 -0
  420. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/exceptions.py +0 -0
  421. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/proxy.py +0 -0
  422. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/__init__.py +0 -0
  423. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/base.py +0 -0
  424. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/macos.py +0 -0
  425. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/verified_local_proxy/verification/windows.py +0 -0
  426. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_installer.py +0 -0
  427. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_installer_verifier.py +0 -0
  428. {runlayer-0.31.0 → runlayer-0.31.2}/runlayer_cli/windows_update_handoff.py +0 -0
  429. {runlayer-0.31.0 → runlayer-0.31.2}/scripts/check_published_hook_transport.py +0 -0
  430. {runlayer-0.31.0 → runlayer-0.31.2}/scripts/check_regex_engine.py +0 -0
  431. {runlayer-0.31.0 → runlayer-0.31.2}/scripts/smoke_installed_hooks.py +0 -0
  432. {runlayer-0.31.0 → runlayer-0.31.2}/tests/daemon_frame_helpers.py +0 -0
  433. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/__init__.py +0 -0
  434. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/cache/__init__.py +0 -0
  435. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/cache/test_cache.py +0 -0
  436. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/conftest.py +0 -0
  437. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/credentials/__init__.py +0 -0
  438. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/credentials/test_credentials.py +0 -0
  439. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/__init__.py +0 -0
  440. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/test_lifecycle.py +0 -0
  441. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/deploy/test_validate.py +0 -0
  442. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/antigravity.md +0 -0
  443. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/claude_code.md +0 -0
  444. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/claude_desktop.md +0 -0
  445. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cline.md +0 -0
  446. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cline_cli.md +0 -0
  447. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/codex.md +0 -0
  448. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/cursor.md +0 -0
  449. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/gemini_cli.md +0 -0
  450. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/github_copilot_cli.md +0 -0
  451. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/goose.md +0 -0
  452. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/opencode.md +0 -0
  453. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/vscode.md +0 -0
  454. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/windsurf.md +0 -0
  455. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/client_specs/zed.md +0 -0
  456. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.claude-plugin/marketplace.json +0 -0
  457. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.claude-plugin/plugin.json +0 -0
  458. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.lsp.json +0 -0
  459. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/.mcp.json +0 -0
  460. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/README.md +0 -0
  461. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/agents/README.md +0 -0
  462. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/agents/code-reviewer.md +0 -0
  463. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/commands/review.md +0 -0
  464. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/config.json +0 -0
  465. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/hooks/hooks.json +0 -0
  466. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/hooks/validate.sh +0 -0
  467. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/notes.txt +0 -0
  468. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/scripts/deploy.sh +0 -0
  469. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/settings.json +0 -0
  470. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/code-review/SKILL.md +0 -0
  471. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/code-review/prompts.md +0 -0
  472. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/SKILL.md +0 -0
  473. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills/ticket-triage/helper.py +0 -0
  474. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skills-v2/notes.md +0 -0
  475. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/skillsets/reference.md +0 -0
  476. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/fixtures/full_plugin/tool.ts +0 -0
  477. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/__init__.py +0 -0
  478. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/test_install_hooks.py +0 -0
  479. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/hooks/test_relay.py +0 -0
  480. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/org_api_key/__init__.py +0 -0
  481. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/org_api_key/test_org_api_key.py +0 -0
  482. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/__init__.py +0 -0
  483. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_add.py +0 -0
  484. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_mcp_fallback.py +0 -0
  485. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/plugins/test_push.py +0 -0
  486. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/run/__init__.py +0 -0
  487. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/run/test_run.py +0 -0
  488. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/__init__.py +0 -0
  489. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/conftest.py +0 -0
  490. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan.py +0 -0
  491. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/scan/test_scan_lock_isolation.py +0 -0
  492. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/setup/test_install_opencode.py +0 -0
  493. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/skills/__init__.py +0 -0
  494. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/skills/test_lifecycle.py +0 -0
  495. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/terraform/__init__.py +0 -0
  496. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/test_help_matrix.py +0 -0
  497. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/version/__init__.py +0 -0
  498. {runlayer-0.31.0 → runlayer-0.31.2}/tests/e2e/version/test_version.py +0 -0
  499. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/labels.json +0 -0
  500. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/debug_adapter/adapter.py +0 -0
  501. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/debug_adapter/pyproject.toml +0 -0
  502. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/flask_api/app.py +0 -0
  503. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/flask_api/requirements.txt +0 -0
  504. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/go_cli/go.mod +0 -0
  505. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/go_cli/main.go +0 -0
  506. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/node_web/package.json +0 -0
  507. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/non_agent/node_web/server.js +0 -0
  508. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_01/agent.py +0 -0
  509. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_01/pyproject.toml +0 -0
  510. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_02/agent.py +0 -0
  511. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_02/pyproject.toml +0 -0
  512. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_03/agent.py +0 -0
  513. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_03/pyproject.toml +0 -0
  514. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_04/agent.py +0 -0
  515. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_04/pyproject.toml +0 -0
  516. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_05/agent.py +0 -0
  517. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_05/pyproject.toml +0 -0
  518. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_06/agent.py +0 -0
  519. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_06/pyproject.toml +0 -0
  520. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_07/agent.py +0 -0
  521. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_07/pyproject.toml +0 -0
  522. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_08/agent.py +0 -0
  523. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_08/pyproject.toml +0 -0
  524. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_09/agent.ts +0 -0
  525. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_09/package.json +0 -0
  526. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_10/agent.ts +0 -0
  527. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_10/package.json +0 -0
  528. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_11/agent.ts +0 -0
  529. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_11/package.json +0 -0
  530. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_12/agent.ts +0 -0
  531. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_12/package.json +0 -0
  532. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_13/Cargo.toml +0 -0
  533. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_13/main.rs +0 -0
  534. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_14/go.mod +0 -0
  535. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_14/main.go +0 -0
  536. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_15/Main.java +0 -0
  537. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_15/pom.xml +0 -0
  538. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_16/Main.java +0 -0
  539. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_16/pom.xml +0 -0
  540. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_17/Program.cs +0 -0
  541. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_17/SemanticKernelAgent.csproj +0 -0
  542. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_18/package.json +0 -0
  543. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/agent_detection/samples/sample_18/server.ts +0 -0
  544. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/claude_code_config.json +0 -0
  545. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/claude_desktop_config.json +0 -0
  546. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/container_command_cases.json +0 -0
  547. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/container_label_normalization_cases.json +0 -0
  548. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/cursor_config.json +0 -0
  549. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/devin_cli_config.json +0 -0
  550. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/empty_config.json +0 -0
  551. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/goose_config.yaml +0 -0
  552. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/imported_claude_hook_guard.json +0 -0
  553. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/lifecycle_events.json +0 -0
  554. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_exec.json +0 -0
  555. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_file_tools.json +0 -0
  556. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_dispatch/devin_cli/pre_tool_use_mcp.json +0 -0
  557. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/event_hooks_matrix.json +0 -0
  558. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_failure_allow.json +0 -0
  559. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_failure_output_block.json +0 -0
  560. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_output_allow.json +0 -0
  561. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/post_tool_output_block.json +0 -0
  562. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_local_stdio_deny.json +0 -0
  563. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_mcp_managed_proxy_allow.json +0 -0
  564. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_allow.json +0 -0
  565. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_native_bash_deny.json +0 -0
  566. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/pre_tool_read_env_deny.json +0 -0
  567. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/claude_code/user_prompt_submit_event.json +0 -0
  568. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/event_hooks_matrix.json +0 -0
  569. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/permission_request_allow.json +0 -0
  570. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/permission_request_env_deny.json +0 -0
  571. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_event_allow.json +0 -0
  572. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_failure_allow.json +0 -0
  573. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_failure_output_block.json +0 -0
  574. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/post_tool_output_block.json +0 -0
  575. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_mcp_local_stdio_deny.json +0 -0
  576. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_mcp_managed_proxy_allow.json +0 -0
  577. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_allow.json +0 -0
  578. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/codex/pre_tool_native_bash_deny.json +0 -0
  579. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/after_file_edit_event.json +0 -0
  580. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_direct_url_allow.json +0 -0
  581. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_local_stdio_deny.json +0 -0
  582. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_mcp_managed_proxy_allow.json +0 -0
  583. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_read_file_allow.json +0 -0
  584. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_read_file_env_deny.json +0 -0
  585. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_shell_execution_allow.json +0 -0
  586. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_shell_execution_env_deny.json +0 -0
  587. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_tab_file_read_allow.json +0 -0
  588. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/before_tab_file_read_mcp_config_deny.json +0 -0
  589. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/event_hooks_matrix.json +0 -0
  590. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_allow.json +0 -0
  591. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_allow.json +0 -0
  592. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_failure_output_block.json +0 -0
  593. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/post_tool_use_output_block.json +0 -0
  594. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_allow_modified.json +0 -0
  595. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/pre_tool_native_bash_deny.json +0 -0
  596. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/hook_replay/cursor/stop_session_end_event.json +0 -0
  597. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/invalid_json.txt +0 -0
  598. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/junie_config.json +0 -0
  599. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/kilo_code_config.jsonc +0 -0
  600. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/kimi_code_config.json +0 -0
  601. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/macos_policy_reader.c +0 -0
  602. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/pi_config.json +0 -0
  603. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/roo_code_config.json +0 -0
  604. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/sse_server_config.json +0 -0
  605. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/vscode_config.json +0 -0
  606. {runlayer-0.31.0 → runlayer-0.31.2}/tests/fixtures/warp_config.json +0 -0
  607. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/__init__.py +0 -0
  608. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/conftest.py +0 -0
  609. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_credential.py +0 -0
  610. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_install.py +0 -0
  611. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_policy_publication.py +0 -0
  612. {runlayer-0.31.0 → runlayer-0.31.2}/tests/frozen/test_frozen_runlayer.py +0 -0
  613. {runlayer-0.31.0 → runlayer-0.31.2}/tests/hostile_inputs.py +0 -0
  614. {runlayer-0.31.0 → runlayer-0.31.2}/tests/macos_installer_helpers.py +0 -0
  615. {runlayer-0.31.0 → runlayer-0.31.2}/tests/platform_installer_helpers.py +0 -0
  616. {runlayer-0.31.0 → runlayer-0.31.2}/tests/plugin_installer_helpers.py +0 -0
  617. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/__init__.py +0 -0
  618. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/__init__.py +0 -0
  619. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/harness.py +0 -0
  620. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_agent_scan.py +0 -0
  621. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_detect.py +0 -0
  622. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_discover.py +0 -0
  623. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_eval.py +0 -0
  624. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_manifests.py +0 -0
  625. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_redact.py +0 -0
  626. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_registry.py +0 -0
  627. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/agents/test_report.py +0 -0
  628. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/conftest.py +0 -0
  629. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/__init__.py +0 -0
  630. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_classify.py +0 -0
  631. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_discovery.py +0 -0
  632. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_enumerate.py +0 -0
  633. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_probes.py +0 -0
  634. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_redact.py +0 -0
  635. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/processes/test_settings_override.py +0 -0
  636. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_agent_definition_scanner.py +0 -0
  637. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_agent_scan.py +0 -0
  638. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_completeness.py +0 -0
  639. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_config_redact.py +0 -0
  640. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_container_command.py +0 -0
  641. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_containers.py +0 -0
  642. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_docker_socket.py +0 -0
  643. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_k3s.py +0 -0
  644. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_phase_isolation.py +0 -0
  645. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_presence_decode_hardening.py +0 -0
  646. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_runtime_decode_hardening.py +0 -0
  647. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_skip_dirs.py +0 -0
  648. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_windows_named_pipe.py +0 -0
  649. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_exec.py +0 -0
  650. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_paths.py +0 -0
  651. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_presence.py +0 -0
  652. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_projects.py +0 -0
  653. {runlayer-0.31.0 → runlayer-0.31.2}/tests/scan/test_wsl_runtime_signals.py +0 -0
  654. {runlayer-0.31.0 → runlayer-0.31.2}/tests/sign_shards_smoke.ps1 +0 -0
  655. {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/__init__.py +0 -0
  656. {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/test_merkle.py +0 -0
  657. {runlayer-0.31.0 → runlayer-0.31.2}/tests/skill_identifier/test_skill_id.py +0 -0
  658. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_basename_dispatch.py +0 -0
  659. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_bootstrap.py +0 -0
  660. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_checkin.py +0 -0
  661. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_cache.py +0 -0
  662. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_command.py +0 -0
  663. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_isolation.py +0 -0
  664. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_config_sync.py +0 -0
  665. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_credential.py +0 -0
  666. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_hook_shim_packaging.py +0 -0
  667. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_hook_version.py +0 -0
  668. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_imports.py +0 -0
  669. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_setup_hooks.py +0 -0
  670. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_uninstall.py +0 -0
  671. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_uninstall_packaging.py +0 -0
  672. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_aiwatch_update_command.py +0 -0
  673. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_api.py +0 -0
  674. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_artifact_cache.py +0 -0
  675. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_auth.py +0 -0
  676. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_backwards_compatibility.py +0 -0
  677. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_bin_shims.py +0 -0
  678. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_browser_extension_install.py +0 -0
  679. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_browser_extensions.py +0 -0
  680. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cache.py +0 -0
  681. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_catalog_commands.py +0 -0
  682. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_catalog_enrichment.py +0 -0
  683. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_chromium_profile_health.py +0 -0
  684. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_code_plugins.py +0 -0
  685. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_json_integration.py +0 -0
  686. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_claude_output_replacement.py +0 -0
  687. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_backwards_compat.py +0 -0
  688. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_binaries.py +0 -0
  689. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_linux_schedule_assets.py +0 -0
  690. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cli_update_schedule_assets.py +0 -0
  691. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_client_presence.py +0 -0
  692. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_command_contract.py +0 -0
  693. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_command_metrics.py +0 -0
  694. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_config.py +0 -0
  695. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_container_label_contract.py +0 -0
  696. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_copilot_plugins.py +0 -0
  697. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credential_store.py +0 -0
  698. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credential_store_macos.py +0 -0
  699. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_credentials_commands.py +0 -0
  700. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_cursor_plugins.py +0 -0
  701. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_client.py +0 -0
  702. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_lifecycle.py +0 -0
  703. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_protocol.py +0 -0
  704. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_runtime.py +0 -0
  705. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_server.py +0 -0
  706. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_status.py +0 -0
  707. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_daemon_windows_pipe.py +0 -0
  708. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_debug_hook_binary.py +0 -0
  709. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_decide_approval.py +0 -0
  710. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_deploy_service.py +0 -0
  711. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_desktop_release_workflow.py +0 -0
  712. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_disguised_skills.py +0 -0
  713. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_dispatch_decode_hardening.py +0 -0
  714. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_docker_builder.py +0 -0
  715. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_docs_client_sync.py +0 -0
  716. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_doctor.py +0 -0
  717. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_edge_extension_install.py +0 -0
  718. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_endpoint_modes.py +0 -0
  719. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enroll_checkins.py +0 -0
  720. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enroll_command.py +0 -0
  721. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_enrollment.py +0 -0
  722. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_env_substitution.py +0 -0
  723. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_error_classification.py +0 -0
  724. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_firefox_extension_install.py +0 -0
  725. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_contract.py +0 -0
  726. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_delivery.py +0 -0
  727. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_spool.py +0 -0
  728. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_flow_trace.py +0 -0
  729. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_gemini_extensions.py +0 -0
  730. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hidden_space_sweep.py +0 -0
  731. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_binary_convergence.py +0 -0
  732. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_credential_rejection.py +0 -0
  733. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_dispatch_replay.py +0 -0
  734. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow.py +0 -0
  735. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_departed_harness.py +0 -0
  736. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_harness_closed_stdout.py +0 -0
  737. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_flow_operations.py +0 -0
  738. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_host_override.py +0 -0
  739. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_safe_fs.py +0 -0
  740. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_install_windows_safe_fs.py +0 -0
  741. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_messages.py +0 -0
  742. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_replay_fixtures.py +0 -0
  743. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_script.py +0 -0
  744. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_hook_shim_protocol.py +0 -0
  745. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_identity_forward.py +0 -0
  746. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_install_window.py +0 -0
  747. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_interactive_find.py +0 -0
  748. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_jetbrains_plugins.py +0 -0
  749. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_keychain_adopt.py +0 -0
  750. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_keychain_guard.py +0 -0
  751. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_lazy_enrollment.py +0 -0
  752. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_legacy_re2_tag_coupling.py +0 -0
  753. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_linux_cron_assets.py +0 -0
  754. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_linux_installer.py +0 -0
  755. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_logs.py +0 -0
  756. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_config_profile_assets.py +0 -0
  757. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_installer.py +0 -0
  758. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_managed_policy_publication.py +0 -0
  759. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_mdm_mode_compatibility.py +0 -0
  760. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_macos_plists.py +0 -0
  761. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_main_hook_dispatch.py +0 -0
  762. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_managed_policy_publication.py +0 -0
  763. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_manual_oauth.py +0 -0
  764. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_manylinux2014_lock_floor.py +0 -0
  765. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_mcp_lookup_decode_hardening.py +0 -0
  766. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_mdm_config.py +0 -0
  767. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_metrics.py +0 -0
  768. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_middleware.py +0 -0
  769. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_native_messaging.py +0 -0
  770. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_npm_global.py +0 -0
  771. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_browser_lock.py +0 -0
  772. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_callback_lifecycle.py +0 -0
  773. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_callback_port.py +0 -0
  774. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_error_guidance.py +0 -0
  775. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_sibling_wait.py +0 -0
  776. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_oauth_token_storage.py +0 -0
  777. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_opencode_plugins.py +0 -0
  778. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_org_api_key_commands.py +0 -0
  779. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_pip_global.py +0 -0
  780. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_platform_installers.py +0 -0
  781. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugin_layouts.py +0 -0
  782. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugin_scanner.py +0 -0
  783. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_commands.py +0 -0
  784. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_discovery.py +0 -0
  785. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_installer.py +0 -0
  786. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_installer_cursor_layout.py +0 -0
  787. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_plugins_sync.py +0 -0
  788. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_product.py +0 -0
  789. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_published_hook_transport.py +0 -0
  790. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_py310_compat.py +0 -0
  791. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_regex_parity.py +0 -0
  792. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_regex_safe_mirror_drift.py +0 -0
  793. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_renamed_plugin_caches.py +0 -0
  794. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_resource_governor.py +0 -0
  795. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_safe_parse.py +0 -0
  796. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_clients.py +0 -0
  797. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_concurrency.py +0 -0
  798. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_detect_error_checkin.py +0 -0
  799. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_device.py +0 -0
  800. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_memory_caps.py +0 -0
  801. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_no_findings.py +0 -0
  802. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_openclaw.py +0 -0
  803. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_parser.py +0 -0
  804. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_project.py +0 -0
  805. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_run_lock.py +0 -0
  806. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_skills.py +0 -0
  807. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_summary.py +0 -0
  808. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_timing.py +0 -0
  809. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_verbose.py +0 -0
  810. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scan_windows_profile.py +0 -0
  811. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_scanner_primitives.py +0 -0
  812. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_schedule_command.py +0 -0
  813. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_claude_desktop.py +0 -0
  814. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_config_formats.py +0 -0
  815. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_install_local_servers.py +0 -0
  816. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_setup_sync.py +0 -0
  817. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_names.py +0 -0
  818. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_presence.py +0 -0
  819. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skill_sync_credentials.py +0 -0
  820. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_commands.py +0 -0
  821. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_device_sync.py +0 -0
  822. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_discovery.py +0 -0
  823. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_installer.py +0 -0
  824. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_installer_core.py +0 -0
  825. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_marker.py +0 -0
  826. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_sync.py +0 -0
  827. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_skills_sync_command.py +0 -0
  828. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_status.py +0 -0
  829. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_symbols.py +0 -0
  830. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_sync.py +0 -0
  831. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_telemetry.py +0 -0
  832. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_terraform_commands.py +0 -0
  833. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_test_device_config.py +0 -0
  834. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_tls.py +0 -0
  835. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_transcript_decode_hardening.py +0 -0
  836. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_truststore_init.py +0 -0
  837. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_commands.py +0 -0
  838. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_contract.py +0 -0
  839. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_privilege.py +0 -0
  840. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_update_source.py +0 -0
  841. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_updater.py +0 -0
  842. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_url_handler.py +0 -0
  843. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_uv_tool_cleanup.py +0 -0
  844. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_variant.py +0 -0
  845. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_variant_packaging_contract.py +0 -0
  846. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_version_file.py +0 -0
  847. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_vscode_extensions.py +0 -0
  848. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_warp_sqlite.py +0 -0
  849. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_browser_policy.py +0 -0
  850. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_daemon_service.py +0 -0
  851. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_installer.py +0 -0
  852. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_installer_verifier.py +0 -0
  853. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_msi_sequencing.py +0 -0
  854. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_native_messaging_packaging.py +0 -0
  855. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_ps1_gates.py +0 -0
  856. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_scan_all_users.py +0 -0
  857. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_sign_shards.py +0 -0
  858. {runlayer-0.31.0 → runlayer-0.31.2}/tests/test_windows_update_handoff.py +0 -0
  859. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/__init__.py +0 -0
  860. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_config.py +0 -0
  861. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_proxy.py +0 -0
  862. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/__init__.py +0 -0
  863. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_base.py +0 -0
  864. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_macos.py +0 -0
  865. {runlayer-0.31.0 → runlayer-0.31.2}/tests/verified_local_proxy/test_verification/test_windows.py +0 -0
  866. {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.
@@ -30,7 +30,7 @@ version-bump:
30
30
  fi
31
31
 
32
32
  test:
33
- uv run pytest
33
+ uv run pytest -n auto
34
34
 
35
35
  test-e2e:
36
36
  uv run pytest tests/e2e -m e2e -v --tb=short -n auto
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: runlayer
3
- Version: 0.31.0
3
+ Version: 0.31.2
4
4
  Summary: A command-line interface for running MCP servers via HTTP transport
5
5
  Project-URL: Homepage, https://runlayer.com
6
6
  Project-URL: Documentation, https://docs.runlayer.com/
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "runlayer"
3
- version = "0.31.0"
3
+ version = "0.31.2"
4
4
  description = "A command-line interface for running MCP servers via HTTP transport"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -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 = sys.stdin.read()
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: RunlayerClient,
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: RunlayerClient,
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: RunlayerClient,
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: RunlayerClient, result: ScanResult) -> None:
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="aiwatch_detect_checkin_failed")
318
+ _submit_payload(client, payload, log_event=_SCAN_LOG_EVENTS["detect"])
259
319
 
260
320
 
261
- def _hook_host_detail(client: RunlayerClient) -> host_override.HostOverride | None:
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
- destination = getattr(client, "base_url", None)
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: RunlayerClient,
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: RunlayerClient,
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=f"aiwatch_{feature}_checkin_failed",
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="aiwatch_enforce_checkin_failed",
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="aiwatch_protect_checkin_failed",
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=log_event,
467
+ log_event=_SCAN_LOG_EVENTS[feature],
413
468
  )
414
469
 
415
470
 
416
471
  def submit_sessions_validation_checkin(
417
- client: RunlayerClient,
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="aiwatch_sessions_checkin_failed",
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="aiwatch_sessions_checkin_failed",
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: RunlayerClient,
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="aiwatch_daemon_checkin_failed")
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: RunlayerClient,
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 transient
676
- failure — corrupt MDM config, a network blip — never interrupts the scan.
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
- submit_validation_checkins(client, ctx=ctx, tools=result.tools)
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(client, ctx=ctx, tools=result.tools),
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 reconcile_routing, unroute
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. Returns the backup path, or ``None`` when there is no real file
327
- to back up.
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
- timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
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
- if tool_name not in _DEVIN_BUILTIN_TOOLS and hook_io.getenv("CLAUDECODE"):
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,