plugin-scanner 3.2.0__py3-none-any.whl → 3.3.1__py3-none-any.whl

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 (28) hide show
  1. codex_plugin_scanner/guard/adapters/bounded_cli_hook_failure.py +2 -2
  2. codex_plugin_scanner/guard/adapters/codex_daemon_hook_bridge.py +16 -1
  3. codex_plugin_scanner/guard/adapters/codex_daemon_hook_bridge_flow.py +9 -3
  4. codex_plugin_scanner/guard/cli/approval_gate_prompt.py +6 -0
  5. codex_plugin_scanner/guard/cli/extension_builder_commands.py +105 -2
  6. codex_plugin_scanner/guard/daemon/hook_availability_policy.py +8 -1
  7. codex_plugin_scanner/guard/daemon/hook_launcher_recovery.py +106 -0
  8. codex_plugin_scanner/guard/daemon/static/assets/chunks/app-detail-workspace.js +1 -1
  9. codex_plugin_scanner/guard/daemon/static/assets/chunks/approval-proof-modal.js +1 -1
  10. codex_plugin_scanner/guard/daemon/static/assets/chunks/audit-workspace.js +1 -1
  11. codex_plugin_scanner/guard/daemon/static/assets/chunks/extensions-workspace.js +131 -111
  12. codex_plugin_scanner/guard/daemon/static/assets/chunks/home-protection-module.js +1 -1
  13. codex_plugin_scanner/guard/daemon/static/assets/chunks/mcp-policy-request-panel.js +1 -1
  14. codex_plugin_scanner/guard/daemon/static/assets/chunks/policy-workspace-page.js +1 -1
  15. codex_plugin_scanner/guard/daemon/static/assets/chunks/supply-chain-hub-workspace.js +1 -1
  16. codex_plugin_scanner/guard/daemon/static/assets/guard-dashboard.js +15 -15
  17. codex_plugin_scanner/guard/extension_builder/kit.py +43 -6
  18. codex_plugin_scanner/guard/extension_builder/listing.py +44 -6
  19. codex_plugin_scanner/guard/extension_builder/listing.v2.schema.json +126 -0
  20. codex_plugin_scanner/guard/native_policy_test_support.py +3 -1
  21. codex_plugin_scanner/guard/runtime/package_intent_parser.py +4 -1
  22. codex_plugin_scanner/guard/runtime/supply_chain_package_eval.py +181 -24
  23. codex_plugin_scanner/version.py +1 -1
  24. {plugin_scanner-3.2.0.dist-info → plugin_scanner-3.3.1.dist-info}/METADATA +58 -16
  25. {plugin_scanner-3.2.0.dist-info → plugin_scanner-3.3.1.dist-info}/RECORD +28 -26
  26. {plugin_scanner-3.2.0.dist-info → plugin_scanner-3.3.1.dist-info}/WHEEL +0 -0
  27. {plugin_scanner-3.2.0.dist-info → plugin_scanner-3.3.1.dist-info}/entry_points.txt +0 -0
  28. {plugin_scanner-3.2.0.dist-info → plugin_scanner-3.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,10 +4,10 @@ from __future__ import annotations
4
4
 
5
5
  from ..daemon.hook_availability_policy import (
6
6
  EMERGENCY_SAFE_REASON,
7
- hook_action_is_emergency_safe,
8
7
  hook_event_is_permission_request,
9
8
  hook_event_pauses_when_unavailable,
10
9
  )
10
+ from ..daemon.hook_launcher_recovery import hook_action_is_launcher_recovery_safe
11
11
 
12
12
  _DECISION_HOOK_HARNESSES = frozenset({"grok", "hermes", "openclaw"})
13
13
 
@@ -134,7 +134,7 @@ def failure_payload(
134
134
  pauses
135
135
  and not _is_permission_event(event_name)
136
136
  and isinstance(payload, dict)
137
- and hook_action_is_emergency_safe(payload)
137
+ and hook_action_is_launcher_recovery_safe(payload)
138
138
  ):
139
139
  return _emergency_safe_payload(harness, event_name), 0
140
140
  if not pauses:
@@ -14,6 +14,7 @@ if __package__:
14
14
  from ..codex_hook_bridge_runtime import bridge_config_from_argv as _parse_bridge_config
15
15
  from ..config import MAX_APPROVAL_WAIT_TIMEOUT_SECONDS
16
16
  from ..daemon.hook_availability_policy import hook_event_is_permission_request
17
+ from ..daemon.hook_launcher_recovery import hook_action_is_launcher_recovery_safe
17
18
  from ..live_process_identity import (
18
19
  CODEX_BROWSER_WAIT_PROCESS_KEY,
19
20
  CODEX_BROWSER_WAIT_TIMEOUT_SECONDS_KEY,
@@ -44,6 +45,9 @@ else: # pragma: no cover - exercised by subprocess integration tests
44
45
  from codex_plugin_scanner.guard.daemon.hook_availability_policy import (
45
46
  hook_event_is_permission_request,
46
47
  )
48
+ from codex_plugin_scanner.guard.daemon.hook_launcher_recovery import (
49
+ hook_action_is_launcher_recovery_safe,
50
+ )
47
51
  from codex_plugin_scanner.guard.live_process_identity import (
48
52
  CODEX_BROWSER_WAIT_PROCESS_KEY,
49
53
  CODEX_BROWSER_WAIT_TIMEOUT_SECONDS_KEY,
@@ -232,7 +236,7 @@ def main(
232
236
  )
233
237
  if response is None:
234
238
  if launch_integrity_failed:
235
- response = _fail_closed(event_name, _LAUNCH_INTEGRITY_REASON)
239
+ response = _launcher_integrity_response(event_name, data)
236
240
  else:
237
241
  failure_reason = _OVERLOAD_REASON if daemon_overloaded else _FAIL_CLOSED_REASON
238
242
  response = _unavailable_response(event_name, failure_reason, data)
@@ -248,6 +252,17 @@ def main(
248
252
  return 0
249
253
 
250
254
 
255
+ def _launcher_integrity_response(event_name: str, data: str) -> dict[str, object]:
256
+ """Keep a bad launcher from approving work, without locking out its repair."""
257
+
258
+ payload = _json_object(data)
259
+ if event_name == "PreToolUse" and payload is not None and hook_action_is_launcher_recovery_safe(payload):
260
+ return _unavailable_response(event_name, _LAUNCH_INTEGRITY_REASON, data)
261
+ if event_name in {"PreToolUse", "PermissionRequest"}:
262
+ return _fail_closed(event_name, _LAUNCH_INTEGRITY_REASON)
263
+ return _unavailable_response(event_name, _LAUNCH_INTEGRITY_REASON, data)
264
+
265
+
251
266
  def _bridge_output(
252
267
  response: dict[str, object],
253
268
  *,
@@ -17,6 +17,8 @@ from .codex_daemon_hook_auth import _DaemonResponseError
17
17
  from .codex_daemon_hook_transport import _daemon_response_once, _DaemonGenerationChangedError
18
18
 
19
19
  _DAEMON_START_TIMEOUT_SECONDS = 8
20
+ _DAEMON_RPC_TIMEOUT_SECONDS = 4.0
21
+ _FALLBACK_TIMEOUT_SECONDS = 4.0
20
22
  _MINIMUM_OPERATION_SECONDS = 0.01
21
23
  _OVERLOAD_RESERVE_MS = 100
22
24
 
@@ -42,7 +44,7 @@ def bridge_review_response(
42
44
  state_path=state_path,
43
45
  query=query,
44
46
  data=data,
45
- timeout_seconds=_remaining_seconds(deadline),
47
+ timeout_seconds=min(_remaining_seconds(deadline), _DAEMON_RPC_TIMEOUT_SECONDS),
46
48
  )
47
49
 
48
50
  try:
@@ -199,14 +201,18 @@ def _fallback_response(
199
201
  fallback_stdout = trusted_launch.run_fallback(
200
202
  fallback_command,
201
203
  data=data,
202
- timeout_seconds=_remaining_seconds(deadline),
204
+ timeout_seconds=_remaining_seconds(deadline, cap=_FALLBACK_TIMEOUT_SECONDS),
203
205
  )
204
206
  if fallback_stdout is None:
205
207
  return None
206
208
  return _json_object(fallback_stdout.strip()) if fallback_stdout.strip() else {}
207
209
  if launch_integrity_failed:
208
210
  return None
209
- return _run_local_fallback(fallback_command, data=data, timeout_seconds=_remaining_seconds(deadline))
211
+ return _run_local_fallback(
212
+ fallback_command,
213
+ data=data,
214
+ timeout_seconds=_remaining_seconds(deadline, cap=_FALLBACK_TIMEOUT_SECONDS),
215
+ )
210
216
 
211
217
 
212
218
  def _run_daemon_start(
@@ -74,6 +74,12 @@ def prompt_for_approval_gate(
74
74
  )
75
75
  if summary:
76
76
  print(summary, file=sys.stderr)
77
+ proof_name = "authenticator code" if gate.totp_enabled else "approval password"
78
+ print(
79
+ f"HOL Guard is waiting for your {proof_name}. Enter it at the next prompt to continue.",
80
+ file=sys.stderr,
81
+ flush=True,
82
+ )
77
83
  password = None if gate.totp_enabled else getpass.getpass("Approval password: ")
78
84
  totp_code = getpass.getpass("Authenticator code: ") if gate.totp_enabled else None
79
85
  return ApprovalGateInput(
@@ -3,12 +3,14 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import argparse
6
+ import json
7
+ import subprocess
6
8
  import sys
7
9
  from pathlib import Path
8
10
  from typing import TextIO
9
11
 
10
12
  from ..extension_builder.errors import BuilderError
11
- from ..extension_builder.io import canonical_json
13
+ from ..extension_builder.io import canonical_json, list_value, object_value, read_json
12
14
 
13
15
  _METADATA_FLAGS = (
14
16
  "slug",
@@ -21,6 +23,7 @@ _METADATA_FLAGS = (
21
23
  "launcher",
22
24
  "package",
23
25
  )
26
+ _HANDOFF_TIMEOUT_SECONDS = 1_500
24
27
 
25
28
 
26
29
  def configure_extension_builder_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
@@ -54,7 +57,16 @@ def configure_extension_builder_parser(subparsers: argparse._SubParsersAction[ar
54
57
  apply.add_argument("--repo", type=Path, required=True, help="HOL Guard source checkout")
55
58
  apply.add_argument("--write", action="store_true", help="Explicitly apply the inspected source changes")
56
59
  apply.add_argument("--expected-plan", help="Require the plan digest from a previous inspection")
57
- for command in (generate, validate, diff, apply):
60
+ handoff = commands.add_parser(
61
+ "handoff", help="Check command-extension inputs and generated projections before opening a pull request"
62
+ )
63
+ handoff.add_argument("--source", type=Path, required=True, help="Canonical command source JSON")
64
+ handoff.add_argument("--fixture", type=Path, required=True, help="Portable command fixture JSON")
65
+ handoff.add_argument(
66
+ "--repo", type=Path, default=Path("."), help="HOL Guard checkout containing generated projections"
67
+ )
68
+ handoff.add_argument("--compiler", type=Path, help="Use an already-built native source compiler")
69
+ for command in (generate, validate, diff, apply, handoff):
58
70
  command.add_argument("--json", action="store_true", help="Emit a deterministic JSON result")
59
71
 
60
72
 
@@ -96,6 +108,91 @@ def _generate(args: argparse.Namespace) -> dict[str, object]:
96
108
  return {**kit.summary(), "generated": True}
97
109
 
98
110
 
111
+ def _handoff(args: argparse.Namespace) -> dict[str, object]:
112
+ source = object_value(read_json(args.source), code="source_shape")
113
+ if source.get("schema") != "guard.command-extension-source.v1":
114
+ raise BuilderError("source_schema", "Source must use guard.command-extension-source.v1.")
115
+ extension = object_value(source.get("extension"), code="source_shape")
116
+ extension_id = extension.get("extension_id")
117
+ if not isinstance(extension_id, str) or not extension_id.startswith("command."):
118
+ raise BuilderError("source_identity", "Source must declare a command.* extension ID.")
119
+ try:
120
+ repo = args.repo.resolve(strict=True)
121
+ source_path = args.source.resolve(strict=True)
122
+ fixture_path = args.fixture.resolve(strict=True)
123
+ except OSError as exc:
124
+ raise BuilderError("repository_path", "Repository, source, and fixture paths must exist.") from exc
125
+ expected_source = repo / "contributions" / "command-sources" / f"{extension_id}.json"
126
+ expected_fixture = repo / "tests" / "fixtures" / f"command-source-{extension_id.removeprefix('command.')}.v1.json"
127
+ if source_path != expected_source or fixture_path != expected_fixture:
128
+ raise BuilderError("canonical_paths", "Source and fixture must use their canonical repository paths.")
129
+ trust_map = object_value(
130
+ read_json(repo / "contracts" / "extensions" / "trust-class-map.v1.json"), code="trust_shape"
131
+ )
132
+ if trust_map.get("schemaVersion") != "guard.extension-trust-class-map.v1":
133
+ raise BuilderError("trust_schema", "Trust map must use guard.extension-trust-class-map.v1.")
134
+ classes = object_value(trust_map.get("classes"), code="trust_shape")
135
+ external = list_value(classes.get("external"), maximum=4096)
136
+ if not all(isinstance(item, str) for item in external):
137
+ raise BuilderError("trust_shape", "Trust map must list extension IDs as strings.")
138
+ other_classes = {
139
+ class_name
140
+ for class_name in ("first-party", "trusted-library")
141
+ if extension_id in list_value(classes.get(class_name), maximum=4096)
142
+ }
143
+ if extension_id not in external:
144
+ if other_classes:
145
+ raise BuilderError(
146
+ "trust_class", "External contributions must remain in the reviewed external trust class."
147
+ )
148
+ raise BuilderError("missing_external_trust", "Trust map must list the extension under external.")
149
+ if other_classes:
150
+ raise BuilderError("trust_class", "Trust map must assign the extension to only the external trust class.")
151
+ script = repo / "scripts" / "prepare_extension_contribution.py"
152
+ if script.is_symlink() or not script.is_file():
153
+ raise BuilderError("repository_layout", "Repository preparation tooling is unavailable.")
154
+ command = [
155
+ sys.executable,
156
+ str(script),
157
+ "--check",
158
+ "--source",
159
+ str(source_path),
160
+ "--fixture",
161
+ str(fixture_path),
162
+ ]
163
+ if args.compiler is not None:
164
+ command.extend(("--compiler", str(args.compiler)))
165
+ try:
166
+ completed = subprocess.run(
167
+ command,
168
+ cwd=repo,
169
+ capture_output=True,
170
+ text=True,
171
+ timeout=_HANDOFF_TIMEOUT_SECONDS,
172
+ check=False,
173
+ )
174
+ except (OSError, subprocess.TimeoutExpired) as exc:
175
+ raise BuilderError("handoff_validation", "Native handoff validation could not be completed.") from exc
176
+ if completed.returncode:
177
+ raise BuilderError("handoff_validation", "Native source or generated-projection validation failed.")
178
+ try:
179
+ validation = json.loads(completed.stdout)
180
+ except json.JSONDecodeError as exc:
181
+ raise BuilderError("handoff_validation", "Native handoff validation produced an invalid result.") from exc
182
+ if (
183
+ not isinstance(validation, dict)
184
+ or validation.get("ok") is not True
185
+ or validation.get("checked") is not True
186
+ or validation.get("targetCommandsExecuted") != 0
187
+ ):
188
+ raise BuilderError("handoff_validation", "Native handoff validation did not complete safely.")
189
+ return {
190
+ "contributionId": extension_id,
191
+ "readyForPullRequest": True,
192
+ "targetCommandsExecuted": 0,
193
+ }
194
+
195
+
99
196
  def _operate(args: argparse.Namespace) -> dict[str, object]:
100
197
  from ..extension_builder.kit import diff_kits, load_kit
101
198
  from ..extension_builder.repository_write import apply_kit
@@ -104,6 +201,8 @@ def _operate(args: argparse.Namespace) -> dict[str, object]:
104
201
  command = args.extension_builder_command
105
202
  if command == "generate":
106
203
  return _generate(args)
204
+ if command == "handoff":
205
+ return _handoff(args)
107
206
  if command == "validate":
108
207
  return {**load_kit(args.kit).summary(), "validated": True}
109
208
  if command == "diff":
@@ -129,6 +228,10 @@ def _emit(result: dict[str, object], command: str, output: TextIO) -> None:
129
228
  print("Kits differ." if result["changed"] else "Kits are identical.", file=output)
130
229
  for name in ("addedOperations", "removedOperations", "changedOperations", "changedReviews"):
131
230
  print(f"{name}: {result[name]}", file=output)
231
+ elif command == "handoff":
232
+ print(f"Contribution handoff is ready for {result['contributionId']}.", file=output)
233
+ print("Source, fixture, external trust mapping, and generated projections agree.", file=output)
234
+ print("No target was executed and active protection was not changed.", file=output)
132
235
  else:
133
236
  verb = "Generated" if command == "generate" else "Validated"
134
237
  print(
@@ -187,9 +187,10 @@ def availability_harness_response(
187
187
  ) -> dict[str, object]:
188
188
  """Render a schema-valid harness result when native review is unavailable."""
189
189
 
190
+ from .hook_launcher_recovery import hook_action_is_launcher_recovery_safe
190
191
  from .hook_worker_responses import observe_lifecycle_fail_safe_response
191
192
 
192
- del payload, workspace, home_dir, guard_home, recording_only
193
+ del guard_home, recording_only
193
194
  canonical_lifecycle = _LIFECYCLE_CANONICAL_BY_COMPACT.get(_compact_hook_event_name(event_name))
194
195
  if canonical_lifecycle is not None:
195
196
  return observe_lifecycle_fail_safe_response(
@@ -211,6 +212,12 @@ def availability_harness_response(
211
212
  if pre_tool_event and reason_code.strip() in _INTEGRITY_FAIL_CLOSED_REASON_CODES:
212
213
  from .hook_worker_responses import integrity_fail_closed_pre_tool_response
213
214
 
215
+ if hook_action_is_launcher_recovery_safe(payload, workspace=workspace, home_dir=home_dir):
216
+ return recording_only_pre_tool_response(
217
+ harness,
218
+ reason_code=reason_code,
219
+ reason=reason,
220
+ )
214
221
  return integrity_fail_closed_pre_tool_response(
215
222
  harness,
216
223
  reason=reason,
@@ -0,0 +1,106 @@
1
+ """Exact repair commands that may start while hook review cannot authenticate."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import shlex
6
+ from collections.abc import Mapping
7
+ from pathlib import Path
8
+
9
+ from .hook_availability_floor import (
10
+ _BLOCKED_SOURCE_EVENTS,
11
+ _MUTATING_TOOLS,
12
+ _UNSAFE_SHELL_MARKERS,
13
+ _flag_name,
14
+ _payload_command,
15
+ _payload_is_mcp,
16
+ _payload_source_events,
17
+ _tool_name,
18
+ hook_action_is_emergency_safe,
19
+ )
20
+ from .hook_request_parsing import runtime_hook_event_name
21
+
22
+ _LAUNCHER_REPAIR_BINARIES = frozenset({"hol-guard", "plugin-guard"})
23
+ _LAUNCHER_REPAIR_FLAGS = frozenset({"--dry-run", "--force-pypi-reinstall", "--json"})
24
+ _LAUNCHER_REPAIR_HARNESSES = frozenset(
25
+ {
26
+ "antigravity",
27
+ "claude-code",
28
+ "cline",
29
+ "codex",
30
+ "copilot",
31
+ "cursor",
32
+ "gemini",
33
+ "grok",
34
+ "hermes",
35
+ "kimi",
36
+ "omp",
37
+ "openclaw",
38
+ "opencode",
39
+ "paseo",
40
+ "pi",
41
+ "zcode",
42
+ }
43
+ )
44
+
45
+
46
+ def hook_action_is_launcher_recovery_safe(
47
+ payload: Mapping[str, object],
48
+ *,
49
+ workspace: Path | None = None,
50
+ home_dir: Path | None = None,
51
+ ) -> bool:
52
+ """Allow inspection, or the exact bare command that restores a managed launcher.
53
+
54
+ A path-qualified executable is never treated as the managed launcher. An
55
+ unauthenticated payload reference is not evidence of the tool that will run.
56
+ Every other action stays blocked.
57
+ """
58
+
59
+ if "guard_payload_ref" in payload:
60
+ return False
61
+ if hook_action_is_emergency_safe(payload, workspace=workspace, home_dir=home_dir):
62
+ return True
63
+ if runtime_hook_event_name(payload) != "PreToolUse":
64
+ return False
65
+ tool_name = _tool_name(payload)
66
+ if tool_name in _MUTATING_TOOLS and tool_name not in {"bash", "shell"}:
67
+ return False
68
+ if _payload_source_events(payload) & _BLOCKED_SOURCE_EVENTS:
69
+ return False
70
+ if _payload_is_mcp(payload) or tool_name.startswith("plugin-"):
71
+ return False
72
+ command = _payload_command(payload)
73
+ if command is None:
74
+ return False
75
+ return _command_is_launcher_repair(command)
76
+
77
+
78
+ def _command_is_launcher_repair(command: str) -> bool:
79
+ stripped = command.strip()
80
+ if not stripped or len(stripped) > 4096:
81
+ return False
82
+ if any(marker in stripped for marker in _UNSAFE_SHELL_MARKERS):
83
+ return False
84
+ try:
85
+ tokens = shlex.split(stripped, posix=True, comments=False)
86
+ except ValueError:
87
+ return False
88
+ if len(tokens) < 2 or tokens[0] not in _LAUNCHER_REPAIR_BINARIES:
89
+ return False
90
+ positional: list[str] = []
91
+ for token in tokens[1:]:
92
+ if token.startswith("-"):
93
+ if _flag_name(token) not in _LAUNCHER_REPAIR_FLAGS or "=" in token:
94
+ return False
95
+ continue
96
+ positional.append(token)
97
+ if positional[:1] == ["install"]:
98
+ return len(positional) == 2 and positional[1] in _LAUNCHER_REPAIR_HARNESSES
99
+ if positional[:1] == ["update"]:
100
+ return len(positional) == 1
101
+ if positional[:1] == ["daemon"]:
102
+ return positional[1:] in (["repair"], ["status"])
103
+ return False
104
+
105
+
106
+ __all__ = ["hook_action_is_launcher_recovery_safe"]
@@ -1,4 +1,4 @@
1
- import { r as reactExports, i as harnessDisplayName, aq as fetchSettings, b3 as runHarnessAction, b4 as GuardHarnessActionError, j as jsxRuntimeExports, S as SectionLabel, A as ActionButton, b5 as HiMiniRocketLaunch, w as HiMiniShieldCheck, am as HiMiniArrowPath, y as formatRelativeTime, P as HiMiniExclamationTriangle, s as HiMiniCheckCircle, b6 as HiMiniTrash, b7 as isGuardDemoMode, b8 as fetchGuardApi, b9 as formatHarnessCommand, ah as HiMiniAdjustmentsHorizontal, ba as fetchApprovalPage, bb as fetchPolicy, x as guardActionDisposition, p as protectionHealthFor, l as useProtectionPresentationState, aY as HiMiniArrowLeft, c as HiMiniChevronRight, t as GuardHero, a5 as ProofStrip, bc as HiMiniHome, Q as HiMiniBolt, bd as appSetupTarget, be as guardActionPresentation, R as Badge, bf as DEFAULT_FILTER_STATE, bg as filterEvidence, bh as sortEvidence, bi as computeMetrics, bj as CommandActivityWorkspace, n as EmptyState, bk as EvidenceFilterBar, bl as EvidenceInsightStrip, bm as EvidenceActionList, bn as EvidenceActionDetail, M as useFocusTrap, bo as policyIdentityKey, K as HiMiniCloud, aJ as Tag, a7 as HiMiniXCircle, bp as clearLabelForScope, bq as HiMiniChartBar } from "../guard-dashboard.js";
1
+ import { r as reactExports, i as harnessDisplayName, aq as fetchSettings, b3 as runHarnessAction, b4 as GuardHarnessActionError, j as jsxRuntimeExports, S as SectionLabel, A as ActionButton, b5 as HiMiniRocketLaunch, w as HiMiniShieldCheck, am as HiMiniArrowPath, y as formatRelativeTime, P as HiMiniExclamationTriangle, s as HiMiniCheckCircle, b6 as HiMiniTrash, b7 as isGuardDemoMode, b8 as fetchGuardApi, b9 as formatHarnessCommand, ah as HiMiniAdjustmentsHorizontal, ba as fetchApprovalPage, bb as fetchPolicy, x as guardActionDisposition, p as protectionHealthFor, l as useProtectionPresentationState, aZ as HiMiniArrowLeft, c as HiMiniChevronRight, t as GuardHero, a5 as ProofStrip, bc as HiMiniHome, Q as HiMiniBolt, bd as appSetupTarget, be as guardActionPresentation, R as Badge, bf as DEFAULT_FILTER_STATE, bg as filterEvidence, bh as sortEvidence, bi as computeMetrics, bj as CommandActivityWorkspace, n as EmptyState, bk as EvidenceFilterBar, bl as EvidenceInsightStrip, bm as EvidenceActionList, bn as EvidenceActionDetail, M as useFocusTrap, bo as policyIdentityKey, K as HiMiniCloud, aJ as Tag, a7 as HiMiniXCircle, bp as clearLabelForScope, bq as HiMiniChartBar } from "../guard-dashboard.js";
2
2
  import { A as ApprovalProofModal } from "./approval-proof-modal.js";
3
3
  import { u as useHarnessDetection, i as isHarnessDetected } from "./harness-detection.js";
4
4
  function HarnessSetupPanel(props) {
@@ -1,4 +1,4 @@
1
- import { r as reactExports, M as useFocusTrap, al as isApprovalProofSubmitDisabled, aP as buildApprovalProofCredentials, j as jsxRuntimeExports, S as SectionLabel, an as ApprovalProofFieldInputs, A as ActionButton } from "../guard-dashboard.js";
1
+ import { r as reactExports, M as useFocusTrap, al as isApprovalProofSubmitDisabled, aQ as buildApprovalProofCredentials, j as jsxRuntimeExports, S as SectionLabel, an as ApprovalProofFieldInputs, A as ActionButton } from "../guard-dashboard.js";
2
2
  function ApprovalProofModal(props) {
3
3
  const {
4
4
  title,
@@ -1,4 +1,4 @@
1
- import { j as jsxRuntimeExports, aJ as Tag, y as formatRelativeTime, r as reactExports, A as ActionButton, ck as HiMiniChevronLeft, c as HiMiniChevronRight, bw as IconActionButton, C as HiMiniXMark, bB as GuardModalLayer, cl as HiMiniFunnel, aG as HiMiniMagnifyingGlass, cm as HiMiniArrowDown, cn as HiMiniArrowUp, S as SectionLabel, am as HiMiniArrowPath, bA as HiMiniBugAnt, n as EmptyState, ah as HiMiniAdjustmentsHorizontal, bC as ConnectFlowCard, P as HiMiniExclamationTriangle, aN as useResolvedApprovalGate, co as runAuditRemediation, R as Badge, ch as isBlockedGuardAction, bs as isSupplyChainAuditEvidence, s as HiMiniCheckCircle, a7 as HiMiniXCircle, i as harnessDisplayName, bU as HiMiniDocumentText, b2 as guardAwareHref, w as HiMiniShieldCheck } from "../guard-dashboard.js";
1
+ import { j as jsxRuntimeExports, aJ as Tag, y as formatRelativeTime, r as reactExports, A as ActionButton, ck as HiMiniChevronLeft, c as HiMiniChevronRight, bw as IconActionButton, C as HiMiniXMark, bB as GuardModalLayer, cl as HiMiniFunnel, aG as HiMiniMagnifyingGlass, cm as HiMiniArrowDown, cn as HiMiniArrowUp, S as SectionLabel, am as HiMiniArrowPath, bA as HiMiniBugAnt, n as EmptyState, ah as HiMiniAdjustmentsHorizontal, bC as ConnectFlowCard, P as HiMiniExclamationTriangle, aO as useResolvedApprovalGate, co as runAuditRemediation, R as Badge, ch as isBlockedGuardAction, bs as isSupplyChainAuditEvidence, s as HiMiniCheckCircle, a7 as HiMiniXCircle, i as harnessDisplayName, bU as HiMiniDocumentText, b2 as guardAwareHref, w as HiMiniShieldCheck } from "../guard-dashboard.js";
2
2
  import { A as ApprovalProofModal } from "./approval-proof-modal.js";
3
3
  import { p as packageWorkbenchEcosystems, f as filterPackageWorkbenchFindings, c as sortPackageWorkbenchFindings, i as isApprovalGateRequiredError } from "./supply-chain-hub-workspace.js";
4
4
  import { r as resolveManagerCoverageManagers, a as resolveManagerCoverageStatus } from "./supply-chain-protection-stats.js";