instar 0.28.76 → 0.28.77
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/index.html +306 -0
- package/dist/cli.js +5 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/discovery.d.ts.map +1 -1
- package/dist/commands/discovery.js +2 -2
- package/dist/commands/discovery.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +22 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/job.d.ts.map +1 -1
- package/dist/commands/job.js +2 -2
- package/dist/commands/job.js.map +1 -1
- package/dist/commands/ledgerCleanup.d.ts.map +1 -1
- package/dist/commands/ledgerCleanup.js +2 -2
- package/dist/commands/ledgerCleanup.js.map +1 -1
- package/dist/commands/listener.d.ts.map +1 -1
- package/dist/commands/listener.js +7 -12
- package/dist/commands/listener.js.map +1 -1
- package/dist/commands/nuke.d.ts.map +1 -1
- package/dist/commands/nuke.js +11 -21
- package/dist/commands/nuke.js.map +1 -1
- package/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +35 -5
- package/dist/commands/server.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +11 -15
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/slack-cli.d.ts.map +1 -1
- package/dist/commands/slack-cli.js +5 -8
- package/dist/commands/slack-cli.js.map +1 -1
- package/dist/commands/whatsapp.d.ts.map +1 -1
- package/dist/commands/whatsapp.js +2 -2
- package/dist/commands/whatsapp.js.map +1 -1
- package/dist/commands/worktree.d.ts.map +1 -1
- package/dist/commands/worktree.js +2 -2
- package/dist/commands/worktree.js.map +1 -1
- package/dist/core/AgentConnector.d.ts.map +1 -1
- package/dist/core/AgentConnector.js +9 -10
- package/dist/core/AgentConnector.js.map +1 -1
- package/dist/core/AgentRegistry.d.ts.map +1 -1
- package/dist/core/AgentRegistry.js +3 -4
- package/dist/core/AgentRegistry.js.map +1 -1
- package/dist/core/AutoDispatcher.d.ts.map +1 -1
- package/dist/core/AutoDispatcher.js +2 -2
- package/dist/core/AutoDispatcher.js.map +1 -1
- package/dist/core/AutoUpdater.d.ts.map +1 -1
- package/dist/core/AutoUpdater.js +2 -2
- package/dist/core/AutoUpdater.js.map +1 -1
- package/dist/core/AutonomousEvolution.d.ts.map +1 -1
- package/dist/core/AutonomousEvolution.js +2 -2
- package/dist/core/AutonomousEvolution.js.map +1 -1
- package/dist/core/BackupManager.d.ts.map +1 -1
- package/dist/core/BackupManager.js +2 -2
- package/dist/core/BackupManager.js.map +1 -1
- package/dist/core/BranchManager.d.ts.map +1 -1
- package/dist/core/BranchManager.js +3 -3
- package/dist/core/BranchManager.js.map +1 -1
- package/dist/core/CaffeinateManager.d.ts.map +1 -1
- package/dist/core/CaffeinateManager.js +2 -2
- package/dist/core/CaffeinateManager.js.map +1 -1
- package/dist/core/DeferredDispatchTracker.d.ts.map +1 -1
- package/dist/core/DeferredDispatchTracker.js +2 -2
- package/dist/core/DeferredDispatchTracker.js.map +1 -1
- package/dist/core/DispatchManager.d.ts.map +1 -1
- package/dist/core/DispatchManager.js +3 -4
- package/dist/core/DispatchManager.js.map +1 -1
- package/dist/core/EvolutionManager.d.ts.map +1 -1
- package/dist/core/EvolutionManager.js +2 -2
- package/dist/core/EvolutionManager.js.map +1 -1
- package/dist/core/ExecutionJournal.d.ts.map +1 -1
- package/dist/core/ExecutionJournal.js +2 -2
- package/dist/core/ExecutionJournal.js.map +1 -1
- package/dist/core/FeedbackManager.d.ts.map +1 -1
- package/dist/core/FeedbackManager.js +2 -2
- package/dist/core/FeedbackManager.js.map +1 -1
- package/dist/core/FileClassifier.d.ts.map +1 -1
- package/dist/core/FileClassifier.js +8 -17
- package/dist/core/FileClassifier.js.map +1 -1
- package/dist/core/ForegroundRestartWatcher.d.ts.map +1 -1
- package/dist/core/ForegroundRestartWatcher.js +3 -4
- package/dist/core/ForegroundRestartWatcher.js.map +1 -1
- package/dist/core/GitStateManager.d.ts.map +1 -1
- package/dist/core/GitStateManager.js +3 -12
- package/dist/core/GitStateManager.js.map +1 -1
- package/dist/core/GitSync.d.ts.map +1 -1
- package/dist/core/GitSync.js +6 -6
- package/dist/core/GitSync.js.map +1 -1
- package/dist/core/GlobalInstallCleanup.d.ts.map +1 -1
- package/dist/core/GlobalInstallCleanup.js +3 -4
- package/dist/core/GlobalInstallCleanup.js.map +1 -1
- package/dist/core/GlobalSecretStore.d.ts.map +1 -1
- package/dist/core/GlobalSecretStore.js +3 -4
- package/dist/core/GlobalSecretStore.js.map +1 -1
- package/dist/core/HandoffManager.d.ts.map +1 -1
- package/dist/core/HandoffManager.js +5 -5
- package/dist/core/HandoffManager.js.map +1 -1
- package/dist/core/JargonDetector.d.ts +28 -0
- package/dist/core/JargonDetector.d.ts.map +1 -0
- package/dist/core/JargonDetector.js +59 -0
- package/dist/core/JargonDetector.js.map +1 -0
- package/dist/core/LedgerSessionRegistry.d.ts.map +1 -1
- package/dist/core/LedgerSessionRegistry.js +2 -2
- package/dist/core/LedgerSessionRegistry.js.map +1 -1
- package/dist/core/MachineIdentity.d.ts.map +1 -1
- package/dist/core/MachineIdentity.js +2 -2
- package/dist/core/MachineIdentity.js.map +1 -1
- package/dist/core/MessagingToneGate.d.ts +42 -5
- package/dist/core/MessagingToneGate.d.ts.map +1 -1
- package/dist/core/MessagingToneGate.js +40 -6
- package/dist/core/MessagingToneGate.js.map +1 -1
- package/dist/core/ParallelDevWiring.d.ts.map +1 -1
- package/dist/core/ParallelDevWiring.js +3 -6
- package/dist/core/ParallelDevWiring.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +26 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +249 -46
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/ProjectMapper.d.ts.map +1 -1
- package/dist/core/ProjectMapper.js +5 -11
- package/dist/core/ProjectMapper.js.map +1 -1
- package/dist/core/RelationshipManager.d.ts.map +1 -1
- package/dist/core/RelationshipManager.js +4 -5
- package/dist/core/RelationshipManager.js.map +1 -1
- package/dist/core/SafeGitExecutor.d.ts +11 -5
- package/dist/core/SafeGitExecutor.d.ts.map +1 -1
- package/dist/core/SafeGitExecutor.js +87 -1
- package/dist/core/SafeGitExecutor.js.map +1 -1
- package/dist/core/ScopeVerifier.d.ts.map +1 -1
- package/dist/core/ScopeVerifier.js +3 -6
- package/dist/core/ScopeVerifier.js.map +1 -1
- package/dist/core/SecretStore.d.ts.map +1 -1
- package/dist/core/SecretStore.js +2 -2
- package/dist/core/SecretStore.js.map +1 -1
- package/dist/core/SharedStateLedger.d.ts.map +1 -1
- package/dist/core/SharedStateLedger.js +2 -2
- package/dist/core/SharedStateLedger.js.map +1 -1
- package/dist/core/SoulManager.d.ts.map +1 -1
- package/dist/core/SoulManager.js +3 -4
- package/dist/core/SoulManager.js.map +1 -1
- package/dist/core/StateManager.d.ts.map +1 -1
- package/dist/core/StateManager.js +4 -6
- package/dist/core/StateManager.js.map +1 -1
- package/dist/core/SyncOrchestrator.d.ts.map +1 -1
- package/dist/core/SyncOrchestrator.js +6 -7
- package/dist/core/SyncOrchestrator.js.map +1 -1
- package/dist/core/UpdateChecker.d.ts.map +1 -1
- package/dist/core/UpdateChecker.js +3 -4
- package/dist/core/UpdateChecker.js.map +1 -1
- package/dist/core/UpgradeGuideProcessor.d.ts.map +1 -1
- package/dist/core/UpgradeGuideProcessor.js +3 -4
- package/dist/core/UpgradeGuideProcessor.js.map +1 -1
- package/dist/core/WorktreeManager.d.ts.map +1 -1
- package/dist/core/WorktreeManager.js +9 -14
- package/dist/core/WorktreeManager.js.map +1 -1
- package/dist/knowledge/KnowledgeManager.d.ts.map +1 -1
- package/dist/knowledge/KnowledgeManager.js +2 -2
- package/dist/knowledge/KnowledgeManager.js.map +1 -1
- package/dist/lifeline/ServerSupervisor.d.ts +28 -0
- package/dist/lifeline/ServerSupervisor.d.ts.map +1 -1
- package/dist/lifeline/ServerSupervisor.js +171 -73
- package/dist/lifeline/ServerSupervisor.js.map +1 -1
- package/dist/lifeline/TelegramLifeline.d.ts.map +1 -1
- package/dist/lifeline/TelegramLifeline.js +10 -4
- package/dist/lifeline/TelegramLifeline.js.map +1 -1
- package/dist/lifeline/detectLaunchdSupervised.d.ts +43 -0
- package/dist/lifeline/detectLaunchdSupervised.d.ts.map +1 -0
- package/dist/lifeline/detectLaunchdSupervised.js +106 -0
- package/dist/lifeline/detectLaunchdSupervised.js.map +1 -0
- package/dist/lifeline/droppedMessages.d.ts.map +1 -1
- package/dist/lifeline/droppedMessages.js +2 -2
- package/dist/lifeline/droppedMessages.js.map +1 -1
- package/dist/memory/EpisodicMemory.d.ts.map +1 -1
- package/dist/memory/EpisodicMemory.js +2 -2
- package/dist/memory/EpisodicMemory.js.map +1 -1
- package/dist/memory/TopicMemory.d.ts.map +1 -1
- package/dist/memory/TopicMemory.js +5 -8
- package/dist/memory/TopicMemory.js.map +1 -1
- package/dist/messaging/AgentTokenManager.d.ts.map +1 -1
- package/dist/messaging/AgentTokenManager.js +2 -2
- package/dist/messaging/AgentTokenManager.js.map +1 -1
- package/dist/messaging/DropPickup.d.ts.map +1 -1
- package/dist/messaging/DropPickup.js +2 -2
- package/dist/messaging/DropPickup.js.map +1 -1
- package/dist/messaging/GitSyncTransport.d.ts.map +1 -1
- package/dist/messaging/GitSyncTransport.js +4 -6
- package/dist/messaging/GitSyncTransport.js.map +1 -1
- package/dist/messaging/MessageStore.d.ts.map +1 -1
- package/dist/messaging/MessageStore.js +3 -4
- package/dist/messaging/MessageStore.js.map +1 -1
- package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
- package/dist/messaging/TelegramAdapter.js +5 -8
- package/dist/messaging/TelegramAdapter.js.map +1 -1
- package/dist/messaging/backends/BaileysBackend.d.ts.map +1 -1
- package/dist/messaging/backends/BaileysBackend.js +3 -4
- package/dist/messaging/backends/BaileysBackend.js.map +1 -1
- package/dist/messaging/local-tone-check.d.ts +61 -0
- package/dist/messaging/local-tone-check.d.ts.map +1 -0
- package/dist/messaging/local-tone-check.js +78 -0
- package/dist/messaging/local-tone-check.js.map +1 -0
- package/dist/messaging/pending-relay-store.d.ts +153 -0
- package/dist/messaging/pending-relay-store.d.ts.map +1 -0
- package/dist/messaging/pending-relay-store.js +351 -0
- package/dist/messaging/pending-relay-store.js.map +1 -0
- package/dist/messaging/secret-patterns.d.ts +35 -0
- package/dist/messaging/secret-patterns.d.ts.map +1 -0
- package/dist/messaging/secret-patterns.js +70 -0
- package/dist/messaging/secret-patterns.js.map +1 -0
- package/dist/messaging/shared/EncryptedAuthStore.d.ts.map +1 -1
- package/dist/messaging/shared/EncryptedAuthStore.js +3 -4
- package/dist/messaging/shared/EncryptedAuthStore.js.map +1 -1
- package/dist/messaging/shared/MessageLogger.d.ts.map +1 -1
- package/dist/messaging/shared/MessageLogger.js +2 -2
- package/dist/messaging/shared/MessageLogger.js.map +1 -1
- package/dist/messaging/shared/PrivacyConsent.d.ts.map +1 -1
- package/dist/messaging/shared/PrivacyConsent.js +2 -2
- package/dist/messaging/shared/PrivacyConsent.js.map +1 -1
- package/dist/messaging/shared/SessionChannelRegistry.d.ts.map +1 -1
- package/dist/messaging/shared/SessionChannelRegistry.js +2 -2
- package/dist/messaging/shared/SessionChannelRegistry.js.map +1 -1
- package/dist/messaging/system-templates.d.ts +87 -0
- package/dist/messaging/system-templates.d.ts.map +1 -0
- package/dist/messaging/system-templates.js +236 -0
- package/dist/messaging/system-templates.js.map +1 -0
- package/dist/messaging/whoami-cache.d.ts +66 -0
- package/dist/messaging/whoami-cache.d.ts.map +1 -0
- package/dist/messaging/whoami-cache.js +149 -0
- package/dist/messaging/whoami-cache.js.map +1 -0
- package/dist/moltbridge/ProfileCompiler.d.ts.map +1 -1
- package/dist/moltbridge/ProfileCompiler.js +13 -7
- package/dist/moltbridge/ProfileCompiler.js.map +1 -1
- package/dist/monitoring/CommitmentTracker.d.ts.map +1 -1
- package/dist/monitoring/CommitmentTracker.js +2 -2
- package/dist/monitoring/CommitmentTracker.js.map +1 -1
- package/dist/monitoring/CredentialProvider.d.ts.map +1 -1
- package/dist/monitoring/CredentialProvider.js +2 -2
- package/dist/monitoring/CredentialProvider.js.map +1 -1
- package/dist/monitoring/DegradationReporter.d.ts +41 -0
- package/dist/monitoring/DegradationReporter.d.ts.map +1 -1
- package/dist/monitoring/DegradationReporter.js +96 -4
- package/dist/monitoring/DegradationReporter.js.map +1 -1
- package/dist/monitoring/HealthChecker.d.ts.map +1 -1
- package/dist/monitoring/HealthChecker.js +2 -2
- package/dist/monitoring/HealthChecker.js.map +1 -1
- package/dist/monitoring/HookEventReceiver.d.ts.map +1 -1
- package/dist/monitoring/HookEventReceiver.js +2 -2
- package/dist/monitoring/HookEventReceiver.js.map +1 -1
- package/dist/monitoring/InstructionsVerifier.d.ts.map +1 -1
- package/dist/monitoring/InstructionsVerifier.js +2 -2
- package/dist/monitoring/InstructionsVerifier.js.map +1 -1
- package/dist/monitoring/PresenceProxy.d.ts.map +1 -1
- package/dist/monitoring/PresenceProxy.js +5 -8
- package/dist/monitoring/PresenceProxy.js.map +1 -1
- package/dist/monitoring/QuotaTracker.d.ts.map +1 -1
- package/dist/monitoring/QuotaTracker.js +2 -2
- package/dist/monitoring/QuotaTracker.js.map +1 -1
- package/dist/monitoring/SessionMigrator.d.ts.map +1 -1
- package/dist/monitoring/SessionMigrator.js +2 -2
- package/dist/monitoring/SessionMigrator.js.map +1 -1
- package/dist/monitoring/SessionRecovery.d.ts.map +1 -1
- package/dist/monitoring/SessionRecovery.js +2 -2
- package/dist/monitoring/SessionRecovery.js.map +1 -1
- package/dist/monitoring/TelemetryAuth.d.ts.map +1 -1
- package/dist/monitoring/TelemetryAuth.js +3 -4
- package/dist/monitoring/TelemetryAuth.js.map +1 -1
- package/dist/monitoring/TokenLedger.d.ts +91 -0
- package/dist/monitoring/TokenLedger.d.ts.map +1 -0
- package/dist/monitoring/TokenLedger.js +426 -0
- package/dist/monitoring/TokenLedger.js.map +1 -0
- package/dist/monitoring/TokenLedgerPoller.d.ts +26 -0
- package/dist/monitoring/TokenLedgerPoller.d.ts.map +1 -0
- package/dist/monitoring/TokenLedgerPoller.js +44 -0
- package/dist/monitoring/TokenLedgerPoller.js.map +1 -0
- package/dist/monitoring/TriageOrchestrator.d.ts.map +1 -1
- package/dist/monitoring/TriageOrchestrator.js +3 -4
- package/dist/monitoring/TriageOrchestrator.js.map +1 -1
- package/dist/monitoring/WorktreeReaper.d.ts.map +1 -1
- package/dist/monitoring/WorktreeReaper.js +5 -7
- package/dist/monitoring/WorktreeReaper.js.map +1 -1
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.d.ts +83 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.d.ts.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.js +218 -0
- package/dist/monitoring/delivery-failure-sentinel/recovery-policy.js.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel.d.ts +177 -0
- package/dist/monitoring/delivery-failure-sentinel.d.ts.map +1 -0
- package/dist/monitoring/delivery-failure-sentinel.js +598 -0
- package/dist/monitoring/delivery-failure-sentinel.js.map +1 -0
- package/dist/monitoring/probes/PlatformProbe.d.ts.map +1 -1
- package/dist/monitoring/probes/PlatformProbe.js +3 -4
- package/dist/monitoring/probes/PlatformProbe.js.map +1 -1
- package/dist/monitoring/templates-drift-verifier.d.ts +109 -0
- package/dist/monitoring/templates-drift-verifier.d.ts.map +1 -0
- package/dist/monitoring/templates-drift-verifier.js +324 -0
- package/dist/monitoring/templates-drift-verifier.js.map +1 -0
- package/dist/paste/PasteManager.d.ts.map +1 -1
- package/dist/paste/PasteManager.js +5 -8
- package/dist/paste/PasteManager.js.map +1 -1
- package/dist/publishing/PrivateViewer.d.ts.map +1 -1
- package/dist/publishing/PrivateViewer.js +2 -2
- package/dist/publishing/PrivateViewer.js.map +1 -1
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +2 -2
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/dist/server/AgentServer.d.ts +18 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +186 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/WebSocketManager.d.ts +11 -0
- package/dist/server/WebSocketManager.d.ts.map +1 -1
- package/dist/server/WebSocketManager.js +28 -0
- package/dist/server/WebSocketManager.js.map +1 -1
- package/dist/server/boot-id.d.ts +58 -0
- package/dist/server/boot-id.d.ts.map +1 -0
- package/dist/server/boot-id.js +121 -0
- package/dist/server/boot-id.js.map +1 -0
- package/dist/server/middleware.d.ts +14 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +81 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes.d.ts +69 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +528 -11
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/AgentDiscovery.d.ts.map +1 -1
- package/dist/threadline/AgentDiscovery.js +2 -2
- package/dist/threadline/AgentDiscovery.js.map +1 -1
- package/dist/threadline/AgentTrustManager.d.ts.map +1 -1
- package/dist/threadline/AgentTrustManager.js +2 -2
- package/dist/threadline/AgentTrustManager.js.map +1 -1
- package/dist/threadline/CircuitBreaker.d.ts.map +1 -1
- package/dist/threadline/CircuitBreaker.js +2 -2
- package/dist/threadline/CircuitBreaker.js.map +1 -1
- package/dist/threadline/ComputeMeter.d.ts.map +1 -1
- package/dist/threadline/ComputeMeter.js +2 -2
- package/dist/threadline/ComputeMeter.js.map +1 -1
- package/dist/threadline/ContextThreadMap.d.ts.map +1 -1
- package/dist/threadline/ContextThreadMap.js +2 -2
- package/dist/threadline/ContextThreadMap.js.map +1 -1
- package/dist/threadline/HeartbeatWatchdog.d.ts +78 -0
- package/dist/threadline/HeartbeatWatchdog.d.ts.map +1 -0
- package/dist/threadline/HeartbeatWatchdog.js +212 -0
- package/dist/threadline/HeartbeatWatchdog.js.map +1 -0
- package/dist/threadline/HeartbeatWriter.d.ts +79 -0
- package/dist/threadline/HeartbeatWriter.d.ts.map +1 -0
- package/dist/threadline/HeartbeatWriter.js +109 -0
- package/dist/threadline/HeartbeatWriter.js.map +1 -0
- package/dist/threadline/InvitationManager.d.ts.map +1 -1
- package/dist/threadline/InvitationManager.js +2 -2
- package/dist/threadline/InvitationManager.js.map +1 -1
- package/dist/threadline/ListenerSessionManager.d.ts +24 -0
- package/dist/threadline/ListenerSessionManager.d.ts.map +1 -1
- package/dist/threadline/ListenerSessionManager.js +38 -0
- package/dist/threadline/ListenerSessionManager.js.map +1 -1
- package/dist/threadline/MCPAuth.d.ts.map +1 -1
- package/dist/threadline/MCPAuth.js +2 -2
- package/dist/threadline/MCPAuth.js.map +1 -1
- package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -1
- package/dist/threadline/PipeSessionSpawner.js +3 -4
- package/dist/threadline/PipeSessionSpawner.js.map +1 -1
- package/dist/threadline/RateLimiter.d.ts.map +1 -1
- package/dist/threadline/RateLimiter.js +2 -2
- package/dist/threadline/RateLimiter.js.map +1 -1
- package/dist/threadline/RelaySpawnFailureHandler.d.ts +53 -0
- package/dist/threadline/RelaySpawnFailureHandler.d.ts.map +1 -0
- package/dist/threadline/RelaySpawnFailureHandler.js +73 -0
- package/dist/threadline/RelaySpawnFailureHandler.js.map +1 -0
- package/dist/threadline/SessionLifecycle.d.ts.map +1 -1
- package/dist/threadline/SessionLifecycle.js +2 -2
- package/dist/threadline/SessionLifecycle.js.map +1 -1
- package/dist/threadline/SpawnLedger.d.ts +94 -0
- package/dist/threadline/SpawnLedger.d.ts.map +1 -0
- package/dist/threadline/SpawnLedger.js +194 -0
- package/dist/threadline/SpawnLedger.js.map +1 -0
- package/dist/threadline/SpawnNonce.d.ts +49 -0
- package/dist/threadline/SpawnNonce.d.ts.map +1 -0
- package/dist/threadline/SpawnNonce.js +99 -0
- package/dist/threadline/SpawnNonce.js.map +1 -0
- package/dist/threadline/TelegramBridgeConfig.d.ts +79 -0
- package/dist/threadline/TelegramBridgeConfig.d.ts.map +1 -0
- package/dist/threadline/TelegramBridgeConfig.js +168 -0
- package/dist/threadline/TelegramBridgeConfig.js.map +1 -0
- package/dist/threadline/ThreadlineBootstrap.d.ts.map +1 -1
- package/dist/threadline/ThreadlineBootstrap.js +2 -2
- package/dist/threadline/ThreadlineBootstrap.js.map +1 -1
- package/dist/threadline/WakeSocketServer.d.ts.map +1 -1
- package/dist/threadline/WakeSocketServer.js +3 -4
- package/dist/threadline/WakeSocketServer.js.map +1 -1
- package/dist/threadline/listener-daemon.d.ts.map +1 -1
- package/dist/threadline/listener-daemon.js +3 -4
- package/dist/threadline/listener-daemon.js.map +1 -1
- package/dist/users/UserManager.d.ts.map +1 -1
- package/dist/users/UserManager.js +2 -2
- package/dist/users/UserManager.js.map +1 -1
- package/dist/users/UserOnboarding.d.ts.map +1 -1
- package/dist/users/UserOnboarding.js +2 -2
- package/dist/users/UserOnboarding.js.map +1 -1
- package/dist/utils/jsonl-rotation.d.ts.map +1 -1
- package/dist/utils/jsonl-rotation.js +2 -2
- package/dist/utils/jsonl-rotation.js.map +1 -1
- package/package.json +1 -1
- package/scripts/analyze-release.js +7 -12
- package/scripts/check-contract-evidence.js +27 -10
- package/scripts/fix-better-sqlite3.cjs +0 -2
- package/scripts/instar-dev-precommit.js +0 -2
- package/scripts/lint-no-direct-destructive.js +24 -4
- package/scripts/lint-template-sha-history.ts +183 -0
- package/scripts/migrate-incident-2026-04-17.mjs +2 -2
- package/scripts/run-migration.js +500 -0
- package/scripts/test-bootstrap-relay.mjs +2 -2
- package/scripts/verify-deployed-templates.ts +87 -0
- package/src/data/builtin-manifest.json +140 -132
- package/src/templates/scripts/git-sync-gate.sh +0 -4
- package/src/templates/scripts/telegram-reply.sh +318 -13
- package/upgrades/0.28.77.md +133 -0
- package/upgrades/side-effects/agent-health-alert-authority-routing.md +121 -0
- package/upgrades/side-effects/comprehensive-destructive-tool-containment-migration.md +82 -0
- package/upgrades/side-effects/deferral-detector-orphan-todo.md +101 -0
- package/upgrades/side-effects/lifeline-self-heal-hardening.md +151 -0
- package/upgrades/side-effects/relay-spawn-ghost-reply-phase1.md +139 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-2.md +320 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-3.md +202 -0
- package/upgrades/side-effects/telegram-delivery-robustness-layer-7.md +339 -0
- package/upgrades/side-effects/telegram-delivery-robustness.md +178 -0
- package/upgrades/side-effects/threadline-canonical-inbox-write.md +218 -0
- package/upgrades/side-effects/threadline-tg-bridge-settings-surface.md +208 -0
- package/upgrades/side-effects/token-ledger-phase1.md +123 -0
- package/upgrades/NEXT.md +0 -53
- /package/upgrades/side-effects/{telegram-lifeline-version-missing-info.md → 0.28.76.md} +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpawnLedger — SQLite-backed compare-and-swap ledger for relay-spawned sessions.
|
|
3
|
+
*
|
|
4
|
+
* Implements Component A of the Threadline Relay-Spawn Ghost-Reply
|
|
5
|
+
* Containment Spec. The ledger is the spawn-creation step itself, not a
|
|
6
|
+
* post-hoc check: tryReserve() atomically claims an eventId or returns null
|
|
7
|
+
* if another spawn already claimed it. This is the idempotency primitive
|
|
8
|
+
* that makes "Spawned session for X (twice)" structurally impossible.
|
|
9
|
+
*
|
|
10
|
+
* Per spec §Component A:
|
|
11
|
+
* - Backed by SQLite (WAL mode, flock-coordinated for second-instar-on-host)
|
|
12
|
+
* - Per-spawn HMAC nonce generated here, never written to a path the
|
|
13
|
+
* spawned session can read after launch (handed to the session via FD-3
|
|
14
|
+
* by SpawnNonce.ts).
|
|
15
|
+
* - Per-peer rolling rate cap (1000 spawns / 24h) enforced on tryReserve
|
|
16
|
+
* - Global hard cap of 100k rows; prune by TTL (30d) via a background job.
|
|
17
|
+
*
|
|
18
|
+
* Authority classification (per docs/signal-vs-authority.md): structural
|
|
19
|
+
* idempotency-key dedup at the transport layer. Permitted authority — not
|
|
20
|
+
* a judgment call, mechanics.
|
|
21
|
+
*/
|
|
22
|
+
import Database from 'better-sqlite3';
|
|
23
|
+
import crypto from 'node:crypto';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
import fs from 'node:fs';
|
|
26
|
+
const DEFAULTS = {
|
|
27
|
+
perPeerCap: 1000,
|
|
28
|
+
perPeerWindowMs: 24 * 60 * 60 * 1000,
|
|
29
|
+
globalCap: 100_000,
|
|
30
|
+
};
|
|
31
|
+
// ── Implementation ───────────────────────────────────────────────────
|
|
32
|
+
export class SpawnLedger {
|
|
33
|
+
db;
|
|
34
|
+
opts;
|
|
35
|
+
constructor(dbPath, opts = {}) {
|
|
36
|
+
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
|
37
|
+
this.db = new Database(dbPath);
|
|
38
|
+
this.db.pragma('journal_mode = WAL');
|
|
39
|
+
this.db.pragma('synchronous = NORMAL');
|
|
40
|
+
this.db.pragma('foreign_keys = ON');
|
|
41
|
+
this.opts = { ...DEFAULTS, ...opts };
|
|
42
|
+
this.applySchema();
|
|
43
|
+
}
|
|
44
|
+
applySchema() {
|
|
45
|
+
this.db.exec(`
|
|
46
|
+
CREATE TABLE IF NOT EXISTS spawn_ledger (
|
|
47
|
+
eventId TEXT PRIMARY KEY,
|
|
48
|
+
peerId TEXT NOT NULL,
|
|
49
|
+
spawnNonce BLOB NOT NULL,
|
|
50
|
+
spawnedAt INTEGER NOT NULL,
|
|
51
|
+
status TEXT NOT NULL CHECK (status IN ('spawning','verified','failed','completed')),
|
|
52
|
+
terminalAt INTEGER,
|
|
53
|
+
failureReason TEXT
|
|
54
|
+
);
|
|
55
|
+
CREATE INDEX IF NOT EXISTS idx_spawn_ledger_peer_time
|
|
56
|
+
ON spawn_ledger (peerId, spawnedAt);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_spawn_ledger_status_time
|
|
58
|
+
ON spawn_ledger (status, spawnedAt);
|
|
59
|
+
`);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Atomically reserve a spawn slot for `eventId`. Returns the spawn nonce
|
|
63
|
+
* the caller must hand to the spawned session via FD-3, or a collision
|
|
64
|
+
* with the reason.
|
|
65
|
+
*
|
|
66
|
+
* This is the single point where a spawn is decided. If two relay
|
|
67
|
+
* threads race on the same eventId, exactly one tryReserve() returns
|
|
68
|
+
* {reserved: true}; the other gets {reserved: false, reason: 'duplicate-event'}.
|
|
69
|
+
*/
|
|
70
|
+
tryReserve(eventId, peerId, now = Date.now()) {
|
|
71
|
+
if (!eventId || !peerId) {
|
|
72
|
+
throw new Error('SpawnLedger.tryReserve requires eventId and peerId');
|
|
73
|
+
}
|
|
74
|
+
// Global cap check (cheap COUNT — index on status covers it).
|
|
75
|
+
const total = this.db
|
|
76
|
+
.prepare('SELECT COUNT(*) AS n FROM spawn_ledger')
|
|
77
|
+
.get();
|
|
78
|
+
if (total.n >= this.opts.globalCap) {
|
|
79
|
+
return { reserved: false, reason: 'ledger-full' };
|
|
80
|
+
}
|
|
81
|
+
// Per-peer rolling rate cap.
|
|
82
|
+
const windowStart = now - this.opts.perPeerWindowMs;
|
|
83
|
+
const peerRecent = this.db
|
|
84
|
+
.prepare('SELECT COUNT(*) AS n FROM spawn_ledger WHERE peerId = ? AND spawnedAt >= ?')
|
|
85
|
+
.get(peerId, windowStart);
|
|
86
|
+
if (peerRecent.n >= this.opts.perPeerCap) {
|
|
87
|
+
return { reserved: false, reason: 'peer-rate-limit' };
|
|
88
|
+
}
|
|
89
|
+
const spawnNonce = crypto.randomBytes(32);
|
|
90
|
+
const insert = this.db.prepare(`INSERT INTO spawn_ledger (eventId, peerId, spawnNonce, spawnedAt, status, terminalAt, failureReason)
|
|
91
|
+
VALUES (?, ?, ?, ?, 'spawning', NULL, NULL)`);
|
|
92
|
+
try {
|
|
93
|
+
insert.run(eventId, peerId, spawnNonce, now);
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
// SQLite UNIQUE constraint on PRIMARY KEY → another spawn won the race.
|
|
97
|
+
if (err instanceof Error &&
|
|
98
|
+
/UNIQUE|PRIMARY KEY/.test(err.message)) {
|
|
99
|
+
const existing = this.get(eventId);
|
|
100
|
+
return {
|
|
101
|
+
reserved: false,
|
|
102
|
+
reason: 'duplicate-event',
|
|
103
|
+
existing: existing ?? undefined,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
const row = this.get(eventId);
|
|
109
|
+
return { reserved: true, spawnNonce, row };
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Mark a reserved spawn as having moved to a terminal state. Verified =
|
|
113
|
+
* heartbeat HMAC validated. Failed = watchdog signal triggered. Completed
|
|
114
|
+
* = session exited cleanly.
|
|
115
|
+
*/
|
|
116
|
+
markStatus(eventId, status, failureReason = null, now = Date.now()) {
|
|
117
|
+
const stmt = this.db.prepare(`UPDATE spawn_ledger
|
|
118
|
+
SET status = ?, terminalAt = ?, failureReason = ?
|
|
119
|
+
WHERE eventId = ? AND status != ?`);
|
|
120
|
+
const result = stmt.run(status, now, failureReason, eventId, status);
|
|
121
|
+
return result.changes > 0;
|
|
122
|
+
}
|
|
123
|
+
get(eventId) {
|
|
124
|
+
const row = this.db
|
|
125
|
+
.prepare('SELECT * FROM spawn_ledger WHERE eventId = ?')
|
|
126
|
+
.get(eventId);
|
|
127
|
+
return row ?? null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Verify a heartbeat HMAC against the stored spawn nonce.
|
|
131
|
+
* Returns true if valid; false if no row or mismatch.
|
|
132
|
+
*/
|
|
133
|
+
verifyHeartbeatHmac(eventId, payload, presentedHmac) {
|
|
134
|
+
const row = this.get(eventId);
|
|
135
|
+
if (!row)
|
|
136
|
+
return false;
|
|
137
|
+
const expected = crypto
|
|
138
|
+
.createHmac('sha256', row.spawnNonce)
|
|
139
|
+
.update(payload)
|
|
140
|
+
.digest('hex');
|
|
141
|
+
// Constant-time compare to avoid timing side channel.
|
|
142
|
+
const a = Buffer.from(expected, 'hex');
|
|
143
|
+
const b = Buffer.from(presentedHmac, 'hex');
|
|
144
|
+
if (a.length !== b.length)
|
|
145
|
+
return false;
|
|
146
|
+
return crypto.timingSafeEqual(a, b);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Prune rows older than `olderThanMs` AND in a terminal state.
|
|
150
|
+
* Spawning rows are NEVER pruned (they may still be in flight).
|
|
151
|
+
* Returns count of rows removed.
|
|
152
|
+
*/
|
|
153
|
+
pruneTerminal(olderThanMs, now = Date.now()) {
|
|
154
|
+
const cutoff = now - olderThanMs;
|
|
155
|
+
const result = this.db
|
|
156
|
+
.prepare(`DELETE FROM spawn_ledger
|
|
157
|
+
WHERE status != 'spawning'
|
|
158
|
+
AND terminalAt IS NOT NULL
|
|
159
|
+
AND terminalAt < ?`)
|
|
160
|
+
.run(cutoff);
|
|
161
|
+
return result.changes;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* List ALL rows currently in 'spawning' state, regardless of age.
|
|
165
|
+
* Used by HeartbeatWatchdog which applies its own grace-window filter.
|
|
166
|
+
*/
|
|
167
|
+
listSpawning() {
|
|
168
|
+
return this.db
|
|
169
|
+
.prepare(`SELECT * FROM spawn_ledger WHERE status = 'spawning'`)
|
|
170
|
+
.all();
|
|
171
|
+
}
|
|
172
|
+
/** Sweep stale 'spawning' rows (heartbeat never confirmed, no terminal mark). */
|
|
173
|
+
sweepStaleSpawning(staleAfterMs, now = Date.now()) {
|
|
174
|
+
const cutoff = now - staleAfterMs;
|
|
175
|
+
const rows = this.db
|
|
176
|
+
.prepare(`SELECT * FROM spawn_ledger
|
|
177
|
+
WHERE status = 'spawning' AND spawnedAt < ?`)
|
|
178
|
+
.all(cutoff);
|
|
179
|
+
return rows;
|
|
180
|
+
}
|
|
181
|
+
count() {
|
|
182
|
+
return this.db.prepare('SELECT COUNT(*) AS n FROM spawn_ledger').get().n;
|
|
183
|
+
}
|
|
184
|
+
close() {
|
|
185
|
+
try {
|
|
186
|
+
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* db may already be closed; safe to ignore */
|
|
190
|
+
}
|
|
191
|
+
this.db.close();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=SpawnLedger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnLedger.js","sourceRoot":"","sources":["../../src/threadline/SpawnLedger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpawnNonce — relay-side helpers for binding a SpawnLedger reservation
|
|
3
|
+
* to a freshly-spawned session via FD 3 inheritance, and for deriving a
|
|
4
|
+
* deterministic eventId from envelope material.
|
|
5
|
+
*
|
|
6
|
+
* Component A glue for RELAY-SPAWN-GHOST-REPLY-CONTAINMENT-SPEC. The
|
|
7
|
+
* reader counterpart (`readSpawnNonceFromFd3`) lives in HeartbeatWriter
|
|
8
|
+
* since it runs in the spawned session, not the relay.
|
|
9
|
+
*
|
|
10
|
+
* Why FD 3 and not env: round-1 review surfaced that env vars propagate
|
|
11
|
+
* to every fork-helper a session may spawn (build tools, shells), giving
|
|
12
|
+
* those processes the nonce. FD 3 is single-read by the spawned process
|
|
13
|
+
* and is closed by the relay immediately after handoff.
|
|
14
|
+
*/
|
|
15
|
+
import type { SpawnOptions, StdioOptions } from 'node:child_process';
|
|
16
|
+
import type { MessageEnvelope } from '../messaging/types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Deterministic eventId from envelope material. Bound to:
|
|
19
|
+
* - sender identity (signedBy or hmacBy on transport metadata)
|
|
20
|
+
* - the transport-layer nonce (already used for replay prevention)
|
|
21
|
+
* - the application-level message id
|
|
22
|
+
*
|
|
23
|
+
* Why this triple: any one alone is insufficient. The transport nonce is
|
|
24
|
+
* unique per delivery but not authenticated to a specific message body
|
|
25
|
+
* (a relay or attacker could re-route the same nonce with a different
|
|
26
|
+
* payload). Combining with the signed-by + message id binds the eventId
|
|
27
|
+
* to "this exact message from this exact sender via this exact relay
|
|
28
|
+
* delivery". Replays produce the same eventId → ledger CAS rejects.
|
|
29
|
+
*/
|
|
30
|
+
export declare function deriveEventId(envelope: MessageEnvelope): string;
|
|
31
|
+
export interface NonceFdHandle {
|
|
32
|
+
/** Read FD to be passed as stdio[3] to child_process.spawn(). */
|
|
33
|
+
readFd: number;
|
|
34
|
+
/** Call after spawn returns to release the relay-side handle. */
|
|
35
|
+
close: () => void;
|
|
36
|
+
}
|
|
37
|
+
export declare function prepareNonceFd(spawnNonce: Buffer): NonceFdHandle;
|
|
38
|
+
/**
|
|
39
|
+
* Build a stdio array suitable for child_process.spawn() that inherits
|
|
40
|
+
* stdin/stdout/stderr from the parent and binds FD 3 to the nonce read
|
|
41
|
+
* end. Caller owns calling handle.close() AFTER spawn returns.
|
|
42
|
+
*/
|
|
43
|
+
export declare function stdioWithNonceFd(handle: NonceFdHandle): StdioOptions;
|
|
44
|
+
/**
|
|
45
|
+
* Convenience: enrich a SpawnOptions with FD-3 nonce binding. Returns a
|
|
46
|
+
* new options object plus the handle to close after spawn.
|
|
47
|
+
*/
|
|
48
|
+
export declare function withNonceFd(baseOpts: SpawnOptions, handle: NonceFdHandle): SpawnOptions;
|
|
49
|
+
//# sourceMappingURL=SpawnNonce.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnNonce.d.ts","sourceRoot":"","sources":["../../src/threadline/SpawnNonce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAS/D;AAkBD,MAAM,WAAW,aAAa;IAC5B,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,aAAa,CA4BhE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,YAAY,CAEpE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,aAAa,GACpB,YAAY,CAKd"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SpawnNonce — relay-side helpers for binding a SpawnLedger reservation
|
|
3
|
+
* to a freshly-spawned session via FD 3 inheritance, and for deriving a
|
|
4
|
+
* deterministic eventId from envelope material.
|
|
5
|
+
*
|
|
6
|
+
* Component A glue for RELAY-SPAWN-GHOST-REPLY-CONTAINMENT-SPEC. The
|
|
7
|
+
* reader counterpart (`readSpawnNonceFromFd3`) lives in HeartbeatWriter
|
|
8
|
+
* since it runs in the spawned session, not the relay.
|
|
9
|
+
*
|
|
10
|
+
* Why FD 3 and not env: round-1 review surfaced that env vars propagate
|
|
11
|
+
* to every fork-helper a session may spawn (build tools, shells), giving
|
|
12
|
+
* those processes the nonce. FD 3 is single-read by the spawned process
|
|
13
|
+
* and is closed by the relay immediately after handoff.
|
|
14
|
+
*/
|
|
15
|
+
import crypto from 'node:crypto';
|
|
16
|
+
/**
|
|
17
|
+
* Deterministic eventId from envelope material. Bound to:
|
|
18
|
+
* - sender identity (signedBy or hmacBy on transport metadata)
|
|
19
|
+
* - the transport-layer nonce (already used for replay prevention)
|
|
20
|
+
* - the application-level message id
|
|
21
|
+
*
|
|
22
|
+
* Why this triple: any one alone is insufficient. The transport nonce is
|
|
23
|
+
* unique per delivery but not authenticated to a specific message body
|
|
24
|
+
* (a relay or attacker could re-route the same nonce with a different
|
|
25
|
+
* payload). Combining with the signed-by + message id binds the eventId
|
|
26
|
+
* to "this exact message from this exact sender via this exact relay
|
|
27
|
+
* delivery". Replays produce the same eventId → ledger CAS rejects.
|
|
28
|
+
*/
|
|
29
|
+
export function deriveEventId(envelope) {
|
|
30
|
+
const t = envelope.transport;
|
|
31
|
+
const signer = t.signedBy ?? t.hmacBy ?? '<unsigned>';
|
|
32
|
+
const nonce = t.nonce ?? '<no-nonce>';
|
|
33
|
+
const msgId = envelope.message?.id ?? '<no-msg-id>';
|
|
34
|
+
return crypto
|
|
35
|
+
.createHash('sha256')
|
|
36
|
+
.update(`${signer}\x00${nonce}\x00${msgId}`)
|
|
37
|
+
.digest('hex');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Open a pipe, write the per-spawn nonce into it, return both ends so
|
|
41
|
+
* the caller can hand the read end to child_process.spawn() via FD 3
|
|
42
|
+
* and close the write end after spawn returns.
|
|
43
|
+
*
|
|
44
|
+
* Node's child_process does not expose POSIX pipe(2) directly, so we use
|
|
45
|
+
* a tmpfile + open-for-read pattern as a portable substitute. The file
|
|
46
|
+
* is unlinked immediately after open so even root cannot read it from
|
|
47
|
+
* disk after the spawn returns.
|
|
48
|
+
*/
|
|
49
|
+
import fs from 'node:fs';
|
|
50
|
+
import os from 'node:os';
|
|
51
|
+
import path from 'node:path';
|
|
52
|
+
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
53
|
+
export function prepareNonceFd(spawnNonce) {
|
|
54
|
+
if (spawnNonce.length !== 32) {
|
|
55
|
+
throw new Error('SpawnNonce.prepareNonceFd requires a 32-byte nonce');
|
|
56
|
+
}
|
|
57
|
+
// tmpfile in os.tmpdir(); 0o600; immediately unlinked after open.
|
|
58
|
+
const tmp = path.join(os.tmpdir(), `instar-spawn-nonce-${process.pid}-${crypto.randomBytes(6).toString('hex')}`);
|
|
59
|
+
fs.writeFileSync(tmp, spawnNonce, { mode: 0o600 });
|
|
60
|
+
const readFd = fs.openSync(tmp, 'r');
|
|
61
|
+
// Unlink immediately; the open FD keeps the inode alive only as long
|
|
62
|
+
// as one of the processes holds it.
|
|
63
|
+
try {
|
|
64
|
+
SafeFsExecutor.safeUnlinkSync(tmp, { operation: 'SpawnNonce.prepareNonceFd' });
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* best-effort */
|
|
68
|
+
}
|
|
69
|
+
return {
|
|
70
|
+
readFd,
|
|
71
|
+
close: () => {
|
|
72
|
+
try {
|
|
73
|
+
fs.closeSync(readFd);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* already closed */
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Build a stdio array suitable for child_process.spawn() that inherits
|
|
83
|
+
* stdin/stdout/stderr from the parent and binds FD 3 to the nonce read
|
|
84
|
+
* end. Caller owns calling handle.close() AFTER spawn returns.
|
|
85
|
+
*/
|
|
86
|
+
export function stdioWithNonceFd(handle) {
|
|
87
|
+
return ['inherit', 'inherit', 'inherit', handle.readFd];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Convenience: enrich a SpawnOptions with FD-3 nonce binding. Returns a
|
|
91
|
+
* new options object plus the handle to close after spawn.
|
|
92
|
+
*/
|
|
93
|
+
export function withNonceFd(baseOpts, handle) {
|
|
94
|
+
return {
|
|
95
|
+
...baseOpts,
|
|
96
|
+
stdio: stdioWithNonceFd(handle),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=SpawnNonce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpawnNonce.js","sourceRoot":"","sources":["../../src/threadline/SpawnNonce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAKjC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,QAAyB;IACrD,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC;IAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,YAAY,CAAC;IACtD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,EAAE,IAAI,aAAa,CAAC;IACpD,OAAO,MAAM;SACV,UAAU,CAAC,QAAQ,CAAC;SACpB,MAAM,CAAC,GAAG,MAAM,OAAO,KAAK,OAAO,KAAK,EAAE,CAAC;SAC3C,MAAM,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAS3D,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,IAAI,UAAU,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IACD,kEAAkE;IAClE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CACnB,EAAE,CAAC,MAAM,EAAE,EACX,sBAAsB,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAC7E,CAAC;IACF,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrC,qEAAqE;IACrE,oCAAoC;IACpC,IAAI,CAAC;QACH,cAAc,CAAC,cAAc,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,2BAA2B,EAAE,CAAC,CAAC;IACjF,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;IACD,OAAO;QACL,MAAM;QACN,KAAK,EAAE,GAAG,EAAE;YACV,IAAI,CAAC;gBACH,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,oBAAoB;YACtB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AAC1D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CACzB,QAAsB,EACtB,MAAqB;IAErB,OAAO;QACL,GAAG,QAAQ;QACX,KAAK,EAAE,gBAAgB,CAAC,MAAM,CAAC;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelegramBridgeConfig — settings surface for the threadline → telegram bridge.
|
|
3
|
+
*
|
|
4
|
+
* The bridge mirrors threadline messages into per-thread Telegram topics so the
|
|
5
|
+
* user has visibility into agent-to-agent conversations. To avoid noise, all
|
|
6
|
+
* topic-creating behavior is gated by user-controlled toggles. This class is
|
|
7
|
+
* the single source of truth for those toggles and the per-remote-agent
|
|
8
|
+
* allow/deny list.
|
|
9
|
+
*
|
|
10
|
+
* Stored under `threadline.telegramBridge` in the agent's `.instar/config.json`.
|
|
11
|
+
* Reads and writes go through LiveConfig so changes from the dashboard are
|
|
12
|
+
* picked up without a server restart.
|
|
13
|
+
*
|
|
14
|
+
* Defaults — the noise budget:
|
|
15
|
+
* enabled = false master kill-switch (default OFF)
|
|
16
|
+
* autoCreateTopics = false never spawn a brand-new topic unless an allow-list entry says so
|
|
17
|
+
* mirrorExisting = true once a topic exists for a thread, mirror traffic into it
|
|
18
|
+
* allowList = [] remote-agent identifiers that always get auto-created topics
|
|
19
|
+
* denyList = [] remote-agent identifiers that never get auto-created topics
|
|
20
|
+
*
|
|
21
|
+
* Allow-list takes precedence over deny-list when both contain the same id.
|
|
22
|
+
*/
|
|
23
|
+
import { EventEmitter } from 'node:events';
|
|
24
|
+
import type { LiveConfig } from '../config/LiveConfig.js';
|
|
25
|
+
export interface TelegramBridgeSettings {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
autoCreateTopics: boolean;
|
|
28
|
+
mirrorExisting: boolean;
|
|
29
|
+
allowList: string[];
|
|
30
|
+
denyList: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare const DEFAULT_TELEGRAM_BRIDGE_SETTINGS: TelegramBridgeSettings;
|
|
33
|
+
export type TelegramBridgeConfigChangeEvent = {
|
|
34
|
+
field: keyof TelegramBridgeSettings;
|
|
35
|
+
before: unknown;
|
|
36
|
+
after: unknown;
|
|
37
|
+
};
|
|
38
|
+
export declare class TelegramBridgeConfig extends EventEmitter {
|
|
39
|
+
private readonly liveConfig;
|
|
40
|
+
constructor(liveConfig: LiveConfig);
|
|
41
|
+
getSettings(): TelegramBridgeSettings;
|
|
42
|
+
/**
|
|
43
|
+
* Apply a partial update. Returns the full settings after the update.
|
|
44
|
+
* Validation: booleans must be boolean; lists must be string[].
|
|
45
|
+
*/
|
|
46
|
+
update(patch: Partial<TelegramBridgeSettings>): TelegramBridgeSettings;
|
|
47
|
+
addToAllowList(agentId: string): TelegramBridgeSettings;
|
|
48
|
+
removeFromAllowList(agentId: string): TelegramBridgeSettings;
|
|
49
|
+
addToDenyList(agentId: string): TelegramBridgeSettings;
|
|
50
|
+
removeFromDenyList(agentId: string): TelegramBridgeSettings;
|
|
51
|
+
/**
|
|
52
|
+
* Decide whether a brand-new Telegram topic should be auto-created for an
|
|
53
|
+
* inbound message from `remoteAgent`. The bridge module calls this on every
|
|
54
|
+
* inbound message that doesn't already have a bridged topic.
|
|
55
|
+
*
|
|
56
|
+
* Decision order (first match wins):
|
|
57
|
+
* 1. If bridge is disabled overall → false.
|
|
58
|
+
* 2. If allowList contains the agent (any matching id) → true. (allow > deny)
|
|
59
|
+
* 3. If denyList contains the agent → false.
|
|
60
|
+
* 4. Otherwise fall through to autoCreateTopics (the global default).
|
|
61
|
+
*
|
|
62
|
+
* `remoteAgent` is an opaque identifier — typically the remote agent's
|
|
63
|
+
* fingerprint, but the matcher accepts any string the dashboard surfaces
|
|
64
|
+
* (display name, fingerprint prefix). Allow/deny matching is case-sensitive
|
|
65
|
+
* exact-match.
|
|
66
|
+
*/
|
|
67
|
+
shouldAutoCreateTopic(remoteAgent: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Decide whether to mirror an inbound/outbound message into a topic that
|
|
70
|
+
* already exists for this thread. Bridge module calls this when there's a
|
|
71
|
+
* known topic-id binding for the thread.
|
|
72
|
+
*
|
|
73
|
+
* Mirroring is independent of the deny-list — once the user has a topic
|
|
74
|
+
* for a thread (which they explicitly created or allow-listed), traffic
|
|
75
|
+
* keeps flowing unless the master switch is off or `mirrorExisting` is off.
|
|
76
|
+
*/
|
|
77
|
+
shouldMirrorIntoExistingTopic(): boolean;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=TelegramBridgeConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TelegramBridgeConfig.d.ts","sourceRoot":"","sources":["../../src/threadline/TelegramBridgeConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,gCAAgC,EAAE,sBAM9C,CAAC;AAQF,MAAM,MAAM,+BAA+B,GAAG;IAC5C,KAAK,EAAE,MAAM,sBAAsB,CAAC;IACpC,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,qBAAa,oBAAqB,SAAQ,YAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,EAAE,UAAU;IAInD,WAAW,IAAI,sBAAsB;IAUrC;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,sBAAsB,CAAC,GAAG,sBAAsB;IAuCtE,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB;IAMvD,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB;IAK5D,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB;IAMtD,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB;IAK3D;;;;;;;;;;;;;;;OAeG;IACH,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO;IAQnD;;;;;;;;OAQG;IACH,6BAA6B,IAAI,OAAO;CAIzC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TelegramBridgeConfig — settings surface for the threadline → telegram bridge.
|
|
3
|
+
*
|
|
4
|
+
* The bridge mirrors threadline messages into per-thread Telegram topics so the
|
|
5
|
+
* user has visibility into agent-to-agent conversations. To avoid noise, all
|
|
6
|
+
* topic-creating behavior is gated by user-controlled toggles. This class is
|
|
7
|
+
* the single source of truth for those toggles and the per-remote-agent
|
|
8
|
+
* allow/deny list.
|
|
9
|
+
*
|
|
10
|
+
* Stored under `threadline.telegramBridge` in the agent's `.instar/config.json`.
|
|
11
|
+
* Reads and writes go through LiveConfig so changes from the dashboard are
|
|
12
|
+
* picked up without a server restart.
|
|
13
|
+
*
|
|
14
|
+
* Defaults — the noise budget:
|
|
15
|
+
* enabled = false master kill-switch (default OFF)
|
|
16
|
+
* autoCreateTopics = false never spawn a brand-new topic unless an allow-list entry says so
|
|
17
|
+
* mirrorExisting = true once a topic exists for a thread, mirror traffic into it
|
|
18
|
+
* allowList = [] remote-agent identifiers that always get auto-created topics
|
|
19
|
+
* denyList = [] remote-agent identifiers that never get auto-created topics
|
|
20
|
+
*
|
|
21
|
+
* Allow-list takes precedence over deny-list when both contain the same id.
|
|
22
|
+
*/
|
|
23
|
+
import { EventEmitter } from 'node:events';
|
|
24
|
+
export const DEFAULT_TELEGRAM_BRIDGE_SETTINGS = {
|
|
25
|
+
enabled: false,
|
|
26
|
+
autoCreateTopics: false,
|
|
27
|
+
mirrorExisting: true,
|
|
28
|
+
allowList: [],
|
|
29
|
+
denyList: [],
|
|
30
|
+
};
|
|
31
|
+
const KEY_ENABLED = 'threadline.telegramBridge.enabled';
|
|
32
|
+
const KEY_AUTO_CREATE = 'threadline.telegramBridge.autoCreateTopics';
|
|
33
|
+
const KEY_MIRROR_EXISTING = 'threadline.telegramBridge.mirrorExisting';
|
|
34
|
+
const KEY_ALLOW_LIST = 'threadline.telegramBridge.allowList';
|
|
35
|
+
const KEY_DENY_LIST = 'threadline.telegramBridge.denyList';
|
|
36
|
+
export class TelegramBridgeConfig extends EventEmitter {
|
|
37
|
+
liveConfig;
|
|
38
|
+
constructor(liveConfig) {
|
|
39
|
+
super();
|
|
40
|
+
this.liveConfig = liveConfig;
|
|
41
|
+
}
|
|
42
|
+
getSettings() {
|
|
43
|
+
return {
|
|
44
|
+
enabled: this.liveConfig.get(KEY_ENABLED, DEFAULT_TELEGRAM_BRIDGE_SETTINGS.enabled),
|
|
45
|
+
autoCreateTopics: this.liveConfig.get(KEY_AUTO_CREATE, DEFAULT_TELEGRAM_BRIDGE_SETTINGS.autoCreateTopics),
|
|
46
|
+
mirrorExisting: this.liveConfig.get(KEY_MIRROR_EXISTING, DEFAULT_TELEGRAM_BRIDGE_SETTINGS.mirrorExisting),
|
|
47
|
+
allowList: [...this.liveConfig.get(KEY_ALLOW_LIST, DEFAULT_TELEGRAM_BRIDGE_SETTINGS.allowList)],
|
|
48
|
+
denyList: [...this.liveConfig.get(KEY_DENY_LIST, DEFAULT_TELEGRAM_BRIDGE_SETTINGS.denyList)],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Apply a partial update. Returns the full settings after the update.
|
|
53
|
+
* Validation: booleans must be boolean; lists must be string[].
|
|
54
|
+
*/
|
|
55
|
+
update(patch) {
|
|
56
|
+
const before = this.getSettings();
|
|
57
|
+
if (patch.enabled !== undefined) {
|
|
58
|
+
if (typeof patch.enabled !== 'boolean')
|
|
59
|
+
throw new Error('enabled must be boolean');
|
|
60
|
+
this.liveConfig.set(KEY_ENABLED, patch.enabled);
|
|
61
|
+
}
|
|
62
|
+
if (patch.autoCreateTopics !== undefined) {
|
|
63
|
+
if (typeof patch.autoCreateTopics !== 'boolean')
|
|
64
|
+
throw new Error('autoCreateTopics must be boolean');
|
|
65
|
+
this.liveConfig.set(KEY_AUTO_CREATE, patch.autoCreateTopics);
|
|
66
|
+
}
|
|
67
|
+
if (patch.mirrorExisting !== undefined) {
|
|
68
|
+
if (typeof patch.mirrorExisting !== 'boolean')
|
|
69
|
+
throw new Error('mirrorExisting must be boolean');
|
|
70
|
+
this.liveConfig.set(KEY_MIRROR_EXISTING, patch.mirrorExisting);
|
|
71
|
+
}
|
|
72
|
+
if (patch.allowList !== undefined) {
|
|
73
|
+
if (!Array.isArray(patch.allowList) || !patch.allowList.every(s => typeof s === 'string')) {
|
|
74
|
+
throw new Error('allowList must be string[]');
|
|
75
|
+
}
|
|
76
|
+
this.liveConfig.set(KEY_ALLOW_LIST, dedupeAndTrim(patch.allowList));
|
|
77
|
+
}
|
|
78
|
+
if (patch.denyList !== undefined) {
|
|
79
|
+
if (!Array.isArray(patch.denyList) || !patch.denyList.every(s => typeof s === 'string')) {
|
|
80
|
+
throw new Error('denyList must be string[]');
|
|
81
|
+
}
|
|
82
|
+
this.liveConfig.set(KEY_DENY_LIST, dedupeAndTrim(patch.denyList));
|
|
83
|
+
}
|
|
84
|
+
const after = this.getSettings();
|
|
85
|
+
for (const k of Object.keys(after)) {
|
|
86
|
+
const b = before[k];
|
|
87
|
+
const a = after[k];
|
|
88
|
+
const changed = Array.isArray(b) || Array.isArray(a)
|
|
89
|
+
? JSON.stringify(b) !== JSON.stringify(a)
|
|
90
|
+
: b !== a;
|
|
91
|
+
if (changed)
|
|
92
|
+
this.emit('change', { field: k, before: b, after: a });
|
|
93
|
+
}
|
|
94
|
+
return after;
|
|
95
|
+
}
|
|
96
|
+
addToAllowList(agentId) {
|
|
97
|
+
const list = this.getSettings().allowList;
|
|
98
|
+
if (list.includes(agentId))
|
|
99
|
+
return this.getSettings();
|
|
100
|
+
return this.update({ allowList: [...list, agentId] });
|
|
101
|
+
}
|
|
102
|
+
removeFromAllowList(agentId) {
|
|
103
|
+
const list = this.getSettings().allowList.filter(a => a !== agentId);
|
|
104
|
+
return this.update({ allowList: list });
|
|
105
|
+
}
|
|
106
|
+
addToDenyList(agentId) {
|
|
107
|
+
const list = this.getSettings().denyList;
|
|
108
|
+
if (list.includes(agentId))
|
|
109
|
+
return this.getSettings();
|
|
110
|
+
return this.update({ denyList: [...list, agentId] });
|
|
111
|
+
}
|
|
112
|
+
removeFromDenyList(agentId) {
|
|
113
|
+
const list = this.getSettings().denyList.filter(a => a !== agentId);
|
|
114
|
+
return this.update({ denyList: list });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Decide whether a brand-new Telegram topic should be auto-created for an
|
|
118
|
+
* inbound message from `remoteAgent`. The bridge module calls this on every
|
|
119
|
+
* inbound message that doesn't already have a bridged topic.
|
|
120
|
+
*
|
|
121
|
+
* Decision order (first match wins):
|
|
122
|
+
* 1. If bridge is disabled overall → false.
|
|
123
|
+
* 2. If allowList contains the agent (any matching id) → true. (allow > deny)
|
|
124
|
+
* 3. If denyList contains the agent → false.
|
|
125
|
+
* 4. Otherwise fall through to autoCreateTopics (the global default).
|
|
126
|
+
*
|
|
127
|
+
* `remoteAgent` is an opaque identifier — typically the remote agent's
|
|
128
|
+
* fingerprint, but the matcher accepts any string the dashboard surfaces
|
|
129
|
+
* (display name, fingerprint prefix). Allow/deny matching is case-sensitive
|
|
130
|
+
* exact-match.
|
|
131
|
+
*/
|
|
132
|
+
shouldAutoCreateTopic(remoteAgent) {
|
|
133
|
+
const s = this.getSettings();
|
|
134
|
+
if (!s.enabled)
|
|
135
|
+
return false;
|
|
136
|
+
if (s.allowList.includes(remoteAgent))
|
|
137
|
+
return true;
|
|
138
|
+
if (s.denyList.includes(remoteAgent))
|
|
139
|
+
return false;
|
|
140
|
+
return s.autoCreateTopics;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Decide whether to mirror an inbound/outbound message into a topic that
|
|
144
|
+
* already exists for this thread. Bridge module calls this when there's a
|
|
145
|
+
* known topic-id binding for the thread.
|
|
146
|
+
*
|
|
147
|
+
* Mirroring is independent of the deny-list — once the user has a topic
|
|
148
|
+
* for a thread (which they explicitly created or allow-listed), traffic
|
|
149
|
+
* keeps flowing unless the master switch is off or `mirrorExisting` is off.
|
|
150
|
+
*/
|
|
151
|
+
shouldMirrorIntoExistingTopic() {
|
|
152
|
+
const s = this.getSettings();
|
|
153
|
+
return s.enabled && s.mirrorExisting;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function dedupeAndTrim(list) {
|
|
157
|
+
const seen = new Set();
|
|
158
|
+
const out = [];
|
|
159
|
+
for (const raw of list) {
|
|
160
|
+
const v = raw.trim();
|
|
161
|
+
if (!v || seen.has(v))
|
|
162
|
+
continue;
|
|
163
|
+
seen.add(v);
|
|
164
|
+
out.push(v);
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=TelegramBridgeConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TelegramBridgeConfig.js","sourceRoot":"","sources":["../../src/threadline/TelegramBridgeConfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThreadlineBootstrap.d.ts","sourceRoot":"","sources":["../../src/threadline/ThreadlineBootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"ThreadlineBootstrap.d.ts","sourceRoot":"","sources":["../../src/threadline/ThreadlineBootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAK3D,MAAM,WAAW,yBAAyB;IACxC,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,wBAAwB;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,UAAU,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,SAAS,CAAC;IAC/C,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,8CAA8C;IAC9C,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,8BAA8B;IAC9B,SAAS,EAAE,cAAc,CAAC;IAC1B,wBAAwB;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,+CAA+C;IAC/C,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,iDAAiD;IACjD,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,oBAAoB;IACpB,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAQD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,yBAAyB,CAAC,CAqPpC"}
|
|
@@ -22,6 +22,7 @@ import { generateIdentityKeyPair } from './ThreadlineCrypto.js';
|
|
|
22
22
|
import { ThreadlineClient } from './client/ThreadlineClient.js';
|
|
23
23
|
import { InboundMessageGate } from './InboundMessageGate.js';
|
|
24
24
|
import { AgentTrustManager } from './AgentTrustManager.js';
|
|
25
|
+
import { SafeFsExecutor } from '../core/SafeFsExecutor.js';
|
|
25
26
|
// ── Constants ────────────────────────────────────────────────────────
|
|
26
27
|
const IDENTITY_KEY_FILE = 'identity-keys.json';
|
|
27
28
|
// ── Implementation ───────────────────────────────────────────────────
|
|
@@ -91,9 +92,8 @@ export async function bootstrapThreadline(config) {
|
|
|
91
92
|
}
|
|
92
93
|
catch {
|
|
93
94
|
// PID file exists but process is dead — clean up stale PID
|
|
94
|
-
// safe-git-allow: incremental-migration
|
|
95
95
|
try {
|
|
96
|
-
|
|
96
|
+
SafeFsExecutor.safeUnlinkSync(daemonPidPath, { operation: 'src/threadline/ThreadlineBootstrap.ts:153' });
|
|
97
97
|
}
|
|
98
98
|
catch { /* ignore */ }
|
|
99
99
|
}
|