@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,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool supervision wrapper for pre-tool execution checks.
|
|
3
|
+
*
|
|
4
|
+
* Intercepts tool execution to run heuristics before the tool executes.
|
|
5
|
+
* This allows the supervision system to block or modify tool calls based
|
|
6
|
+
* on configured policies (e.g., preventing certain actions without approval).
|
|
7
|
+
*/
|
|
8
|
+
import {
|
|
9
|
+
supervisorOrchestrator,
|
|
10
|
+
type PreToolContext,
|
|
11
|
+
} from "@/agents/supervision";
|
|
12
|
+
import type { ToolExecutionOptions } from "@ai-sdk/provider-utils";
|
|
13
|
+
import type { Tool as CoreTool } from "ai";
|
|
14
|
+
import { AgentEventDecoder } from "@/nostr/AgentEventDecoder";
|
|
15
|
+
import { buildSystemPromptMessages } from "@/prompts/utils/systemPromptBuilder";
|
|
16
|
+
import { NudgeService } from "@/services/nudge";
|
|
17
|
+
import { getProjectContext } from "@/services/projects";
|
|
18
|
+
import { RALRegistry } from "@/services/ral";
|
|
19
|
+
import { getToolsObject } from "@/tools/registry";
|
|
20
|
+
import type { FullRuntimeContext } from "./types";
|
|
21
|
+
import { formatAnyError } from "@/lib/error-formatter";
|
|
22
|
+
import { logger } from "@/utils/logger";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Wrap tools with pre-tool supervision checks.
|
|
26
|
+
*
|
|
27
|
+
* This function intercepts each tool's execute method to run supervision
|
|
28
|
+
* heuristics before the tool actually executes. If a violation is detected,
|
|
29
|
+
* the tool execution is blocked and a message is returned to the agent.
|
|
30
|
+
*
|
|
31
|
+
* @param toolsObject - The original tools object from the tool registry
|
|
32
|
+
* @param context - The full runtime context for the execution
|
|
33
|
+
* @returns A new tools object with wrapped execute methods
|
|
34
|
+
*/
|
|
35
|
+
export function wrapToolsWithSupervision(
|
|
36
|
+
toolsObject: Record<string, CoreTool<unknown, unknown>>,
|
|
37
|
+
context: FullRuntimeContext
|
|
38
|
+
): Record<string, CoreTool<unknown, unknown>> {
|
|
39
|
+
const wrappedTools: Record<string, CoreTool<unknown, unknown>> = {};
|
|
40
|
+
const ralRegistry = RALRegistry.getInstance();
|
|
41
|
+
|
|
42
|
+
for (const [toolName, tool] of Object.entries(toolsObject)) {
|
|
43
|
+
// Skip tools without execute function
|
|
44
|
+
if (!tool.execute) {
|
|
45
|
+
wrappedTools[toolName] = tool;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Preserve the original tool's properties
|
|
50
|
+
const originalExecute = tool.execute.bind(tool);
|
|
51
|
+
|
|
52
|
+
// Create wrapped tool
|
|
53
|
+
wrappedTools[toolName] = {
|
|
54
|
+
...tool,
|
|
55
|
+
execute: async (input: unknown, options: ToolExecutionOptions) => {
|
|
56
|
+
try {
|
|
57
|
+
// Build PreToolContext for this tool
|
|
58
|
+
const conversation = context.getConversation();
|
|
59
|
+
const conversationStore = context.conversationStore;
|
|
60
|
+
|
|
61
|
+
// Get system prompt and conversation history
|
|
62
|
+
const projectContext = getProjectContext();
|
|
63
|
+
|
|
64
|
+
// Fetch nudge content if triggering event has nudge tags
|
|
65
|
+
const preToolNudgeEventIds = AgentEventDecoder.extractNudgeEventIds(context.triggeringEvent);
|
|
66
|
+
const preToolNudgeContent = preToolNudgeEventIds.length > 0
|
|
67
|
+
? await NudgeService.getInstance().fetchNudges(preToolNudgeEventIds)
|
|
68
|
+
: "";
|
|
69
|
+
|
|
70
|
+
const systemPromptMessages = await buildSystemPromptMessages({
|
|
71
|
+
agent: context.agent,
|
|
72
|
+
project: projectContext.project,
|
|
73
|
+
conversation,
|
|
74
|
+
projectBasePath: context.projectBasePath,
|
|
75
|
+
workingDirectory: context.workingDirectory,
|
|
76
|
+
currentBranch: context.currentBranch,
|
|
77
|
+
availableAgents: Array.from(projectContext.agents.values()),
|
|
78
|
+
mcpManager: projectContext.mcpManager,
|
|
79
|
+
agentLessons: projectContext.agentLessons,
|
|
80
|
+
nudgeContent: preToolNudgeContent,
|
|
81
|
+
});
|
|
82
|
+
const systemPrompt = systemPromptMessages.map(m => m.message.content).join("\n\n");
|
|
83
|
+
|
|
84
|
+
// Build conversation history from ConversationStore
|
|
85
|
+
const conversationMessages = await conversationStore.buildMessagesForRal(context.agent.pubkey, context.ralNumber);
|
|
86
|
+
|
|
87
|
+
// Get available tools
|
|
88
|
+
const toolNames = context.agent.tools || [];
|
|
89
|
+
const toolsForContext = toolNames.length > 0 ? getToolsObject(toolNames, context) : {};
|
|
90
|
+
|
|
91
|
+
// Build PreToolContext
|
|
92
|
+
const preToolContext: PreToolContext = {
|
|
93
|
+
agentSlug: context.agent.slug,
|
|
94
|
+
agentPubkey: context.agent.pubkey,
|
|
95
|
+
toolName,
|
|
96
|
+
toolArgs: input,
|
|
97
|
+
systemPrompt,
|
|
98
|
+
conversationHistory: conversationMessages,
|
|
99
|
+
availableTools: toolsForContext,
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Run pre-tool supervision check
|
|
103
|
+
logger.debug(`[ToolSupervisionWrapper] Running pre-tool supervision for "${toolName}"`, {
|
|
104
|
+
agent: context.agent.slug,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Build executionId for heuristic enforcement tracking
|
|
108
|
+
const preToolExecutionId = `${context.agent.pubkey}:${context.conversationId}:${context.ralNumber}`;
|
|
109
|
+
const supervisionResult = await supervisorOrchestrator.checkPreTool(preToolContext, preToolExecutionId);
|
|
110
|
+
|
|
111
|
+
// If supervision detected a violation, block the tool
|
|
112
|
+
if (supervisionResult.hasViolation && supervisionResult.correctionAction) {
|
|
113
|
+
logger.warn(
|
|
114
|
+
`[ToolSupervisionWrapper] Pre-tool supervision blocked "${toolName}" execution`,
|
|
115
|
+
{
|
|
116
|
+
agent: context.agent.slug,
|
|
117
|
+
heuristic: supervisionResult.heuristicId,
|
|
118
|
+
actionType: supervisionResult.correctionAction.type,
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// Mark this heuristic as enforced so it won't fire again in this RAL
|
|
123
|
+
if (supervisionResult.heuristicId) {
|
|
124
|
+
supervisorOrchestrator.markHeuristicEnforced(preToolExecutionId, supervisionResult.heuristicId);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Queue correction message if available (for both inject-message and block-tool)
|
|
128
|
+
if (
|
|
129
|
+
supervisionResult.correctionAction.message &&
|
|
130
|
+
supervisionResult.correctionAction.reEngage
|
|
131
|
+
) {
|
|
132
|
+
ralRegistry.queueUserMessage(
|
|
133
|
+
context.agent.pubkey,
|
|
134
|
+
context.conversationId,
|
|
135
|
+
context.ralNumber,
|
|
136
|
+
supervisionResult.correctionAction.message
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Return a blocked execution message
|
|
141
|
+
return `Tool execution blocked: ${supervisionResult.correctionAction.message || "This tool cannot be executed at this time."}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// No violation - execute the original tool
|
|
145
|
+
logger.debug(`[ToolSupervisionWrapper] Pre-tool supervision passed for "${toolName}"`, {
|
|
146
|
+
agent: context.agent.slug,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return await originalExecute(input, options);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
logger.error("[ToolSupervisionWrapper] Error during pre-tool supervision check", {
|
|
152
|
+
tool: toolName,
|
|
153
|
+
error: formatAnyError(error),
|
|
154
|
+
});
|
|
155
|
+
// On supervision error, allow tool to execute (fail-safe)
|
|
156
|
+
return await originalExecute(input, options);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Preserve non-enumerable properties like getHumanReadableContent
|
|
162
|
+
const toolWithCustomProps = tool as CoreTool<unknown, unknown> & {
|
|
163
|
+
getHumanReadableContent?: (args: unknown) => string;
|
|
164
|
+
};
|
|
165
|
+
if (toolWithCustomProps.getHumanReadableContent) {
|
|
166
|
+
Object.defineProperty(wrappedTools[toolName], "getHumanReadableContent", {
|
|
167
|
+
value: toolWithCustomProps.getHumanReadableContent,
|
|
168
|
+
enumerable: false,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return wrappedTools;
|
|
174
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration constants for agent execution
|
|
3
|
+
*/
|
|
4
|
+
export const ExecutionConfig = {
|
|
5
|
+
/** Delay in milliseconds after publishing typing indicator */
|
|
6
|
+
TOOL_INDICATOR_DELAY_MS: 100,
|
|
7
|
+
|
|
8
|
+
/** Default duration for tool execution when not tracked */
|
|
9
|
+
DEFAULT_TOOL_DURATION_MS: 1000,
|
|
10
|
+
|
|
11
|
+
/** Default timeout for shell commands in milliseconds (30 seconds) */
|
|
12
|
+
DEFAULT_COMMAND_TIMEOUT_MS: 30000,
|
|
13
|
+
|
|
14
|
+
/** Threshold for considering a phase transition as recent in milliseconds (30 seconds) */
|
|
15
|
+
RECENT_TRANSITION_THRESHOLD_MS: 30000,
|
|
16
|
+
} as const;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Tool as CoreTool, ModelMessage } from "ai";
|
|
2
|
+
import type { AgentInstance } from "@/agents/types";
|
|
3
|
+
import type { MessageCompiler } from "@/agents/execution/MessageCompiler";
|
|
4
|
+
import type { ConversationStore } from "@/conversations/ConversationStore";
|
|
5
|
+
import type { CompleteEvent } from "@/llm/types";
|
|
6
|
+
import type { AgentPublisher } from "@/nostr/AgentPublisher";
|
|
7
|
+
import type { MCPManager } from "@/services/mcp/MCPManager";
|
|
8
|
+
import type { ToolRegistryContext } from "@/tools/types";
|
|
9
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Execution context for agent runs.
|
|
13
|
+
*
|
|
14
|
+
* This is the context created by createExecutionContext and enriched during execution.
|
|
15
|
+
* Runtime dependencies (agentPublisher, ralNumber, conversationStore) may not be
|
|
16
|
+
* available at creation time - they are added by prepareExecution().
|
|
17
|
+
*
|
|
18
|
+
* When passing context to tools via getToolsObject(), ensure all required fields
|
|
19
|
+
* are present (use ToolRegistryContext type to enforce this).
|
|
20
|
+
*/
|
|
21
|
+
export interface ExecutionContext {
|
|
22
|
+
agent: AgentInstance;
|
|
23
|
+
conversationId: string;
|
|
24
|
+
projectBasePath: string;
|
|
25
|
+
workingDirectory: string;
|
|
26
|
+
currentBranch: string;
|
|
27
|
+
triggeringEvent: NDKEvent;
|
|
28
|
+
getConversation: () => ConversationStore | undefined;
|
|
29
|
+
|
|
30
|
+
// Runtime dependencies - added by prepareExecution()
|
|
31
|
+
agentPublisher?: AgentPublisher;
|
|
32
|
+
ralNumber?: number;
|
|
33
|
+
conversationStore?: ConversationStore;
|
|
34
|
+
|
|
35
|
+
// Execution flags
|
|
36
|
+
isDelegationCompletion?: boolean;
|
|
37
|
+
hasPendingDelegations?: boolean;
|
|
38
|
+
debug?: boolean;
|
|
39
|
+
mcpManager?: MCPManager;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Result of executeStreaming - discriminated union for clear error handling.
|
|
45
|
+
* - 'complete': Stream finished successfully with a completion event
|
|
46
|
+
* - 'error-handled': Stream error occurred and was already published to user
|
|
47
|
+
*/
|
|
48
|
+
export type StreamExecutionResult =
|
|
49
|
+
| {
|
|
50
|
+
kind: "complete";
|
|
51
|
+
event: CompleteEvent;
|
|
52
|
+
aborted?: boolean;
|
|
53
|
+
/** The reason the execution was aborted (if aborted=true) */
|
|
54
|
+
abortReason?: string;
|
|
55
|
+
messageCompiler: MessageCompiler;
|
|
56
|
+
/** Accumulated LLM runtime in milliseconds (captured before RAL cleanup) */
|
|
57
|
+
accumulatedRuntime: number;
|
|
58
|
+
}
|
|
59
|
+
| { kind: "error-handled" };
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Mutable context for RAL execution state during streaming.
|
|
63
|
+
*
|
|
64
|
+
* Makes explicit the state that coordinates between prepareStep and onStopCheck
|
|
65
|
+
* callbacks. Previously this was implicit closure variables.
|
|
66
|
+
*/
|
|
67
|
+
export interface RALExecutionContext {
|
|
68
|
+
/**
|
|
69
|
+
* Messages accumulated from prepareStep callbacks.
|
|
70
|
+
* Updated in prepareStep (before each LLM step), read in onStopCheck.
|
|
71
|
+
* Contains messages up to but not including the current step.
|
|
72
|
+
*/
|
|
73
|
+
accumulatedMessages: ModelMessage[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Full runtime context for executor methods.
|
|
78
|
+
* Extends ToolRegistryContext with:
|
|
79
|
+
* - agent: AgentInstance (full agent type, not just ToolAgentInfo)
|
|
80
|
+
* - Execution-specific flags from ExecutionContext
|
|
81
|
+
*/
|
|
82
|
+
export type FullRuntimeContext = Omit<ToolRegistryContext, "agent"> & {
|
|
83
|
+
agent: AgentInstance;
|
|
84
|
+
isDelegationCompletion?: boolean;
|
|
85
|
+
hasPendingDelegations?: boolean;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Request object for LLM completion preparation.
|
|
90
|
+
* Created by prepareLLMRequest() for external callers that need to prepare
|
|
91
|
+
* an LLM request without executing it (e.g., schema extraction).
|
|
92
|
+
*/
|
|
93
|
+
export interface LLMCompletionRequest {
|
|
94
|
+
messages: ModelMessage[];
|
|
95
|
+
tools?: Record<string, CoreTool>;
|
|
96
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Extract the text content from the last user message in the conversation.
|
|
5
|
+
* Handles both simple string content and complex content arrays (with text parts).
|
|
6
|
+
*/
|
|
7
|
+
export function extractLastUserMessage(messages: ModelMessage[]): string | undefined {
|
|
8
|
+
// Find the last user message
|
|
9
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
10
|
+
const msg = messages[i];
|
|
11
|
+
if (msg.role === "user") {
|
|
12
|
+
// Handle simple string content
|
|
13
|
+
if (typeof msg.content === "string") {
|
|
14
|
+
return msg.content;
|
|
15
|
+
}
|
|
16
|
+
// Handle complex content arrays (e.g., [{ type: "text", text: "hello" }])
|
|
17
|
+
if (Array.isArray(msg.content)) {
|
|
18
|
+
const textParts = msg.content
|
|
19
|
+
.filter((part): part is { type: "text"; text: string } => part.type === "text")
|
|
20
|
+
.map(part => part.text);
|
|
21
|
+
return textParts.join("\n");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import type NDK from "@nostr-dev-kit/ndk";
|
|
4
|
+
import type { NDKEvent } from "@nostr-dev-kit/ndk";
|
|
5
|
+
import { getAgentHomeDirectory } from "@/lib/agent-home";
|
|
6
|
+
import { ensureDirectory } from "@/lib/fs";
|
|
7
|
+
import { logger } from "@/utils/logger";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Information about a script file from a NIP-94 (kind 1063) event
|
|
11
|
+
*/
|
|
12
|
+
export interface ScriptFileInfo {
|
|
13
|
+
eventId: string;
|
|
14
|
+
url: string;
|
|
15
|
+
relativePath: string;
|
|
16
|
+
mimeType?: string;
|
|
17
|
+
sha256?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Result of downloading and installing a script
|
|
22
|
+
*/
|
|
23
|
+
export interface ScriptInstallResult {
|
|
24
|
+
eventId: string;
|
|
25
|
+
relativePath: string;
|
|
26
|
+
absolutePath: string;
|
|
27
|
+
success: boolean;
|
|
28
|
+
error?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const DOWNLOAD_TIMEOUT_MS = 30_000;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract script file information from a kind 1063 (NIP-94 file metadata) event.
|
|
35
|
+
*
|
|
36
|
+
* Expected tags:
|
|
37
|
+
* - ["url", "https://blossom.server/sha256"] - Required: Blossom download URL
|
|
38
|
+
* - ["name", "scripts/research.py"] - Required: Relative filepath from agent's home
|
|
39
|
+
* - ["m", "text/x-python"] - Optional: MIME type
|
|
40
|
+
* - ["x", "sha256hash"] - Optional: SHA-256 hash for verification
|
|
41
|
+
*
|
|
42
|
+
* @param event - The kind 1063 event to extract info from
|
|
43
|
+
* @returns Script file info or null if required tags are missing
|
|
44
|
+
*/
|
|
45
|
+
export function extractScriptFileInfo(event: NDKEvent): ScriptFileInfo | null {
|
|
46
|
+
if (event.kind !== 1063) {
|
|
47
|
+
logger.warn(`Expected kind 1063 event, got kind ${event.kind}`);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const url = event.tagValue("url");
|
|
52
|
+
const relativePath = event.tagValue("name");
|
|
53
|
+
|
|
54
|
+
if (!url || !relativePath) {
|
|
55
|
+
logger.warn(`Kind 1063 event ${event.id} missing required tags`, {
|
|
56
|
+
hasUrl: !!url,
|
|
57
|
+
hasName: !!relativePath,
|
|
58
|
+
});
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
eventId: event.id,
|
|
64
|
+
url,
|
|
65
|
+
relativePath,
|
|
66
|
+
mimeType: event.tagValue("m") || undefined,
|
|
67
|
+
sha256: event.tagValue("x") || undefined,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Download a file from a Blossom URL
|
|
73
|
+
*
|
|
74
|
+
* @param url - The Blossom URL to download from
|
|
75
|
+
* @returns The downloaded file content as a Buffer
|
|
76
|
+
*/
|
|
77
|
+
async function downloadFile(url: string): Promise<Buffer> {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
const timeout = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch(url, {
|
|
83
|
+
headers: {
|
|
84
|
+
"User-Agent": "TENEX/1.0 (Script Installer)",
|
|
85
|
+
},
|
|
86
|
+
signal: controller.signal,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
if (!response.ok) {
|
|
90
|
+
throw new Error(`Failed to download: ${response.status} ${response.statusText}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
94
|
+
return Buffer.from(arrayBuffer);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
97
|
+
throw new Error(`Download timed out after ${DOWNLOAD_TIMEOUT_MS}ms`);
|
|
98
|
+
}
|
|
99
|
+
throw error;
|
|
100
|
+
} finally {
|
|
101
|
+
clearTimeout(timeout);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Install a single script file to the agent's home directory.
|
|
107
|
+
*
|
|
108
|
+
* @param scriptInfo - Information about the script to install
|
|
109
|
+
* @param agentPubkey - The agent's public key (determines home directory)
|
|
110
|
+
* @returns Result of the installation
|
|
111
|
+
*/
|
|
112
|
+
export async function installScriptFile(
|
|
113
|
+
scriptInfo: ScriptFileInfo,
|
|
114
|
+
agentPubkey: string
|
|
115
|
+
): Promise<ScriptInstallResult> {
|
|
116
|
+
const homeDir = getAgentHomeDirectory(agentPubkey);
|
|
117
|
+
const absolutePath = path.join(homeDir, scriptInfo.relativePath);
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
// Security check: ensure the path doesn't escape the home directory
|
|
121
|
+
const normalizedPath = path.normalize(absolutePath);
|
|
122
|
+
const normalizedHome = path.normalize(homeDir);
|
|
123
|
+
if (!normalizedPath.startsWith(normalizedHome)) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`Security violation: path "${scriptInfo.relativePath}" would escape agent home directory`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Create parent directories
|
|
130
|
+
const parentDir = path.dirname(absolutePath);
|
|
131
|
+
await ensureDirectory(parentDir);
|
|
132
|
+
|
|
133
|
+
// Download the file
|
|
134
|
+
logger.debug(`Downloading script from ${scriptInfo.url}`);
|
|
135
|
+
const content = await downloadFile(scriptInfo.url);
|
|
136
|
+
|
|
137
|
+
// TODO: Verify SHA-256 hash if provided
|
|
138
|
+
// if (scriptInfo.sha256) {
|
|
139
|
+
// const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
140
|
+
// if (hash !== scriptInfo.sha256) {
|
|
141
|
+
// throw new Error(`SHA-256 mismatch: expected ${scriptInfo.sha256}, got ${hash}`);
|
|
142
|
+
// }
|
|
143
|
+
// }
|
|
144
|
+
|
|
145
|
+
// Write the file
|
|
146
|
+
await fs.writeFile(absolutePath, content);
|
|
147
|
+
|
|
148
|
+
// Make script executable if it's a script file
|
|
149
|
+
const ext = path.extname(scriptInfo.relativePath).toLowerCase();
|
|
150
|
+
const scriptExtensions = [".sh", ".py", ".rb", ".pl", ".js", ".ts"];
|
|
151
|
+
if (scriptExtensions.includes(ext)) {
|
|
152
|
+
await fs.chmod(absolutePath, 0o755);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
logger.info(`Installed script: ${scriptInfo.relativePath}`, {
|
|
156
|
+
eventId: scriptInfo.eventId,
|
|
157
|
+
absolutePath,
|
|
158
|
+
size: content.length,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
eventId: scriptInfo.eventId,
|
|
163
|
+
relativePath: scriptInfo.relativePath,
|
|
164
|
+
absolutePath,
|
|
165
|
+
success: true,
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
169
|
+
logger.error(`Failed to install script: ${scriptInfo.relativePath}`, {
|
|
170
|
+
eventId: scriptInfo.eventId,
|
|
171
|
+
error: errorMessage,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
return {
|
|
175
|
+
eventId: scriptInfo.eventId,
|
|
176
|
+
relativePath: scriptInfo.relativePath,
|
|
177
|
+
absolutePath,
|
|
178
|
+
success: false,
|
|
179
|
+
error: errorMessage,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Fetch and install all scripts referenced by e-tags in an agent definition.
|
|
186
|
+
*
|
|
187
|
+
* @param scriptETags - Array of script e-tag references from the agent definition
|
|
188
|
+
* @param agentPubkey - The agent's public key
|
|
189
|
+
* @param ndk - NDK instance for fetching events
|
|
190
|
+
* @returns Array of installation results
|
|
191
|
+
*/
|
|
192
|
+
export async function installAgentScripts(
|
|
193
|
+
scriptETags: Array<{ eventId: string; relayUrl?: string }>,
|
|
194
|
+
agentPubkey: string,
|
|
195
|
+
ndk: NDK
|
|
196
|
+
): Promise<ScriptInstallResult[]> {
|
|
197
|
+
if (scriptETags.length === 0) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
logger.info(`Installing ${scriptETags.length} script(s) for agent`, {
|
|
202
|
+
agentPubkey: agentPubkey.substring(0, 8),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const results: ScriptInstallResult[] = [];
|
|
206
|
+
|
|
207
|
+
for (const scriptRef of scriptETags) {
|
|
208
|
+
try {
|
|
209
|
+
// Fetch the 1063 event
|
|
210
|
+
logger.debug(`Fetching script event ${scriptRef.eventId}`);
|
|
211
|
+
const event = await ndk.fetchEvent(scriptRef.eventId, { groupable: false });
|
|
212
|
+
|
|
213
|
+
if (!event) {
|
|
214
|
+
results.push({
|
|
215
|
+
eventId: scriptRef.eventId,
|
|
216
|
+
relativePath: "unknown",
|
|
217
|
+
absolutePath: "unknown",
|
|
218
|
+
success: false,
|
|
219
|
+
error: `Could not fetch event ${scriptRef.eventId}`,
|
|
220
|
+
});
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Extract script info
|
|
225
|
+
const scriptInfo = extractScriptFileInfo(event);
|
|
226
|
+
if (!scriptInfo) {
|
|
227
|
+
results.push({
|
|
228
|
+
eventId: scriptRef.eventId,
|
|
229
|
+
relativePath: "unknown",
|
|
230
|
+
absolutePath: "unknown",
|
|
231
|
+
success: false,
|
|
232
|
+
error: "Event is not a valid kind 1063 file metadata event",
|
|
233
|
+
});
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Install the script
|
|
238
|
+
const result = await installScriptFile(scriptInfo, agentPubkey);
|
|
239
|
+
results.push(result);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
242
|
+
results.push({
|
|
243
|
+
eventId: scriptRef.eventId,
|
|
244
|
+
relativePath: "unknown",
|
|
245
|
+
absolutePath: "unknown",
|
|
246
|
+
success: false,
|
|
247
|
+
error: errorMessage,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Log summary
|
|
253
|
+
const successCount = results.filter((r) => r.success).length;
|
|
254
|
+
const failCount = results.filter((r) => !r.success).length;
|
|
255
|
+
|
|
256
|
+
if (failCount > 0) {
|
|
257
|
+
logger.warn(`Script installation completed with errors`, {
|
|
258
|
+
success: successCount,
|
|
259
|
+
failed: failCount,
|
|
260
|
+
});
|
|
261
|
+
} else {
|
|
262
|
+
logger.info(`All scripts installed successfully`, { count: successCount });
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return results;
|
|
266
|
+
}
|