plugin-scanner 2.0.149__tar.gz → 2.0.150__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 (448) hide show
  1. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/PKG-INFO +1 -1
  2. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/app.tsx +50 -12
  3. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/approval-center-layout.tsx +168 -29
  4. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/approval-center-primitives.tsx +24 -9
  5. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/fleet-workspace.tsx +33 -16
  6. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/home-dashboard.tsx +175 -2
  7. plugin_scanner-2.0.150/dashboard/src/queue-chip-filter.tsx +58 -0
  8. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/runtime-overview.tsx +1 -1
  9. plugin_scanner-2.0.150/dashboard/src/scanner-evidence-badge.tsx +66 -0
  10. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/settings-workspace.tsx +12 -0
  11. plugin_scanner-2.0.150/dashboard/src/watched-app-card.tsx +182 -0
  12. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/pyproject.toml +1 -1
  13. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/pyproject.toml.bak +1 -1
  14. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +524 -52
  15. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/assets/index.css +69 -0
  16. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/version.py +1 -1
  17. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.clusterfuzzlite/Dockerfile +0 -0
  18. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.clusterfuzzlite/build.sh +0 -0
  19. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.clusterfuzzlite/project.yaml +0 -0
  20. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.clusterfuzzlite/requirements-atheris.txt +0 -0
  21. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.dockerignore +0 -0
  22. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/CODEOWNERS +0 -0
  23. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/ISSUE_TEMPLATE/bug-report.yml +0 -0
  24. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  25. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/ISSUE_TEMPLATE/feature-request.yml +0 -0
  26. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/dependabot.yml +0 -0
  27. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/ci.yml +0 -0
  28. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/codeql.yml +0 -0
  29. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/dependabot-uv-lock.yml +0 -0
  30. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/fuzz.yml +0 -0
  31. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/harness-smoke.yml +0 -0
  32. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/publish.yml +0 -0
  33. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.github/workflows/scorecard.yml +0 -0
  34. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.gitignore +0 -0
  35. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/.pre-commit-hooks.yaml +0 -0
  36. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/CONTRIBUTING.md +0 -0
  37. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/Dockerfile +0 -0
  38. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/LICENSE +0 -0
  39. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/README.md +0 -0
  40. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/SECURITY.md +0 -0
  41. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/index.html +0 -0
  42. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/package.json +0 -0
  43. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/pnpm-lock.yaml +0 -0
  44. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/apple-touch-icon.png +0 -0
  45. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/brand/Logo_Icon_Dark.png +0 -0
  46. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/brand/Logo_Whole.png +0 -0
  47. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/favicon-16x16.png +0 -0
  48. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/favicon-32x32.png +0 -0
  49. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/public/favicon.ico +0 -0
  50. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/approval-center-layout.test.ts +0 -0
  51. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/approval-center-review-cards.tsx +0 -0
  52. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/approval-center-utils.ts +0 -0
  53. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/data-flow-evidence-card.tsx +0 -0
  54. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/guard-api.test.ts +0 -0
  55. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/guard-api.ts +0 -0
  56. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/guard-demo.ts +0 -0
  57. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/guard-types.ts +0 -0
  58. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/main.tsx +0 -0
  59. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/queue-state.test.ts +0 -0
  60. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/queue-state.ts +0 -0
  61. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/receipts-workspace.test.ts +0 -0
  62. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/receipts-workspace.tsx +0 -0
  63. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/risk-signal-cards.test.ts +0 -0
  64. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/risk-signal-cards.tsx +0 -0
  65. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/runtime-overview.test.ts +0 -0
  66. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/settings-workspace.test.ts +0 -0
  67. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/styles.css +0 -0
  68. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/src/vite-env.d.ts +0 -0
  69. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/tsconfig.json +0 -0
  70. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/dashboard/vite.config.ts +0 -0
  71. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docker-requirements.txt +0 -0
  72. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/approval-audit.md +0 -0
  73. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/architecture.md +0 -0
  74. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/get-started.md +0 -0
  75. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/harness-support.md +0 -0
  76. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/local-vs-cloud.md +0 -0
  77. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/release-checklist.md +0 -0
  78. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/release-notes.md +0 -0
  79. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/smoke-tests.md +0 -0
  80. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/guard/testing-matrix.md +0 -0
  81. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/trust/mcp-trust-draft.md +0 -0
  82. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/trust/plugin-trust-draft.md +0 -0
  83. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/docs/trust/skill-trust-local.md +0 -0
  84. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/fuzzers/manifest_fuzzer.py +0 -0
  85. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/requirements.txt +0 -0
  86. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/schemas/plugin-quality.v1.json +0 -0
  87. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/schemas/scan-result.v1.json +0 -0
  88. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/schemas/verify-result.v1.json +0 -0
  89. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/__init__.py +0 -0
  90. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/action_runner.py +0 -0
  91. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/argparse_utils.py +0 -0
  92. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/__init__.py +0 -0
  93. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/best_practices.py +0 -0
  94. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/claude.py +0 -0
  95. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/code_quality.py +0 -0
  96. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/ecosystem_common.py +0 -0
  97. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/gemini.py +0 -0
  98. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/manifest.py +0 -0
  99. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/manifest_support.py +0 -0
  100. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/marketplace.py +0 -0
  101. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/mcp_security.py +0 -0
  102. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/opencode.py +0 -0
  103. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/operational_security.py +0 -0
  104. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/security.py +0 -0
  105. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/checks/skill_security.py +0 -0
  106. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/cli.py +0 -0
  107. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/cli_ui.py +0 -0
  108. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/config.py +0 -0
  109. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/__init__.py +0 -0
  110. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/base.py +0 -0
  111. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/claude.py +0 -0
  112. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/codex.py +0 -0
  113. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/detect.py +0 -0
  114. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/gemini.py +0 -0
  115. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/opencode.py +0 -0
  116. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/registry.py +0 -0
  117. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/ecosystems/types.py +0 -0
  118. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/github_reporting.py +0 -0
  119. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/__init__.py +0 -0
  120. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/access_graph_events.py +0 -0
  121. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/__init__.py +0 -0
  122. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/antigravity.py +0 -0
  123. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/base.py +0 -0
  124. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/claude_code.py +0 -0
  125. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/cloud_identity.py +0 -0
  126. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/codex.py +0 -0
  127. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/contracts.py +0 -0
  128. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/copilot.py +0 -0
  129. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/cursor.py +0 -0
  130. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/gemini.py +0 -0
  131. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/hermes.py +0 -0
  132. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/mcp_servers.py +0 -0
  133. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/openclaw.py +0 -0
  134. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/openclaw_config.py +0 -0
  135. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/openclaw_support.py +0 -0
  136. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/opencode.py +0 -0
  137. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/adapters/opencode_artifacts.py +0 -0
  138. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/advisory_model.py +0 -0
  139. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/approvals.py +0 -0
  140. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/bridge/__init__.py +0 -0
  141. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/capabilities.py +0 -0
  142. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/__init__.py +0 -0
  143. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/approval_commands.py +0 -0
  144. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/bootstrap.py +0 -0
  145. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/commands.py +0 -0
  146. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/connect_flow.py +0 -0
  147. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/install_commands.py +0 -0
  148. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/product.py +0 -0
  149. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/prompt.py +0 -0
  150. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/render.py +0 -0
  151. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/cli/update_commands.py +0 -0
  152. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/codex_config.py +0 -0
  153. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/config.py +0 -0
  154. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/consumer/__init__.py +0 -0
  155. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/consumer/service.py +0 -0
  156. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/__init__.py +0 -0
  157. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/client.py +0 -0
  158. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/manager.py +0 -0
  159. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/server.py +0 -0
  160. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/apple-touch-icon.png +0 -0
  161. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Icon_Dark.png +0 -0
  162. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/brand/Logo_Whole.png +0 -0
  163. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/favicon-16x16.png +0 -0
  164. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/favicon-32x32.png +0 -0
  165. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/favicon.ico +0 -0
  166. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/daemon/static/index.html +0 -0
  167. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/edge_events.py +0 -0
  168. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/incident.py +0 -0
  169. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/launcher.py +0 -0
  170. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/mcp_tool_calls.py +0 -0
  171. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/models.py +0 -0
  172. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/policy/__init__.py +0 -0
  173. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/policy/engine.py +0 -0
  174. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/protect.py +0 -0
  175. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/proxy/__init__.py +0 -0
  176. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/proxy/remote.py +0 -0
  177. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/proxy/runtime_mcp.py +0 -0
  178. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/proxy/stdio.py +0 -0
  179. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/receipts/__init__.py +0 -0
  180. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/receipts/manager.py +0 -0
  181. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/redaction.py +0 -0
  182. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/risk.py +0 -0
  183. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/__init__.py +0 -0
  184. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/action_identity.py +0 -0
  185. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/actions.py +0 -0
  186. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/advisory_escalation.py +0 -0
  187. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/advisory_matchers.py +0 -0
  188. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/cisco_evidence.py +0 -0
  189. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/cisco_preflight.py +0 -0
  190. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/data_flow.py +0 -0
  191. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/data_flow_rules.py +0 -0
  192. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/data_flow_variables.py +0 -0
  193. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/decisions.py +0 -0
  194. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/detectors.py +0 -0
  195. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/mcp_protection.py +0 -0
  196. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/prompt_injection.py +0 -0
  197. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/runner.py +0 -0
  198. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/safe_decode.py +0 -0
  199. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/sandbox.py +0 -0
  200. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/scanner_cache.py +0 -0
  201. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/secret_file_requests.py +0 -0
  202. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/secret_sensitivity.py +0 -0
  203. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/secret_sources.py +0 -0
  204. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/shell_commands.py +0 -0
  205. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/signals.py +0 -0
  206. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/skill_protection.py +0 -0
  207. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/supply_chain.py +0 -0
  208. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/surface_server.py +0 -0
  209. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/temp_files.py +0 -0
  210. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/runtime/threat_intel.py +0 -0
  211. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/schemas/__init__.py +0 -0
  212. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/schemas/consumer_mode.py +0 -0
  213. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/schemas/guard_event_v1.py +0 -0
  214. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/schemas/surface_server.py +0 -0
  215. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/shims.py +0 -0
  216. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/store.py +0 -0
  217. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/store_approvals.py +0 -0
  218. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/store_connect.py +0 -0
  219. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/store_evidence.py +0 -0
  220. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/store_threat_intel.py +0 -0
  221. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/guard/types.py +0 -0
  222. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/integrations/__init__.py +0 -0
  223. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/integrations/cisco_mcp_scanner.py +0 -0
  224. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/integrations/cisco_skill_scanner.py +0 -0
  225. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/lint_fixes.py +0 -0
  226. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/marketplace_support.py +0 -0
  227. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/models.py +0 -0
  228. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/path_support.py +0 -0
  229. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/policy.py +0 -0
  230. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/quality_artifact.py +0 -0
  231. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/repo_detect.py +0 -0
  232. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/reporting.py +0 -0
  233. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/rules/__init__.py +0 -0
  234. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/rules/registry.py +0 -0
  235. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/rules/specs.py +0 -0
  236. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/scanner.py +0 -0
  237. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/submission.py +0 -0
  238. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/suppressions.py +0 -0
  239. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_domain_scoring.py +0 -0
  240. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_helpers.py +0 -0
  241. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_mcp_scoring.py +0 -0
  242. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_models.py +0 -0
  243. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_plugin_scoring.py +0 -0
  244. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_scoring.py +0 -0
  245. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_skill_scoring.py +0 -0
  246. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/trust_specs.py +0 -0
  247. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/src/codex_plugin_scanner/verification.py +0 -0
  248. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/__init__.py +0 -0
  249. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/conftest.py +0 -0
  250. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/__init__.py +0 -0
  251. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/bad-plugin/.codex-plugin/plugin.json +0 -0
  252. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/bad-plugin/.mcp.json +0 -0
  253. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/bad-plugin/secrets.js +0 -0
  254. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/.claude-plugin/plugin.json +0 -0
  255. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/LICENSE +0 -0
  256. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/README.md +0 -0
  257. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/SECURITY.md +0 -0
  258. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/hooks/hooks.json +0 -0
  259. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/claude-plugin-good/skills/example/SKILL.md +0 -0
  260. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/code-quality-bad/evil.js +0 -0
  261. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/code-quality-bad/inject.js +0 -0
  262. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/GEMINI.md +0 -0
  263. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/LICENSE +0 -0
  264. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/README.md +0 -0
  265. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/SECURITY.md +0 -0
  266. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/commands/hello.toml +0 -0
  267. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/gemini-extension-good/gemini-extension.json +0 -0
  268. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/.codex-plugin/plugin.json +0 -0
  269. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/.codexignore +0 -0
  270. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/LICENSE +0 -0
  271. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/README.md +0 -0
  272. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/SECURITY.md +0 -0
  273. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/assets/icon.svg +0 -0
  274. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/assets/logo.svg +0 -0
  275. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/assets/screenshot.svg +0 -0
  276. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/good-plugin/skills/example/SKILL.md +0 -0
  277. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-codex-malicious-mcp/.codex/config.toml +0 -0
  278. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/README.md +0 -0
  279. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/benign-docs-fake-token.py +0 -0
  280. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/benign-health-endpoint.py +0 -0
  281. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/benign-nvmrc-fake-creds.py +0 -0
  282. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/benign-source-search.py +0 -0
  283. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/canary-exfil-encoded.py +0 -0
  284. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/canary-exfil.py +0 -0
  285. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/expected-decisions.json +0 -0
  286. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-dockerfile.txt +0 -0
  287. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-encoded-shell-exfil.py +0 -0
  288. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-github-action.yml +0 -0
  289. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-mcp-delete.md +0 -0
  290. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-mcp-secret-read.md +0 -0
  291. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-mcp-skill-exfil.md +0 -0
  292. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-npm-postinstall.js +0 -0
  293. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-prompt-env-read.md +0 -0
  294. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-prompt-guard-bypass.md +0 -0
  295. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-prompt-npmrc-read.md +0 -0
  296. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/malicious-python-setup.py +0 -0
  297. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/guard-red-team/smoke-evidence-template.json +0 -0
  298. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/config.yaml +0 -0
  299. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/mcp_servers.json +0 -0
  300. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/skills/security/malicious/SKILL.md +0 -0
  301. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/SKILL.md +0 -0
  302. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/references/api-setup.md +0 -0
  303. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/skills/stealth/sneaky/scripts/deploy.sh +0 -0
  304. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/hermes-plugin-evil/skills/utils/benign/SKILL.md +0 -0
  305. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malformed-json/.codex-plugin/plugin.json +0 -0
  306. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/.codex-plugin/plugin.json +0 -0
  307. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/.codexignore +0 -0
  308. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/LICENSE +0 -0
  309. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/README.md +0 -0
  310. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/SECURITY.md +0 -0
  311. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/malicious-skill-plugin/skills/leaky-skill/SKILL.md +0 -0
  312. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/mcp-canary-server.py +0 -0
  313. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/minimal-plugin/.codex-plugin/plugin.json +0 -0
  314. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/missing-fields/.codex-plugin/plugin.json +0 -0
  315. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/mit-license/LICENSE +0 -0
  316. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/codex-plugin/.codex-plugin/plugin.json +0 -0
  317. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/codex-plugin/LICENSE +0 -0
  318. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/codex-plugin/README.md +0 -0
  319. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/codex-plugin/SECURITY.md +0 -0
  320. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/gemini-ext/README.md +0 -0
  321. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-ecosystem-repo/gemini-ext/gemini-extension.json +0 -0
  322. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/.agents/plugins/marketplace.json +0 -0
  323. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codex-plugin/plugin.json +0 -0
  324. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/.codexignore +0 -0
  325. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/LICENSE +0 -0
  326. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/README.md +0 -0
  327. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/SECURITY.md +0 -0
  328. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/alpha-plugin/skills/example/SKILL.md +0 -0
  329. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/.codex-plugin/plugin.json +0 -0
  330. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/multi-plugin-repo/plugins/beta-plugin/skills/example/SKILL.md +0 -0
  331. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/no-version/.codex-plugin/plugin.json +0 -0
  332. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/.opencode/commands/hello.md +0 -0
  333. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/.opencode/plugins/example.ts +0 -0
  334. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/LICENSE +0 -0
  335. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/README.md +0 -0
  336. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/SECURITY.md +0 -0
  337. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/opencode-good/opencode.jsonc +0 -0
  338. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/skills-missing-dir/.codex-plugin/plugin.json +0 -0
  339. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/skills-no-frontmatter/.codex-plugin/plugin.json +0 -0
  340. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/skills-no-frontmatter/skills/bad-skill/SKILL.md +0 -0
  341. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/benign-npm-package.json +0 -0
  342. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/benign-pnpm-package.json +0 -0
  343. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/benign-pyproject.toml +0 -0
  344. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/malicious-Dockerfile +0 -0
  345. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/malicious-action.yml +0 -0
  346. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/malicious-npm-package.json +0 -0
  347. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/supply-chain/malicious-setup.py +0 -0
  348. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/with-marketplace/.codex-plugin/plugin.json +0 -0
  349. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/with-marketplace/marketplace-broken.json +0 -0
  350. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/fixtures/with-marketplace/marketplace.json +0 -0
  351. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test-trust-scoring.py +0 -0
  352. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test-trust-specs.py +0 -0
  353. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_action_runner.py +0 -0
  354. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_best_practices.py +0 -0
  355. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_cisco_install_surfaces.py +0 -0
  356. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_cli.py +0 -0
  357. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_code_quality.py +0 -0
  358. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_config.py +0 -0
  359. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_coverage_remaining.py +0 -0
  360. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_ecosystems.py +0 -0
  361. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_edge_cases.py +0 -0
  362. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_final_coverage.py +0 -0
  363. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_access_graph.py +0 -0
  364. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_action_identity.py +0 -0
  365. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_advisory_escalation.py +0 -0
  366. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_approval_continuity.py +0 -0
  367. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_approval_copy_commands.py +0 -0
  368. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_approval_store_dedup.py +0 -0
  369. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_approval_store_scale.py +0 -0
  370. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_approvals.py +0 -0
  371. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_bootstrap.py +0 -0
  372. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_canary_fixtures.py +0 -0
  373. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_capabilities.py +0 -0
  374. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_cisco_evidence.py +0 -0
  375. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_cisco_runtime_cli.py +0 -0
  376. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_claude_adapter.py +0 -0
  377. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_cli.py +0 -0
  378. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_cloud_local_sync.py +0 -0
  379. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_codex_e2e.py +0 -0
  380. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_codex_install.py +0 -0
  381. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_codex_proxy.py +0 -0
  382. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_config_paths.py +0 -0
  383. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_connect_flow.py +0 -0
  384. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_consumer_mode.py +0 -0
  385. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_copilot_adapter.py +0 -0
  386. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_copilot_proxy.py +0 -0
  387. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_daemon_manager.py +0 -0
  388. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_daemon_perf.py +0 -0
  389. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_daemon_repair_perf.py +0 -0
  390. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_data_flow.py +0 -0
  391. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_decision_propagation.py +0 -0
  392. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_event_schema_v1.py +0 -0
  393. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_events.py +0 -0
  394. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_evidence_store.py +0 -0
  395. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_harness_contracts.py +0 -0
  396. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_harness_setup.py +0 -0
  397. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_harness_smoke.py +0 -0
  398. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_launch_env.py +0 -0
  399. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_mcp_protection.py +0 -0
  400. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_opencode_proxy.py +0 -0
  401. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_policy_dedup.py +0 -0
  402. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_product_flow.py +0 -0
  403. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_prompt_injection.py +0 -0
  404. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_protect.py +0 -0
  405. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_queue_api_contract.py +0 -0
  406. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_queue_contract.py +0 -0
  407. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_red_team.py +0 -0
  408. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_render.py +0 -0
  409. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_resolution_copy.py +0 -0
  410. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_risk.py +0 -0
  411. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime.py +0 -0
  412. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime_action_harnesses.py +0 -0
  413. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime_actions.py +0 -0
  414. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime_decisions.py +0 -0
  415. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime_detectors.py +0 -0
  416. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_runtime_signals.py +0 -0
  417. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_safe_decode.py +0 -0
  418. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_sandbox.py +0 -0
  419. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_skill_protection.py +0 -0
  420. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_store_migrations.py +0 -0
  421. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_supply_chain.py +0 -0
  422. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_surface_server.py +0 -0
  423. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_threat_intel.py +0 -0
  424. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_verdicts.py +0 -0
  425. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_guard_web_recovery.py +0 -0
  426. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_hermes_adapter.py +0 -0
  427. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_integration.py +0 -0
  428. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_lint_fixes.py +0 -0
  429. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_live_cisco_smoke.py +0 -0
  430. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_manifest.py +0 -0
  431. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_marketplace.py +0 -0
  432. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_mcp_security.py +0 -0
  433. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_openclaw_adapter.py +0 -0
  434. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_operational_security.py +0 -0
  435. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_policy.py +0 -0
  436. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_quality_artifact.py +0 -0
  437. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_rule_registry.py +0 -0
  438. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_scanner.py +0 -0
  439. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_schema_contracts.py +0 -0
  440. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_security.py +0 -0
  441. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_security_ops.py +0 -0
  442. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_skill_security.py +0 -0
  443. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_submission.py +0 -0
  444. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_trust_scoring.py +0 -0
  445. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_trust_specs.py +0 -0
  446. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_verification.py +0 -0
  447. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/tests/test_versioning.py +0 -0
  448. {plugin_scanner-2.0.149 → plugin_scanner-2.0.150}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plugin-scanner
3
- Version: 2.0.149
3
+ Version: 2.0.150
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
@@ -1,4 +1,4 @@
1
- import { useEffect, useState, useCallback } from "react";
1
+ import { useEffect, useState, useCallback, useRef } from "react";
2
2
 
3
3
  import {
4
4
  clearPolicy,
@@ -142,6 +142,7 @@ export function App() {
142
142
  const [policies, setPolicies] = useState<PolicyState>({ kind: "loading" });
143
143
  const [inventory, setInventory] = useState<InventoryState>({ kind: "idle" });
144
144
  const [resolutionMessage, setResolutionMessage] = useState<string | null>(null);
145
+ const resolutionInFlight = useRef(false);
145
146
 
146
147
  useEffect(() => {
147
148
  let cancelled = false;
@@ -149,13 +150,13 @@ export function App() {
149
150
  const loadRuntimeSnapshot = () => {
150
151
  fetchRuntimeSnapshot()
151
152
  .then((snapshot) => {
152
- if (!cancelled) {
153
+ if (!cancelled && !resolutionInFlight.current) {
153
154
  setRuntime({ kind: "ready", snapshot });
154
155
  setRequests({ kind: "ready", items: snapshot.items });
155
156
  }
156
157
  })
157
158
  .catch((error: unknown) => {
158
- if (!cancelled) {
159
+ if (!cancelled && !resolutionInFlight.current) {
159
160
  const message =
160
161
  error instanceof Error ? error.message : "Unable to load the local approval queue.";
161
162
  setRuntime({ kind: "error", message });
@@ -330,17 +331,22 @@ export function App() {
330
331
  workspace?: string;
331
332
  reason: string;
332
333
  }) => {
334
+ resolutionInFlight.current = true;
333
335
  const queuedItemsSnapshot = requests.kind === "ready" ? requests.items : [];
334
- const result = await resolveRequestWithQueueResult(payload);
335
- const nextId = selectNextAfterResolution(result, queuedItemsSnapshot);
336
- if (nextId !== null) {
337
- setResolutionMessage(null);
338
- navigate(`/requests/${nextId}`);
339
- } else {
340
- setResolutionMessage(result.resolution_summary || "Decision saved. Return to your chat and retry the command.");
341
- navigate("/inbox");
336
+ try {
337
+ const result = await resolveRequestWithQueueResult(payload);
338
+ const nextId = selectNextAfterResolution(result, queuedItemsSnapshot);
339
+ if (nextId !== null) {
340
+ setResolutionMessage(null);
341
+ navigate(`/requests/${nextId}`);
342
+ } else {
343
+ setResolutionMessage(result.resolution_summary || "Decision saved. Return to your chat and retry the command.");
344
+ navigate("/inbox");
345
+ }
346
+ await refreshStateAfterAction();
347
+ } finally {
348
+ resolutionInFlight.current = false;
342
349
  }
343
- await refreshStateAfterAction();
344
350
  }, [requests, refreshStateAfterAction, setResolutionMessage]);
345
351
 
346
352
  const handleBulkApprove = useCallback(async (ids: string[]) => {
@@ -360,6 +366,34 @@ export function App() {
360
366
  await refreshStateAfterAction();
361
367
  }, [refreshStateAfterAction, setResolutionMessage]);
362
368
 
369
+ const handleRetry = useCallback(() => {
370
+ setRuntime({ kind: "loading" });
371
+ setRequests({ kind: "loading" });
372
+ fetchRuntimeSnapshot()
373
+ .then((snapshot) => {
374
+ setRuntime({ kind: "ready", snapshot });
375
+ setRequests({ kind: "ready", items: snapshot.items });
376
+ })
377
+ .catch((error: unknown) => {
378
+ const message =
379
+ error instanceof Error ? error.message : "Unable to load the local approval queue.";
380
+ setRuntime({ kind: "error", message });
381
+ setRequests({ kind: "error", message });
382
+ });
383
+ }, []);
384
+
385
+ const handleConnectHarness = useCallback((_harness: string) => {
386
+ navigate("/settings");
387
+ }, []);
388
+
389
+ const handleTestHarness = useCallback((_harness: string) => {
390
+ navigate("/inbox");
391
+ }, []);
392
+
393
+ const handleRepairHarness = useCallback((_harness: string) => {
394
+ navigate("/settings");
395
+ }, []);
396
+
363
397
  return (
364
398
  <ApprovalCenterLayout
365
399
  view={view}
@@ -387,12 +421,16 @@ export function App() {
387
421
  onOpenRequest={handleOpenRequest}
388
422
  onResolve={handleResolve}
389
423
  onBulkApprove={handleBulkApprove}
424
+ onRetry={handleRetry}
390
425
  fleetContent={
391
426
  runtime.kind === "ready" ? (
392
427
  <FleetWorkspace
393
428
  runtime={runtime.snapshot}
394
429
  policies={policies.kind === "ready" ? policies.items : []}
395
430
  inventory={inventory}
431
+ onConnectHarness={handleConnectHarness}
432
+ onTestHarness={handleTestHarness}
433
+ onRepairHarness={handleRepairHarness}
396
434
  />
397
435
  ) : null
398
436
  }
@@ -7,6 +7,10 @@ import {
7
7
  HiMiniNoSymbol,
8
8
  HiMiniArrowTopRightOnSquare,
9
9
  HiMiniChevronLeft,
10
+ HiBars3,
11
+ HiMiniXMark as HiMiniXMarkLayout,
12
+ HiMiniCheckCircle,
13
+ HiMiniInformationCircle,
10
14
  } from "react-icons/hi2";
11
15
  import {
12
16
  ShellHeader,
@@ -19,12 +23,13 @@ import {
19
23
  EmptyState,
20
24
  WelcomeState,
21
25
  SectionLabel,
22
- ListControls,
23
26
  PaginationControls
24
27
  } from "./approval-center-primitives";
25
28
  import { DataFlowEvidenceCard } from "./data-flow-evidence-card";
26
29
  import { SkillRiskCard, SupplyChainRiskCard, DecodedLayerCard } from "./risk-signal-cards";
27
30
  import { ReceiptsWorkspace } from "./receipts-workspace";
31
+ import { QueueChipFilter } from "./queue-chip-filter";
32
+ import { ScannerEvidenceSection } from "./scanner-evidence-badge";
28
33
  import {
29
34
  buildPauseLine,
30
35
  buildRecommendation,
@@ -110,6 +115,7 @@ type LayoutProps = {
110
115
  onGoHome: () => void;
111
116
  onNavigate: (pathname: string) => void;
112
117
  onOpenRequest: (requestId: string) => void;
118
+ onRetry?: () => void;
113
119
  onResolve: (payload: {
114
120
  requestId: string;
115
121
  action: "allow" | "block";
@@ -132,9 +138,14 @@ const commonScopeValues = new Set<DecisionScope>(["artifact", "workspace"]);
132
138
  const broadScopeValues = new Set<DecisionScope>(["publisher", "harness", "global"]);
133
139
  const queuePageSize = 8;
134
140
  export function ApprovalCenterLayout(props: LayoutProps) {
141
+ const [mobileQueueOpen, setMobileQueueOpen] = useState(false);
135
142
  const queuedItems = props.requests.kind === "ready" ? props.requests.items : [];
136
143
  const activeHarness =
137
144
  props.detail.kind === "ready" ? props.detail.item.harness : queuedItems[0]?.harness ?? null;
145
+
146
+ const handleOpenMobileQueue = useCallback(() => setMobileQueueOpen(true), []);
147
+ const handleCloseMobileQueue = useCallback(() => setMobileQueueOpen(false), []);
148
+
138
149
  return (
139
150
  <div className="min-h-screen bg-white text-brand-dark">
140
151
  <ShellHeader
@@ -142,8 +153,18 @@ export function ApprovalCenterLayout(props: LayoutProps) {
142
153
  activeHarness={activeHarness}
143
154
  view={props.view}
144
155
  onNavigate={props.onNavigate}
156
+ onOpenMobileQueue={handleOpenMobileQueue}
145
157
  />
146
158
  <ShellSidebar queuedCount={queuedItems.length} activeHarness={activeHarness} view={props.view} />
159
+ {mobileQueueOpen && props.view === "inbox" && props.requests.kind === "ready" && (
160
+ <MobileQueueDrawer
161
+ requests={props.requests.items}
162
+ activeRequestId={props.activeRequestId}
163
+ onClose={handleCloseMobileQueue}
164
+ onOpenRequest={props.onOpenRequest}
165
+ onBulkApprove={props.onBulkApprove}
166
+ />
167
+ )}
147
168
  <div className="flex flex-col lg:pl-64">
148
169
  <main className="flex-1 p-6 lg:p-10">
149
170
  <div className="mx-auto max-w-6xl">
@@ -166,6 +187,7 @@ export function ApprovalCenterLayout(props: LayoutProps) {
166
187
  onGoHome={props.onGoHome}
167
188
  onResolve={props.onResolve}
168
189
  onBulkApprove={props.onBulkApprove}
190
+ onRetry={props.onRetry}
169
191
  />
170
192
  )}
171
193
  </div>
@@ -175,6 +197,45 @@ export function ApprovalCenterLayout(props: LayoutProps) {
175
197
  );
176
198
  }
177
199
 
200
+ function MobileQueueDrawer(props: {
201
+ requests: GuardApprovalRequest[];
202
+ activeRequestId: string | null;
203
+ onClose: () => void;
204
+ onOpenRequest: (requestId: string) => void;
205
+ onBulkApprove?: (ids: string[]) => void;
206
+ }) {
207
+ return (
208
+ <div
209
+ className="fixed inset-0 z-50 flex lg:hidden"
210
+ >
211
+ <div className="absolute inset-0 bg-black/30 backdrop-blur-sm" onClick={props.onClose} />
212
+ <div className="relative ml-0 flex w-full max-w-sm flex-col overflow-hidden bg-white shadow-2xl" onClick={(e) => e.stopPropagation()}>
213
+ <div className="flex items-center justify-between border-b border-slate-200 px-4 py-3">
214
+ <span className="text-sm font-semibold text-brand-dark">
215
+ Review Queue ({props.requests.length})
216
+ </span>
217
+ <button
218
+ type="button"
219
+ onClick={props.onClose}
220
+ aria-label="Close queue"
221
+ className="rounded-full p-1.5 text-slate-500 hover:bg-slate-100"
222
+ >
223
+ <HiMiniXMarkLayout className="h-5 w-5" />
224
+ </button>
225
+ </div>
226
+ <div className="flex-1 overflow-y-auto">
227
+ <QueueBrowser
228
+ activeRequestId={props.activeRequestId}
229
+ items={props.requests}
230
+ onOpenRequest={props.onOpenRequest}
231
+ onBulkApprove={props.onBulkApprove}
232
+ />
233
+ </div>
234
+ </div>
235
+ </div>
236
+ );
237
+ }
238
+
178
239
  function QueueWorkspace(props: {
179
240
  requests: RequestState;
180
241
  detail: DetailState;
@@ -185,6 +246,7 @@ function QueueWorkspace(props: {
185
246
  onGoHome: () => void;
186
247
  onResolve: LayoutProps["onResolve"];
187
248
  onBulkApprove?: (ids: string[]) => void;
249
+ onRetry?: () => void;
188
250
  }) {
189
251
  if (props.requests.kind === "loading") {
190
252
  return (
@@ -195,10 +257,24 @@ function QueueWorkspace(props: {
195
257
  );
196
258
  }
197
259
  if (props.requests.kind === "error") {
260
+ const approvalUrl =
261
+ props.runtime.kind === "ready" ? props.runtime.snapshot.approval_center_url : null;
198
262
  return (
199
- <Surface tone="danger">
200
- <p className="text-sm text-brand-purple">{props.requests.message}</p>
201
- </Surface>
263
+ <div className="space-y-4">
264
+ <Surface tone="danger">
265
+ <p className="text-sm text-brand-purple">{props.requests.message}</p>
266
+ <div className="mt-4 flex flex-wrap gap-3">
267
+ {props.onRetry && (
268
+ <ActionButton onClick={props.onRetry}>Retry</ActionButton>
269
+ )}
270
+ {approvalUrl && (
271
+ <ActionButton href={approvalUrl} variant="outline">
272
+ Open Guard dashboard
273
+ </ActionButton>
274
+ )}
275
+ </div>
276
+ </Surface>
277
+ </div>
202
278
  );
203
279
  }
204
280
  if (props.requests.items.length === 0) {
@@ -222,6 +298,12 @@ function QueueWorkspace(props: {
222
298
  );
223
299
  return (
224
300
  <div className="space-y-4">
301
+ {props.resolutionMessage && props.requests.items.length > 0 && (
302
+ <div className="flex items-start gap-3 rounded-2xl border border-brand-green/25 bg-brand-green-bg/30 px-4 py-3">
303
+ <HiMiniCheckCircle className="mt-0.5 h-4 w-4 shrink-0 text-brand-green" aria-hidden="true" />
304
+ <p className="text-sm font-medium text-brand-green-text">{props.resolutionMessage}</p>
305
+ </div>
306
+ )}
225
307
  <QueueHeader
226
308
  activeRequestId={props.activeRequestId}
227
309
  requests={props.requests.items}
@@ -329,6 +411,14 @@ function QueueBrowser(props: {
329
411
  const pageStart = (currentPage - 1) * queuePageSize;
330
412
  const visibleGroups = groups.slice(pageStart, pageStart + queuePageSize);
331
413
 
414
+ const allGroups = useMemo(() => groupDuplicates(props.items), [props.items]);
415
+ const nextUpItem = useMemo(() => {
416
+ if (allGroups.length < 2 || props.activeRequestId === null) return null;
417
+ const activeIdx = allGroups.findIndex((g) => g.primary.request_id === props.activeRequestId);
418
+ if (activeIdx < 0 || activeIdx >= allGroups.length - 1) return null;
419
+ return allGroups[activeIdx + 1]?.primary ?? null;
420
+ }, [allGroups, props.activeRequestId]);
421
+
332
422
  useEffect(() => {
333
423
  setPage(1);
334
424
  }, [harnessFilter, searchTerm, sortDirection, props.items.length]);
@@ -337,10 +427,6 @@ function QueueBrowser(props: {
337
427
  setSearchTerm(event.target.value);
338
428
  }, []);
339
429
 
340
- const handleHarnessFilterChange = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
341
- setHarnessFilter(event.target.value);
342
- }, []);
343
-
344
430
  const handleSortChange = useCallback((event: ChangeEvent<HTMLSelectElement>) => {
345
431
  setSortDirection(event.target.value as QueueSortDirection);
346
432
  }, []);
@@ -391,18 +477,24 @@ function QueueBrowser(props: {
391
477
  </button>
392
478
  </div>
393
479
  )}
394
- <div className="mb-3 grid gap-2">
395
- <ListControls
396
- searchLabel="Search waiting actions"
397
- searchValue={searchTerm}
398
- searchPlaceholder="Command, file, MCP, host…"
399
- filterLabel="Filter by app"
400
- filterValue={harnessFilter}
401
- filterOptions={harnesses}
402
- allLabel="All apps"
403
- onSearchChange={handleSearchChange}
404
- onFilterChange={handleHarnessFilterChange}
405
- />
480
+ <div className="mb-3 space-y-2">
481
+ <label className="block">
482
+ <span className="sr-only">Search waiting actions</span>
483
+ <input
484
+ type="search"
485
+ value={searchTerm}
486
+ onChange={handleSearchChange}
487
+ placeholder="Command, file, MCP, host…"
488
+ className="min-h-11 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-brand-dark placeholder:text-slate-400 transition-colors duration-150 focus:border-brand-blue focus:outline-none focus:ring-2 focus:ring-brand-blue/20"
489
+ />
490
+ </label>
491
+ {harnesses.length > 1 && (
492
+ <QueueChipFilter
493
+ harnesses={harnesses}
494
+ activeFilter={harnessFilter}
495
+ onFilterChange={setHarnessFilter}
496
+ />
497
+ )}
406
498
  <label className="block">
407
499
  <span className="sr-only">Sort order</span>
408
500
  <select
@@ -422,6 +514,11 @@ function QueueBrowser(props: {
422
514
  key={group.primary.request_id}
423
515
  group={group}
424
516
  activeRequestId={props.activeRequestId}
517
+ nextUpItem={
518
+ nextUpItem !== null && group.primary.request_id === props.activeRequestId
519
+ ? nextUpItem
520
+ : null
521
+ }
425
522
  onOpenRequest={props.onOpenRequest}
426
523
  />
427
524
  ))
@@ -447,6 +544,7 @@ function QueueBrowser(props: {
447
544
  function QueueCardRow(props: {
448
545
  group: ReturnType<typeof groupDuplicates>[number];
449
546
  activeRequestId: string | null;
547
+ nextUpItem: GuardApprovalRequest | null;
450
548
  onOpenRequest: (requestId: string) => void;
451
549
  }) {
452
550
  const handleClick = useCallback(() => {
@@ -454,12 +552,22 @@ function QueueCardRow(props: {
454
552
  }, [props.onOpenRequest, props.group.primary.request_id]);
455
553
 
456
554
  return (
457
- <QueueCard
458
- item={props.group.primary}
459
- duplicateCount={props.group.duplicateCount}
460
- active={props.group.primary.request_id === props.activeRequestId}
461
- onClick={handleClick}
462
- />
555
+ <div>
556
+ <QueueCard
557
+ item={props.group.primary}
558
+ duplicateCount={props.group.duplicateCount}
559
+ active={props.group.primary.request_id === props.activeRequestId}
560
+ onClick={handleClick}
561
+ />
562
+ {props.nextUpItem !== null && (
563
+ <div className="border-t border-slate-100 bg-slate-50/60 px-4 py-2">
564
+ <p className="truncate text-[11px] text-muted-foreground">
565
+ <span className="font-semibold">Next up:</span>{" "}
566
+ {displayArtifactName(props.nextUpItem)}
567
+ </p>
568
+ </div>
569
+ )}
570
+ </div>
463
571
  );
464
572
  }
465
573
 
@@ -633,8 +741,19 @@ function DecisionWorkspace(props: {
633
741
  const { item, diff, receipt, policy } = props.detail;
634
742
  const commonScopeOpts = scopeOptions.filter((option) => commonScopeValues.has(option.value));
635
743
  const broadScopeOpts = scopeOptions.filter((option) => !commonScopeValues.has(option.value));
744
+ const isAlreadyDecided = item.resolution_action !== null;
745
+ const decidedLabel =
746
+ item.resolution_action === "allow" ? "allow" : item.resolution_action === "block" ? "block" : item.resolution_action ?? "decided";
636
747
  return (
637
748
  <div className="guard-surface-in space-y-4">
749
+ {isAlreadyDecided && (
750
+ <div className="flex items-start gap-3 rounded-2xl border border-slate-200/60 bg-slate-50 px-4 py-3">
751
+ <HiMiniInformationCircle className="mt-0.5 h-4 w-4 shrink-0 text-slate-400" aria-hidden="true" />
752
+ <p className="text-sm text-muted-foreground">
753
+ This action was already decided — {decidedLabel}. No further action needed.
754
+ </p>
755
+ </div>
756
+ )}
638
757
  {confirmPending !== null && (
639
758
  <ConfirmModal
640
759
  action={confirmPending}
@@ -655,13 +774,18 @@ function DecisionWorkspace(props: {
655
774
  onReasonChange={setReason}
656
775
  onResolve={handleRequestResolve}
657
776
  />
658
- <ScannerEvidenceSection item={item} />
777
+ <ScannerEvidenceSectionFull item={item} />
659
778
  <WhatChanged item={item} diff={diff} receipt={receipt} policy={policy} />
660
779
  </div>
661
780
  );
662
781
  }
663
782
 
664
- function ScannerEvidenceSection(props: { item: GuardApprovalRequest }) {
783
+ function InlineScannerSection(props: { item: GuardApprovalRequest }) {
784
+ const allSignals = props.item.decision_v2_json?.signals ?? [];
785
+ return <ScannerEvidenceSection signals={allSignals} />;
786
+ }
787
+
788
+ function ScannerEvidenceSectionFull(props: { item: GuardApprovalRequest }) {
665
789
  const hasSignals =
666
790
  (props.item.risk_signals ?? []).length > 0 ||
667
791
  !!props.item.risk_summary ||
@@ -669,6 +793,7 @@ function ScannerEvidenceSection(props: { item: GuardApprovalRequest }) {
669
793
  if (!hasSignals) return null;
670
794
  return (
671
795
  <div className="space-y-3">
796
+ <InlineScannerSection item={props.item} />
672
797
  <WhyGuardCares item={props.item} />
673
798
  <DataFlowEvidenceCard item={props.item} />
674
799
  <SkillRiskCard item={props.item} />
@@ -795,7 +920,7 @@ function RuleBuilder(props: {
795
920
  </div>
796
921
  </div>
797
922
 
798
- <div className="relative mt-5">
923
+ <div className="relative mt-5 sticky top-4 z-10">
799
924
  <DecisionActionPanel
800
925
  allowLabel={allowLabel}
801
926
  previewText={previewText}
@@ -1009,6 +1134,10 @@ function BlockedActionCard(props: { item: GuardApprovalRequest }) {
1009
1134
  const bannerLabel = isBlocked ? "Blocked" : "Paused for review";
1010
1135
  const bannerIcon = isBlocked ? HiMiniNoSymbol : HiMiniExclamationTriangle;
1011
1136
  const BannerIcon = bannerIcon;
1137
+ const envelope = props.item.action_envelope_json;
1138
+ const isMcpTool = envelope?.action_type === "mcp_tool";
1139
+ const mcpServer = isMcpTool ? (envelope?.mcp_server ?? null) : null;
1140
+ const mcpTool = isMcpTool ? (envelope?.mcp_tool ?? null) : null;
1012
1141
 
1013
1142
  return (
1014
1143
  <div className="overflow-hidden rounded-[1.65rem] border border-brand-blue/15 bg-white/70 shadow-[inset_0_1px_0_rgba(255,255,255,0.85)]">
@@ -1030,6 +1159,16 @@ function BlockedActionCard(props: { item: GuardApprovalRequest }) {
1030
1159
  ) : null}
1031
1160
  </div>
1032
1161
  <div className="p-4">
1162
+ {isMcpTool && mcpServer !== null && mcpTool !== null && (
1163
+ <div className="mb-3 flex items-center gap-2 rounded-xl border border-brand-blue/20 bg-brand-blue/[0.04] px-3 py-2">
1164
+ <span className="font-mono text-[11px] font-semibold uppercase tracking-[0.15em] text-brand-blue">
1165
+ MCP
1166
+ </span>
1167
+ <span className="font-mono text-sm font-medium text-brand-dark">
1168
+ {mcpServer} → {mcpTool}
1169
+ </span>
1170
+ </div>
1171
+ )}
1033
1172
  <div className="flex flex-wrap items-center justify-between gap-2">
1034
1173
  <SectionLabel>What was stopped</SectionLabel>
1035
1174
  </div>
@@ -9,6 +9,7 @@ import {
9
9
  HiMiniServerStack,
10
10
  HiMiniAdjustmentsHorizontal,
11
11
  HiMiniShieldCheck,
12
+ HiBars3,
12
13
  } from "react-icons/hi2";
13
14
 
14
15
  import { guardAwareHref } from "./guard-api";
@@ -53,6 +54,7 @@ export function ShellHeader(props: {
53
54
  activeHarness: string | null;
54
55
  view: "home" | "inbox" | "fleet" | "evidence" | "settings";
55
56
  onNavigate: (pathname: string) => void;
57
+ onOpenMobileQueue?: () => void;
56
58
  }) {
57
59
  function handleMobileNavigationChange(event: ChangeEvent<HTMLSelectElement>) {
58
60
  props.onNavigate(event.target.value);
@@ -85,13 +87,26 @@ export function ShellHeader(props: {
85
87
  ))}
86
88
  </select>
87
89
  </div>
88
- <a
89
- href={guardAwareHref("/inbox")}
90
- className="inline-flex min-h-11 shrink-0 items-center rounded-full border border-white/25 bg-white/10 px-3 py-2 text-sm font-semibold text-white no-underline transition-colors duration-150 hover:bg-white/15"
91
- aria-label={`${props.queuedCount} Guard actions queued`}
92
- >
93
- {props.queuedCount > 99 ? "99+" : props.queuedCount}
94
- </a>
90
+ {props.onOpenMobileQueue && props.view === "inbox" && props.queuedCount > 0 && (
91
+ <button
92
+ type="button"
93
+ onClick={props.onOpenMobileQueue}
94
+ aria-label="Open queue list"
95
+ className="inline-flex min-h-11 shrink-0 items-center gap-1.5 rounded-full border border-white/25 bg-white/10 px-3 py-2 text-sm font-semibold text-white no-underline transition-colors duration-150 hover:bg-white/15"
96
+ >
97
+ <HiBars3 className="h-4 w-4" aria-hidden="true" />
98
+ {props.queuedCount > 99 ? "99+" : props.queuedCount}
99
+ </button>
100
+ )}
101
+ {(!props.onOpenMobileQueue || props.view !== "inbox" || props.queuedCount === 0) && (
102
+ <a
103
+ href={guardAwareHref("/inbox")}
104
+ className="inline-flex min-h-11 shrink-0 items-center rounded-full border border-white/25 bg-white/10 px-3 py-2 text-sm font-semibold text-white no-underline transition-colors duration-150 hover:bg-white/15"
105
+ aria-label={`${props.queuedCount} Guard actions queued`}
106
+ >
107
+ {props.queuedCount > 99 ? "99+" : props.queuedCount}
108
+ </a>
109
+ )}
95
110
  </div>
96
111
  </header>
97
112
  );
@@ -523,9 +538,9 @@ export function WelcomeState(props: {
523
538
  <div className="mb-6 flex h-20 w-20 items-center justify-center rounded-full bg-brand-green-bg/50 ring-1 ring-brand-green/20">
524
539
  <HiMiniShieldCheck className="h-10 w-10 text-brand-green" aria-hidden="true" />
525
540
  </div>
526
- <h2 className="text-2xl font-semibold tracking-tight text-brand-dark sm:text-3xl">Your environment is secure</h2>
541
+ <h2 className="text-2xl font-semibold tracking-tight text-brand-dark sm:text-3xl">No blocked actions</h2>
527
542
  <p className="mx-auto mt-4 max-w-lg text-[15px] leading-relaxed text-muted-foreground">
528
- HOL Guard is watching connected apps on this machine. Connect Cloud when you want shared decisions across the team.
543
+ Guard is still watching your apps. You'll be notified here if something needs your approval.
529
544
  </p>
530
545
 
531
546
  <div className="mt-12 text-left w-full max-w-3xl">
@@ -1,12 +1,13 @@
1
+ import { useCallback } from "react";
1
2
  import {
2
3
  ActionButton,
3
- Badge,
4
4
  EmptyState,
5
5
  KeyValueGrid,
6
6
  SectionLabel,
7
7
  Tag
8
8
  } from "./approval-center-primitives";
9
9
  import { harnessDisplayName } from "./approval-center-utils";
10
+ import { WatchedAppCard } from "./watched-app-card";
10
11
  import type { GuardInventoryItem, GuardPolicyDecision, GuardReceipt, GuardRuntimeSnapshot } from "./guard-types";
11
12
 
12
13
  type FleetWorkspaceProps = {
@@ -17,6 +18,9 @@ type FleetWorkspaceProps = {
17
18
  | { kind: "loading" }
18
19
  | { kind: "error"; message: string }
19
20
  | { kind: "ready"; items: GuardInventoryItem[] };
21
+ onConnectHarness?: (harness: string) => void;
22
+ onTestHarness?: (harness: string) => void;
23
+ onRepairHarness?: (harness: string) => void;
20
24
  };
21
25
 
22
26
  function collectHarnesses(snapshot: GuardRuntimeSnapshot): string[] {
@@ -50,6 +54,20 @@ export function FleetWorkspace(props: FleetWorkspaceProps) {
50
54
  ).sort((left, right) => left.localeCompare(right));
51
55
  const runtimeState = props.runtime.runtime_state;
52
56
 
57
+ const receiptHarnesses = new Set(props.runtime.latest_receipts.map((r) => r.harness));
58
+
59
+ const handleConnect = useCallback((harness: string) => {
60
+ props.onConnectHarness?.(harness);
61
+ }, [props.onConnectHarness]);
62
+
63
+ const handleTest = useCallback((harness: string) => {
64
+ props.onTestHarness?.(harness);
65
+ }, [props.onTestHarness]);
66
+
67
+ const handleRepair = useCallback((harness: string) => {
68
+ props.onRepairHarness?.(harness);
69
+ }, [props.onRepairHarness]);
70
+
53
71
  return (
54
72
  <div className="space-y-6">
55
73
  <section className="guard-surface-in relative overflow-hidden rounded-[2rem] border border-brand-blue/15 bg-[radial-gradient(circle_at_top_left,rgba(85,153,254,0.12),transparent_32%),linear-gradient(135deg,#ffffff_0%,#ffffff_62%,rgba(72,223,123,0.10)_100%)] p-5 shadow-[0_20px_60px_rgba(63,65,116,0.08)] sm:p-6 lg:p-7">
@@ -86,26 +104,25 @@ export function FleetWorkspace(props: FleetWorkspaceProps) {
86
104
  <section className="rounded-[1.75rem] border border-slate-200/70 bg-white/80 p-5 shadow-sm sm:p-6">
87
105
  <SectionLabel>App coverage</SectionLabel>
88
106
  {visibleHarnesses.length > 0 ? (
89
- <div className="mt-4 overflow-hidden rounded-[1.5rem] border border-slate-200/70 bg-white/75">
107
+ <div className="mt-4 grid gap-3 sm:grid-cols-2">
90
108
  {visibleHarnesses.map((harness) => {
91
109
  const install = managedInstalls.find((item) => item.harness === harness);
92
110
  const harnessInventory = inventory.filter((item) => item.harness === harness && item.present);
93
111
  const harnessPolicies = props.policies.filter((item) => item.harness === harness);
94
- const statusLabel = install === undefined ? "Observed" : install.active ? "Protected" : "Disabled";
112
+ const hasReceipts = receiptHarnesses.has(harness);
95
113
  return (
96
- <div key={harness} className="border-b border-slate-200/70 px-4 py-3 last:border-b-0">
97
- <div className="flex items-start justify-between gap-3">
98
- <div>
99
- <p className="text-sm font-semibold text-brand-dark">{harnessDisplayName(harness)}</p>
100
- <p className="mt-1 text-xs text-muted-foreground">
101
- {harnessInventory.length} actions seen · {harnessPolicies.length} saved approvals
102
- </p>
103
- </div>
104
- <Badge tone={install === undefined || install.active ? "success" : "destructive"}>
105
- {statusLabel}
106
- </Badge>
107
- </div>
108
- </div>
114
+ <WatchedAppCard
115
+ key={harness}
116
+ harness={harness}
117
+ install={install}
118
+ harnessInventory={harnessInventory}
119
+ harnessPolicies={harnessPolicies}
120
+ hasReceipts={hasReceipts}
121
+ fleetUrl={props.runtime.fleet_url}
122
+ onConnect={handleConnect}
123
+ onTest={handleTest}
124
+ onRepair={handleRepair}
125
+ />
109
126
  );
110
127
  })}
111
128
  </div>