skillctl-secure 0.30.3__tar.gz → 0.30.4__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 (132) hide show
  1. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/PKG-INFO +1 -1
  2. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/pyproject.toml +1 -1
  3. skillctl_secure-0.30.4/skillctl/__init__.py +1 -0
  4. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/attack_surface_tui.py +20 -5
  5. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/inventory_audit_tui.py +6 -2
  6. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/tui_original.py +4 -4
  7. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/tui_progressive.py +2 -0
  8. skillctl_secure-0.30.3/skillctl/__init__.py +0 -1
  9. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/.gitignore +0 -0
  10. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/LICENSE +0 -0
  11. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/README.md +0 -0
  12. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/__main__.py +0 -0
  13. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/attack_surface.py +0 -0
  14. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/authcontrols.py +0 -0
  15. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/benchmark.py +0 -0
  16. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/browsercontrols.py +0 -0
  17. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/bulk_cli.py +0 -0
  18. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/bulk_plan.py +0 -0
  19. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/bulk_update.py +0 -0
  20. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/bulk_update_tui.py +0 -0
  21. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/cacheutil.py +0 -0
  22. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/candidates.py +0 -0
  23. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog.py +0 -0
  24. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog_discovery.py +0 -0
  25. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog_index.py +0 -0
  26. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog_schema.py +0 -0
  27. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog_search_cli.py +0 -0
  28. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/catalog_search_tui.py +0 -0
  29. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/cicdflow.py +0 -0
  30. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/cli.py +0 -0
  31. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/cli_contract.py +0 -0
  32. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/compatibility.py +0 -0
  33. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/context_cost.py +0 -0
  34. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/context_tui.py +0 -0
  35. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/copilot_export.py +0 -0
  36. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/coverage.py +0 -0
  37. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/dedupe.py +0 -0
  38. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/destinations.py +0 -0
  39. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/destinations_cli.py +0 -0
  40. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/destinations_tui.py +0 -0
  41. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/doctor.py +0 -0
  42. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/entrypoint.py +0 -0
  43. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/environments.py +0 -0
  44. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/estimate.py +0 -0
  45. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/evidence.py +0 -0
  46. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/findings.py +0 -0
  47. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/findings_tui.py +0 -0
  48. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/flow.py +0 -0
  49. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/governor.py +0 -0
  50. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/hardening.py +0 -0
  51. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/history_tui.py +0 -0
  52. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/iac.py +0 -0
  53. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/install_intent.py +0 -0
  54. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/install_review.py +0 -0
  55. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/intent_diff.py +0 -0
  56. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/inventory.py +0 -0
  57. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/inventory_audit.py +0 -0
  58. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/journal.py +0 -0
  59. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/journal_hooks.py +0 -0
  60. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/journal_operations.py +0 -0
  61. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/lockfile.py +0 -0
  62. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/manager.py +0 -0
  63. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/models.py +0 -0
  64. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/navigation_tui.py +0 -0
  65. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/operation_lock.py +0 -0
  66. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/packet.py +0 -0
  67. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/paths.py +0 -0
  68. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/permissions.py +0 -0
  69. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/policy.py +0 -0
  70. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/policy_editor.py +0 -0
  71. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/precision.py +0 -0
  72. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/profiles.py +0 -0
  73. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/publishers.py +0 -0
  74. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/ranking.py +0 -0
  75. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/recommendation.py +0 -0
  76. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/recommendation_tui.py +0 -0
  77. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/reconcile_cli.py +0 -0
  78. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/reconcile_recovery.py +0 -0
  79. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/reconcile_transaction.py +0 -0
  80. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/reconcile_tui.py +0 -0
  81. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/reconciliation.py +0 -0
  82. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/remote.py +0 -0
  83. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/answer-key.yaml +0 -0
  84. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/.env +0 -0
  85. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/.github/workflows/build.yml +0 -0
  86. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/README.md +0 -0
  87. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/app.py +0 -0
  88. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/openapi.yaml +0 -0
  89. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/requirements.txt +0 -0
  90. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/scripts/build.sh +0 -0
  91. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/templates/payment.html +0 -0
  92. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/trivy-results.json +0 -0
  93. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/.gitkeep +0 -0
  94. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/SKILL.md +0 -0
  95. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/references/inventory-template.md +0 -0
  96. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/references/output-template.md +0 -0
  97. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/SKILL.md +0 -0
  98. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/disposition.md +0 -0
  99. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/orchestration.md +0 -0
  100. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/output-template.md +0 -0
  101. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/review-checklist.md +0 -0
  102. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/risk-rating.md +0 -0
  103. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/cicd-security-review/SKILL.md +0 -0
  104. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/cicd-security-review/references/output-template.md +0 -0
  105. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/SKILL.md +0 -0
  106. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/references/control-matrix.md +0 -0
  107. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/references/output-template.md +0 -0
  108. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/SKILL.md +0 -0
  109. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/references/output-template.md +0 -0
  110. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/references/risk-rating.md +0 -0
  111. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/SKILL.md +0 -0
  112. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/escalation.md +0 -0
  113. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/output-template.md +0 -0
  114. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/prioritization.md +0 -0
  115. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/finding-schema.json +0 -0
  116. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/resources/skills.yaml +0 -0
  117. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/review.py +0 -0
  118. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/review_candidates.py +0 -0
  119. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/risk_acknowledgment.py +0 -0
  120. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/runtime_binding.py +0 -0
  121. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/safety_plan.py +0 -0
  122. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/section_navigation.py +0 -0
  123. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/stagecache.py +0 -0
  124. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/stateio.py +0 -0
  125. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/transactions.py +0 -0
  126. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/trust.py +0 -0
  127. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/tui.py +0 -0
  128. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/tui_interaction.py +0 -0
  129. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/tui_refresh.py +0 -0
  130. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/update_intent_review.py +0 -0
  131. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/update_intent_tui.py +0 -0
  132. {skillctl_secure-0.30.3 → skillctl_secure-0.30.4}/skillctl/vulnnormalize.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: skillctl-secure
3
- Version: 0.30.3
3
+ Version: 0.30.4
4
4
  Summary: Package manager, trust layer, and portability layer for Agent Skills
5
5
  Project-URL: Homepage, https://github.com/brian-scardina/skillctl
6
6
  Project-URL: Repository, https://github.com/brian-scardina/skillctl
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "skillctl-secure"
3
- version = "0.30.3"
3
+ version = "0.30.4"
4
4
  description = "Package manager, trust layer, and portability layer for Agent Skills"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -0,0 +1 @@
1
+ __version__ = "0.30.4"
@@ -38,7 +38,7 @@ class AttackSurfacePanel(Vertical):
38
38
  with VerticalScroll(id='surface-details'):
39
39
  yield Static(METHOD + '\n\nSelect a skill or indicator to see evidence and fixes. Shared copies appear under each destination but count once. Each run assesses at most 100 copies; remaining copies stay UNKNOWN.', id='surface-detail', markup=False)
40
40
  with Horizontal(id='surface-actions'):
41
- yield Button('Assess installed skills', id='surface-assess', variant='primary', disabled=True)
41
+ yield Button('Reassess installed skills', id='surface-assess', variant='primary', disabled=True)
42
42
  if self.auto_load:
43
43
  yield Button('Close', id='surface-close')
44
44
 
@@ -49,13 +49,27 @@ class AttackSurfacePanel(Vertical):
49
49
  def ensure_loaded(self):
50
50
  if not self._loaded:
51
51
  self._loaded = True
52
- self.load_surface()
52
+ self.start_assessment()
53
+
54
+ def start_assessment(self):
55
+ self._selection_made = False
56
+ self.query_one('#surface-assess', Button).disabled = True
57
+ self.query_one('#surface-detail', Static).update(METHOD + '\n\nAssessment in progress. Select a copy for current findings.')
58
+ self.load_surface(True, self.query_one('#surface-cves', Checkbox).value)
59
+
60
+ def on_checkbox_changed(self, event):
61
+ if event.checkbox.id == 'surface-cves':
62
+ event.stop()
63
+ if self._loaded:
64
+ self.start_assessment()
53
65
 
54
66
  @work(thread=True, exclusive=True, group='surface-assessment')
55
67
  def load_surface(self, assess=False, online=False):
56
68
  worker = get_current_worker()
57
69
  try:
58
70
  inventory = scan_inventory(self.manager)
71
+ if worker.is_cancelled:
72
+ return
59
73
  self.app.call_from_thread(self.show_surface, inventory, {}, not assess)
60
74
  if assess:
61
75
  def progress(done, total, reports):
@@ -79,6 +93,8 @@ class AttackSurfacePanel(Vertical):
79
93
  surface = build_surface(inventory, reports)
80
94
  self.query_one('#surface-summary', Static).update(surface_summary(surface) + ('' if finished else '\nAssessing…'))
81
95
  self.query_one('#surface-assess', Button).disabled = not finished
96
+ if finished and not getattr(self, '_selection_made', False):
97
+ self.query_one('#surface-detail', Static).update(METHOD + '\n\nAssessment complete. Select a skill or indicator to see evidence and fixes.')
82
98
  tree = self.query_one('#surface-tree', Tree)
83
99
  tree.clear()
84
100
  tree.root.expand()
@@ -99,6 +115,7 @@ class AttackSurfacePanel(Vertical):
99
115
 
100
116
  def on_tree_node_selected(self, event):
101
117
  if event.node.data:
118
+ self._selection_made = True
102
119
  self.query_one('#surface-detail', Static).update(node_detail(event.node.data))
103
120
 
104
121
  def action_close(self):
@@ -110,9 +127,7 @@ class AttackSurfacePanel(Vertical):
110
127
  if event.button.id == 'surface-close':
111
128
  self.action_close()
112
129
  elif event.button.id == 'surface-assess':
113
- event.button.disabled = True
114
- self.query_one('#surface-detail', Static).update(METHOD + '\n\nAssessment in progress. Select a copy for current findings.')
115
- self.load_surface(True, self.query_one('#surface-cves', Checkbox).value)
130
+ self.start_assessment()
116
131
 
117
132
 
118
133
  class AttackSurfaceScreen(ModalScreen):
@@ -22,11 +22,15 @@ class InventoryAuditScreen(FindingsScreen):
22
22
  yield Button('Audit', id='findings-audit', variant='primary')
23
23
  yield Button('Close', id='findings-close')
24
24
 
25
- def on_mount(self):
26
- pass
25
+ def on_mount(self, event):
26
+ # Keep this explicit local audit idle until the user presses Audit.
27
+ event.prevent_default()
27
28
 
28
29
  def on_button_pressed(self, event):
29
30
  event.stop()
31
+ # Textual also dispatches to base-class handlers unless prevented.
32
+ # This dialog audits a local copy, so FindingsScreen must not handle it.
33
+ event.prevent_default()
30
34
  if event.button.id == 'findings-close':
31
35
  self.dismiss()
32
36
  elif event.button.id == 'findings-audit':
@@ -269,22 +269,22 @@ class SkillCtlTUI(App):
269
269
  def compose(self) -> ComposeResult:
270
270
  yield Header()
271
271
  with Horizontal(id="navigation"):
272
- yield Tabs(*(Tab(label, id="section-" + key) for key, label in (("home", "Home"), ("skills", "Skills"), ("risk", "Attack Surface & Risk"), ("reviews", "Reviews"), ("organize", "Organize"), ("system", "System"))), id="sections")
272
+ yield Tabs(*(Tab(label, id="section-" + key) for key, label in (("home", "Home"), ("skills", "Skills"), ("risk", "Risks"), ("reviews", "Reviews"), ("organize", "Organize"), ("system", "System"))), id="sections")
273
273
  yield Input(placeholder="Search… [/]", id="search", tooltip="Search skills, descriptions, categories, and collections. Press / to focus.")
274
274
  with Horizontal(id="body"):
275
275
  with TabbedContent(id="catalog"):
276
- with TabPane("Home", id="home"):
276
+ with TabPane("Overview", id="home"):
277
277
  yield DataTable(id="table-home", cursor_type="row")
278
278
  with TabPane("Stats", id="stats"):
279
279
  with VerticalScroll():
280
280
  yield Static("", id="summary", markup=True)
281
- with TabPane("Attack Surface & Risk", id="attack-surface"):
281
+ with TabPane("Risks", id="attack-surface"):
282
282
  from .attack_surface_tui import AttackSurfacePanel
283
283
  yield AttackSurfacePanel(self.manager, auto_load=False)
284
284
  with TabPane("Available", id="available"):
285
285
  yield DataTable(id="table-available", cursor_type="row")
286
286
  with TabPane("Inventory", id="inventory"):
287
- yield Button("Attack surface & risk", id="btn-attack-surface")
287
+ yield Button("Risks", id="btn-attack-surface")
288
288
  yield Static("Discovering installed skills…", id="inventory-summary", markup=False)
289
289
  yield DataTable(id="table-inventory", cursor_type="row")
290
290
  with TabPane("Installed here", id="installed"):
@@ -53,6 +53,8 @@ def install_progressive_startup(SkillCtlTUI, legacy_on_mount) -> None:
53
53
  pass
54
54
  # Start audit only after the primary catalog is visible and interactive.
55
55
  self.set_timer(0.05, self._auto_audit_catalog)
56
+ from .attack_surface_tui import AttackSurfacePanel
57
+ self.query_one(AttackSurfacePanel).ensure_loaded()
56
58
 
57
59
  def progressive_on_mount(self) -> None:
58
60
  self._primary_ready = False
@@ -1 +0,0 @@
1
- __version__ = "0.30.3"