@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,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nostr Publish As User Tool
|
|
3
|
+
*
|
|
4
|
+
* Enables agents to request the project owner to sign and publish
|
|
5
|
+
* arbitrary Nostr events via NIP-46 remote signing.
|
|
6
|
+
*
|
|
7
|
+
* The agent provides an unsigned event along with a human-readable
|
|
8
|
+
* explanation of WHY the signing is being requested. The explanation
|
|
9
|
+
* is transported as a root-level `tenex_explanation` property on the
|
|
10
|
+
* event object (NOT as a tag). Since NIP-01 event hashing only commits
|
|
11
|
+
* to [0, pubkey, created_at, kind, tags, content], root-level extras
|
|
12
|
+
* are never part of the hash or signature, making them safe transport
|
|
13
|
+
* metadata that the frontend/TUI can read and display to the user.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
17
|
+
import { getNDK } from "@/nostr/ndkClient";
|
|
18
|
+
import { Nip46SigningService } from "@/services/nip46";
|
|
19
|
+
import { getProjectContext } from "@/services/projects";
|
|
20
|
+
import { logger } from "@/utils/logger";
|
|
21
|
+
import { NDKEvent, NDKNip46Signer, NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
|
22
|
+
import { tool } from "ai";
|
|
23
|
+
import { verifyEvent } from "nostr-tools";
|
|
24
|
+
import { z } from "zod";
|
|
25
|
+
|
|
26
|
+
const NIP46_CONNECT_TIMEOUT_MS = 30_000;
|
|
27
|
+
const NIP46_SIGNING_TIMEOUT_MS = 120_000;
|
|
28
|
+
|
|
29
|
+
const nostrPublishAsUserSchema = z.object({
|
|
30
|
+
description: z
|
|
31
|
+
.string()
|
|
32
|
+
.describe("A short one-liner describing what this event is"),
|
|
33
|
+
explanation: z
|
|
34
|
+
.string()
|
|
35
|
+
.describe(
|
|
36
|
+
"An explanation for the human user telling them WHY we want them to sign this event. " +
|
|
37
|
+
"This context is shown to the user in the frontend before they approve signing."
|
|
38
|
+
),
|
|
39
|
+
event: z
|
|
40
|
+
.union([
|
|
41
|
+
z.string(),
|
|
42
|
+
z.object({
|
|
43
|
+
kind: z.number(),
|
|
44
|
+
content: z.string(),
|
|
45
|
+
tags: z.array(z.array(z.string())).optional(),
|
|
46
|
+
}).passthrough(),
|
|
47
|
+
])
|
|
48
|
+
.describe(
|
|
49
|
+
"An unsigned Nostr event as a JSON object or JSON string. " +
|
|
50
|
+
"Must include 'kind' (number) and 'content' (string). " +
|
|
51
|
+
"Tags must be an array of string arrays. " +
|
|
52
|
+
"The event will be re-signed by the project owner via NIP-46."
|
|
53
|
+
),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
type NostrPublishAsUserInput = z.infer<typeof nostrPublishAsUserSchema>;
|
|
57
|
+
|
|
58
|
+
/** Schema for validating a parsed event object */
|
|
59
|
+
const parsedEventSchema = z.object({
|
|
60
|
+
kind: z.number({ error: "Event must include a numeric 'kind' field" }),
|
|
61
|
+
content: z.string({ error: "Event must include a string 'content' field" }),
|
|
62
|
+
tags: z.array(z.array(z.string())).optional(),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Parse the event input into a raw event object.
|
|
67
|
+
* Accepts either a JSON string or an already-validated object.
|
|
68
|
+
*/
|
|
69
|
+
function parseEventInput(
|
|
70
|
+
input: string | { kind: number; content: string; tags?: string[][] }
|
|
71
|
+
): { kind: number; content: string; tags?: string[][] } {
|
|
72
|
+
let raw: unknown;
|
|
73
|
+
|
|
74
|
+
if (typeof input === "string") {
|
|
75
|
+
try {
|
|
76
|
+
raw = JSON.parse(input);
|
|
77
|
+
} catch (e) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Invalid JSON in event field: ${e instanceof Error ? e.message : String(e)}`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
// Already validated by Zod schema at the input boundary
|
|
84
|
+
raw = input;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const result = parsedEventSchema.safeParse(raw);
|
|
88
|
+
if (!result.success) {
|
|
89
|
+
const issues = result.error.issues.map((i) => i.message).join("; ");
|
|
90
|
+
throw new Error(`Invalid event: ${issues}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return result.data;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Create an NDKNip46Signer using the agent's private key as local signer
|
|
98
|
+
* and the owner's pubkey as the remote signer target.
|
|
99
|
+
*/
|
|
100
|
+
async function connectNip46Signer(
|
|
101
|
+
agentSigner: NDKPrivateKeySigner,
|
|
102
|
+
ownerPubkey: string,
|
|
103
|
+
): Promise<NDKNip46Signer> {
|
|
104
|
+
const ndk = getNDK();
|
|
105
|
+
const nip46Service = Nip46SigningService.getInstance();
|
|
106
|
+
const bunkerUri = nip46Service.getBunkerUri(ownerPubkey);
|
|
107
|
+
|
|
108
|
+
if (!bunkerUri?.startsWith("bunker://")) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Invalid bunker URI for owner ${ownerPubkey.substring(0, 12)}: ` +
|
|
111
|
+
`expected "bunker://" URI but got "${bunkerUri || "(empty)"}"`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
logger.info("[nostr_publish_as_user] Creating NIP-46 signer", {
|
|
116
|
+
ownerPubkey: ownerPubkey.substring(0, 12),
|
|
117
|
+
bunkerUri: bunkerUri.substring(0, 60),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const signer = NDKNip46Signer.bunker(ndk, bunkerUri, agentSigner);
|
|
121
|
+
|
|
122
|
+
signer.on("authUrl", (url: string) => {
|
|
123
|
+
logger.info("[nostr_publish_as_user] NIP-46 auth URL required", {
|
|
124
|
+
ownerPubkey: ownerPubkey.substring(0, 12),
|
|
125
|
+
url,
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
let connectTimer: ReturnType<typeof setTimeout> | undefined;
|
|
130
|
+
try {
|
|
131
|
+
await Promise.race([
|
|
132
|
+
signer.blockUntilReady(),
|
|
133
|
+
new Promise<never>((_, reject) => {
|
|
134
|
+
connectTimer = setTimeout(
|
|
135
|
+
() => reject(new Error(
|
|
136
|
+
`NIP-46 connect timed out after ${NIP46_CONNECT_TIMEOUT_MS / 1000}s`
|
|
137
|
+
)),
|
|
138
|
+
NIP46_CONNECT_TIMEOUT_MS,
|
|
139
|
+
);
|
|
140
|
+
}),
|
|
141
|
+
]);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
try { signer.stop(); } catch { /* best-effort cleanup */ }
|
|
144
|
+
throw error;
|
|
145
|
+
} finally {
|
|
146
|
+
clearTimeout(connectTimer);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return signer;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Execute the nostr_publish_as_user tool.
|
|
154
|
+
*
|
|
155
|
+
* Flow:
|
|
156
|
+
* 1. Parse and validate the provided event
|
|
157
|
+
* 2. Set `tenex_explanation` as root-level property (transport for frontend context)
|
|
158
|
+
* 3. Send NIP-46 signing request to the project owner
|
|
159
|
+
* 4. Strip `tenex_explanation` property after signing (harmless — never part of hash)
|
|
160
|
+
* 5. Verify the signature is valid
|
|
161
|
+
* 6. Publish the signed event to relays
|
|
162
|
+
*/
|
|
163
|
+
async function executeNostrPublishAsUser(
|
|
164
|
+
input: NostrPublishAsUserInput,
|
|
165
|
+
context: ToolExecutionContext,
|
|
166
|
+
): Promise<string> {
|
|
167
|
+
const { description, explanation, event: eventInput } = input;
|
|
168
|
+
|
|
169
|
+
// Resolve owner pubkey
|
|
170
|
+
const projectCtx = getProjectContext();
|
|
171
|
+
const ownerPubkey = projectCtx?.project?.pubkey;
|
|
172
|
+
|
|
173
|
+
if (!ownerPubkey) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
"Cannot publish as user: no project owner pubkey found. " +
|
|
176
|
+
"Ensure the project has an owner configured."
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Verify NIP-46 is enabled
|
|
181
|
+
const nip46Service = Nip46SigningService.getInstance();
|
|
182
|
+
if (!nip46Service.isEnabled()) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
"Cannot publish as user: NIP-46 remote signing is not enabled. " +
|
|
185
|
+
"Enable it by setting nip46.enabled=true in your TENEX config."
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Verify agent signer type
|
|
190
|
+
const agentSigner: unknown = context.agent.signer;
|
|
191
|
+
if (!(agentSigner instanceof NDKPrivateKeySigner)) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
`Expected agent signer to be NDKPrivateKeySigner for NIP-46 signing, ` +
|
|
194
|
+
`got ${(agentSigner as { constructor?: { name?: string } })?.constructor?.name ?? "undefined"}.`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Parse the event input
|
|
199
|
+
const parsedEvent = parseEventInput(eventInput);
|
|
200
|
+
|
|
201
|
+
// Build the NDKEvent
|
|
202
|
+
const ndk = getNDK();
|
|
203
|
+
const ndkEvent = new NDKEvent(ndk);
|
|
204
|
+
ndkEvent.kind = parsedEvent.kind;
|
|
205
|
+
ndkEvent.content = parsedEvent.content;
|
|
206
|
+
ndkEvent.tags = parsedEvent.tags ? [...parsedEvent.tags] : [];
|
|
207
|
+
|
|
208
|
+
// Add tenex_explanation as a root-level property for frontend context.
|
|
209
|
+
// Root-level extras are NOT part of the NIP-01 event hash
|
|
210
|
+
// ([0, pubkey, created_at, kind, tags, content]), so the signature
|
|
211
|
+
// is computed over the clean event regardless.
|
|
212
|
+
(ndkEvent as any).tenex_explanation = explanation;
|
|
213
|
+
|
|
214
|
+
// Set pubkey to the owner's
|
|
215
|
+
ndkEvent.pubkey = ownerPubkey;
|
|
216
|
+
|
|
217
|
+
logger.info("[nostr_publish_as_user] Requesting user signature", {
|
|
218
|
+
description,
|
|
219
|
+
kind: ndkEvent.kind,
|
|
220
|
+
ownerPubkey: ownerPubkey.substring(0, 12),
|
|
221
|
+
agentPubkey: context.agent.pubkey.substring(0, 12),
|
|
222
|
+
tagCount: ndkEvent.tags.length,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Connect NIP-46 signer
|
|
226
|
+
const nip46Signer = await connectNip46Signer(
|
|
227
|
+
context.agent.signer,
|
|
228
|
+
ownerPubkey,
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Sign with NIP-46 (the signer sends the event to the user's bunker for approval).
|
|
232
|
+
//
|
|
233
|
+
// The `tenex_explanation` root-level property is present on the event object
|
|
234
|
+
// during signing so the TUI/bunker can read and display it to the user.
|
|
235
|
+
// Since it's not in `tags`, it's never part of the event hash — the signature
|
|
236
|
+
// is always computed over the clean event.
|
|
237
|
+
let signingTimer: ReturnType<typeof setTimeout> | undefined;
|
|
238
|
+
try {
|
|
239
|
+
await Promise.race([
|
|
240
|
+
ndkEvent.sign(nip46Signer),
|
|
241
|
+
new Promise<never>((_, reject) => {
|
|
242
|
+
signingTimer = setTimeout(
|
|
243
|
+
() => reject(new Error(
|
|
244
|
+
`NIP-46 signing timed out after ${NIP46_SIGNING_TIMEOUT_MS / 1000}s`
|
|
245
|
+
)),
|
|
246
|
+
NIP46_SIGNING_TIMEOUT_MS,
|
|
247
|
+
);
|
|
248
|
+
}),
|
|
249
|
+
]);
|
|
250
|
+
} catch (error) {
|
|
251
|
+
try { nip46Signer.stop(); } catch { /* best-effort cleanup */ }
|
|
252
|
+
throw error;
|
|
253
|
+
} finally {
|
|
254
|
+
clearTimeout(signingTimer);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Strip the root-level tenex_explanation property now that signing is done.
|
|
258
|
+
// This is purely cosmetic cleanup — the property was never part of the
|
|
259
|
+
// event hash or signature.
|
|
260
|
+
delete (ndkEvent as any).tenex_explanation;
|
|
261
|
+
|
|
262
|
+
// Validate timestamp is in seconds, not milliseconds
|
|
263
|
+
if (ndkEvent.created_at && ndkEvent.created_at > 1_000_000_000_000) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
"Event created_at appears to be in milliseconds instead of seconds. " +
|
|
266
|
+
"Nostr timestamps must be Unix timestamps in seconds."
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Verify the signature is valid
|
|
271
|
+
const rawEvent = ndkEvent.rawEvent();
|
|
272
|
+
if (!verifyEvent(rawEvent)) {
|
|
273
|
+
try { nip46Signer.stop(); } catch { /* best-effort cleanup */ }
|
|
274
|
+
throw new Error(
|
|
275
|
+
"Signature verification failed after NIP-46 signing. " +
|
|
276
|
+
"The event signature does not match the clean event content."
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Validate event structure per NDK guardrails
|
|
281
|
+
if (!ndkEvent.validate()) {
|
|
282
|
+
try { nip46Signer.stop(); } catch { /* best-effort cleanup */ }
|
|
283
|
+
throw new Error(
|
|
284
|
+
"NDK validation failed: event structure is invalid. " +
|
|
285
|
+
"Ensure kind, content, pubkey, created_at, and tags are well-formed."
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Publish the signed event
|
|
290
|
+
try {
|
|
291
|
+
await ndkEvent.publish();
|
|
292
|
+
} finally {
|
|
293
|
+
try { nip46Signer.stop(); } catch { /* best-effort cleanup */ }
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
logger.info("[nostr_publish_as_user] Event published successfully", {
|
|
297
|
+
eventId: ndkEvent.id,
|
|
298
|
+
kind: ndkEvent.kind,
|
|
299
|
+
ownerPubkey: ownerPubkey.substring(0, 12),
|
|
300
|
+
description,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return JSON.stringify({
|
|
304
|
+
success: true,
|
|
305
|
+
eventId: ndkEvent.id,
|
|
306
|
+
kind: ndkEvent.kind,
|
|
307
|
+
description,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Create the nostr_publish_as_user AI SDK tool
|
|
313
|
+
*/
|
|
314
|
+
export function createNostrPublishAsUserTool(context: ToolExecutionContext): AISdkTool {
|
|
315
|
+
const aiTool = tool({
|
|
316
|
+
description:
|
|
317
|
+
"Request the project owner/user to sign and publish a Nostr event via NIP-46 remote signing. " +
|
|
318
|
+
"Provide the unsigned event, a short description, and an explanation of WHY the user should sign it. " +
|
|
319
|
+
"The explanation is shown to the user in the frontend before they approve. " +
|
|
320
|
+
"Once approved, the event is signed by the user and published to relays.",
|
|
321
|
+
|
|
322
|
+
inputSchema: nostrPublishAsUserSchema,
|
|
323
|
+
|
|
324
|
+
execute: async (input: NostrPublishAsUserInput) => {
|
|
325
|
+
try {
|
|
326
|
+
return await executeNostrPublishAsUser(input, context);
|
|
327
|
+
} catch (error) {
|
|
328
|
+
logger.error("[nostr_publish_as_user] Failed", {
|
|
329
|
+
error: error instanceof Error ? error.message : String(error),
|
|
330
|
+
});
|
|
331
|
+
throw new Error(
|
|
332
|
+
`Failed to publish as user: ${error instanceof Error ? error.message : String(error)}`,
|
|
333
|
+
{ cause: error }
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
340
|
+
value: ({ description, event }: NostrPublishAsUserInput) => {
|
|
341
|
+
try {
|
|
342
|
+
const parsed = typeof event === "string" ? JSON.parse(event) : event;
|
|
343
|
+
return `Requesting user to sign kind:${parsed.kind} event — ${description}`;
|
|
344
|
+
} catch {
|
|
345
|
+
return `Requesting user to sign event — ${description}`;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
enumerable: false,
|
|
349
|
+
configurable: true,
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
return aiTool as AISdkTool;
|
|
353
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
2
|
+
import { getDaemon } from "@/daemon";
|
|
3
|
+
import { agentStorage } from "@/agents/AgentStorage";
|
|
4
|
+
import { logger } from "@/utils/logger";
|
|
5
|
+
import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
|
6
|
+
import { PREFIX_LENGTH } from "@/utils/nostr-entity-parser";
|
|
7
|
+
import { tool } from "ai";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
const projectListSchema = z.object({});
|
|
11
|
+
|
|
12
|
+
type ProjectAgent = {
|
|
13
|
+
slug: string;
|
|
14
|
+
pubkey: string;
|
|
15
|
+
role: string;
|
|
16
|
+
isPM?: true;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type ProjectInfo = {
|
|
20
|
+
id: string; // The project's dTag (unique identifier)
|
|
21
|
+
title?: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
repository?: string;
|
|
24
|
+
isRunning: boolean;
|
|
25
|
+
agents: ProjectAgent[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type ProjectListOutput = {
|
|
29
|
+
projects: ProjectInfo[];
|
|
30
|
+
summary: {
|
|
31
|
+
totalProjects: number;
|
|
32
|
+
runningProjects: number;
|
|
33
|
+
totalAgents: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
async function executeProjectList(context: ToolExecutionContext): Promise<ProjectListOutput> {
|
|
38
|
+
const daemon = getDaemon();
|
|
39
|
+
const knownProjects = daemon.getKnownProjects();
|
|
40
|
+
const activeRuntimes = daemon.getActiveRuntimes();
|
|
41
|
+
|
|
42
|
+
logger.info("📦 Listing all known projects", {
|
|
43
|
+
knownCount: knownProjects.size,
|
|
44
|
+
runningCount: activeRuntimes.size,
|
|
45
|
+
agent: context.agent.name,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const projects: ProjectInfo[] = [];
|
|
49
|
+
let totalAgents = 0;
|
|
50
|
+
|
|
51
|
+
for (const [projectId, project] of knownProjects) {
|
|
52
|
+
// projectId format is "31933:pubkey:id"
|
|
53
|
+
const id = projectId.split(":")[2];
|
|
54
|
+
if (!id) {
|
|
55
|
+
logger.warn("⚠️ Project missing id, skipping", { projectId });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const title = project.tagValue("title") || project.tagValue("name");
|
|
60
|
+
const description = project.tagValue("description");
|
|
61
|
+
const repository = project.tagValue("repository");
|
|
62
|
+
// Check if this project is running
|
|
63
|
+
const runtime = activeRuntimes.get(projectId);
|
|
64
|
+
const isRunning = !!runtime;
|
|
65
|
+
|
|
66
|
+
// Get agents - from running context if available, otherwise from storage
|
|
67
|
+
const agents: ProjectAgent[] = [];
|
|
68
|
+
|
|
69
|
+
if (runtime) {
|
|
70
|
+
// Running project - get agents from runtime context
|
|
71
|
+
const runtimeContext = runtime.getContext();
|
|
72
|
+
const pmPubkey = runtimeContext?.projectManager?.pubkey;
|
|
73
|
+
const agentMap = runtimeContext?.agentRegistry.getAllAgentsMap() || new Map();
|
|
74
|
+
for (const agent of agentMap.values()) {
|
|
75
|
+
const isPM = agent.pubkey === pmPubkey;
|
|
76
|
+
agents.push({
|
|
77
|
+
slug: agent.slug,
|
|
78
|
+
pubkey: agent.pubkey.substring(0, PREFIX_LENGTH),
|
|
79
|
+
role: agent.role,
|
|
80
|
+
...(isPM && { isPM: true }),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
// Not running - get agents from storage
|
|
85
|
+
const storedAgents = await agentStorage.getProjectAgents(id);
|
|
86
|
+
for (const storedAgent of storedAgents) {
|
|
87
|
+
const signer = new NDKPrivateKeySigner(storedAgent.nsec);
|
|
88
|
+
const pubkey = (await signer.user()).pubkey;
|
|
89
|
+
agents.push({
|
|
90
|
+
slug: storedAgent.slug,
|
|
91
|
+
pubkey: pubkey.substring(0, PREFIX_LENGTH),
|
|
92
|
+
role: storedAgent.role,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
totalAgents += agents.length;
|
|
98
|
+
|
|
99
|
+
projects.push({
|
|
100
|
+
id,
|
|
101
|
+
title,
|
|
102
|
+
description,
|
|
103
|
+
repository,
|
|
104
|
+
isRunning,
|
|
105
|
+
agents,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const runningCount = projects.filter((p) => p.isRunning).length;
|
|
110
|
+
|
|
111
|
+
logger.info("✅ Project list complete", {
|
|
112
|
+
totalProjects: projects.length,
|
|
113
|
+
runningProjects: runningCount,
|
|
114
|
+
totalAgents,
|
|
115
|
+
agent: context.agent.name,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
projects,
|
|
120
|
+
summary: {
|
|
121
|
+
totalProjects: projects.length,
|
|
122
|
+
runningProjects: runningCount,
|
|
123
|
+
totalAgents,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function createProjectListTool(context: ToolExecutionContext): AISdkTool {
|
|
129
|
+
const coreTool = tool({
|
|
130
|
+
description:
|
|
131
|
+
"List ALL known projects with their agents and running status. " +
|
|
132
|
+
"For each project shows: id, title, description, repository, isRunning flag, and all agents. " +
|
|
133
|
+
"For each agent shows: slug, pubkey (shortened), role, and isPM (only if true). " +
|
|
134
|
+
"Includes both running and non-running projects discovered by the daemon.",
|
|
135
|
+
inputSchema: projectListSchema,
|
|
136
|
+
execute: async () => {
|
|
137
|
+
return await executeProjectList(context);
|
|
138
|
+
},
|
|
139
|
+
}) as AISdkTool;
|
|
140
|
+
|
|
141
|
+
coreTool.getHumanReadableContent = () => {
|
|
142
|
+
return "Listing all known projects and their agents";
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
return coreTool;
|
|
146
|
+
}
|