@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,553 @@
|
|
|
1
|
+
import { exec, spawn, type ExecException } from "node:child_process";
|
|
2
|
+
import { createWriteStream } from "node:fs";
|
|
3
|
+
import { mkdir } from "node:fs/promises";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import type { AISdkTool, ToolExecutionContext } from "@/tools/types";
|
|
8
|
+
import { logger } from "@/utils/logger";
|
|
9
|
+
import { trace } from "@opentelemetry/api";
|
|
10
|
+
import { tool } from "ai";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
const execAsync = promisify(exec);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Commands known to use non-zero exit codes for non-error conditions.
|
|
17
|
+
* These commands return exit code 1 for "no matches" or similar expected outcomes.
|
|
18
|
+
*/
|
|
19
|
+
const COMMANDS_WITH_EXPECTED_NON_ZERO_EXIT: Record<string, { exitCodes: number[]; description: string }> = {
|
|
20
|
+
grep: { exitCodes: [1], description: "No matches found" },
|
|
21
|
+
rg: { exitCodes: [1], description: "No matches found" },
|
|
22
|
+
ripgrep: { exitCodes: [1], description: "No matches found" },
|
|
23
|
+
diff: { exitCodes: [1], description: "Files differ" },
|
|
24
|
+
cmp: { exitCodes: [1], description: "Files differ" },
|
|
25
|
+
test: { exitCodes: [1], description: "Condition is false" },
|
|
26
|
+
"[": { exitCodes: [1], description: "Condition is false" },
|
|
27
|
+
"[[": { exitCodes: [1], description: "Condition is false" },
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Structure returned when a shell command completes with non-zero exit
|
|
32
|
+
* but it's an expected condition (not an error)
|
|
33
|
+
*/
|
|
34
|
+
interface ShellExpectedNonZeroResult {
|
|
35
|
+
type: "expected-non-zero-exit";
|
|
36
|
+
command: string;
|
|
37
|
+
exitCode: number;
|
|
38
|
+
stdout: string;
|
|
39
|
+
stderr: string;
|
|
40
|
+
explanation: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Structure returned when a shell command fails unexpectedly
|
|
45
|
+
*/
|
|
46
|
+
interface ShellErrorResult {
|
|
47
|
+
type: "shell-error";
|
|
48
|
+
command: string;
|
|
49
|
+
exitCode: number | null;
|
|
50
|
+
error: string;
|
|
51
|
+
stdout: string;
|
|
52
|
+
stderr: string;
|
|
53
|
+
signal: string | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Structure returned when a shell command is started in the background
|
|
58
|
+
*/
|
|
59
|
+
interface ShellBackgroundResult {
|
|
60
|
+
type: "background-task";
|
|
61
|
+
taskId: string;
|
|
62
|
+
command: string;
|
|
63
|
+
description: string | null;
|
|
64
|
+
outputFile: string;
|
|
65
|
+
message: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type BackgroundTaskInfo = {
|
|
69
|
+
pid: number;
|
|
70
|
+
command: string;
|
|
71
|
+
description: string | null;
|
|
72
|
+
outputFile: string;
|
|
73
|
+
startTime: Date;
|
|
74
|
+
projectId: string;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Track background tasks
|
|
78
|
+
const backgroundTasks = new Map<string, BackgroundTaskInfo>();
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Generate a unique task ID for background processes
|
|
82
|
+
*/
|
|
83
|
+
function generateTaskId(): string {
|
|
84
|
+
return Math.random().toString(36).substring(2, 9);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Extracts the base command from a shell command string.
|
|
89
|
+
* Handles pipes, redirects, and command chaining.
|
|
90
|
+
*/
|
|
91
|
+
function extractBaseCommand(command: string): string {
|
|
92
|
+
// Remove leading whitespace and common prefixes
|
|
93
|
+
const trimmed = command.trim();
|
|
94
|
+
|
|
95
|
+
// Handle common patterns like "command args | ..." or "command args && ..."
|
|
96
|
+
// Get just the first word (the command itself)
|
|
97
|
+
const firstWord = trimmed.split(/\s+/)[0];
|
|
98
|
+
|
|
99
|
+
// Remove any path prefix (e.g., /usr/bin/grep -> grep)
|
|
100
|
+
const baseName = firstWord.split("/").pop() || firstWord;
|
|
101
|
+
|
|
102
|
+
return baseName;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Checks if a command's non-zero exit code is expected behavior
|
|
107
|
+
*/
|
|
108
|
+
function isExpectedNonZeroExit(command: string, exitCode: number): { expected: boolean; explanation?: string } {
|
|
109
|
+
const baseCommand = extractBaseCommand(command);
|
|
110
|
+
const config = COMMANDS_WITH_EXPECTED_NON_ZERO_EXIT[baseCommand];
|
|
111
|
+
|
|
112
|
+
if (config && config.exitCodes.includes(exitCode)) {
|
|
113
|
+
return { expected: true, explanation: config.description };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { expected: false };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const shellSchema = z.object({
|
|
120
|
+
command: z.string().describe("The shell command to execute"),
|
|
121
|
+
description: z
|
|
122
|
+
.string()
|
|
123
|
+
.trim()
|
|
124
|
+
.min(1, "Description is required and cannot be empty")
|
|
125
|
+
.describe(
|
|
126
|
+
"REQUIRED: A clear, concise description of what this command does (5-10 words). Helps provide human-readable context for the operation."
|
|
127
|
+
),
|
|
128
|
+
cwd: z
|
|
129
|
+
.string()
|
|
130
|
+
.nullable()
|
|
131
|
+
.optional()
|
|
132
|
+
.describe("Working directory for the command (defaults to project root)"),
|
|
133
|
+
timeout: z
|
|
134
|
+
.preprocess(
|
|
135
|
+
// Coerce numeric strings to numbers while preserving undefined/null
|
|
136
|
+
// Reject empty/whitespace strings (treat as undefined) to avoid Number("") === 0
|
|
137
|
+
(val) => {
|
|
138
|
+
if (val === undefined || val === null) return val;
|
|
139
|
+
if (typeof val === "number") return val;
|
|
140
|
+
if (typeof val === "string") {
|
|
141
|
+
const trimmed = val.trim();
|
|
142
|
+
if (trimmed === "") return undefined; // Treat empty/whitespace as "not provided"
|
|
143
|
+
const parsed = Number(trimmed);
|
|
144
|
+
return Number.isNaN(parsed) ? val : parsed;
|
|
145
|
+
}
|
|
146
|
+
return val;
|
|
147
|
+
},
|
|
148
|
+
z.number().nullable().optional()
|
|
149
|
+
)
|
|
150
|
+
.describe(
|
|
151
|
+
`Command timeout in seconds (default: 30, max: 600). Optional for background processes.`
|
|
152
|
+
),
|
|
153
|
+
run_in_background: z
|
|
154
|
+
.boolean()
|
|
155
|
+
.nullable()
|
|
156
|
+
.optional()
|
|
157
|
+
.describe(
|
|
158
|
+
"Set to true to run the command in the background. Returns immediately with a task ID that can be used to check status later."
|
|
159
|
+
),
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
type ShellInput = z.infer<typeof shellSchema>;
|
|
163
|
+
type ShellOutput = string | ShellExpectedNonZeroResult | ShellErrorResult | ShellBackgroundResult;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Core implementation of shell command execution
|
|
167
|
+
* Shared between AI SDK and legacy Tool interfaces
|
|
168
|
+
*
|
|
169
|
+
* Handles four cases:
|
|
170
|
+
* 1. Success (exit code 0): Returns stdout + stderr as string
|
|
171
|
+
* 2. Expected non-zero exit (e.g., grep with no matches): Returns structured result, NOT an error
|
|
172
|
+
* 3. Genuine failure: Returns structured error result for LLM recovery
|
|
173
|
+
* 4. Background execution: Returns task info immediately, output written to file
|
|
174
|
+
*/
|
|
175
|
+
async function executeShell(input: ShellInput, context: ToolExecutionContext): Promise<ShellOutput> {
|
|
176
|
+
const { command, description, cwd, timeout = 30, run_in_background } = input;
|
|
177
|
+
|
|
178
|
+
// Resolve cwd: if provided and relative, resolve against context.workingDirectory
|
|
179
|
+
// If not provided, use context.workingDirectory directly
|
|
180
|
+
let workingDir: string;
|
|
181
|
+
if (cwd) {
|
|
182
|
+
// If cwd is relative (like "."), resolve it against the project working directory
|
|
183
|
+
const { isAbsolute, resolve } = await import("node:path");
|
|
184
|
+
workingDir = isAbsolute(cwd) ? cwd : resolve(context.workingDirectory, cwd);
|
|
185
|
+
} else {
|
|
186
|
+
workingDir = context.workingDirectory;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Add trace span with all context for debugging
|
|
190
|
+
const span = trace.getActiveSpan();
|
|
191
|
+
span?.setAttributes({
|
|
192
|
+
"shell.command": command.substring(0, 200),
|
|
193
|
+
"shell.description": description || "(not provided)",
|
|
194
|
+
"shell.cwd_param_raw": cwd || "(not provided)",
|
|
195
|
+
"shell.cwd_resolved": workingDir || "(empty)",
|
|
196
|
+
"shell.context.working_directory": context.workingDirectory || "(empty)",
|
|
197
|
+
"shell.context.project_base_path": context.projectBasePath || "(empty)",
|
|
198
|
+
"shell.context.current_branch": context.currentBranch || "(empty)",
|
|
199
|
+
"shell.agent": context.agent.name,
|
|
200
|
+
"shell.timeout": (timeout ?? 30) * 1000,
|
|
201
|
+
"shell.run_in_background": run_in_background ?? false,
|
|
202
|
+
});
|
|
203
|
+
span?.addEvent("shell.execute_start", {
|
|
204
|
+
command: command.substring(0, 200),
|
|
205
|
+
description: description || "(not provided)",
|
|
206
|
+
cwd: workingDir || "(empty)",
|
|
207
|
+
run_in_background: run_in_background ?? false,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Validate working directory - fail fast if it's empty
|
|
211
|
+
if (!workingDir) {
|
|
212
|
+
const errorMsg = "Shell command cannot run: workingDirectory is empty. " +
|
|
213
|
+
`Context projectBasePath: "${context.projectBasePath}", ` +
|
|
214
|
+
`Context workingDirectory: "${context.workingDirectory}"`;
|
|
215
|
+
span?.addEvent("shell.error", { error: errorMsg });
|
|
216
|
+
throw new Error(errorMsg);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
logger.info("Executing shell command", {
|
|
220
|
+
command,
|
|
221
|
+
description: description || undefined,
|
|
222
|
+
cwd: workingDir,
|
|
223
|
+
contextWorkingDir: context.workingDirectory,
|
|
224
|
+
contextProjectBasePath: context.projectBasePath,
|
|
225
|
+
agent: context.agent.name,
|
|
226
|
+
timeout,
|
|
227
|
+
runInBackground: run_in_background ?? false,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Handle background execution
|
|
231
|
+
if (run_in_background) {
|
|
232
|
+
const taskId = generateTaskId();
|
|
233
|
+
const outputDir = join(tmpdir(), "tenex-shell-tasks");
|
|
234
|
+
await mkdir(outputDir, { recursive: true });
|
|
235
|
+
const outputFile = join(outputDir, `${taskId}.output`);
|
|
236
|
+
|
|
237
|
+
const child = spawn(command, [], {
|
|
238
|
+
cwd: workingDir,
|
|
239
|
+
shell: true,
|
|
240
|
+
detached: true,
|
|
241
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
242
|
+
env: {
|
|
243
|
+
...process.env,
|
|
244
|
+
PATH: process.env.PATH,
|
|
245
|
+
HOME: process.env.HOME,
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Write output to file
|
|
250
|
+
const outputStream = createWriteStream(outputFile);
|
|
251
|
+
child.stdout?.pipe(outputStream);
|
|
252
|
+
child.stderr?.pipe(outputStream);
|
|
253
|
+
|
|
254
|
+
// Track the background task with project isolation
|
|
255
|
+
if (child.pid === undefined) {
|
|
256
|
+
throw new Error("Failed to start background task: process ID unavailable");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Get project ID for isolation enforcement
|
|
260
|
+
const conversation = context.getConversation?.();
|
|
261
|
+
const projectId = conversation?.getProjectId();
|
|
262
|
+
if (!projectId) {
|
|
263
|
+
throw new Error("Cannot create background task: no project context available");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
backgroundTasks.set(taskId, {
|
|
267
|
+
pid: child.pid,
|
|
268
|
+
command: command.substring(0, 200),
|
|
269
|
+
description: description || null,
|
|
270
|
+
outputFile,
|
|
271
|
+
startTime: new Date(),
|
|
272
|
+
projectId,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Unref so parent can exit independently
|
|
276
|
+
child.unref();
|
|
277
|
+
|
|
278
|
+
// Clean up task tracking when process exits
|
|
279
|
+
child.on("exit", () => {
|
|
280
|
+
// Keep task info for a while so status can be checked
|
|
281
|
+
// It will be cleaned up eventually by a cleanup routine
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
span?.addEvent("shell.background_started", {
|
|
285
|
+
task_id: taskId,
|
|
286
|
+
output_file: outputFile,
|
|
287
|
+
pid: child.pid,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
logger.info("Shell command started in background", {
|
|
291
|
+
taskId,
|
|
292
|
+
command: command.substring(0, 200),
|
|
293
|
+
description: description || undefined,
|
|
294
|
+
outputFile,
|
|
295
|
+
pid: child.pid,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const result: ShellBackgroundResult = {
|
|
299
|
+
type: "background-task",
|
|
300
|
+
taskId,
|
|
301
|
+
command: command.substring(0, 200),
|
|
302
|
+
description: description || null,
|
|
303
|
+
outputFile,
|
|
304
|
+
message: `Command started in background. Task ID: ${taskId}. Output is being written to: ${outputFile}`,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
312
|
+
cwd: workingDir,
|
|
313
|
+
timeout: timeout != null ? timeout * 1000 : undefined,
|
|
314
|
+
env: {
|
|
315
|
+
...process.env,
|
|
316
|
+
PATH: process.env.PATH,
|
|
317
|
+
HOME: process.env.HOME,
|
|
318
|
+
},
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
const output = stdout + (stderr ? `\nSTDERR:\n${stderr}` : "");
|
|
322
|
+
|
|
323
|
+
span?.addEvent("shell.execute_complete", {
|
|
324
|
+
has_stdout: !!stdout,
|
|
325
|
+
has_stderr: !!stderr,
|
|
326
|
+
output_length: output.length,
|
|
327
|
+
exit_code: 0,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
logger.info("Shell command completed", {
|
|
331
|
+
command,
|
|
332
|
+
hasStdout: !!stdout,
|
|
333
|
+
hasStderr: !!stderr,
|
|
334
|
+
exitCode: 0,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
return output;
|
|
338
|
+
} catch (error) {
|
|
339
|
+
// Handle exec errors - which include non-zero exit codes
|
|
340
|
+
const execError = error as ExecException & { stdout?: string; stderr?: string };
|
|
341
|
+
const exitCode = execError.code ?? null;
|
|
342
|
+
const stdout = execError.stdout || "";
|
|
343
|
+
const stderr = execError.stderr || "";
|
|
344
|
+
const signal = execError.signal || null;
|
|
345
|
+
|
|
346
|
+
// Check if this is an expected non-zero exit code
|
|
347
|
+
if (exitCode !== null) {
|
|
348
|
+
const { expected, explanation } = isExpectedNonZeroExit(command, exitCode);
|
|
349
|
+
|
|
350
|
+
if (expected) {
|
|
351
|
+
// This is NOT an error - it's expected behavior (e.g., grep found no matches)
|
|
352
|
+
const result: ShellExpectedNonZeroResult = {
|
|
353
|
+
type: "expected-non-zero-exit",
|
|
354
|
+
command: command.substring(0, 200),
|
|
355
|
+
exitCode,
|
|
356
|
+
stdout,
|
|
357
|
+
stderr,
|
|
358
|
+
explanation: explanation || `Command exited with code ${exitCode}`,
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
span?.addEvent("shell.execute_complete", {
|
|
362
|
+
has_stdout: !!stdout,
|
|
363
|
+
has_stderr: !!stderr,
|
|
364
|
+
exit_code: exitCode,
|
|
365
|
+
expected_non_zero: true,
|
|
366
|
+
explanation: explanation,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
logger.info("Shell command completed with expected non-zero exit", {
|
|
370
|
+
command,
|
|
371
|
+
exitCode,
|
|
372
|
+
explanation,
|
|
373
|
+
hasStdout: !!stdout,
|
|
374
|
+
hasStderr: !!stderr,
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Return structured result - NOT throwing an error
|
|
378
|
+
return result;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// This is a genuine error - return structured error for LLM recovery
|
|
383
|
+
const errorResult: ShellErrorResult = {
|
|
384
|
+
type: "shell-error",
|
|
385
|
+
command: command.substring(0, 200),
|
|
386
|
+
exitCode,
|
|
387
|
+
error: execError.message,
|
|
388
|
+
stdout,
|
|
389
|
+
stderr,
|
|
390
|
+
signal,
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
span?.addEvent("shell.execute_error", {
|
|
394
|
+
exit_code: exitCode ?? "unknown",
|
|
395
|
+
signal: signal ?? "none",
|
|
396
|
+
error_message: execError.message.substring(0, 200),
|
|
397
|
+
has_stdout: !!stdout,
|
|
398
|
+
has_stderr: !!stderr,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
logger.error("Shell command failed", {
|
|
402
|
+
command,
|
|
403
|
+
exitCode,
|
|
404
|
+
signal,
|
|
405
|
+
error: execError.message,
|
|
406
|
+
hasStdout: !!stdout,
|
|
407
|
+
hasStderr: !!stderr,
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Return structured error instead of throwing
|
|
411
|
+
// This allows the LLM to see the full context and make recovery decisions
|
|
412
|
+
return errorResult;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Create an AI SDK tool for executing shell commands
|
|
418
|
+
*/
|
|
419
|
+
export function createShellTool(context: ToolExecutionContext): AISdkTool {
|
|
420
|
+
const aiTool = tool({
|
|
421
|
+
description: `Execute shell commands in the project directory.
|
|
422
|
+
|
|
423
|
+
IMPORTANT ESCAPING & STRING HANDLING:
|
|
424
|
+
- For complex/multi-line strings (git commits, PR bodies, JSON, etc.), ALWAYS use HEREDOC pattern:
|
|
425
|
+
command -m "$(cat <<'EOF'
|
|
426
|
+
Your multi-line content here
|
|
427
|
+
With "quotes" and $variables that don't need escaping!
|
|
428
|
+
EOF
|
|
429
|
+
)"
|
|
430
|
+
- Always quote file paths with spaces: cd "/path with spaces/file.txt"
|
|
431
|
+
- NEVER use nested quotes without HEREDOC - they will fail
|
|
432
|
+
- DO NOT use newlines to separate commands (newlines OK in quoted strings)
|
|
433
|
+
|
|
434
|
+
COMMAND CHAINING:
|
|
435
|
+
- For independent commands: Use multiple shell() calls in parallel
|
|
436
|
+
- For dependent sequential commands: Use && to chain (e.g., "cmd1 && cmd2 && cmd3")
|
|
437
|
+
- Use ; only when you don't care if earlier commands fail
|
|
438
|
+
- Prefer absolute paths over cd: "pytest /foo/bar/tests" NOT "cd /foo/bar && pytest tests"
|
|
439
|
+
|
|
440
|
+
WHEN NOT TO USE SHELL:
|
|
441
|
+
- File operations: Use fs_read/write_path (NOT cat/echo/sed/awk)
|
|
442
|
+
- Code modifications: Use edit tools directly (NOT sed/awk)
|
|
443
|
+
- File search: Use glob patterns (NOT find/ls)
|
|
444
|
+
- Content search: Use grep tools (NOT grep/rg commands)
|
|
445
|
+
|
|
446
|
+
OTHER RESTRICTIONS:
|
|
447
|
+
- NEVER use interactive flags like -i (git rebase -i, git add -i, etc.)
|
|
448
|
+
- Commands run with timeout in seconds (default: 30s, max: 600s / 10 minutes)
|
|
449
|
+
|
|
450
|
+
Use for: git operations, npm/build tools, docker, system commands where specialized tools don't exist.
|
|
451
|
+
- Time-based delays: Use shell(sleep N) to wait N seconds (e.g., shell(sleep 5) for 5 seconds).`,
|
|
452
|
+
|
|
453
|
+
inputSchema: shellSchema,
|
|
454
|
+
|
|
455
|
+
execute: async (input: ShellInput) => {
|
|
456
|
+
// executeShell now handles all error cases internally
|
|
457
|
+
// and returns structured results instead of throwing
|
|
458
|
+
return await executeShell(input, context);
|
|
459
|
+
},
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
Object.defineProperty(aiTool, "getHumanReadableContent", {
|
|
463
|
+
value: ({ command, description, run_in_background }: ShellInput) => {
|
|
464
|
+
const prefix = run_in_background ? "Running in background: " : "Executing: ";
|
|
465
|
+
if (description) {
|
|
466
|
+
return `${prefix}${description} (${command})`;
|
|
467
|
+
}
|
|
468
|
+
return `${prefix}${command}`;
|
|
469
|
+
},
|
|
470
|
+
enumerable: false,
|
|
471
|
+
configurable: true,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
return aiTool as AISdkTool;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Get information about a background task by its ID
|
|
479
|
+
*/
|
|
480
|
+
export function getBackgroundTaskInfo(taskId: string): BackgroundTaskInfo | undefined {
|
|
481
|
+
return backgroundTasks.get(taskId);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Get all background tasks
|
|
486
|
+
*/
|
|
487
|
+
export function getAllBackgroundTasks(): Array<{ taskId: string } & BackgroundTaskInfo> {
|
|
488
|
+
return Array.from(backgroundTasks.entries()).map(([id, info]) => ({
|
|
489
|
+
taskId: id,
|
|
490
|
+
...info,
|
|
491
|
+
}));
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Kill a background task by its ID
|
|
496
|
+
* @returns Object with success status and message
|
|
497
|
+
*/
|
|
498
|
+
export function killBackgroundTask(taskId: string): { success: boolean; message: string; pid?: number } {
|
|
499
|
+
const taskInfo = backgroundTasks.get(taskId);
|
|
500
|
+
|
|
501
|
+
if (!taskInfo) {
|
|
502
|
+
return {
|
|
503
|
+
success: false,
|
|
504
|
+
message: `No background task found with ID: ${taskId}`,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
try {
|
|
509
|
+
// Send SIGTERM to gracefully terminate the process
|
|
510
|
+
process.kill(taskInfo.pid, "SIGTERM");
|
|
511
|
+
|
|
512
|
+
// Remove from tracking
|
|
513
|
+
backgroundTasks.delete(taskId);
|
|
514
|
+
|
|
515
|
+
logger.info("Background task killed", {
|
|
516
|
+
taskId,
|
|
517
|
+
pid: taskInfo.pid,
|
|
518
|
+
command: taskInfo.command,
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
return {
|
|
522
|
+
success: true,
|
|
523
|
+
message: `Successfully terminated background task ${taskId} (PID: ${taskInfo.pid})`,
|
|
524
|
+
pid: taskInfo.pid,
|
|
525
|
+
};
|
|
526
|
+
} catch (error) {
|
|
527
|
+
// Process might already be dead
|
|
528
|
+
if ((error as NodeJS.ErrnoException).code === "ESRCH") {
|
|
529
|
+
// Process doesn't exist anymore, clean up tracking
|
|
530
|
+
backgroundTasks.delete(taskId);
|
|
531
|
+
return {
|
|
532
|
+
success: true,
|
|
533
|
+
message: `Task ${taskId} was already terminated (PID: ${taskInfo.pid})`,
|
|
534
|
+
pid: taskInfo.pid,
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
logger.error("Failed to kill background task", {
|
|
539
|
+
taskId,
|
|
540
|
+
pid: taskInfo.pid,
|
|
541
|
+
error: error instanceof Error ? error.message : String(error),
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
return {
|
|
545
|
+
success: false,
|
|
546
|
+
message: `Failed to terminate task ${taskId}: ${error instanceof Error ? error.message : String(error)}`,
|
|
547
|
+
pid: taskInfo.pid,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Export types for use in other modules
|
|
553
|
+
export type { ShellBackgroundResult, ShellErrorResult, ShellExpectedNonZeroResult };
|