sneakoscope 8.0.2 → 8.0.4

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 (376) hide show
  1. package/README.md +150 -37
  2. package/config/skills-hash-ledger.v1.json +1 -1
  3. package/crates/sks-core/Cargo.lock +1 -1
  4. package/crates/sks-core/Cargo.toml +1 -1
  5. package/dist/bin/fast-inline.js +55 -27
  6. package/dist/bin/install.js +6 -32
  7. package/dist/bin/sks-dispatch.js +1 -1
  8. package/dist/cli/args.js +0 -2
  9. package/dist/cli/cli-theme.js +18 -9
  10. package/dist/cli/command-manifest-lite.js +6 -6
  11. package/dist/cli/command-registry.js +6 -6
  12. package/dist/cli/feature-commands.js +9 -7
  13. package/dist/cli/install-helpers-codex-lb-chain.js +198 -7
  14. package/dist/cli/install-helpers-codex-lb-config.js +78 -10
  15. package/dist/cli/install-helpers-install-support.js +9 -6
  16. package/dist/cli/install-helpers.js +101 -49
  17. package/dist/cli/install-tool-helpers.js +2 -82
  18. package/dist/cli/output.js +6 -1
  19. package/dist/cli/router.js +101 -2
  20. package/dist/commands/codex-lb.js +119 -19
  21. package/dist/commands/doctor-profile.js +1 -1
  22. package/dist/commands/doctor.js +727 -144
  23. package/dist/commands/mad-sks.js +1 -5
  24. package/dist/config/skills-manifest.json +4 -2
  25. package/dist/core/agents/agent-codex-cockpit.js +0 -3
  26. package/dist/core/agents/agent-effort-policy.js +5 -5
  27. package/dist/core/agents/agent-janitor.js +0 -20
  28. package/dist/core/agents/agent-orchestrator.js +9 -56
  29. package/dist/core/agents/agent-output-validator.js +2 -3
  30. package/dist/core/agents/agent-patch-schema.js +2 -2
  31. package/dist/core/agents/agent-proof-evidence.js +0 -65
  32. package/dist/core/agents/agent-recursion-guard.js +1 -1
  33. package/dist/core/agents/agent-runner-codex-exec.js +5 -3
  34. package/dist/core/agents/agent-scheduler.js +327 -85
  35. package/dist/core/agents/agent-schema.js +1 -1
  36. package/dist/core/agents/agent-trust-report.js +0 -36
  37. package/dist/core/agents/agent-worker-pipeline.js +0 -1
  38. package/dist/core/agents/fast-mode-policy.js +1 -3
  39. package/dist/core/agents/native-cli-worker-runtime-proof.js +1 -1
  40. package/dist/core/agents/native-cli-worker-runtime.js +69 -647
  41. package/dist/core/agents/native-cli-worker.js +6 -7
  42. package/dist/core/agents/native-worker-backend-router.js +2 -32
  43. package/dist/core/agents/no-subagent-scaling-policy.js +1 -1
  44. package/dist/core/agents/parallel-runtime-proof.js +1 -6
  45. package/dist/core/agents/runtime-proof-summary.js +1 -35
  46. package/dist/core/architecture-hardening/contracts/contracts.js +193 -0
  47. package/dist/core/architecture-hardening/migration/migration.js +111 -0
  48. package/dist/core/architecture-hardening/state/state-service.js +155 -0
  49. package/dist/core/artifact-schemas.js +0 -3
  50. package/dist/core/codex/codex-config-guard.js +238 -52
  51. package/dist/core/codex-adapter.js +5 -3
  52. package/dist/core/codex-app/auxiliary-oauth-policy.js +36 -0
  53. package/dist/core/codex-app/catalog-compat/catalog-service.js +104 -0
  54. package/dist/core/codex-app/child-policy/child-policy.js +35 -0
  55. package/dist/core/codex-app/codex-app-handoff.js +0 -1
  56. package/dist/core/codex-app/codex-hook-lifecycle.js +1 -1
  57. package/dist/core/codex-app/codex-init-deep.js +1 -1
  58. package/dist/core/codex-app/menubar/app-bundle.js +2 -0
  59. package/dist/core/codex-app/menubar/constants.js +14 -1
  60. package/dist/core/codex-app/menubar/global-install.js +288 -0
  61. package/dist/core/codex-app/menubar/installer.js +79 -14
  62. package/dist/core/codex-app/menubar/launch-agent.js +267 -45
  63. package/dist/core/codex-app/menubar/paths.js +3 -0
  64. package/dist/core/codex-app/menubar/rollback.js +55 -7
  65. package/dist/core/codex-app/menubar/status.js +75 -4
  66. package/dist/core/codex-app/provider-child-policy.js +64 -0
  67. package/dist/core/codex-app/provider-mode.js +91 -0
  68. package/dist/core/codex-app/provider-operation-stages.js +20 -0
  69. package/dist/core/codex-app/provider-session-policy.js +85 -0
  70. package/dist/core/codex-app/session-policy/session-pinning.js +68 -0
  71. package/dist/core/codex-app.js +3 -2
  72. package/dist/core/codex-control/codex-0139-image-path-real-probe.js +3 -1
  73. package/dist/core/codex-control/codex-0139-web-search-probe.js +3 -1
  74. package/dist/core/codex-control/codex-app-server-runtime-env.js +13 -4
  75. package/dist/core/codex-control/codex-app-server-v2-client.js +3 -3
  76. package/dist/core/codex-control/codex-control-proof.js +0 -1
  77. package/dist/core/codex-control/codex-task-runner.js +1 -4
  78. package/dist/core/codex-exec-output-schema.js +4 -1
  79. package/dist/core/codex-lb/codex-lb-env.js +63 -72
  80. package/dist/core/codex-lb/codex-lb-setup.js +15 -2
  81. package/dist/core/codex-lb/desktop-bridge/header-policy.js +6 -0
  82. package/dist/core/codex-lb/desktop-bridge/http-forward.js +48 -6
  83. package/dist/core/codex-lb/desktop-bridge/security.js +134 -0
  84. package/dist/core/codex-lb/desktop-bridge/server.js +9 -3
  85. package/dist/core/codex-lb/desktop-bridge/state.js +26 -6
  86. package/dist/core/codex-lb/desktop-bridge/types.js +1 -0
  87. package/dist/core/codex-lb/desktop-center-credentials.js +517 -58
  88. package/dist/core/codex-lb/desktop-controller.js +177 -56
  89. package/dist/core/codex-lb/desktop-service.js +179 -40
  90. package/dist/core/codex-lb/legacy-migration.js +1 -3
  91. package/dist/core/codex-lb/native-openai-transport/transport.js +68 -0
  92. package/dist/core/codex-lb/probes/cli-image-tool-probe.js +1 -1
  93. package/dist/core/codex-lb/provider-routing/provider-router.js +58 -0
  94. package/dist/core/codex-lb/routing-truth.js +327 -0
  95. package/dist/core/codex-native/codex-native-feature-broker.js +4 -0
  96. package/dist/core/codex-native/codex-native-pattern-analysis.js +1 -2
  97. package/dist/core/codex-native/core-skill-manifest.js +1 -1
  98. package/dist/core/codex-plugins/codex-plugin-json.js +26 -6
  99. package/dist/core/codex-plugins/codex-plugin-repair.js +32 -6
  100. package/dist/core/commands/basic-cli.js +9 -7
  101. package/dist/core/commands/computer-use-command.js +1 -1
  102. package/dist/core/commands/image-ux-review-command.js +16 -9
  103. package/dist/core/commands/install-package-command.js +105 -0
  104. package/dist/core/commands/intent-normalization/normalizer.js +96 -0
  105. package/dist/core/commands/mad-sks-command.js +23 -274
  106. package/dist/core/commands/mad-sks-headless.js +11 -30
  107. package/dist/core/commands/naruto-command.js +0 -25
  108. package/dist/core/commands/qa-loop-command.js +104 -22
  109. package/dist/core/commands/remote-command.js +2 -2
  110. package/dist/core/commands/research-command.js +10 -5
  111. package/dist/core/commands/telegram-command.js +407 -0
  112. package/dist/core/config-adopt/config-adopt-command.js +35 -0
  113. package/dist/core/config-adopt/config-adopt.js +346 -0
  114. package/dist/core/config-adopt/index.js +3 -0
  115. package/dist/core/doctor/command-alias-cleanup.js +4 -1
  116. package/dist/core/doctor/current-project-guidance-nested.js +37 -6
  117. package/dist/core/doctor/current-project-guidance.js +15 -9
  118. package/dist/core/doctor/doctor-dirty-planner.js +1 -4
  119. package/dist/core/doctor/doctor-readiness-matrix.js +15 -18
  120. package/dist/core/doctor/retired-managed-residue-private.js +4 -3
  121. package/dist/core/doctor/retired-managed-residue-runtime.js +2 -2
  122. package/dist/core/doctor/skill-legacy-surface.js +11 -10
  123. package/dist/core/doctor/sks-menubar-doctor.js +4 -0
  124. package/dist/core/evaluation.js +0 -19
  125. package/dist/core/evidence/v2/evidence-key.js +105 -0
  126. package/dist/core/feature-fixtures.js +12 -7
  127. package/dist/core/feature-registry.js +52 -21
  128. package/dist/core/hooks-runtime/hook-context.js +9 -0
  129. package/dist/core/hooks-runtime/managed-skill-admission.js +54 -4
  130. package/dist/core/hooks-runtime/official-subagent-lifecycle.js +69 -52
  131. package/dist/core/hooks-runtime/stop-finalization.js +226 -0
  132. package/dist/core/hooks-runtime/stop-repeat-guard.js +21 -2
  133. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +2 -2
  134. package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +3 -3
  135. package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +43 -5
  136. package/dist/core/hooks-runtime/subagent-skill-availability.js +64 -30
  137. package/dist/core/hooks-runtime/subagent-stop-hook.js +15 -2
  138. package/dist/core/hooks-runtime.js +179 -212
  139. package/dist/core/image/reference-evidence/reference-registry.js +145 -0
  140. package/dist/core/image-ux-review/imagegen-adapter.js +21 -9
  141. package/dist/core/image-ux-review/reference-policy/reference-policy.js +9 -0
  142. package/dist/core/imagegen/codex-lb-imagegen-target.js +8 -0
  143. package/dist/core/imagegen/imagegen-capability.js +59 -2
  144. package/dist/core/imagegen/require-imagegen.js +2 -2
  145. package/dist/core/init/skills.js +17 -3
  146. package/dist/core/init.js +3 -3
  147. package/dist/core/install/installed-package-smoke.js +23 -5
  148. package/dist/core/json/canonical.js +9 -0
  149. package/dist/core/locks/file-lock.js +0 -1
  150. package/dist/core/loops/loop-continuation-enforcer.js +65 -7
  151. package/dist/core/loops/loop-decomposer.js +0 -1
  152. package/dist/core/loops/loop-gate-runner.js +65 -4
  153. package/dist/core/loops/loop-gate-selector.js +0 -2
  154. package/dist/core/loops/loop-proof-validation.js +38 -0
  155. package/dist/core/loops/loop-risk-classifier.js +1 -1
  156. package/dist/core/loops/loop-runtime.js +14 -2
  157. package/dist/core/loops/loop-scheduler.js +7 -2
  158. package/dist/core/loops/loop-worker-runtime.js +0 -15
  159. package/dist/core/loops/loop-worktree-runtime.js +52 -4
  160. package/dist/core/managed-assets/managed-assets-manifest.js +14 -14
  161. package/dist/core/naruto/hardware-capacity-probe.js +9 -6
  162. package/dist/core/naruto/naruto-active-pool.js +2 -14
  163. package/dist/core/naruto/naruto-concurrency-governor.js +71 -31
  164. package/dist/core/naruto/naruto-loop-worker-router.js +0 -2
  165. package/dist/core/naruto/naruto-verification-dag.js +0 -1
  166. package/dist/core/naruto/naruto-write-e2e.js +1 -2
  167. package/dist/core/naruto/resource-pressure-monitor.js +0 -4
  168. package/dist/core/observability/architecture-hardening/safe-projection.js +65 -0
  169. package/dist/core/perf/import-graph-budget.js +0 -1
  170. package/dist/core/perf/release-latency-slo.js +3 -2
  171. package/dist/core/preflight/parallel-preflight-engine.js +2 -15
  172. package/dist/core/product-design-app-server.js +13 -1
  173. package/dist/core/proof/fake-real-proof-policy.js +2 -17
  174. package/dist/core/proof/route-proof-gate.js +2 -10
  175. package/dist/core/proof/route-proof-policy.js +1 -1
  176. package/dist/core/proof/runtime-evidence-policy.js +185 -0
  177. package/dist/core/proof/runtime-truth-matrix.js +64 -39
  178. package/dist/core/proof/validation.js +27 -11
  179. package/dist/core/provider/provider-context.js +18 -2
  180. package/dist/core/providers/openrouter/openrouter-account.js +3 -2
  181. package/dist/core/python-tools/python-tool-runner.js +1 -1
  182. package/dist/core/qa-loop/qa-execution-control.js +57 -0
  183. package/dist/core/questions.js +1 -1
  184. package/dist/core/release/extreme-parallel-scheduler.js +0 -3
  185. package/dist/core/release/gate-manifest.js +3 -7
  186. package/dist/core/release/gate-pack-manifest.js +3 -7
  187. package/dist/core/release/package-size-budget.js +2 -2
  188. package/dist/core/release/physical-release-gates.js +189 -0
  189. package/dist/core/release/publish-preflight.js +113 -0
  190. package/dist/core/release/release-gate-affected-selector.js +0 -2
  191. package/dist/core/release/release-gate-batch-runner.js +1 -1
  192. package/dist/core/release/release-gate-node.js +0 -1
  193. package/dist/core/release/release-gate-resource-governor.js +0 -1
  194. package/dist/core/release/release-pack-receipt.js +5 -8
  195. package/dist/core/release/release-real-contract.js +0 -6
  196. package/dist/core/release/resource-class-budget.js +0 -1
  197. package/dist/core/release/stage-publish.js +178 -36
  198. package/dist/core/research/research-adversarial-review.js +103 -9
  199. package/dist/core/research.js +1 -1
  200. package/dist/core/retention.js +0 -1
  201. package/dist/core/routes/constants.js +1 -1
  202. package/dist/core/routes/diagnostic-allowlist.js +0 -1
  203. package/dist/core/routes/dollar-manifest-lite.js +1 -1
  204. package/dist/core/routes.js +46 -15
  205. package/dist/core/runtime/execution-control.js +226 -0
  206. package/dist/core/runtime/progress-recovery/progress-recovery.js +89 -0
  207. package/dist/core/runtime/task-profile.js +10 -4
  208. package/dist/core/runtime/verification-budget.js +10 -1
  209. package/dist/core/safety/intent-contract/intent-contract.js +94 -0
  210. package/dist/core/safety/mutation-guard.js +0 -2
  211. package/dist/core/safety/mutation-ledger.js +0 -2
  212. package/dist/core/safety/requested-scope-contract.js +0 -0
  213. package/dist/core/search-visibility/discovery.js +1 -1
  214. package/dist/core/search-visibility/index.js +12 -0
  215. package/dist/core/search-visibility/verifier.js +112 -3
  216. package/dist/core/security/private-credential-file.js +209 -0
  217. package/dist/core/session/project-namespace.js +0 -5
  218. package/dist/core/skills/skill-agent-metadata.js +1 -3
  219. package/dist/core/strategy/adhd-orchestrating-gate.js +0 -1
  220. package/dist/core/subagents/agent-catalog.js +19 -34
  221. package/dist/core/subagents/model-policy.js +65 -24
  222. package/dist/core/subagents/naruto-help-contract.js +8 -8
  223. package/dist/core/subagents/naruto-host-credentials.js +13 -0
  224. package/dist/core/subagents/official-subagent-config.js +16 -6
  225. package/dist/core/subagents/official-subagent-preparation.js +35 -16
  226. package/dist/core/subagents/official-subagent-prompt.js +7 -7
  227. package/dist/core/subagents/official-subagent-runner.js +27 -4
  228. package/dist/core/subagents/role-model-preferences.js +1 -1
  229. package/dist/core/subagents/thread-budget.js +19 -12
  230. package/dist/core/subagents/wave-lifecycle.js +18 -6
  231. package/dist/core/telegram/access.js +58 -0
  232. package/dist/core/telegram/client.js +157 -0
  233. package/dist/core/telegram/confirmation.js +37 -0
  234. package/dist/core/telegram/doctor.js +154 -0
  235. package/dist/core/telegram/index.js +9 -0
  236. package/dist/core/telegram/keychain.js +317 -0
  237. package/dist/core/telegram/liveness.js +118 -0
  238. package/dist/core/telegram/poller.js +90 -0
  239. package/dist/core/telegram/redaction.js +15 -0
  240. package/dist/core/telegram/state-lock.js +416 -0
  241. package/dist/core/telegram/types.js +1 -0
  242. package/dist/core/text/strings.js +3 -0
  243. package/dist/core/triwiki/context-graph/store/evidence-write-lock.js +29 -0
  244. package/dist/core/triwiki/context-graph/store/fragment-cache.js +24 -0
  245. package/dist/core/triwiki/context-graph/store/snapshot-store.js +69 -21
  246. package/dist/core/triwiki/triwiki-gate-impact-map.js +2 -2
  247. package/dist/core/triwiki/triwiki-module-card.js +1 -2
  248. package/dist/core/update/installed-cli-resolution.js +170 -0
  249. package/dist/core/update/update-diagnostics.js +52 -0
  250. package/dist/core/update/update-migration-state.js +30 -12
  251. package/dist/core/update/update-operation.js +2 -1
  252. package/dist/core/update/update-stage-diagnostics.js +38 -0
  253. package/dist/core/update/update-status.js +2 -9
  254. package/dist/core/update-check.js +279 -91
  255. package/dist/core/version.js +1 -1
  256. package/dist/native/sks-menubar/Sources/AppDelegate.swift +19 -1
  257. package/dist/native/sks-menubar/Sources/AppIdentity.swift +7 -0
  258. package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +6 -2
  259. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +159 -92
  260. package/dist/native/sks-menubar/Sources/OperationModels.swift +389 -0
  261. package/dist/native/sks-menubar/Sources/OverviewViewController.swift +57 -0
  262. package/dist/native/sks-menubar/Sources/ProcessClient.swift +3 -1
  263. package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +115 -0
  264. package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +17 -0
  265. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +3 -0
  266. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +58 -17
  267. package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +302 -0
  268. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +5 -0
  269. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +190 -0
  270. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +158 -126
  271. package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +462 -26
  272. package/dist/native/sks-menubar/Sources/SKSKeychainStore.swift +344 -0
  273. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +27 -0
  274. package/dist/native/sks-menubar/Sources/SingletonInstanceGuard.swift +328 -0
  275. package/dist/native/sks-menubar/Sources/StatusItemController.swift +10 -2
  276. package/dist/native/sks-menubar/Sources/TelegramPrivateFileStore.swift +498 -0
  277. package/dist/native/sks-menubar/Sources/TelegramPrivateFileSupport.swift +236 -0
  278. package/dist/native/sks-menubar/Sources/TelegramProcessGateway.swift +454 -0
  279. package/dist/native/sks-menubar/Sources/TelegramRuntimeSupport.swift +56 -0
  280. package/dist/native/sks-menubar/Sources/TelegramStateLock.swift +448 -0
  281. package/dist/native/sks-menubar/Sources/TelegramSupport.swift +187 -0
  282. package/dist/native/sks-menubar/Sources/TelegramTransport.swift +499 -0
  283. package/dist/native/sks-menubar/Sources/main.swift +15 -1
  284. package/dist/scripts/all-feature-deep-completion-check.js +5 -1
  285. package/dist/scripts/check-publish-tag.js +56 -0
  286. package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
  287. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +12 -3
  288. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +4 -2
  289. package/dist/scripts/codex-native-agent-role-content-check.js +3 -3
  290. package/dist/scripts/codex-native-gate-lib.js +14 -7
  291. package/dist/scripts/current-command-surface-check.js +7 -7
  292. package/dist/scripts/current-surface-update-e2e-check.js +4 -3
  293. package/dist/scripts/current-upgrade-matrix-check.js +5 -24
  294. package/dist/scripts/docs-truthfulness-check.js +17 -13
  295. package/dist/scripts/gate-lib.js +0 -2
  296. package/dist/scripts/gate-policy-audit-check.js +3 -2
  297. package/dist/scripts/harness-benchmark-check.js +1 -1
  298. package/dist/scripts/init-deep-backup-retention-check.js +1 -1
  299. package/dist/scripts/lib/codex-sdk-gate-lib.js +1 -2
  300. package/dist/scripts/loop-directive-check-lib.js +28 -38
  301. package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +14 -180
  302. package/dist/scripts/mad-sks-launch-sql-plane-boundary-check.js +2 -11
  303. package/dist/scripts/official-subagent-workflow-check.js +1 -1
  304. package/dist/scripts/packlist-performance-check.js +1 -2
  305. package/dist/scripts/prepublish-release-check-or-fast.js +32 -0
  306. package/dist/scripts/publish-preflight.js +12 -0
  307. package/dist/scripts/release-affected-selector-check.js +2 -2
  308. package/dist/scripts/release-gate-batch-runner-check.js +2 -2
  309. package/dist/scripts/release-metadata-check.js +8 -12
  310. package/dist/scripts/release-real-check.js +2 -54
  311. package/dist/scripts/runtime-domain-gate-lib.js +2 -96
  312. package/dist/scripts/runtime-proof-summary-check.js +2 -6
  313. package/dist/scripts/search-visibility-gate-lib.js +0 -1
  314. package/dist/scripts/sks-cli-gate-lib.js +1 -1
  315. package/dist/scripts/typed-routing-gate-lib.js +7 -59
  316. package/docs/demo.tape +1 -1
  317. package/infra-harness-gates.json +1 -1456
  318. package/package.json +10 -7
  319. package/release-gates.v2.json +0 -1
  320. package/schemas/agents/parallel-runtime-proof.schema.json +0 -2
  321. package/schemas/codex/agent-result.schema.json +0 -6
  322. package/schemas/naruto/naruto-concurrency-governor.schema.json +1 -3
  323. package/schemas/release/release-gate-node.schema.json +1 -1
  324. package/dist/commands/zellij-lane.js +0 -22
  325. package/dist/commands/zellij-monitor-pane.js +0 -26
  326. package/dist/commands/zellij-slot-column-anchor.js +0 -22
  327. package/dist/commands/zellij-slot-pane.js +0 -80
  328. package/dist/commands/zellij-viewport-pane.js +0 -57
  329. package/dist/commands/zellij.js +0 -422
  330. package/dist/core/agents/agent-runner-zellij.js +0 -164
  331. package/dist/core/agents/agent-slot-pane-binding-proof.js +0 -96
  332. package/dist/core/agents/parallel-write-fixture.js +0 -305
  333. package/dist/core/agents/worker-pane-communication-contract.js +0 -100
  334. package/dist/core/agents/zellij-lane-supervisor.js +0 -428
  335. package/dist/core/agents/zellij-right-lane-cockpit.js +0 -66
  336. package/dist/core/doctor/doctor-zellij-repair.js +0 -40
  337. package/dist/core/ops/upgrade-migration-fixtures.js +0 -119
  338. package/dist/core/proof/route-finalizer-fixtures.js +0 -21
  339. package/dist/core/zellij/homebrew-policy.js +0 -43
  340. package/dist/core/zellij/zellij-capability.js +0 -126
  341. package/dist/core/zellij/zellij-clipboard-config.js +0 -52
  342. package/dist/core/zellij/zellij-command.js +0 -149
  343. package/dist/core/zellij/zellij-fake-adapter.js +0 -186
  344. package/dist/core/zellij/zellij-lane-renderer.js +0 -706
  345. package/dist/core/zellij/zellij-lane-runtime.js +0 -189
  346. package/dist/core/zellij/zellij-launcher.js +0 -268
  347. package/dist/core/zellij/zellij-layout-builder.js +0 -191
  348. package/dist/core/zellij/zellij-monitor-renderer.js +0 -52
  349. package/dist/core/zellij/zellij-official-subagent-activity.js +0 -526
  350. package/dist/core/zellij/zellij-official-subagent-telemetry.js +0 -258
  351. package/dist/core/zellij/zellij-pane-proof.js +0 -226
  352. package/dist/core/zellij/zellij-right-column-manager.js +0 -308
  353. package/dist/core/zellij/zellij-screen-proof.js +0 -120
  354. package/dist/core/zellij/zellij-self-heal-types.js +0 -44
  355. package/dist/core/zellij/zellij-self-heal.js +0 -408
  356. package/dist/core/zellij/zellij-slot-column-anchor.js +0 -304
  357. package/dist/core/zellij/zellij-slot-pane-renderer.js +0 -521
  358. package/dist/core/zellij/zellij-slot-telemetry.js +0 -384
  359. package/dist/core/zellij/zellij-theme.js +0 -66
  360. package/dist/core/zellij/zellij-ui-mode.js +0 -34
  361. package/dist/core/zellij/zellij-update.js +0 -348
  362. package/dist/core/zellij/zellij-viewport-binder.js +0 -61
  363. package/dist/core/zellij/zellij-worker-pane-manager.js +0 -881
  364. package/dist/core/zellij/zellij-worker-pane-summary.js +0 -64
  365. package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +0 -26
  366. package/dist/native/sks-menubar/Tests/OperationCoordinatorTests.swift +0 -174
  367. package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +0 -20
  368. package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +0 -142
  369. package/dist/scripts/zellij-pane-proof-check.js +0 -88
  370. package/dist/scripts/zellij-real-session-cleanup-check.js +0 -139
  371. package/dist/scripts/zellij-real-session-launch-check.js +0 -126
  372. package/dist/scripts/zellij-screen-proof-check.js +0 -43
  373. package/schemas/zellij/zellij-right-column-state.schema.json +0 -40
  374. package/schemas/zellij/zellij-slot-telemetry.schema.json +0 -89
  375. package/schemas/zellij/zellij-worker-pane.schema.json +0 -53
  376. package/scripts/build-clean-atomic.mjs +0 -323
@@ -1,49 +1,485 @@
1
1
  import Cocoa
2
2
 
3
- final class RemoteCodingViewController: NSViewController {
4
- private static let websiteURL = URL(string: "https://www.onorca.dev")!
5
- private static let sourceURL = URL(string: "https://github.com/stablyai/orca")!
3
+ final class RemoteCodingViewController: NSViewController, ControlCenterPage {
4
+ private static let botFatherURL = URL(string: "https://t.me/BotFather")!
5
+ private static let tokenPattern = #"^\d{5,20}:[A-Za-z0-9_-]{20,128}$"#
6
+
7
+ private let processClient: ProcessClient
8
+ private let telegramService: TelegramMenuBarService
9
+ private let serviceBadge = NativeView.badge("Checking Telegram service", color: .systemBlue)
10
+ private let serviceDetail = NativeView.detail("Reading secret-free Telegram liveness status…")
11
+ private let pairingDetail = NativeView.detail("No pairing code has been issued in this session.")
12
+ private let serviceSpinner = NativeView.spinner(label: "Telegram operation in progress")
13
+ private lazy var setupButton = NativeView.button("Enter Bot Token…", target: self, action: #selector(enterToken))
14
+ private lazy var pairButton = NativeView.button("Generate Pairing Code", target: self, action: #selector(generatePairingCode))
15
+ private lazy var startButton = NativeView.button("Start", target: self, action: #selector(startService))
16
+ private lazy var stopButton = NativeView.button("Stop", target: self, action: #selector(stopService))
17
+ private lazy var restartButton = NativeView.button("Restart", target: self, action: #selector(restartService))
18
+ private lazy var refreshButton = NativeView.button("Refresh Status", target: self, action: #selector(refreshStatusAction))
19
+ private var operationInFlight = false
20
+ private var tokenConfigured = false
21
+ private var pollerRunning = false
22
+
23
+ init(processClient: ProcessClient, telegramService: TelegramMenuBarService) {
24
+ self.processClient = processClient
25
+ self.telegramService = telegramService
26
+ super.init(nibName: nil, bundle: nil)
27
+ }
28
+
29
+ required init?(coder: NSCoder) { nil }
6
30
 
7
31
  override func loadView() {
8
- let websiteButton = NativeView.button(
9
- "Visit Orca Website",
10
- target: self,
11
- action: #selector(openWebsite)
12
- )
13
- websiteButton.setAccessibilityHelp("Open the external Orca website in your default browser.")
32
+ let botFatherButton = NativeView.button("Open @BotFather", target: self, action: #selector(openBotFather))
33
+ botFatherButton.setAccessibilityHelp("Open the official Telegram BotFather chat in your default handler.")
34
+ setupButton.setAccessibilityHelp("Enter a BotFather token securely. The token is verified live and stored in the private SKS user secret file.")
35
+ pairButton.setAccessibilityHelp("With Telegram polling running, issue a short-lived, single-use code for pairing one intended private chat.")
36
+ startButton.setAccessibilityHelp("Start Telegram polling for the current SKS companion session after a bot token is configured.")
37
+ stopButton.setAccessibilityHelp("Stop polling for the current companion session without deleting the token or paired chats. A companion relaunch starts it again.")
38
+ restartButton.setAccessibilityHelp("Restart the single resident Telegram poller and revalidate the stored bot identity.")
39
+ refreshButton.setAccessibilityHelp("Refresh secret-free bot, pairing, audit, and poller status.")
40
+ pairingDetail.isSelectable = true
41
+ pairingDetail.setAccessibilityLabel("Telegram pairing instructions")
42
+ serviceDetail.setAccessibilityLabel("Telegram service status detail")
14
43
 
15
- let sourceButton = NativeView.button(
16
- "View Orca on GitHub",
17
- target: self,
18
- action: #selector(openSource)
44
+ let setupCard = NativeView.card(
45
+ title: "Connect with BotFather",
46
+ subtitle: "Create a Telegram bot, then let SKS validate and store its token privately.",
47
+ views: [
48
+ NativeView.detail(
49
+ "1. Open @BotFather and send /newbot. 2. Finish the bot name and username prompts. " +
50
+ "3. Copy the HTTP API token BotFather returns. 4. Choose Enter Bot Token below."
51
+ ),
52
+ NativeView.detail(
53
+ "The token is sent only through process stdin to the canonical SKS setup command, verified with Telegram getMe, and stored in the private user secret file. It is never shown again or written to the SKS action log. Revoke it in BotFather if you suspect exposure."
54
+ ),
55
+ NativeView.row([botFatherButton, setupButton])
56
+ ]
19
57
  )
20
- sourceButton.setAccessibilityHelp("Open the external Orca source repository in your default browser.")
21
58
 
22
- let recommendation = NativeView.card(
23
- title: "Explore Orca",
24
- subtitle: "A remote coding option maintained outside Sneakoscope.",
59
+ let pairingCard = NativeView.card(
60
+ title: "Pair a Private Chat",
61
+ subtitle: "Authorize only the intended Telegram account and private chat.",
25
62
  views: [
26
63
  NativeView.detail(
27
- "Orca is an external beta project from Stably AI. It is not part of Sneakoscope, and SKS does not install, configure, authenticate, monitor, or depend on it."
64
+ "With Telegram polling running, generate a short-lived code, open your new bot from the intended private chat, and send /start followed by that code. Codes are single-use; group chats are rejected. After pairing, try /sks status {}."
28
65
  ),
29
- NativeView.row([websiteButton, sourceButton])
66
+ pairingDetail,
67
+ pairButton
68
+ ]
69
+ )
70
+
71
+ let statusCard = NativeView.card(
72
+ title: "Service Status",
73
+ subtitle: "Control the single SKS-owned poller for this companion session and inspect secret-free health evidence.",
74
+ views: [
75
+ NativeView.row([serviceBadge, serviceSpinner]),
76
+ serviceDetail,
77
+ NativeView.row([startButton, stopButton, restartButton, refreshButton])
30
78
  ]
31
79
  )
32
80
 
33
81
  view = NativeView.page([
34
- NativeView.title("Remote Coding"),
82
+ NativeView.title("Telegram Remote Control"),
35
83
  NativeView.detail(
36
- "Looking for a remote coding companion? You can evaluate Orca independently using its website and open-source repository."
84
+ "Connect SKS to a BotFather-created Telegram bot for paired, allowlisted remote commands with confirmation gates and a local audit trail."
37
85
  ),
38
- recommendation
86
+ setupCard,
87
+ pairingCard,
88
+ statusCard
39
89
  ])
90
+ updateControls()
91
+ }
92
+
93
+ func refreshOnAppear() { refreshStatus() }
94
+
95
+ @objc private func openBotFather() {
96
+ NSWorkspace.shared.open(Self.botFatherURL)
97
+ }
98
+
99
+ @objc private func enterToken() {
100
+ if TelegramPrivateFileStore.operatorEnvironmentOverrideActive() {
101
+ showAttention(
102
+ "Environment-managed token is active",
103
+ detail: "SKS is using an operator-managed Telegram token environment override. Remove TELEGRAM_BOT_TOKEN or SKS_TELEGRAM_BOT_TOKEN and relaunch the companion before storing a BotFather token file."
104
+ )
105
+ return
106
+ }
107
+ promptForToken(removeWebhook: false)
108
+ }
109
+
110
+ private func promptForToken(removeWebhook: Bool) {
111
+ guard !operationInFlight, let window = view.window else { return }
112
+ AlertFactory.textSheet(
113
+ window: window,
114
+ title: "Enter Telegram Bot Token",
115
+ message: removeWebhook
116
+ ? "Paste the BotFather token again. With your consent, SKS will remove this bot's existing webhook without dropping pending updates, verify the bot, and store the token privately."
117
+ : "Paste the HTTP API token supplied by @BotFather. SKS will verify the bot identity before storing it privately.",
118
+ secure: true,
119
+ placeholder: "123456789:BotFatherToken",
120
+ actionTitle: removeWebhook ? "Remove Webhook & Save" : "Verify & Save"
121
+ ) { [weak self] token in
122
+ guard let self, let token else { return }
123
+ let normalizedToken = token.trimmingCharacters(in: .whitespacesAndNewlines)
124
+ guard self.validTokenShape(normalizedToken) else {
125
+ self.showAttention(
126
+ "Token not saved",
127
+ detail: "That value does not match the BotFather token format. Copy the complete HTTP API token and try again."
128
+ )
129
+ return
130
+ }
131
+ self.saveToken(normalizedToken, removeWebhook: removeWebhook)
132
+ }
133
+ }
134
+
135
+ @objc private func generatePairingCode() {
136
+ guard !operationInFlight else { return }
137
+ beginOperation("Issuing a short-lived pairing code…")
138
+ processClient.run(
139
+ ["telegram", "pair", "--json"],
140
+ environment: telegramSecretFreeEnvironment,
141
+ timeout: NativeView.statusTimeout,
142
+ logOutput: false
143
+ ) { [weak self] result in
144
+ guard let self else { return }
145
+ self.endOperation()
146
+ guard result.code == 0,
147
+ let response = self.decode(TelegramCenterPairResponse.self, result.output),
148
+ response.ok,
149
+ let code = response.code,
150
+ code.range(of: #"^\d{6}-[A-F0-9]{4}$"#, options: .regularExpression) != nil else {
151
+ self.showAttention(
152
+ "Pairing code unavailable",
153
+ detail: self.publicFailure(result.output, fallback: "SKS could not create a pairing code. Refresh status and try again.")
154
+ )
155
+ return
156
+ }
157
+ let expiration = response.expires_at.map { " It expires at \($0)." } ?? ""
158
+ let instruction = response.instruction
159
+ ?? "Send /start \(code) to this bot from the intended private chat."
160
+ let postPair = response.post_pair_command ?? "/sks status {}"
161
+ let confirmation = response.confirmation_grammar ?? "/confirm <nonce>"
162
+ let statusGuidance = instruction.contains(postPair) ? "" : " Then try \(postPair)."
163
+ self.pairingDetail.stringValue = "\(instruction)\(expiration)\(statusGuidance) Confirm prompted actions with \(confirmation)."
164
+ self.pairingDetail.setAccessibilityValue(self.pairingDetail.stringValue)
165
+ self.showProgress("Pairing code ready", detail: "Use the displayed code once in the intended private chat.")
166
+ self.refreshStatus(after: 1)
167
+ }
168
+ }
169
+
170
+ @objc private func startService() { runLifecycle(.start) }
171
+ @objc private func stopService() { runLifecycle(.stop) }
172
+ @objc private func restartService() { runLifecycle(.restart) }
173
+ @objc private func refreshStatusAction() { refreshStatus() }
174
+
175
+ private enum LifecycleAction { case start, stop, restart }
176
+
177
+ private func runLifecycle(_ action: LifecycleAction) {
178
+ guard !operationInFlight else { return }
179
+ let actionName: String
180
+ switch action {
181
+ case .start: actionName = "Starting"
182
+ case .stop: actionName = "Stopping"
183
+ case .restart: actionName = "Restarting"
184
+ }
185
+ beginOperation("\(actionName) Telegram polling…")
186
+
187
+ switch action {
188
+ case .stop:
189
+ let task = telegramService.stop()
190
+ Task { @MainActor [weak self] in
191
+ await task.value
192
+ self?.endOperation()
193
+ self?.showProgress(
194
+ "Telegram polling stopped",
195
+ detail: "The token and paired chats were preserved. Relaunching the SKS companion starts polling again."
196
+ )
197
+ self?.refreshStatus(after: 0.2)
198
+ }
199
+ case .start, .restart:
200
+ let task = action == .start ? telegramService.start() : telegramService.restart()
201
+ Task { @MainActor [weak self] in
202
+ do {
203
+ let receipt = try await task.value
204
+ self?.endOperation()
205
+ self?.render(receipt)
206
+ } catch {
207
+ self?.endOperation()
208
+ self?.showAttention(
209
+ "Telegram polling did not start",
210
+ detail: "Refresh status for the verified blocker. Re-enter the BotFather token if identity validation failed."
211
+ )
212
+ }
213
+ self?.refreshStatus(after: 0.3)
214
+ }
215
+ }
216
+ }
217
+
218
+ private func saveToken(_ token: String, removeWebhook: Bool) {
219
+ let normalizedToken = token.trimmingCharacters(in: .whitespacesAndNewlines)
220
+ guard validTokenShape(normalizedToken) else {
221
+ showAttention(
222
+ "Token not saved",
223
+ detail: "That value does not match the BotFather token format. Copy the complete token and try again."
224
+ )
225
+ return
226
+ }
227
+ beginOperation("Verifying bot identity with Telegram…")
228
+ var arguments = ["telegram", "setup", "--token-stdin", "--json"]
229
+ if TelegramPrivateFileStore.operatorEnvironmentOverrideActive() {
230
+ arguments.append("--operator-env-override-active")
231
+ }
232
+ if removeWebhook { arguments.append("--remove-webhook") }
233
+ processClient.run(
234
+ arguments,
235
+ stdin: normalizedToken + "\n",
236
+ environment: telegramSecretFreeEnvironment,
237
+ timeout: NativeView.mutationTimeout,
238
+ logOutput: false
239
+ ) { [weak self] result in
240
+ guard let self else { return }
241
+ let response = self.decode(TelegramCenterSetupResponse.self, result.output)
242
+ guard result.code == 0,
243
+ let response,
244
+ response.ok,
245
+ response.getme_verified == true,
246
+ response.token_stored == true else {
247
+ self.endOperation()
248
+ if !removeWebhook,
249
+ response?.error == "telegram_webhook_configured_remove_consent_required" {
250
+ self.confirmWebhookRemoval()
251
+ return
252
+ }
253
+ if response?.error == "telegram_operator_env_override_active" {
254
+ self.showAttention(
255
+ "Environment-managed token is active",
256
+ detail: response?.operator_action
257
+ ?? "Remove the operator-managed Telegram token environment override and relaunch before storing a file token."
258
+ )
259
+ return
260
+ }
261
+ if response?.partial_success == true {
262
+ self.showAttention(
263
+ "Telegram setup partially completed",
264
+ detail: self.partialSetupRecovery(response)
265
+ )
266
+ return
267
+ }
268
+ self.showAttention(
269
+ "Token not saved",
270
+ detail: self.publicFailure(
271
+ result.output,
272
+ fallback: "Telegram could not verify this bot token. Confirm it in @BotFather and try again."
273
+ )
274
+ )
275
+ return
276
+ }
277
+ let restart = self.telegramService.restart()
278
+ Task { @MainActor [weak self] in
279
+ do {
280
+ let receipt = try await restart.value
281
+ self?.endOperation()
282
+ self?.render(receipt)
283
+ self?.showProgress(
284
+ "Bot verified and connected",
285
+ detail: response.bot_state_reset == true
286
+ ? "The token is stored privately. Bot-scoped pairing and poll state were reset; generate a new pairing code."
287
+ : "The token is stored privately. Generate a pairing code for the intended private chat."
288
+ )
289
+ } catch {
290
+ self?.endOperation()
291
+ self?.showAttention(
292
+ "Token saved; poller needs attention",
293
+ detail: "The verified token was stored, but the resident poller did not restart. Refresh status for the blocker."
294
+ )
295
+ }
296
+ self?.refreshStatus(after: 0.3)
297
+ }
298
+ }
299
+ }
300
+
301
+ private func confirmWebhookRemoval() {
302
+ guard let window = view.window else { return }
303
+ AlertFactory.confirmSheet(
304
+ window: window,
305
+ title: "Remove the existing Telegram webhook?",
306
+ message: "Telegram cannot run getUpdates while this bot has a webhook. Removing it changes delivery: the existing webhook endpoint will stop receiving updates and SKS long polling can start. SKS requests removal without dropping pending updates. The token was not retained; after Continue, paste it again to authorize this one change.",
307
+ destructive: true,
308
+ actionTitle: "Continue"
309
+ ) { [weak self] confirmed in
310
+ guard confirmed else { return }
311
+ self?.promptForToken(removeWebhook: true)
312
+ }
313
+ }
314
+
315
+ private var telegramSecretFreeEnvironment: [String: String] {
316
+ ["TELEGRAM_BOT_TOKEN": "", "SKS_TELEGRAM_BOT_TOKEN": ""]
317
+ }
318
+
319
+ private func refreshStatus(after delay: TimeInterval = 0) {
320
+ guard delay > 0 else {
321
+ loadStatus()
322
+ return
323
+ }
324
+ DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in self?.loadStatus() }
325
+ }
326
+
327
+ private func loadStatus() {
328
+ guard !operationInFlight else { return }
329
+ beginOperation("Refreshing secret-free Telegram status…")
330
+ processClient.run(
331
+ ["telegram", "doctor", "--json"],
332
+ environment: telegramSecretFreeEnvironment,
333
+ timeout: NativeView.statusTimeout,
334
+ logOutput: false
335
+ ) { [weak self] result in
336
+ guard let self else { return }
337
+ self.endOperation()
338
+ guard let response = self.decode(TelegramCenterDoctorResponse.self, result.output) else {
339
+ self.tokenConfigured = false
340
+ self.pollerRunning = false
341
+ self.showAttention("Status unavailable", detail: "SKS could not read the Telegram liveness receipt.")
342
+ return
343
+ }
344
+ self.render(response)
345
+ }
346
+ }
347
+
348
+ private func render(_ response: TelegramCenterDoctorResponse) {
349
+ tokenConfigured = response.token_configured
350
+ pollerRunning = response.poller.running
351
+ let paired = response.paired_chat_count == 1 ? "1 paired chat" : "\(response.paired_chat_count) paired chats"
352
+ let source = tokenSourceDescription(response.token_source)
353
+ if response.ok {
354
+ NativeView.setBadge(serviceBadge, text: "Ready", color: .systemGreen)
355
+ serviceDetail.stringValue = "Bot identity verified · \(source) · \(paired) · poller running · audit healthy."
356
+ } else if response.self_heal_action == "operator_remove_webhook"
357
+ || response.poller.last_error?.range(of: "409|webhook", options: .regularExpression) != nil {
358
+ NativeView.setBadge(serviceBadge, text: "Webhook blocks polling", color: .systemOrange)
359
+ serviceDetail.stringValue = "This bot has an active Telegram webhook, so getUpdates polling cannot run. Choose Enter Bot Token again; SKS will explain the delivery change and request explicit consent before removing the webhook without dropping pending updates."
360
+ } else if !response.token_configured {
361
+ NativeView.setBadge(serviceBadge, text: "Bot token required", color: .systemOrange)
362
+ serviceDetail.stringValue = "Create a bot with @BotFather, then enter and verify its HTTP API token."
363
+ } else if !response.bot_identity_valid {
364
+ NativeView.setBadge(serviceBadge, text: "Bot identity not verified", color: .systemRed)
365
+ serviceDetail.stringValue = "Telegram could not validate the stored bot identity. Enter the current BotFather token again."
366
+ } else if !response.audit_healthy {
367
+ NativeView.setBadge(serviceBadge, text: "Audit unavailable", color: .systemRed)
368
+ serviceDetail.stringValue = "Remote control is stopped because its local audit ledger is unavailable. Repair local SKS permissions before restarting."
369
+ } else if response.paired_chat_count == 0 {
370
+ NativeView.setBadge(serviceBadge, text: "Private chat not paired", color: .systemOrange)
371
+ serviceDetail.stringValue = "Bot verified · \(source) · no paired chats · \(response.poller.running ? "poller running" : "poller stopped"). Generate a pairing code and use it once in the intended private chat."
372
+ } else if !response.poller.running {
373
+ NativeView.setBadge(serviceBadge, text: "Poller stopped", color: .systemOrange)
374
+ serviceDetail.stringValue = "Bot identity verified · \(source) · \(paired) · poller stopped. Choose Start to resume."
375
+ } else {
376
+ NativeView.setBadge(serviceBadge, text: "Needs attention", color: .systemOrange)
377
+ serviceDetail.stringValue = "Bot identity verified · \(paired) · poller degraded after \(response.poller.consecutive_failures) consecutive failures. Refresh status or Restart."
378
+ }
379
+ serviceDetail.setAccessibilityValue(serviceDetail.stringValue)
380
+ updateControls()
381
+ }
382
+
383
+ private func render(_ receipt: TelegramLivenessReceipt) {
384
+ tokenConfigured = receipt.token_configured
385
+ pollerRunning = receipt.running && receipt.poller.running
386
+ let paired = receipt.paired_chat_count == 1 ? "1 paired chat" : "\(receipt.paired_chat_count) paired chats"
387
+ let source = tokenSourceDescription(receipt.token_source.rawValue)
388
+ NativeView.setBadge(
389
+ serviceBadge,
390
+ text: pollerRunning ? "Running" : "Stopped",
391
+ color: pollerRunning ? .systemGreen : .systemOrange
392
+ )
393
+ serviceDetail.stringValue = "Bot identity \(receipt.bot_identity_valid ? "verified" : "not verified") · \(source) · \(paired) · poller \(pollerRunning ? "running" : "stopped") · audit \(receipt.audit_healthy == true ? "healthy" : "unavailable")."
394
+ serviceDetail.setAccessibilityValue(serviceDetail.stringValue)
395
+ updateControls()
396
+ }
397
+
398
+ private func beginOperation(_ detail: String) {
399
+ operationInFlight = true
400
+ serviceSpinner.startAnimation(nil)
401
+ serviceDetail.stringValue = detail
402
+ updateControls()
403
+ }
404
+
405
+ private func endOperation() {
406
+ operationInFlight = false
407
+ serviceSpinner.stopAnimation(nil)
408
+ updateControls()
409
+ }
410
+
411
+ private func showProgress(_ title: String, detail: String) {
412
+ NativeView.setBadge(serviceBadge, text: title, color: .systemBlue)
413
+ serviceDetail.stringValue = detail
414
+ serviceDetail.setAccessibilityValue(detail)
415
+ updateControls()
416
+ }
417
+
418
+ private func showAttention(_ title: String, detail: String) {
419
+ NativeView.setBadge(serviceBadge, text: title, color: .systemOrange)
420
+ serviceDetail.stringValue = detail
421
+ serviceDetail.setAccessibilityValue(detail)
422
+ updateControls()
423
+ }
424
+
425
+ private func updateControls() {
426
+ setupButton.isEnabled = !operationInFlight
427
+ pairButton.isEnabled = !operationInFlight && tokenConfigured && pollerRunning
428
+ startButton.isEnabled = !operationInFlight && tokenConfigured && !pollerRunning
429
+ stopButton.isEnabled = !operationInFlight && pollerRunning
430
+ restartButton.isEnabled = !operationInFlight && tokenConfigured
431
+ refreshButton.isEnabled = !operationInFlight
432
+ }
433
+
434
+ private func validTokenShape(_ value: String) -> Bool {
435
+ value.utf8.count <= 1024
436
+ && value.range(of: Self.tokenPattern, options: .regularExpression) != nil
437
+ }
438
+
439
+ private func decode<T: Decodable>(_ type: T.Type, _ output: String) -> T? {
440
+ guard let data = output.data(using: .utf8) else { return nil }
441
+ return try? JSONDecoder().decode(type, from: data)
442
+ }
443
+
444
+ private func publicFailure(_ output: String, fallback: String) -> String {
445
+ guard let data = output.data(using: .utf8),
446
+ let row = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
447
+ let error = row["error"] as? String else { return fallback }
448
+ switch error {
449
+ case "telegram_token_invalid", "telegram_token_stdin_empty":
450
+ return "That value is not a complete BotFather HTTP API token."
451
+ case let value where value.contains("401") || value.contains("Unauthorized"):
452
+ return "Telegram rejected this token. Copy the current token from @BotFather and try again."
453
+ case let value where value.contains("timeout") || value.contains("network"):
454
+ return "Telegram identity verification could not complete. Check the network connection and try again."
455
+ default:
456
+ return fallback
457
+ }
40
458
  }
41
459
 
42
- @objc private func openWebsite() {
43
- NSWorkspace.shared.open(Self.websiteURL)
460
+ private func partialSetupRecovery(_ response: TelegramCenterSetupResponse?) -> String {
461
+ var parts: [String] = []
462
+ if response?.webhook_removed == true {
463
+ parts.append("The existing webhook was removed without dropping pending updates.")
464
+ }
465
+ if response?.bot_state_reset == true {
466
+ parts.append("Bot-scoped pairing and poll state were reset safely.")
467
+ }
468
+ if response?.token_stored == false {
469
+ parts.append("The token was not stored; rerun secure setup to finish.")
470
+ }
471
+ if let note = response?.recovery?.note, !note.isEmpty { parts.append(note) }
472
+ return parts.isEmpty
473
+ ? "Review the secret-free recovery status, then rerun secure setup."
474
+ : parts.joined(separator: " ")
44
475
  }
45
476
 
46
- @objc private func openSource() {
47
- NSWorkspace.shared.open(Self.sourceURL)
477
+ private func tokenSourceDescription(_ source: String) -> String {
478
+ switch source {
479
+ case "env": return "operator environment token"
480
+ case "user_secret_file": return "private token file"
481
+ case "none": return "no token source"
482
+ default: return "token source unknown"
483
+ }
48
484
  }
49
485
  }