instar 1.3.1649 → 1.3.1650
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/dashboard/console/accounts.js +2 -1
- package/dashboard/console/agents-model.js +3 -3
- package/dashboard/console/agents.js +7 -4
- package/dashboard/console/console.css +1 -0
- package/dashboard/console/console.js +35 -4
- package/dashboard/console/costs-model.js +12 -0
- package/dashboard/console/costs.js +6 -3
- package/dashboard/console/development-model.js +9 -3
- package/dashboard/console/development.js +7 -4
- package/dashboard/console/home-model.js +30 -14
- package/dashboard/console/mandates.js +3 -3
- package/dashboard/console/needs-model.js +105 -0
- package/dashboard/console/plans.js +2 -1
- package/dashboard/console/secrets.js +2 -2
- package/dashboard/console/ticket-model.js +36 -0
- package/dashboard/console/ui.js +3 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/install.d.ts +9 -7
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +2 -19
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/reflect.d.ts.map +1 -1
- package/dist/commands/reflect.js +2 -0
- package/dist/commands/reflect.js.map +1 -1
- package/dist/commands/route.d.ts.map +1 -1
- package/dist/commands/route.js +2 -0
- package/dist/commands/route.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +315 -14
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setClaudeKey.d.ts +8 -0
- package/dist/commands/setClaudeKey.d.ts.map +1 -0
- package/dist/commands/setClaudeKey.js +35 -0
- package/dist/commands/setClaudeKey.js.map +1 -0
- package/dist/core/AccountFollowMeOrchestrator.d.ts.map +1 -1
- package/dist/core/AccountFollowMeOrchestrator.js +4 -0
- package/dist/core/AccountFollowMeOrchestrator.js.map +1 -1
- package/dist/core/AppMediaStore.d.ts.map +1 -1
- package/dist/core/AppMediaStore.js +3 -0
- package/dist/core/AppMediaStore.js.map +1 -1
- package/dist/core/BackupManager.d.ts.map +1 -1
- package/dist/core/BackupManager.js +2 -0
- package/dist/core/BackupManager.js.map +1 -1
- package/dist/core/ClaudeCliIntelligenceProvider.d.ts.map +1 -1
- package/dist/core/ClaudeCliIntelligenceProvider.js +11 -3
- package/dist/core/ClaudeCliIntelligenceProvider.js.map +1 -1
- package/dist/core/ClaudeKeyHealth.d.ts +141 -0
- package/dist/core/ClaudeKeyHealth.d.ts.map +1 -0
- package/dist/core/ClaudeKeyHealth.js +467 -0
- package/dist/core/ClaudeKeyHealth.js.map +1 -0
- package/dist/core/CodexTaskContinuationStore.d.ts.map +1 -1
- package/dist/core/CodexTaskContinuationStore.js +7 -0
- package/dist/core/CodexTaskContinuationStore.js.map +1 -1
- package/dist/core/CoherenceJournal.d.ts +1 -1
- package/dist/core/CoherenceJournal.d.ts.map +1 -1
- package/dist/core/CoherenceJournal.js +11 -2
- package/dist/core/CoherenceJournal.js.map +1 -1
- package/dist/core/Config.d.ts +8 -0
- package/dist/core/Config.d.ts.map +1 -1
- package/dist/core/Config.js +26 -0
- package/dist/core/Config.js.map +1 -1
- package/dist/core/CredentialSwapExecutor.d.ts.map +1 -1
- package/dist/core/CredentialSwapExecutor.js +10 -0
- package/dist/core/CredentialSwapExecutor.js.map +1 -1
- package/dist/core/DecisionQualityRecorderImpl.d.ts.map +1 -1
- package/dist/core/DecisionQualityRecorderImpl.js +6 -0
- package/dist/core/DecisionQualityRecorderImpl.js.map +1 -1
- package/dist/core/DiscoveryEvaluator.d.ts.map +1 -1
- package/dist/core/DiscoveryEvaluator.js +4 -0
- package/dist/core/DiscoveryEvaluator.js.map +1 -1
- package/dist/core/IdentityReannounceClaimant.d.ts.map +1 -1
- package/dist/core/IdentityReannounceClaimant.js +4 -0
- package/dist/core/IdentityReannounceClaimant.js.map +1 -1
- package/dist/core/IntelligenceRouter.d.ts.map +1 -1
- package/dist/core/IntelligenceRouter.js +9 -0
- package/dist/core/IntelligenceRouter.js.map +1 -1
- package/dist/core/JournalSyncApplier.d.ts +1 -0
- package/dist/core/JournalSyncApplier.d.ts.map +1 -1
- package/dist/core/JournalSyncApplier.js +48 -0
- package/dist/core/JournalSyncApplier.js.map +1 -1
- package/dist/core/LeaseCoordinator.d.ts +4 -0
- package/dist/core/LeaseCoordinator.d.ts.map +1 -1
- package/dist/core/LeaseCoordinator.js +64 -1
- package/dist/core/LeaseCoordinator.js.map +1 -1
- package/dist/core/MessagingToneGate.d.ts +11 -7
- package/dist/core/MessagingToneGate.d.ts.map +1 -1
- package/dist/core/MessagingToneGate.js +15 -1
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/MobileDeviceKeys.d.ts +10 -0
- package/dist/core/MobileDeviceKeys.d.ts.map +1 -1
- package/dist/core/MobileDeviceKeys.js +17 -0
- package/dist/core/MobileDeviceKeys.js.map +1 -1
- package/dist/core/MultiMachineCoordinator.d.ts +12 -0
- package/dist/core/MultiMachineCoordinator.d.ts.map +1 -1
- package/dist/core/MultiMachineCoordinator.js +115 -3
- package/dist/core/MultiMachineCoordinator.js.map +1 -1
- package/dist/core/MutualSshRuntime.d.ts +1 -0
- package/dist/core/MutualSshRuntime.d.ts.map +1 -1
- package/dist/core/MutualSshRuntime.js +17 -1
- package/dist/core/MutualSshRuntime.js.map +1 -1
- package/dist/core/ObservedEndpointTracker.d.ts +1 -0
- package/dist/core/ObservedEndpointTracker.d.ts.map +1 -1
- package/dist/core/ObservedEndpointTracker.js +17 -0
- package/dist/core/ObservedEndpointTracker.js.map +1 -1
- package/dist/core/OverloadShedPlanner.d.ts.map +1 -1
- package/dist/core/OverloadShedPlanner.js +9 -0
- package/dist/core/OverloadShedPlanner.js.map +1 -1
- package/dist/core/OwnershipApplier.d.ts.map +1 -1
- package/dist/core/OwnershipApplier.js +7 -0
- package/dist/core/OwnershipApplier.js.map +1 -1
- package/dist/core/OwnershipReconciler.d.ts.map +1 -1
- package/dist/core/OwnershipReconciler.js +5 -0
- package/dist/core/OwnershipReconciler.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +8 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +76 -2
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/PrHandLease.d.ts.map +1 -1
- package/dist/core/PrHandLease.js +2 -0
- package/dist/core/PrHandLease.js.map +1 -1
- package/dist/core/ProactiveSwapMonitor.d.ts.map +1 -1
- package/dist/core/ProactiveSwapMonitor.js +7 -0
- package/dist/core/ProactiveSwapMonitor.js.map +1 -1
- package/dist/core/ProjectRoundExecution.d.ts.map +1 -1
- package/dist/core/ProjectRoundExecution.js +3 -2
- package/dist/core/ProjectRoundExecution.js.map +1 -1
- package/dist/core/QueueDrainLoop.d.ts +7 -0
- package/dist/core/QueueDrainLoop.d.ts.map +1 -1
- package/dist/core/QueueDrainLoop.js +37 -1
- package/dist/core/QueueDrainLoop.js.map +1 -1
- package/dist/core/RemoteAckStore.d.ts.map +1 -1
- package/dist/core/RemoteAckStore.js +4 -0
- package/dist/core/RemoteAckStore.js.map +1 -1
- package/dist/core/ReplicatedStoreReconcilerWiring.d.ts.map +1 -1
- package/dist/core/ReplicatedStoreReconcilerWiring.js +1 -0
- package/dist/core/ReplicatedStoreReconcilerWiring.js.map +1 -1
- package/dist/core/SecretSync.d.ts +1 -0
- package/dist/core/SecretSync.d.ts.map +1 -1
- package/dist/core/SecretSync.js +16 -0
- package/dist/core/SecretSync.js.map +1 -1
- package/dist/core/SessionManager.d.ts +11 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +125 -14
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/SessionPoolFailoverRunner.d.ts.map +1 -1
- package/dist/core/SessionPoolFailoverRunner.js +4 -0
- package/dist/core/SessionPoolFailoverRunner.js.map +1 -1
- package/dist/core/SleepWakeDetector.d.ts.map +1 -1
- package/dist/core/SleepWakeDetector.js +10 -0
- package/dist/core/SleepWakeDetector.js.map +1 -1
- package/dist/core/SubscriptionReloginStore.d.ts.map +1 -1
- package/dist/core/SubscriptionReloginStore.js +10 -1
- package/dist/core/SubscriptionReloginStore.js.map +1 -1
- package/dist/core/TopicPinMutation.d.ts.map +1 -1
- package/dist/core/TopicPinMutation.js +5 -0
- package/dist/core/TopicPinMutation.js.map +1 -1
- package/dist/core/UnjustifiedStopGate.d.ts.map +1 -1
- package/dist/core/UnjustifiedStopGate.js +22 -0
- package/dist/core/UnjustifiedStopGate.js.map +1 -1
- package/dist/core/WindowRunCadenceExecutor.d.ts.map +1 -1
- package/dist/core/WindowRunCadenceExecutor.js +20 -0
- package/dist/core/WindowRunCadenceExecutor.js.map +1 -1
- package/dist/core/claudeChildAuth.d.ts +68 -0
- package/dist/core/claudeChildAuth.d.ts.map +1 -0
- package/dist/core/claudeChildAuth.js +173 -0
- package/dist/core/claudeChildAuth.js.map +1 -0
- package/dist/core/claudeKeyProbe.d.ts +23 -0
- package/dist/core/claudeKeyProbe.d.ts.map +1 -0
- package/dist/core/claudeKeyProbe.js +68 -0
- package/dist/core/claudeKeyProbe.js.map +1 -0
- package/dist/core/codexDeviceLimitWiring.d.ts.map +1 -1
- package/dist/core/codexDeviceLimitWiring.js +12 -0
- package/dist/core/codexDeviceLimitWiring.js.map +1 -1
- package/dist/core/deliverToConversation.d.ts.map +1 -1
- package/dist/core/deliverToConversation.js +11 -0
- package/dist/core/deliverToConversation.js.map +1 -1
- package/dist/core/meteredCallEntry.d.ts.map +1 -1
- package/dist/core/meteredCallEntry.js +21 -0
- package/dist/core/meteredCallEntry.js.map +1 -1
- package/dist/core/nobodyPollingActuator.d.ts.map +1 -1
- package/dist/core/nobodyPollingActuator.js +5 -0
- package/dist/core/nobodyPollingActuator.js.map +1 -1
- package/dist/core/operatorSurfaceReferral.d.ts +18 -0
- package/dist/core/operatorSurfaceReferral.d.ts.map +1 -0
- package/dist/core/operatorSurfaceReferral.js +32 -0
- package/dist/core/operatorSurfaceReferral.js.map +1 -0
- package/dist/core/ownershipFollowsLiveWork.d.ts.map +1 -1
- package/dist/core/ownershipFollowsLiveWork.js +10 -1
- package/dist/core/ownershipFollowsLiveWork.js.map +1 -1
- package/dist/core/types.d.ts +15 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/worktreeDirtyCheck.d.ts.map +1 -1
- package/dist/core/worktreeDirtyCheck.js +2 -0
- package/dist/core/worktreeDirtyCheck.js.map +1 -1
- package/dist/data/stageBCertifiedSet.d.ts +9 -0
- package/dist/data/stageBCertifiedSet.d.ts.map +1 -1
- package/dist/data/stageBCertifiedSet.js +12 -0
- package/dist/data/stageBCertifiedSet.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +17 -3
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/messaging/attentionHubPolicy.d.ts.map +1 -1
- package/dist/messaging/attentionHubPolicy.js +1 -0
- package/dist/messaging/attentionHubPolicy.js.map +1 -1
- package/dist/monitoring/AgentWorktreeReaper.d.ts.map +1 -1
- package/dist/monitoring/AgentWorktreeReaper.js +15 -0
- package/dist/monitoring/AgentWorktreeReaper.js.map +1 -1
- package/dist/monitoring/ApprenticeshipCycleSlaMonitor.d.ts.map +1 -1
- package/dist/monitoring/ApprenticeshipCycleSlaMonitor.js +18 -9
- package/dist/monitoring/ApprenticeshipCycleSlaMonitor.js.map +1 -1
- package/dist/monitoring/CodexArmSessionSweeper.d.ts.map +1 -1
- package/dist/monitoring/CodexArmSessionSweeper.js +11 -0
- package/dist/monitoring/CodexArmSessionSweeper.js.map +1 -1
- package/dist/monitoring/CrashLoopPauser.d.ts.map +1 -1
- package/dist/monitoring/CrashLoopPauser.js +8 -0
- package/dist/monitoring/CrashLoopPauser.js.map +1 -1
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +7 -1
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/DegradedTmuxGuard.d.ts +2 -0
- package/dist/monitoring/DegradedTmuxGuard.d.ts.map +1 -1
- package/dist/monitoring/DegradedTmuxGuard.js +14 -0
- package/dist/monitoring/DegradedTmuxGuard.js.map +1 -1
- package/dist/monitoring/DurableOutputScrubber.d.ts.map +1 -1
- package/dist/monitoring/DurableOutputScrubber.js +7 -0
- package/dist/monitoring/DurableOutputScrubber.js.map +1 -1
- package/dist/monitoring/DurableVaultSession.d.ts.map +1 -1
- package/dist/monitoring/DurableVaultSession.js +15 -0
- package/dist/monitoring/DurableVaultSession.js.map +1 -1
- package/dist/monitoring/ExternalHogSentinel.d.ts +2 -0
- package/dist/monitoring/ExternalHogSentinel.d.ts.map +1 -1
- package/dist/monitoring/ExternalHogSentinel.js +27 -1
- package/dist/monitoring/ExternalHogSentinel.js.map +1 -1
- package/dist/monitoring/FailureLedger.d.ts.map +1 -1
- package/dist/monitoring/FailureLedger.js +38 -1
- package/dist/monitoring/FailureLedger.js.map +1 -1
- package/dist/monitoring/FeatureEvidenceLog.d.ts +5 -0
- package/dist/monitoring/FeatureEvidenceLog.d.ts.map +1 -1
- package/dist/monitoring/FeatureEvidenceLog.js +25 -0
- package/dist/monitoring/FeatureEvidenceLog.js.map +1 -1
- package/dist/monitoring/GeminiCapacityEscalationMonitor.d.ts.map +1 -1
- package/dist/monitoring/GeminiCapacityEscalationMonitor.js +20 -2
- package/dist/monitoring/GeminiCapacityEscalationMonitor.js.map +1 -1
- package/dist/monitoring/GeminiLoopRunner.d.ts.map +1 -1
- package/dist/monitoring/GeminiLoopRunner.js +11 -1
- package/dist/monitoring/GeminiLoopRunner.js.map +1 -1
- package/dist/monitoring/GreenPrAutoMerger.d.ts.map +1 -1
- package/dist/monitoring/GreenPrAutoMerger.js +11 -0
- package/dist/monitoring/GreenPrAutoMerger.js.map +1 -1
- package/dist/monitoring/GrowthDigestPublisher.d.ts.map +1 -1
- package/dist/monitoring/GrowthDigestPublisher.js +16 -0
- package/dist/monitoring/GrowthDigestPublisher.js.map +1 -1
- package/dist/monitoring/GrowthMilestoneAnalyst.d.ts +3 -0
- package/dist/monitoring/GrowthMilestoneAnalyst.d.ts.map +1 -1
- package/dist/monitoring/GrowthMilestoneAnalyst.js +45 -1
- package/dist/monitoring/GrowthMilestoneAnalyst.js.map +1 -1
- package/dist/monitoring/McpProcessReaper.d.ts +2 -0
- package/dist/monitoring/McpProcessReaper.d.ts.map +1 -1
- package/dist/monitoring/McpProcessReaper.js +32 -0
- package/dist/monitoring/McpProcessReaper.js.map +1 -1
- package/dist/monitoring/MissingLoginSessionDetector.d.ts +2 -1
- package/dist/monitoring/MissingLoginSessionDetector.d.ts.map +1 -1
- package/dist/monitoring/MissingLoginSessionDetector.js +23 -0
- package/dist/monitoring/MissingLoginSessionDetector.js.map +1 -1
- package/dist/monitoring/OrchestratorPoller.d.ts +1 -0
- package/dist/monitoring/OrchestratorPoller.d.ts.map +1 -1
- package/dist/monitoring/OrchestratorPoller.js +13 -0
- package/dist/monitoring/OrchestratorPoller.js.map +1 -1
- package/dist/monitoring/OrphanedWorkSentinel.d.ts.map +1 -1
- package/dist/monitoring/OrphanedWorkSentinel.js +7 -0
- package/dist/monitoring/OrphanedWorkSentinel.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +9 -1
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/ProcessFootprintMonitor.d.ts.map +1 -1
- package/dist/monitoring/ProcessFootprintMonitor.js +20 -2
- package/dist/monitoring/ProcessFootprintMonitor.js.map +1 -1
- package/dist/monitoring/PromiseBeacon.d.ts.map +1 -1
- package/dist/monitoring/PromiseBeacon.js +20 -0
- package/dist/monitoring/PromiseBeacon.js.map +1 -1
- package/dist/monitoring/ReleaseReadinessSentinel.d.ts +2 -0
- package/dist/monitoring/ReleaseReadinessSentinel.d.ts.map +1 -1
- package/dist/monitoring/ReleaseReadinessSentinel.js +26 -0
- package/dist/monitoring/ReleaseReadinessSentinel.js.map +1 -1
- package/dist/monitoring/RopeHealthMonitor.d.ts.map +1 -1
- package/dist/monitoring/RopeHealthMonitor.js +35 -1
- package/dist/monitoring/RopeHealthMonitor.js.map +1 -1
- package/dist/monitoring/SentinelNotifier.d.ts.map +1 -1
- package/dist/monitoring/SentinelNotifier.js +16 -0
- package/dist/monitoring/SentinelNotifier.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts.map +1 -1
- package/dist/monitoring/SessionReaper.js +11 -2
- package/dist/monitoring/SessionReaper.js.map +1 -1
- package/dist/monitoring/SingleMachineFailoverGapDetector.d.ts +2 -0
- package/dist/monitoring/SingleMachineFailoverGapDetector.d.ts.map +1 -1
- package/dist/monitoring/SingleMachineFailoverGapDetector.js +20 -0
- package/dist/monitoring/SingleMachineFailoverGapDetector.js.map +1 -1
- package/dist/monitoring/SpeakerElection.d.ts.map +1 -1
- package/dist/monitoring/SpeakerElection.js +8 -0
- package/dist/monitoring/SpeakerElection.js.map +1 -1
- package/dist/monitoring/StrandedTopicSentinel.d.ts +3 -0
- package/dist/monitoring/StrandedTopicSentinel.d.ts.map +1 -1
- package/dist/monitoring/StrandedTopicSentinel.js +33 -0
- package/dist/monitoring/StrandedTopicSentinel.js.map +1 -1
- package/dist/native/InstarWedgeCanary.app/Contents/MacOS/InstarWedgeCanary +0 -0
- package/dist/native/instar-desktop-host +0 -0
- package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.d.ts.map +1 -1
- package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.js +5 -2
- package/dist/providers/adapters/anthropic-headless/transport/oneShotCompletion.js.map +1 -1
- package/dist/recommended/RecommendedServicesLedger.d.ts +91 -0
- package/dist/recommended/RecommendedServicesLedger.d.ts.map +1 -0
- package/dist/recommended/RecommendedServicesLedger.js +193 -0
- package/dist/recommended/RecommendedServicesLedger.js.map +1 -0
- package/dist/recommended/RecommendedServicesReplicatedStore.d.ts +14 -0
- package/dist/recommended/RecommendedServicesReplicatedStore.d.ts.map +1 -0
- package/dist/recommended/RecommendedServicesReplicatedStore.js +34 -0
- package/dist/recommended/RecommendedServicesReplicatedStore.js.map +1 -0
- package/dist/recommended/legacyDeclines.d.ts +11 -0
- package/dist/recommended/legacyDeclines.d.ts.map +1 -0
- package/dist/recommended/legacyDeclines.js +17 -0
- package/dist/recommended/legacyDeclines.js.map +1 -0
- package/dist/recommended/serviceIds.d.ts +3 -0
- package/dist/recommended/serviceIds.d.ts.map +1 -0
- package/dist/recommended/serviceIds.js +6 -0
- package/dist/recommended/serviceIds.js.map +1 -0
- package/dist/scaffold/templates.d.ts +2 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +8 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/scheduler/JobResultTriage.d.ts.map +1 -1
- package/dist/scheduler/JobResultTriage.js +10 -0
- package/dist/scheduler/JobResultTriage.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +12 -0
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.d.ts +3 -0
- package/dist/scheduler/MentorOnboardingRunner.d.ts.map +1 -1
- package/dist/scheduler/MentorOnboardingRunner.js +24 -2
- package/dist/scheduler/MentorOnboardingRunner.js.map +1 -1
- package/dist/server/AgentServer.d.ts +2 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +76 -15
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/BootHealthBeacon.d.ts +3 -0
- package/dist/server/BootHealthBeacon.d.ts.map +1 -1
- package/dist/server/BootHealthBeacon.js +9 -0
- package/dist/server/BootHealthBeacon.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +10 -1
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/LifelineIngressGuard.d.ts.map +1 -1
- package/dist/server/LifelineIngressGuard.js +11 -0
- package/dist/server/LifelineIngressGuard.js.map +1 -1
- package/dist/server/PoolPollCache.d.ts +4 -0
- package/dist/server/PoolPollCache.d.ts.map +1 -1
- package/dist/server/PoolPollCache.js +33 -0
- package/dist/server/PoolPollCache.js.map +1 -1
- package/dist/server/machineRoutes.d.ts.map +1 -1
- package/dist/server/machineRoutes.js +6 -0
- package/dist/server/machineRoutes.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +6 -0
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/mobileConsoleTicket.d.ts +113 -0
- package/dist/server/mobileConsoleTicket.d.ts.map +1 -0
- package/dist/server/mobileConsoleTicket.js +405 -0
- package/dist/server/mobileConsoleTicket.js.map +1 -0
- package/dist/server/mobileConversationRoutes.d.ts.map +1 -1
- package/dist/server/mobileConversationRoutes.js +20 -1
- package/dist/server/mobileConversationRoutes.js.map +1 -1
- package/dist/server/mobileMediaRoutes.d.ts.map +1 -1
- package/dist/server/mobileMediaRoutes.js +3 -0
- package/dist/server/mobileMediaRoutes.js.map +1 -1
- package/dist/server/mobilePairingRoutes.d.ts +8 -2
- package/dist/server/mobilePairingRoutes.d.ts.map +1 -1
- package/dist/server/mobilePairingRoutes.js +67 -6
- package/dist/server/mobilePairingRoutes.js.map +1 -1
- package/dist/server/mobileSessionTerminalRoutes.d.ts +128 -0
- package/dist/server/mobileSessionTerminalRoutes.d.ts.map +1 -0
- package/dist/server/mobileSessionTerminalRoutes.js +389 -0
- package/dist/server/mobileSessionTerminalRoutes.js.map +1 -0
- package/dist/server/recommendedServiceRoutes.d.ts +13 -0
- package/dist/server/recommendedServiceRoutes.d.ts.map +1 -0
- package/dist/server/recommendedServiceRoutes.js +49 -0
- package/dist/server/recommendedServiceRoutes.js.map +1 -0
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +170 -4
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +36 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/dist/threadline/A2ACheckInProxy.d.ts.map +1 -1
- package/dist/threadline/A2ACheckInProxy.js +26 -15
- package/dist/threadline/A2ACheckInProxy.js.map +1 -1
- package/dist/threadline/AgentTrustManager.d.ts.map +1 -1
- package/dist/threadline/AgentTrustManager.js +3 -0
- package/dist/threadline/AgentTrustManager.js.map +1 -1
- package/dist/threadline/InboundIdLedger.d.ts.map +1 -1
- package/dist/threadline/InboundIdLedger.js +18 -1
- package/dist/threadline/InboundIdLedger.js.map +1 -1
- package/dist/threadline/NegotiatorGate.d.ts.map +1 -1
- package/dist/threadline/NegotiatorGate.js +11 -0
- package/dist/threadline/NegotiatorGate.js.map +1 -1
- package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -1
- package/dist/threadline/PipeSessionSpawner.js +8 -0
- package/dist/threadline/PipeSessionSpawner.js.map +1 -1
- package/dist/threadline/ThreadlineRouter.d.ts.map +1 -1
- package/dist/threadline/ThreadlineRouter.js +13 -0
- package/dist/threadline/ThreadlineRouter.js.map +1 -1
- package/dist/threadline/pairingReplicationWiring.d.ts.map +1 -1
- package/dist/threadline/pairingReplicationWiring.js +9 -0
- package/dist/threadline/pairingReplicationWiring.js.map +1 -1
- package/dist/threadline/relayForward.d.ts.map +1 -1
- package/dist/threadline/relayForward.js +13 -2
- package/dist/threadline/relayForward.js.map +1 -1
- package/dist/threadline/relayUnknownSenderTrust.d.ts +0 -9
- package/dist/threadline/relayUnknownSenderTrust.d.ts.map +1 -1
- package/dist/threadline/relayUnknownSenderTrust.js +16 -0
- package/dist/threadline/relayUnknownSenderTrust.js.map +1 -1
- package/package.json +1 -1
- package/scripts/check-constitution-pairing.mjs +273 -0
- package/scripts/safe-merge.mjs +9 -0
- package/src/data/builtin-manifest.json +103 -103
- package/src/data/feature-ladders.json +113 -113
- package/src/data/stageBCertifiedSet.ts +12 -0
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/src/data/state-coherence-registry.json +18 -0
- package/src/scaffold/templates.ts +9 -0
- package/upgrades/1.3.1650.md +105 -0
- package/upgrades/mobile-console-device-signin.eli16.md +5 -0
- package/upgrades/side-effects/cloud-key-internal-calls.md +116 -0
- package/upgrades/side-effects/constitution-alignment.eli16.md +11 -0
- package/upgrades/side-effects/constitution-alignment.md +69 -0
- package/upgrades/side-effects/feature-evidence-recording.eli16.md +3 -0
- package/upgrades/side-effects/feature-evidence-recording.md +66 -0
- package/upgrades/side-effects/feedback-reroute-admission-parity.md +77 -0
- package/upgrades/side-effects/mobile-console-device-signin.md +102 -0
- package/upgrades/side-effects/mobile-native-session-screen.md +88 -0
- package/upgrades/side-effects/operator-needs-first-screen.md +87 -0
- package/upgrades/side-effects/recommended-services-choices.md +50 -0
- package/upgrades/side-effects/rerouted-lifetime-active-process.md +63 -0
- package/upgrades/side-effects/undated-resurfacer-e2e-wait.eli16.md +5 -0
- package/upgrades/side-effects/undated-resurfacer-e2e-wait.md +9 -0
|
@@ -28,6 +28,7 @@ import { Router } from 'express';
|
|
|
28
28
|
import { resolveDevAgentGate } from '../core/devAgentGate.js';
|
|
29
29
|
import { arrivedOverLocalTls } from '../core/desktopTransport.js';
|
|
30
30
|
import { PairingCodeStore, NONCE_PATTERN, buildPairLink, cleanText, codeTtlMs, pingAnswer, stableOrigin, } from '../core/MobilePairing.js';
|
|
31
|
+
import { featureEvidence } from '../monitoring/FeatureEvidenceLog.js';
|
|
31
32
|
import { ConfirmationCodes, DeviceRegistry, displayCode, ReplayGuard, parseDevicePublicKey, verifyDeviceRequest, } from '../core/MobileDeviceKeys.js';
|
|
32
33
|
import { isPeerUrlAllowedForCredentials } from './peerUrlGuard.js';
|
|
33
34
|
import { poolPeerFetch } from './poolPeerFetch.js';
|
|
@@ -38,6 +39,7 @@ import { PairingInviteTelegram } from '../threadline/PairingInviteTelegram.js';
|
|
|
38
39
|
import { APP_CONVERSATION_KEY_PATTERN, derivedEventId, hideCredentialSpans, removeAuthorityTokens } from '../core/appConversationText.js';
|
|
39
40
|
import { deviceKeyHashOf } from '../core/AppRecordSignatures.js';
|
|
40
41
|
import { buildSignedOrigin } from './mobileConversationRoutes.js';
|
|
42
|
+
import { mountConsoleTicketDeviceRoutes } from './mobileConsoleTicket.js';
|
|
41
43
|
import { checkSignedFiles, claimMediaUploads, mediaRecordTooLarge, mirrorMediaToTelegram, preflightMediaAttachments, publishMediaMessage, signedFileHashParts, } from './mobileMediaSend.js';
|
|
42
44
|
import { isExactStopMessage } from '../core/MessageSentinel.js';
|
|
43
45
|
import { UserManager } from '../users/UserManager.js';
|
|
@@ -392,16 +394,26 @@ export class MobilePairingService {
|
|
|
392
394
|
this.deviceRate.set(deviceId, arr);
|
|
393
395
|
return true;
|
|
394
396
|
}
|
|
395
|
-
/**
|
|
396
|
-
|
|
397
|
+
/**
|
|
398
|
+
* A rule's own per-minute bucket, independent of the read allowance. Each named bucket counts
|
|
399
|
+
* separately (media chunks use 'default'; the session screen has its own two), and a key whose
|
|
400
|
+
* window has emptied is deleted, so the map holds only devices active in the last minute.
|
|
401
|
+
*/
|
|
402
|
+
deviceBucketOk(deviceId, perMinute, bucket = 'default') {
|
|
397
403
|
const t = this.now();
|
|
398
|
-
const
|
|
404
|
+
const key = bucket === 'default' ? deviceId : `${deviceId}\u0000${bucket}`;
|
|
405
|
+
const arr = (this.deviceBucket.get(key) ?? []).filter((x) => t - x < 60_000);
|
|
399
406
|
if (arr.length >= perMinute) {
|
|
400
|
-
this.deviceBucket.set(
|
|
407
|
+
this.deviceBucket.set(key, arr);
|
|
401
408
|
return false;
|
|
402
409
|
}
|
|
403
410
|
arr.push(t);
|
|
404
|
-
this.deviceBucket.set(
|
|
411
|
+
this.deviceBucket.set(key, arr);
|
|
412
|
+
if (this.deviceBucket.size > 64) {
|
|
413
|
+
for (const [k, v] of this.deviceBucket)
|
|
414
|
+
if (!v.some((x) => t - x < 60_000))
|
|
415
|
+
this.deviceBucket.delete(k);
|
|
416
|
+
}
|
|
405
417
|
return true;
|
|
406
418
|
}
|
|
407
419
|
/** Inbound Telegram text: void any pending device whose live code appears in it. */
|
|
@@ -609,12 +621,14 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
609
621
|
const reqHost = normalizeRequestHost(req.headers.host);
|
|
610
622
|
const eligible = svc.redeemHostEligible(reqHost);
|
|
611
623
|
if (!arrivedOverLocalTls(req.secure, req.socket.remoteAddress, req.headers['x-forwarded-proto']) || !eligible) {
|
|
624
|
+
featureEvidence.recordAtMostEvery('mobilePairing', 'redeem|not-secure-address', 60_000, { kind: 'held', reason: 'redeem refused: not-secure-address' });
|
|
612
625
|
res.status(403).json({ error: 'Pairing only works over this agent\'s secure address.' });
|
|
613
626
|
return;
|
|
614
627
|
}
|
|
615
628
|
const body = (req.body ?? {});
|
|
616
629
|
const publicKey = typeof body.devicePublicKey === 'string' ? body.devicePublicKey : '';
|
|
617
630
|
if (!parseDevicePublicKey(publicKey)) {
|
|
631
|
+
featureEvidence.recordAtMostEvery('mobilePairing', 'redeem|bad-device-key', 60_000, { kind: 'held', reason: 'redeem refused: bad-device-key' });
|
|
618
632
|
res.status(400).json({ error: 'A valid device public key is required.' });
|
|
619
633
|
return;
|
|
620
634
|
}
|
|
@@ -624,16 +638,19 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
624
638
|
// session, which needs no lease.
|
|
625
639
|
const approval = svc.approvalPath();
|
|
626
640
|
if (!approval || (approval === 'telegram' && !svc.holdsLease())) {
|
|
641
|
+
featureEvidence.recordAtMostEvery('mobilePairing', 'redeem|approval-unavailable', 60_000, { kind: 'held', reason: 'redeem refused: approval-unavailable' });
|
|
627
642
|
res.status(409).json({ error: 'approval-unavailable', detail: 'This agent cannot send you the confirmation code right now (no Telegram owner chat on this machine).' });
|
|
628
643
|
return;
|
|
629
644
|
}
|
|
630
645
|
if (svc.devices.pairingPaused()) {
|
|
646
|
+
featureEvidence.recordAtMostEvery('mobilePairing', 'redeem|pairing-paused', 60_000, { kind: 'held', reason: 'redeem refused: pairing-paused' });
|
|
631
647
|
res.status(429).json({ error: 'pairing-paused' });
|
|
632
648
|
return;
|
|
633
649
|
}
|
|
634
650
|
// Take-and-delete happens synchronously inside redeem(), before any async work.
|
|
635
651
|
const r = svc.codes.redeem(body.code, token);
|
|
636
652
|
if (!r.ok) {
|
|
653
|
+
featureEvidence.recordAtMostEvery('mobilePairing', `redeem|${r.reason}`, 60_000, { kind: 'held', reason: `redeem refused: ${r.reason}` });
|
|
637
654
|
if (r.reason === 'too-many-attempts') {
|
|
638
655
|
res.status(429).json({ error: 'too-many-attempts' });
|
|
639
656
|
return;
|
|
@@ -644,6 +661,7 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
644
661
|
// §3.2 step 3: an honest phone sends to the link's own origin. A code with no bound origin
|
|
645
662
|
// (minted before this change, in this process) keeps the old rule: the eligible host.
|
|
646
663
|
if (r.bound && (r.bound.host !== reqHost || r.bound.kind !== eligible.kind)) {
|
|
664
|
+
featureEvidence.recordAtMostEvery('mobilePairing', 'redeem|wrong-origin', 60_000, { kind: 'held', reason: 'redeem refused: wrong-origin' });
|
|
647
665
|
res.status(403).json({ error: 'That link has expired or was already used.' });
|
|
648
666
|
return;
|
|
649
667
|
}
|
|
@@ -653,11 +671,13 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
653
671
|
}
|
|
654
672
|
catch (err) {
|
|
655
673
|
svc.deps.reportDegradation?.('MobilePairing.registryWrite', err);
|
|
674
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'redeem failed: registry write', context: { routeKind: eligible.kind } });
|
|
656
675
|
res.status(500).json({ error: 'Could not record the device. Ask for a new link.' });
|
|
657
676
|
return;
|
|
658
677
|
}
|
|
659
678
|
if (!created.ok) {
|
|
660
679
|
const status = created.reason === 'duplicate-key' ? 409 : 429;
|
|
680
|
+
featureEvidence.record('mobilePairing', { kind: 'held', reason: `redeem refused: ${created.reason}`, context: { routeKind: eligible.kind, status } });
|
|
661
681
|
res.status(status).json({ error: created.reason });
|
|
662
682
|
return;
|
|
663
683
|
}
|
|
@@ -672,6 +692,7 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
672
692
|
svc.holdDashboardCode(device.id, code, Date.parse(device.expiresAt));
|
|
673
693
|
// dashboard-console-default-and-pair-page §3.3: the code page on the host this phone just
|
|
674
694
|
// redeemed on (already checked above: local TLS, an eligible host, the code's bound host).
|
|
695
|
+
featureEvidence.record('mobilePairing', { kind: 'fired', reason: 'redeemed: code held on dashboard', context: { deviceId: device.id, approval: 'dashboard', role: device.role ?? 'owner', routeKind: eligible.kind, codeFormat } });
|
|
675
696
|
res.json({ deviceId: device.id, agentName: svc.deps.config.projectName, status: 'pending', approval: 'dashboard', codeFormat,
|
|
676
697
|
codePageUrl: codePageUrlForDevice(reqHost, device.id) });
|
|
677
698
|
return;
|
|
@@ -707,9 +728,11 @@ export function mountPublicMobilePairingRoutes(app, svc) {
|
|
|
707
728
|
catch (err) {
|
|
708
729
|
svc.deps.reportDegradation?.('MobilePairing.registryWrite', err);
|
|
709
730
|
}
|
|
731
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'redeem failed: confirmation code not delivered', context: { deviceId: device.id, routeKind: eligible.kind } });
|
|
710
732
|
res.status(409).json({ error: 'approval-unavailable', detail: 'I could not send you the confirmation code in Telegram. Open a private chat with the bot and send it any message, then ask me for a new link.' });
|
|
711
733
|
return;
|
|
712
734
|
}
|
|
735
|
+
featureEvidence.record('mobilePairing', { kind: 'fired', reason: 'redeemed: code sent by Telegram', context: { deviceId: device.id, approval: 'telegram', role: device.role ?? 'owner', routeKind: eligible.kind, codeFormat } });
|
|
713
736
|
res.json({ deviceId: device.id, agentName: svc.deps.config.projectName, status: 'pending', approval: 'telegram', codeFormat });
|
|
714
737
|
});
|
|
715
738
|
}
|
|
@@ -1062,15 +1085,18 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1062
1085
|
catch (err) {
|
|
1063
1086
|
deps.reportDegradation?.('MobilePairing.registryWrite', err);
|
|
1064
1087
|
}
|
|
1088
|
+
featureEvidence.record('mobilePairing', { kind: 'held', reason: 'confirm refused: approval-moved', context: { deviceId: d.id } });
|
|
1065
1089
|
res.status(409).json({ error: 'approval-moved', detail: 'This pairing moved machines. Ask for a new link.' });
|
|
1066
1090
|
return;
|
|
1067
1091
|
}
|
|
1068
1092
|
if (svc.devices.pairingPaused()) {
|
|
1093
|
+
featureEvidence.record('mobilePairing', { kind: 'held', reason: 'confirm refused: pairing-paused', context: { deviceId: d.id } });
|
|
1069
1094
|
res.status(429).json({ error: 'pairing-paused' });
|
|
1070
1095
|
return;
|
|
1071
1096
|
}
|
|
1072
1097
|
const check = svc.confirm.check(d.id, req.body?.code);
|
|
1073
1098
|
if (check.result === 'none') {
|
|
1099
|
+
featureEvidence.record('mobilePairing', { kind: 'held', reason: 'confirm refused: expired', context: { deviceId: d.id } });
|
|
1074
1100
|
res.status(409).json({ error: 'expired' });
|
|
1075
1101
|
return;
|
|
1076
1102
|
}
|
|
@@ -1088,6 +1114,7 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1088
1114
|
}
|
|
1089
1115
|
catch (err) {
|
|
1090
1116
|
deps.reportDegradation?.('MobilePairing.keyLedger', err);
|
|
1117
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'confirm failed: key ledger write', context: { deviceId: d.id, approvedVia } });
|
|
1091
1118
|
res.status(500).json({ error: 'Could not record the confirmation. Try again.' });
|
|
1092
1119
|
return;
|
|
1093
1120
|
}
|
|
@@ -1097,6 +1124,7 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1097
1124
|
}
|
|
1098
1125
|
catch (err) {
|
|
1099
1126
|
deps.reportDegradation?.('MobilePairing.registryWrite', err);
|
|
1127
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'confirm failed: registry write', context: { deviceId: d.id, approvedVia } });
|
|
1100
1128
|
res.status(500).json({ error: 'Could not record the confirmation. Try again.' });
|
|
1101
1129
|
return;
|
|
1102
1130
|
}
|
|
@@ -1106,9 +1134,11 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1106
1134
|
for (const [n, id] of svc.declineNonces)
|
|
1107
1135
|
if (id === d.id)
|
|
1108
1136
|
svc.declineNonces.delete(n);
|
|
1137
|
+
featureEvidence.record('mobilePairing', { kind: 'fired', reason: 'confirmed', context: { deviceId: d.id, approvedVia, role: d.role ?? 'owner' } });
|
|
1109
1138
|
res.json({ status: 'active' });
|
|
1110
1139
|
return;
|
|
1111
1140
|
}
|
|
1141
|
+
featureEvidence.record('mobilePairing', { kind: 'held', reason: 'confirm refused: wrong code', context: { deviceId: d.id, nowDeclined: after?.status === 'declined', pairingPaused: svc.devices.pairingPaused() } });
|
|
1112
1142
|
if (svc.devices.pairingPaused()) {
|
|
1113
1143
|
deps.raiseAttention?.('Phone pairing paused', 'Ten wrong pairing codes were entered in the last 24 hours, so phone pairing is paused for now. If you were not pairing a phone, someone may be guessing.');
|
|
1114
1144
|
}
|
|
@@ -1121,6 +1151,8 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1121
1151
|
}
|
|
1122
1152
|
res.status(403).json({ error: 'wrong-code' });
|
|
1123
1153
|
});
|
|
1154
|
+
// Console sign-in from an owner phone (docs/specs/mobile-console-device-signin.md).
|
|
1155
|
+
mountConsoleTicketDeviceRoutes(router, svc);
|
|
1124
1156
|
// Revoke: bearer may revoke any device; a device only itself.
|
|
1125
1157
|
router.post('/mobile/devices/:id/revoke', async (req, res) => {
|
|
1126
1158
|
if (!svc.enabled()) {
|
|
@@ -1158,11 +1190,13 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1158
1190
|
}
|
|
1159
1191
|
catch (err) {
|
|
1160
1192
|
deps.reportDegradation?.('MobilePairing.registryWrite', err);
|
|
1193
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'revoke failed: registry write', context: { deviceId: id, by: p.kind } });
|
|
1161
1194
|
res.status(500).json({ error: 'Could not record the revocation. Try again.' });
|
|
1162
1195
|
return;
|
|
1163
1196
|
}
|
|
1164
1197
|
if (held) {
|
|
1165
1198
|
svc.confirm.drop(id);
|
|
1199
|
+
featureEvidence.record('mobilePairing', { kind: 'fired', reason: 'revoked here', context: { deviceId: id, by: p.kind, heldHere: true } });
|
|
1166
1200
|
res.json({ revoked: true, machine: deps.selfMachineId ?? null });
|
|
1167
1201
|
return;
|
|
1168
1202
|
}
|
|
@@ -1172,9 +1206,11 @@ export function createMobilePairingRouter(svc, deps, poolCtx) {
|
|
|
1172
1206
|
}
|
|
1173
1207
|
const r = await forwardRevoke(poolCtx, id);
|
|
1174
1208
|
if (r.confirmedBy) {
|
|
1209
|
+
featureEvidence.record('mobilePairing', { kind: 'fired', reason: 'revoked by a peer', context: { deviceId: id, by: p.kind, heldHere: false } });
|
|
1175
1210
|
res.json({ revoked: true, machine: r.confirmedBy });
|
|
1176
1211
|
return;
|
|
1177
1212
|
}
|
|
1213
|
+
featureEvidence.record('mobilePairing', { kind: 'error', reason: 'revoke unconfirmed: no machine holding this phone answered', context: { deviceId: id, by: p.kind } });
|
|
1178
1214
|
res.status(202).json({ pending: true, detail: 'No machine holding this phone confirmed yet. Until one does, the phone may still have access. Revoke it on the machine that serves its address for an immediate effect.' });
|
|
1179
1215
|
});
|
|
1180
1216
|
// ── Mobile push (docs/specs/mobile-push.md) ──
|
|
@@ -1733,6 +1769,8 @@ const UUID = APP_CONVERSATION_KEY_PATTERN;
|
|
|
1733
1769
|
// `unassignedOk`: the route answers a phone whose person is no longer in the registry (people and
|
|
1734
1770
|
// roles §3.4): only its own status, confirm and self-revoke. `conversationRef`: the route names a
|
|
1735
1771
|
// conversation, so it must call the shared `mayUse` check (the coverage test reads this flag).
|
|
1772
|
+
// `ownerOnly`: only a phone whose person is the owner (403 owner-phone-required otherwise).
|
|
1773
|
+
// `bucket`: the name of the rule's own bucket (rules sharing a name share a count).
|
|
1736
1774
|
export const DEVICE_ALLOWLIST = (() => {
|
|
1737
1775
|
const active = new Set(['active']);
|
|
1738
1776
|
return [
|
|
@@ -1775,7 +1813,18 @@ export const DEVICE_ALLOWLIST = (() => {
|
|
|
1775
1813
|
{ method: 'GET', re: new RegExp(`^/mobile/media/uploads/${UUID}$`), statuses: active, body: 'none' },
|
|
1776
1814
|
{ method: 'GET', re: /^\/mobile\/media\/[0-9a-f]{64}$/, statuses: active, body: 'none', conversationRef: true },
|
|
1777
1815
|
{ method: 'POST', re: /^\/mobile\/media\/purge$/, statuses: active, body: 'json', conversationRef: true },
|
|
1816
|
+
// Console sign-in from an owner phone (mobile-console-device-signin §3.1-3.2); each route
|
|
1817
|
+
// re-checks owner, local TLS and the feature switch itself.
|
|
1818
|
+
{ method: 'POST', re: /^\/mobile\/device\/presence-key$/, statuses: active, body: 'json' },
|
|
1819
|
+
{ method: 'POST', re: /^\/mobile\/console-ticket\/challenge$/, statuses: active, body: 'json' },
|
|
1820
|
+
{ method: 'POST', re: /^\/mobile\/console-ticket$/, statuses: active, body: 'json' },
|
|
1778
1821
|
{ method: 'POST', re: /^\/mobile\/devices\/[^/]+\/revoke$/, statuses: new Set(['pending', 'active', 'declined', 'expired']), unassignedOk: true },
|
|
1822
|
+
// The native session screen (docs/specs/mobile-native-session-screen.md): read a session's pane
|
|
1823
|
+
// and type plain text into it. Owner phones only; each has its own bucket so polling and typing
|
|
1824
|
+
// never use up the read allowance the chat list needs. The path is lower-cased here; the router
|
|
1825
|
+
// reads the name with its case kept.
|
|
1826
|
+
{ method: 'GET', re: /^\/sessions\/[a-z0-9_-]{1,200}\/output$/, statuses: active, body: 'none', ownerOnly: true, ownBucket: 90, bucket: 'session-output' },
|
|
1827
|
+
{ method: 'POST', re: /^\/sessions\/[a-z0-9_-]{1,200}\/input$/, statuses: active, body: 'json', ownerOnly: true, ownBucket: 12, bucket: 'session-input' },
|
|
1779
1828
|
];
|
|
1780
1829
|
})();
|
|
1781
1830
|
/**
|
|
@@ -1837,6 +1886,9 @@ export function deviceAuthenticator(svc) {
|
|
|
1837
1886
|
if (svc.ownNames) {
|
|
1838
1887
|
const h = normalizeRequestHost(req.headers.host);
|
|
1839
1888
|
if (!h || !svc.ownNames.accepts(h) || !arrivedOverLocalTls(req.secure, req.socket.remoteAddress, req.headers['x-forwarded-proto'])) {
|
|
1889
|
+
// The bar is about OWN names: a name that is not ours is someone knocking, not a refusal of a real route.
|
|
1890
|
+
const ownName = !!h && svc.ownNames.accepts(h);
|
|
1891
|
+
featureEvidence.recordAtMostEvery('mobilePairing.multiRoute', `host-refused|${ownName}`, 60_000, { kind: ownName ? 'error' : 'held', reason: ownName ? 'refused on an own name: not over local TLS' : 'refused: host is not an own name', context: { ownName, routeKind: ownName ? svc.ownNames.listed().find((n) => n.host === h)?.kind ?? 'unknown' : null } });
|
|
1840
1892
|
return refuse(401, 'device-unauthorized');
|
|
1841
1893
|
}
|
|
1842
1894
|
host = h;
|
|
@@ -1851,10 +1903,13 @@ export function deviceAuthenticator(svc) {
|
|
|
1851
1903
|
const ledgerRevoked = !!svc.keyLedger && svc.keyLedger.isRevoked(deviceKeyHashOf(d.publicKey), d.id);
|
|
1852
1904
|
return { publicKey: d.publicKey, host: d.host, status: ledgerRevoked ? 'revoked' : d.status };
|
|
1853
1905
|
}, rule.statuses, svc.replay, Date.now(), rule.sendRoute === true);
|
|
1906
|
+
if (!v.ok && host) {
|
|
1907
|
+
featureEvidence.recordAtMostEvery('mobilePairing.multiRoute', `signature-refused|${v.reason}|${host}`, 60_000, { kind: v.reason === 'rate-limited' ? 'held' : 'error', reason: `signature refused on an own name: ${v.reason}`, context: { signatureReason: v.reason, host, routeKind: svc.ownNames?.listed().find((n) => n.host === host)?.kind ?? 'unknown' } });
|
|
1908
|
+
}
|
|
1854
1909
|
if (!v.ok)
|
|
1855
1910
|
return refuse(v.reason === 'rate-limited' ? 429 : 401, v.reason === 'rate-limited' ? 'too-many-requests' : 'device-unauthorized');
|
|
1856
1911
|
if (rule.ownBucket !== undefined) {
|
|
1857
|
-
if (!svc.deviceBucketOk(v.deviceId, rule.ownBucket))
|
|
1912
|
+
if (!svc.deviceBucketOk(v.deviceId, rule.ownBucket, rule.bucket))
|
|
1858
1913
|
return refuse(429, 'too-many-requests');
|
|
1859
1914
|
}
|
|
1860
1915
|
else if (!(rule.sendRoute && svc.nativeOn) && !svc.deviceRateOk(v.deviceId))
|
|
@@ -1869,6 +1924,8 @@ export function deviceAuthenticator(svc) {
|
|
|
1869
1924
|
return refuse(403, 'person-unknown');
|
|
1870
1925
|
}
|
|
1871
1926
|
else {
|
|
1927
|
+
if (rule.ownerOnly && person.role !== 'owner')
|
|
1928
|
+
return refuse(403, 'owner-phone-required');
|
|
1872
1929
|
req.instarDevicePerson = person;
|
|
1873
1930
|
}
|
|
1874
1931
|
req.instarPrincipal = { kind: 'device', deviceId: v.deviceId };
|
|
@@ -1877,6 +1934,10 @@ export function deviceAuthenticator(svc) {
|
|
|
1877
1934
|
// The Host the signature was checked against (multi-route: one of this machine's own names;
|
|
1878
1935
|
// otherwise the paired host). Signed records store THIS host, never the paired one.
|
|
1879
1936
|
req.instarDeviceHost = host ?? svc.devices.get(v.deviceId)?.host ?? '';
|
|
1937
|
+
if (host) {
|
|
1938
|
+
// Per request by nature: one row a device and route an hour, carrying how many it stands for.
|
|
1939
|
+
featureEvidence.recordAtMostEvery('mobilePairing.multiRoute', `accepted|${v.deviceId}|${host}`, 60 * 60 * 1000, { kind: 'fired', reason: 'signature accepted on an own name', context: { deviceId: v.deviceId, host, routeKind: svc.ownNames?.listed().find((n) => n.host === host)?.kind ?? 'unknown', pairedHost: rec?.host === host } });
|
|
1940
|
+
}
|
|
1880
1941
|
return 'ok';
|
|
1881
1942
|
};
|
|
1882
1943
|
}
|