plugin-scanner 2.0.62__tar.gz → 2.0.63__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 (317) hide show
  1. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/pyproject.toml +1 -1
  3. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/pyproject.toml.bak +1 -1
  4. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/claude_code.py +8 -6
  5. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/commands.py +198 -46
  6. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/version.py +1 -1
  7. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_claude_adapter.py +10 -2
  8. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_runtime.py +347 -31
  9. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_surface_server.py +9 -3
  10. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.clusterfuzzlite/Dockerfile +0 -0
  11. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.clusterfuzzlite/build.sh +0 -0
  12. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.clusterfuzzlite/project.yaml +0 -0
  13. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  14. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.dockerignore +0 -0
  15. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/CODEOWNERS +0 -0
  16. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  17. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  18. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  19. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/dependabot.yml +0 -0
  20. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/ci.yml +0 -0
  21. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/codeql.yml +0 -0
  22. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/dependabot-uv-lock.yml +0 -0
  23. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/fuzz.yml +0 -0
  24. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/harness-smoke.yml +0 -0
  25. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/publish.yml +0 -0
  26. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.github/workflows/scorecard.yml +0 -0
  27. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.gitignore +0 -0
  28. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/.pre-commit-hooks.yaml +0 -0
  29. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/CONTRIBUTING.md +0 -0
  30. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/Dockerfile +0 -0
  31. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/LICENSE +0 -0
  32. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/README.md +0 -0
  33. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/SECURITY.md +0 -0
  34. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/index.html +0 -0
  35. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/package.json +0 -0
  36. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/pnpm-lock.yaml +0 -0
  37. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/public/brand/Logo_Whole.png +0 -0
  38. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/app.tsx +0 -0
  39. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/approval-center-layout.tsx +0 -0
  40. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/approval-center-primitives.tsx +0 -0
  41. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/approval-center-utils.ts +0 -0
  42. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/fleet-workspace.tsx +0 -0
  43. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/guard-api.ts +0 -0
  44. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/guard-demo.ts +0 -0
  45. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/guard-types.ts +0 -0
  46. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/main.tsx +0 -0
  47. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/receipts-workspace.tsx +0 -0
  48. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/runtime-overview.tsx +0 -0
  49. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/styles.css +0 -0
  50. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/src/vite-env.d.ts +0 -0
  51. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/tsconfig.json +0 -0
  52. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/dashboard/vite.config.ts +0 -0
  53. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docker-requirements.txt +0 -0
  54. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/approval-audit.md +0 -0
  55. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/architecture.md +0 -0
  56. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/get-started.md +0 -0
  57. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/harness-support.md +0 -0
  58. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/local-vs-cloud.md +0 -0
  59. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/guard/testing-matrix.md +0 -0
  60. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/trust/mcp-trust-draft.md +0 -0
  61. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/trust/plugin-trust-draft.md +0 -0
  62. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/docs/trust/skill-trust-local.md +0 -0
  63. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/fuzzers/manifest_fuzzer.py +0 -0
  64. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/requirements.txt +0 -0
  65. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/schemas/plugin-quality.v1.json +0 -0
  66. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/schemas/scan-result.v1.json +0 -0
  67. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/schemas/verify-result.v1.json +0 -0
  68. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/__init__.py +0 -0
  69. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/action_runner.py +0 -0
  70. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  71. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  72. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  73. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/claude.py +0 -0
  74. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  75. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  76. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  77. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  78. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  79. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  80. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  81. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  82. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  83. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/security.py +0 -0
  84. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  85. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/cli.py +0 -0
  86. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/cli_ui.py +0 -0
  87. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/config.py +0 -0
  88. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  89. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  90. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  91. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  92. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  93. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  94. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  95. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  96. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  97. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/github_reporting.py +0 -0
  98. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  99. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  100. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  101. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  102. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  103. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  104. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  105. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  106. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  107. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  108. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  109. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  110. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  111. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  112. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  113. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  114. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  115. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  116. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  117. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  118. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  119. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  120. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  121. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  122. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  123. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/config.py +0 -0
  124. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  125. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  126. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  127. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  128. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  129. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  130. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -0
  131. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  132. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  133. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  134. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/incident.py +0 -0
  135. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  136. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  137. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/models.py +0 -0
  138. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  139. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  140. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/protect.py +0 -0
  141. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  142. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  143. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  144. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  145. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  146. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  147. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/risk.py +0 -0
  148. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  149. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  150. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  151. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  152. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  153. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  154. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  155. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/shims.py +0 -0
  156. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/store.py +0 -0
  157. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  158. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  159. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/guard/types.py +0 -0
  160. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  161. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  162. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  163. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  164. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  165. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/models.py +0 -0
  166. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/path_support.py +0 -0
  167. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/policy.py +0 -0
  168. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  169. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/repo_detect.py +0 -0
  170. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/reporting.py +0 -0
  171. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  172. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/rules/registry.py +0 -0
  173. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/rules/specs.py +0 -0
  174. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/scanner.py +0 -0
  175. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/submission.py +0 -0
  176. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/suppressions.py +0 -0
  177. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  178. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  179. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  180. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_models.py +0 -0
  181. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  182. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  183. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  184. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/trust_specs.py +0 -0
  185. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/src/codex_plugin_scanner/verification.py +0 -0
  186. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/__init__.py +0 -0
  187. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/conftest.py +0 -0
  188. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/__init__.py +0 -0
  189. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  190. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  191. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/bad-plugin/secrets.js +0 -0
  192. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  193. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  194. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/README.md +0 -0
  195. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  196. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  197. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  198. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/code-quality-bad/evil.js +0 -0
  199. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/code-quality-bad/inject.js +0 -0
  200. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  201. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  202. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/README.md +0 -0
  203. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  204. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  205. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  206. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  207. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/.codexignore +0 -0
  208. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/LICENSE +0 -0
  209. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/README.md +0 -0
  210. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  211. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  212. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  213. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  214. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  215. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  216. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  217. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  218. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  219. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  220. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  221. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  222. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  223. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  224. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  225. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  226. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  227. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  228. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  229. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  230. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/mcp-canary-server.py +0 -0
  231. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  232. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  233. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/mit-license/LICENSE +0 -0
  234. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  235. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  236. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  237. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  238. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  239. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  240. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  241. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  242. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  243. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  244. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  245. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  246. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  247. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  248. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  249. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  250. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  251. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  252. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/LICENSE +0 -0
  253. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/README.md +0 -0
  254. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  255. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  256. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  257. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  258. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  259. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  260. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  261. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  262. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test-trust-scoring.py +0 -0
  263. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test-trust-specs.py +0 -0
  264. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_action_runner.py +0 -0
  265. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_best_practices.py +0 -0
  266. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_cisco_install_surfaces.py +0 -0
  267. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_cli.py +0 -0
  268. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_code_quality.py +0 -0
  269. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_config.py +0 -0
  270. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_coverage_remaining.py +0 -0
  271. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_ecosystems.py +0 -0
  272. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_edge_cases.py +0 -0
  273. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_final_coverage.py +0 -0
  274. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_approvals.py +0 -0
  275. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_bootstrap.py +0 -0
  276. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_capabilities.py +0 -0
  277. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_cli.py +0 -0
  278. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_codex_e2e.py +0 -0
  279. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_codex_install.py +0 -0
  280. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_codex_proxy.py +0 -0
  281. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_config_paths.py +0 -0
  282. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_connect_flow.py +0 -0
  283. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_consumer_mode.py +0 -0
  284. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_copilot_adapter.py +0 -0
  285. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_copilot_proxy.py +0 -0
  286. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_daemon_manager.py +0 -0
  287. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_events.py +0 -0
  288. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_launch_env.py +0 -0
  289. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_opencode_proxy.py +0 -0
  290. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_product_flow.py +0 -0
  291. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_protect.py +0 -0
  292. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_render.py +0 -0
  293. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_risk.py +0 -0
  294. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_store_migrations.py +0 -0
  295. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_guard_verdicts.py +0 -0
  296. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_hermes_adapter.py +0 -0
  297. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_integration.py +0 -0
  298. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_lint_fixes.py +0 -0
  299. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_live_cisco_smoke.py +0 -0
  300. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_manifest.py +0 -0
  301. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_marketplace.py +0 -0
  302. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_mcp_security.py +0 -0
  303. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_operational_security.py +0 -0
  304. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_policy.py +0 -0
  305. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_quality_artifact.py +0 -0
  306. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_rule_registry.py +0 -0
  307. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_scanner.py +0 -0
  308. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_schema_contracts.py +0 -0
  309. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_security.py +0 -0
  310. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_security_ops.py +0 -0
  311. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_skill_security.py +0 -0
  312. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_submission.py +0 -0
  313. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_trust_scoring.py +0 -0
  314. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_trust_specs.py +0 -0
  315. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_verification.py +0 -0
  316. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/tests/test_versioning.py +0 -0
  317. {plugin_scanner-2.0.62 → plugin_scanner-2.0.63}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.62
3
+ Version: 2.0.63
4
4
  Summary: Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows.
5
5
  Project-URL: Homepage, https://github.com/hashgraph-online/ai-plugin-scanner
6
6
  Project-URL: Repository, https://github.com/hashgraph-online/ai-plugin-scanner
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.62"
7
+ version = "2.0.63"
8
8
  description = "Lint, verify, and gate plugin ecosystems for maintainers, CI, and publish workflows."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hol-guard"
7
- version = "2.0.62"
7
+ version = "2.0.63"
8
8
  description = "Protect local AI harnesses with HOL Guard and run scanner checks for Codex, Claude, Cursor, Gemini, and OpenCode."
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -19,6 +19,7 @@ from ..shims import install_guard_shim, remove_guard_shim
19
19
  from .base import HarnessAdapter, HarnessContext, _ensure_path_within_root, _json_payload, _run_command_probe
20
20
 
21
21
  CLAUDE_GUARD_TOOL_MATCHER = "Bash|Read|Write|Edit|MultiEdit|WebFetch|WebSearch|mcp__.*"
22
+ CLAUDE_GUARD_POST_TOOL_MATCHER = f"{CLAUDE_GUARD_TOOL_MATCHER}|AskUserQuestion"
22
23
  CLAUDE_GUARD_NOTIFICATION_MATCHER = "permission_prompt"
23
24
  CLAUDE_GUARD_SESSION_START_MATCHERS = ("startup", "resume", "clear", "compact")
24
25
  CLAUDE_GUARD_TOOL_TIMEOUT_SECONDS = 30
@@ -45,7 +46,7 @@ def _sync_runtime_hook_groups(hooks: dict[str, object], hook_command: str) -> No
45
46
  for key, matcher, timeout in (
46
47
  ("PreToolUse", CLAUDE_GUARD_TOOL_MATCHER, CLAUDE_GUARD_TOOL_TIMEOUT_SECONDS),
47
48
  ("PermissionRequest", CLAUDE_GUARD_TOOL_MATCHER, CLAUDE_GUARD_NOTIFICATION_TIMEOUT_SECONDS),
48
- ("PostToolUse", CLAUDE_GUARD_TOOL_MATCHER, CLAUDE_GUARD_TOOL_TIMEOUT_SECONDS),
49
+ ("PostToolUse", CLAUDE_GUARD_POST_TOOL_MATCHER, CLAUDE_GUARD_TOOL_TIMEOUT_SECONDS),
49
50
  ("UserPromptSubmit", None, CLAUDE_GUARD_PROMPT_TIMEOUT_SECONDS),
50
51
  ("Notification", CLAUDE_GUARD_NOTIFICATION_MATCHER, CLAUDE_GUARD_NOTIFICATION_TIMEOUT_SECONDS),
51
52
  ("Stop", None, CLAUDE_GUARD_STOP_TIMEOUT_SECONDS),
@@ -519,12 +520,13 @@ class ClaudeCodeHarnessAdapter(HarnessAdapter):
519
520
  "function degraded(reason,data){"
520
521
  "const event=eventName(data);"
521
522
  "const message=`HOL Guard could not reach the local daemon (${reason}), so it is using Claude's native "
522
- "approval prompt as a safety fallback.`;"
523
+ "approval prompt as a temporary safety fallback.`;"
523
524
  "if(event==='UserPromptSubmit'){return '';}"
524
- "if(event==='PreToolUse'){return JSON.stringify({systemMessage:'HOL Guard opened this Claude approval "
525
- "prompt because local daemon evaluation was unavailable.',hookSpecificOutput:{hookEventName:'PreToolUse',"
526
- "permissionDecision:'ask',permissionDecisionReason:`${message} Choose Yes to allow it once, Yes during "
527
- "this session to trust the same action for this session, or No to keep it blocked.`}});}"
525
+ "if(event==='PreToolUse'){return JSON.stringify({systemMessage:'HOL Guard could not reach the local "
526
+ "daemon, so it cannot render the full HOL Guard approval flow.',hookSpecificOutput:{"
527
+ "hookEventName:'PreToolUse',permissionDecision:'ask',permissionDecisionReason:`${message} Keep this "
528
+ "action blocked unless you intentionally trust it. Restart Guard to restore the branded Allow once / "
529
+ "Allow during this session / Keep blocked flow.`}});}"
528
530
  "return '{}';"
529
531
  "}"
530
532
  "function shouldSuppressOutput(data,responseBody){"
@@ -1195,11 +1195,11 @@ def run_guard_command(
1195
1195
  _mark_claude_pending_permission_prompt_seen(store=store, payload=payload, notice=notice)
1196
1196
  _emit_native_hook_response(
1197
1197
  harness=args.harness,
1198
- policy_action="require-reapproval",
1198
+ policy_action="block",
1199
1199
  event_name="PermissionRequest",
1200
- reason="HOL Guard is keeping Claude's native permission prompt open for user review.",
1200
+ reason="HOL Guard is routing this approval through AskUserQuestion.",
1201
1201
  system_message=_claude_permission_prompt_system_message(payload=payload, notice=notice),
1202
- additional_context=_claude_permission_prompt_additional_context(notice),
1202
+ additional_context=_claude_guard_approval_question_message(notice),
1203
1203
  output_stream=output_stream,
1204
1204
  )
1205
1205
  return 0
@@ -1226,7 +1226,7 @@ def run_guard_command(
1226
1226
  harness=args.harness,
1227
1227
  policy_action="allow",
1228
1228
  event_name="Notification",
1229
- reason="HOL Guard intercepted the tool request and opened this Claude approval prompt.",
1229
+ reason="HOL Guard intercepted the tool request and is routing it through a HOL Guard approval prompt.",
1230
1230
  system_message=system_message,
1231
1231
  additional_context=additional_context,
1232
1232
  output_stream=output_stream,
@@ -1240,6 +1240,10 @@ def run_guard_command(
1240
1240
  _now(),
1241
1241
  )
1242
1242
  return 0
1243
+ if _canonical_harness_name(args.harness) == "claude-code" and _persist_claude_guard_question_decision(
1244
+ store, payload
1245
+ ):
1246
+ return 0
1243
1247
  if runtime_artifact is not None:
1244
1248
  event_name = _hook_event_name(payload) or "PreToolUse"
1245
1249
  runtime_artifact_hash = artifact_hash(runtime_artifact)
@@ -1346,14 +1350,6 @@ def run_guard_command(
1346
1350
  "risk_headline": incident["risk_headline"],
1347
1351
  "path_summary": _runtime_requested_path(runtime_artifact),
1348
1352
  }
1349
- if (
1350
- _canonical_harness_name(args.harness) == "claude-code"
1351
- and event_name == "UserPromptSubmit"
1352
- and policy_action == "require-reapproval"
1353
- and not _prompt_requires_hard_block(runtime_artifact)
1354
- and (not getattr(args, "json", False) or output_stream is not None)
1355
- ):
1356
- return 0
1357
1353
  if policy_action in {"block", "sandbox-required", "require-reapproval"}:
1358
1354
  native_reason = _runtime_artifact_native_reason(runtime_artifact, response_payload)
1359
1355
  additional_context = _claude_prompt_additional_context(
@@ -1881,6 +1877,42 @@ def _mark_claude_pending_permission_prompt_seen(
1881
1877
  return
1882
1878
 
1883
1879
 
1880
+ def _load_single_claude_pending_permission(
1881
+ store: GuardStore,
1882
+ payload: dict[str, object],
1883
+ ) -> tuple[str, dict[str, object]] | None:
1884
+ session_id = _optional_string(payload.get("session_id"))
1885
+ if session_id is None:
1886
+ return None
1887
+ try:
1888
+ index_payload = store.get_sync_payload(_claude_pending_permission_index_key(session_id))
1889
+ except (OSError, sqlite3.Error):
1890
+ return None
1891
+ if not isinstance(index_payload, list):
1892
+ return None
1893
+ pending_keys = [str(item) for item in index_payload]
1894
+ pending_items: list[tuple[str, dict[str, object]]] = []
1895
+ for pending_key in pending_keys:
1896
+ try:
1897
+ pending = store.get_sync_payload(pending_key)
1898
+ except (OSError, sqlite3.Error):
1899
+ continue
1900
+ if isinstance(pending, dict):
1901
+ pending_items.append((pending_key, pending))
1902
+ prompt_seen_items = [item for item in pending_items if item[1].get("permission_prompt_seen") is True]
1903
+ if len(prompt_seen_items) == 1:
1904
+ return prompt_seen_items[0]
1905
+ if len(pending_items) != 1:
1906
+ return None
1907
+ try:
1908
+ pending = store.get_sync_payload(pending_items[0][0])
1909
+ except (OSError, sqlite3.Error):
1910
+ return None
1911
+ if not isinstance(pending, dict):
1912
+ return None
1913
+ return pending_items[0][0], pending
1914
+
1915
+
1884
1916
  def _load_claude_pending_permission(
1885
1917
  store: GuardStore,
1886
1918
  payload: dict[str, object],
@@ -1938,6 +1970,7 @@ def _persist_claude_native_permission_policy(
1938
1970
  action: str,
1939
1971
  reason: str,
1940
1972
  now: str,
1973
+ source: str = "claude-native-approval",
1941
1974
  ) -> bool:
1942
1975
  try:
1943
1976
  store.upsert_policy(
@@ -1948,7 +1981,7 @@ def _persist_claude_native_permission_policy(
1948
1981
  artifact_id=artifact_id,
1949
1982
  artifact_hash=artifact_hash,
1950
1983
  reason=reason,
1951
- source="claude-native-approval",
1984
+ source=source,
1952
1985
  ),
1953
1986
  now,
1954
1987
  )
@@ -2082,6 +2115,106 @@ def _persist_claude_pending_permission_denials(store: GuardStore, payload: dict[
2082
2115
  return denied
2083
2116
 
2084
2117
 
2118
+ def _claude_guard_approval_question_message(notice: dict[str, object] | None) -> str:
2119
+ tool_name = _optional_string((notice or {}).get("tool_name")) or "this tool"
2120
+ reason = _optional_string((notice or {}).get("reason"))
2121
+ reason_text = f" HOL Guard reason: {_ensure_terminal_punctuation(reason)}" if reason is not None else ""
2122
+ return (
2123
+ f"HOL Guard needs the user's explicit decision before {tool_name} can run.{reason_text} "
2124
+ "The native Claude permission prompt is not the final decision surface for this request. Call "
2125
+ "AskUserQuestion now with one HOL Guard approval question before retrying the tool. Use header "
2126
+ "'HOL Guard', question 'HOL Guard intercepted this sensitive action. What should Claude do?', and exactly "
2127
+ "these options: 'Allow once', 'Allow during this session', and 'Keep blocked'. If the user chooses an "
2128
+ "allow option, retry the same tool once. If the user chooses Keep blocked, do not retry the sensitive "
2129
+ "action."
2130
+ )
2131
+
2132
+
2133
+ def _is_claude_guard_approval_question(payload: dict[str, object]) -> bool:
2134
+ if _hook_event_name(payload) != "PostToolUse":
2135
+ return False
2136
+ tool_name = _optional_string(payload.get("tool_name"))
2137
+ if tool_name is None or tool_name.lower() != "askuserquestion":
2138
+ return False
2139
+ combined = json.dumps(
2140
+ {
2141
+ "tool_input": payload.get("tool_input"),
2142
+ "tool_response": payload.get("tool_response"),
2143
+ },
2144
+ sort_keys=True,
2145
+ default=str,
2146
+ ).lower()
2147
+ return "hol guard" in combined and (
2148
+ "allow once" in combined or "allow during this session" in combined or "keep blocked" in combined
2149
+ )
2150
+
2151
+
2152
+ def _claude_guard_approval_answer(payload: dict[str, object]) -> str | None:
2153
+ response = payload.get("tool_response")
2154
+ answer_text: str | None = None
2155
+ if isinstance(response, dict):
2156
+ answers = response.get("answers")
2157
+ if isinstance(answers, dict):
2158
+ joined_answers = " ".join(str(answer) for answer in answers.values() if str(answer).strip())
2159
+ if joined_answers:
2160
+ answer_text = joined_answers
2161
+ if answer_text is None:
2162
+ for key in ("answer", "selected_answer", "selected", "choice", "value", "label"):
2163
+ value = response.get(key)
2164
+ if isinstance(value, str) and value.strip():
2165
+ answer_text = value
2166
+ break
2167
+ if answer_text is None and "questions" not in response and "options" not in response:
2168
+ content = response.get("content")
2169
+ if isinstance(content, str) and content.strip():
2170
+ answer_text = content
2171
+ elif isinstance(response, str) and response.strip():
2172
+ answer_text = response
2173
+ if answer_text is None:
2174
+ return None
2175
+ normalized_answer = answer_text.lower()
2176
+ if "keep blocked" in normalized_answer:
2177
+ return "block"
2178
+ if "allow during this session" in normalized_answer or "allow once" in normalized_answer:
2179
+ return "allow"
2180
+ return None
2181
+
2182
+
2183
+ def _persist_claude_guard_question_decision(store: GuardStore, payload: dict[str, object]) -> bool:
2184
+ if not _is_claude_guard_approval_question(payload):
2185
+ return False
2186
+ action = _claude_guard_approval_answer(payload)
2187
+ if action is None:
2188
+ return False
2189
+ pending_pair = _load_single_claude_pending_permission(store, payload)
2190
+ if pending_pair is None:
2191
+ return False
2192
+ pending_key, pending = pending_pair
2193
+ artifact_id = _optional_string(pending.get("artifact_id"))
2194
+ artifact_hash_value = _optional_string(pending.get("artifact_hash"))
2195
+ if artifact_id is None or artifact_hash_value is None:
2196
+ return False
2197
+ saved = _persist_claude_native_permission_policy(
2198
+ store=store,
2199
+ artifact_id=artifact_id,
2200
+ artifact_hash=artifact_hash_value,
2201
+ action=action,
2202
+ reason=(
2203
+ "Allowed through HOL Guard AskUserQuestion approval."
2204
+ if action == "allow"
2205
+ else "Blocked through HOL Guard AskUserQuestion approval."
2206
+ ),
2207
+ now=_now(),
2208
+ source="claude-ask-user-question",
2209
+ )
2210
+ if not saved:
2211
+ return False
2212
+ session_id = _optional_string(payload.get("session_id"))
2213
+ if session_id is not None:
2214
+ _remove_claude_pending_permission(store, session_id=session_id, pending_key=pending_key)
2215
+ return True
2216
+
2217
+
2085
2218
  def _is_claude_permission_prompt_notification(args: argparse.Namespace, payload: dict[str, object]) -> bool:
2086
2219
  return (
2087
2220
  _canonical_harness_name(args.harness) == "claude-code"
@@ -2103,20 +2236,23 @@ def _claude_permission_prompt_system_message(
2103
2236
  if tool_name is None and notice is not None:
2104
2237
  tool_name = _optional_string(notice.get("tool_name"))
2105
2238
  reason = _optional_string(notice.get("reason")) if notice is not None else None
2106
- intro = "HOL Guard intercepted a sensitive request and opened this Claude approval prompt."
2239
+ intro = "HOL Guard intercepted a sensitive request and is routing it to a HOL Guard approval question."
2107
2240
  if tool_name is not None:
2108
- intro = f"HOL Guard intercepted Claude's attempt to use {tool_name} and opened this approval prompt."
2241
+ intro = (
2242
+ f"HOL Guard intercepted Claude's attempt to use {tool_name} and is routing it to a HOL Guard approval "
2243
+ "question."
2244
+ )
2109
2245
  if reason is not None:
2110
2246
  return (
2111
- f"{intro} This approval dialog came from HOL Guard, not from Claude alone. "
2247
+ f"{intro} This approval flow came from HOL Guard, not from Claude alone. "
2112
2248
  f"{_ensure_terminal_punctuation(reason)} "
2113
- "Use the Claude choices below: Yes to allow it once, Yes during this session to trust the same action "
2114
- "for the rest of this session, or No to keep the sensitive action blocked."
2249
+ "HOL Guard will ask the user to choose Allow once, Allow during this session, or Keep blocked before "
2250
+ "Claude retries the action."
2115
2251
  )
2116
2252
  return (
2117
- f"{intro} This approval dialog came from HOL Guard, not from Claude alone. "
2118
- "Use the Claude choices below: Yes to allow it once, Yes during this session to trust the same action for "
2119
- "the rest of this session, or No to keep the sensitive action blocked."
2253
+ f"{intro} This approval flow came from HOL Guard, not from Claude alone. "
2254
+ "HOL Guard will ask the user to choose Allow once, Allow during this session, or Keep blocked before Claude "
2255
+ "retries the action."
2120
2256
  )
2121
2257
 
2122
2258
 
@@ -2124,17 +2260,17 @@ def _claude_permission_prompt_additional_context(notice: dict[str, object] | Non
2124
2260
  reason = _optional_string(notice.get("reason")) if notice is not None else None
2125
2261
  if reason is not None:
2126
2262
  return (
2127
- "HOL Guard intercepted the sensitive request and opened the Claude approval dialog that is currently "
2128
- "open. "
2129
- "This approval dialog came from HOL Guard, not from Claude alone. "
2130
- f"{_ensure_terminal_punctuation(reason)} The user can choose Yes, Yes during this session, or No in the "
2131
- "prompt that is already visible. If the user denies it, do not retry the same sensitive access."
2263
+ "HOL Guard intercepted the sensitive request and is routing it into a HOL Guard approval question. "
2264
+ "This approval flow came from HOL Guard, not from Claude alone. "
2265
+ f"{_ensure_terminal_punctuation(reason)} Ask the user with AskUserQuestion and the options Allow once, "
2266
+ "Allow during this session, and Keep blocked. If the user chooses Keep blocked, do not retry the same "
2267
+ "sensitive access."
2132
2268
  )
2133
2269
  return (
2134
- "HOL Guard intercepted the sensitive request and opened the Claude approval dialog that is currently open. "
2135
- "This approval dialog came from HOL Guard, not from Claude alone. "
2136
- "The user can choose Yes, Yes during this session, or No in the prompt that is already visible. "
2137
- "If the user denies it, do not retry the same action."
2270
+ "HOL Guard intercepted the sensitive request and is routing it into a HOL Guard approval question. "
2271
+ "This approval flow came from HOL Guard, not from Claude alone. Ask the user with AskUserQuestion and the "
2272
+ "options Allow once, Allow during this session, and Keep blocked. If the user chooses Keep blocked, do not "
2273
+ "retry the same action."
2138
2274
  )
2139
2275
 
2140
2276
 
@@ -2147,28 +2283,32 @@ def _claude_permission_prompt_terminal_notice(
2147
2283
  reason = _optional_string(notice.get("reason")) if notice is not None else None
2148
2284
  if tool_name is not None and reason is not None:
2149
2285
  return (
2150
- f"HOL Guard opened this Claude approval prompt for {tool_name}. "
2286
+ f"HOL Guard is routing this Claude approval request for {tool_name} into a HOL Guard decision prompt. "
2151
2287
  f"{_ensure_terminal_punctuation(reason)} "
2152
- "Review the request below, then choose Yes, Yes during this session, or No."
2288
+ "Choose Allow once, Allow during this session, or Keep blocked in the HOL Guard prompt."
2153
2289
  )
2154
2290
  if tool_name is not None:
2155
2291
  return (
2156
- f"HOL Guard opened this Claude approval prompt for {tool_name}. "
2157
- "Review the request below, then choose Yes, Yes during this session, or No."
2292
+ f"HOL Guard is routing this Claude approval request for {tool_name} into a HOL Guard decision prompt. "
2293
+ "Choose Allow once, Allow during this session, or Keep blocked in the HOL Guard prompt."
2158
2294
  )
2159
2295
  return (
2160
- "HOL Guard opened this Claude approval prompt to protect a sensitive action. "
2161
- "Review the request below, then choose Yes, Yes during this session, or No."
2296
+ "HOL Guard is routing this Claude approval request into a HOL Guard decision prompt to protect a sensitive "
2297
+ "action. Choose Allow once, Allow during this session, or Keep blocked in the HOL Guard prompt."
2162
2298
  )
2163
2299
 
2164
2300
 
2165
2301
  def _claude_native_pretooluse_terminal_notice(*, payload: dict[str, object], reason: str) -> str:
2166
2302
  tool_name = _claude_notification_tool_name(payload)
2167
2303
  if tool_name is not None:
2168
- return f"HOL Guard opened this Claude approval prompt for {tool_name}. {_ensure_terminal_punctuation(reason)}"
2304
+ return (
2305
+ f"HOL Guard intercepted Claude's attempt to use {tool_name}. {_ensure_terminal_punctuation(reason)} "
2306
+ "Guard will route the next approval through a HOL Guard prompt if Claude asks to continue."
2307
+ )
2169
2308
  return (
2170
- "HOL Guard opened this Claude approval prompt to protect a sensitive action. "
2171
- f"{_ensure_terminal_punctuation(reason)}"
2309
+ "HOL Guard intercepted a sensitive Claude action. "
2310
+ f"{_ensure_terminal_punctuation(reason)} Guard will route the next approval through a HOL Guard prompt if "
2311
+ "Claude asks to continue."
2172
2312
  )
2173
2313
 
2174
2314
 
@@ -2266,9 +2406,8 @@ def _runtime_artifact_native_reason(artifact: GuardArtifact, response_payload: d
2266
2406
  if harness == "claude-code" and policy_action == "require-reapproval":
2267
2407
  return (
2268
2408
  f"HOL Guard intercepted Claude's attempt to use {tool_name} for {path_class} to protect your local "
2269
- "secrets. This approval prompt came from HOL Guard, not from Claude alone. "
2270
- "Choose Yes to allow it once, Yes during this session to trust the same action for the rest of this "
2271
- "session, or No to keep the secret private."
2409
+ "secrets. The approval flow came from HOL Guard, not from Claude alone. HOL Guard will ask you to "
2410
+ "choose Allow once, Allow during this session, or Keep blocked before Claude retries this action."
2272
2411
  )
2273
2412
  return (
2274
2413
  f"HOL Guard blocked Claude's attempt to use {tool_name} for {path_class} to protect your local secrets. "
@@ -2311,7 +2450,10 @@ def _claude_prompt_additional_context(
2311
2450
  )
2312
2451
  return (
2313
2452
  f"{_ensure_terminal_punctuation(native_reason)} "
2314
- "Before you use the first sensitive tool for this request, tell the user exactly: "
2453
+ "Before you use the first sensitive tool for this request, call AskUserQuestion with header 'HOL Guard', "
2454
+ "question 'HOL Guard intercepted this sensitive action. What should Claude do?', and exactly these options: "
2455
+ "'Allow once', 'Allow during this session', and 'Keep blocked'. If the user chooses Keep blocked, do not "
2456
+ "retry the sensitive action. Then tell the user exactly: "
2315
2457
  f"'{briefing_sentence}' "
2316
2458
  "Attempt that sensitive tool at most once. If HOL Guard or Claude denies it, do not retry the same sensitive "
2317
2459
  "action automatically. Instead, tell the user approval is required in Claude to continue."
@@ -2330,12 +2472,11 @@ def _claude_prompt_system_message(
2330
2472
  if "secret_read" in _prompt_request_classes(artifact):
2331
2473
  return (
2332
2474
  "HOL Guard intercepted this prompt because it asks Claude to access local secrets. "
2333
- "If Claude opens a permission dialog on the next tool call, that approval prompt came from HOL "
2334
- "Guard."
2475
+ "If Claude asks to continue, HOL Guard will route the decision through a branded approval prompt."
2335
2476
  )
2336
2477
  return (
2337
2478
  "HOL Guard intercepted this prompt because it leads to a sensitive action. "
2338
- "If Claude opens a permission dialog on the next tool call, that approval prompt came from HOL Guard."
2479
+ "If Claude asks to continue, HOL Guard will route the decision through a branded approval prompt."
2339
2480
  )
2340
2481
  if policy_action in {"block", "sandbox-required"}:
2341
2482
  return _ensure_terminal_punctuation(native_reason)
@@ -2453,6 +2594,17 @@ def _emit_native_hook_response(
2453
2594
  _write_json_line(payload, output_stream=output_stream)
2454
2595
  return
2455
2596
  if event_name in {"Notification", "PermissionRequest"}:
2597
+ if event_name == "PermissionRequest" and policy_action in {"block", "sandbox-required"}:
2598
+ payload["hookSpecificOutput"] = {
2599
+ "hookEventName": event_name,
2600
+ "decision": {
2601
+ "behavior": "deny",
2602
+ "message": additional_context or reason,
2603
+ "interrupt": False,
2604
+ },
2605
+ }
2606
+ _write_json_line(payload, output_stream=output_stream)
2607
+ return
2456
2608
  if additional_context:
2457
2609
  payload["hookSpecificOutput"] = {
2458
2610
  "hookEventName": event_name,
@@ -1,3 +1,3 @@
1
1
  """Single source of truth for tool version."""
2
2
 
3
- __version__ = "2.0.62"
3
+ __version__ = "2.0.63"
@@ -163,6 +163,7 @@ def test_claude_install_writes_session_start_and_command_hook_schema_and_is_idem
163
163
  assert permission_request[0]["hooks"][0]["type"] == "command"
164
164
  assert permission_request[0]["hooks"][0]["timeout"] == 10
165
165
  assert len(post_tool_use) == 1
166
+ assert post_tool_use[0]["matcher"] == "Bash|Read|Write|Edit|MultiEdit|WebFetch|WebSearch|mcp__.*|AskUserQuestion"
166
167
  assert post_tool_use[0]["hooks"][0]["type"] == "command"
167
168
  assert len(prompt_submit) == 1
168
169
  assert "matcher" not in prompt_submit[0]
@@ -396,7 +397,10 @@ def test_claude_daemon_hook_command_falls_back_without_blocking_prompt_on_daemon
396
397
  )
397
398
  assert result.returncode == 0
398
399
  assert result.stderr == ""
399
- assert result.stdout == ""
400
+ payload = json.loads(result.stdout)
401
+ assert payload["hookSpecificOutput"]["hookEventName"] == "UserPromptSubmit"
402
+ assert "AskUserQuestion" in payload["hookSpecificOutput"]["additionalContext"]
403
+ assert "Keep blocked" in payload["hookSpecificOutput"]["additionalContext"]
400
404
 
401
405
 
402
406
  def test_claude_daemon_hook_command_falls_back_to_native_ask_on_daemon_miss(tmp_path):
@@ -424,7 +428,11 @@ def test_claude_daemon_hook_command_falls_back_to_native_ask_on_daemon_miss(tmp_
424
428
  assert result.stderr == ""
425
429
  assert payload["hookSpecificOutput"]["hookEventName"] == "PreToolUse"
426
430
  assert payload["hookSpecificOutput"]["permissionDecision"] == "ask"
427
- assert "HOL Guard" in payload["hookSpecificOutput"]["permissionDecisionReason"]
431
+ reason = payload["hookSpecificOutput"]["permissionDecisionReason"]
432
+ assert "HOL Guard" in reason
433
+ assert "approval flow came from HOL Guard" in reason
434
+ assert "Allow once" in reason
435
+ assert "Keep blocked" in reason
428
436
 
429
437
 
430
438
  def test_claude_install_replaces_prior_session_start_guard_handlers_when_context_changes(tmp_path):