@tenex-chat/backend 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +194 -0
- package/dist/backend-wrapper.cjs +3 -0
- package/dist/src/index.js +331928 -0
- package/package.json +103 -0
- package/src/agents/AgentRegistry.ts +418 -0
- package/src/agents/AgentStorage.ts +1133 -0
- package/src/agents/ConfigResolver.ts +229 -0
- package/src/agents/agent-installer.ts +236 -0
- package/src/agents/agent-loader.ts +241 -0
- package/src/agents/constants.ts +82 -0
- package/src/agents/errors.ts +48 -0
- package/src/agents/execution/AgentExecutor.ts +561 -0
- package/src/agents/execution/ExecutionContextFactory.ts +112 -0
- package/src/agents/execution/MessageCompiler.ts +597 -0
- package/src/agents/execution/MessageSyncer.ts +100 -0
- package/src/agents/execution/PostCompletionChecker.ts +278 -0
- package/src/agents/execution/ProgressMonitor.ts +50 -0
- package/src/agents/execution/RALResolver.ts +177 -0
- package/src/agents/execution/SessionManager.ts +181 -0
- package/src/agents/execution/StreamCallbacks.ts +312 -0
- package/src/agents/execution/StreamExecutionHandler.ts +579 -0
- package/src/agents/execution/StreamSetup.ts +313 -0
- package/src/agents/execution/ToolEventHandlers.ts +239 -0
- package/src/agents/execution/ToolExecutionTracker.ts +498 -0
- package/src/agents/execution/ToolResultUtils.ts +97 -0
- package/src/agents/execution/ToolSupervisionWrapper.ts +174 -0
- package/src/agents/execution/constants.ts +16 -0
- package/src/agents/execution/index.ts +3 -0
- package/src/agents/execution/types.ts +96 -0
- package/src/agents/execution/utils.ts +26 -0
- package/src/agents/index.ts +4 -0
- package/src/agents/script-installer.ts +266 -0
- package/src/agents/supervision/SupervisorLLMService.ts +253 -0
- package/src/agents/supervision/SupervisorOrchestrator.ts +471 -0
- package/src/agents/supervision/heuristics/ConsecutiveToolsWithoutTodoHeuristic.ts +73 -0
- package/src/agents/supervision/heuristics/DelegationClaimHeuristic.ts +80 -0
- package/src/agents/supervision/heuristics/HeuristicRegistry.ts +114 -0
- package/src/agents/supervision/heuristics/PendingTodosHeuristic.ts +93 -0
- package/src/agents/supervision/heuristics/SilentAgentHeuristic.ts +54 -0
- package/src/agents/supervision/heuristics/index.ts +5 -0
- package/src/agents/supervision/index.ts +28 -0
- package/src/agents/supervision/registerHeuristics.ts +110 -0
- package/src/agents/supervision/supervisionHealthCheck.ts +123 -0
- package/src/agents/supervision/types.ts +171 -0
- package/src/agents/tool-names.ts +46 -0
- package/src/agents/tool-normalization.ts +184 -0
- package/src/agents/types/index.ts +2 -0
- package/src/agents/types/runtime.ts +74 -0
- package/src/agents/types/storage.ts +145 -0
- package/src/commands/agent/import/index.ts +6 -0
- package/src/commands/agent/import/openclaw-distiller.ts +57 -0
- package/src/commands/agent/import/openclaw-reader.ts +141 -0
- package/src/commands/agent/import/openclaw.ts +154 -0
- package/src/commands/agent/index.ts +6 -0
- package/src/commands/agent.ts +215 -0
- package/src/commands/daemon.ts +198 -0
- package/src/commands/doctor.ts +134 -0
- package/src/commands/setup/embed.ts +228 -0
- package/src/commands/setup/global-system-prompt.ts +223 -0
- package/src/commands/setup/image.ts +179 -0
- package/src/commands/setup/index.ts +16 -0
- package/src/commands/setup/interactive.ts +95 -0
- package/src/commands/setup/llm.ts +38 -0
- package/src/commands/setup/onboarding.ts +294 -0
- package/src/commands/setup/providers.ts +27 -0
- package/src/constants.ts +34 -0
- package/src/conversations/ConversationDiskReader.ts +148 -0
- package/src/conversations/ConversationRegistry.ts +728 -0
- package/src/conversations/ConversationStore.ts +868 -0
- package/src/conversations/MessageBuilder.ts +866 -0
- package/src/conversations/executionTime.ts +62 -0
- package/src/conversations/formatters/DelegationXmlFormatter.ts +64 -0
- package/src/conversations/formatters/ThreadedConversationFormatter.ts +303 -0
- package/src/conversations/formatters/index.ts +9 -0
- package/src/conversations/formatters/utils/MessageFormatter.ts +46 -0
- package/src/conversations/formatters/utils/TimestampFormatter.ts +56 -0
- package/src/conversations/formatters/utils/TreeBuilder.ts +131 -0
- package/src/conversations/formatters/utils/TreeRenderer.ts +49 -0
- package/src/conversations/index.ts +2 -0
- package/src/conversations/persistence/ToolMessageStorage.ts +143 -0
- package/src/conversations/search/ConversationIndexManager.ts +393 -0
- package/src/conversations/search/QueryParser.ts +114 -0
- package/src/conversations/search/SearchEngine.ts +175 -0
- package/src/conversations/search/SnippetExtractor.ts +345 -0
- package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +484 -0
- package/src/conversations/search/embeddings/ConversationIndexingJob.ts +320 -0
- package/src/conversations/search/embeddings/IndexingStateManager.ts +338 -0
- package/src/conversations/search/embeddings/index.ts +18 -0
- package/src/conversations/search/index.ts +49 -0
- package/src/conversations/search/types.ts +124 -0
- package/src/conversations/services/CategoryManager.ts +160 -0
- package/src/conversations/services/ConversationResolver.ts +296 -0
- package/src/conversations/services/ConversationSummarizer.ts +234 -0
- package/src/conversations/services/MetadataDebounceManager.ts +188 -0
- package/src/conversations/services/index.ts +2 -0
- package/src/conversations/types.ts +148 -0
- package/src/conversations/utils/content-utils.ts +69 -0
- package/src/conversations/utils/image-placeholder.ts +281 -0
- package/src/conversations/utils/image-url-utils.ts +171 -0
- package/src/conversations/utils/multimodal-content.ts +90 -0
- package/src/conversations/utils/tool-result-truncator.ts +159 -0
- package/src/daemon/Daemon.ts +1883 -0
- package/src/daemon/ProjectRuntime.ts +657 -0
- package/src/daemon/RestartState.ts +152 -0
- package/src/daemon/RuntimeLifecycle.ts +268 -0
- package/src/daemon/SubscriptionManager.ts +305 -0
- package/src/daemon/UnixSocketTransport.ts +318 -0
- package/src/daemon/filters/SubscriptionFilterBuilder.ts +119 -0
- package/src/daemon/index.ts +9 -0
- package/src/daemon/routing/DaemonRouter.ts +491 -0
- package/src/daemon/types.ts +150 -0
- package/src/daemon/utils/routing-log.ts +76 -0
- package/src/daemon/utils/telemetry.ts +173 -0
- package/src/event-handler/agentDeletion.ts +383 -0
- package/src/event-handler/index.ts +749 -0
- package/src/event-handler/newConversation.ts +165 -0
- package/src/event-handler/project.ts +166 -0
- package/src/event-handler/reply.ts +18 -0
- package/src/events/NDKAgentDefinition.ts +292 -0
- package/src/events/NDKAgentLesson.ts +106 -0
- package/src/events/NDKEventMetadata.ts +34 -0
- package/src/events/NDKMCPTool.ts +60 -0
- package/src/events/NDKProjectStatus.ts +384 -0
- package/src/events/index.ts +4 -0
- package/src/index.ts +126 -0
- package/src/lib/agent-home.ts +334 -0
- package/src/lib/error-formatter.ts +200 -0
- package/src/lib/fs/filesystem.ts +128 -0
- package/src/lib/fs/index.ts +1 -0
- package/src/lib/json-parser.ts +30 -0
- package/src/lib/string.ts +15 -0
- package/src/lib/time.ts +74 -0
- package/src/llm/ChunkHandler.ts +277 -0
- package/src/llm/FinishHandler.ts +250 -0
- package/src/llm/LLMConfigEditor.ts +154 -0
- package/src/llm/LLMServiceFactory.ts +230 -0
- package/src/llm/MessageProcessor.ts +90 -0
- package/src/llm/RecordingState.ts +37 -0
- package/src/llm/StreamPublisher.ts +40 -0
- package/src/llm/TracingUtils.ts +77 -0
- package/src/llm/chunk-validators.ts +57 -0
- package/src/llm/constants.ts +6 -0
- package/src/llm/index.ts +12 -0
- package/src/llm/meta/MetaModelResolver.ts +352 -0
- package/src/llm/meta/index.ts +11 -0
- package/src/llm/middleware/flight-recorder.ts +188 -0
- package/src/llm/providers/MockProvider.ts +332 -0
- package/src/llm/providers/agent/ClaudeCodeProvider.ts +343 -0
- package/src/llm/providers/agent/ClaudeCodeToolsAdapter.ts +203 -0
- package/src/llm/providers/agent/CodexAppServerProvider.ts +214 -0
- package/src/llm/providers/agent/CodexAppServerToolsAdapter.ts +91 -0
- package/src/llm/providers/agent/index.ts +10 -0
- package/src/llm/providers/base/AgentProvider.ts +107 -0
- package/src/llm/providers/base/BaseProvider.ts +114 -0
- package/src/llm/providers/base/StandardProvider.ts +38 -0
- package/src/llm/providers/base/index.ts +9 -0
- package/src/llm/providers/index.ts +106 -0
- package/src/llm/providers/key-manager.ts +238 -0
- package/src/llm/providers/ollama-models.ts +105 -0
- package/src/llm/providers/openrouter-models.ts +102 -0
- package/src/llm/providers/provider-ids.ts +18 -0
- package/src/llm/providers/registry/ProviderRegistry.ts +414 -0
- package/src/llm/providers/registry/index.ts +7 -0
- package/src/llm/providers/standard/AnthropicProvider.ts +71 -0
- package/src/llm/providers/standard/OllamaProvider.ts +59 -0
- package/src/llm/providers/standard/OpenAIProvider.ts +44 -0
- package/src/llm/providers/standard/OpenRouterProvider.ts +103 -0
- package/src/llm/providers/standard/index.ts +10 -0
- package/src/llm/providers/types.ts +194 -0
- package/src/llm/providers/usage-metadata.ts +78 -0
- package/src/llm/service.ts +713 -0
- package/src/llm/types.ts +167 -0
- package/src/llm/utils/ConfigurationManager.ts +650 -0
- package/src/llm/utils/ConfigurationTester.ts +229 -0
- package/src/llm/utils/ModelSelector.ts +212 -0
- package/src/llm/utils/ProviderConfigUI.ts +177 -0
- package/src/llm/utils/claudeCodePromptCompiler.ts +141 -0
- package/src/llm/utils/codex-models.ts +53 -0
- package/src/llm/utils/context-window-cache.ts +30 -0
- package/src/llm/utils/models-dev-cache.ts +267 -0
- package/src/llm/utils/provider-setup.ts +50 -0
- package/src/llm/utils/tool-errors.ts +78 -0
- package/src/llm/utils/usage.ts +74 -0
- package/src/logging/EventRoutingLogger.ts +205 -0
- package/src/nostr/AgentEventDecoder.ts +357 -0
- package/src/nostr/AgentEventEncoder.ts +677 -0
- package/src/nostr/AgentProfilePublisher.ts +657 -0
- package/src/nostr/AgentPublisher.ts +437 -0
- package/src/nostr/BlossomService.ts +226 -0
- package/src/nostr/InterventionPublisher.ts +132 -0
- package/src/nostr/TagExtractor.ts +228 -0
- package/src/nostr/collectEvents.ts +83 -0
- package/src/nostr/constants.ts +38 -0
- package/src/nostr/encryption.ts +26 -0
- package/src/nostr/index.ts +31 -0
- package/src/nostr/keys.ts +17 -0
- package/src/nostr/kinds.ts +37 -0
- package/src/nostr/ndkClient.ts +72 -0
- package/src/nostr/relays.ts +43 -0
- package/src/nostr/trace-context.ts +39 -0
- package/src/nostr/types.ts +227 -0
- package/src/nostr/utils.ts +84 -0
- package/src/prompts/core/FragmentRegistry.ts +30 -0
- package/src/prompts/core/PromptBuilder.ts +98 -0
- package/src/prompts/core/index.ts +3 -0
- package/src/prompts/core/types.ts +13 -0
- package/src/prompts/fragments/00-global-system-prompt.ts +44 -0
- package/src/prompts/fragments/01-agent-identity.ts +69 -0
- package/src/prompts/fragments/02-agent-home-directory.ts +114 -0
- package/src/prompts/fragments/03-system-reminders-explanation.ts +14 -0
- package/src/prompts/fragments/04-relay-configuration.ts +38 -0
- package/src/prompts/fragments/05-delegation-chain.ts +45 -0
- package/src/prompts/fragments/06-agent-todos.ts +74 -0
- package/src/prompts/fragments/06-todo-usage-guidance.ts +34 -0
- package/src/prompts/fragments/07-meta-project-context.ts +234 -0
- package/src/prompts/fragments/08-active-conversations.ts +382 -0
- package/src/prompts/fragments/09-recent-conversations.ts +153 -0
- package/src/prompts/fragments/10-referenced-article.ts +21 -0
- package/src/prompts/fragments/11-nudges.ts +134 -0
- package/src/prompts/fragments/12-skills.ts +127 -0
- package/src/prompts/fragments/13-available-nudges.ts +122 -0
- package/src/prompts/fragments/15-available-agents.ts +53 -0
- package/src/prompts/fragments/16-stay-in-your-lane.ts +41 -0
- package/src/prompts/fragments/17-todo-before-delegation.ts +39 -0
- package/src/prompts/fragments/20-voice-mode.ts +62 -0
- package/src/prompts/fragments/22-scheduled-tasks.ts +175 -0
- package/src/prompts/fragments/24-retrieved-lessons.ts +26 -0
- package/src/prompts/fragments/25-rag-instructions.ts +333 -0
- package/src/prompts/fragments/26-mcp-resources.ts +237 -0
- package/src/prompts/fragments/27-memorized-reports.ts +77 -0
- package/src/prompts/fragments/28-agent-directed-monitoring.ts +32 -0
- package/src/prompts/fragments/29-rag-collections.ts +50 -0
- package/src/prompts/fragments/30-worktree-context.ts +98 -0
- package/src/prompts/fragments/31-agents-md-guidance.ts +96 -0
- package/src/prompts/fragments/32-process-metrics.ts +72 -0
- package/src/prompts/fragments/debug-mode.ts +48 -0
- package/src/prompts/fragments/delegation-completion.ts +44 -0
- package/src/prompts/fragments/index.ts +91 -0
- package/src/prompts/index.ts +21 -0
- package/src/prompts/utils/systemPromptBuilder.ts +777 -0
- package/src/scripts/migrate-prefix-index.ts +157 -0
- package/src/services/AgentDefinitionMonitor.ts +701 -0
- package/src/services/ConfigService.ts +723 -0
- package/src/services/CooldownRegistry.ts +199 -0
- package/src/services/LLMOperationsRegistry.ts +424 -0
- package/src/services/OwnerAgentListService.ts +354 -0
- package/src/services/PubkeyService.ts +308 -0
- package/src/services/agents/AgentMetadataStore.ts +72 -0
- package/src/services/agents/AgentResolution.ts +59 -0
- package/src/services/agents/EscalationService.ts +281 -0
- package/src/services/agents/NDKAgentDiscovery.ts +95 -0
- package/src/services/agents/index.ts +7 -0
- package/src/services/agents-md/AgentsMdService.ts +184 -0
- package/src/services/agents-md/SystemReminderInjector.ts +238 -0
- package/src/services/agents-md/index.ts +11 -0
- package/src/services/apns/APNsClient.ts +203 -0
- package/src/services/apns/APNsService.ts +358 -0
- package/src/services/apns/index.ts +11 -0
- package/src/services/apns/types.ts +80 -0
- package/src/services/compression/CompressionService.ts +445 -0
- package/src/services/compression/compression-schema.ts +28 -0
- package/src/services/compression/compression-types.ts +74 -0
- package/src/services/compression/compression-utils.ts +587 -0
- package/src/services/config/types.ts +394 -0
- package/src/services/dispatch/AgentDispatchService.ts +937 -0
- package/src/services/dispatch/AgentRouter.ts +181 -0
- package/src/services/dispatch/DelegationCompletionHandler.ts +232 -0
- package/src/services/embedding/EmbeddingProvider.ts +188 -0
- package/src/services/embedding/index.ts +5 -0
- package/src/services/event-context/EventContextService.ts +108 -0
- package/src/services/event-context/index.ts +2 -0
- package/src/services/heuristics/ContextBuilder.ts +106 -0
- package/src/services/heuristics/HeuristicEngine.ts +200 -0
- package/src/services/heuristics/formatters.ts +58 -0
- package/src/services/heuristics/index.ts +12 -0
- package/src/services/heuristics/rules/index.ts +25 -0
- package/src/services/heuristics/rules/todoBeforeDelegation.ts +69 -0
- package/src/services/heuristics/rules/todoReminderOnToolUse.ts +63 -0
- package/src/services/heuristics/types.ts +144 -0
- package/src/services/image/ImageGenerationService.ts +389 -0
- package/src/services/image/index.ts +12 -0
- package/src/services/intervention/InterventionService.ts +1352 -0
- package/src/services/intervention/index.ts +7 -0
- package/src/services/mcp/MCPManager.ts +683 -0
- package/src/services/mcp/McpNotificationDelivery.ts +139 -0
- package/src/services/mcp/McpSubscriptionService.ts +653 -0
- package/src/services/mcp/mcpInstaller.ts +130 -0
- package/src/services/nip46/Nip46SigningLog.ts +81 -0
- package/src/services/nip46/Nip46SigningService.ts +467 -0
- package/src/services/nip46/index.ts +4 -0
- package/src/services/nudge/NudgeService.ts +224 -0
- package/src/services/nudge/NudgeWhitelistService.ts +382 -0
- package/src/services/nudge/index.ts +5 -0
- package/src/services/nudge/types.ts +83 -0
- package/src/services/projects/ProjectContext.ts +672 -0
- package/src/services/projects/ProjectContextStore.ts +102 -0
- package/src/services/projects/index.ts +6 -0
- package/src/services/prompt-compiler/index.ts +15 -0
- package/src/services/prompt-compiler/prompt-compiler-service.ts +1143 -0
- package/src/services/pubkey-gate/PubkeyGateService.ts +93 -0
- package/src/services/pubkey-gate/index.ts +1 -0
- package/src/services/rag/EmbeddingProviderFactory.ts +292 -0
- package/src/services/rag/LanceDBMaintenanceService.ts +211 -0
- package/src/services/rag/RAGDatabaseService.ts +173 -0
- package/src/services/rag/RAGOperations.ts +682 -0
- package/src/services/rag/RAGService.ts +240 -0
- package/src/services/rag/RagSubscriptionService.ts +618 -0
- package/src/services/rag/rag-utils.ts +174 -0
- package/src/services/ral/PendingDelegationsRegistry.ts +168 -0
- package/src/services/ral/RALRegistry.ts +2782 -0
- package/src/services/ral/index.ts +4 -0
- package/src/services/ral/types.ts +292 -0
- package/src/services/reports/LocalReportStore.ts +380 -0
- package/src/services/reports/ReportEmbeddingService.ts +430 -0
- package/src/services/reports/ReportService.ts +440 -0
- package/src/services/reports/articleUtils.ts +52 -0
- package/src/services/reports/index.ts +7 -0
- package/src/services/scheduling/SchedulerService.ts +1057 -0
- package/src/services/scheduling/errors.ts +14 -0
- package/src/services/scheduling/index.ts +7 -0
- package/src/services/scheduling/utils.ts +77 -0
- package/src/services/search/SearchProviderRegistry.ts +78 -0
- package/src/services/search/UnifiedSearchService.ts +218 -0
- package/src/services/search/index.ts +47 -0
- package/src/services/search/projectFilter.ts +22 -0
- package/src/services/search/providers/ConversationSearchProvider.ts +48 -0
- package/src/services/search/providers/LessonSearchProvider.ts +75 -0
- package/src/services/search/providers/ReportSearchProvider.ts +49 -0
- package/src/services/search/types.ts +144 -0
- package/src/services/skill/SkillService.ts +482 -0
- package/src/services/skill/index.ts +2 -0
- package/src/services/skill/types.ts +70 -0
- package/src/services/status/OperationsStatusService.ts +276 -0
- package/src/services/status/ProjectStatusService.ts +522 -0
- package/src/services/status/index.ts +11 -0
- package/src/services/storage/PrefixKVStore.ts +242 -0
- package/src/services/storage/index.ts +1 -0
- package/src/services/system-reminder/SystemReminderUtils.ts +96 -0
- package/src/services/system-reminder/index.ts +7 -0
- package/src/services/trust-pubkeys/TrustPubkeyService.ts +325 -0
- package/src/services/trust-pubkeys/index.ts +2 -0
- package/src/telemetry/ConversationSpanManager.ts +111 -0
- package/src/telemetry/EventLoopMonitor.ts +206 -0
- package/src/telemetry/LLMSpanRegistry.ts +20 -0
- package/src/telemetry/NostrSpanProcessor.ts +89 -0
- package/src/telemetry/ToolCallSpanProcessor.ts +66 -0
- package/src/telemetry/diagnostics.ts +27 -0
- package/src/telemetry/setup.ts +120 -0
- package/src/tools/implementations/agents_discover.ts +121 -0
- package/src/tools/implementations/agents_hire.ts +127 -0
- package/src/tools/implementations/agents_list.ts +96 -0
- package/src/tools/implementations/agents_publish.ts +611 -0
- package/src/tools/implementations/agents_read.ts +173 -0
- package/src/tools/implementations/agents_write.ts +200 -0
- package/src/tools/implementations/ask.ts +411 -0
- package/src/tools/implementations/change_model.ts +141 -0
- package/src/tools/implementations/conversation_get.ts +661 -0
- package/src/tools/implementations/conversation_list.ts +377 -0
- package/src/tools/implementations/conversation_search.ts +370 -0
- package/src/tools/implementations/delegate.ts +327 -0
- package/src/tools/implementations/delegate_crossproject.ts +209 -0
- package/src/tools/implementations/delegate_followup.ts +300 -0
- package/src/tools/implementations/fs_edit.ts +162 -0
- package/src/tools/implementations/fs_glob.ts +182 -0
- package/src/tools/implementations/fs_grep.ts +513 -0
- package/src/tools/implementations/fs_read.ts +332 -0
- package/src/tools/implementations/fs_write.ts +113 -0
- package/src/tools/implementations/generate_image.ts +259 -0
- package/src/tools/implementations/home_fs.ts +515 -0
- package/src/tools/implementations/kill.ts +651 -0
- package/src/tools/implementations/learn.ts +166 -0
- package/src/tools/implementations/lesson-formatter.ts +38 -0
- package/src/tools/implementations/lesson_delete.ts +164 -0
- package/src/tools/implementations/lesson_get.ts +105 -0
- package/src/tools/implementations/lessons_list.ts +153 -0
- package/src/tools/implementations/mcp_resource_read.ts +161 -0
- package/src/tools/implementations/mcp_subscribe.ts +158 -0
- package/src/tools/implementations/mcp_subscription_stop.ts +85 -0
- package/src/tools/implementations/nostr_fetch.ts +149 -0
- package/src/tools/implementations/nostr_publish_as_user.ts +353 -0
- package/src/tools/implementations/project_list.ts +146 -0
- package/src/tools/implementations/rag_add_documents.ts +573 -0
- package/src/tools/implementations/rag_create_collection.ts +65 -0
- package/src/tools/implementations/rag_delete_collection.ts +68 -0
- package/src/tools/implementations/rag_list_collections.ts +77 -0
- package/src/tools/implementations/rag_query.ts +107 -0
- package/src/tools/implementations/rag_subscription_create.ts +105 -0
- package/src/tools/implementations/rag_subscription_delete.ts +80 -0
- package/src/tools/implementations/rag_subscription_get.ts +123 -0
- package/src/tools/implementations/rag_subscription_list.ts +128 -0
- package/src/tools/implementations/report_delete.ts +79 -0
- package/src/tools/implementations/report_read.ts +160 -0
- package/src/tools/implementations/report_write.ts +278 -0
- package/src/tools/implementations/reports_list.ts +77 -0
- package/src/tools/implementations/schedule_task.ts +104 -0
- package/src/tools/implementations/schedule_task_cancel.ts +62 -0
- package/src/tools/implementations/schedule_task_once.ts +128 -0
- package/src/tools/implementations/schedule_tasks_list.ts +79 -0
- package/src/tools/implementations/search.ts +160 -0
- package/src/tools/implementations/shell.ts +553 -0
- package/src/tools/implementations/todo.ts +260 -0
- package/src/tools/implementations/upload_blob.ts +381 -0
- package/src/tools/implementations/web_fetch.ts +153 -0
- package/src/tools/implementations/web_search.ts +250 -0
- package/src/tools/registry.ts +670 -0
- package/src/tools/types.ts +177 -0
- package/src/tools/utils.ts +256 -0
- package/src/types/event-ids.ts +320 -0
- package/src/types/index.ts +46 -0
- package/src/utils/agentFetcher.ts +107 -0
- package/src/utils/cli-error.ts +29 -0
- package/src/utils/conversation-id.ts +27 -0
- package/src/utils/conversation-utils.ts +1 -0
- package/src/utils/delegation-chain.ts +357 -0
- package/src/utils/error-handler.ts +42 -0
- package/src/utils/git/gitignore.ts +69 -0
- package/src/utils/git/index.ts +2 -0
- package/src/utils/git/initializeGitRepo.ts +204 -0
- package/src/utils/git/worktree.ts +260 -0
- package/src/utils/lessonFormatter.ts +70 -0
- package/src/utils/lessonTrust.ts +24 -0
- package/src/utils/lockfile.ts +123 -0
- package/src/utils/logger.ts +149 -0
- package/src/utils/nostr-entity-parser.ts +365 -0
- package/src/utils/process.ts +49 -0
- package/src/wrapper.ts +262 -0
- package/tsconfig.json +41 -0
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
import type { AgentRegistry } from "@/agents/AgentRegistry";
|
|
2
|
+
import type { AgentInstance } from "@/agents/types";
|
|
3
|
+
import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
|
|
4
|
+
import type { MCPManager } from "@/services/mcp/MCPManager";
|
|
5
|
+
import { NudgeWhitelistService, type WhitelistItem } from "@/services/nudge";
|
|
6
|
+
import type { LessonComment } from "@/services/prompt-compiler";
|
|
7
|
+
import type { LocalReportStore } from "@/services/reports/LocalReportStore";
|
|
8
|
+
import type { ReportInfo } from "@/services/reports/ReportService";
|
|
9
|
+
import { articleToReportInfo } from "@/services/reports/articleUtils";
|
|
10
|
+
import type { ProjectStatusService } from "@/services/status/ProjectStatusService";
|
|
11
|
+
import { logger } from "@/utils/logger";
|
|
12
|
+
import type { Hexpubkey, NDKProject, NDKArticle } from "@nostr-dev-kit/ndk";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Resolve the Project Manager for a project.
|
|
16
|
+
*
|
|
17
|
+
* Priority order:
|
|
18
|
+
* 1. Global PM designation via kind 24020 event ["pm"] tag without a-tag (highest priority)
|
|
19
|
+
* 2. Project-scoped PM designation via kind 24020 event ["pm"] tag WITH a-tag (projectOverrides[dTag].isPM)
|
|
20
|
+
* 3. Local PM override for this specific project (pmOverrides) - legacy, for backward compatibility
|
|
21
|
+
* 4. Explicit PM designation in 31933 project tags (role="pm")
|
|
22
|
+
* 5. First agent from project tags
|
|
23
|
+
* 6. First agent in registry (fallback for projects with no agent tags)
|
|
24
|
+
*
|
|
25
|
+
* @param project - The NDKProject event
|
|
26
|
+
* @param agents - Map of agent slug to AgentInstance
|
|
27
|
+
* @param projectDTag - The project's dTag for checking project-scoped PM overrides
|
|
28
|
+
* @returns The resolved PM agent or undefined if no agents exist
|
|
29
|
+
* @throws Error if PM is designated but not loaded in registry
|
|
30
|
+
*/
|
|
31
|
+
export function resolveProjectManager(
|
|
32
|
+
project: NDKProject,
|
|
33
|
+
agents: Map<string, AgentInstance>,
|
|
34
|
+
projectDTag: string | undefined
|
|
35
|
+
): AgentInstance | undefined {
|
|
36
|
+
// Step 1: Check for global PM designation via kind 24020 ["pm"] tag (highest priority)
|
|
37
|
+
// Collect all agents with isPM=true to detect conflicts
|
|
38
|
+
const globalPMAgents: AgentInstance[] = [];
|
|
39
|
+
for (const agent of agents.values()) {
|
|
40
|
+
if (agent.isPM === true) {
|
|
41
|
+
globalPMAgents.push(agent);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (globalPMAgents.length > 0) {
|
|
46
|
+
if (globalPMAgents.length > 1) {
|
|
47
|
+
// Warn about multiple global PM agents - this is a configuration issue
|
|
48
|
+
logger.warn("Multiple agents have global PM designation (isPM=true). Using first found.", {
|
|
49
|
+
pmAgents: globalPMAgents.map((a) => ({ slug: a.slug, name: a.name })),
|
|
50
|
+
selectedAgent: globalPMAgents[0].slug,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
logger.info("Found global PM designation via kind 24020 event", {
|
|
55
|
+
agentName: globalPMAgents[0].name,
|
|
56
|
+
agentSlug: globalPMAgents[0].slug,
|
|
57
|
+
});
|
|
58
|
+
return globalPMAgents[0];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Step 2: Check for project-scoped PM designation via kind 24020 with a-tag
|
|
62
|
+
if (projectDTag) {
|
|
63
|
+
for (const agent of agents.values()) {
|
|
64
|
+
if (agent.projectOverrides?.[projectDTag]?.isPM === true) {
|
|
65
|
+
logger.info("Found project-scoped PM designation via kind 24020 event", {
|
|
66
|
+
agentName: agent.name,
|
|
67
|
+
agentSlug: agent.slug,
|
|
68
|
+
projectDTag,
|
|
69
|
+
});
|
|
70
|
+
return agent;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Step 3: Check for local PM override for this specific project (pmOverrides)
|
|
76
|
+
if (projectDTag) {
|
|
77
|
+
for (const agent of agents.values()) {
|
|
78
|
+
if (agent.pmOverrides?.[projectDTag] === true) {
|
|
79
|
+
logger.info("Found legacy PM override for project", {
|
|
80
|
+
agentName: agent.name,
|
|
81
|
+
agentSlug: agent.slug,
|
|
82
|
+
projectDTag,
|
|
83
|
+
});
|
|
84
|
+
return agent;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Step 4: Check for explicit "pm" role in project tags
|
|
90
|
+
const pmAgentTag = project.tags.find(
|
|
91
|
+
(tag: string[]) => tag[0] === "agent" && tag[2] === "pm"
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (pmAgentTag?.[1]) {
|
|
95
|
+
const pmEventId = pmAgentTag[1];
|
|
96
|
+
logger.debug("Found explicit PM designation in project tags", { pmEventId });
|
|
97
|
+
|
|
98
|
+
for (const agent of agents.values()) {
|
|
99
|
+
if (agent.eventId === pmEventId) {
|
|
100
|
+
return agent;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
throw new Error(
|
|
105
|
+
`Project Manager agent not found. PM agent (eventId: ${pmEventId}) not loaded in registry.`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Step 5: Fallback to first agent from project tags
|
|
110
|
+
const firstAgentTag = project.tags.find(
|
|
111
|
+
(tag: string[]) => tag[0] === "agent" && tag[1]
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (firstAgentTag?.[1]) {
|
|
115
|
+
const pmEventId = firstAgentTag[1];
|
|
116
|
+
logger.debug("No explicit PM found, using first agent from project tags");
|
|
117
|
+
|
|
118
|
+
for (const agent of agents.values()) {
|
|
119
|
+
if (agent.eventId === pmEventId) {
|
|
120
|
+
return agent;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Project Manager agent not found. First agent (eventId: ${pmEventId}) not loaded in registry.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Step 6: No agent tags in project, use first from registry if any exist
|
|
130
|
+
if (agents.size > 0) {
|
|
131
|
+
const firstAgent = agents.values().next().value;
|
|
132
|
+
if (firstAgent) {
|
|
133
|
+
logger.info(
|
|
134
|
+
"No agent tags in project event, using first agent from registry as PM",
|
|
135
|
+
{
|
|
136
|
+
agentName: firstAgent.name,
|
|
137
|
+
agentSlug: firstAgent.slug,
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
return firstAgent;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// No agents at all
|
|
145
|
+
logger.warn(
|
|
146
|
+
"No agents found in project or registry. Project will run without a project manager."
|
|
147
|
+
);
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* ProjectContext provides system-wide access to loaded project and agents
|
|
153
|
+
* Initialized during "tenex project run" by ProjectManager
|
|
154
|
+
*/
|
|
155
|
+
export class ProjectContext {
|
|
156
|
+
/**
|
|
157
|
+
* Event that represents this project, note that this is SIGNED
|
|
158
|
+
* by the USER, so this.project.pubkey is NOT the project's pubkey but the
|
|
159
|
+
* USER OWNER'S pubkey.
|
|
160
|
+
*/
|
|
161
|
+
public project: NDKProject;
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* The project manager agent for this project
|
|
165
|
+
*/
|
|
166
|
+
public projectManager?: AgentInstance;
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Agent registry - single source of truth for all agents
|
|
170
|
+
*/
|
|
171
|
+
public readonly agentRegistry: AgentRegistry;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Getter for agents map to maintain compatibility
|
|
175
|
+
*/
|
|
176
|
+
get agents(): Map<string, AgentInstance> {
|
|
177
|
+
return this.agentRegistry.getAllAgentsMap();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Lessons learned by agents in this project
|
|
182
|
+
* Key: agent pubkey, Value: array of lessons (limited to most recent 50 per agent)
|
|
183
|
+
*/
|
|
184
|
+
public readonly agentLessons: Map<string, NDKAgentLesson[]>;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Comments on agent lessons (kind 1111 events per NIP-22)
|
|
188
|
+
* Key: agent pubkey, Value: array of comments (limited to most recent 100 per agent)
|
|
189
|
+
*/
|
|
190
|
+
public readonly agentComments: Map<string, LessonComment[]>;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Reports cache for this project
|
|
194
|
+
* Key: compound key "author:slug", Value: ReportInfo object
|
|
195
|
+
* Using compound key allows efficient lookup by both slug and author
|
|
196
|
+
*/
|
|
197
|
+
public readonly reports: Map<string, ReportInfo>;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Maximum number of reports to cache per project (memory efficiency)
|
|
201
|
+
*/
|
|
202
|
+
private static readonly MAX_REPORTS_CACHE_SIZE = 200;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Status publisher for immediately publishing project status updates
|
|
206
|
+
*/
|
|
207
|
+
public statusPublisher?: ProjectStatusService;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* MCP manager for this project's MCP tool access
|
|
211
|
+
*/
|
|
212
|
+
public mcpManager?: MCPManager;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Local report store for this project's report storage.
|
|
216
|
+
* Each project has its own store to ensure isolation.
|
|
217
|
+
*/
|
|
218
|
+
public localReportStore?: LocalReportStore;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* @deprecated Nudge whitelist is now user-scoped, not project-scoped.
|
|
222
|
+
* Use NudgeSkillWhitelistService.getInstance() directly instead.
|
|
223
|
+
* Retained as a backward-compatible shim; callers should migrate to the singleton.
|
|
224
|
+
*/
|
|
225
|
+
public nudgeWhitelist: NudgeWhitelistService;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Callback invoked when a new agent is added to this project's registry.
|
|
229
|
+
* Used by Daemon to synchronize its routing map (agentPubkeyToProjects).
|
|
230
|
+
*
|
|
231
|
+
* Set via setOnAgentAdded() - typically by the Daemon during runtime startup.
|
|
232
|
+
*/
|
|
233
|
+
private onAgentAddedCallback?: (agent: AgentInstance) => void;
|
|
234
|
+
|
|
235
|
+
constructor(project: NDKProject, agentRegistry: AgentRegistry) {
|
|
236
|
+
this.project = project;
|
|
237
|
+
this.agentRegistry = agentRegistry;
|
|
238
|
+
|
|
239
|
+
const agents = agentRegistry.getAllAgentsMap();
|
|
240
|
+
const projectDTag = project.dTag || project.tagValue("d");
|
|
241
|
+
|
|
242
|
+
// Debug logging
|
|
243
|
+
logger.debug("Initializing ProjectContext", {
|
|
244
|
+
projectId: project.id,
|
|
245
|
+
projectTitle: project.tagValue("title"),
|
|
246
|
+
projectDTag,
|
|
247
|
+
agentsCount: agents.size,
|
|
248
|
+
agentSlugs: Array.from(agents.keys()),
|
|
249
|
+
agentDetails: Array.from(agents.entries()).map(([slug, agent]) => ({
|
|
250
|
+
slug,
|
|
251
|
+
name: agent.name,
|
|
252
|
+
eventId: agent.eventId,
|
|
253
|
+
})),
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Use consolidated PM resolution logic
|
|
257
|
+
const projectManagerAgent = resolveProjectManager(project, agents, projectDTag);
|
|
258
|
+
|
|
259
|
+
if (projectManagerAgent) {
|
|
260
|
+
logger.info(`Using "${projectManagerAgent.name}" as Project Manager`);
|
|
261
|
+
this.projectManager = projectManagerAgent;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.agentLessons = new Map();
|
|
265
|
+
this.agentComments = new Map();
|
|
266
|
+
this.reports = new Map();
|
|
267
|
+
|
|
268
|
+
// Reference the daemon-scoped nudge whitelist singleton
|
|
269
|
+
this.nudgeWhitelist = NudgeWhitelistService.getInstance();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @deprecated Nudge whitelist is now initialized at daemon level (user-scoped).
|
|
274
|
+
* This method is a no-op. See Daemon.ts step 6d.
|
|
275
|
+
*/
|
|
276
|
+
initializeNudgeWhitelist(_additionalPubkeys: string[] = []): void {
|
|
277
|
+
logger.debug("initializeNudgeWhitelist is deprecated — nudge whitelist is now initialized at daemon level");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @deprecated Use NudgeSkillWhitelistService.getInstance().getWhitelistedNudges() directly.
|
|
282
|
+
* Nudges are user-scoped, not project-scoped.
|
|
283
|
+
*/
|
|
284
|
+
getAvailableNudges(): WhitelistItem[] {
|
|
285
|
+
return this.nudgeWhitelist.getWhitelistedNudges();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// =====================================================================================
|
|
289
|
+
// AGENT ACCESS HELPERS
|
|
290
|
+
// =====================================================================================
|
|
291
|
+
|
|
292
|
+
getAgent(slug: string): AgentInstance | undefined {
|
|
293
|
+
return this.agentRegistry.getAgent(slug);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
getAgentByPubkey(pubkey: Hexpubkey): AgentInstance | undefined {
|
|
297
|
+
return this.agentRegistry.getAgentByPubkey(pubkey);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
getProjectManager(): AgentInstance {
|
|
301
|
+
if (!this.projectManager) {
|
|
302
|
+
throw new Error("Project manager not initialized");
|
|
303
|
+
}
|
|
304
|
+
return this.projectManager;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
getAgentSlugs(): string[] {
|
|
308
|
+
return Array.from(this.agentRegistry.getAllAgentsMap().keys());
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
hasAgent(slug: string): boolean {
|
|
312
|
+
return this.agentRegistry.getAgent(slug) !== undefined;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Register a callback to be invoked when a new agent is added to this project.
|
|
317
|
+
* Used by the Daemon to keep its routing map (agentPubkeyToProjects) synchronized.
|
|
318
|
+
*
|
|
319
|
+
* @param callback - Function to invoke with the newly added agent
|
|
320
|
+
*/
|
|
321
|
+
setOnAgentAdded(callback: (agent: AgentInstance) => void): void {
|
|
322
|
+
this.onAgentAddedCallback = callback;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Notify that a new agent has been added to the registry.
|
|
327
|
+
* This triggers the onAgentAdded callback if one is registered.
|
|
328
|
+
*
|
|
329
|
+
* Called by AgentRegistry.addAgent() when running within this context.
|
|
330
|
+
*/
|
|
331
|
+
notifyAgentAdded(agent: AgentInstance): void {
|
|
332
|
+
if (this.onAgentAddedCallback) {
|
|
333
|
+
this.onAgentAddedCallback(agent);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// =====================================================================================
|
|
338
|
+
// LESSON MANAGEMENT
|
|
339
|
+
// =====================================================================================
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Add a lesson for an agent, maintaining the 50-lesson limit per agent.
|
|
343
|
+
*/
|
|
344
|
+
addLesson(agentPubkey: string, lesson: NDKAgentLesson): void {
|
|
345
|
+
const existingLessons = this.agentLessons.get(agentPubkey) || [];
|
|
346
|
+
|
|
347
|
+
// Add the new lesson at the beginning (most recent first)
|
|
348
|
+
const updatedLessons = [lesson, ...existingLessons];
|
|
349
|
+
|
|
350
|
+
// Keep only the most recent 50 lessons
|
|
351
|
+
const limitedLessons = updatedLessons.slice(0, 50);
|
|
352
|
+
|
|
353
|
+
this.agentLessons.set(agentPubkey, limitedLessons);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Remove a lesson for an agent by event ID.
|
|
358
|
+
* @returns true if the lesson was found and removed, false otherwise
|
|
359
|
+
*/
|
|
360
|
+
removeLesson(agentPubkey: string, eventId: string): boolean {
|
|
361
|
+
const lessons = this.agentLessons.get(agentPubkey);
|
|
362
|
+
if (!lessons) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const index = lessons.findIndex((l) => l.id === eventId);
|
|
367
|
+
if (index === -1) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const newLessons = [...lessons.slice(0, index), ...lessons.slice(index + 1)];
|
|
372
|
+
this.agentLessons.set(agentPubkey, newLessons);
|
|
373
|
+
|
|
374
|
+
logger.debug("ProjectContext: removed lesson from cache", {
|
|
375
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
376
|
+
eventId: eventId.substring(0, 8),
|
|
377
|
+
remainingLessons: newLessons.length,
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Get lessons for a specific agent
|
|
385
|
+
*/
|
|
386
|
+
getLessonsForAgent(agentPubkey: string): NDKAgentLesson[] {
|
|
387
|
+
return this.agentLessons.get(agentPubkey) || [];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Get all lessons across all agents
|
|
392
|
+
*/
|
|
393
|
+
getAllLessons(): NDKAgentLesson[] {
|
|
394
|
+
return Array.from(this.agentLessons.values()).flat();
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// =====================================================================================
|
|
398
|
+
// COMMENT MANAGEMENT (kind 1111 NIP-22 comments on lessons)
|
|
399
|
+
// =====================================================================================
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Maximum number of comments to store per agent (memory efficiency)
|
|
403
|
+
*/
|
|
404
|
+
private static readonly MAX_COMMENTS_PER_AGENT = 100;
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Add a comment for an agent, maintaining the 100-comment limit per agent.
|
|
408
|
+
* Comments are de-duplicated by event ID.
|
|
409
|
+
*/
|
|
410
|
+
addComment(agentPubkey: string, comment: LessonComment): void {
|
|
411
|
+
const existingComments = this.agentComments.get(agentPubkey) || [];
|
|
412
|
+
|
|
413
|
+
// Check for duplicates
|
|
414
|
+
if (existingComments.some((c) => c.id === comment.id)) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// Add the new comment at the beginning (most recent first)
|
|
419
|
+
const updatedComments = [comment, ...existingComments];
|
|
420
|
+
|
|
421
|
+
// Keep only the most recent comments
|
|
422
|
+
const limitedComments = updatedComments.slice(0, ProjectContext.MAX_COMMENTS_PER_AGENT);
|
|
423
|
+
|
|
424
|
+
this.agentComments.set(agentPubkey, limitedComments);
|
|
425
|
+
|
|
426
|
+
logger.debug("ProjectContext: added comment for agent", {
|
|
427
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
428
|
+
commentId: comment.id.substring(0, 8),
|
|
429
|
+
lessonEventId: comment.lessonEventId.substring(0, 8),
|
|
430
|
+
totalComments: limitedComments.length,
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Get comments for a specific agent
|
|
436
|
+
*/
|
|
437
|
+
getCommentsForAgent(agentPubkey: string): LessonComment[] {
|
|
438
|
+
return this.agentComments.get(agentPubkey) || [];
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Get comments for a specific lesson event ID
|
|
443
|
+
*/
|
|
444
|
+
getCommentsForLesson(agentPubkey: string, lessonEventId: string): LessonComment[] {
|
|
445
|
+
const comments = this.agentComments.get(agentPubkey) || [];
|
|
446
|
+
return comments.filter((c) => c.lessonEventId === lessonEventId);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// =====================================================================================
|
|
450
|
+
// REPORT MANAGEMENT
|
|
451
|
+
// =====================================================================================
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Generate a compound key for report storage
|
|
455
|
+
*/
|
|
456
|
+
private static reportKey(authorPubkey: string, slug: string): string {
|
|
457
|
+
return `${authorPubkey}:${slug}`;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Add or update a report in the cache
|
|
462
|
+
* @param report The report info to add/update
|
|
463
|
+
*/
|
|
464
|
+
addReport(report: ReportInfo): void {
|
|
465
|
+
// Get author hex pubkey from report
|
|
466
|
+
const authorPubkey = this.extractPubkeyFromReport(report);
|
|
467
|
+
if (!authorPubkey) {
|
|
468
|
+
logger.warn("Cannot add report without author pubkey", { slug: report.slug });
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const key = ProjectContext.reportKey(authorPubkey, report.slug);
|
|
473
|
+
|
|
474
|
+
// Check if this is a deleted report
|
|
475
|
+
if (report.isDeleted) {
|
|
476
|
+
// Remove from cache instead of adding
|
|
477
|
+
this.reports.delete(key);
|
|
478
|
+
logger.debug("📰 Removed deleted report from cache", {
|
|
479
|
+
slug: report.slug,
|
|
480
|
+
author: authorPubkey.substring(0, 8),
|
|
481
|
+
});
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Add/update the report
|
|
486
|
+
this.reports.set(key, report);
|
|
487
|
+
|
|
488
|
+
// Enforce cache size limit (LRU-style: oldest entries first based on Map insertion order)
|
|
489
|
+
if (this.reports.size > ProjectContext.MAX_REPORTS_CACHE_SIZE) {
|
|
490
|
+
const oldestKey = this.reports.keys().next().value;
|
|
491
|
+
if (oldestKey) {
|
|
492
|
+
this.reports.delete(oldestKey);
|
|
493
|
+
logger.debug("📰 Evicted oldest report from cache due to size limit");
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
logger.debug("📰 Added/updated report in cache", {
|
|
498
|
+
slug: report.slug,
|
|
499
|
+
author: authorPubkey.substring(0, 8),
|
|
500
|
+
cacheSize: this.reports.size,
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Add a report directly from an NDKArticle event
|
|
506
|
+
* Converts the article to ReportInfo and adds to cache
|
|
507
|
+
*/
|
|
508
|
+
addReportFromArticle(article: NDKArticle): void {
|
|
509
|
+
const report = articleToReportInfo(article);
|
|
510
|
+
this.addReport(report);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Get a report by slug for a specific agent
|
|
515
|
+
*/
|
|
516
|
+
getReport(agentPubkey: string, slug: string): ReportInfo | undefined {
|
|
517
|
+
const key = ProjectContext.reportKey(agentPubkey, slug);
|
|
518
|
+
return this.reports.get(key);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Get a report by slug (searches all authors)
|
|
523
|
+
* Returns the first match found
|
|
524
|
+
*/
|
|
525
|
+
getReportBySlug(slug: string): ReportInfo | undefined {
|
|
526
|
+
for (const report of this.reports.values()) {
|
|
527
|
+
if (report.slug === slug) {
|
|
528
|
+
return report;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return undefined;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Get all reports from the cache
|
|
536
|
+
*/
|
|
537
|
+
getAllReports(): ReportInfo[] {
|
|
538
|
+
return Array.from(this.reports.values());
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Get reports for a specific agent by pubkey
|
|
543
|
+
*/
|
|
544
|
+
getReportsForAgent(agentPubkey: string): ReportInfo[] {
|
|
545
|
+
const reports: ReportInfo[] = [];
|
|
546
|
+
const prefix = `${agentPubkey}:`;
|
|
547
|
+
for (const [key, report] of this.reports) {
|
|
548
|
+
if (key.startsWith(prefix)) {
|
|
549
|
+
reports.push(report);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
return reports;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Get all memorized reports (reports tagged with memorize=true)
|
|
557
|
+
*/
|
|
558
|
+
getMemorizedReports(): ReportInfo[] {
|
|
559
|
+
return Array.from(this.reports.values()).filter((report) => report.isMemorized);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Get memorized reports for a specific agent
|
|
564
|
+
*/
|
|
565
|
+
getMemorizedReportsForAgent(agentPubkey: string): ReportInfo[] {
|
|
566
|
+
return this.getReportsForAgent(agentPubkey).filter((report) => report.isMemorized);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Get all team-memorized reports (reports tagged with memorize_team=true).
|
|
571
|
+
* These reports are injected into ALL agents' system prompts.
|
|
572
|
+
*/
|
|
573
|
+
getTeamMemorizedReports(): ReportInfo[] {
|
|
574
|
+
return Array.from(this.reports.values()).filter((report) => report.isMemorizedTeam);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Get reports by hashtag
|
|
579
|
+
*/
|
|
580
|
+
getReportsByHashtag(hashtag: string): ReportInfo[] {
|
|
581
|
+
return Array.from(this.reports.values()).filter(
|
|
582
|
+
(report) => report.hashtags?.includes(hashtag)
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Get report cache statistics
|
|
588
|
+
*/
|
|
589
|
+
getReportCacheStats(): { total: number; memorized: number; byAuthor: Record<string, number> } {
|
|
590
|
+
const byAuthor: Record<string, number> = {};
|
|
591
|
+
let memorized = 0;
|
|
592
|
+
|
|
593
|
+
for (const report of this.reports.values()) {
|
|
594
|
+
const author = this.extractPubkeyFromReport(report) || "unknown";
|
|
595
|
+
byAuthor[author.substring(0, 8)] = (byAuthor[author.substring(0, 8)] || 0) + 1;
|
|
596
|
+
if (report.isMemorized) memorized++;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return {
|
|
600
|
+
total: this.reports.size,
|
|
601
|
+
memorized,
|
|
602
|
+
byAuthor,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Clear all reports from cache
|
|
608
|
+
*/
|
|
609
|
+
clearReports(): void {
|
|
610
|
+
this.reports.clear();
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Extract pubkey from report. Author is stored as hex pubkey.
|
|
615
|
+
*/
|
|
616
|
+
private extractPubkeyFromReport(report: ReportInfo): string | undefined {
|
|
617
|
+
return report.author;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Safely update project data without creating a new instance.
|
|
622
|
+
* This ensures all parts of the system work with consistent state.
|
|
623
|
+
*/
|
|
624
|
+
async updateProjectData(newProject: NDKProject): Promise<void> {
|
|
625
|
+
this.project = newProject;
|
|
626
|
+
|
|
627
|
+
// Reload agents from project
|
|
628
|
+
await this.agentRegistry.loadFromProject(newProject);
|
|
629
|
+
|
|
630
|
+
const agents = this.agentRegistry.getAllAgentsMap();
|
|
631
|
+
const projectDTag = newProject.dTag || newProject.tagValue("d");
|
|
632
|
+
|
|
633
|
+
// Use consolidated PM resolution logic (same as constructor)
|
|
634
|
+
try {
|
|
635
|
+
const newPM = resolveProjectManager(newProject, agents, projectDTag);
|
|
636
|
+
if (newPM) {
|
|
637
|
+
this.projectManager = newPM;
|
|
638
|
+
}
|
|
639
|
+
} catch (error) {
|
|
640
|
+
logger.error("Failed to resolve project manager in updateProjectData", { error });
|
|
641
|
+
// Keep existing PM if resolution fails
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
logger.info("ProjectContext updated with new data", {
|
|
645
|
+
projectId: newProject.id,
|
|
646
|
+
projectTitle: newProject.tagValue("title"),
|
|
647
|
+
totalAgents: agents.size,
|
|
648
|
+
agentSlugs: Array.from(agents.keys()),
|
|
649
|
+
projectManager: this.projectManager?.slug,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
import { projectContextStore } from "./ProjectContextStore";
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Get the current project context from AsyncLocalStorage.
|
|
658
|
+
* This is the ONLY way to access project context - it must be set via
|
|
659
|
+
* projectContextStore.run(context, async () => {...})
|
|
660
|
+
*
|
|
661
|
+
* @throws Error if no context is available (not inside a .run() call)
|
|
662
|
+
*/
|
|
663
|
+
export function getProjectContext(): ProjectContext {
|
|
664
|
+
return projectContextStore.getContextOrThrow();
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Check if project context is initialized in current async context
|
|
669
|
+
*/
|
|
670
|
+
export function isProjectContextInitialized(): boolean {
|
|
671
|
+
return projectContextStore.hasContext();
|
|
672
|
+
}
|