@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.
Files changed (427) hide show
  1. package/README.md +194 -0
  2. package/dist/backend-wrapper.cjs +3 -0
  3. package/dist/src/index.js +331928 -0
  4. package/package.json +103 -0
  5. package/src/agents/AgentRegistry.ts +418 -0
  6. package/src/agents/AgentStorage.ts +1133 -0
  7. package/src/agents/ConfigResolver.ts +229 -0
  8. package/src/agents/agent-installer.ts +236 -0
  9. package/src/agents/agent-loader.ts +241 -0
  10. package/src/agents/constants.ts +82 -0
  11. package/src/agents/errors.ts +48 -0
  12. package/src/agents/execution/AgentExecutor.ts +561 -0
  13. package/src/agents/execution/ExecutionContextFactory.ts +112 -0
  14. package/src/agents/execution/MessageCompiler.ts +597 -0
  15. package/src/agents/execution/MessageSyncer.ts +100 -0
  16. package/src/agents/execution/PostCompletionChecker.ts +278 -0
  17. package/src/agents/execution/ProgressMonitor.ts +50 -0
  18. package/src/agents/execution/RALResolver.ts +177 -0
  19. package/src/agents/execution/SessionManager.ts +181 -0
  20. package/src/agents/execution/StreamCallbacks.ts +312 -0
  21. package/src/agents/execution/StreamExecutionHandler.ts +579 -0
  22. package/src/agents/execution/StreamSetup.ts +313 -0
  23. package/src/agents/execution/ToolEventHandlers.ts +239 -0
  24. package/src/agents/execution/ToolExecutionTracker.ts +498 -0
  25. package/src/agents/execution/ToolResultUtils.ts +97 -0
  26. package/src/agents/execution/ToolSupervisionWrapper.ts +174 -0
  27. package/src/agents/execution/constants.ts +16 -0
  28. package/src/agents/execution/index.ts +3 -0
  29. package/src/agents/execution/types.ts +96 -0
  30. package/src/agents/execution/utils.ts +26 -0
  31. package/src/agents/index.ts +4 -0
  32. package/src/agents/script-installer.ts +266 -0
  33. package/src/agents/supervision/SupervisorLLMService.ts +253 -0
  34. package/src/agents/supervision/SupervisorOrchestrator.ts +471 -0
  35. package/src/agents/supervision/heuristics/ConsecutiveToolsWithoutTodoHeuristic.ts +73 -0
  36. package/src/agents/supervision/heuristics/DelegationClaimHeuristic.ts +80 -0
  37. package/src/agents/supervision/heuristics/HeuristicRegistry.ts +114 -0
  38. package/src/agents/supervision/heuristics/PendingTodosHeuristic.ts +93 -0
  39. package/src/agents/supervision/heuristics/SilentAgentHeuristic.ts +54 -0
  40. package/src/agents/supervision/heuristics/index.ts +5 -0
  41. package/src/agents/supervision/index.ts +28 -0
  42. package/src/agents/supervision/registerHeuristics.ts +110 -0
  43. package/src/agents/supervision/supervisionHealthCheck.ts +123 -0
  44. package/src/agents/supervision/types.ts +171 -0
  45. package/src/agents/tool-names.ts +46 -0
  46. package/src/agents/tool-normalization.ts +184 -0
  47. package/src/agents/types/index.ts +2 -0
  48. package/src/agents/types/runtime.ts +74 -0
  49. package/src/agents/types/storage.ts +145 -0
  50. package/src/commands/agent/import/index.ts +6 -0
  51. package/src/commands/agent/import/openclaw-distiller.ts +57 -0
  52. package/src/commands/agent/import/openclaw-reader.ts +141 -0
  53. package/src/commands/agent/import/openclaw.ts +154 -0
  54. package/src/commands/agent/index.ts +6 -0
  55. package/src/commands/agent.ts +215 -0
  56. package/src/commands/daemon.ts +198 -0
  57. package/src/commands/doctor.ts +134 -0
  58. package/src/commands/setup/embed.ts +228 -0
  59. package/src/commands/setup/global-system-prompt.ts +223 -0
  60. package/src/commands/setup/image.ts +179 -0
  61. package/src/commands/setup/index.ts +16 -0
  62. package/src/commands/setup/interactive.ts +95 -0
  63. package/src/commands/setup/llm.ts +38 -0
  64. package/src/commands/setup/onboarding.ts +294 -0
  65. package/src/commands/setup/providers.ts +27 -0
  66. package/src/constants.ts +34 -0
  67. package/src/conversations/ConversationDiskReader.ts +148 -0
  68. package/src/conversations/ConversationRegistry.ts +728 -0
  69. package/src/conversations/ConversationStore.ts +868 -0
  70. package/src/conversations/MessageBuilder.ts +866 -0
  71. package/src/conversations/executionTime.ts +62 -0
  72. package/src/conversations/formatters/DelegationXmlFormatter.ts +64 -0
  73. package/src/conversations/formatters/ThreadedConversationFormatter.ts +303 -0
  74. package/src/conversations/formatters/index.ts +9 -0
  75. package/src/conversations/formatters/utils/MessageFormatter.ts +46 -0
  76. package/src/conversations/formatters/utils/TimestampFormatter.ts +56 -0
  77. package/src/conversations/formatters/utils/TreeBuilder.ts +131 -0
  78. package/src/conversations/formatters/utils/TreeRenderer.ts +49 -0
  79. package/src/conversations/index.ts +2 -0
  80. package/src/conversations/persistence/ToolMessageStorage.ts +143 -0
  81. package/src/conversations/search/ConversationIndexManager.ts +393 -0
  82. package/src/conversations/search/QueryParser.ts +114 -0
  83. package/src/conversations/search/SearchEngine.ts +175 -0
  84. package/src/conversations/search/SnippetExtractor.ts +345 -0
  85. package/src/conversations/search/embeddings/ConversationEmbeddingService.ts +484 -0
  86. package/src/conversations/search/embeddings/ConversationIndexingJob.ts +320 -0
  87. package/src/conversations/search/embeddings/IndexingStateManager.ts +338 -0
  88. package/src/conversations/search/embeddings/index.ts +18 -0
  89. package/src/conversations/search/index.ts +49 -0
  90. package/src/conversations/search/types.ts +124 -0
  91. package/src/conversations/services/CategoryManager.ts +160 -0
  92. package/src/conversations/services/ConversationResolver.ts +296 -0
  93. package/src/conversations/services/ConversationSummarizer.ts +234 -0
  94. package/src/conversations/services/MetadataDebounceManager.ts +188 -0
  95. package/src/conversations/services/index.ts +2 -0
  96. package/src/conversations/types.ts +148 -0
  97. package/src/conversations/utils/content-utils.ts +69 -0
  98. package/src/conversations/utils/image-placeholder.ts +281 -0
  99. package/src/conversations/utils/image-url-utils.ts +171 -0
  100. package/src/conversations/utils/multimodal-content.ts +90 -0
  101. package/src/conversations/utils/tool-result-truncator.ts +159 -0
  102. package/src/daemon/Daemon.ts +1883 -0
  103. package/src/daemon/ProjectRuntime.ts +657 -0
  104. package/src/daemon/RestartState.ts +152 -0
  105. package/src/daemon/RuntimeLifecycle.ts +268 -0
  106. package/src/daemon/SubscriptionManager.ts +305 -0
  107. package/src/daemon/UnixSocketTransport.ts +318 -0
  108. package/src/daemon/filters/SubscriptionFilterBuilder.ts +119 -0
  109. package/src/daemon/index.ts +9 -0
  110. package/src/daemon/routing/DaemonRouter.ts +491 -0
  111. package/src/daemon/types.ts +150 -0
  112. package/src/daemon/utils/routing-log.ts +76 -0
  113. package/src/daemon/utils/telemetry.ts +173 -0
  114. package/src/event-handler/agentDeletion.ts +383 -0
  115. package/src/event-handler/index.ts +749 -0
  116. package/src/event-handler/newConversation.ts +165 -0
  117. package/src/event-handler/project.ts +166 -0
  118. package/src/event-handler/reply.ts +18 -0
  119. package/src/events/NDKAgentDefinition.ts +292 -0
  120. package/src/events/NDKAgentLesson.ts +106 -0
  121. package/src/events/NDKEventMetadata.ts +34 -0
  122. package/src/events/NDKMCPTool.ts +60 -0
  123. package/src/events/NDKProjectStatus.ts +384 -0
  124. package/src/events/index.ts +4 -0
  125. package/src/index.ts +126 -0
  126. package/src/lib/agent-home.ts +334 -0
  127. package/src/lib/error-formatter.ts +200 -0
  128. package/src/lib/fs/filesystem.ts +128 -0
  129. package/src/lib/fs/index.ts +1 -0
  130. package/src/lib/json-parser.ts +30 -0
  131. package/src/lib/string.ts +15 -0
  132. package/src/lib/time.ts +74 -0
  133. package/src/llm/ChunkHandler.ts +277 -0
  134. package/src/llm/FinishHandler.ts +250 -0
  135. package/src/llm/LLMConfigEditor.ts +154 -0
  136. package/src/llm/LLMServiceFactory.ts +230 -0
  137. package/src/llm/MessageProcessor.ts +90 -0
  138. package/src/llm/RecordingState.ts +37 -0
  139. package/src/llm/StreamPublisher.ts +40 -0
  140. package/src/llm/TracingUtils.ts +77 -0
  141. package/src/llm/chunk-validators.ts +57 -0
  142. package/src/llm/constants.ts +6 -0
  143. package/src/llm/index.ts +12 -0
  144. package/src/llm/meta/MetaModelResolver.ts +352 -0
  145. package/src/llm/meta/index.ts +11 -0
  146. package/src/llm/middleware/flight-recorder.ts +188 -0
  147. package/src/llm/providers/MockProvider.ts +332 -0
  148. package/src/llm/providers/agent/ClaudeCodeProvider.ts +343 -0
  149. package/src/llm/providers/agent/ClaudeCodeToolsAdapter.ts +203 -0
  150. package/src/llm/providers/agent/CodexAppServerProvider.ts +214 -0
  151. package/src/llm/providers/agent/CodexAppServerToolsAdapter.ts +91 -0
  152. package/src/llm/providers/agent/index.ts +10 -0
  153. package/src/llm/providers/base/AgentProvider.ts +107 -0
  154. package/src/llm/providers/base/BaseProvider.ts +114 -0
  155. package/src/llm/providers/base/StandardProvider.ts +38 -0
  156. package/src/llm/providers/base/index.ts +9 -0
  157. package/src/llm/providers/index.ts +106 -0
  158. package/src/llm/providers/key-manager.ts +238 -0
  159. package/src/llm/providers/ollama-models.ts +105 -0
  160. package/src/llm/providers/openrouter-models.ts +102 -0
  161. package/src/llm/providers/provider-ids.ts +18 -0
  162. package/src/llm/providers/registry/ProviderRegistry.ts +414 -0
  163. package/src/llm/providers/registry/index.ts +7 -0
  164. package/src/llm/providers/standard/AnthropicProvider.ts +71 -0
  165. package/src/llm/providers/standard/OllamaProvider.ts +59 -0
  166. package/src/llm/providers/standard/OpenAIProvider.ts +44 -0
  167. package/src/llm/providers/standard/OpenRouterProvider.ts +103 -0
  168. package/src/llm/providers/standard/index.ts +10 -0
  169. package/src/llm/providers/types.ts +194 -0
  170. package/src/llm/providers/usage-metadata.ts +78 -0
  171. package/src/llm/service.ts +713 -0
  172. package/src/llm/types.ts +167 -0
  173. package/src/llm/utils/ConfigurationManager.ts +650 -0
  174. package/src/llm/utils/ConfigurationTester.ts +229 -0
  175. package/src/llm/utils/ModelSelector.ts +212 -0
  176. package/src/llm/utils/ProviderConfigUI.ts +177 -0
  177. package/src/llm/utils/claudeCodePromptCompiler.ts +141 -0
  178. package/src/llm/utils/codex-models.ts +53 -0
  179. package/src/llm/utils/context-window-cache.ts +30 -0
  180. package/src/llm/utils/models-dev-cache.ts +267 -0
  181. package/src/llm/utils/provider-setup.ts +50 -0
  182. package/src/llm/utils/tool-errors.ts +78 -0
  183. package/src/llm/utils/usage.ts +74 -0
  184. package/src/logging/EventRoutingLogger.ts +205 -0
  185. package/src/nostr/AgentEventDecoder.ts +357 -0
  186. package/src/nostr/AgentEventEncoder.ts +677 -0
  187. package/src/nostr/AgentProfilePublisher.ts +657 -0
  188. package/src/nostr/AgentPublisher.ts +437 -0
  189. package/src/nostr/BlossomService.ts +226 -0
  190. package/src/nostr/InterventionPublisher.ts +132 -0
  191. package/src/nostr/TagExtractor.ts +228 -0
  192. package/src/nostr/collectEvents.ts +83 -0
  193. package/src/nostr/constants.ts +38 -0
  194. package/src/nostr/encryption.ts +26 -0
  195. package/src/nostr/index.ts +31 -0
  196. package/src/nostr/keys.ts +17 -0
  197. package/src/nostr/kinds.ts +37 -0
  198. package/src/nostr/ndkClient.ts +72 -0
  199. package/src/nostr/relays.ts +43 -0
  200. package/src/nostr/trace-context.ts +39 -0
  201. package/src/nostr/types.ts +227 -0
  202. package/src/nostr/utils.ts +84 -0
  203. package/src/prompts/core/FragmentRegistry.ts +30 -0
  204. package/src/prompts/core/PromptBuilder.ts +98 -0
  205. package/src/prompts/core/index.ts +3 -0
  206. package/src/prompts/core/types.ts +13 -0
  207. package/src/prompts/fragments/00-global-system-prompt.ts +44 -0
  208. package/src/prompts/fragments/01-agent-identity.ts +69 -0
  209. package/src/prompts/fragments/02-agent-home-directory.ts +114 -0
  210. package/src/prompts/fragments/03-system-reminders-explanation.ts +14 -0
  211. package/src/prompts/fragments/04-relay-configuration.ts +38 -0
  212. package/src/prompts/fragments/05-delegation-chain.ts +45 -0
  213. package/src/prompts/fragments/06-agent-todos.ts +74 -0
  214. package/src/prompts/fragments/06-todo-usage-guidance.ts +34 -0
  215. package/src/prompts/fragments/07-meta-project-context.ts +234 -0
  216. package/src/prompts/fragments/08-active-conversations.ts +382 -0
  217. package/src/prompts/fragments/09-recent-conversations.ts +153 -0
  218. package/src/prompts/fragments/10-referenced-article.ts +21 -0
  219. package/src/prompts/fragments/11-nudges.ts +134 -0
  220. package/src/prompts/fragments/12-skills.ts +127 -0
  221. package/src/prompts/fragments/13-available-nudges.ts +122 -0
  222. package/src/prompts/fragments/15-available-agents.ts +53 -0
  223. package/src/prompts/fragments/16-stay-in-your-lane.ts +41 -0
  224. package/src/prompts/fragments/17-todo-before-delegation.ts +39 -0
  225. package/src/prompts/fragments/20-voice-mode.ts +62 -0
  226. package/src/prompts/fragments/22-scheduled-tasks.ts +175 -0
  227. package/src/prompts/fragments/24-retrieved-lessons.ts +26 -0
  228. package/src/prompts/fragments/25-rag-instructions.ts +333 -0
  229. package/src/prompts/fragments/26-mcp-resources.ts +237 -0
  230. package/src/prompts/fragments/27-memorized-reports.ts +77 -0
  231. package/src/prompts/fragments/28-agent-directed-monitoring.ts +32 -0
  232. package/src/prompts/fragments/29-rag-collections.ts +50 -0
  233. package/src/prompts/fragments/30-worktree-context.ts +98 -0
  234. package/src/prompts/fragments/31-agents-md-guidance.ts +96 -0
  235. package/src/prompts/fragments/32-process-metrics.ts +72 -0
  236. package/src/prompts/fragments/debug-mode.ts +48 -0
  237. package/src/prompts/fragments/delegation-completion.ts +44 -0
  238. package/src/prompts/fragments/index.ts +91 -0
  239. package/src/prompts/index.ts +21 -0
  240. package/src/prompts/utils/systemPromptBuilder.ts +777 -0
  241. package/src/scripts/migrate-prefix-index.ts +157 -0
  242. package/src/services/AgentDefinitionMonitor.ts +701 -0
  243. package/src/services/ConfigService.ts +723 -0
  244. package/src/services/CooldownRegistry.ts +199 -0
  245. package/src/services/LLMOperationsRegistry.ts +424 -0
  246. package/src/services/OwnerAgentListService.ts +354 -0
  247. package/src/services/PubkeyService.ts +308 -0
  248. package/src/services/agents/AgentMetadataStore.ts +72 -0
  249. package/src/services/agents/AgentResolution.ts +59 -0
  250. package/src/services/agents/EscalationService.ts +281 -0
  251. package/src/services/agents/NDKAgentDiscovery.ts +95 -0
  252. package/src/services/agents/index.ts +7 -0
  253. package/src/services/agents-md/AgentsMdService.ts +184 -0
  254. package/src/services/agents-md/SystemReminderInjector.ts +238 -0
  255. package/src/services/agents-md/index.ts +11 -0
  256. package/src/services/apns/APNsClient.ts +203 -0
  257. package/src/services/apns/APNsService.ts +358 -0
  258. package/src/services/apns/index.ts +11 -0
  259. package/src/services/apns/types.ts +80 -0
  260. package/src/services/compression/CompressionService.ts +445 -0
  261. package/src/services/compression/compression-schema.ts +28 -0
  262. package/src/services/compression/compression-types.ts +74 -0
  263. package/src/services/compression/compression-utils.ts +587 -0
  264. package/src/services/config/types.ts +394 -0
  265. package/src/services/dispatch/AgentDispatchService.ts +937 -0
  266. package/src/services/dispatch/AgentRouter.ts +181 -0
  267. package/src/services/dispatch/DelegationCompletionHandler.ts +232 -0
  268. package/src/services/embedding/EmbeddingProvider.ts +188 -0
  269. package/src/services/embedding/index.ts +5 -0
  270. package/src/services/event-context/EventContextService.ts +108 -0
  271. package/src/services/event-context/index.ts +2 -0
  272. package/src/services/heuristics/ContextBuilder.ts +106 -0
  273. package/src/services/heuristics/HeuristicEngine.ts +200 -0
  274. package/src/services/heuristics/formatters.ts +58 -0
  275. package/src/services/heuristics/index.ts +12 -0
  276. package/src/services/heuristics/rules/index.ts +25 -0
  277. package/src/services/heuristics/rules/todoBeforeDelegation.ts +69 -0
  278. package/src/services/heuristics/rules/todoReminderOnToolUse.ts +63 -0
  279. package/src/services/heuristics/types.ts +144 -0
  280. package/src/services/image/ImageGenerationService.ts +389 -0
  281. package/src/services/image/index.ts +12 -0
  282. package/src/services/intervention/InterventionService.ts +1352 -0
  283. package/src/services/intervention/index.ts +7 -0
  284. package/src/services/mcp/MCPManager.ts +683 -0
  285. package/src/services/mcp/McpNotificationDelivery.ts +139 -0
  286. package/src/services/mcp/McpSubscriptionService.ts +653 -0
  287. package/src/services/mcp/mcpInstaller.ts +130 -0
  288. package/src/services/nip46/Nip46SigningLog.ts +81 -0
  289. package/src/services/nip46/Nip46SigningService.ts +467 -0
  290. package/src/services/nip46/index.ts +4 -0
  291. package/src/services/nudge/NudgeService.ts +224 -0
  292. package/src/services/nudge/NudgeWhitelistService.ts +382 -0
  293. package/src/services/nudge/index.ts +5 -0
  294. package/src/services/nudge/types.ts +83 -0
  295. package/src/services/projects/ProjectContext.ts +672 -0
  296. package/src/services/projects/ProjectContextStore.ts +102 -0
  297. package/src/services/projects/index.ts +6 -0
  298. package/src/services/prompt-compiler/index.ts +15 -0
  299. package/src/services/prompt-compiler/prompt-compiler-service.ts +1143 -0
  300. package/src/services/pubkey-gate/PubkeyGateService.ts +93 -0
  301. package/src/services/pubkey-gate/index.ts +1 -0
  302. package/src/services/rag/EmbeddingProviderFactory.ts +292 -0
  303. package/src/services/rag/LanceDBMaintenanceService.ts +211 -0
  304. package/src/services/rag/RAGDatabaseService.ts +173 -0
  305. package/src/services/rag/RAGOperations.ts +682 -0
  306. package/src/services/rag/RAGService.ts +240 -0
  307. package/src/services/rag/RagSubscriptionService.ts +618 -0
  308. package/src/services/rag/rag-utils.ts +174 -0
  309. package/src/services/ral/PendingDelegationsRegistry.ts +168 -0
  310. package/src/services/ral/RALRegistry.ts +2782 -0
  311. package/src/services/ral/index.ts +4 -0
  312. package/src/services/ral/types.ts +292 -0
  313. package/src/services/reports/LocalReportStore.ts +380 -0
  314. package/src/services/reports/ReportEmbeddingService.ts +430 -0
  315. package/src/services/reports/ReportService.ts +440 -0
  316. package/src/services/reports/articleUtils.ts +52 -0
  317. package/src/services/reports/index.ts +7 -0
  318. package/src/services/scheduling/SchedulerService.ts +1057 -0
  319. package/src/services/scheduling/errors.ts +14 -0
  320. package/src/services/scheduling/index.ts +7 -0
  321. package/src/services/scheduling/utils.ts +77 -0
  322. package/src/services/search/SearchProviderRegistry.ts +78 -0
  323. package/src/services/search/UnifiedSearchService.ts +218 -0
  324. package/src/services/search/index.ts +47 -0
  325. package/src/services/search/projectFilter.ts +22 -0
  326. package/src/services/search/providers/ConversationSearchProvider.ts +48 -0
  327. package/src/services/search/providers/LessonSearchProvider.ts +75 -0
  328. package/src/services/search/providers/ReportSearchProvider.ts +49 -0
  329. package/src/services/search/types.ts +144 -0
  330. package/src/services/skill/SkillService.ts +482 -0
  331. package/src/services/skill/index.ts +2 -0
  332. package/src/services/skill/types.ts +70 -0
  333. package/src/services/status/OperationsStatusService.ts +276 -0
  334. package/src/services/status/ProjectStatusService.ts +522 -0
  335. package/src/services/status/index.ts +11 -0
  336. package/src/services/storage/PrefixKVStore.ts +242 -0
  337. package/src/services/storage/index.ts +1 -0
  338. package/src/services/system-reminder/SystemReminderUtils.ts +96 -0
  339. package/src/services/system-reminder/index.ts +7 -0
  340. package/src/services/trust-pubkeys/TrustPubkeyService.ts +325 -0
  341. package/src/services/trust-pubkeys/index.ts +2 -0
  342. package/src/telemetry/ConversationSpanManager.ts +111 -0
  343. package/src/telemetry/EventLoopMonitor.ts +206 -0
  344. package/src/telemetry/LLMSpanRegistry.ts +20 -0
  345. package/src/telemetry/NostrSpanProcessor.ts +89 -0
  346. package/src/telemetry/ToolCallSpanProcessor.ts +66 -0
  347. package/src/telemetry/diagnostics.ts +27 -0
  348. package/src/telemetry/setup.ts +120 -0
  349. package/src/tools/implementations/agents_discover.ts +121 -0
  350. package/src/tools/implementations/agents_hire.ts +127 -0
  351. package/src/tools/implementations/agents_list.ts +96 -0
  352. package/src/tools/implementations/agents_publish.ts +611 -0
  353. package/src/tools/implementations/agents_read.ts +173 -0
  354. package/src/tools/implementations/agents_write.ts +200 -0
  355. package/src/tools/implementations/ask.ts +411 -0
  356. package/src/tools/implementations/change_model.ts +141 -0
  357. package/src/tools/implementations/conversation_get.ts +661 -0
  358. package/src/tools/implementations/conversation_list.ts +377 -0
  359. package/src/tools/implementations/conversation_search.ts +370 -0
  360. package/src/tools/implementations/delegate.ts +327 -0
  361. package/src/tools/implementations/delegate_crossproject.ts +209 -0
  362. package/src/tools/implementations/delegate_followup.ts +300 -0
  363. package/src/tools/implementations/fs_edit.ts +162 -0
  364. package/src/tools/implementations/fs_glob.ts +182 -0
  365. package/src/tools/implementations/fs_grep.ts +513 -0
  366. package/src/tools/implementations/fs_read.ts +332 -0
  367. package/src/tools/implementations/fs_write.ts +113 -0
  368. package/src/tools/implementations/generate_image.ts +259 -0
  369. package/src/tools/implementations/home_fs.ts +515 -0
  370. package/src/tools/implementations/kill.ts +651 -0
  371. package/src/tools/implementations/learn.ts +166 -0
  372. package/src/tools/implementations/lesson-formatter.ts +38 -0
  373. package/src/tools/implementations/lesson_delete.ts +164 -0
  374. package/src/tools/implementations/lesson_get.ts +105 -0
  375. package/src/tools/implementations/lessons_list.ts +153 -0
  376. package/src/tools/implementations/mcp_resource_read.ts +161 -0
  377. package/src/tools/implementations/mcp_subscribe.ts +158 -0
  378. package/src/tools/implementations/mcp_subscription_stop.ts +85 -0
  379. package/src/tools/implementations/nostr_fetch.ts +149 -0
  380. package/src/tools/implementations/nostr_publish_as_user.ts +353 -0
  381. package/src/tools/implementations/project_list.ts +146 -0
  382. package/src/tools/implementations/rag_add_documents.ts +573 -0
  383. package/src/tools/implementations/rag_create_collection.ts +65 -0
  384. package/src/tools/implementations/rag_delete_collection.ts +68 -0
  385. package/src/tools/implementations/rag_list_collections.ts +77 -0
  386. package/src/tools/implementations/rag_query.ts +107 -0
  387. package/src/tools/implementations/rag_subscription_create.ts +105 -0
  388. package/src/tools/implementations/rag_subscription_delete.ts +80 -0
  389. package/src/tools/implementations/rag_subscription_get.ts +123 -0
  390. package/src/tools/implementations/rag_subscription_list.ts +128 -0
  391. package/src/tools/implementations/report_delete.ts +79 -0
  392. package/src/tools/implementations/report_read.ts +160 -0
  393. package/src/tools/implementations/report_write.ts +278 -0
  394. package/src/tools/implementations/reports_list.ts +77 -0
  395. package/src/tools/implementations/schedule_task.ts +104 -0
  396. package/src/tools/implementations/schedule_task_cancel.ts +62 -0
  397. package/src/tools/implementations/schedule_task_once.ts +128 -0
  398. package/src/tools/implementations/schedule_tasks_list.ts +79 -0
  399. package/src/tools/implementations/search.ts +160 -0
  400. package/src/tools/implementations/shell.ts +553 -0
  401. package/src/tools/implementations/todo.ts +260 -0
  402. package/src/tools/implementations/upload_blob.ts +381 -0
  403. package/src/tools/implementations/web_fetch.ts +153 -0
  404. package/src/tools/implementations/web_search.ts +250 -0
  405. package/src/tools/registry.ts +670 -0
  406. package/src/tools/types.ts +177 -0
  407. package/src/tools/utils.ts +256 -0
  408. package/src/types/event-ids.ts +320 -0
  409. package/src/types/index.ts +46 -0
  410. package/src/utils/agentFetcher.ts +107 -0
  411. package/src/utils/cli-error.ts +29 -0
  412. package/src/utils/conversation-id.ts +27 -0
  413. package/src/utils/conversation-utils.ts +1 -0
  414. package/src/utils/delegation-chain.ts +357 -0
  415. package/src/utils/error-handler.ts +42 -0
  416. package/src/utils/git/gitignore.ts +69 -0
  417. package/src/utils/git/index.ts +2 -0
  418. package/src/utils/git/initializeGitRepo.ts +204 -0
  419. package/src/utils/git/worktree.ts +260 -0
  420. package/src/utils/lessonFormatter.ts +70 -0
  421. package/src/utils/lessonTrust.ts +24 -0
  422. package/src/utils/lockfile.ts +123 -0
  423. package/src/utils/logger.ts +149 -0
  424. package/src/utils/nostr-entity-parser.ts +365 -0
  425. package/src/utils/process.ts +49 -0
  426. package/src/wrapper.ts +262 -0
  427. package/tsconfig.json +41 -0
@@ -0,0 +1,618 @@
1
+ import * as fs from "node:fs/promises";
2
+ import { config } from "@/services/ConfigService";
3
+ import { getProjectContext, isProjectContextInitialized } from "@/services/projects";
4
+ import * as path from "node:path";
5
+ import { handleError } from "@/utils/error-handler";
6
+ import { logger } from "@/utils/logger";
7
+ import { RAGService } from "./RAGService";
8
+ import type { DocumentMetadata } from "./rag-utils";
9
+
10
+ /**
11
+ * RagSubscriptionService - Manages persistent RAG subscriptions to MCP resources
12
+ *
13
+ * This service enables automatic ingestion of MCP resource updates into RAG collections.
14
+ * When a resource is updated, the MCP server sends a notification, which is automatically
15
+ * processed and added to the configured RAG collection.
16
+ *
17
+ * Features:
18
+ * - Persistent subscriptions across restarts
19
+ * - Automatic reconnection on initialization
20
+ * - Error tracking and metrics
21
+ * - Fallback polling support for servers without subscription capabilities
22
+ */
23
+
24
+ type Notification = {
25
+ method: string;
26
+ params: Record<string, unknown>;
27
+ };
28
+
29
+ export enum SubscriptionStatus {
30
+ RUNNING = "RUNNING",
31
+ ERROR = "ERROR",
32
+ STOPPED = "STOPPED",
33
+ }
34
+
35
+ export interface RagSubscription {
36
+ subscriptionId: string;
37
+ agentPubkey: string;
38
+ mcpServerId: string;
39
+ resourceUri: string;
40
+ ragCollection: string;
41
+ description: string;
42
+ status: SubscriptionStatus;
43
+ documentsProcessed: number;
44
+ lastDocumentIngested?: string;
45
+ createdAt: number;
46
+ updatedAt: number;
47
+ lastError?: string;
48
+ }
49
+
50
+ export class RagSubscriptionService {
51
+ private static instance: RagSubscriptionService;
52
+ private subscriptions: Map<string, RagSubscription> = new Map();
53
+ private persistencePath: string;
54
+ private ragService: RAGService;
55
+ private isInitialized = false;
56
+ private resourceListeners: Map<string, (notification: Notification) => void> = new Map();
57
+ /** Removal functions returned by MCPManager.addResourceNotificationHandler() */
58
+ private handlerRemovers: Map<string, () => void> = new Map();
59
+
60
+ private constructor() {
61
+ // Use global location for RAG subscriptions since it's a singleton
62
+ const tenexDir = config.getConfigPath();
63
+ this.persistencePath = path.join(tenexDir, "rag_subscriptions.json");
64
+ this.ragService = RAGService.getInstance();
65
+ }
66
+
67
+ public static getInstance(): RagSubscriptionService {
68
+ if (!RagSubscriptionService.instance) {
69
+ RagSubscriptionService.instance = new RagSubscriptionService();
70
+ }
71
+ return RagSubscriptionService.instance;
72
+ }
73
+
74
+ /**
75
+ * Reset the singleton instance (for testing purposes)
76
+ */
77
+ public static resetInstance(): void {
78
+ RagSubscriptionService.instance = undefined as unknown as RagSubscriptionService;
79
+ }
80
+
81
+ /**
82
+ * Initialize the service and restore subscriptions from disk
83
+ */
84
+ public async initialize(): Promise<void> {
85
+ if (this.isInitialized) {
86
+ return;
87
+ }
88
+
89
+ try {
90
+ // Ensure .tenex directory exists
91
+ const tenexDir = path.dirname(this.persistencePath);
92
+ await fs.mkdir(tenexDir, { recursive: true });
93
+
94
+ // Load existing subscriptions
95
+ await this.loadSubscriptions();
96
+
97
+ // Re-subscribe to all active subscriptions
98
+ for (const subscription of this.subscriptions.values()) {
99
+ if (subscription.status === SubscriptionStatus.RUNNING) {
100
+ await this.setupResourceSubscription(subscription);
101
+ }
102
+ }
103
+
104
+ this.isInitialized = true;
105
+ logger.info(
106
+ `RagSubscriptionService initialized with ${this.subscriptions.size} subscriptions`
107
+ );
108
+ } catch (error) {
109
+ handleError(error, "Failed to initialize RagSubscriptionService", {
110
+ logLevel: "error",
111
+ });
112
+ throw error;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Create a new RAG subscription
118
+ */
119
+ public async createSubscription(
120
+ subscriptionId: string,
121
+ agentPubkey: string,
122
+ mcpServerId: string,
123
+ resourceUri: string,
124
+ ragCollection: string,
125
+ description: string
126
+ ): Promise<RagSubscription> {
127
+ // Check if subscription already exists
128
+ if (this.subscriptions.has(subscriptionId)) {
129
+ throw new Error(`Subscription with ID '${subscriptionId}' already exists`);
130
+ }
131
+
132
+ // Validate resourceUri is a proper URI format
133
+ try {
134
+ new URL(resourceUri);
135
+ } catch {
136
+ throw new Error(
137
+ `Invalid resourceUri: "${resourceUri}". Resource URI must be a valid URI format (e.g., "nostr://feed/pubkey/kinds", "file:///path/to/file"). This appears to be a tool name or invalid format. If you're using a resource template, you must first expand it with parameters to get the actual URI.`
138
+ );
139
+ }
140
+
141
+ // Verify the RAG collection exists
142
+ const collections = await this.ragService.listCollections();
143
+ if (!collections.includes(ragCollection)) {
144
+ throw new Error(`RAG collection '${ragCollection}' does not exist`);
145
+ }
146
+
147
+ // Create subscription object
148
+ const subscription: RagSubscription = {
149
+ subscriptionId,
150
+ agentPubkey,
151
+ mcpServerId,
152
+ resourceUri,
153
+ ragCollection,
154
+ description,
155
+ status: SubscriptionStatus.RUNNING,
156
+ documentsProcessed: 0,
157
+ createdAt: Date.now(),
158
+ updatedAt: Date.now(),
159
+ };
160
+
161
+ try {
162
+ // Setup MCP resource subscription
163
+ await this.setupResourceSubscription(subscription);
164
+
165
+ // Store subscription
166
+ this.subscriptions.set(subscriptionId, subscription);
167
+ await this.saveSubscriptions();
168
+
169
+ logger.info(`Created RAG subscription '${subscriptionId}' for agent ${agentPubkey}`);
170
+ return subscription;
171
+ } catch (error) {
172
+ subscription.status = SubscriptionStatus.ERROR;
173
+ subscription.lastError = error instanceof Error ? error.message : "Unknown error";
174
+ handleError(error, `Failed to create subscription '${subscriptionId}'`, {
175
+ logLevel: "error",
176
+ });
177
+ throw error;
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Setup MCP resource subscription and listener
183
+ */
184
+ private async setupResourceSubscription(subscription: RagSubscription): Promise<void> {
185
+ const listenerKey = `${subscription.mcpServerId}:${subscription.resourceUri}`;
186
+
187
+ // Create listener for this resource.
188
+ // IMPORTANT: MCPManager fans out notifications to ALL handlers on a server,
189
+ // so we must filter by URI to avoid cross-subscription contamination.
190
+ const listener = async (notification: { uri: string; content?: string }): Promise<void> => {
191
+ if (notification.uri !== subscription.resourceUri) {
192
+ return;
193
+ }
194
+ await this.handleResourceUpdate(subscription, {
195
+ method: "notifications/resources/updated",
196
+ params: notification,
197
+ });
198
+ };
199
+
200
+ try {
201
+ // Validate that resourceUri is a proper URI format
202
+ try {
203
+ new URL(subscription.resourceUri);
204
+ } catch {
205
+ throw new Error(
206
+ `Invalid resourceUri: "${subscription.resourceUri}". Resource URI must be a valid URI format (e.g., "nostr://feed/pubkey/kinds", "file:///path/to/file"). This appears to be a tool name or invalid format. If you're using a resource template, you must first expand it with parameters to get the actual URI.`
207
+ );
208
+ }
209
+
210
+ // Get mcpManager from project context
211
+ const projectCtx = getProjectContext();
212
+ const mcpManager = projectCtx.mcpManager;
213
+ if (!mcpManager) {
214
+ throw new Error("MCPManager not available in project context");
215
+ }
216
+
217
+ // Try to subscribe to resource updates
218
+ let subscriptionSupported = true;
219
+ try {
220
+ // CRITICAL: Register handler FIRST, then subscribe
221
+ const removeHandler = mcpManager.addResourceNotificationHandler(subscription.mcpServerId, listener);
222
+
223
+ // Subscribe to resource updates
224
+ await mcpManager.subscribeToResource(
225
+ subscription.mcpServerId,
226
+ subscription.resourceUri
227
+ );
228
+
229
+ // Store listener reference and removal function for cleanup
230
+ this.resourceListeners.set(
231
+ listenerKey,
232
+ listener as unknown as (notification: Notification) => void
233
+ );
234
+ this.handlerRemovers.set(listenerKey, removeHandler);
235
+
236
+ logger.info(
237
+ `RAG subscription '${subscription.subscriptionId}' active with push notifications. ` +
238
+ `Listening for updates from ${subscription.mcpServerId}:${subscription.resourceUri}`
239
+ );
240
+ } catch (error) {
241
+ if (
242
+ error instanceof Error &&
243
+ error.message.includes("does not support resource subscriptions")
244
+ ) {
245
+ // Server doesn't support subscriptions, gracefully degrade to polling
246
+ subscriptionSupported = false;
247
+ logger.warn(
248
+ `Server '${subscription.mcpServerId}' does not support resource subscriptions. ` +
249
+ `Subscription '${subscription.subscriptionId}' will use polling mode. ` +
250
+ `Call pollResource() manually or set up a polling interval.`
251
+ );
252
+ // Don't exit - gracefully degrade to polling mode
253
+ } else {
254
+ throw error;
255
+ }
256
+ }
257
+
258
+ if (!subscriptionSupported) {
259
+ subscription.lastError = "Server does not support subscriptions - use polling mode";
260
+ }
261
+ } catch (error) {
262
+ subscription.status = SubscriptionStatus.ERROR;
263
+ subscription.lastError = error instanceof Error ? error.message : "Unknown error";
264
+ throw error;
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Handle resource update notifications
270
+ */
271
+ private async handleResourceUpdate(
272
+ subscription: RagSubscription,
273
+ notification: Notification
274
+ ): Promise<void> {
275
+ try {
276
+ // Extract content from notification
277
+ const content = this.extractContentFromNotification(notification);
278
+
279
+ if (!content) {
280
+ logger.warn(
281
+ `Received empty update for subscription '${subscription.subscriptionId}'`
282
+ );
283
+ return;
284
+ }
285
+
286
+ // Build metadata with provenance fields for filtering at query time
287
+ const metadata: DocumentMetadata = {
288
+ // Auto-inject provenance for filtering at query time
289
+ agent_pubkey: subscription.agentPubkey,
290
+ // Subscription-specific metadata
291
+ subscriptionId: subscription.subscriptionId,
292
+ mcpServerId: subscription.mcpServerId,
293
+ resourceUri: subscription.resourceUri,
294
+ timestamp: Date.now(),
295
+ };
296
+
297
+ // Add project_id if available from project context (uses NIP-33 address format)
298
+ if (isProjectContextInitialized()) {
299
+ try {
300
+ const projectCtx = getProjectContext();
301
+ const projectId = projectCtx.project.tagId();
302
+ if (projectId) {
303
+ metadata.project_id = projectId;
304
+ }
305
+ } catch (error) {
306
+ logger.debug("Project context error during RAG subscription update", { error });
307
+ }
308
+ }
309
+
310
+ // Add document to RAG collection
311
+ await this.ragService.addDocuments(subscription.ragCollection, [
312
+ {
313
+ content,
314
+ metadata,
315
+ source: `${subscription.mcpServerId}:${subscription.resourceUri}`,
316
+ timestamp: Date.now(),
317
+ },
318
+ ]);
319
+
320
+ // Update subscription metrics
321
+ subscription.documentsProcessed++;
322
+ subscription.lastDocumentIngested = content.substring(0, 200); // Store snippet
323
+ subscription.updatedAt = Date.now();
324
+ subscription.status = SubscriptionStatus.RUNNING;
325
+ subscription.lastError = undefined;
326
+
327
+ await this.saveSubscriptions();
328
+
329
+ logger.debug(
330
+ `Processed update for subscription '${subscription.subscriptionId}', total documents: ${subscription.documentsProcessed}`
331
+ );
332
+ } catch (error) {
333
+ subscription.status = SubscriptionStatus.ERROR;
334
+ subscription.lastError = error instanceof Error ? error.message : "Unknown error";
335
+ subscription.updatedAt = Date.now();
336
+ await this.saveSubscriptions();
337
+
338
+ handleError(
339
+ error,
340
+ `Failed to process update for subscription '${subscription.subscriptionId}'`,
341
+ { logLevel: "error" }
342
+ );
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Extract content from MCP notification
348
+ */
349
+ private extractContentFromNotification(notification: Notification): string {
350
+ // Handle different notification formats
351
+ if (typeof notification.params === "object" && notification.params !== null) {
352
+ if ("content" in notification.params) {
353
+ return String(notification.params.content);
354
+ }
355
+ if ("data" in notification.params) {
356
+ return JSON.stringify(notification.params.data);
357
+ }
358
+ if ("text" in notification.params) {
359
+ return String(notification.params.text);
360
+ }
361
+ }
362
+
363
+ // Fallback to stringifying the entire params
364
+ return JSON.stringify(notification.params);
365
+ }
366
+
367
+ /**
368
+ * List all subscriptions for an agent
369
+ */
370
+ public async listSubscriptions(agentPubkey: string): Promise<RagSubscription[]> {
371
+ const agentSubscriptions = Array.from(this.subscriptions.values()).filter(
372
+ (sub) => sub.agentPubkey === agentPubkey
373
+ );
374
+
375
+ return agentSubscriptions;
376
+ }
377
+
378
+ /**
379
+ * Get a specific subscription
380
+ */
381
+ public async getSubscription(
382
+ subscriptionId: string,
383
+ agentPubkey: string
384
+ ): Promise<RagSubscription | null> {
385
+ const subscription = this.subscriptions.get(subscriptionId);
386
+
387
+ if (!subscription || subscription.agentPubkey !== agentPubkey) {
388
+ return null;
389
+ }
390
+
391
+ return subscription;
392
+ }
393
+
394
+ /**
395
+ * Delete a subscription
396
+ */
397
+ public async deleteSubscription(subscriptionId: string, agentPubkey: string): Promise<boolean> {
398
+ const subscription = this.subscriptions.get(subscriptionId);
399
+
400
+ if (!subscription || subscription.agentPubkey !== agentPubkey) {
401
+ return false;
402
+ }
403
+
404
+ // Clean up MCP resources (best-effort — don't block deletion if MCP server lost state)
405
+ const listenerKey = `${subscription.mcpServerId}:${subscription.resourceUri}`;
406
+
407
+ // Remove notification handler from MCPManager dispatcher
408
+ const removeHandler = this.handlerRemovers.get(listenerKey);
409
+ if (removeHandler) {
410
+ try {
411
+ removeHandler();
412
+ this.handlerRemovers.delete(listenerKey);
413
+ } catch (error) {
414
+ // Keep the map entry on failure so a future retry can re-attempt removal
415
+ logger.warn(`Failed to remove handler for subscription '${subscriptionId}': ${error instanceof Error ? error.message : error}`);
416
+ }
417
+ }
418
+
419
+ if (this.resourceListeners.has(listenerKey)) {
420
+ try {
421
+ const projectCtx = getProjectContext();
422
+ const mcpManager = projectCtx.mcpManager;
423
+
424
+ if (mcpManager) {
425
+ // Best-effort: unsubscribe from the MCP resource
426
+ await mcpManager.unsubscribeFromResource(
427
+ subscription.mcpServerId,
428
+ subscription.resourceUri
429
+ );
430
+ }
431
+ } catch (error) {
432
+ // MCP server may have lost subscription state (e.g. after restart).
433
+ // Log and continue — we still need to remove the local record.
434
+ logger.warn(
435
+ `Best-effort MCP unsubscribe failed for subscription '${subscriptionId}': ${error instanceof Error ? error.message : error}`
436
+ );
437
+ }
438
+
439
+ this.resourceListeners.delete(listenerKey);
440
+ }
441
+
442
+ // Always remove the subscription from local state and persist
443
+ this.subscriptions.delete(subscriptionId);
444
+ await this.saveSubscriptions();
445
+
446
+ logger.info(`Deleted subscription '${subscriptionId}'`);
447
+ return true;
448
+ }
449
+
450
+ /**
451
+ * Load subscriptions from disk
452
+ */
453
+ private async loadSubscriptions(): Promise<void> {
454
+ try {
455
+ const data = await fs.readFile(this.persistencePath, "utf-8");
456
+ const subscriptions = JSON.parse(data) as RagSubscription[];
457
+
458
+ for (const subscription of subscriptions) {
459
+ this.subscriptions.set(subscription.subscriptionId, subscription);
460
+ }
461
+
462
+ logger.debug(`Loaded ${subscriptions.length} subscriptions from disk`);
463
+ } catch (error) {
464
+ // File doesn't exist yet, that's okay
465
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
466
+ handleError(error, "Failed to load subscriptions", { logLevel: "warn" });
467
+ }
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Save subscriptions to disk
473
+ */
474
+ private async saveSubscriptions(): Promise<void> {
475
+ try {
476
+ const subscriptions = Array.from(this.subscriptions.values());
477
+ await fs.writeFile(this.persistencePath, JSON.stringify(subscriptions, null, 2));
478
+ logger.debug(`Saved ${subscriptions.length} subscriptions to disk`);
479
+ } catch (error) {
480
+ handleError(error, "Failed to save subscriptions", { logLevel: "error" });
481
+ }
482
+ }
483
+
484
+ /**
485
+ * Get statistics for all subscriptions
486
+ */
487
+ public getStatistics(): {
488
+ total: number;
489
+ running: number;
490
+ error: number;
491
+ stopped: number;
492
+ totalDocuments: number;
493
+ } {
494
+ let running = 0;
495
+ let error = 0;
496
+ let stopped = 0;
497
+ let totalDocuments = 0;
498
+
499
+ for (const subscription of this.subscriptions.values()) {
500
+ totalDocuments += subscription.documentsProcessed;
501
+
502
+ switch (subscription.status) {
503
+ case SubscriptionStatus.RUNNING:
504
+ running++;
505
+ break;
506
+ case SubscriptionStatus.ERROR:
507
+ error++;
508
+ break;
509
+ case SubscriptionStatus.STOPPED:
510
+ stopped++;
511
+ break;
512
+ }
513
+ }
514
+
515
+ return {
516
+ total: this.subscriptions.size,
517
+ running,
518
+ error,
519
+ stopped,
520
+ totalDocuments,
521
+ };
522
+ }
523
+
524
+ /**
525
+ * Manually trigger a resource update for a subscription
526
+ *
527
+ * This is a workaround until MCP SDK supports resources/subscribe.
528
+ * Allows manual polling or webhook-triggered updates to be processed.
529
+ *
530
+ * @param subscriptionId - The subscription to update
531
+ * @param agentPubkey - Agent pubkey for authorization
532
+ * @param content - The resource content to ingest
533
+ */
534
+ public async manualResourceUpdate(
535
+ subscriptionId: string,
536
+ agentPubkey: string,
537
+ content: string
538
+ ): Promise<void> {
539
+ const subscription = this.subscriptions.get(subscriptionId);
540
+
541
+ if (!subscription || subscription.agentPubkey !== agentPubkey) {
542
+ throw new Error(`Subscription '${subscriptionId}' not found or unauthorized`);
543
+ }
544
+
545
+ // Simulate a notification
546
+ const notification: Notification = {
547
+ method: "notifications/resources/updated",
548
+ params: {
549
+ content,
550
+ uri: subscription.resourceUri,
551
+ timestamp: Date.now(),
552
+ },
553
+ };
554
+
555
+ await this.handleResourceUpdate(subscription, notification);
556
+ }
557
+
558
+ /**
559
+ * Poll a resource and update the subscription
560
+ *
561
+ * Fetches the current resource content via MCPManager and ingests it.
562
+ * This is a workaround until MCP SDK supports resources/subscribe.
563
+ *
564
+ * @param subscriptionId - The subscription to poll
565
+ * @param agentPubkey - Agent pubkey for authorization
566
+ */
567
+ public async pollResource(subscriptionId: string, agentPubkey: string): Promise<void> {
568
+ const subscription = this.subscriptions.get(subscriptionId);
569
+
570
+ if (!subscription || subscription.agentPubkey !== agentPubkey) {
571
+ throw new Error(`Subscription '${subscriptionId}' not found or unauthorized`);
572
+ }
573
+
574
+ try {
575
+ // Get mcpManager from project context
576
+ const projectCtx = getProjectContext();
577
+ const mcpManager = projectCtx.mcpManager;
578
+ if (!mcpManager) {
579
+ throw new Error("MCPManager not available in project context");
580
+ }
581
+
582
+ // Read the current resource content
583
+ const result = await mcpManager.readResource(
584
+ subscription.mcpServerId,
585
+ subscription.resourceUri
586
+ );
587
+
588
+ // Extract text content
589
+ for (const content of result.contents) {
590
+ if ("text" in content) {
591
+ // Create notification with the content
592
+ const notification: Notification = {
593
+ method: "notifications/resources/updated",
594
+ params: {
595
+ content: content.text,
596
+ uri: subscription.resourceUri,
597
+ timestamp: Date.now(),
598
+ },
599
+ };
600
+
601
+ await this.handleResourceUpdate(subscription, notification);
602
+ }
603
+ }
604
+
605
+ logger.debug(`Polled resource for subscription '${subscriptionId}'`);
606
+ } catch (error) {
607
+ subscription.status = SubscriptionStatus.ERROR;
608
+ subscription.lastError = error instanceof Error ? error.message : "Unknown error";
609
+ subscription.updatedAt = Date.now();
610
+ await this.saveSubscriptions();
611
+
612
+ handleError(error, `Failed to poll resource for subscription '${subscriptionId}'`, {
613
+ logLevel: "error",
614
+ });
615
+ throw error;
616
+ }
617
+ }
618
+ }