sneakoscope 7.3.0 → 7.6.0

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 (283) hide show
  1. package/README.md +129 -10
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/cli/codex-app-command.js +1 -1
  5. package/dist/cli/command-manifest-lite.js +4 -1
  6. package/dist/cli/command-registry.js +2 -0
  7. package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
  8. package/dist/cli/install-helpers-codex-lb-config.js +114 -9
  9. package/dist/cli/install-helpers-install-support.js +6 -16
  10. package/dist/cli/install-helpers.js +788 -600
  11. package/dist/cli/router.js +30 -2
  12. package/dist/commands/codex-app.js +37 -1
  13. package/dist/commands/codex-lb.js +491 -300
  14. package/dist/config/skills-manifest.json +57 -71
  15. package/dist/core/align/align-route.js +127 -0
  16. package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
  17. package/dist/core/codex-app/codex-app-restart.js +83 -0
  18. package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
  19. package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
  20. package/dist/core/codex-app/menubar/constants.js +5 -0
  21. package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
  22. package/dist/core/codex-app/menubar/installer.js +18 -0
  23. package/dist/core/codex-app/multi-provider-router.js +22 -10
  24. package/dist/core/codex-app/openrouter-activate.js +26 -1
  25. package/dist/core/codex-app.js +118 -26
  26. package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
  27. package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
  28. package/dist/core/codex-control/codex-task-runner.js +2 -2
  29. package/dist/core/codex-lb/capability-runner.js +204 -0
  30. package/dist/core/codex-lb/capability-types.js +1 -0
  31. package/dist/core/codex-lb/codex-lb-env.js +9 -13
  32. package/dist/core/codex-lb/codex-lb-setup.js +45 -8
  33. package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
  34. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
  35. package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
  36. package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
  37. package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
  38. package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
  39. package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
  40. package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
  41. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
  42. package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
  43. package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
  44. package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
  45. package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
  46. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
  47. package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
  48. package/dist/core/codex-lb/desktop-controller.js +1410 -0
  49. package/dist/core/codex-lb/desktop-mode.js +32 -0
  50. package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
  51. package/dist/core/codex-lb/desktop-service.js +613 -0
  52. package/dist/core/codex-lb/legacy-migration.js +575 -0
  53. package/dist/core/codex-lb/migration-receipt.js +246 -0
  54. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
  55. package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
  56. package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
  57. package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
  58. package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
  59. package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
  60. package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
  61. package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
  62. package/dist/core/codex-native/core-skill-manifest.js +22 -6
  63. package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
  64. package/dist/core/commands/align-command.js +220 -0
  65. package/dist/core/commands/image-ux-review-command.js +280 -68
  66. package/dist/core/commands/naruto-command.js +257 -8
  67. package/dist/core/commands/ppt-command.js +2 -2
  68. package/dist/core/commands/telegram-command.js +402 -34
  69. package/dist/core/commands/triwiki-command.js +11 -1
  70. package/dist/core/commands/triwiki-graph-command.js +160 -0
  71. package/dist/core/commands/wiki-command.js +100 -20
  72. package/dist/core/doctor/skill-legacy-surface.js +1 -3
  73. package/dist/core/errors/message.js +3 -0
  74. package/dist/core/evidence/evidence-freshness.js +14 -0
  75. package/dist/core/feature-fixtures.js +9 -1
  76. package/dist/core/feature-registry.js +5 -3
  77. package/dist/core/fsx.js +7 -3
  78. package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
  79. package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
  80. package/dist/core/hooks-runtime/hook-context.js +15 -2
  81. package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
  82. package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
  83. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
  84. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  85. package/dist/core/hooks-runtime.js +33 -89
  86. package/dist/core/image-ux-review/callout-extraction.js +6 -0
  87. package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
  88. package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
  89. package/dist/core/image-ux-review.js +230 -12
  90. package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
  91. package/dist/core/imagegen/imagegen-capability.js +10 -4
  92. package/dist/core/imagegen/require-imagegen.js +29 -5
  93. package/dist/core/init/skills.js +25 -13
  94. package/dist/core/init.js +1 -1
  95. package/dist/core/install/installed-package-smoke.js +157 -4
  96. package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
  97. package/dist/core/managed-path-safety.js +8 -10
  98. package/dist/core/mcp-config/backup.js +2 -4
  99. package/dist/core/mcp-config/config-reader.js +2 -4
  100. package/dist/core/mcp-config/scope.js +3 -5
  101. package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
  102. package/dist/core/naruto/context-graph-advisor.js +0 -0
  103. package/dist/core/perf/release-latency-slo.js +12 -6
  104. package/dist/core/pipeline-internals/runtime-core.js +78 -0
  105. package/dist/core/pipeline-internals/runtime-gates.js +5 -2
  106. package/dist/core/policy/latest-version-guidance.js +113 -0
  107. package/dist/core/ppt.js +8 -8
  108. package/dist/core/preflight/parallel-preflight-engine.js +1 -1
  109. package/dist/core/proof/auto-finalize.js +98 -6
  110. package/dist/core/proof/route-proof-gate.js +12 -1
  111. package/dist/core/proof/route-proof-policy.js +8 -8
  112. package/dist/core/release/gate-manifest.js +32 -1
  113. package/dist/core/release/npm-stage-contract.js +21 -0
  114. package/dist/core/release/package-size-budget.js +2 -2
  115. package/dist/core/release/release-gate-contract.js +5 -0
  116. package/dist/core/release/release-proof-io.js +1 -3
  117. package/dist/core/release/release-real-contract.js +5 -4
  118. package/dist/core/release/release-stamp-proof.js +1 -3
  119. package/dist/core/release/stage-publish.js +27 -0
  120. package/dist/core/remote/audit-idempotency.js +50 -18
  121. package/dist/core/remote/codex-public-activity.js +283 -0
  122. package/dist/core/remote/index.js +1 -0
  123. package/dist/core/remote/ssh-worker-client.js +4 -1
  124. package/dist/core/remote/worker.js +206 -27
  125. package/dist/core/research/research-adversarial-review.js +1 -3
  126. package/dist/core/research/research-claim-synthesizer.js +1 -3
  127. package/dist/core/research/research-falsification-runner.js +1 -3
  128. package/dist/core/research/research-source-evidence.js +1 -3
  129. package/dist/core/responses-stream.js +65 -19
  130. package/dist/core/routes/constants.js +1 -1
  131. package/dist/core/routes/design-policy.js +7 -2
  132. package/dist/core/routes/dollar-manifest-lite.js +2 -4
  133. package/dist/core/routes/evidence.js +1 -1
  134. package/dist/core/routes.js +30 -10
  135. package/dist/core/safety/command-contract/contracts.js +2 -0
  136. package/dist/core/safety/command-contract/types.js +1 -1
  137. package/dist/core/search/context-graph-seeds.js +205 -0
  138. package/dist/core/search/context.js +0 -0
  139. package/dist/core/search/provider.js +2 -2
  140. package/dist/core/secret-redaction.js +6 -0
  141. package/dist/core/subagents/naruto-help-contract.js +2 -1
  142. package/dist/core/subagents/naruto-host-credentials.js +161 -0
  143. package/dist/core/subagents/official-subagent-preparation.js +4 -1
  144. package/dist/core/subagents/official-subagent-prompt.js +44 -2
  145. package/dist/core/subagents/official-subagent-runner.js +26 -8
  146. package/dist/core/subagents/triwiki-attention.js +135 -123
  147. package/dist/core/telegram/bot-api.js +85 -10
  148. package/dist/core/telegram/center-snapshot.js +718 -0
  149. package/dist/core/telegram/config.js +158 -31
  150. package/dist/core/telegram/hub.js +288 -33
  151. package/dist/core/telegram/index.js +2 -0
  152. package/dist/core/telegram/ingress-spool.js +419 -0
  153. package/dist/core/telegram/ledgers.js +188 -29
  154. package/dist/core/telegram/messages.js +26 -6
  155. package/dist/core/telegram/owner-lock.js +10 -7
  156. package/dist/core/telegram/runtime-projection.js +38 -3
  157. package/dist/core/telegram/runtime.js +298 -63
  158. package/dist/core/telegram/service.js +137 -8
  159. package/dist/core/telegram/setup.js +291 -73
  160. package/dist/core/text/strings.js +3 -0
  161. package/dist/core/triwiki/code-pack.js +12 -120
  162. package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
  163. package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
  164. package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
  165. package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
  166. package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
  167. package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
  168. package/dist/core/triwiki/context-graph/contracts.js +236 -0
  169. package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
  170. package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
  171. package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
  172. package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
  173. package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
  174. package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
  175. package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
  176. package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
  177. package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
  178. package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
  179. package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
  180. package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
  181. package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
  182. package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
  183. package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
  184. package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
  185. package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
  186. package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
  187. package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
  188. package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
  189. package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
  190. package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
  191. package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
  192. package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
  193. package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
  194. package/dist/core/triwiki/context-graph/graph-index.js +143 -0
  195. package/dist/core/triwiki/context-graph/ids.js +0 -0
  196. package/dist/core/triwiki/context-graph/lint/index.js +0 -0
  197. package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
  198. package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
  199. package/dist/core/triwiki/context-graph/paths.js +116 -0
  200. package/dist/core/triwiki/context-graph/profiles.js +78 -0
  201. package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
  202. package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
  203. package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
  204. package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
  205. package/dist/core/triwiki/context-graph/projections/index.js +7 -0
  206. package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
  207. package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
  208. package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
  209. package/dist/core/triwiki/context-graph/query/explain.js +0 -0
  210. package/dist/core/triwiki/context-graph/query/index.js +178 -0
  211. package/dist/core/triwiki/context-graph/query/load.js +116 -0
  212. package/dist/core/triwiki/context-graph/query/pack.js +117 -0
  213. package/dist/core/triwiki/context-graph/query/rank.js +142 -0
  214. package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
  215. package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
  216. package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
  217. package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
  218. package/dist/core/triwiki/context-graph/query-types.js +29 -0
  219. package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
  220. package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
  221. package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
  222. package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
  223. package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
  224. package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
  225. package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
  226. package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
  227. package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
  228. package/dist/core/verification/context-graph-affected.js +271 -0
  229. package/dist/core/version.js +1 -1
  230. package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
  231. package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
  232. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
  233. package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
  234. package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
  235. package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
  236. package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
  237. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
  238. package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
  239. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
  240. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
  241. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
  242. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
  243. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
  244. package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
  245. package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
  246. package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
  247. package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
  248. package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
  249. package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
  250. package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
  251. package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
  252. package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
  253. package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
  254. package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
  255. package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
  256. package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
  257. package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
  258. package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
  259. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
  260. package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
  261. package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
  262. package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
  263. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
  264. package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
  265. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
  266. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
  267. package/dist/scripts/context-graph-check.js +191 -0
  268. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
  269. package/dist/scripts/gate-policy-audit-check.js +1 -1
  270. package/dist/scripts/helper-dedup-check.js +0 -2
  271. package/dist/scripts/installed-package-smoke-check.js +4 -1
  272. package/dist/scripts/latest-version-guidance-check.js +74 -0
  273. package/dist/scripts/release-metadata-check.js +21 -4
  274. package/dist/scripts/release-real-check.js +7 -0
  275. package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
  276. package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
  277. package/package.json +8 -3
  278. package/release-gates.v2.json +176 -1
  279. package/runtime-required-scripts.json +30 -0
  280. package/schemas/triwiki/context-graph.schema.json +119 -0
  281. package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
  282. package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
  283. package/dist/core/triwiki/code-index-scanner.js +0 -309
@@ -74,6 +74,7 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
74
74
  private let scopePopup = NSPopUpButton()
75
75
  private var rows: [McpRow] = []
76
76
  private var mutating = false
77
+ private var refreshGeneration = 0
77
78
  private var editor: McpEditorSheet?
78
79
  private lazy var addButton = actionButton("Add…", #selector(addServer))
79
80
  private lazy var editButton = actionButton("Edit…", #selector(editServer))
@@ -93,10 +94,17 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
93
94
  required init?(coder: NSCoder) { nil }
94
95
 
95
96
  override func loadView() {
96
- for (id, title, width) in [("state", "State", 105.0), ("name", "Name", 170.0), ("transport", "Transport", 120.0), ("configuration", "Configuration", 260.0)] {
97
- let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(id)); column.title = title; column.width = width
97
+ for (id, title, width, minimum) in [
98
+ ("state", "State", 90.0, 72.0),
99
+ ("name", "Name", 150.0, 110.0),
100
+ ("transport", "Transport", 110.0, 86.0),
101
+ ("configuration", "Configuration", 230.0, 150.0)
102
+ ] {
103
+ let column = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(id))
104
+ column.title = title; column.width = width; column.minWidth = minimum
98
105
  table.addTableColumn(column)
99
106
  }
107
+ table.columnAutoresizingStyle = .lastColumnOnlyAutoresizingStyle
100
108
  table.dataSource = self; table.delegate = self; table.usesAlternatingRowBackgroundColors = true
101
109
  table.allowsMultipleSelection = false; table.setAccessibilityLabel("Effective MCP servers")
102
110
  let scroll = NSScrollView(); scroll.documentView = table; scroll.hasVerticalScroller = true; scroll.hasHorizontalScroller = true
@@ -107,18 +115,24 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
107
115
  scopeRow.orientation = .horizontal; scopeRow.spacing = 8
108
116
  // Destructive Remove sits apart from routine edit actions; connection
109
117
  // and maintenance actions live on their own labeled row.
110
- let primary = ControlKit.actionRow([addButton, editButton, duplicateButton, toggleButton], trailing: [removeButton])
118
+ let primary = ControlKit.actionRow([addButton, editButton, duplicateButton])
119
+ let stateActions = ControlKit.actionRow([toggleButton], trailing: [removeButton])
111
120
  let manageLabel = NSTextField(labelWithString: "Manage"); manageLabel.textColor = .secondaryLabelColor
112
121
  let connectLabel = NSTextField(labelWithString: "Connection"); connectLabel.textColor = .secondaryLabelColor
113
122
  for label in [manageLabel, connectLabel] { label.font = NSFont.systemFont(ofSize: 11, weight: .medium) }
114
- let secondary = NSStackView(views: [testButton, oauthButton, legacySecretButton, backupsButton, refreshButton])
115
- secondary.orientation = .horizontal; secondary.spacing = 8
116
- view = NativeView.stack([
117
- NativeView.title("MCP Servers"),
118
- NativeView.detail("Inspect global, trusted-project, or effective configuration. Effective and plugin entries are read-only until an exact writable scope is selected. New authentication uses OAuth or environment-variable names only."),
119
- scopeRow, scroll, status, manageLabel, primary, connectLabel, secondary
123
+ let secondary = ControlKit.actionRow([testButton, oauthButton, legacySecretButton])
124
+ let maintenance = ControlKit.actionRow([backupsButton, refreshButton])
125
+ let inventoryCard = NativeView.card(
126
+ title: "Server inventory",
127
+ subtitle: "Select one row before using edit, connection, authentication, or removal actions.",
128
+ views: [scroll, status, manageLabel, primary, stateActions, connectLabel, secondary, maintenance]
129
+ )
130
+ view = NativeView.page([
131
+ ControlKit.header("MCP Servers", "Inspect global, trusted-project, or effective configuration. Effective and plugin entries are read-only until an exact writable scope is selected. New authentication uses OAuth or environment-variable names only."),
132
+ scopeRow,
133
+ inventoryCard
120
134
  ])
121
- updateButtons(); refresh()
135
+ updateButtons()
122
136
  }
123
137
 
124
138
  func numberOfRows(in tableView: NSTableView) -> Int { rows.count }
@@ -143,9 +157,14 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
143
157
  @objc private func scopeChanged() { refresh() }
144
158
 
145
159
  @objc private func refresh() {
146
- let scope = selectedScope(); status.stringValue = "Loading \(scope) MCP configuration…"
160
+ guard !mutating else { return }
161
+ refreshGeneration += 1
162
+ let requestGeneration = refreshGeneration
163
+ let scope = selectedScope()
164
+ status.stringValue = "Loading \(scope) MCP configuration…"
165
+ refreshButton.isEnabled = false
147
166
  processClient.run(["mcp", "config", "list", "--scope", scope] + scopeContext(scope, mutation: false) + ["--json"], timeout: NativeView.statusTimeout) { [weak self] result in
148
- guard let self = self else { return }
167
+ guard let self = self, self.refreshGeneration == requestGeneration else { return }
149
168
  guard let json = self.json(result.output), let servers = json["servers"] as? [[String: Any]] else {
150
169
  self.rows = []; self.table.reloadData(); self.status.stringValue = "MCP inventory unavailable. No configuration was changed."
151
170
  self.updateButtons(); return
@@ -155,7 +174,9 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
155
174
  let enabled = json["enabled_count"] as? Int ?? self.rows.filter(\.enabled).count
156
175
  let failed = json["failed_count"] as? Int ?? 0
157
176
  let warnings = (json["warnings"] as? [String] ?? []).filter { !$0.hasPrefix("public_error:") }
158
- self.status.stringValue = "\(self.rows.count) servers · \(enabled) enabled · \(failed) need attention" + (warnings.isEmpty ? "" : " · \(warnings.count) advisory")
177
+ self.status.stringValue = self.rows.isEmpty
178
+ ? "No MCP servers are configured in the \(scope) scope."
179
+ : "\(self.rows.count) servers · \(enabled) enabled · \(failed) need attention" + (warnings.isEmpty ? "" : " · \(warnings.count) advisory")
159
180
  self.updateButtons()
160
181
  }
161
182
  }
@@ -296,6 +317,7 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
296
317
 
297
318
  private func mutate(_ args: [String], stdin: String? = nil) {
298
319
  guard !mutating, let operation = operations.begin(kind: "mcp-config", mutationGroup: "mcp", summary: "MCP configuration change") else { status.stringValue = "An update or MCP mutation is already running."; return }
320
+ refreshGeneration += 1
299
321
  mutating = true; updateButtons(); _ = operations.update(operation, state: .running, stage: "apply", progress: nil, summary: "Applying scoped MCP change")
300
322
  processClient.run(args, stdin: stdin, timeout: NativeView.mutationTimeout) { [weak self] result in
301
323
  guard let self = self else { return }
@@ -326,6 +348,11 @@ final class MCPServersViewController: NSViewController, NSTableViewDataSource, N
326
348
  private func actionButton(_ title: String, _ action: Selector) -> NSButton { NativeView.button(title, target: self, action: action) }
327
349
  private func updateButtons() {
328
350
  let row = selected()?.row; let writable = selectedWritableRow() != nil
351
+ toggleButton.title = row?.enabled == true ? "Disable Selected" : "Enable Selected"
352
+ removeButton.title = "Remove Selected"
353
+ testButton.title = "Test Selected"
354
+ oauthButton.title = row?.authenticated == true ? "Sign Out OAuth" : "Sign In with OAuth"
355
+ legacySecretButton.title = "Review Legacy Secret…"
329
356
  addButton.isEnabled = !mutating; refreshButton.isEnabled = !mutating; scopePopup.isEnabled = !mutating
330
357
  for button in [editButton, duplicateButton, toggleButton, removeButton] { button.isEnabled = !mutating && writable }
331
358
  testButton.isEnabled = !mutating && row != nil && row?.managedBy != "plugin"
@@ -391,12 +418,13 @@ private final class McpEditorSheet: NSObject {
391
418
  pair("Default approval mode", approval), pair("Environment", remote), pair("Requirement", required)
392
419
  ])
393
420
  grid.rowSpacing = 6; grid.columnSpacing = 12; grid.column(at: 0).xPlacement = .trailing; grid.column(at: 1).xPlacement = .fill
394
- grid.column(at: 1).width = 420
421
+ grid.column(at: 1).width = 300
395
422
  let cancel = NSButton(title: "Cancel", target: self, action: #selector(cancelSheet)); let buttons = NSStackView(views: [cancel, apply])
396
423
  buttons.orientation = .horizontal; buttons.spacing = 8
397
- let stack = NativeView.stack([NativeView.detail("Connection values are used only for the selected transport. Edit fields may be left blank to preserve existing connection data."), grid, review, buttons])
398
- stack.translatesAutoresizingMaskIntoConstraints = false; panel.contentView = NSView(); panel.contentView?.addSubview(stack)
399
- NSLayoutConstraint.activate([stack.leadingAnchor.constraint(equalTo: panel.contentView!.leadingAnchor), stack.trailingAnchor.constraint(equalTo: panel.contentView!.trailingAnchor), stack.topAnchor.constraint(equalTo: panel.contentView!.topAnchor), stack.bottomAnchor.constraint(equalTo: panel.contentView!.bottomAnchor)])
424
+ let stack = NativeView.page([NativeView.detail("Connection values are used only for the selected transport. Edit fields may be left blank to preserve existing connection data."), grid, review, buttons])
425
+ let scroll = NativeView.scrollable(stack)
426
+ panel.contentView = NSView(); panel.contentView?.addSubview(scroll)
427
+ NSLayoutConstraint.activate([scroll.leadingAnchor.constraint(equalTo: panel.contentView!.leadingAnchor), scroll.trailingAnchor.constraint(equalTo: panel.contentView!.trailingAnchor), scroll.topAnchor.constraint(equalTo: panel.contentView!.topAnchor), scroll.bottomAnchor.constraint(equalTo: panel.contentView!.bottomAnchor)])
400
428
  }
401
429
 
402
430
  @objc private func transportChanged() { let local = transport.indexOfSelectedItem == 0; command.isEnabled = local; args.isEditable = local; cwd.isEnabled = local; env.isEditable = local; remote.isEnabled = local; url.isEnabled = !local; bearer.isEnabled = !local; reviewed = nil; apply.title = "Review" }
@@ -0,0 +1,162 @@
1
+ import Foundation
2
+
3
+ enum OverviewSummary {
4
+ static func render(
5
+ update: [String: Any]?,
6
+ mcp: [String: Any]?,
7
+ telegram: [String: Any]?,
8
+ menuBarBuild: String,
9
+ codexRunning: Bool?,
10
+ operationSummary: String
11
+ ) -> String {
12
+ let codexAppState = codexRunning.map { $0 ? "Running" : "Not running" } ?? "Not configured"
13
+ var lines: [String] = []
14
+ let update = validatedUpdate(update)
15
+ let mcp = validatedMCP(mcp)
16
+ let telegram = validatedTelegram(telegram)
17
+
18
+ if let update = update {
19
+ let sks = update["sks"] as? [String: Any]
20
+ let codex = update["codex_cli"] as? [String: Any]
21
+ let menu = update["menubar"] as? [String: Any]
22
+ lines.append("SKS install: \(versionSummary(sks))")
23
+ lines.append("Codex CLI: \(versionSummary(codex)) · Codex app: \(codexAppState)")
24
+ if let inducement = codexUpdateInducement(codex) {
25
+ lines.append(inducement)
26
+ }
27
+
28
+ var menuParts = ["running build \(menuBarBuild)"]
29
+ if let expected = menu?["expected_version"] as? String { menuParts.append("expected \(expected)") }
30
+ if let installed = menu?["installed_version"] as? String, installed != menuBarBuild {
31
+ menuParts.append("snapshot installed \(installed)")
32
+ }
33
+ if let rebuildRequired = menu?["rebuild_required"] as? Bool {
34
+ menuParts.append(rebuildRequired ? "rebuild required" : "current")
35
+ } else {
36
+ menuParts.append("rebuild state unknown")
37
+ }
38
+ menuParts.append("signature \(verificationState(menu?["signature_ok"]))")
39
+ menuParts.append("resources \(verificationState(menu?["resources_ok"]))")
40
+ lines.append("Menu Bar: \(menuParts.joined(separator: " · "))")
41
+
42
+ let source = snapshotSource(update["source"] as? String)
43
+ var updateParts = [integer(update["update_count"]).map { "\($0) pending" } ?? "pending count unknown", "\(source) snapshot"]
44
+ if let error = diagnosticNotice(update["public_error"] as? String, update: update) {
45
+ updateParts.append("notice: \(error)")
46
+ } else if let warnings = update["warnings"] as? [String], !warnings.isEmpty {
47
+ updateParts.append("\(warnings.count) warning\(warnings.count == 1 ? "" : "s")")
48
+ }
49
+ lines.append("Updates: \(updateParts.joined(separator: " · "))")
50
+ } else {
51
+ lines.append("SKS install: unavailable")
52
+ lines.append("Codex CLI: unavailable · Codex app: \(codexAppState)")
53
+ lines.append("Menu Bar: running build \(menuBarBuild) · update status unavailable")
54
+ lines.append("Updates: unavailable")
55
+ }
56
+
57
+ if let mcp = mcp,
58
+ let enabled = integer(mcp["enabled_count"]),
59
+ let failed = integer(mcp["failed_count"]) {
60
+ lines.append("MCP: \(enabled) enabled · \(failed) failed")
61
+ } else {
62
+ lines.append("MCP: unavailable")
63
+ }
64
+
65
+ if let telegram = telegram {
66
+ let owner = telegram["owner"] as? [String: Any]
67
+ let configured = telegram["configured"] as? Bool
68
+ let hubState = owner != nil ? "Running" : configured == true ? "Stopped" : configured == false ? "Not configured" : "Unknown"
69
+ let machines = integer(telegram["machine_count"]).map { "\($0) registered Macs" } ?? "registered Macs unknown"
70
+ let targets = integer(telegram["target_count"]).map { "\($0) configured targets" } ?? "configured targets unknown"
71
+ let issues = ((telegram["config_issues"] as? [String]) ?? []).count
72
+ + ((telegram["remote_config_issues"] as? [String]) ?? []).count
73
+ var fleet = "Remote fleet: \(machines) · \(targets)"
74
+ if issues > 0 { fleet += " · \(issues) issue\(issues == 1 ? "" : "s")" }
75
+ lines.append("Telegram Hub: \(hubState) · \(fleet)")
76
+ } else {
77
+ lines.append("Telegram Hub: unavailable · Remote fleet: unavailable")
78
+ }
79
+
80
+ lines.append("Last operation: \(operationSummary) · Logs and snapshots use mode 0600")
81
+ return lines.joined(separator: "\n")
82
+ }
83
+
84
+ private static func validatedUpdate(_ value: [String: Any]?) -> [String: Any]? {
85
+ guard value?["schema"] as? String == "sks.update-status.v3",
86
+ value?["source"] is String,
87
+ integer(value?["update_count"]) != nil,
88
+ let sks = value?["sks"] as? [String: Any],
89
+ let codex = value?["codex_cli"] as? [String: Any],
90
+ let menu = value?["menubar"] as? [String: Any],
91
+ sks["update_available"] is Bool,
92
+ codex["update_available"] is Bool,
93
+ menu["expected_version"] is String,
94
+ menu["rebuild_required"] is Bool else { return nil }
95
+ return value
96
+ }
97
+
98
+ private static func validatedMCP(_ value: [String: Any]?) -> [String: Any]? {
99
+ guard value?["schema"] as? String == "sks.mcp-inventory.v2",
100
+ integer(value?["enabled_count"]) != nil,
101
+ integer(value?["failed_count"]) != nil else { return nil }
102
+ return value
103
+ }
104
+
105
+ private static func validatedTelegram(_ value: [String: Any]?) -> [String: Any]? {
106
+ guard value?["schema"] as? String == "sks.telegram-status.v1",
107
+ value?["configured"] is Bool,
108
+ integer(value?["machine_count"]) != nil,
109
+ integer(value?["target_count"]) != nil,
110
+ value?["config_issues"] is [String],
111
+ value?["remote_config_issues"] is [String] else { return nil }
112
+ return value
113
+ }
114
+
115
+ private static func versionSummary(_ value: [String: Any]?) -> String {
116
+ guard let current = nonEmpty(value?["current"] as? String) else { return "not detected" }
117
+ guard let latest = nonEmpty(value?["latest"] as? String) else { return current }
118
+ if value?["update_available"] as? Bool == true, latest != current { return "\(current) → \(latest) available" }
119
+ if latest == current { return "\(current) (current)" }
120
+ return "\(current) · registry last seen \(latest)"
121
+ }
122
+
123
+ private static func codexUpdateInducement(_ value: [String: Any]?) -> String? {
124
+ guard value?["update_available"] as? Bool == true else { return nil }
125
+ let current = nonEmpty(value?["current"] as? String) ?? "installed"
126
+ let latest = nonEmpty(value?["latest"] as? String) ?? "preferred latest"
127
+ return "Action: update Codex CLI (\(current) → \(latest)) from Updates, or choose Update Codex CLI Now in the menu bar."
128
+ }
129
+
130
+ private static func verificationState(_ value: Any?) -> String {
131
+ guard let value = value as? Bool else { return "unknown" }
132
+ return value ? "verified" : "needs attention"
133
+ }
134
+
135
+ private static func snapshotSource(_ value: String?) -> String {
136
+ guard let value = nonEmpty(value) else { return "unknown" }
137
+ return value.replacingOccurrences(of: "_", with: " ")
138
+ }
139
+
140
+ private static func diagnosticNotice(_ value: String?, update: [String: Any]) -> String? {
141
+ guard let value = nonEmpty(value) else { return nil }
142
+ let versions = [
143
+ (update["sks"] as? [String: Any])?["current"] as? String,
144
+ (update["sks"] as? [String: Any])?["latest"] as? String,
145
+ (update["codex_cli"] as? [String: Any])?["current"] as? String,
146
+ (update["codex_cli"] as? [String: Any])?["latest"] as? String
147
+ ].compactMap { $0 }
148
+ if versions.contains(value) { return nil }
149
+ if value.range(of: #"^v?\d+(?:\.\d+){1,3}(?:[-+][A-Za-z0-9.-]+)?$"#, options: .regularExpression) != nil { return nil }
150
+ return value
151
+ }
152
+
153
+ private static func integer(_ value: Any?) -> Int? {
154
+ if let value = value as? Int { return value }
155
+ return (value as? NSNumber)?.intValue
156
+ }
157
+
158
+ private static func nonEmpty(_ value: String?) -> String? {
159
+ guard let value = value?.trimmingCharacters(in: .whitespacesAndNewlines), !value.isEmpty else { return nil }
160
+ return value
161
+ }
162
+ }