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.
- package/README.md +150 -37
- package/config/skills-hash-ledger.v1.json +1 -1
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +55 -27
- package/dist/bin/install.js +6 -32
- package/dist/bin/sks-dispatch.js +1 -1
- package/dist/cli/args.js +0 -2
- package/dist/cli/cli-theme.js +18 -9
- package/dist/cli/command-manifest-lite.js +6 -6
- package/dist/cli/command-registry.js +6 -6
- package/dist/cli/feature-commands.js +9 -7
- package/dist/cli/install-helpers-codex-lb-chain.js +198 -7
- package/dist/cli/install-helpers-codex-lb-config.js +78 -10
- package/dist/cli/install-helpers-install-support.js +9 -6
- package/dist/cli/install-helpers.js +101 -49
- package/dist/cli/install-tool-helpers.js +2 -82
- package/dist/cli/output.js +6 -1
- package/dist/cli/router.js +101 -2
- package/dist/commands/codex-lb.js +119 -19
- package/dist/commands/doctor-profile.js +1 -1
- package/dist/commands/doctor.js +727 -144
- package/dist/commands/mad-sks.js +1 -5
- package/dist/config/skills-manifest.json +4 -2
- package/dist/core/agents/agent-codex-cockpit.js +0 -3
- package/dist/core/agents/agent-effort-policy.js +5 -5
- package/dist/core/agents/agent-janitor.js +0 -20
- package/dist/core/agents/agent-orchestrator.js +9 -56
- package/dist/core/agents/agent-output-validator.js +2 -3
- package/dist/core/agents/agent-patch-schema.js +2 -2
- package/dist/core/agents/agent-proof-evidence.js +0 -65
- package/dist/core/agents/agent-recursion-guard.js +1 -1
- package/dist/core/agents/agent-runner-codex-exec.js +5 -3
- package/dist/core/agents/agent-scheduler.js +327 -85
- package/dist/core/agents/agent-schema.js +1 -1
- package/dist/core/agents/agent-trust-report.js +0 -36
- package/dist/core/agents/agent-worker-pipeline.js +0 -1
- package/dist/core/agents/fast-mode-policy.js +1 -3
- package/dist/core/agents/native-cli-worker-runtime-proof.js +1 -1
- package/dist/core/agents/native-cli-worker-runtime.js +69 -647
- package/dist/core/agents/native-cli-worker.js +6 -7
- package/dist/core/agents/native-worker-backend-router.js +2 -32
- package/dist/core/agents/no-subagent-scaling-policy.js +1 -1
- package/dist/core/agents/parallel-runtime-proof.js +1 -6
- package/dist/core/agents/runtime-proof-summary.js +1 -35
- package/dist/core/architecture-hardening/contracts/contracts.js +193 -0
- package/dist/core/architecture-hardening/migration/migration.js +111 -0
- package/dist/core/architecture-hardening/state/state-service.js +155 -0
- package/dist/core/artifact-schemas.js +0 -3
- package/dist/core/codex/codex-config-guard.js +238 -52
- package/dist/core/codex-adapter.js +5 -3
- package/dist/core/codex-app/auxiliary-oauth-policy.js +36 -0
- package/dist/core/codex-app/catalog-compat/catalog-service.js +104 -0
- package/dist/core/codex-app/child-policy/child-policy.js +35 -0
- package/dist/core/codex-app/codex-app-handoff.js +0 -1
- package/dist/core/codex-app/codex-hook-lifecycle.js +1 -1
- package/dist/core/codex-app/codex-init-deep.js +1 -1
- package/dist/core/codex-app/menubar/app-bundle.js +2 -0
- package/dist/core/codex-app/menubar/constants.js +14 -1
- package/dist/core/codex-app/menubar/global-install.js +288 -0
- package/dist/core/codex-app/menubar/installer.js +79 -14
- package/dist/core/codex-app/menubar/launch-agent.js +267 -45
- package/dist/core/codex-app/menubar/paths.js +3 -0
- package/dist/core/codex-app/menubar/rollback.js +55 -7
- package/dist/core/codex-app/menubar/status.js +75 -4
- package/dist/core/codex-app/provider-child-policy.js +64 -0
- package/dist/core/codex-app/provider-mode.js +91 -0
- package/dist/core/codex-app/provider-operation-stages.js +20 -0
- package/dist/core/codex-app/provider-session-policy.js +85 -0
- package/dist/core/codex-app/session-policy/session-pinning.js +68 -0
- package/dist/core/codex-app.js +3 -2
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +3 -1
- package/dist/core/codex-control/codex-0139-web-search-probe.js +3 -1
- package/dist/core/codex-control/codex-app-server-runtime-env.js +13 -4
- package/dist/core/codex-control/codex-app-server-v2-client.js +3 -3
- package/dist/core/codex-control/codex-control-proof.js +0 -1
- package/dist/core/codex-control/codex-task-runner.js +1 -4
- package/dist/core/codex-exec-output-schema.js +4 -1
- package/dist/core/codex-lb/codex-lb-env.js +63 -72
- package/dist/core/codex-lb/codex-lb-setup.js +15 -2
- package/dist/core/codex-lb/desktop-bridge/header-policy.js +6 -0
- package/dist/core/codex-lb/desktop-bridge/http-forward.js +48 -6
- package/dist/core/codex-lb/desktop-bridge/security.js +134 -0
- package/dist/core/codex-lb/desktop-bridge/server.js +9 -3
- package/dist/core/codex-lb/desktop-bridge/state.js +26 -6
- package/dist/core/codex-lb/desktop-bridge/types.js +1 -0
- package/dist/core/codex-lb/desktop-center-credentials.js +517 -58
- package/dist/core/codex-lb/desktop-controller.js +177 -56
- package/dist/core/codex-lb/desktop-service.js +179 -40
- package/dist/core/codex-lb/legacy-migration.js +1 -3
- package/dist/core/codex-lb/native-openai-transport/transport.js +68 -0
- package/dist/core/codex-lb/probes/cli-image-tool-probe.js +1 -1
- package/dist/core/codex-lb/provider-routing/provider-router.js +58 -0
- package/dist/core/codex-lb/routing-truth.js +327 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +4 -0
- package/dist/core/codex-native/codex-native-pattern-analysis.js +1 -2
- package/dist/core/codex-native/core-skill-manifest.js +1 -1
- package/dist/core/codex-plugins/codex-plugin-json.js +26 -6
- package/dist/core/codex-plugins/codex-plugin-repair.js +32 -6
- package/dist/core/commands/basic-cli.js +9 -7
- package/dist/core/commands/computer-use-command.js +1 -1
- package/dist/core/commands/image-ux-review-command.js +16 -9
- package/dist/core/commands/install-package-command.js +105 -0
- package/dist/core/commands/intent-normalization/normalizer.js +96 -0
- package/dist/core/commands/mad-sks-command.js +23 -274
- package/dist/core/commands/mad-sks-headless.js +11 -30
- package/dist/core/commands/naruto-command.js +0 -25
- package/dist/core/commands/qa-loop-command.js +104 -22
- package/dist/core/commands/remote-command.js +2 -2
- package/dist/core/commands/research-command.js +10 -5
- package/dist/core/commands/telegram-command.js +407 -0
- package/dist/core/config-adopt/config-adopt-command.js +35 -0
- package/dist/core/config-adopt/config-adopt.js +346 -0
- package/dist/core/config-adopt/index.js +3 -0
- package/dist/core/doctor/command-alias-cleanup.js +4 -1
- package/dist/core/doctor/current-project-guidance-nested.js +37 -6
- package/dist/core/doctor/current-project-guidance.js +15 -9
- package/dist/core/doctor/doctor-dirty-planner.js +1 -4
- package/dist/core/doctor/doctor-readiness-matrix.js +15 -18
- package/dist/core/doctor/retired-managed-residue-private.js +4 -3
- package/dist/core/doctor/retired-managed-residue-runtime.js +2 -2
- package/dist/core/doctor/skill-legacy-surface.js +11 -10
- package/dist/core/doctor/sks-menubar-doctor.js +4 -0
- package/dist/core/evaluation.js +0 -19
- package/dist/core/evidence/v2/evidence-key.js +105 -0
- package/dist/core/feature-fixtures.js +12 -7
- package/dist/core/feature-registry.js +52 -21
- package/dist/core/hooks-runtime/hook-context.js +9 -0
- package/dist/core/hooks-runtime/managed-skill-admission.js +54 -4
- package/dist/core/hooks-runtime/official-subagent-lifecycle.js +69 -52
- package/dist/core/hooks-runtime/stop-finalization.js +226 -0
- package/dist/core/hooks-runtime/stop-repeat-guard.js +21 -2
- package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +2 -2
- package/dist/core/hooks-runtime/subagent-skill-availability-evidence.js +3 -3
- package/dist/core/hooks-runtime/subagent-skill-availability-guards.js +43 -5
- package/dist/core/hooks-runtime/subagent-skill-availability.js +64 -30
- package/dist/core/hooks-runtime/subagent-stop-hook.js +15 -2
- package/dist/core/hooks-runtime.js +179 -212
- package/dist/core/image/reference-evidence/reference-registry.js +145 -0
- package/dist/core/image-ux-review/imagegen-adapter.js +21 -9
- package/dist/core/image-ux-review/reference-policy/reference-policy.js +9 -0
- package/dist/core/imagegen/codex-lb-imagegen-target.js +8 -0
- package/dist/core/imagegen/imagegen-capability.js +59 -2
- package/dist/core/imagegen/require-imagegen.js +2 -2
- package/dist/core/init/skills.js +17 -3
- package/dist/core/init.js +3 -3
- package/dist/core/install/installed-package-smoke.js +23 -5
- package/dist/core/json/canonical.js +9 -0
- package/dist/core/locks/file-lock.js +0 -1
- package/dist/core/loops/loop-continuation-enforcer.js +65 -7
- package/dist/core/loops/loop-decomposer.js +0 -1
- package/dist/core/loops/loop-gate-runner.js +65 -4
- package/dist/core/loops/loop-gate-selector.js +0 -2
- package/dist/core/loops/loop-proof-validation.js +38 -0
- package/dist/core/loops/loop-risk-classifier.js +1 -1
- package/dist/core/loops/loop-runtime.js +14 -2
- package/dist/core/loops/loop-scheduler.js +7 -2
- package/dist/core/loops/loop-worker-runtime.js +0 -15
- package/dist/core/loops/loop-worktree-runtime.js +52 -4
- package/dist/core/managed-assets/managed-assets-manifest.js +14 -14
- package/dist/core/naruto/hardware-capacity-probe.js +9 -6
- package/dist/core/naruto/naruto-active-pool.js +2 -14
- package/dist/core/naruto/naruto-concurrency-governor.js +71 -31
- package/dist/core/naruto/naruto-loop-worker-router.js +0 -2
- package/dist/core/naruto/naruto-verification-dag.js +0 -1
- package/dist/core/naruto/naruto-write-e2e.js +1 -2
- package/dist/core/naruto/resource-pressure-monitor.js +0 -4
- package/dist/core/observability/architecture-hardening/safe-projection.js +65 -0
- package/dist/core/perf/import-graph-budget.js +0 -1
- package/dist/core/perf/release-latency-slo.js +3 -2
- package/dist/core/preflight/parallel-preflight-engine.js +2 -15
- package/dist/core/product-design-app-server.js +13 -1
- package/dist/core/proof/fake-real-proof-policy.js +2 -17
- package/dist/core/proof/route-proof-gate.js +2 -10
- package/dist/core/proof/route-proof-policy.js +1 -1
- package/dist/core/proof/runtime-evidence-policy.js +185 -0
- package/dist/core/proof/runtime-truth-matrix.js +64 -39
- package/dist/core/proof/validation.js +27 -11
- package/dist/core/provider/provider-context.js +18 -2
- package/dist/core/providers/openrouter/openrouter-account.js +3 -2
- package/dist/core/python-tools/python-tool-runner.js +1 -1
- package/dist/core/qa-loop/qa-execution-control.js +57 -0
- package/dist/core/questions.js +1 -1
- package/dist/core/release/extreme-parallel-scheduler.js +0 -3
- package/dist/core/release/gate-manifest.js +3 -7
- package/dist/core/release/gate-pack-manifest.js +3 -7
- package/dist/core/release/package-size-budget.js +2 -2
- package/dist/core/release/physical-release-gates.js +189 -0
- package/dist/core/release/publish-preflight.js +113 -0
- package/dist/core/release/release-gate-affected-selector.js +0 -2
- package/dist/core/release/release-gate-batch-runner.js +1 -1
- package/dist/core/release/release-gate-node.js +0 -1
- package/dist/core/release/release-gate-resource-governor.js +0 -1
- package/dist/core/release/release-pack-receipt.js +5 -8
- package/dist/core/release/release-real-contract.js +0 -6
- package/dist/core/release/resource-class-budget.js +0 -1
- package/dist/core/release/stage-publish.js +178 -36
- package/dist/core/research/research-adversarial-review.js +103 -9
- package/dist/core/research.js +1 -1
- package/dist/core/retention.js +0 -1
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/diagnostic-allowlist.js +0 -1
- package/dist/core/routes/dollar-manifest-lite.js +1 -1
- package/dist/core/routes.js +46 -15
- package/dist/core/runtime/execution-control.js +226 -0
- package/dist/core/runtime/progress-recovery/progress-recovery.js +89 -0
- package/dist/core/runtime/task-profile.js +10 -4
- package/dist/core/runtime/verification-budget.js +10 -1
- package/dist/core/safety/intent-contract/intent-contract.js +94 -0
- package/dist/core/safety/mutation-guard.js +0 -2
- package/dist/core/safety/mutation-ledger.js +0 -2
- package/dist/core/safety/requested-scope-contract.js +0 -0
- package/dist/core/search-visibility/discovery.js +1 -1
- package/dist/core/search-visibility/index.js +12 -0
- package/dist/core/search-visibility/verifier.js +112 -3
- package/dist/core/security/private-credential-file.js +209 -0
- package/dist/core/session/project-namespace.js +0 -5
- package/dist/core/skills/skill-agent-metadata.js +1 -3
- package/dist/core/strategy/adhd-orchestrating-gate.js +0 -1
- package/dist/core/subagents/agent-catalog.js +19 -34
- package/dist/core/subagents/model-policy.js +65 -24
- package/dist/core/subagents/naruto-help-contract.js +8 -8
- package/dist/core/subagents/naruto-host-credentials.js +13 -0
- package/dist/core/subagents/official-subagent-config.js +16 -6
- package/dist/core/subagents/official-subagent-preparation.js +35 -16
- package/dist/core/subagents/official-subagent-prompt.js +7 -7
- package/dist/core/subagents/official-subagent-runner.js +27 -4
- package/dist/core/subagents/role-model-preferences.js +1 -1
- package/dist/core/subagents/thread-budget.js +19 -12
- package/dist/core/subagents/wave-lifecycle.js +18 -6
- package/dist/core/telegram/access.js +58 -0
- package/dist/core/telegram/client.js +157 -0
- package/dist/core/telegram/confirmation.js +37 -0
- package/dist/core/telegram/doctor.js +154 -0
- package/dist/core/telegram/index.js +9 -0
- package/dist/core/telegram/keychain.js +317 -0
- package/dist/core/telegram/liveness.js +118 -0
- package/dist/core/telegram/poller.js +90 -0
- package/dist/core/telegram/redaction.js +15 -0
- package/dist/core/telegram/state-lock.js +416 -0
- package/dist/core/telegram/types.js +1 -0
- package/dist/core/text/strings.js +3 -0
- package/dist/core/triwiki/context-graph/store/evidence-write-lock.js +29 -0
- package/dist/core/triwiki/context-graph/store/fragment-cache.js +24 -0
- package/dist/core/triwiki/context-graph/store/snapshot-store.js +69 -21
- package/dist/core/triwiki/triwiki-gate-impact-map.js +2 -2
- package/dist/core/triwiki/triwiki-module-card.js +1 -2
- package/dist/core/update/installed-cli-resolution.js +170 -0
- package/dist/core/update/update-diagnostics.js +52 -0
- package/dist/core/update/update-migration-state.js +30 -12
- package/dist/core/update/update-operation.js +2 -1
- package/dist/core/update/update-stage-diagnostics.js +38 -0
- package/dist/core/update/update-status.js +2 -9
- package/dist/core/update-check.js +279 -91
- package/dist/core/version.js +1 -1
- package/dist/native/sks-menubar/Sources/AppDelegate.swift +19 -1
- package/dist/native/sks-menubar/Sources/AppIdentity.swift +7 -0
- package/dist/native/sks-menubar/Sources/ControlCenterWindowController.swift +6 -2
- package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +159 -92
- package/dist/native/sks-menubar/Sources/OperationModels.swift +389 -0
- package/dist/native/sks-menubar/Sources/OverviewViewController.swift +57 -0
- package/dist/native/sks-menubar/Sources/ProcessClient.swift +3 -1
- package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +115 -0
- package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +17 -0
- package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +3 -0
- package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +58 -17
- package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +302 -0
- package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +5 -0
- package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +190 -0
- package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +158 -126
- package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +462 -26
- package/dist/native/sks-menubar/Sources/SKSKeychainStore.swift +344 -0
- package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +27 -0
- package/dist/native/sks-menubar/Sources/SingletonInstanceGuard.swift +328 -0
- package/dist/native/sks-menubar/Sources/StatusItemController.swift +10 -2
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileStore.swift +498 -0
- package/dist/native/sks-menubar/Sources/TelegramPrivateFileSupport.swift +236 -0
- package/dist/native/sks-menubar/Sources/TelegramProcessGateway.swift +454 -0
- package/dist/native/sks-menubar/Sources/TelegramRuntimeSupport.swift +56 -0
- package/dist/native/sks-menubar/Sources/TelegramStateLock.swift +448 -0
- package/dist/native/sks-menubar/Sources/TelegramSupport.swift +187 -0
- package/dist/native/sks-menubar/Sources/TelegramTransport.swift +499 -0
- package/dist/native/sks-menubar/Sources/main.swift +15 -1
- package/dist/scripts/all-feature-deep-completion-check.js +5 -1
- package/dist/scripts/check-publish-tag.js +56 -0
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +10 -3
- package/dist/scripts/codex-lb-fast-ui-preservation-check.js +12 -3
- package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +4 -2
- package/dist/scripts/codex-native-agent-role-content-check.js +3 -3
- package/dist/scripts/codex-native-gate-lib.js +14 -7
- package/dist/scripts/current-command-surface-check.js +7 -7
- package/dist/scripts/current-surface-update-e2e-check.js +4 -3
- package/dist/scripts/current-upgrade-matrix-check.js +5 -24
- package/dist/scripts/docs-truthfulness-check.js +17 -13
- package/dist/scripts/gate-lib.js +0 -2
- package/dist/scripts/gate-policy-audit-check.js +3 -2
- package/dist/scripts/harness-benchmark-check.js +1 -1
- package/dist/scripts/init-deep-backup-retention-check.js +1 -1
- package/dist/scripts/lib/codex-sdk-gate-lib.js +1 -2
- package/dist/scripts/loop-directive-check-lib.js +28 -38
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +14 -180
- package/dist/scripts/mad-sks-launch-sql-plane-boundary-check.js +2 -11
- package/dist/scripts/official-subagent-workflow-check.js +1 -1
- package/dist/scripts/packlist-performance-check.js +1 -2
- package/dist/scripts/prepublish-release-check-or-fast.js +32 -0
- package/dist/scripts/publish-preflight.js +12 -0
- package/dist/scripts/release-affected-selector-check.js +2 -2
- package/dist/scripts/release-gate-batch-runner-check.js +2 -2
- package/dist/scripts/release-metadata-check.js +8 -12
- package/dist/scripts/release-real-check.js +2 -54
- package/dist/scripts/runtime-domain-gate-lib.js +2 -96
- package/dist/scripts/runtime-proof-summary-check.js +2 -6
- package/dist/scripts/search-visibility-gate-lib.js +0 -1
- package/dist/scripts/sks-cli-gate-lib.js +1 -1
- package/dist/scripts/typed-routing-gate-lib.js +7 -59
- package/docs/demo.tape +1 -1
- package/infra-harness-gates.json +1 -1456
- package/package.json +10 -7
- package/release-gates.v2.json +0 -1
- package/schemas/agents/parallel-runtime-proof.schema.json +0 -2
- package/schemas/codex/agent-result.schema.json +0 -6
- package/schemas/naruto/naruto-concurrency-governor.schema.json +1 -3
- package/schemas/release/release-gate-node.schema.json +1 -1
- package/dist/commands/zellij-lane.js +0 -22
- package/dist/commands/zellij-monitor-pane.js +0 -26
- package/dist/commands/zellij-slot-column-anchor.js +0 -22
- package/dist/commands/zellij-slot-pane.js +0 -80
- package/dist/commands/zellij-viewport-pane.js +0 -57
- package/dist/commands/zellij.js +0 -422
- package/dist/core/agents/agent-runner-zellij.js +0 -164
- package/dist/core/agents/agent-slot-pane-binding-proof.js +0 -96
- package/dist/core/agents/parallel-write-fixture.js +0 -305
- package/dist/core/agents/worker-pane-communication-contract.js +0 -100
- package/dist/core/agents/zellij-lane-supervisor.js +0 -428
- package/dist/core/agents/zellij-right-lane-cockpit.js +0 -66
- package/dist/core/doctor/doctor-zellij-repair.js +0 -40
- package/dist/core/ops/upgrade-migration-fixtures.js +0 -119
- package/dist/core/proof/route-finalizer-fixtures.js +0 -21
- package/dist/core/zellij/homebrew-policy.js +0 -43
- package/dist/core/zellij/zellij-capability.js +0 -126
- package/dist/core/zellij/zellij-clipboard-config.js +0 -52
- package/dist/core/zellij/zellij-command.js +0 -149
- package/dist/core/zellij/zellij-fake-adapter.js +0 -186
- package/dist/core/zellij/zellij-lane-renderer.js +0 -706
- package/dist/core/zellij/zellij-lane-runtime.js +0 -189
- package/dist/core/zellij/zellij-launcher.js +0 -268
- package/dist/core/zellij/zellij-layout-builder.js +0 -191
- package/dist/core/zellij/zellij-monitor-renderer.js +0 -52
- package/dist/core/zellij/zellij-official-subagent-activity.js +0 -526
- package/dist/core/zellij/zellij-official-subagent-telemetry.js +0 -258
- package/dist/core/zellij/zellij-pane-proof.js +0 -226
- package/dist/core/zellij/zellij-right-column-manager.js +0 -308
- package/dist/core/zellij/zellij-screen-proof.js +0 -120
- package/dist/core/zellij/zellij-self-heal-types.js +0 -44
- package/dist/core/zellij/zellij-self-heal.js +0 -408
- package/dist/core/zellij/zellij-slot-column-anchor.js +0 -304
- package/dist/core/zellij/zellij-slot-pane-renderer.js +0 -521
- package/dist/core/zellij/zellij-slot-telemetry.js +0 -384
- package/dist/core/zellij/zellij-theme.js +0 -66
- package/dist/core/zellij/zellij-ui-mode.js +0 -34
- package/dist/core/zellij/zellij-update.js +0 -348
- package/dist/core/zellij/zellij-viewport-binder.js +0 -61
- package/dist/core/zellij/zellij-worker-pane-manager.js +0 -881
- package/dist/core/zellij/zellij-worker-pane-summary.js +0 -64
- package/dist/native/sks-menubar/Tests/AppRuntimeTestSupport.swift +0 -26
- package/dist/native/sks-menubar/Tests/OperationCoordinatorTests.swift +0 -174
- package/dist/native/sks-menubar/Tests/ProcessClientTests.swift +0 -20
- package/dist/native/sks-menubar/Tests/ProvidersViewControllerTests.swift +0 -142
- package/dist/scripts/zellij-pane-proof-check.js +0 -88
- package/dist/scripts/zellij-real-session-cleanup-check.js +0 -139
- package/dist/scripts/zellij-real-session-launch-check.js +0 -126
- package/dist/scripts/zellij-screen-proof-check.js +0 -43
- package/schemas/zellij/zellij-right-column-state.schema.json +0 -40
- package/schemas/zellij/zellij-slot-telemetry.schema.json +0 -89
- package/schemas/zellij/zellij-worker-pane.schema.json +0 -53
- package/scripts/build-clean-atomic.mjs +0 -323
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
// SKS CLI timestamps come from JavaScript Date.toISOString() and carry
|
|
4
|
+
// fractional seconds ("2026-07-24T00:00:00.000Z"), which the default
|
|
5
|
+
// ISO8601DateFormatter options cannot parse. Try fractional first, then plain.
|
|
6
|
+
enum SKSTimestamp {
|
|
7
|
+
private static let fractional: ISO8601DateFormatter = {
|
|
8
|
+
let formatter = ISO8601DateFormatter()
|
|
9
|
+
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
|
10
|
+
return formatter
|
|
11
|
+
}()
|
|
12
|
+
private static let plain = ISO8601DateFormatter()
|
|
13
|
+
|
|
14
|
+
static func date(from value: String) -> Date? {
|
|
15
|
+
fractional.date(from: value) ?? plain.date(from: value)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
enum OperationState: String, Codable {
|
|
20
|
+
case queued, running, waitingForConfirmation, succeeded, failed, cancelled, terminalUncertain
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
enum OperationProgressSignal: String, Codable, CaseIterable {
|
|
24
|
+
case evidence, fileChange, testResult, modelResponse, toolResponse, none
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
enum OperationRecoveryCause: String, Codable, CaseIterable {
|
|
28
|
+
case transientNetwork
|
|
29
|
+
case authentication
|
|
30
|
+
case providerMode
|
|
31
|
+
case accountBinding
|
|
32
|
+
case externalConfiguration
|
|
33
|
+
case unknown
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
enum OperationRecoveryState: String, Codable {
|
|
37
|
+
case active
|
|
38
|
+
case warning
|
|
39
|
+
case autoResumePending
|
|
40
|
+
case pausedResumable
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
enum ProviderApplyStageName: String, Codable, CaseIterable {
|
|
44
|
+
case configSaved = "config_saved"
|
|
45
|
+
case proxyApplied = "proxy_applied"
|
|
46
|
+
case catalogRefreshed = "catalog_refreshed"
|
|
47
|
+
case newSessionReady = "new_session_ready"
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
enum ProviderApplyStageState: String, Codable {
|
|
51
|
+
case pending, running, succeeded, failed
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
struct ProviderApplyStageReceipt: Codable, Equatable {
|
|
55
|
+
let stage: ProviderApplyStageName
|
|
56
|
+
let status: ProviderApplyStageState
|
|
57
|
+
let reasonCode: String?
|
|
58
|
+
let updatedAt: String
|
|
59
|
+
|
|
60
|
+
enum CodingKeys: String, CodingKey {
|
|
61
|
+
case stage, status
|
|
62
|
+
case reasonCode = "reason_code"
|
|
63
|
+
case updatedAt = "updated_at"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
struct ProviderSessionCopy: Codable, Equatable {
|
|
68
|
+
let mode: String
|
|
69
|
+
let model: String
|
|
70
|
+
let catalogVersion: String
|
|
71
|
+
|
|
72
|
+
enum CodingKeys: String, CodingKey {
|
|
73
|
+
case mode, model
|
|
74
|
+
case catalogVersion = "catalog_version"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
struct ProviderApplyProjection: Codable, Equatable {
|
|
79
|
+
let schema: String
|
|
80
|
+
let stages: [ProviderApplyStageReceipt]
|
|
81
|
+
let existingSession: ProviderSessionCopy?
|
|
82
|
+
let newSessionDefault: ProviderSessionCopy
|
|
83
|
+
|
|
84
|
+
enum CodingKeys: String, CodingKey {
|
|
85
|
+
case schema, stages
|
|
86
|
+
case existingSession = "existing_session"
|
|
87
|
+
case newSessionDefault = "new_session_default"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
static func initial(
|
|
91
|
+
existingSession: ProviderSessionCopy?,
|
|
92
|
+
newSessionDefault: ProviderSessionCopy,
|
|
93
|
+
now: Date = Date()
|
|
94
|
+
) -> ProviderApplyProjection {
|
|
95
|
+
let timestamp = ISO8601DateFormatter().string(from: now)
|
|
96
|
+
return ProviderApplyProjection(
|
|
97
|
+
schema: "sks.provider-apply-projection.v1",
|
|
98
|
+
stages: ProviderApplyStageName.allCases.map {
|
|
99
|
+
ProviderApplyStageReceipt(stage: $0, status: .pending, reasonCode: nil, updatedAt: timestamp)
|
|
100
|
+
},
|
|
101
|
+
existingSession: existingSession,
|
|
102
|
+
newSessionDefault: newSessionDefault
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func transitioning(
|
|
107
|
+
stage: ProviderApplyStageName,
|
|
108
|
+
to status: ProviderApplyStageState,
|
|
109
|
+
reasonCode: String? = nil,
|
|
110
|
+
now: Date = Date()
|
|
111
|
+
) throws -> ProviderApplyProjection {
|
|
112
|
+
guard schema == "sks.provider-apply-projection.v1",
|
|
113
|
+
stages.map(\.stage) == ProviderApplyStageName.allCases,
|
|
114
|
+
let index = stages.firstIndex(where: { $0.stage == stage }) else {
|
|
115
|
+
throw ProviderApplyProjectionError.invalidProjection
|
|
116
|
+
}
|
|
117
|
+
if status == .failed, reasonCode == nil { throw ProviderApplyProjectionError.failureReasonRequired }
|
|
118
|
+
if status != .failed, reasonCode != nil { throw ProviderApplyProjectionError.unexpectedReason }
|
|
119
|
+
let current = stages[index].status
|
|
120
|
+
let validTransition = current == status
|
|
121
|
+
|| current == .pending && status == .running
|
|
122
|
+
|| current == .running && (status == .succeeded || status == .failed)
|
|
123
|
+
|| current == .failed && status == .running
|
|
124
|
+
guard validTransition else { throw ProviderApplyProjectionError.invalidTransition }
|
|
125
|
+
if status != .pending, index > 0, stages[index - 1].status != .succeeded {
|
|
126
|
+
throw ProviderApplyProjectionError.previousStageIncomplete
|
|
127
|
+
}
|
|
128
|
+
var next = stages
|
|
129
|
+
next[index] = ProviderApplyStageReceipt(
|
|
130
|
+
stage: stage,
|
|
131
|
+
status: status,
|
|
132
|
+
reasonCode: reasonCode,
|
|
133
|
+
updatedAt: ISO8601DateFormatter().string(from: now)
|
|
134
|
+
)
|
|
135
|
+
return ProviderApplyProjection(
|
|
136
|
+
schema: schema,
|
|
137
|
+
stages: next,
|
|
138
|
+
existingSession: existingSession,
|
|
139
|
+
newSessionDefault: newSessionDefault
|
|
140
|
+
)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
var allSucceeded: Bool { stages.allSatisfy { $0.status == .succeeded } }
|
|
144
|
+
var failedStage: ProviderApplyStageReceipt? { stages.first { $0.status == .failed } }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
enum ProviderApplyProjectionError: Error {
|
|
148
|
+
case invalidProjection
|
|
149
|
+
case failureReasonRequired
|
|
150
|
+
case unexpectedReason
|
|
151
|
+
case invalidTransition
|
|
152
|
+
case previousStageIncomplete
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
struct OperationRecoveryStatus: Codable, Equatable {
|
|
156
|
+
let schema: String
|
|
157
|
+
let state: OperationRecoveryState
|
|
158
|
+
let cause: OperationRecoveryCause?
|
|
159
|
+
let automaticResume: Bool
|
|
160
|
+
let retryCount: Int
|
|
161
|
+
let maxAutomaticRetries: Int
|
|
162
|
+
let lastProgressSignal: OperationProgressSignal
|
|
163
|
+
let lastProgressAt: String
|
|
164
|
+
let stallReason: String?
|
|
165
|
+
let recoveryAttempt: String?
|
|
166
|
+
let nextAction: String
|
|
167
|
+
let pinnedMode: String?
|
|
168
|
+
let pinnedModel: String?
|
|
169
|
+
let accountBinding: String
|
|
170
|
+
let evidenceIntegrity: String
|
|
171
|
+
|
|
172
|
+
enum CodingKeys: String, CodingKey {
|
|
173
|
+
case schema, state, cause
|
|
174
|
+
case automaticResume = "automatic_resume"
|
|
175
|
+
case retryCount = "retry_count"
|
|
176
|
+
case maxAutomaticRetries = "max_automatic_retries"
|
|
177
|
+
case lastProgressSignal = "last_progress_signal"
|
|
178
|
+
case lastProgressAt = "last_progress_at"
|
|
179
|
+
case stallReason = "stall_reason"
|
|
180
|
+
case recoveryAttempt = "recovery_attempt"
|
|
181
|
+
case nextAction = "next_action"
|
|
182
|
+
case pinnedMode = "pinned_mode"
|
|
183
|
+
case pinnedModel = "pinned_model"
|
|
184
|
+
case accountBinding = "account_binding"
|
|
185
|
+
case evidenceIntegrity = "evidence_integrity"
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
struct OperationRecoveryAttemptOutcome {
|
|
190
|
+
let succeeded: Bool
|
|
191
|
+
let cause: OperationRecoveryCause?
|
|
192
|
+
let progressSignal: OperationProgressSignal
|
|
193
|
+
|
|
194
|
+
static func success(_ signal: OperationProgressSignal) -> OperationRecoveryAttemptOutcome {
|
|
195
|
+
OperationRecoveryAttemptOutcome(succeeded: true, cause: nil, progressSignal: signal)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static func failure(_ cause: OperationRecoveryCause) -> OperationRecoveryAttemptOutcome {
|
|
199
|
+
OperationRecoveryAttemptOutcome(succeeded: false, cause: cause, progressSignal: .none)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
enum OperationRecoveryPolicy {
|
|
204
|
+
static let maxAutomaticNetworkRetries = 2
|
|
205
|
+
|
|
206
|
+
/// Time is diagnostic only. A fresh progress signal always keeps the work
|
|
207
|
+
/// active, even after a warning threshold. Only a classified cause may choose
|
|
208
|
+
/// automatic or manual recovery, and only transient network causes auto-resume.
|
|
209
|
+
static func evaluate(
|
|
210
|
+
cause: OperationRecoveryCause?,
|
|
211
|
+
sameCauseRetryCount: Int,
|
|
212
|
+
progressSignal: OperationProgressSignal,
|
|
213
|
+
progressObserved: Bool,
|
|
214
|
+
secondsWithoutProgress: TimeInterval,
|
|
215
|
+
warningAfter: TimeInterval,
|
|
216
|
+
pinnedMode: String? = nil,
|
|
217
|
+
pinnedModel: String? = nil,
|
|
218
|
+
now: Date = Date()
|
|
219
|
+
) -> OperationRecoveryStatus {
|
|
220
|
+
let retryCount = max(0, sameCauseRetryCount)
|
|
221
|
+
let timestamp = ISO8601DateFormatter().string(from: now)
|
|
222
|
+
let shared = (
|
|
223
|
+
schema: "sks.operation-recovery.v1",
|
|
224
|
+
signal: progressSignal,
|
|
225
|
+
timestamp: timestamp,
|
|
226
|
+
mode: pinnedMode,
|
|
227
|
+
model: pinnedModel
|
|
228
|
+
)
|
|
229
|
+
if progressObserved {
|
|
230
|
+
return OperationRecoveryStatus(
|
|
231
|
+
schema: shared.schema, state: .active, cause: nil,
|
|
232
|
+
automaticResume: false, retryCount: retryCount,
|
|
233
|
+
maxAutomaticRetries: maxAutomaticNetworkRetries,
|
|
234
|
+
lastProgressSignal: shared.signal, lastProgressAt: shared.timestamp,
|
|
235
|
+
stallReason: nil, recoveryAttempt: nil,
|
|
236
|
+
nextAction: "Work is progressing; keep running.",
|
|
237
|
+
pinnedMode: shared.mode, pinnedModel: shared.model,
|
|
238
|
+
accountBinding: "pinned_unchanged", evidenceIntegrity: "preserved"
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
guard let cause = cause else {
|
|
242
|
+
let warning = secondsWithoutProgress >= max(1, warningAfter)
|
|
243
|
+
return OperationRecoveryStatus(
|
|
244
|
+
schema: shared.schema, state: warning ? .warning : .active, cause: nil,
|
|
245
|
+
automaticResume: false, retryCount: retryCount,
|
|
246
|
+
maxAutomaticRetries: maxAutomaticNetworkRetries,
|
|
247
|
+
lastProgressSignal: shared.signal, lastProgressAt: shared.timestamp,
|
|
248
|
+
stallReason: warning ? "No progress signal observed; time budget is warning-only." : nil,
|
|
249
|
+
recoveryAttempt: warning ? "Inspect runner health without terminating the operation." : nil,
|
|
250
|
+
nextAction: warning ? "Keep state resumable and inspect the stalled stage." : "Keep running.",
|
|
251
|
+
pinnedMode: shared.mode, pinnedModel: shared.model,
|
|
252
|
+
accountBinding: "pinned_unchanged", evidenceIntegrity: "preserved"
|
|
253
|
+
)
|
|
254
|
+
}
|
|
255
|
+
if cause == .transientNetwork, retryCount < maxAutomaticNetworkRetries {
|
|
256
|
+
let nextRetry = retryCount + 1
|
|
257
|
+
return OperationRecoveryStatus(
|
|
258
|
+
schema: shared.schema, state: .autoResumePending, cause: cause,
|
|
259
|
+
automaticResume: true, retryCount: nextRetry,
|
|
260
|
+
maxAutomaticRetries: maxAutomaticNetworkRetries,
|
|
261
|
+
lastProgressSignal: shared.signal, lastProgressAt: shared.timestamp,
|
|
262
|
+
stallReason: "Transient network interruption.",
|
|
263
|
+
recoveryAttempt: "Bounded automatic resume \(nextRetry)/\(maxAutomaticNetworkRetries).",
|
|
264
|
+
nextAction: "Retry the same request with the same pinned mode, model, and account binding.",
|
|
265
|
+
pinnedMode: shared.mode, pinnedModel: shared.model,
|
|
266
|
+
accountBinding: "pinned_unchanged", evidenceIntegrity: "preserved"
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
let reason = cause == .transientNetwork
|
|
270
|
+
? "Transient network retry limit reached."
|
|
271
|
+
: "\(cause.rawValue) requires explicit user review."
|
|
272
|
+
return OperationRecoveryStatus(
|
|
273
|
+
schema: shared.schema, state: .pausedResumable, cause: cause,
|
|
274
|
+
automaticResume: false, retryCount: min(retryCount, maxAutomaticNetworkRetries),
|
|
275
|
+
maxAutomaticRetries: maxAutomaticNetworkRetries,
|
|
276
|
+
lastProgressSignal: shared.signal, lastProgressAt: shared.timestamp,
|
|
277
|
+
stallReason: reason, recoveryAttempt: nil,
|
|
278
|
+
nextAction: "Review the cause in SKS Center, then resume explicitly from the owning section.",
|
|
279
|
+
pinnedMode: shared.mode, pinnedModel: shared.model,
|
|
280
|
+
accountBinding: "pinned_unchanged", evidenceIntegrity: "preserved"
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
struct OperationSnapshot: Codable {
|
|
286
|
+
let schema: String
|
|
287
|
+
let id: String
|
|
288
|
+
let kind: String
|
|
289
|
+
let state: OperationState
|
|
290
|
+
let stage: String?
|
|
291
|
+
let progress: Double?
|
|
292
|
+
let startedAt: String
|
|
293
|
+
let updatedAt: String
|
|
294
|
+
let publicSummary: String
|
|
295
|
+
let logPath: String?
|
|
296
|
+
let retryable: Bool
|
|
297
|
+
let targetVersion: String?
|
|
298
|
+
let projectRoot: String?
|
|
299
|
+
let registry: String?
|
|
300
|
+
let recovery: OperationRecoveryStatus?
|
|
301
|
+
let providerApply: ProviderApplyProjection?
|
|
302
|
+
|
|
303
|
+
init(
|
|
304
|
+
schema: String,
|
|
305
|
+
id: String,
|
|
306
|
+
kind: String,
|
|
307
|
+
state: OperationState,
|
|
308
|
+
stage: String?,
|
|
309
|
+
progress: Double?,
|
|
310
|
+
startedAt: String,
|
|
311
|
+
updatedAt: String,
|
|
312
|
+
publicSummary: String,
|
|
313
|
+
logPath: String?,
|
|
314
|
+
retryable: Bool,
|
|
315
|
+
targetVersion: String?,
|
|
316
|
+
projectRoot: String?,
|
|
317
|
+
registry: String?,
|
|
318
|
+
recovery: OperationRecoveryStatus? = nil,
|
|
319
|
+
providerApply: ProviderApplyProjection? = nil
|
|
320
|
+
) {
|
|
321
|
+
self.schema = schema
|
|
322
|
+
self.id = id
|
|
323
|
+
self.kind = kind
|
|
324
|
+
self.state = state
|
|
325
|
+
self.stage = stage
|
|
326
|
+
self.progress = progress
|
|
327
|
+
self.startedAt = startedAt
|
|
328
|
+
self.updatedAt = updatedAt
|
|
329
|
+
self.publicSummary = publicSummary
|
|
330
|
+
self.logPath = logPath
|
|
331
|
+
self.retryable = retryable
|
|
332
|
+
self.targetVersion = targetVersion
|
|
333
|
+
self.projectRoot = projectRoot
|
|
334
|
+
self.registry = registry
|
|
335
|
+
self.recovery = recovery
|
|
336
|
+
self.providerApply = providerApply
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
struct UpdateOperationStageSnapshot: Codable {
|
|
341
|
+
let id: String
|
|
342
|
+
let ok: Bool
|
|
343
|
+
let status: String
|
|
344
|
+
let updatedAt: String
|
|
345
|
+
|
|
346
|
+
enum CodingKeys: String, CodingKey {
|
|
347
|
+
case id, ok, status
|
|
348
|
+
case updatedAt = "updated_at"
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
struct UpdateOperationReceiptSnapshot: Codable {
|
|
353
|
+
let schema: String
|
|
354
|
+
let id: String
|
|
355
|
+
let kind: String
|
|
356
|
+
let state: String
|
|
357
|
+
let currentStage: String?
|
|
358
|
+
let startedAt: String
|
|
359
|
+
let updatedAt: String
|
|
360
|
+
let fromVersion: String
|
|
361
|
+
let targetVersion: String?
|
|
362
|
+
let previousVersion: String
|
|
363
|
+
let projectRoot: String?
|
|
364
|
+
let registry: String?
|
|
365
|
+
let rollbackCommand: String
|
|
366
|
+
let sideEffectsStarted: Bool
|
|
367
|
+
let stages: [UpdateOperationStageSnapshot]
|
|
368
|
+
let resultStatus: String?
|
|
369
|
+
let publicError: String?
|
|
370
|
+
let receiptPath: String
|
|
371
|
+
|
|
372
|
+
enum CodingKeys: String, CodingKey {
|
|
373
|
+
case schema, id, kind, state, stages
|
|
374
|
+
case currentStage = "current_stage"
|
|
375
|
+
case startedAt = "started_at"
|
|
376
|
+
case updatedAt = "updated_at"
|
|
377
|
+
case fromVersion = "from_version"
|
|
378
|
+
case targetVersion = "target_version"
|
|
379
|
+
case previousVersion = "previous_version"
|
|
380
|
+
case projectRoot = "project_root"
|
|
381
|
+
case registry
|
|
382
|
+
case rollbackCommand = "rollback_command"
|
|
383
|
+
case sideEffectsStarted = "side_effects_started"
|
|
384
|
+
case resultStatus = "result_status"
|
|
385
|
+
case publicError = "public_error"
|
|
386
|
+
case receiptPath = "receipt_path"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
@@ -186,6 +186,7 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
186
186
|
private let operations: OperationCoordinator
|
|
187
187
|
private let status = NativeView.detail("Loading local SKS status…")
|
|
188
188
|
private let notificationInbox = NativeView.detail("Notifications: checking authorization…")
|
|
189
|
+
private let recoveryStatus = NativeView.detail("Progress recovery: no operation state loaded yet.")
|
|
189
190
|
private let healthBadge = NativeView.badge("Checking local status", color: .systemBlue)
|
|
190
191
|
private let statusSpinner = NativeView.spinner(label: "Checking SKS Center status")
|
|
191
192
|
private var generation = 0
|
|
@@ -193,6 +194,7 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
193
194
|
private var doctorButton: NSButton!
|
|
194
195
|
private var refreshButton: NSButton!
|
|
195
196
|
private var updateCodexButton: NSButton!
|
|
197
|
+
private var reviewAndResumeButton: NSButton!
|
|
196
198
|
/// Section navigation by sidebar title, wired by ControlCenterWindowController.
|
|
197
199
|
var openSection: ((String) -> Void)?
|
|
198
200
|
|
|
@@ -207,6 +209,8 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
207
209
|
doctorButton = NativeView.button("Run Doctor", target: self, action: #selector(doctor))
|
|
208
210
|
refreshButton = NativeView.button("Refresh", target: self, action: #selector(refreshStatus))
|
|
209
211
|
updateCodexButton = NativeView.button("Update Codex CLI", target: self, action: #selector(updateCodexCLI))
|
|
212
|
+
reviewAndResumeButton = NativeView.button("Review & Resume…", target: self, action: #selector(reviewAndResume))
|
|
213
|
+
reviewAndResumeButton.isEnabled = false
|
|
210
214
|
updateCodexButton.setAccessibilityHelp("Update the operator Codex CLI to the preferred latest channel.")
|
|
211
215
|
let buttons = NativeView.row([refreshButton, doctorButton, updateCodexButton])
|
|
212
216
|
let shortcuts = NativeView.row([
|
|
@@ -226,10 +230,16 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
226
230
|
subtitle: "Results remain available here even when macOS notifications are disabled.",
|
|
227
231
|
views: [notificationInbox, shortcuts]
|
|
228
232
|
)
|
|
233
|
+
let recoveryCard = NativeView.card(
|
|
234
|
+
title: "Progress, pause & recovery",
|
|
235
|
+
subtitle: "Time budgets are warnings, never automatic termination. Only transient network failures can auto-resume, at most twice. Authentication, mode, account binding, and external configuration always wait for explicit review.",
|
|
236
|
+
views: [recoveryStatus, NativeView.row([reviewAndResumeButton])]
|
|
237
|
+
)
|
|
229
238
|
view = NativeView.page([
|
|
230
239
|
NativeView.title("Overview"),
|
|
231
240
|
NativeView.detail("Menu Bar build \(AppRuntime.packageVersion) · Local health for SKS, Codex CLI, MCP, and operations. Prefer the latest Codex CLI; SKS stays version-agnostic and capability-gates features."),
|
|
232
241
|
healthCard,
|
|
242
|
+
recoveryCard,
|
|
233
243
|
nextStepsCard
|
|
234
244
|
])
|
|
235
245
|
}
|
|
@@ -238,6 +248,28 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
238
248
|
@objc private func openUpdates() { openSection?("Updates") }
|
|
239
249
|
@objc private func openDiagnostics() { openSection?("Diagnostics") }
|
|
240
250
|
|
|
251
|
+
@objc private func reviewAndResume() {
|
|
252
|
+
guard let operation = operations.latestSnapshot(),
|
|
253
|
+
let recovery = operation.recovery,
|
|
254
|
+
recovery.state == .pausedResumable || recovery.state == .warning else {
|
|
255
|
+
recoveryStatus.stringValue = "No resumable pause is available. Refresh status to inspect the latest progress signal."
|
|
256
|
+
reviewAndResumeButton.isEnabled = false
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
let section: String
|
|
260
|
+
if operation.kind.localizedCaseInsensitiveContains("provider")
|
|
261
|
+
|| operation.kind.localizedCaseInsensitiveContains("openrouter")
|
|
262
|
+
|| operation.kind.localizedCaseInsensitiveContains("codex-lb") {
|
|
263
|
+
section = "Providers"
|
|
264
|
+
} else if operation.kind.localizedCaseInsensitiveContains("update") {
|
|
265
|
+
section = "Updates"
|
|
266
|
+
} else {
|
|
267
|
+
section = "Diagnostics"
|
|
268
|
+
}
|
|
269
|
+
recoveryStatus.stringValue = "Review opened for \(operation.kind). Confirm the unchanged mode/model/account binding, then retry from \(section). Nothing resumed automatically."
|
|
270
|
+
openSection?(section)
|
|
271
|
+
}
|
|
272
|
+
|
|
241
273
|
func refreshOnAppear() {
|
|
242
274
|
loadStatus(forceUpdateRefresh: false)
|
|
243
275
|
}
|
|
@@ -381,6 +413,7 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
381
413
|
private func renderStatus(update: [String: Any]?, mcp: [String: Any]?, partial: Bool) {
|
|
382
414
|
let rendered = summary(update: update, mcp: mcp)
|
|
383
415
|
status.stringValue = rendered
|
|
416
|
+
renderRecoveryStatus(operations.latestSnapshot())
|
|
384
417
|
if partial {
|
|
385
418
|
NativeView.setBadge(healthBadge, text: "Partial status · still checking", color: .systemBlue)
|
|
386
419
|
} else if rendered.localizedCaseInsensitiveContains("unavailable")
|
|
@@ -391,6 +424,30 @@ final class OverviewViewController: NSViewController, ControlCenterPage {
|
|
|
391
424
|
}
|
|
392
425
|
}
|
|
393
426
|
|
|
427
|
+
private func renderRecoveryStatus(_ operation: OperationSnapshot?) {
|
|
428
|
+
guard let operation = operation else {
|
|
429
|
+
recoveryStatus.stringValue = "Progress recovery: no operation recorded · automatic resume inactive."
|
|
430
|
+
reviewAndResumeButton.isEnabled = false
|
|
431
|
+
return
|
|
432
|
+
}
|
|
433
|
+
guard let recovery = operation.recovery else {
|
|
434
|
+
recoveryStatus.stringValue = "Progress recovery: no pause/retry decision recorded for \(operation.kind) · critical path \(operation.stage ?? "unknown") · cache evidence not reported."
|
|
435
|
+
reviewAndResumeButton.isEnabled = false
|
|
436
|
+
return
|
|
437
|
+
}
|
|
438
|
+
let cause = recovery.cause?.rawValue ?? "none"
|
|
439
|
+
let automatic = recovery.automaticResume ? "yes" : "no"
|
|
440
|
+
let mode = recovery.pinnedMode ?? "not reported"
|
|
441
|
+
let model = recovery.pinnedModel ?? "not reported"
|
|
442
|
+
let stall = recovery.stallReason.map { " · stop reason: \($0)" } ?? ""
|
|
443
|
+
let attempt = recovery.recoveryAttempt.map { " · recovery: \($0)" } ?? ""
|
|
444
|
+
recoveryStatus.stringValue = "State \(recovery.state.rawValue) · progress \(recovery.lastProgressSignal.rawValue) at \(recovery.lastProgressAt) · cause \(cause) · auto resume \(automatic) · retry \(recovery.retryCount)/\(recovery.maxAutomaticRetries) · critical path \(operation.stage ?? "unknown") · mode \(mode) · model \(model) · account \(recovery.accountBinding) · evidence \(recovery.evidenceIntegrity)\(stall)\(attempt) · next: \(recovery.nextAction)"
|
|
445
|
+
reviewAndResumeButton.isEnabled = recovery.state == .pausedResumable || recovery.state == .warning
|
|
446
|
+
reviewAndResumeButton.toolTip = reviewAndResumeButton.isEnabled
|
|
447
|
+
? "Open the owning section for explicit review; this button never changes authentication, mode, account, or evidence."
|
|
448
|
+
: "No manual resume action is required for the current state."
|
|
449
|
+
}
|
|
450
|
+
|
|
394
451
|
private func summary(update: [String: Any]?, mcp: [String: Any]?) -> String {
|
|
395
452
|
let codexRunning = AppRuntime.codexBundleId.map { bundle in
|
|
396
453
|
NSWorkspace.shared.runningApplications.contains { $0.bundleIdentifier == bundle }
|
|
@@ -421,7 +421,9 @@ final class ProcessClient {
|
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
private func sensitiveStdinValues(arguments: [String], stdin: String?) -> [String] {
|
|
424
|
-
|
|
424
|
+
let receivesSensitiveStdin = arguments.contains("--api-key-stdin")
|
|
425
|
+
|| arguments.contains("--token-stdin")
|
|
426
|
+
guard receivesSensitiveStdin, let stdin = stdin else { return [] }
|
|
425
427
|
let normalized = stdin.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
426
428
|
guard !normalized.isEmpty else { return [] }
|
|
427
429
|
return normalized == stdin ? [normalized] : [normalized, stdin]
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import Cocoa
|
|
2
|
+
|
|
3
|
+
extension ProvidersViewController {
|
|
4
|
+
func makeCliConnectProgressView() -> NSStackView {
|
|
5
|
+
cliConnectConfigurationStage.setAccessibilityLabel("Codex LB configuration stage: waiting")
|
|
6
|
+
cliConnectConfigurationStage.setAccessibilityIdentifier("sks-center-codex-lb-configuration-stage")
|
|
7
|
+
cliConnectRequestStage.setAccessibilityLabel("Codex LB one-request low-token test stage: waiting")
|
|
8
|
+
cliConnectRequestStage.setAccessibilityIdentifier("sks-center-codex-lb-request-stage")
|
|
9
|
+
cliConnectResponseStage.setAccessibilityLabel("Codex LB response stage: not received")
|
|
10
|
+
cliConnectResponseStage.setAccessibilityIdentifier("sks-center-codex-lb-response-stage")
|
|
11
|
+
cliConnectResult.setAccessibilityLabel("Codex LB connection proof result: not run")
|
|
12
|
+
cliConnectResult.setAccessibilityIdentifier("sks-center-codex-lb-connect-result")
|
|
13
|
+
let title = NativeView.sectionTitle("Connection Proof")
|
|
14
|
+
title.setAccessibilityIdentifier("sks-center-codex-lb-connect-heading")
|
|
15
|
+
let stack = NSStackView(views: [title, cliConnectProgress, cliConnectConfigurationStage, cliConnectRequestStage, cliConnectResponseStage, cliConnectResult])
|
|
16
|
+
stack.orientation = .vertical
|
|
17
|
+
stack.alignment = .width
|
|
18
|
+
stack.spacing = 6
|
|
19
|
+
stack.setAccessibilityRole(.group)
|
|
20
|
+
stack.setAccessibilityLabel("Codex LB connection proof")
|
|
21
|
+
stack.setAccessibilityIdentifier("sks-center-codex-lb-connect-proof")
|
|
22
|
+
return stack
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func renderCliConnectStages(
|
|
26
|
+
progress: Double,
|
|
27
|
+
configuration: String,
|
|
28
|
+
request: String,
|
|
29
|
+
response: String,
|
|
30
|
+
result: String,
|
|
31
|
+
tone: NSColor
|
|
32
|
+
) {
|
|
33
|
+
cliConnectProgress.doubleValue = min(3, max(0, progress))
|
|
34
|
+
cliConnectProgress.setAccessibilityValue("Stage \(Int(cliConnectProgress.doubleValue)) of 3")
|
|
35
|
+
cliConnectConfigurationStage.stringValue = "1. Configuration · \(configuration)"
|
|
36
|
+
cliConnectConfigurationStage.setAccessibilityLabel("Codex LB configuration stage: \(configuration)")
|
|
37
|
+
cliConnectRequestStage.stringValue = "2. One-request low-token test · \(request)"
|
|
38
|
+
cliConnectRequestStage.setAccessibilityLabel("Codex LB one-request low-token test stage: \(request)")
|
|
39
|
+
cliConnectResponseStage.stringValue = "3. Response · \(response)"
|
|
40
|
+
cliConnectResponseStage.setAccessibilityLabel("Codex LB response stage: \(response)")
|
|
41
|
+
cliConnectResult.stringValue = result
|
|
42
|
+
cliConnectResult.textColor = tone
|
|
43
|
+
cliConnectResult.setAccessibilityLabel("Codex LB connection proof result: \(result)")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@objc func testConnection() {
|
|
47
|
+
runConnectTest()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func runConnectTest() {
|
|
51
|
+
guard !connectTestInFlight else {
|
|
52
|
+
cliProviderStatus.stringValue = "A Codex LB connection proof is already running."
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
guard !busy else { cliProviderStatus.stringValue = "Another provider action is already running."; return }
|
|
56
|
+
guard let snapshot = operations.begin(kind: "codex-lb-connect-test", mutationGroup: nil, summary: "Run Codex LB connect test") else {
|
|
57
|
+
cliProviderStatus.stringValue = "Another guarded operation is already running. Wait or open Diagnostics."
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
connectTestInFlight = true
|
|
61
|
+
setBusy(true)
|
|
62
|
+
cliProviderStatus.stringValue = "Codex LB mode \(codexLbSelectedNow ? "selected" : "selection unconfirmed") · sending one bounded low-token request…"
|
|
63
|
+
renderCliConnectStages(
|
|
64
|
+
progress: 2,
|
|
65
|
+
configuration: codexLbSelectedNow ? "CLI provider selected" : "selection unconfirmed",
|
|
66
|
+
request: "sending one bounded request…",
|
|
67
|
+
response: "waiting",
|
|
68
|
+
result: "Waiting for structured proof. Connectivity has not been claimed.",
|
|
69
|
+
tone: .secondaryLabelColor
|
|
70
|
+
)
|
|
71
|
+
_ = operations.update(snapshot, state: .running, stage: "one-request-low-token-test", progress: 2.0 / 3.0, summary: "Run Codex LB connect test")
|
|
72
|
+
processClient.run(["codex-lb", "connect-test", "--json"], timeout: NativeView.mutationTimeout) { [weak self] result in
|
|
73
|
+
guard let self = self else { return }
|
|
74
|
+
self.connectTestInFlight = false
|
|
75
|
+
self.setBusy(false)
|
|
76
|
+
let parsed = self.json(result.output)
|
|
77
|
+
let proof = parsed.flatMap(CodexLbConnectTestTruth.success(from:))
|
|
78
|
+
let proved = result.code == 0 && proof != nil
|
|
79
|
+
_ = self.operations.update(snapshot, state: proved ? .succeeded : .failed, stage: "complete", progress: 1, summary: proved ? "Codex LB connection proved" : "Codex LB connection proof failed")
|
|
80
|
+
if let proof = proof, result.code == 0 {
|
|
81
|
+
self.codexLbSelectedNow = true
|
|
82
|
+
self.cliProviderStatus.stringValue = "Codex LB mode selected · connection proved by one live response."
|
|
83
|
+
ControlKit.setBadge(self.activeProviderBadge, text: "Codex LB · active · model \(proof.model) · \(proof.latencyMs) ms", tone: .ok)
|
|
84
|
+
self.renderCliConnectStages(
|
|
85
|
+
progress: 3,
|
|
86
|
+
configuration: "CLI provider selected",
|
|
87
|
+
request: "completed · \(proof.outputTokens) output tokens",
|
|
88
|
+
response: "received · id \(proof.responseId)",
|
|
89
|
+
result: proof.renderedSummary,
|
|
90
|
+
tone: .systemGreen
|
|
91
|
+
)
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
let selected = self.codexLbSelectedNow
|
|
95
|
+
let failure = parsed.map(CodexLbConnectTestTruth.validationFailure(from:))
|
|
96
|
+
?? "structured connect-test JSON was not returned"
|
|
97
|
+
self.cliProviderStatus.stringValue = selected
|
|
98
|
+
? "Codex LB mode is selected, but connection proof failed · \(failure)."
|
|
99
|
+
: "Codex LB connection proof failed and provider selection is unconfirmed · \(failure)."
|
|
100
|
+
if selected {
|
|
101
|
+
ControlKit.setBadge(self.activeProviderBadge, text: "Codex LB · selected · connection proof failed", tone: .warning)
|
|
102
|
+
}
|
|
103
|
+
self.renderCliConnectStages(
|
|
104
|
+
progress: 3,
|
|
105
|
+
configuration: selected ? "CLI provider remains selected" : "selection unconfirmed",
|
|
106
|
+
request: "completed without valid proof",
|
|
107
|
+
response: "failed",
|
|
108
|
+
result: selected
|
|
109
|
+
? "Mode is selected, but connection proof failed · \(failure). Use Run Connect Test to retry."
|
|
110
|
+
: "Connection proof failed · \(failure). Confirm the provider, then retry.",
|
|
111
|
+
tone: .systemRed
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Cocoa
|
|
2
|
+
|
|
3
|
+
extension ProvidersViewController {
|
|
4
|
+
func refreshFastStatus() {
|
|
5
|
+
if !busy { fastStatus.stringValue = "Codex Fast: checking the official service-tier setting…" }
|
|
6
|
+
processClient.run(["fast-mode", "status", "--json"], timeout: NativeView.statusTimeout) { [weak self] result in
|
|
7
|
+
guard let self = self else { return }
|
|
8
|
+
guard result.code == 0, let json = self.json(result.output),
|
|
9
|
+
let global = json["global"] as? [String: Any], let on = global["on"] as? Bool else {
|
|
10
|
+
self.fastStatus.stringValue = "Codex Fast: unavailable — no state was assumed."
|
|
11
|
+
return
|
|
12
|
+
}
|
|
13
|
+
let tier = global["service_tier"] as? String ?? (on ? "fast" : "default")
|
|
14
|
+
self.fastStatus.stringValue = "Codex Fast: \(on ? "On" : "Off") · official service_tier=\(tier) · model and reasoning remain separate."
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -63,6 +63,9 @@ extension ProvidersViewController {
|
|
|
63
63
|
test.setAccessibilityHelp("Checks that the selected model exists in both the local catalog and the live loopback router. No configuration is changed.")
|
|
64
64
|
activate.setAccessibilityHelp("Validates the loopback router, writes its provider and catalog settings to Codex config, and restarts Codex App. Runtime adoption still requires a live Codex check.")
|
|
65
65
|
multiProvider.refreshButton = refresh
|
|
66
|
+
registerProviderAction(refresh, id: "sks-provider-refresh-router")
|
|
67
|
+
registerProviderAction(test, id: "sks-provider-test-router")
|
|
68
|
+
registerProviderAction(activate, id: "sks-provider-configure-router")
|
|
66
69
|
actionButtons += [refresh, test, activate]
|
|
67
70
|
|
|
68
71
|
let routerLabel = NSTextField(labelWithString: "Router URL")
|