skillctl-secure 0.30.2__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.2 → skillctl_secure-0.30.4}/PKG-INFO +8 -1
  2. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/README.md +7 -0
  3. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/pyproject.toml +1 -1
  4. skillctl_secure-0.30.4/skillctl/__init__.py +1 -0
  5. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/attack_surface_tui.py +20 -5
  6. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/inventory_audit_tui.py +6 -2
  7. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/section_navigation.py +1 -1
  8. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/tui_original.py +8 -6
  9. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/tui_progressive.py +9 -0
  10. skillctl_secure-0.30.2/skillctl/__init__.py +0 -1
  11. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/.gitignore +0 -0
  12. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/LICENSE +0 -0
  13. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/__main__.py +0 -0
  14. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/attack_surface.py +0 -0
  15. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/authcontrols.py +0 -0
  16. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/benchmark.py +0 -0
  17. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/browsercontrols.py +0 -0
  18. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/bulk_cli.py +0 -0
  19. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/bulk_plan.py +0 -0
  20. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/bulk_update.py +0 -0
  21. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/bulk_update_tui.py +0 -0
  22. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/cacheutil.py +0 -0
  23. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/candidates.py +0 -0
  24. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog.py +0 -0
  25. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog_discovery.py +0 -0
  26. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog_index.py +0 -0
  27. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog_schema.py +0 -0
  28. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog_search_cli.py +0 -0
  29. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/catalog_search_tui.py +0 -0
  30. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/cicdflow.py +0 -0
  31. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/cli.py +0 -0
  32. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/cli_contract.py +0 -0
  33. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/compatibility.py +0 -0
  34. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/context_cost.py +0 -0
  35. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/context_tui.py +0 -0
  36. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/copilot_export.py +0 -0
  37. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/coverage.py +0 -0
  38. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/dedupe.py +0 -0
  39. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/destinations.py +0 -0
  40. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/destinations_cli.py +0 -0
  41. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/destinations_tui.py +0 -0
  42. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/doctor.py +0 -0
  43. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/entrypoint.py +0 -0
  44. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/environments.py +0 -0
  45. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/estimate.py +0 -0
  46. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/evidence.py +0 -0
  47. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/findings.py +0 -0
  48. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/findings_tui.py +0 -0
  49. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/flow.py +0 -0
  50. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/governor.py +0 -0
  51. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/hardening.py +0 -0
  52. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/history_tui.py +0 -0
  53. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/iac.py +0 -0
  54. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/install_intent.py +0 -0
  55. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/install_review.py +0 -0
  56. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/intent_diff.py +0 -0
  57. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/inventory.py +0 -0
  58. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/inventory_audit.py +0 -0
  59. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/journal.py +0 -0
  60. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/journal_hooks.py +0 -0
  61. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/journal_operations.py +0 -0
  62. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/lockfile.py +0 -0
  63. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/manager.py +0 -0
  64. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/models.py +0 -0
  65. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/navigation_tui.py +0 -0
  66. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/operation_lock.py +0 -0
  67. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/packet.py +0 -0
  68. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/paths.py +0 -0
  69. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/permissions.py +0 -0
  70. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/policy.py +0 -0
  71. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/policy_editor.py +0 -0
  72. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/precision.py +0 -0
  73. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/profiles.py +0 -0
  74. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/publishers.py +0 -0
  75. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/ranking.py +0 -0
  76. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/recommendation.py +0 -0
  77. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/recommendation_tui.py +0 -0
  78. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/reconcile_cli.py +0 -0
  79. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/reconcile_recovery.py +0 -0
  80. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/reconcile_transaction.py +0 -0
  81. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/reconcile_tui.py +0 -0
  82. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/reconciliation.py +0 -0
  83. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/remote.py +0 -0
  84. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/answer-key.yaml +0 -0
  85. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/.env +0 -0
  86. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/.github/workflows/build.yml +0 -0
  87. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/README.md +0 -0
  88. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/app.py +0 -0
  89. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/openapi.yaml +0 -0
  90. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/requirements.txt +0 -0
  91. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/scripts/build.sh +0 -0
  92. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/templates/payment.html +0 -0
  93. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/benchmarks/vulnlab/target/trivy-results.json +0 -0
  94. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/.gitkeep +0 -0
  95. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/SKILL.md +0 -0
  96. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/references/inventory-template.md +0 -0
  97. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/api-security-review/references/output-template.md +0 -0
  98. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/SKILL.md +0 -0
  99. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/disposition.md +0 -0
  100. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/orchestration.md +0 -0
  101. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/output-template.md +0 -0
  102. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/review-checklist.md +0 -0
  103. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/biso-security-review/references/risk-rating.md +0 -0
  104. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/cicd-security-review/SKILL.md +0 -0
  105. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/cicd-security-review/references/output-template.md +0 -0
  106. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/SKILL.md +0 -0
  107. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/references/control-matrix.md +0 -0
  108. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/pci-architect/references/output-template.md +0 -0
  109. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/SKILL.md +0 -0
  110. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/references/output-template.md +0 -0
  111. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/threat-model/references/risk-rating.md +0 -0
  112. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/SKILL.md +0 -0
  113. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/escalation.md +0 -0
  114. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/output-template.md +0 -0
  115. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/custom/vulnerability-manager/references/prioritization.md +0 -0
  116. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/finding-schema.json +0 -0
  117. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/resources/skills.yaml +0 -0
  118. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/review.py +0 -0
  119. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/review_candidates.py +0 -0
  120. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/risk_acknowledgment.py +0 -0
  121. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/runtime_binding.py +0 -0
  122. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/safety_plan.py +0 -0
  123. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/stagecache.py +0 -0
  124. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/stateio.py +0 -0
  125. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/transactions.py +0 -0
  126. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/trust.py +0 -0
  127. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/tui.py +0 -0
  128. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/tui_interaction.py +0 -0
  129. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/tui_refresh.py +0 -0
  130. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/update_intent_review.py +0 -0
  131. {skillctl_secure-0.30.2 → skillctl_secure-0.30.4}/skillctl/update_intent_tui.py +0 -0
  132. {skillctl_secure-0.30.2 → 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.2
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
@@ -38,6 +38,13 @@ skillctl
38
38
 
39
39
  ## Quick start
40
40
 
41
+ ### Complete setup in one command
42
+
43
+ For a new machine, use the [complete bootstrap instructions](docs/BOOTSTRAP.md).
44
+ The standalone macOS/Linux and Windows scripts install missing Git, uv, and Python,
45
+ install or update skillctl, configure PATH, verify the command, and launch the app.
46
+ OS-required dialogs or sudo prompts may still require interaction.
47
+
41
48
  ### Recommended: install with uv
42
49
 
43
50
  Install [uv](https://docs.astral.sh/uv/getting-started/installation/) once, then:
@@ -14,6 +14,13 @@ skillctl
14
14
 
15
15
  ## Quick start
16
16
 
17
+ ### Complete setup in one command
18
+
19
+ For a new machine, use the [complete bootstrap instructions](docs/BOOTSTRAP.md).
20
+ The standalone macOS/Linux and Windows scripts install missing Git, uv, and Python,
21
+ install or update skillctl, configure PATH, verify the command, and launch the app.
22
+ OS-required dialogs or sudo prompts may still require interaction.
23
+
17
24
  ### Recommended: install with uv
18
25
 
19
26
  Install [uv](https://docs.astral.sh/uv/getting-started/installation/) once, then:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "skillctl-secure"
3
- version = "0.30.2"
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':
@@ -2,7 +2,7 @@
2
2
  from textual.widgets import Tabs, TabbedContent
3
3
 
4
4
  SECTIONS = {
5
- 'home': ('home',),
5
+ 'home': ('home', 'stats'),
6
6
  'skills': ('available', 'inventory', 'installed', 'updates', 'custom'),
7
7
  'risk': ('attack-surface',),
8
8
  'reviews': ('reviews',),
@@ -6,7 +6,7 @@ from . import __version__
6
6
  from textual import work
7
7
  from textual.app import App, ComposeResult, ScreenStackError
8
8
  from textual.binding import Binding
9
- from textual.containers import Horizontal, Vertical
9
+ from textual.containers import Horizontal, Vertical, VerticalScroll
10
10
  from textual.css.query import NoMatches
11
11
  from textual.screen import ModalScreen
12
12
  from textual.widgets import (
@@ -268,21 +268,23 @@ class SkillCtlTUI(App):
268
268
 
269
269
  def compose(self) -> ComposeResult:
270
270
  yield Header()
271
- yield Static("", id="summary", markup=True)
272
271
  with Horizontal(id="navigation"):
273
- 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")
274
273
  yield Input(placeholder="Search… [/]", id="search", tooltip="Search skills, descriptions, categories, and collections. Press / to focus.")
275
274
  with Horizontal(id="body"):
276
275
  with TabbedContent(id="catalog"):
277
- with TabPane("Home", id="home"):
276
+ with TabPane("Overview", id="home"):
278
277
  yield DataTable(id="table-home", cursor_type="row")
279
- with TabPane("Attack Surface & Risk", id="attack-surface"):
278
+ with TabPane("Stats", id="stats"):
279
+ with VerticalScroll():
280
+ yield Static("", id="summary", markup=True)
281
+ with TabPane("Risks", id="attack-surface"):
280
282
  from .attack_surface_tui import AttackSurfacePanel
281
283
  yield AttackSurfacePanel(self.manager, auto_load=False)
282
284
  with TabPane("Available", id="available"):
283
285
  yield DataTable(id="table-available", cursor_type="row")
284
286
  with TabPane("Inventory", id="inventory"):
285
- yield Button("Attack surface & risk", id="btn-attack-surface")
287
+ yield Button("Risks", id="btn-attack-surface")
286
288
  yield Static("Discovering installed skills…", id="inventory-summary", markup=False)
287
289
  yield DataTable(id="table-inventory", cursor_type="row")
288
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
@@ -79,6 +81,13 @@ def install_progressive_startup(SkillCtlTUI, legacy_on_mount) -> None:
79
81
  return
80
82
  from .section_navigation import sync_section
81
83
  sync_section(self, str(pane_id))
84
+ if pane_id == "stats":
85
+ self._close_detail()
86
+ self.selected_kind = "stats"
87
+ self.selected_name = None
88
+ self.armed_update = None
89
+ self._update_skill_action_buttons(None)
90
+ return
82
91
  if pane_id == "attack-surface":
83
92
  from .attack_surface_tui import AttackSurfacePanel
84
93
  self._close_detail()
@@ -1 +0,0 @@
1
- __version__ = "0.30.2"