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.
- package/README.md +129 -10
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/cli/codex-app-command.js +1 -1
- package/dist/cli/command-manifest-lite.js +4 -1
- package/dist/cli/command-registry.js +2 -0
- package/dist/cli/install-helpers-codex-lb-chain.js +42 -0
- package/dist/cli/install-helpers-codex-lb-config.js +114 -9
- package/dist/cli/install-helpers-install-support.js +6 -16
- package/dist/cli/install-helpers.js +788 -600
- package/dist/cli/router.js +30 -2
- package/dist/commands/codex-app.js +37 -1
- package/dist/commands/codex-lb.js +491 -300
- package/dist/config/skills-manifest.json +57 -71
- package/dist/core/align/align-route.js +127 -0
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +8 -4
- package/dist/core/codex-app/codex-app-restart.js +83 -0
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +8 -4
- package/dist/core/codex-app/desktop-routing-snapshot.js +1 -1
- package/dist/core/codex-app/menubar/constants.js +5 -0
- package/dist/core/codex-app/menubar/generation-transaction-journal.js +1 -3
- package/dist/core/codex-app/menubar/installer.js +18 -0
- package/dist/core/codex-app/multi-provider-router.js +22 -10
- package/dist/core/codex-app/openrouter-activate.js +26 -1
- package/dist/core/codex-app.js +118 -26
- package/dist/core/codex-control/codex-app-server-runtime-env.js +86 -0
- package/dist/core/codex-control/codex-app-server-v2-client.js +78 -8
- package/dist/core/codex-control/codex-task-runner.js +2 -2
- package/dist/core/codex-lb/capability-runner.js +204 -0
- package/dist/core/codex-lb/capability-types.js +1 -0
- package/dist/core/codex-lb/codex-lb-env.js +9 -13
- package/dist/core/codex-lb/codex-lb-setup.js +45 -8
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +52 -74
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +1 -1
- package/dist/core/codex-lb/desktop-auth-invariant.js +185 -0
- package/dist/core/codex-lb/desktop-bridge/client.js +34 -0
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +106 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +101 -0
- package/dist/core/codex-lb/desktop-bridge/index.js +10 -0
- package/dist/core/codex-lb/desktop-bridge/launchd.js +81 -0
- package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +27 -0
- package/dist/core/codex-lb/desktop-bridge/security.js +274 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +179 -0
- package/dist/core/codex-lb/desktop-bridge/state.js +119 -0
- package/dist/core/codex-lb/desktop-bridge/types.js +16 -0
- package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +151 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +189 -0
- package/dist/core/codex-lb/desktop-controller.js +1410 -0
- package/dist/core/codex-lb/desktop-mode.js +32 -0
- package/dist/core/codex-lb/desktop-real-evidence.js +168 -0
- package/dist/core/codex-lb/desktop-service.js +613 -0
- package/dist/core/codex-lb/legacy-migration.js +575 -0
- package/dist/core/codex-lb/migration-receipt.js +246 -0
- package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +60 -0
- package/dist/core/codex-lb/probes/bridge-probe.js +75 -0
- package/dist/core/codex-lb/probes/catalog-probe.js +128 -0
- package/dist/core/codex-lb/probes/computer-use-probe.js +50 -0
- package/dist/core/codex-lb/probes/image-generation-probe.js +47 -0
- package/dist/core/codex-lb/probes/probe-evidence.js +39 -0
- package/dist/core/codex-lb/probes/voice-realtime-probe.js +44 -0
- package/dist/core/codex-lb/trusted-deep-evidence.js +403 -0
- package/dist/core/codex-native/core-skill-manifest.js +22 -6
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +2 -1
- package/dist/core/commands/align-command.js +220 -0
- package/dist/core/commands/image-ux-review-command.js +280 -68
- package/dist/core/commands/naruto-command.js +257 -8
- package/dist/core/commands/ppt-command.js +2 -2
- package/dist/core/commands/telegram-command.js +402 -34
- package/dist/core/commands/triwiki-command.js +11 -1
- package/dist/core/commands/triwiki-graph-command.js +160 -0
- package/dist/core/commands/wiki-command.js +100 -20
- package/dist/core/doctor/skill-legacy-surface.js +1 -3
- package/dist/core/errors/message.js +3 -0
- package/dist/core/evidence/evidence-freshness.js +14 -0
- package/dist/core/feature-fixtures.js +9 -1
- package/dist/core/feature-registry.js +5 -3
- package/dist/core/fsx.js +7 -3
- package/dist/core/hooks-runtime/codex-commit-hooks-selftest.js +82 -0
- package/dist/core/hooks-runtime/context-graph-freshness-preflight.js +113 -0
- package/dist/core/hooks-runtime/hook-context.js +15 -2
- package/dist/core/hooks-runtime/managed-skill-generation-heal.js +46 -0
- package/dist/core/hooks-runtime/naruto-terminal-finalization.js +1 -0
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +1 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
- package/dist/core/hooks-runtime.js +33 -89
- package/dist/core/image-ux-review/callout-extraction.js +6 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +64 -23
- package/dist/core/image-ux-review/real-callout-extractor.js +1 -0
- package/dist/core/image-ux-review.js +230 -12
- package/dist/core/imagegen/codex-lb-imagegen-target.js +21 -7
- package/dist/core/imagegen/imagegen-capability.js +10 -4
- package/dist/core/imagegen/require-imagegen.js +29 -5
- package/dist/core/init/skills.js +25 -13
- package/dist/core/init.js +1 -1
- package/dist/core/install/installed-package-smoke.js +157 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +2 -1
- package/dist/core/managed-path-safety.js +8 -10
- package/dist/core/mcp-config/backup.js +2 -4
- package/dist/core/mcp-config/config-reader.js +2 -4
- package/dist/core/mcp-config/scope.js +3 -5
- package/dist/core/naruto/context-graph-advisor-scope.js +242 -0
- package/dist/core/naruto/context-graph-advisor.js +0 -0
- package/dist/core/perf/release-latency-slo.js +12 -6
- package/dist/core/pipeline-internals/runtime-core.js +78 -0
- package/dist/core/pipeline-internals/runtime-gates.js +5 -2
- package/dist/core/policy/latest-version-guidance.js +113 -0
- package/dist/core/ppt.js +8 -8
- package/dist/core/preflight/parallel-preflight-engine.js +1 -1
- package/dist/core/proof/auto-finalize.js +98 -6
- package/dist/core/proof/route-proof-gate.js +12 -1
- package/dist/core/proof/route-proof-policy.js +8 -8
- package/dist/core/release/gate-manifest.js +32 -1
- package/dist/core/release/npm-stage-contract.js +21 -0
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/release-gate-contract.js +5 -0
- package/dist/core/release/release-proof-io.js +1 -3
- package/dist/core/release/release-real-contract.js +5 -4
- package/dist/core/release/release-stamp-proof.js +1 -3
- package/dist/core/release/stage-publish.js +27 -0
- package/dist/core/remote/audit-idempotency.js +50 -18
- package/dist/core/remote/codex-public-activity.js +283 -0
- package/dist/core/remote/index.js +1 -0
- package/dist/core/remote/ssh-worker-client.js +4 -1
- package/dist/core/remote/worker.js +206 -27
- package/dist/core/research/research-adversarial-review.js +1 -3
- package/dist/core/research/research-claim-synthesizer.js +1 -3
- package/dist/core/research/research-falsification-runner.js +1 -3
- package/dist/core/research/research-source-evidence.js +1 -3
- package/dist/core/responses-stream.js +65 -19
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/design-policy.js +7 -2
- package/dist/core/routes/dollar-manifest-lite.js +2 -4
- package/dist/core/routes/evidence.js +1 -1
- package/dist/core/routes.js +30 -10
- package/dist/core/safety/command-contract/contracts.js +2 -0
- package/dist/core/safety/command-contract/types.js +1 -1
- package/dist/core/search/context-graph-seeds.js +205 -0
- package/dist/core/search/context.js +0 -0
- package/dist/core/search/provider.js +2 -2
- package/dist/core/secret-redaction.js +6 -0
- package/dist/core/subagents/naruto-help-contract.js +2 -1
- package/dist/core/subagents/naruto-host-credentials.js +161 -0
- package/dist/core/subagents/official-subagent-preparation.js +4 -1
- package/dist/core/subagents/official-subagent-prompt.js +44 -2
- package/dist/core/subagents/official-subagent-runner.js +26 -8
- package/dist/core/subagents/triwiki-attention.js +135 -123
- package/dist/core/telegram/bot-api.js +85 -10
- package/dist/core/telegram/center-snapshot.js +718 -0
- package/dist/core/telegram/config.js +158 -31
- package/dist/core/telegram/hub.js +288 -33
- package/dist/core/telegram/index.js +2 -0
- package/dist/core/telegram/ingress-spool.js +419 -0
- package/dist/core/telegram/ledgers.js +188 -29
- package/dist/core/telegram/messages.js +26 -6
- package/dist/core/telegram/owner-lock.js +10 -7
- package/dist/core/telegram/runtime-projection.js +38 -3
- package/dist/core/telegram/runtime.js +298 -63
- package/dist/core/telegram/service.js +137 -8
- package/dist/core/telegram/setup.js +291 -73
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/code-pack.js +12 -120
- package/dist/core/triwiki/context-graph/compiler/cache-key.js +277 -0
- package/dist/core/triwiki/context-graph/compiler/extract.js +104 -0
- package/dist/core/triwiki/context-graph/compiler/freshness.js +108 -0
- package/dist/core/triwiki/context-graph/compiler/index.js +237 -0
- package/dist/core/triwiki/context-graph/compiler/merge.js +0 -0
- package/dist/core/triwiki/context-graph/compiler/serialize.js +115 -0
- package/dist/core/triwiki/context-graph/contracts.js +236 -0
- package/dist/core/triwiki/context-graph/extractors/code/builders.js +150 -0
- package/dist/core/triwiki/context-graph/extractors/code/declarations.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/index.js +265 -0
- package/dist/core/triwiki/context-graph/extractors/code/inventory.js +237 -0
- package/dist/core/triwiki/context-graph/extractors/code/module-graph.js +252 -0
- package/dist/core/triwiki/context-graph/extractors/code/modules.js +79 -0
- package/dist/core/triwiki/context-graph/extractors/code/references.js +184 -0
- package/dist/core/triwiki/context-graph/extractors/code/selection.js +100 -0
- package/dist/core/triwiki/context-graph/extractors/code/ts-config.js +161 -0
- package/dist/core/triwiki/context-graph/extractors/code/types.js +18 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/claims.js +289 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/index.js +54 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proof-index.js +213 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/proofs.js +266 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/redaction.js +177 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/shared.js +0 -0
- package/dist/core/triwiki/context-graph/extractors/evidence/sources.js +154 -0
- package/dist/core/triwiki/context-graph/extractors/index.js +7 -0
- package/dist/core/triwiki/context-graph/extractors/topology/commands.js +207 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gate-edges.js +201 -0
- package/dist/core/triwiki/context-graph/extractors/topology/gates.js +182 -0
- package/dist/core/triwiki/context-graph/extractors/topology/globs.js +124 -0
- package/dist/core/triwiki/context-graph/extractors/topology/index.js +92 -0
- package/dist/core/triwiki/context-graph/extractors/topology/routes.js +135 -0
- package/dist/core/triwiki/context-graph/extractors/topology/shared.js +215 -0
- package/dist/core/triwiki/context-graph/graph-index.js +143 -0
- package/dist/core/triwiki/context-graph/ids.js +0 -0
- package/dist/core/triwiki/context-graph/lint/index.js +0 -0
- package/dist/core/triwiki/context-graph/lint/rules.js +232 -0
- package/dist/core/triwiki/context-graph/lint/warnings.js +93 -0
- package/dist/core/triwiki/context-graph/paths.js +116 -0
- package/dist/core/triwiki/context-graph/profiles.js +78 -0
- package/dist/core/triwiki/context-graph/projections/anchors.js +91 -0
- package/dist/core/triwiki/context-graph/projections/attention.js +58 -0
- package/dist/core/triwiki/context-graph/projections/code-pack-workspace.js +62 -0
- package/dist/core/triwiki/context-graph/projections/code-pack.js +144 -0
- package/dist/core/triwiki/context-graph/projections/index.js +7 -0
- package/dist/core/triwiki/context-graph/projections/module-view.js +140 -0
- package/dist/core/triwiki/context-graph/projections/node-summary.js +118 -0
- package/dist/core/triwiki/context-graph/projections/pack-contract.js +6 -0
- package/dist/core/triwiki/context-graph/query/explain.js +0 -0
- package/dist/core/triwiki/context-graph/query/index.js +178 -0
- package/dist/core/triwiki/context-graph/query/load.js +116 -0
- package/dist/core/triwiki/context-graph/query/pack.js +117 -0
- package/dist/core/triwiki/context-graph/query/rank.js +142 -0
- package/dist/core/triwiki/context-graph/query/ranking-config.js +64 -0
- package/dist/core/triwiki/context-graph/query/seeds.js +241 -0
- package/dist/core/triwiki/context-graph/query/snapshot-cache.js +72 -0
- package/dist/core/triwiki/context-graph/query/traverse.js +154 -0
- package/dist/core/triwiki/context-graph/query-types.js +29 -0
- package/dist/core/triwiki/context-graph/store/compile-lock.js +21 -0
- package/dist/core/triwiki/context-graph/store/event-log.js +48 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +85 -0
- package/dist/core/triwiki/context-graph/store/graph-status.js +85 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +155 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-repair.js +115 -0
- package/dist/core/triwiki/triwiki-proof-bank-index-store.js +290 -0
- package/dist/core/triwiki/triwiki-proof-bank-index.js +126 -0
- package/dist/core/triwiki/triwiki-proof-bank.js +7 -1
- package/dist/core/verification/context-graph-affected.js +271 -0
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AlertFactory.swift +11 -3
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +9 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +25 -3
- package/dist/native/sks-menubar/Sources/ControlKit.swift +19 -8
- package/dist/native/sks-menubar/Sources/DiagnosticsViewController.swift +1 -2
- package/dist/native/sks-menubar/Sources/MCPServersViewController.swift +45 -17
- package/dist/native/sks-menubar/Sources/OverviewSummary.swift +162 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +136 -190
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +107 -11
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +5 -1
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +16 -4
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +4 -1
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +131 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +288 -341
- package/dist/native/sks-menubar/Sources/RemoteTelegramCenterState.swift +447 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramRendering.swift +484 -0
- package/dist/native/sks-menubar/Sources/RemoteTelegramViewController.swift +364 -115
- package/dist/native/sks-menubar/Sources/SettingsViewController.swift +73 -12
- package/dist/native/sks-menubar/Sources/SidebarItem.swift +3 -3
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +13 -13
- package/dist/native/sks-menubar/Sources/TelegramHubSupervisor.swift +469 -0
- package/dist/native/sks-menubar/Sources/UpdatesViewController.swift +1 -6
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +12 -0
- package/dist/native/sks-menubar/Tests/NativeTelegramRegressionRunner.swift +55 -0
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +33 -0
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +142 -0
- package/dist/native/sks-menubar/Tests/RemoteTelegramCenterStateTests.swift +56 -0
- package/dist/native/sks-menubar/Tests/TelegramHubSupervisorTests.swift +55 -0
- package/dist/scripts/codex-lb-catalog-passthrough-check.js +120 -0
- package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +169 -0
- package/dist/scripts/codex-lb-desktop-bridge-check.js +394 -0
- package/dist/scripts/codex-lb-desktop-bridge-latency-check.js +196 -0
- package/dist/scripts/codex-lb-desktop-capabilities-check.js +287 -0
- package/dist/scripts/codex-lb-desktop-real-evidence-check.js +123 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +81 -40
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +99 -37
- package/dist/scripts/context-graph-check.js +191 -0
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +1 -1
- package/dist/scripts/gate-policy-audit-check.js +1 -1
- package/dist/scripts/helper-dedup-check.js +0 -2
- package/dist/scripts/installed-package-smoke-check.js +4 -1
- package/dist/scripts/latest-version-guidance-check.js +74 -0
- package/dist/scripts/release-metadata-check.js +21 -4
- package/dist/scripts/release-real-check.js +7 -0
- package/dist/scripts/ux-review-imagegen-blackbox-check.js +25 -1
- package/dist/scripts/ux-review-run-wires-imagegen-check.js +9 -1
- package/package.json +8 -3
- package/release-gates.v2.json +176 -1
- package/runtime-required-scripts.json +30 -0
- package/schemas/triwiki/context-graph.schema.json +119 -0
- package/dist/cli/install-helpers-codex-lb-selftest-chain.js +0 -112
- package/dist/cli/install-helpers-codex-lb-selftest.js +0 -481
- package/dist/core/triwiki/code-index-scanner.js +0 -309
|
@@ -1,74 +1,276 @@
|
|
|
1
1
|
import Cocoa
|
|
2
2
|
|
|
3
3
|
final class RemoteTelegramViewController: NSViewController, ControlCenterPage {
|
|
4
|
-
|
|
4
|
+
let processClient: ProcessClient
|
|
5
|
+
private let hubSupervisor: TelegramHubSupervisor
|
|
5
6
|
private let operations: OperationCoordinator
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
|
|
8
|
+
let readinessStatus = NativeView.detail("Project readiness has not been checked.")
|
|
9
|
+
let setupBadge = ControlKit.badge("Telegram setup not checked", tone: .neutral)
|
|
10
|
+
let setupStatus = NativeView.detail("Create the bot, send /start in its private chat, then connect the token.")
|
|
11
|
+
let connectionBadge = ControlKit.badge("Telegram connection not checked", tone: .neutral)
|
|
12
|
+
let connectionStatus = NativeView.detail("Connection details are loading…")
|
|
13
|
+
let hubBadge = ControlKit.badge("Telegram Hub not checked", tone: .neutral)
|
|
14
|
+
let hubStatus = NativeView.detail("Complete setup to use the local Hub.")
|
|
15
|
+
let liveSourceBadge = ControlKit.badge("Codex thread not loaded", tone: .neutral)
|
|
16
|
+
let snapshotStatus = NativeView.detail("Conversation and public work activity have not been loaded.")
|
|
17
|
+
let sessionPicker = NSPopUpButton()
|
|
18
|
+
let conversationView = RemoteTelegramViewController.readOnlyTextView(
|
|
19
|
+
label: "Telegram Codex conversation history"
|
|
20
|
+
)
|
|
21
|
+
let activityView = RemoteTelegramViewController.readOnlyTextView(
|
|
22
|
+
label: "Telegram Codex live public activity"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
var setupCard: NSView!
|
|
26
|
+
var connectedCard: NSView!
|
|
27
|
+
var workspaceCard: NSView!
|
|
28
|
+
var generation = 0
|
|
29
|
+
var snapshotGeneration = 0
|
|
30
|
+
var liveGeneration = 0
|
|
31
|
+
var busy = false
|
|
32
|
+
var statusInFlight = false
|
|
33
|
+
var snapshotInFlight = false
|
|
34
|
+
var liveInFlight = false
|
|
35
|
+
var setupReady = false
|
|
36
|
+
var hubRunning = false
|
|
37
|
+
var deadLetterIngressCount = 0
|
|
38
|
+
var selectedSessionId: String?
|
|
39
|
+
var registeredSessionCount = 0
|
|
40
|
+
var conversationCursor: String?
|
|
41
|
+
var conversationSortDirection = "desc"
|
|
42
|
+
var isViewingLatestConversationPage = true
|
|
43
|
+
var olderConversationCursor: String?
|
|
44
|
+
var olderConversationSortDirection = "desc"
|
|
45
|
+
var newerConversationCursor: String?
|
|
46
|
+
var newerConversationSortDirection = "asc"
|
|
47
|
+
var loadedSessionId: String?
|
|
48
|
+
var loadedConversationRevision: String?
|
|
49
|
+
var loadedLiveActivityDigest: String?
|
|
50
|
+
var liveTriggeredConversationRevision: String?
|
|
51
|
+
var loadedTranscriptRows: [[String: Any]] = []
|
|
52
|
+
var loadedHistoryActivityRows: [[String: Any]] = []
|
|
53
|
+
var loadedLiveActivityRows: [[String: Any]] = []
|
|
54
|
+
var loadedThreadId: String?
|
|
55
|
+
var loadedThreadStatus = "unknown"
|
|
56
|
+
var loadedConversationPageTurnCount = 0
|
|
57
|
+
var loadedSnapshotTruncated = false
|
|
58
|
+
var loadedLiveActivityState = "pending"
|
|
59
|
+
var loadedLiveActivityError: String?
|
|
60
|
+
var renderedTranscriptSignature: String?
|
|
61
|
+
var renderedActivitySignature: String?
|
|
62
|
+
var liveSourceFileSignature: String?
|
|
63
|
+
var liveCatchUpInProgress = false
|
|
64
|
+
var liveTimer: Timer?
|
|
65
|
+
|
|
66
|
+
var checkButton: NSButton!
|
|
67
|
+
private var snapshotRefreshButton: NSButton!
|
|
68
|
+
private var olderConversationButton: NSButton!
|
|
69
|
+
private var newerConversationButton: NSButton!
|
|
70
|
+
private var latestConversationButton: NSButton!
|
|
71
|
+
private var setupBotFatherButton: NSButton!
|
|
72
|
+
private var setupConnectButton: NSButton!
|
|
73
|
+
private var connectedBotFatherButton: NSButton!
|
|
74
|
+
private var reconnectButton: NSButton!
|
|
15
75
|
private var startButton: NSButton!
|
|
16
76
|
private var stopButton: NSButton!
|
|
17
77
|
private var restartButton: NSButton!
|
|
78
|
+
private var acknowledgeDeadLettersButton: NSButton!
|
|
18
79
|
|
|
19
|
-
init(
|
|
80
|
+
init(
|
|
81
|
+
processClient: ProcessClient,
|
|
82
|
+
hubSupervisor: TelegramHubSupervisor,
|
|
83
|
+
operations: OperationCoordinator
|
|
84
|
+
) {
|
|
20
85
|
self.processClient = processClient
|
|
86
|
+
self.hubSupervisor = hubSupervisor
|
|
21
87
|
self.operations = operations
|
|
22
88
|
super.init(nibName: nil, bundle: nil)
|
|
23
89
|
}
|
|
24
90
|
required init?(coder: NSCoder) { nil }
|
|
25
91
|
|
|
92
|
+
deinit {
|
|
93
|
+
liveTimer?.invalidate()
|
|
94
|
+
}
|
|
95
|
+
|
|
26
96
|
override func loadView() {
|
|
27
|
-
|
|
97
|
+
for label in [setupStatus, connectionStatus, hubStatus, snapshotStatus, readinessStatus] {
|
|
98
|
+
label.textColor = .labelColor
|
|
99
|
+
label.alignment = .left
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
checkButton = NativeView.button("Refresh All", target: self, action: #selector(check))
|
|
103
|
+
snapshotRefreshButton = NativeView.button("Refresh Conversation", target: self, action: #selector(refreshSnapshotManually))
|
|
104
|
+
olderConversationButton = NativeView.button("Older", target: self, action: #selector(showOlderConversationPage))
|
|
105
|
+
newerConversationButton = NativeView.button("Newer", target: self, action: #selector(showNewerConversationPage))
|
|
106
|
+
latestConversationButton = NativeView.button("Latest", target: self, action: #selector(showLatestConversationPage))
|
|
107
|
+
setupBotFatherButton = ControlKit.primaryButton("Open @BotFather", target: self, action: #selector(openBotFather))
|
|
108
|
+
setupConnectButton = NativeView.button("Connect This Project…", target: self, action: #selector(connectBot))
|
|
109
|
+
connectedBotFatherButton = NativeView.button("Open @BotFather", target: self, action: #selector(openBotFather))
|
|
110
|
+
reconnectButton = NativeView.button("Reconnect / Rotate Token…", target: self, action: #selector(connectBot))
|
|
28
111
|
startButton = NativeView.button("Start Hub", target: self, action: #selector(startHub))
|
|
29
112
|
stopButton = NativeView.button("Stop Hub", target: self, action: #selector(stopHub))
|
|
30
113
|
restartButton = NativeView.button("Restart Hub", target: self, action: #selector(restartHub))
|
|
31
|
-
|
|
114
|
+
acknowledgeDeadLettersButton = NativeView.button(
|
|
115
|
+
"Acknowledge Failed Ingress…",
|
|
116
|
+
target: self,
|
|
117
|
+
action: #selector(acknowledgeDeadLetters)
|
|
118
|
+
)
|
|
32
119
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
120
|
+
setupBotFatherButton.setAccessibilityHelp("Open Telegram BotFather to create or manage the private bot.")
|
|
121
|
+
setupConnectButton.setAccessibilityHelp("Paste the BotFather token securely and register this project.")
|
|
122
|
+
reconnectButton.setAccessibilityHelp("Stop the Hub first, then reconnect the bot or rotate its token.")
|
|
123
|
+
acknowledgeDeadLettersButton.setAccessibilityHelp(
|
|
124
|
+
"After the Hub is stopped, retire failed ingress metadata so the request can be resent from Telegram."
|
|
37
125
|
)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
126
|
+
olderConversationButton.setAccessibilityHelp("Load the next older page from the complete stored Codex conversation.")
|
|
127
|
+
newerConversationButton.setAccessibilityHelp("Load the next newer page from the complete stored Codex conversation.")
|
|
128
|
+
latestConversationButton.setAccessibilityHelp("Return to the live latest page and resume automatic refresh.")
|
|
129
|
+
sessionPicker.target = self
|
|
130
|
+
sessionPicker.action = #selector(sessionChanged)
|
|
131
|
+
sessionPicker.setAccessibilityLabel("Registered Telegram coding session")
|
|
132
|
+
sessionPicker.widthAnchor.constraint(greaterThanOrEqualToConstant: 260).isActive = true
|
|
133
|
+
|
|
134
|
+
let setupSteps = NSStackView(views: [
|
|
135
|
+
guideStep("1", title: "Create the bot", detail: "Open @BotFather, send /newbot, and copy the HTTP API token."),
|
|
136
|
+
guideStep("2", title: "Pair your account", detail: "Open the new bot in a private chat and send /start."),
|
|
137
|
+
guideStep("3", title: "Connect this project", detail: "Paste the token here. SKS verifies one private chat/user and stores the token only in macOS Keychain.")
|
|
138
|
+
])
|
|
139
|
+
setupSteps.orientation = .vertical; setupSteps.alignment = .leading; setupSteps.spacing = 9
|
|
140
|
+
for step in setupSteps.arrangedSubviews { step.widthAnchor.constraint(equalTo: setupSteps.widthAnchor).isActive = true }
|
|
141
|
+
setupCard = NativeView.card(
|
|
142
|
+
title: "Connect Telegram in 3 steps",
|
|
143
|
+
subtitle: "This creates one private, project-scoped Telegram coding session. SKS never puts the bot token in arguments, project config, or logs.",
|
|
144
|
+
views: [
|
|
145
|
+
setupBadge,
|
|
146
|
+
setupStatus,
|
|
147
|
+
setupSteps,
|
|
148
|
+
ControlKit.actionRow([setupBotFatherButton, setupConnectButton])
|
|
149
|
+
],
|
|
150
|
+
fullWidthLeadingContent: true
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
let sessionLabel = NSTextField(labelWithString: "Coding session")
|
|
154
|
+
sessionLabel.font = NSFont.systemFont(ofSize: 12, weight: .medium)
|
|
155
|
+
sessionLabel.textColor = .secondaryLabelColor
|
|
156
|
+
sessionLabel.setContentHuggingPriority(.required, for: .horizontal)
|
|
157
|
+
let sessionRow = ControlKit.actionRow([sessionLabel, sessionPicker])
|
|
158
|
+
connectedCard = NativeView.card(
|
|
159
|
+
title: "Telegram connected",
|
|
160
|
+
subtitle: "Plain text from the paired private chat continues this project's dedicated Codex thread.",
|
|
161
|
+
views: [
|
|
162
|
+
connectionBadge,
|
|
163
|
+
connectionStatus,
|
|
164
|
+
sessionRow,
|
|
165
|
+
hubBadge,
|
|
166
|
+
hubStatus,
|
|
167
|
+
ControlKit.actionRow([startButton, stopButton, restartButton]),
|
|
168
|
+
ControlKit.actionRow([acknowledgeDeadLettersButton]),
|
|
169
|
+
ControlKit.actionRow([connectedBotFatherButton, reconnectButton])
|
|
170
|
+
],
|
|
171
|
+
fullWidthLeadingContent: true
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
let conversationScroll = textArea(conversationView, height: 210)
|
|
175
|
+
let activityScroll = textArea(activityView, height: 150)
|
|
176
|
+
let conversationTitle = NativeView.sectionTitle("Conversation history")
|
|
177
|
+
let conversationPageRow = ControlKit.actionRow(
|
|
178
|
+
[conversationTitle],
|
|
179
|
+
trailing: [olderConversationButton, newerConversationButton, latestConversationButton]
|
|
180
|
+
)
|
|
181
|
+
let activityTitle = NativeView.sectionTitle("Live public activity")
|
|
182
|
+
workspaceCard = NativeView.card(
|
|
183
|
+
title: "Connected Codex thread",
|
|
184
|
+
subtitle: "Browse the real Telegram-bound Codex conversation and bounded public activity. Latest checks local journal files every 2.5 seconds and refreshes only after a change; reasoning, raw tool output, and credentials stay private.",
|
|
185
|
+
views: [
|
|
186
|
+
ControlKit.actionRow([liveSourceBadge], trailing: [snapshotRefreshButton]),
|
|
187
|
+
snapshotStatus,
|
|
188
|
+
conversationPageRow,
|
|
189
|
+
conversationScroll,
|
|
190
|
+
activityTitle,
|
|
191
|
+
activityScroll
|
|
192
|
+
],
|
|
193
|
+
fullWidthLeadingContent: true
|
|
42
194
|
)
|
|
195
|
+
|
|
196
|
+
let usageSteps = NSStackView(views: [
|
|
197
|
+
guideStep(
|
|
198
|
+
"1",
|
|
199
|
+
title: "Send a coding request",
|
|
200
|
+
detail: "Type ordinary text in the paired private chat. It starts or resumes only this project's dedicated Codex thread."
|
|
201
|
+
),
|
|
202
|
+
guideStep(
|
|
203
|
+
"2",
|
|
204
|
+
title: "Follow the real Codex work",
|
|
205
|
+
detail: "Conversation history shows stored user and assistant messages. Latest also follows bounded public tool, file, search, subagent, and turn activity."
|
|
206
|
+
),
|
|
207
|
+
guideStep(
|
|
208
|
+
"3",
|
|
209
|
+
title: "Receive and control the result",
|
|
210
|
+
detail: "SKS waits for the turn and sends Codex's final response back to Telegram. Use the commands below for status and guarded actions."
|
|
211
|
+
)
|
|
212
|
+
])
|
|
213
|
+
usageSteps.orientation = .vertical; usageSteps.alignment = .leading; usageSteps.spacing = 9
|
|
214
|
+
for step in usageSteps.arrangedSubviews { step.widthAnchor.constraint(equalTo: usageSteps.widthAnchor).isActive = true }
|
|
215
|
+
let readCommandGuide = NativeView.detail("/status /tail /diff /gates /trust /proof /artifacts")
|
|
216
|
+
readCommandGuide.font = NSFont.monospacedSystemFont(ofSize: 11, weight: .regular); readCommandGuide.setAccessibilityLabel("Read-only Telegram commands")
|
|
217
|
+
let actionCommandGuide = NativeView.detail("/input <text> /verify /cancel /refresh /open")
|
|
218
|
+
actionCommandGuide.font = NSFont.monospacedSystemFont(ofSize: 11, weight: .regular)
|
|
219
|
+
actionCommandGuide.setAccessibilityLabel("Telegram action commands")
|
|
43
220
|
let usageCard = NativeView.card(
|
|
44
|
-
title: "
|
|
45
|
-
subtitle: "Send ordinary text
|
|
46
|
-
views: [
|
|
221
|
+
title: "How to use it",
|
|
222
|
+
subtitle: "Send ordinary text to continue the linked Codex conversation; no special command is required for everyday coding requests.",
|
|
223
|
+
views: [
|
|
224
|
+
usageSteps,
|
|
225
|
+
NativeView.sectionTitle("Useful bot commands"),
|
|
226
|
+
readCommandGuide,
|
|
227
|
+
actionCommandGuide,
|
|
228
|
+
NativeView.detail("Read commands inspect the linked project without starting arbitrary shell access. /cancel remains owner-proof guarded; unpaired chats stay blocked.")
|
|
229
|
+
],
|
|
230
|
+
fullWidthLeadingContent: true
|
|
47
231
|
)
|
|
48
232
|
let readinessCard = NativeView.card(
|
|
49
233
|
title: "Project readiness",
|
|
50
|
-
subtitle: "Codex
|
|
51
|
-
views: [readinessStatus]
|
|
234
|
+
subtitle: "Codex App, CLI, and Git state for this project.",
|
|
235
|
+
views: [readinessStatus],
|
|
236
|
+
fullWidthLeadingContent: true
|
|
52
237
|
)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
238
|
+
|
|
239
|
+
let page = NativeView.page([
|
|
240
|
+
ControlKit.header("Remote & Telegram", "Code through a private BotFather bot and inspect the exact linked Codex conversation in SKS Center."),
|
|
241
|
+
ControlKit.actionRow([], trailing: [checkButton]),
|
|
242
|
+
connectedCard,
|
|
243
|
+
setupCard,
|
|
244
|
+
workspaceCard,
|
|
245
|
+
usageCard,
|
|
246
|
+
readinessCard
|
|
57
247
|
])
|
|
248
|
+
view = page
|
|
249
|
+
renderVisibility()
|
|
250
|
+
renderConversationPlaceholder("Connect Telegram to load a Codex conversation.")
|
|
251
|
+
renderActivityPlaceholder("Public work activity will appear after a linked Codex turn starts.")
|
|
58
252
|
updateButtons()
|
|
59
|
-
check()
|
|
60
253
|
}
|
|
61
254
|
|
|
62
|
-
func refreshOnAppear() {
|
|
255
|
+
func refreshOnAppear() {
|
|
256
|
+
startLivePolling()
|
|
257
|
+
checkStatus(refreshConversation: loadedSessionId == nil)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@objc private func openBotFather() {
|
|
261
|
+
guard let url = URL(string: "https://t.me/BotFather") else { return }
|
|
262
|
+
NSWorkspace.shared.open(url)
|
|
263
|
+
}
|
|
63
264
|
|
|
64
265
|
@objc private func connectBot() {
|
|
65
266
|
guard let window = view.window else { return }
|
|
66
267
|
AlertFactory.textSheet(
|
|
67
268
|
window: window,
|
|
68
269
|
title: "Telegram Bot Token",
|
|
69
|
-
message: "First send /start to your bot from the private Telegram account you want to pair. Paste the BotFather token below. It is sent through stdin, stored in macOS Keychain, and never logged.",
|
|
270
|
+
message: "First send /start to your bot from the private Telegram account you want to pair. Paste the current BotFather token below. It is sent through stdin, verified, stored in macOS Keychain, and never logged.",
|
|
70
271
|
secure: true,
|
|
71
|
-
placeholder: "123456789:ABC…"
|
|
272
|
+
placeholder: "123456789:ABC…",
|
|
273
|
+
actionTitle: "Connect"
|
|
72
274
|
) { [weak self] token in
|
|
73
275
|
guard let self = self, let token = token else { return }
|
|
74
276
|
self.runMutation(
|
|
@@ -81,58 +283,115 @@ final class RemoteTelegramViewController: NSViewController, ControlCenterPage {
|
|
|
81
283
|
}
|
|
82
284
|
|
|
83
285
|
@objc private func startHub() {
|
|
84
|
-
|
|
85
|
-
args: ["telegram", "hub", "start", "--project-root", AppRuntime.projectRoot, "--json"],
|
|
286
|
+
runHubMutation(
|
|
86
287
|
kind: "telegram-hub-start",
|
|
87
|
-
summary: "Start Telegram Hub"
|
|
288
|
+
summary: "Start Telegram Hub",
|
|
289
|
+
action: hubSupervisor.start
|
|
88
290
|
)
|
|
89
291
|
}
|
|
90
292
|
|
|
91
293
|
@objc private func stopHub() {
|
|
92
|
-
|
|
93
|
-
args: ["telegram", "hub", "stop", "--project-root", AppRuntime.projectRoot, "--json"],
|
|
294
|
+
runHubMutation(
|
|
94
295
|
kind: "telegram-hub-stop",
|
|
95
|
-
summary: "Stop Telegram Hub"
|
|
296
|
+
summary: "Stop Telegram Hub",
|
|
297
|
+
action: hubSupervisor.stop
|
|
96
298
|
)
|
|
97
299
|
}
|
|
98
300
|
|
|
99
301
|
@objc private func restartHub() {
|
|
100
|
-
|
|
101
|
-
args: ["telegram", "hub", "restart", "--project-root", AppRuntime.projectRoot, "--json"],
|
|
302
|
+
runHubMutation(
|
|
102
303
|
kind: "telegram-hub-restart",
|
|
103
|
-
summary: "Restart Telegram Hub"
|
|
304
|
+
summary: "Restart Telegram Hub",
|
|
305
|
+
action: hubSupervisor.restart
|
|
104
306
|
)
|
|
105
307
|
}
|
|
106
308
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
var remote: [String: Any]?
|
|
116
|
-
var telegram: [String: Any]?
|
|
117
|
-
let group = DispatchGroup()
|
|
118
|
-
group.enter()
|
|
119
|
-
processClient.run(["remote", "readiness", "--project-root", AppRuntime.projectRoot, "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
|
|
120
|
-
remote = self?.json(result.output)
|
|
121
|
-
group.leave()
|
|
309
|
+
private func runHubMutation(
|
|
310
|
+
kind: String,
|
|
311
|
+
summary: String,
|
|
312
|
+
action: (@escaping (Bool) -> Void) -> Void
|
|
313
|
+
) {
|
|
314
|
+
guard !busy else {
|
|
315
|
+
hubStatus.stringValue = "Another Telegram operation is already running."
|
|
316
|
+
return
|
|
122
317
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
group.leave()
|
|
318
|
+
guard let operation = operations.begin(kind: kind, mutationGroup: "telegram", summary: summary) else {
|
|
319
|
+
hubStatus.stringValue = "Another guarded mutation is already running. Wait or open Diagnostics."
|
|
320
|
+
return
|
|
127
321
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
322
|
+
setBusy(true)
|
|
323
|
+
_ = operations.update(operation, state: .running, stage: "running", progress: nil, summary: summary)
|
|
324
|
+
ControlKit.setBadge(hubBadge, text: "\(summary)…", tone: .busy)
|
|
325
|
+
hubStatus.stringValue = "\(summary)…"
|
|
326
|
+
action { [weak self] ok in
|
|
327
|
+
guard let self = self else { return }
|
|
328
|
+
_ = self.operations.update(
|
|
329
|
+
operation,
|
|
330
|
+
state: ok ? .succeeded : .failed,
|
|
331
|
+
stage: "complete",
|
|
332
|
+
progress: 1,
|
|
333
|
+
summary: ok ? "\(summary) completed" : "\(summary) failed"
|
|
334
|
+
)
|
|
335
|
+
self.setBusy(false)
|
|
336
|
+
if !ok {
|
|
337
|
+
ControlKit.setBadge(self.hubBadge, text: "Telegram Hub action failed", tone: .error)
|
|
338
|
+
self.hubStatus.stringValue = "\(summary) failed. Open Diagnostics and retry."
|
|
339
|
+
}
|
|
340
|
+
self.checkStatus(refreshConversation: false)
|
|
341
|
+
if ok {
|
|
342
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 3) { [weak self] in
|
|
343
|
+
self?.checkStatus(refreshConversation: false)
|
|
344
|
+
}
|
|
345
|
+
}
|
|
132
346
|
}
|
|
133
347
|
}
|
|
134
348
|
|
|
135
|
-
private func
|
|
349
|
+
@objc private func check() {
|
|
350
|
+
checkStatus(refreshConversation: true)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
@objc private func refreshSnapshotManually() {
|
|
354
|
+
refreshSnapshot(force: true)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@objc private func sessionChanged() {
|
|
358
|
+
guard let item = sessionPicker.selectedItem,
|
|
359
|
+
let sessionId = item.representedObject as? String,
|
|
360
|
+
!sessionId.isEmpty else { return }
|
|
361
|
+
guard sessionId != selectedSessionId || loadedSessionId != sessionId else { return }
|
|
362
|
+
selectedSessionId = sessionId
|
|
363
|
+
invalidateCenterRequests()
|
|
364
|
+
clearLoadedCenterState()
|
|
365
|
+
resetConversationPagination()
|
|
366
|
+
ControlKit.setBadge(liveSourceBadge, text: "Loading selected Codex thread…", tone: .busy)
|
|
367
|
+
snapshotStatus.stringValue = "Reading the selected session’s conversation and bounded public activity…"
|
|
368
|
+
renderConversationPlaceholder("Loading the selected Codex conversation…")
|
|
369
|
+
renderActivityPlaceholder("Loading the selected session’s public activity…")
|
|
370
|
+
refreshSnapshot(force: true)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
@objc private func showOlderConversationPage() {
|
|
374
|
+
guard let cursor = olderConversationCursor else { return }
|
|
375
|
+
conversationCursor = cursor
|
|
376
|
+
conversationSortDirection = olderConversationSortDirection
|
|
377
|
+
isViewingLatestConversationPage = false
|
|
378
|
+
refreshSnapshot(force: true)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
@objc private func showNewerConversationPage() {
|
|
382
|
+
guard let cursor = newerConversationCursor else { return }
|
|
383
|
+
conversationCursor = cursor
|
|
384
|
+
conversationSortDirection = newerConversationSortDirection
|
|
385
|
+
isViewingLatestConversationPage = false
|
|
386
|
+
refreshSnapshot(force: true)
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
@objc private func showLatestConversationPage() {
|
|
390
|
+
resetConversationPagination()
|
|
391
|
+
refreshSnapshot(force: true)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
func runMutation(args: [String], stdin: String? = nil, kind: String, summary: String) {
|
|
136
395
|
guard !busy else {
|
|
137
396
|
hubStatus.stringValue = "Another Telegram operation is already running."
|
|
138
397
|
return
|
|
@@ -143,7 +402,14 @@ final class RemoteTelegramViewController: NSViewController, ControlCenterPage {
|
|
|
143
402
|
}
|
|
144
403
|
setBusy(true)
|
|
145
404
|
_ = operations.update(operation, state: .running, stage: "running", progress: nil, summary: summary)
|
|
146
|
-
|
|
405
|
+
if kind == "telegram-setup" {
|
|
406
|
+
ControlKit.setBadge(setupReady ? connectionBadge : setupBadge, text: "Connecting Telegram…", tone: .busy)
|
|
407
|
+
if setupReady { connectionStatus.stringValue = "\(summary)…" }
|
|
408
|
+
else { setupStatus.stringValue = "\(summary)…" }
|
|
409
|
+
} else {
|
|
410
|
+
ControlKit.setBadge(hubBadge, text: "\(summary)…", tone: .busy)
|
|
411
|
+
hubStatus.stringValue = "\(summary)…"
|
|
412
|
+
}
|
|
147
413
|
processClient.run(args, stdin: stdin, timeout: NativeView.mutationTimeout) { [weak self] result in
|
|
148
414
|
guard let self = self else { return }
|
|
149
415
|
let ok = result.code == 0
|
|
@@ -156,15 +422,17 @@ final class RemoteTelegramViewController: NSViewController, ControlCenterPage {
|
|
|
156
422
|
)
|
|
157
423
|
self.setBusy(false)
|
|
158
424
|
if !ok {
|
|
159
|
-
// Route setup failures to the setup card so the guidance sits
|
|
160
|
-
// next to the Connect button instead of the Hub status line.
|
|
161
425
|
if kind == "telegram-setup" {
|
|
162
|
-
self.
|
|
426
|
+
ControlKit.setBadge(self.setupReady ? self.connectionBadge : self.setupBadge, text: "Telegram setup needs attention", tone: .error)
|
|
427
|
+
let message = self.setupFailureMessage(result.output)
|
|
428
|
+
if self.setupReady { self.connectionStatus.stringValue = message }
|
|
429
|
+
else { self.setupStatus.stringValue = message }
|
|
163
430
|
} else {
|
|
431
|
+
ControlKit.setBadge(self.hubBadge, text: "Telegram Hub action failed", tone: .error)
|
|
164
432
|
self.hubStatus.stringValue = "\(summary) failed · \(NativeView.redactPreview(result.output))"
|
|
165
433
|
}
|
|
166
434
|
}
|
|
167
|
-
self.
|
|
435
|
+
if ok { self.checkStatus(refreshConversation: kind == "telegram-setup") }
|
|
168
436
|
}
|
|
169
437
|
}
|
|
170
438
|
|
|
@@ -173,49 +441,30 @@ final class RemoteTelegramViewController: NSViewController, ControlCenterPage {
|
|
|
173
441
|
updateButtons()
|
|
174
442
|
}
|
|
175
443
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
444
|
+
func updateButtons() {
|
|
445
|
+
let controlsBusy = busy || statusInFlight
|
|
446
|
+
setupBotFatherButton?.isEnabled = !busy
|
|
447
|
+
connectedBotFatherButton?.isEnabled = !busy
|
|
448
|
+
setupConnectButton?.isEnabled = !busy && !hubRunning
|
|
449
|
+
reconnectButton?.isEnabled = !busy && !hubRunning
|
|
450
|
+
startButton?.isEnabled = !controlsBusy && setupReady && !hubRunning
|
|
451
|
+
stopButton?.isEnabled = !controlsBusy && hubRunning
|
|
452
|
+
restartButton?.isEnabled = !controlsBusy && setupReady && hubRunning
|
|
453
|
+
acknowledgeDeadLettersButton?.isEnabled = !controlsBusy
|
|
454
|
+
&& setupReady
|
|
455
|
+
&& !hubRunning
|
|
456
|
+
&& deadLetterIngressCount > 0
|
|
457
|
+
checkButton?.isEnabled = !controlsBusy
|
|
458
|
+
snapshotRefreshButton?.isEnabled = !busy && setupReady && !snapshotInFlight
|
|
459
|
+
olderConversationButton?.isEnabled = !busy && setupReady && !snapshotInFlight && olderConversationCursor != nil
|
|
460
|
+
newerConversationButton?.isEnabled = !busy && setupReady && !snapshotInFlight && newerConversationCursor != nil
|
|
461
|
+
latestConversationButton?.isEnabled = !busy && setupReady && !snapshotInFlight && !isViewingLatestConversationPage
|
|
462
|
+
sessionPicker.isEnabled = !busy && setupReady && !snapshotInFlight && registeredSessionCount > 0
|
|
463
|
+
startButton?.isHidden = !setupReady || hubRunning
|
|
464
|
+
stopButton?.isHidden = !hubRunning
|
|
465
|
+
restartButton?.isHidden = !hubRunning
|
|
466
|
+
acknowledgeDeadLettersButton?.isHidden = deadLetterIngressCount == 0
|
|
467
|
+
reconnectButton?.isHidden = hubRunning
|
|
182
468
|
}
|
|
183
469
|
|
|
184
|
-
private func render(remote: [String: Any]?, telegram: [String: Any]?) {
|
|
185
|
-
if let remote = remote {
|
|
186
|
-
let host = remote["host"] as? [String: Any]
|
|
187
|
-
let project = remote["project"] as? [String: Any]
|
|
188
|
-
let blockers = remote["blockers"] as? [String] ?? []
|
|
189
|
-
readinessStatus.stringValue = "Project readiness: \(remote["ok"] as? Bool == true ? "Ready" : "Needs attention") · Codex app \(host?["codex_app_found"] as? Bool == true ? "found" : "missing") · CLI \(host?["codex_cli_found"] as? Bool == true ? "found" : "missing") · Git \(project?["git_repo"] as? Bool == true ? "ready" : "missing")" + (blockers.isEmpty ? "" : " · \(blockers.prefix(2).joined(separator: "; "))")
|
|
190
|
-
} else {
|
|
191
|
-
readinessStatus.stringValue = "Project readiness is unavailable. Open Diagnostics for the redacted log."
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
guard let telegram = telegram else {
|
|
195
|
-
setupReady = false
|
|
196
|
-
hubRunning = false
|
|
197
|
-
setupStatus.stringValue = "Telegram setup status is unavailable."
|
|
198
|
-
hubStatus.stringValue = "Telegram Hub status is unavailable."
|
|
199
|
-
return
|
|
200
|
-
}
|
|
201
|
-
let token = telegram["token_configured"] as? Bool == true
|
|
202
|
-
let pairing = telegram["pairing_valid"] as? Bool == true
|
|
203
|
-
let sessions = telegram["registered_session_count"] as? Int ?? 0
|
|
204
|
-
setupReady = token && pairing && sessions > 0
|
|
205
|
-
hubRunning = telegram["hub_running"] as? Bool == true
|
|
206
|
-
setupStatus.stringValue = "Keychain token \(token ? "ready" : "missing") · private pairing \(pairing ? "ready" : "missing") · dedicated Codex sessions \(sessions)" + (setupReady ? " · ready to start" : " · connect the bot to continue")
|
|
207
|
-
let service = telegram["service"] as? [String: Any]
|
|
208
|
-
let installed = service?["installed"] as? Bool == true
|
|
209
|
-
let state = service?["state"] as? String
|
|
210
|
-
hubStatus.stringValue = "Hub \(hubRunning ? "Running" : installed ? "Stopped" : "Not installed")" + (state.map { " · launchd \($0)" } ?? "") + (hubRunning ? " · send a Telegram message to code" : setupReady ? " · click Start Hub" : "")
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private func json(_ text: String) -> [String: Any]? {
|
|
214
|
-
guard let data = text.data(using: .utf8) else { return nil }
|
|
215
|
-
if let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { return object }
|
|
216
|
-
guard let start = text.range(of: "{", options: [.backwards])?.lowerBound else { return nil }
|
|
217
|
-
let slice = String(text[start...])
|
|
218
|
-
guard let sliced = slice.data(using: .utf8) else { return nil }
|
|
219
|
-
return try? JSONSerialization.jsonObject(with: sliced) as? [String: Any]
|
|
220
|
-
}
|
|
221
470
|
}
|