@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,141 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
|
|
5
|
+
export interface OpenClawWorkspaceFiles {
|
|
6
|
+
soul: string | null;
|
|
7
|
+
identity: string | null;
|
|
8
|
+
agents: string | null;
|
|
9
|
+
user: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface OpenClawAgent {
|
|
13
|
+
id: string;
|
|
14
|
+
modelPrimary: string;
|
|
15
|
+
workspacePath: string;
|
|
16
|
+
workspaceFiles: OpenClawWorkspaceFiles;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function readFileOrNull(filePath: string): Promise<string | null> {
|
|
20
|
+
try {
|
|
21
|
+
return await fs.readFile(filePath, "utf-8");
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const CONFIG_FILE_NAMES = ["openclaw.json", "clawdbot.json", "moldbot.json", "moltbot.json"] as const;
|
|
28
|
+
|
|
29
|
+
async function configExists(dir: string): Promise<boolean> {
|
|
30
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(path.join(dir, name));
|
|
33
|
+
return true;
|
|
34
|
+
} catch {
|
|
35
|
+
// continue
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export async function findOpenClawStateDir(candidatePaths: string[]): Promise<string | null> {
|
|
42
|
+
// 1. Environment variable takes precedence
|
|
43
|
+
const envDir = process.env.OPENCLAW_STATE_DIR;
|
|
44
|
+
if (envDir && (await configExists(envDir))) {
|
|
45
|
+
return envDir;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 2. Check candidate paths
|
|
49
|
+
for (const dir of candidatePaths) {
|
|
50
|
+
if (await configExists(dir)) {
|
|
51
|
+
return dir;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export async function detectOpenClawStateDir(): Promise<string | null> {
|
|
59
|
+
const home = homedir();
|
|
60
|
+
return findOpenClawStateDir([
|
|
61
|
+
path.join(home, ".openclaw"),
|
|
62
|
+
path.join(home, ".clawdbot"),
|
|
63
|
+
path.join(home, ".moldbot"),
|
|
64
|
+
path.join(home, ".moltbot"),
|
|
65
|
+
]);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async function readConfigJson(stateDir: string): Promise<Record<string, unknown>> {
|
|
69
|
+
for (const name of CONFIG_FILE_NAMES) {
|
|
70
|
+
try {
|
|
71
|
+
const content = await fs.readFile(path.join(stateDir, name), "utf-8");
|
|
72
|
+
return JSON.parse(content);
|
|
73
|
+
} catch {
|
|
74
|
+
// continue
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`No config file found in ${stateDir}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function readWorkspaceFiles(workspacePath: string): Promise<OpenClawWorkspaceFiles> {
|
|
81
|
+
const [soul, identity, agents, user] = await Promise.all([
|
|
82
|
+
readFileOrNull(path.join(workspacePath, "SOUL.md")),
|
|
83
|
+
readFileOrNull(path.join(workspacePath, "IDENTITY.md")),
|
|
84
|
+
readFileOrNull(path.join(workspacePath, "AGENTS.md")),
|
|
85
|
+
readFileOrNull(path.join(workspacePath, "USER.md")),
|
|
86
|
+
]);
|
|
87
|
+
return { soul, identity, agents, user };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function readOpenClawAgents(stateDir: string): Promise<OpenClawAgent[]> {
|
|
91
|
+
const config = await readConfigJson(stateDir);
|
|
92
|
+
const agentsConfig = (config.agents ?? {}) as Record<string, unknown>;
|
|
93
|
+
const defaults = (agentsConfig.defaults ?? {}) as Record<string, unknown>;
|
|
94
|
+
const defaultModel = ((defaults.model ?? {}) as Record<string, unknown>).primary as
|
|
95
|
+
| string
|
|
96
|
+
| undefined;
|
|
97
|
+
const defaultWorkspace =
|
|
98
|
+
(defaults.workspace as string | undefined) ?? path.join(stateDir, "workspace");
|
|
99
|
+
|
|
100
|
+
const list = agentsConfig.list as Array<Record<string, unknown>> | undefined;
|
|
101
|
+
|
|
102
|
+
if (!list || list.length === 0) {
|
|
103
|
+
// Single default "main" agent
|
|
104
|
+
const workspaceFiles = await readWorkspaceFiles(defaultWorkspace);
|
|
105
|
+
return [
|
|
106
|
+
{
|
|
107
|
+
id: "main",
|
|
108
|
+
modelPrimary: defaultModel ?? "anthropic/claude-sonnet-4-6",
|
|
109
|
+
workspacePath: defaultWorkspace,
|
|
110
|
+
workspaceFiles,
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return Promise.all(
|
|
116
|
+
list.map(async (entry) => {
|
|
117
|
+
const id = (entry.id as string | undefined) ?? "main";
|
|
118
|
+
const agentModel = ((entry.model ?? {}) as Record<string, unknown>).primary as
|
|
119
|
+
| string
|
|
120
|
+
| undefined;
|
|
121
|
+
const workspacePath = (entry.workspace as string | undefined) ?? defaultWorkspace;
|
|
122
|
+
const workspaceFiles = await readWorkspaceFiles(workspacePath);
|
|
123
|
+
return {
|
|
124
|
+
id,
|
|
125
|
+
modelPrimary: agentModel ?? defaultModel ?? "anthropic/claude-sonnet-4-6",
|
|
126
|
+
workspacePath,
|
|
127
|
+
workspaceFiles,
|
|
128
|
+
};
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Convert OpenClaw model format to TENEX format.
|
|
135
|
+
* OpenClaw uses "provider/model", TENEX uses "provider:model".
|
|
136
|
+
*/
|
|
137
|
+
export function convertModelFormat(openClawModel: string): string {
|
|
138
|
+
const firstSlash = openClawModel.indexOf("/");
|
|
139
|
+
if (firstSlash === -1) return openClawModel;
|
|
140
|
+
return openClawModel.slice(0, firstSlash) + ":" + openClawModel.slice(firstSlash + 1);
|
|
141
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
|
|
6
|
+
import { agentStorage, createStoredAgent } from "@/agents/AgentStorage";
|
|
7
|
+
import { config as configService } from "@/services/ConfigService";
|
|
8
|
+
import type { LLMConfiguration } from "@/services/config/types";
|
|
9
|
+
import { detectOpenClawStateDir, readOpenClawAgents, convertModelFormat } from "./openclaw-reader";
|
|
10
|
+
import { distillAgentIdentity } from "./openclaw-distiller";
|
|
11
|
+
import type { OpenClawAgent } from "./openclaw-reader";
|
|
12
|
+
|
|
13
|
+
function toSlug(name: string): string {
|
|
14
|
+
return name
|
|
15
|
+
.toLowerCase()
|
|
16
|
+
.trim()
|
|
17
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
18
|
+
.replace(/^-+|-+$/g, "");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function createHomeDir(pubkey: string, workspacePath: string): Promise<string> {
|
|
22
|
+
const homeDir = configService.getConfigPath(`agents/${pubkey}`);
|
|
23
|
+
await fs.mkdir(homeDir, { recursive: true });
|
|
24
|
+
|
|
25
|
+
// Symlink MEMORY.md (dangling is ok — file may not exist yet)
|
|
26
|
+
const memoryMdTarget = path.join(workspacePath, "MEMORY.md");
|
|
27
|
+
const memoryMdLink = path.join(homeDir, "MEMORY.md");
|
|
28
|
+
await fs.rm(memoryMdLink, { force: true });
|
|
29
|
+
await fs.symlink(memoryMdTarget, memoryMdLink);
|
|
30
|
+
|
|
31
|
+
// Symlink memory/ directory (dangling is ok)
|
|
32
|
+
const memoryDirTarget = path.join(workspacePath, "memory");
|
|
33
|
+
const memoryDirLink = path.join(homeDir, "memory");
|
|
34
|
+
await fs.rm(memoryDirLink, { force: true });
|
|
35
|
+
await fs.symlink(memoryDirTarget, memoryDirLink);
|
|
36
|
+
|
|
37
|
+
const indexContent = `# Memory Files
|
|
38
|
+
|
|
39
|
+
This agent's memory is synced live from an OpenClaw installation.
|
|
40
|
+
|
|
41
|
+
- \`MEMORY.md\` — long-term curated memory (updated by OpenClaw)
|
|
42
|
+
- \`memory/YYYY-MM-DD.md\` — daily session logs (updated by OpenClaw)
|
|
43
|
+
|
|
44
|
+
Source: ${workspacePath}
|
|
45
|
+
`;
|
|
46
|
+
await fs.writeFile(path.join(homeDir, "+INDEX.md"), indexContent, "utf-8");
|
|
47
|
+
|
|
48
|
+
return homeDir;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function appendUserMdToGlobalPrompt(userMdContent: string): Promise<void> {
|
|
52
|
+
const globalPath = configService.getGlobalPath();
|
|
53
|
+
const existingConfig = await configService.loadTenexConfig(globalPath);
|
|
54
|
+
|
|
55
|
+
const userSection = `\n## About the User (imported from OpenClaw)\n\n${userMdContent.trim()}`;
|
|
56
|
+
const existingContent = existingConfig.globalSystemPrompt?.content ?? "";
|
|
57
|
+
const newContent = existingContent ? `${existingContent}${userSection}` : userSection.trim();
|
|
58
|
+
|
|
59
|
+
const newConfig = {
|
|
60
|
+
...existingConfig,
|
|
61
|
+
globalSystemPrompt: {
|
|
62
|
+
enabled: true,
|
|
63
|
+
content: newContent,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
await configService.saveGlobalConfig(newConfig);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function importOneAgent(agent: OpenClawAgent, llmConfig: LLMConfiguration): Promise<void> {
|
|
70
|
+
const tenexModel = convertModelFormat(agent.modelPrimary);
|
|
71
|
+
|
|
72
|
+
console.log(chalk.blue(`\nDistilling identity for agent '${agent.id}'...`));
|
|
73
|
+
const identity = await distillAgentIdentity(agent.workspaceFiles, llmConfig);
|
|
74
|
+
|
|
75
|
+
const slug = toSlug(identity.name) || agent.id;
|
|
76
|
+
|
|
77
|
+
const slugTaken = await agentStorage.slugExists(slug);
|
|
78
|
+
if (slugTaken) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Agent '${slug}' already imported. Delete it first if you want to re-import.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const signer = NDKPrivateKeySigner.generate();
|
|
85
|
+
const pubkey = signer.pubkey;
|
|
86
|
+
|
|
87
|
+
const storedAgent = createStoredAgent({
|
|
88
|
+
nsec: signer.privateKey,
|
|
89
|
+
slug,
|
|
90
|
+
name: identity.name,
|
|
91
|
+
role: identity.role,
|
|
92
|
+
description: identity.description,
|
|
93
|
+
instructions: identity.instructions,
|
|
94
|
+
useCriteria: identity.useCriteria,
|
|
95
|
+
defaultConfig: { model: tenexModel },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
await agentStorage.saveAgent(storedAgent);
|
|
99
|
+
const homeDir = await createHomeDir(pubkey, agent.workspacePath);
|
|
100
|
+
|
|
101
|
+
console.log(chalk.green(` ✓ Imported: ${identity.name} (${slug})`));
|
|
102
|
+
console.log(chalk.gray(` Keypair: ${pubkey}`));
|
|
103
|
+
console.log(chalk.gray(` Model: ${tenexModel}`));
|
|
104
|
+
console.log(chalk.gray(` Home dir: ${homeDir}`));
|
|
105
|
+
console.log(chalk.gray(` Symlinks: MEMORY.md, memory/`));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export const openclawImportCommand = new Command("openclaw")
|
|
109
|
+
.description("Import agents from a local OpenClaw installation")
|
|
110
|
+
.action(async () => {
|
|
111
|
+
try {
|
|
112
|
+
const stateDir = await detectOpenClawStateDir();
|
|
113
|
+
if (!stateDir) {
|
|
114
|
+
console.error(chalk.red("No OpenClaw installation detected."));
|
|
115
|
+
console.error(
|
|
116
|
+
chalk.gray(
|
|
117
|
+
"Checked: $OPENCLAW_STATE_DIR, ~/.openclaw, ~/.clawdbot, ~/.moldbot, ~/.moltbot"
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
process.exitCode = 1;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log(chalk.blue(`Found OpenClaw installation at: ${stateDir}`));
|
|
125
|
+
|
|
126
|
+
const agents = await readOpenClawAgents(stateDir);
|
|
127
|
+
console.log(chalk.blue(`Found ${agents.length} agent(s) to import.`));
|
|
128
|
+
|
|
129
|
+
await configService.loadConfig();
|
|
130
|
+
await agentStorage.initialize();
|
|
131
|
+
|
|
132
|
+
const llmConfig = configService.getLLMConfig();
|
|
133
|
+
let userMdProcessed = false;
|
|
134
|
+
|
|
135
|
+
for (const agent of agents) {
|
|
136
|
+
await importOneAgent(agent, llmConfig);
|
|
137
|
+
|
|
138
|
+
if (!userMdProcessed && agent.workspaceFiles.user) {
|
|
139
|
+
await appendUserMdToGlobalPrompt(agent.workspaceFiles.user);
|
|
140
|
+
console.log(chalk.green(" ✓ USER.md appended to global system prompt"));
|
|
141
|
+
userMdProcessed = true;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(chalk.green("\nImport complete."));
|
|
146
|
+
} catch (error: unknown) {
|
|
147
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
148
|
+
if (errorMessage?.includes("SIGINT") || errorMessage?.includes("force closed")) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
console.error(chalk.red(`Import failed: ${errorMessage}`));
|
|
152
|
+
process.exitCode = 1;
|
|
153
|
+
}
|
|
154
|
+
});
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { NDKPrivateKeySigner, NDKEvent } from "@nostr-dev-kit/ndk";
|
|
8
|
+
import { agentStorage, createStoredAgent } from "@/agents/AgentStorage";
|
|
9
|
+
import { installAgentFromNostr, installAgentFromNostrEvent } from "@/agents/agent-installer";
|
|
10
|
+
import { initNDK } from "@/nostr/ndkClient";
|
|
11
|
+
|
|
12
|
+
// ─── OpenClaw discovery ──────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
const OPENCLAW_STATE_DIR_NAMES = [".openclaw", ".clawdbot", ".moldbot", ".moltbot"];
|
|
15
|
+
const OPENCLAW_CONFIG_NAMES = ["openclaw.json", "clawdbot.json", "moldbot.json", "moltbot.json"];
|
|
16
|
+
|
|
17
|
+
function findOpenClawStateDir(): string | undefined {
|
|
18
|
+
// 1. Environment variable
|
|
19
|
+
const envPath = process.env.OPENCLAW_STATE_DIR;
|
|
20
|
+
if (envPath && hasOpenClawConfig(envPath)) {
|
|
21
|
+
return envPath;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 2. Home directory candidates
|
|
25
|
+
const home = homedir();
|
|
26
|
+
for (const name of OPENCLAW_STATE_DIR_NAMES) {
|
|
27
|
+
const candidate = path.join(home, name);
|
|
28
|
+
if (hasOpenClawConfig(candidate)) {
|
|
29
|
+
return candidate;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function hasOpenClawConfig(dir: string): boolean {
|
|
37
|
+
return OPENCLAW_CONFIG_NAMES.some((name) => existsSync(path.join(dir, name)));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Prettify a slug for display: "main" → "Main", "my-agent" → "My Agent" */
|
|
41
|
+
function prettifySlug(slug: string): string {
|
|
42
|
+
return slug
|
|
43
|
+
.replace(/-/g, " ")
|
|
44
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface OpenClawAgent {
|
|
48
|
+
name: string;
|
|
49
|
+
slug: string;
|
|
50
|
+
role: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function discoverOpenClawAgents(stateDir: string): Promise<OpenClawAgent[]> {
|
|
54
|
+
const agentsDir = path.join(stateDir, "agents");
|
|
55
|
+
try {
|
|
56
|
+
const entries = await fs.readdir(agentsDir, { withFileTypes: true });
|
|
57
|
+
return entries
|
|
58
|
+
.filter((e) => e.isDirectory())
|
|
59
|
+
.map((e) => ({
|
|
60
|
+
name: prettifySlug(e.name),
|
|
61
|
+
slug: e.name,
|
|
62
|
+
role: "",
|
|
63
|
+
}));
|
|
64
|
+
} catch {
|
|
65
|
+
return [];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ─── tenex agent import openclaw ────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
async function importOpenClaw(options: {
|
|
72
|
+
dryRun: boolean;
|
|
73
|
+
json: boolean;
|
|
74
|
+
slugs?: string;
|
|
75
|
+
}): Promise<void> {
|
|
76
|
+
const stateDir = findOpenClawStateDir();
|
|
77
|
+
|
|
78
|
+
if (!stateDir) {
|
|
79
|
+
if (options.json) {
|
|
80
|
+
console.log("[]");
|
|
81
|
+
} else {
|
|
82
|
+
console.error(chalk.yellow("OpenClaw installation not found."));
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const agents = await discoverOpenClawAgents(stateDir);
|
|
88
|
+
|
|
89
|
+
// Apply slug filter if provided
|
|
90
|
+
const filtered =
|
|
91
|
+
options.slugs
|
|
92
|
+
? agents.filter((a) => options.slugs!.split(",").map((s) => s.trim()).includes(a.slug))
|
|
93
|
+
: agents;
|
|
94
|
+
|
|
95
|
+
if (options.json) {
|
|
96
|
+
console.log(JSON.stringify(filtered, null, 2));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (filtered.length === 0) {
|
|
101
|
+
console.log(chalk.yellow("No OpenClaw agents found."));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (options.dryRun) {
|
|
106
|
+
console.log(chalk.blue(`Would import ${filtered.length} OpenClaw agent(s):`));
|
|
107
|
+
for (const agent of filtered) {
|
|
108
|
+
console.log(chalk.gray(` ${agent.slug} → "${agent.name}"`));
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await agentStorage.initialize();
|
|
114
|
+
|
|
115
|
+
let imported = 0;
|
|
116
|
+
let skipped = 0;
|
|
117
|
+
|
|
118
|
+
for (const agent of filtered) {
|
|
119
|
+
// Check if already exists by slug
|
|
120
|
+
const existing = await agentStorage.getAgentBySlug(agent.slug);
|
|
121
|
+
if (existing) {
|
|
122
|
+
console.log(chalk.gray(` ${agent.slug}: already exists, skipping`));
|
|
123
|
+
skipped++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const signer = NDKPrivateKeySigner.generate();
|
|
128
|
+
const stored = createStoredAgent({
|
|
129
|
+
nsec: signer.nsec,
|
|
130
|
+
slug: agent.slug,
|
|
131
|
+
name: agent.name,
|
|
132
|
+
role: agent.role,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await agentStorage.saveAgent(stored);
|
|
136
|
+
console.log(
|
|
137
|
+
chalk.green(` ✓ ${agent.slug}`) +
|
|
138
|
+
chalk.gray(` → pubkey ${signer.pubkey.substring(0, 8)}...`)
|
|
139
|
+
);
|
|
140
|
+
imported++;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
console.log(chalk.blue(`\nDone: ${imported} imported, ${skipped} skipped`));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ─── tenex agent add ─────────────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
async function readStdin(): Promise<string> {
|
|
149
|
+
return new Promise((resolve, reject) => {
|
|
150
|
+
let data = "";
|
|
151
|
+
process.stdin.setEncoding("utf-8");
|
|
152
|
+
process.stdin.on("data", (chunk) => {
|
|
153
|
+
data += chunk;
|
|
154
|
+
});
|
|
155
|
+
process.stdin.on("end", () => resolve(data.trim()));
|
|
156
|
+
process.stdin.on("error", reject);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function addAgent(eventId: string | undefined): Promise<void> {
|
|
161
|
+
await agentStorage.initialize();
|
|
162
|
+
|
|
163
|
+
if (!process.stdin.isTTY) {
|
|
164
|
+
const raw = await readStdin();
|
|
165
|
+
const rawEvent = JSON.parse(raw);
|
|
166
|
+
const event = new NDKEvent(undefined, rawEvent);
|
|
167
|
+
const stored = await installAgentFromNostrEvent(event);
|
|
168
|
+
const pubkey = new NDKPrivateKeySigner(stored.nsec).pubkey;
|
|
169
|
+
console.log(chalk.green(`✓ Installed agent "${stored.name}" (${stored.slug})`));
|
|
170
|
+
console.log(chalk.gray(` pubkey: ${pubkey}`));
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!eventId) {
|
|
175
|
+
console.error(chalk.red("Error: provide an event ID or pipe event JSON via stdin"));
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
await initNDK();
|
|
180
|
+
const stored = await installAgentFromNostr(eventId);
|
|
181
|
+
const pubkey = new NDKPrivateKeySigner(stored.nsec).pubkey;
|
|
182
|
+
console.log(chalk.green(`✓ Installed agent "${stored.name}" (${stored.slug})`));
|
|
183
|
+
console.log(chalk.gray(` pubkey: ${pubkey}`));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ─── Command registration ────────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
const importOpenClawCommand = new Command("openclaw")
|
|
189
|
+
.description("Import agents from a local OpenClaw installation")
|
|
190
|
+
.option("--dry-run", "Print what would be imported without making changes")
|
|
191
|
+
.option("--json", "Output as JSON array")
|
|
192
|
+
.option("--slugs <slugs>", "Comma-separated list of slugs to import (default: all)")
|
|
193
|
+
.action(async (options) => {
|
|
194
|
+
await importOpenClaw({
|
|
195
|
+
dryRun: !!options.dryRun,
|
|
196
|
+
json: !!options.json,
|
|
197
|
+
slugs: options.slugs,
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const importCommand = new Command("import")
|
|
202
|
+
.description("Import agents from external sources")
|
|
203
|
+
.addCommand(importOpenClawCommand);
|
|
204
|
+
|
|
205
|
+
const addCommand = new Command("add")
|
|
206
|
+
.description("Install an agent from a Nostr event ID or stdin JSON")
|
|
207
|
+
.argument("[event-id]", "Nostr event ID of the agent definition")
|
|
208
|
+
.action(async (eventId: string | undefined) => {
|
|
209
|
+
await addAgent(eventId);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
export const agentCommand = new Command("agent")
|
|
213
|
+
.description("Manage TENEX agents")
|
|
214
|
+
.addCommand(importCommand)
|
|
215
|
+
.addCommand(addCommand);
|