plugin-scanner 2.0.136__tar.gz → 2.0.138__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 (432) hide show
  1. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/guard-api.ts +12 -0
  3. plugin_scanner-2.0.138/dashboard/src/runtime-overview.test.ts +107 -0
  4. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/runtime-overview.tsx +61 -0
  5. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/settings-workspace.test.ts +4 -0
  6. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/settings-workspace.tsx +29 -1
  7. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/get-started.md +33 -0
  8. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/pyproject.toml +5 -1
  9. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/pyproject.toml.bak +5 -1
  10. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/__init__.py +8 -1
  11. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/manager.py +30 -0
  12. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/server.py +7 -0
  13. plugin_scanner-2.0.138/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +9 -0
  14. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/version.py +1 -1
  15. plugin_scanner-2.0.138/tests/test_guard_daemon_repair_perf.py +226 -0
  16. plugin_scanner-2.0.136/dashboard/src/runtime-overview.test.ts +0 -55
  17. plugin_scanner-2.0.136/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +0 -9
  18. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.clusterfuzzlite/Dockerfile +0 -0
  19. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.clusterfuzzlite/build.sh +0 -0
  20. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.clusterfuzzlite/project.yaml +0 -0
  21. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  22. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.dockerignore +0 -0
  23. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/CODEOWNERS +0 -0
  24. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  25. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  26. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  27. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/dependabot.yml +0 -0
  28. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/ci.yml +0 -0
  29. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/codeql.yml +0 -0
  30. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/dependabot-uv-lock.yml +0 -0
  31. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/fuzz.yml +0 -0
  32. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/harness-smoke.yml +0 -0
  33. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/publish.yml +0 -0
  34. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.github/workflows/scorecard.yml +0 -0
  35. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.gitignore +0 -0
  36. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/.pre-commit-hooks.yaml +0 -0
  37. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/CONTRIBUTING.md +0 -0
  38. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/Dockerfile +0 -0
  39. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/LICENSE +0 -0
  40. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/README.md +0 -0
  41. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/SECURITY.md +0 -0
  42. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/index.html +0 -0
  43. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/package.json +0 -0
  44. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/pnpm-lock.yaml +0 -0
  45. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/apple-touch-icon.png +0 -0
  46. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  47. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/brand/Logo_Whole.png +0 -0
  48. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/favicon-16x16.png +0 -0
  49. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/favicon-32x32.png +0 -0
  50. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/public/favicon.ico +0 -0
  51. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/app.tsx +0 -0
  52. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/approval-center-layout.test.ts +0 -0
  53. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/approval-center-layout.tsx +0 -0
  54. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/approval-center-primitives.tsx +0 -0
  55. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/approval-center-review-cards.tsx +0 -0
  56. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/approval-center-utils.ts +0 -0
  57. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  58. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/fleet-workspace.tsx +0 -0
  59. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/guard-api.test.ts +0 -0
  60. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/guard-demo.ts +0 -0
  61. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/guard-types.ts +0 -0
  62. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/main.tsx +0 -0
  63. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/receipts-workspace.test.ts +0 -0
  64. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/receipts-workspace.tsx +0 -0
  65. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/styles.css +0 -0
  66. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/src/vite-env.d.ts +0 -0
  67. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/tsconfig.json +0 -0
  68. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/dashboard/vite.config.ts +0 -0
  69. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docker-requirements.txt +0 -0
  70. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/approval-audit.md +0 -0
  71. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/architecture.md +0 -0
  72. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/harness-support.md +0 -0
  73. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/local-vs-cloud.md +0 -0
  74. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/release-checklist.md +0 -0
  75. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/smoke-tests.md +0 -0
  76. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/guard/testing-matrix.md +0 -0
  77. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/trust/mcp-trust-draft.md +0 -0
  78. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/trust/plugin-trust-draft.md +0 -0
  79. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/docs/trust/skill-trust-local.md +0 -0
  80. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/fuzzers/manifest_fuzzer.py +0 -0
  81. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/requirements.txt +0 -0
  82. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/schemas/plugin-quality.v1.json +0 -0
  83. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/schemas/scan-result.v1.json +0 -0
  84. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/schemas/verify-result.v1.json +0 -0
  85. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/__init__.py +0 -0
  86. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/action_runner.py +0 -0
  87. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  88. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  89. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  90. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/claude.py +0 -0
  91. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  92. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  93. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  94. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  95. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  96. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  97. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  98. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  99. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  100. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/security.py +0 -0
  101. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  102. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/cli.py +0 -0
  103. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/cli_ui.py +0 -0
  104. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/config.py +0 -0
  105. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  106. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  107. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  108. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  109. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  110. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  111. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  112. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  113. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  114. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/github_reporting.py +0 -0
  115. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  116. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  117. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  118. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  119. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  120. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  121. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  122. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  123. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
  124. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  125. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  126. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  127. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  128. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  129. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  130. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  131. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  132. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  133. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  134. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  135. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  136. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  137. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  138. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  139. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  140. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  141. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  142. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  143. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  144. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  145. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  146. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  147. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  148. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  149. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/config.py +0 -0
  150. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  151. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  152. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  153. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  154. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +0 -0
  155. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  156. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  157. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  158. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  159. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  160. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  161. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  162. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/incident.py +0 -0
  163. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  164. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  165. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/models.py +0 -0
  166. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  167. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  168. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/protect.py +0 -0
  169. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  170. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  171. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  172. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  173. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  174. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  175. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  176. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/risk.py +0 -0
  177. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  178. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
  179. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  180. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
  181. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
  182. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  183. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  184. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  185. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  186. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  187. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  188. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  189. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  190. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  191. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  192. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  193. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  194. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  195. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  196. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  197. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  198. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  199. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  200. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  201. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
  202. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  203. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  204. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  205. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  206. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/shims.py +0 -0
  207. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/store.py +0 -0
  208. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  209. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  210. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
  211. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
  212. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/guard/types.py +0 -0
  213. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  214. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  215. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  216. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  217. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  218. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/models.py +0 -0
  219. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/path_support.py +0 -0
  220. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/policy.py +0 -0
  221. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  222. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/repo_detect.py +0 -0
  223. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/reporting.py +0 -0
  224. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  225. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/rules/registry.py +0 -0
  226. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/rules/specs.py +0 -0
  227. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/scanner.py +0 -0
  228. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/submission.py +0 -0
  229. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/suppressions.py +0 -0
  230. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  231. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  232. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  233. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_models.py +0 -0
  234. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  235. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  236. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  237. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/trust_specs.py +0 -0
  238. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/src/codex_plugin_scanner/verification.py +0 -0
  239. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/__init__.py +0 -0
  240. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/conftest.py +0 -0
  241. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/__init__.py +0 -0
  242. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  243. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  244. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/bad-plugin/secrets.js +0 -0
  245. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  246. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  247. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/README.md +0 -0
  248. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  249. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  250. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  251. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/code-quality-bad/evil.js +0 -0
  252. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/code-quality-bad/inject.js +0 -0
  253. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  254. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  255. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/README.md +0 -0
  256. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  257. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  258. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  259. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  260. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/.codexignore +0 -0
  261. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/LICENSE +0 -0
  262. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/README.md +0 -0
  263. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  264. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  265. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  266. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  267. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  268. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  269. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/README.md +0 -0
  270. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
  271. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
  272. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
  273. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
  274. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
  275. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
  276. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
  277. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
  278. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
  279. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
  280. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
  281. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
  282. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
  283. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
  284. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
  285. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
  286. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
  287. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
  288. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
  289. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  290. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  291. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  292. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  293. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  294. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  295. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  296. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  297. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  298. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  299. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  300. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  301. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  302. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  303. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/mcp-canary-server.py +0 -0
  304. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  305. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  306. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/mit-license/LICENSE +0 -0
  307. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  308. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  309. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  310. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  311. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  312. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  313. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  314. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  315. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  316. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  317. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  318. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  319. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  320. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  321. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  322. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  323. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  324. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  325. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/LICENSE +0 -0
  326. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/README.md +0 -0
  327. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  328. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  329. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  330. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  331. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  332. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  333. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  334. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  335. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  336. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  337. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  338. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  339. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  340. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  341. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  342. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test-trust-scoring.py +0 -0
  343. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test-trust-specs.py +0 -0
  344. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_action_runner.py +0 -0
  345. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_best_practices.py +0 -0
  346. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_cisco_install_surfaces.py +0 -0
  347. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_cli.py +0 -0
  348. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_code_quality.py +0 -0
  349. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_config.py +0 -0
  350. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_coverage_remaining.py +0 -0
  351. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_ecosystems.py +0 -0
  352. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_edge_cases.py +0 -0
  353. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_final_coverage.py +0 -0
  354. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_access_graph.py +0 -0
  355. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_action_identity.py +0 -0
  356. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_advisory_escalation.py +0 -0
  357. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_approval_continuity.py +0 -0
  358. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_approval_copy_commands.py +0 -0
  359. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_approval_store_dedup.py +0 -0
  360. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_approval_store_scale.py +0 -0
  361. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_approvals.py +0 -0
  362. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_bootstrap.py +0 -0
  363. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_canary_fixtures.py +0 -0
  364. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_capabilities.py +0 -0
  365. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_claude_adapter.py +0 -0
  366. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_cli.py +0 -0
  367. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_cloud_local_sync.py +0 -0
  368. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_codex_e2e.py +0 -0
  369. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_codex_install.py +0 -0
  370. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_codex_proxy.py +0 -0
  371. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_config_paths.py +0 -0
  372. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_connect_flow.py +0 -0
  373. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_consumer_mode.py +0 -0
  374. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_copilot_adapter.py +0 -0
  375. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_copilot_proxy.py +0 -0
  376. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_daemon_manager.py +0 -0
  377. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_daemon_perf.py +0 -0
  378. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_data_flow.py +0 -0
  379. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_decision_propagation.py +0 -0
  380. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_event_schema_v1.py +0 -0
  381. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_events.py +0 -0
  382. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_evidence_store.py +0 -0
  383. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_harness_contracts.py +0 -0
  384. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_launch_env.py +0 -0
  385. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_mcp_protection.py +0 -0
  386. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_opencode_proxy.py +0 -0
  387. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_policy_dedup.py +0 -0
  388. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_product_flow.py +0 -0
  389. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_prompt_injection.py +0 -0
  390. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_protect.py +0 -0
  391. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_red_team.py +0 -0
  392. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_render.py +0 -0
  393. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_resolution_copy.py +0 -0
  394. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_risk.py +0 -0
  395. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime.py +0 -0
  396. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime_action_harnesses.py +0 -0
  397. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime_actions.py +0 -0
  398. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime_decisions.py +0 -0
  399. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime_detectors.py +0 -0
  400. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_runtime_signals.py +0 -0
  401. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_safe_decode.py +0 -0
  402. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_sandbox.py +0 -0
  403. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_skill_protection.py +0 -0
  404. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_store_migrations.py +0 -0
  405. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_supply_chain.py +0 -0
  406. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_surface_server.py +0 -0
  407. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_threat_intel.py +0 -0
  408. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_verdicts.py +0 -0
  409. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_guard_web_recovery.py +0 -0
  410. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_hermes_adapter.py +0 -0
  411. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_integration.py +0 -0
  412. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_lint_fixes.py +0 -0
  413. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_live_cisco_smoke.py +0 -0
  414. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_manifest.py +0 -0
  415. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_marketplace.py +0 -0
  416. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_mcp_security.py +0 -0
  417. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_openclaw_adapter.py +0 -0
  418. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_operational_security.py +0 -0
  419. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_policy.py +0 -0
  420. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_quality_artifact.py +0 -0
  421. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_rule_registry.py +0 -0
  422. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_scanner.py +0 -0
  423. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_schema_contracts.py +0 -0
  424. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_security.py +0 -0
  425. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_security_ops.py +0 -0
  426. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_skill_security.py +0 -0
  427. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_submission.py +0 -0
  428. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_trust_scoring.py +0 -0
  429. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_trust_specs.py +0 -0
  430. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_verification.py +0 -0
  431. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/tests/test_versioning.py +0 -0
  432. {plugin_scanner-2.0.136 → plugin_scanner-2.0.138}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.136
3
+ Version: 2.0.138
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
@@ -631,3 +631,15 @@ export async function exportDiagnostics(): Promise<Blob> {
631
631
  }
632
632
  return response.blob();
633
633
  }
634
+
635
+ export async function repairApprovalCenter(): Promise<{ repaired: boolean; cleared: string[] }> {
636
+ if (isGuardDemoMode()) {
637
+ return { repaired: true, cleared: ["locator", "daemon_state"] };
638
+ }
639
+ const response = await fetch(guardApiInput("/v1/daemon/repair"), withGuardAuth({ method: "POST" }));
640
+ if (!response.ok) {
641
+ throw new Error(`Repair failed with ${response.status}`);
642
+ }
643
+ return response.json() as Promise<{ repaired: boolean; cleared: string[] }>;
644
+ }
645
+
@@ -0,0 +1,107 @@
1
+ import { resolveCloudIntelCopy, resolveCloudSyncHealthCopy, resolveProtectionLevelCopy, resolveApprovalCenterHealth } from "./runtime-overview";
2
+ import type { GuardCloudSyncHealth, GuardRuntimeSnapshot } from "./guard-types";
3
+
4
+ function assert(condition: boolean, message: string): void {
5
+ if (!condition) {
6
+ throw new Error(message);
7
+ }
8
+ }
9
+
10
+ const healthDisabled: GuardCloudSyncHealth = {
11
+ state: "disabled",
12
+ label: "Sync disabled",
13
+ detail: "Cloud sync is turned off on this machine.",
14
+ pending_events: 0,
15
+ last_synced_at: null,
16
+ next_retry_after: null
17
+ };
18
+
19
+ const healthHealthy: GuardCloudSyncHealth = {
20
+ state: "healthy",
21
+ label: "Sync healthy",
22
+ detail: "Cloud sync is running normally.",
23
+ pending_events: 0,
24
+ last_synced_at: new Date().toISOString(),
25
+ next_retry_after: null
26
+ };
27
+
28
+ const localOnlyCopy = resolveCloudIntelCopy("local_only");
29
+ assert(localOnlyCopy.label === "Offline, free", "T507: local_only label should be 'Offline, free'");
30
+ assert(localOnlyCopy.detail.length > 0, "T507: local_only detail should not be empty");
31
+ assert(localOnlyCopy.detail.includes("locally"), "T507: local_only detail should mention 'locally'");
32
+
33
+ const localOnlySyncCopy = resolveCloudSyncHealthCopy(healthDisabled);
34
+ assert(localOnlySyncCopy.label === healthDisabled.label, "T507: cloud sync health label should match");
35
+ assert(localOnlySyncCopy.detail === healthDisabled.detail, "T507: cloud sync health detail should match");
36
+
37
+ const protectionBalanced = resolveProtectionLevelCopy("balanced");
38
+ assert(protectionBalanced.includes("secrets"), "T507: balanced description should mention secrets");
39
+
40
+ const pairedActiveCopy = resolveCloudIntelCopy("paired_active");
41
+ assert(pairedActiveCopy.label === "Synced, pro", "T508: paired_active label should be 'Synced, pro'");
42
+ assert(pairedActiveCopy.detail.length > 0, "T508: paired_active detail should not be empty");
43
+ assert(pairedActiveCopy.detail.includes("Guard Cloud"), "T508: paired_active detail should mention Guard Cloud");
44
+
45
+ const pairedWaitingCopy = resolveCloudIntelCopy("paired_waiting");
46
+ assert(pairedWaitingCopy.label === "Pairing…", "T508: paired_waiting label should be 'Pairing…'");
47
+
48
+ const pairedActiveSyncCopy = resolveCloudSyncHealthCopy(healthHealthy);
49
+ assert(pairedActiveSyncCopy.label === healthHealthy.label, "T508: healthy sync label should match");
50
+
51
+ const protectionStrict = resolveProtectionLevelCopy("strict");
52
+ assert(protectionStrict.includes("network"), "T508: strict description should mention network");
53
+
54
+ const protectionCustom = resolveProtectionLevelCopy("custom");
55
+ assert(protectionCustom.includes("Custom"), "T508: custom description should mention Custom");
56
+
57
+ const baseSnapshot: GuardRuntimeSnapshot = {
58
+ generated_at: new Date().toISOString(),
59
+ approval_center_url: "http://localhost:7392/approval",
60
+ runtime_state: {
61
+ session_id: "sess-1",
62
+ daemon_host: "localhost",
63
+ daemon_port: 7391,
64
+ started_at: new Date().toISOString(),
65
+ last_heartbeat_at: new Date().toISOString(),
66
+ approval_center_url: "http://localhost:7392/approval",
67
+ },
68
+ pending_count: 0,
69
+ receipt_count: 0,
70
+ headline_state: "protected",
71
+ headline_label: "Protected",
72
+ headline_detail: "Guard is active.",
73
+ sync_configured: false,
74
+ cloud_state: "local_only",
75
+ cloud_state_label: "Offline",
76
+ cloud_state_detail: "Running locally.",
77
+ cloud_pairing_state: { state: "local_only", label: "Offline", detail: "No cloud." },
78
+ cloud_sync_health: healthDisabled,
79
+ dashboard_url: "http://localhost:7392",
80
+ inbox_url: "http://localhost:7392/inbox",
81
+ fleet_url: "http://localhost:7392/fleet",
82
+ connect_url: "http://localhost:7392/connect",
83
+ items: [],
84
+ latest_receipts: [],
85
+ };
86
+
87
+ const healthyApproval = resolveApprovalCenterHealth(baseSnapshot);
88
+ assert(healthyApproval.state === "ready", "T738: protected snapshot with URL should be ready");
89
+ assert(healthyApproval.label.toLowerCase().includes("ready"), "T738: ready label should say ready");
90
+ assert(healthyApproval.detail.includes("http://localhost:7392/approval"), "T738: ready detail should include the URL");
91
+
92
+ const nullRuntimeSnapshot: GuardRuntimeSnapshot = { ...baseSnapshot, runtime_state: null };
93
+ const offlineApproval = resolveApprovalCenterHealth(nullRuntimeSnapshot);
94
+ assert(offlineApproval.state === "stale", "T738: null runtime_state (non-setup) should be stale");
95
+ assert(offlineApproval.label.toLowerCase().includes("offline"), "T738: stale label should mention offline");
96
+
97
+ const setupSnapshot: GuardRuntimeSnapshot = { ...baseSnapshot, runtime_state: null, headline_state: "setup" };
98
+ const startingApproval = resolveApprovalCenterHealth(setupSnapshot);
99
+ assert(startingApproval.state === "starting", "T738: null runtime_state + setup headline should be starting");
100
+ assert(startingApproval.label.toLowerCase().includes("starting"), "T738: starting label should say starting");
101
+
102
+ const noUrlSnapshot: GuardRuntimeSnapshot = { ...baseSnapshot, approval_center_url: null };
103
+ const repairApproval = resolveApprovalCenterHealth(noUrlSnapshot);
104
+ assert(repairApproval.state === "repair_needed", "T738: null approval_center_url should need repair");
105
+ assert(repairApproval.label.toLowerCase().includes("unreachable"), "T738: repair label should mention unreachable");
106
+ assert(repairApproval.detail.toLowerCase().includes("repair"), "T738: repair detail should suggest repair action");
107
+
@@ -40,6 +40,44 @@ function remediationLine(snapshot: GuardRuntimeSnapshot): string {
40
40
  return "Open Guard Cloud for shared proof, Watched Apps for local coverage, or the review queue when something needs your choice.";
41
41
  }
42
42
 
43
+ export type ApprovalCenterHealthState = "ready" | "starting" | "stale" | "repair_needed";
44
+
45
+ export type ApprovalCenterHealthCopy = {
46
+ state: ApprovalCenterHealthState;
47
+ label: string;
48
+ detail: string;
49
+ };
50
+
51
+ export function resolveApprovalCenterHealth(snapshot: GuardRuntimeSnapshot): ApprovalCenterHealthCopy {
52
+ if (snapshot.runtime_state === null) {
53
+ if (snapshot.headline_state === "setup") {
54
+ return {
55
+ state: "starting",
56
+ label: "Approval center starting",
57
+ detail: "Guard is setting up the local approval center. This takes a few seconds.",
58
+ };
59
+ }
60
+ return {
61
+ state: "stale",
62
+ label: "Approval center offline",
63
+ detail: "The local approval center is not running. Start Guard to restore the approval link.",
64
+ };
65
+ }
66
+ if (snapshot.approval_center_url === null) {
67
+ return {
68
+ state: "repair_needed",
69
+ label: "Approval center unreachable",
70
+ detail: "The approval center URL is missing. Use the repair action in Settings to restore it.",
71
+ };
72
+ }
73
+ return {
74
+ state: "ready",
75
+ label: "Approval center ready",
76
+ detail: `The approval center is running and accepting requests at ${snapshot.approval_center_url}.`,
77
+ };
78
+ }
79
+
80
+
43
81
  export function resolveCloudSyncHealthCopy(health: GuardCloudSyncHealth): { label: string; detail: string } {
44
82
  return {
45
83
  label: health.label,
@@ -95,6 +133,28 @@ function CloudSyncHealthCard(props: { health: GuardCloudSyncHealth }) {
95
133
  );
96
134
  }
97
135
 
136
+ function approvalHealthTone(state: ApprovalCenterHealthState): "green" | "blue" | "slate" | "red" {
137
+ if (state === "ready") return "green";
138
+ if (state === "starting") return "blue";
139
+ if (state === "repair_needed") return "red";
140
+ return "slate";
141
+ }
142
+
143
+ function ApprovalCenterHealthCard(props: { snapshot: GuardRuntimeSnapshot }) {
144
+ const copy = resolveApprovalCenterHealth(props.snapshot);
145
+ return (
146
+ <div className="rounded-xl border border-border bg-white px-5 py-4">
147
+ <div className="flex flex-wrap items-center justify-between gap-2">
148
+ <p className="text-xs font-semibold uppercase tracking-[0.18em] text-brand-blue">
149
+ Approval center health
150
+ </p>
151
+ <Tag tone={approvalHealthTone(copy.state)}>{copy.label}</Tag>
152
+ </div>
153
+ <p className="mt-2 text-sm leading-relaxed text-brand-dark/80">{copy.detail}</p>
154
+ </div>
155
+ );
156
+ }
157
+
98
158
  function WatchedAppsCard(props: { inventory: GuardInventoryItem[] | undefined }) {
99
159
  const inventory = props.inventory ?? [];
100
160
  return (
@@ -247,6 +307,7 @@ export function RuntimeOverview(props: RuntimeOverviewProps) {
247
307
  </div>
248
308
 
249
309
  <CloudSyncHealthCard health={snapshot.cloud_sync_health} />
310
+ <ApprovalCenterHealthCard snapshot={snapshot} />
250
311
 
251
312
  <div className="rounded-xl border border-border bg-white px-5 py-4">
252
313
  <p className="text-xs font-semibold uppercase tracking-[0.18em] text-brand-blue">
@@ -1,4 +1,5 @@
1
1
  import { resolveSecurityLevelDescription, buildClearPolicyPayload } from "./settings-workspace";
2
+ import { repairApprovalCenter } from "./guard-api";
2
3
 
3
4
  function assert(condition: boolean, message: string): void {
4
5
  if (!condition) {
@@ -25,3 +26,6 @@ assert(!("harness" in clearAllPayload) || clearAllPayload.harness === undefined,
25
26
 
26
27
  const clearNonePayload = buildClearPolicyPayload(false);
27
28
  assert(clearNonePayload.all === false, "T530: clearPolicy payload with all=false should have all=false");
29
+
30
+ assert(typeof repairApprovalCenter === "function", "T739: repairApprovalCenter should be exported as a function");
31
+
@@ -13,7 +13,7 @@ import {
13
13
  SectionLabel,
14
14
  Tag
15
15
  } from "./approval-center-primitives";
16
- import { clearEvidence, exportDiagnostics, fetchSettings, updateSettings, clearPolicy } from "./guard-api";
16
+ import { clearEvidence, exportDiagnostics, fetchSettings, updateSettings, clearPolicy, repairApprovalCenter } from "./guard-api";
17
17
  import { resolveProtectionLevelCopy } from "./runtime-overview";
18
18
  import type { GuardSettings, GuardSettingsPayload } from "./guard-types";
19
19
 
@@ -163,6 +163,7 @@ export function SettingsWorkspace() {
163
163
  const [clearingApprovals, setClearingApprovals] = useState(false);
164
164
  const [clearingEvidence, setClearingEvidence] = useState(false);
165
165
  const [exporting, setExporting] = useState(false);
166
+ const [repairing, setRepairing] = useState(false);
166
167
  const [actionMessage, setActionMessage] = useState<string | null>(null);
167
168
  const saveSuccessTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
168
169
 
@@ -359,6 +360,22 @@ export function SettingsWorkspace() {
359
360
  }
360
361
  }, []);
361
362
 
363
+ const handleRepairApprovalCenter = useCallback(async () => {
364
+ if (!window.confirm("Reset the approval center locator? The daemon will be reachable again after Guard restarts. Pending approvals are preserved.")) {
365
+ return;
366
+ }
367
+ setRepairing(true);
368
+ setActionMessage(null);
369
+ try {
370
+ await repairApprovalCenter();
371
+ setActionMessage("Approval center repaired. Restart Guard to reconnect.");
372
+ } catch (error) {
373
+ setActionMessage(error instanceof Error ? error.message : "Unable to repair approval center.");
374
+ } finally {
375
+ setRepairing(false);
376
+ }
377
+ }, []);
378
+
362
379
  if (state.kind === "loading") {
363
380
  return (
364
381
  <div className="space-y-4">
@@ -629,6 +646,17 @@ export function SettingsWorkspace() {
629
646
  </ActionButton>
630
647
  </div>
631
648
  </div>
649
+ <div>
650
+ <p className="text-sm font-semibold text-brand-dark">Repair local approval center</p>
651
+ <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
652
+ Resets the approval center locator when the approval link returns an API error. Pending approvals are preserved.
653
+ </p>
654
+ <div className="mt-2">
655
+ <ActionButton onClick={handleRepairApprovalCenter} disabled={repairing} variant="secondary">
656
+ {repairing ? "Repairing…" : "Repair approval center"}
657
+ </ActionButton>
658
+ </div>
659
+ </div>
632
660
  {actionMessage ? (
633
661
  <p className="guard-fade-in text-sm leading-6 text-brand-dark/70">{actionMessage}</p>
634
662
  ) : null}
@@ -270,3 +270,36 @@ That means the user should never get a silent pass-through on a risky Codex acti
270
270
  - native Bash deny plus HOL Guard approval-center recovery for sensitive shell actions
271
271
  - same-chat approve or deny when Codex can render the inline MCP prompt
272
272
  - explicit approval-center recovery when the session cannot
273
+
274
+ ## Seamless approvals
275
+
276
+ When Guard blocks a launch, it opens a persistent approval link in the terminal rather than pausing the session. You can resolve requests without leaving your harness:
277
+
278
+ 1. Guard returns the approval URL in the block output and queues the request locally.
279
+ 2. Open the approval center at the URL or in your browser.
280
+ 3. Approve or deny the request from the approval center UI or the CLI:
281
+
282
+ ```bash
283
+ hol-guard approvals approve <request-id>
284
+ hol-guard approvals deny <request-id>
285
+ ```
286
+
287
+ 4. After you resolve the request, Guard emits copy telling you to return to your AI assistant and retry. No page reload or session restart is needed.
288
+
289
+ To inspect a pending request's details or get the approval URL, pass the request-id to the `approve` command with `--dry-run`, or visit the approval center URL shown in the block message directly.
290
+
291
+ ## Troubleshooting
292
+
293
+ ### Approval link says API error
294
+
295
+ If the approval center URL in a block message returns an API error, the local approval center locator may be stale.
296
+ Use the **Repair approval center** action in the Guard dashboard Settings tab, or call the repair endpoint directly when the daemon is running. The port shown in Guard's status output or the dashboard URL is your daemon port:
297
+
298
+ ```bash
299
+ GUARD_PORT=$(hol-guard status --json 2>/dev/null | python3 -c "import json,sys; d=json.load(sys.stdin); print((d.get('runtime_state') or {}).get('daemon_port', d.get('daemon_port', 4781)))" 2>/dev/null || echo 4781)
300
+ curl -s -X POST "http://127.0.0.1:${GUARD_PORT}/v1/daemon/repair" \
301
+ -H "X-Guard-Token: $(cat ~/.hol-guard/daemon-auth-token)"
302
+ ```
303
+
304
+ After repair, restart Guard, then retry the block message URL or relaunch your harness through Guard. Pending approval requests are preserved across repairs.
305
+
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "plugin-scanner"
7
- version = "2.0.136"
7
+ version = "2.0.138"
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"
@@ -98,3 +98,7 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "RUF"]
98
98
  [tool.pytest.ini_options]
99
99
  testpaths = ["tests"]
100
100
  python_files = ["test_*.py"]
101
+ addopts = ["-m", "not slow"]
102
+ markers = [
103
+ "slow: marks tests as slow (deselected by default; run with -m slow to include)",
104
+ ]
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "hol-guard"
7
- version = "2.0.136"
7
+ version = "2.0.138"
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"
@@ -100,3 +100,7 @@ select = ["E", "F", "W", "I", "N", "UP", "B", "A", "SIM", "RUF"]
100
100
  [tool.pytest.ini_options]
101
101
  testpaths = ["tests"]
102
102
  python_files = ["test_*.py"]
103
+ addopts = ["-m", "not slow"]
104
+ markers = [
105
+ "slow: marks tests as slow (deselected by default; run with -m slow to include)",
106
+ ]
@@ -2,7 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from .manager import ensure_guard_daemon, guard_daemon_url_for_home, load_guard_daemon_auth_token, load_guard_daemon_url
5
+ from .manager import (
6
+ ensure_guard_daemon,
7
+ guard_daemon_url_for_home,
8
+ load_guard_daemon_auth_token,
9
+ load_guard_daemon_url,
10
+ repair_approval_center_locator,
11
+ )
6
12
 
7
13
  __all__ = [
8
14
  "GuardDaemonServer",
@@ -12,6 +18,7 @@ __all__ = [
12
18
  "load_guard_daemon_auth_token",
13
19
  "load_guard_daemon_url",
14
20
  "load_guard_surface_daemon_client",
21
+ "repair_approval_center_locator",
15
22
  ]
16
23
 
17
24
 
@@ -187,6 +187,36 @@ def clear_guard_daemon_state(guard_home: Path) -> None:
187
187
  _write_private_text(state_path, "{}")
188
188
 
189
189
 
190
+ def repair_approval_center_locator(guard_home: Path) -> dict[str, object]:
191
+ """Remove a stale approval center locator and optionally clear dead daemon state.
192
+
193
+ Only clears daemon-state.json when the recorded PID is no longer running,
194
+ so a live daemon's state is not disturbed. Raises OSError if a required
195
+ write fails so callers can detect incomplete repair.
196
+
197
+ Safe to call while the database is live. Returns a dict describing what was cleared.
198
+ """
199
+ cleared: list[str] = []
200
+ locator = _locator_path(guard_home)
201
+ if locator.is_file():
202
+ locator.unlink()
203
+ cleared.append("locator")
204
+ state = _state_path(guard_home)
205
+ if state.is_file():
206
+ state_payload = _load_state(guard_home)
207
+ pid = state_payload.get("pid") if isinstance(state_payload, dict) else None
208
+ daemon_is_live = (
209
+ isinstance(pid, int)
210
+ and pid > 0
211
+ and _guard_daemon_pid_is_running(pid)
212
+ and _guard_daemon_pid_matches_command(pid, expected_guard_home=guard_home)
213
+ )
214
+ if not daemon_is_live:
215
+ _write_private_text(state, "{}")
216
+ cleared.append("daemon_state")
217
+ return {"repaired": True, "cleared": cleared}
218
+
219
+
190
220
  def _locator_path(guard_home: Path) -> Path:
191
221
  return guard_home / _APPROVAL_CENTER_LOCATOR_FILE
192
222
 
@@ -38,6 +38,7 @@ from .manager import (
38
38
  GUARD_DAEMON_COMPATIBILITY_VERSION,
39
39
  clear_guard_daemon_state,
40
40
  load_guard_daemon_auth_token,
41
+ repair_approval_center_locator,
41
42
  write_guard_daemon_state,
42
43
  )
43
44
 
@@ -401,6 +402,10 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
401
402
  if parsed.path == "/v1/settings":
402
403
  self._handle_settings_update(payload)
403
404
  return
405
+ if parsed.path == "/v1/daemon/repair":
406
+ result = repair_approval_center_locator(self.server.store.guard_home) # type: ignore[attr-defined]
407
+ self._write_json(result)
408
+ return
404
409
  request_id, action, matched = self._resolve_request_action(path_parts, payload)
405
410
  if not matched:
406
411
  self.send_response(404)
@@ -996,6 +1001,7 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
996
1001
  if path in {
997
1002
  "/v1/inventory",
998
1003
  "/v1/connect/state",
1004
+ "/v1/daemon/repair",
999
1005
  "/v1/evidence",
1000
1006
  "/v1/evidence/export",
1001
1007
  "/v1/policy",
@@ -1167,6 +1173,7 @@ class _GuardDaemonHandler(BaseHTTPRequestHandler):
1167
1173
  "/v1/policy/decisions",
1168
1174
  "/v1/policy/clear",
1169
1175
  "/v1/settings",
1176
+ "/v1/daemon/repair",
1170
1177
  }:
1171
1178
  return True
1172
1179
  if len(path_parts) == 4 and path_parts[:2] == ["v1", "operations"] and path_parts[3] in {"items", "status"}: