@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,119 @@
1
+ import { NDKKind } from "@/nostr/kinds";
2
+ import type { Hexpubkey, NDKFilter } from "@nostr-dev-kit/ndk";
3
+
4
+ /**
5
+ * Static utility class for building NDK subscription filters.
6
+ *
7
+ * Each method builds filters for one independent subscription group.
8
+ * The SubscriptionManager calls these individually rather than
9
+ * combining them into a single monolithic filter set.
10
+ */
11
+ export class SubscriptionFilterBuilder {
12
+ /**
13
+ * Build filters for the static subscription (created once at boot, never recreated).
14
+ * Includes:
15
+ * - Project discovery (kind 31933) from whitelisted pubkeys
16
+ * - Agent config updates (kind 24020) from whitelisted pubkeys
17
+ * - Lesson comments (kind 1111, #K: 4129) from whitelisted pubkeys
18
+ */
19
+ static buildStaticFilters(whitelistedPubkeys: Set<Hexpubkey>): NDKFilter[] {
20
+ if (whitelistedPubkeys.size === 0) {
21
+ return [];
22
+ }
23
+
24
+ const authors = Array.from(whitelistedPubkeys);
25
+
26
+ return [
27
+ // Project discovery + agent config updates + agent deletions
28
+ {
29
+ kinds: [31933, NDKKind.TenexAgentConfigUpdate, NDKKind.TenexAgentDelete],
30
+ authors,
31
+ },
32
+ // Lesson comments from whitelisted authors
33
+ // No #p filter — the Daemon uses the E tag to route to the correct agent
34
+ {
35
+ kinds: [NDKKind.Comment],
36
+ "#K": [String(NDKKind.AgentLesson)],
37
+ authors,
38
+ },
39
+ ];
40
+ }
41
+
42
+ /**
43
+ * Build filter for events tagging known projects via A-tags
44
+ * Receives all events tagged to our projects — the Daemon decides
45
+ * which events can boot a cold project vs which require a running one
46
+ * @param knownProjects - Set of project IDs (format: "31933:authorPubkey:dTag")
47
+ * @param since - Optional Unix timestamp (seconds) to filter out historical events
48
+ * @returns NDKFilter for project-tagged events or null if no projects
49
+ */
50
+ static buildProjectTaggedFilter(knownProjects: Set<string>, since?: number): NDKFilter | null {
51
+ if (knownProjects.size === 0) {
52
+ return null;
53
+ }
54
+
55
+ const filter: NDKFilter = {
56
+ "#a": Array.from(knownProjects),
57
+ limit: 0,
58
+ };
59
+
60
+ if (since !== undefined) {
61
+ filter.since = since;
62
+ }
63
+
64
+ return filter;
65
+ }
66
+
67
+ /**
68
+ * Build filter for report events (kind 30023 - NDKArticle)
69
+ * Monitors reports tagged with our project
70
+ * @param knownProjects - Set of project A-tags (format: "31933:authorPubkey:dTag")
71
+ * @returns NDKFilter for report events or null if no projects
72
+ */
73
+ static buildReportFilter(knownProjects: Set<string>): NDKFilter | null {
74
+ if (knownProjects.size === 0) {
75
+ return null;
76
+ }
77
+
78
+ return {
79
+ kinds: [30023],
80
+ "#a": Array.from(knownProjects),
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Build filter for events mentioning agents via P-tags
86
+ * @param agentPubkeys - Set of agent pubkeys to monitor
87
+ * @param since - Optional Unix timestamp (seconds) to filter out historical events
88
+ * @returns NDKFilter for agent mentions or null if no agents
89
+ */
90
+ static buildAgentMentionsFilter(agentPubkeys: Set<Hexpubkey>, since?: number): NDKFilter | null {
91
+ if (agentPubkeys.size === 0) {
92
+ return null;
93
+ }
94
+
95
+ const filter: NDKFilter = {
96
+ "#p": Array.from(agentPubkeys),
97
+ limit: 0,
98
+ };
99
+
100
+ if (since !== undefined) {
101
+ filter.since = since;
102
+ }
103
+
104
+ return filter;
105
+ }
106
+
107
+ /**
108
+ * Build filter for a single agent's lessons by definition event ID.
109
+ * Uses #e tag to match lessons that reference the agent definition.
110
+ * @param definitionId - Agent definition event ID
111
+ * @returns NDKFilter for this agent's lessons
112
+ */
113
+ static buildLessonFilter(definitionId: string): NDKFilter {
114
+ return {
115
+ kinds: [NDKKind.AgentLesson],
116
+ "#e": [definitionId],
117
+ };
118
+ }
119
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Daemon Module
3
+ *
4
+ * This module implements a single-process daemon that manages multiple projects
5
+ * and agents.
6
+ */
7
+
8
+ export { getDaemon } from "./Daemon";
9
+ export { UnixSocketTransport } from "./UnixSocketTransport";
@@ -0,0 +1,491 @@
1
+ import { AgentEventDecoder } from "@/nostr/AgentEventDecoder";
2
+ import { logger } from "@/utils/logger";
3
+ import type { Hexpubkey, NDKEvent } from "@nostr-dev-kit/ndk";
4
+ import type { NDKProject } from "@nostr-dev-kit/ndk";
5
+ import type { ProjectRuntime } from "../ProjectRuntime";
6
+
7
+ /**
8
+ * Result of routing decision for an event
9
+ */
10
+ export interface RoutingDecision {
11
+ projectId: string | null;
12
+ method: "a_tag" | "p_tag_agent" | "none";
13
+ matchedTags: string[];
14
+ reason: string;
15
+ }
16
+
17
+ /**
18
+ * Static utility class for daemon-level event routing.
19
+ * Determines which project an event should be routed to based on tags.
20
+ *
21
+ * This is daemon-level routing (event -> project), separate from
22
+ * AgentRouter which handles project-level routing (event -> agent).
23
+ */
24
+ export class DaemonRouter {
25
+ /**
26
+ * Check if this daemon should trace this event.
27
+ *
28
+ * This balances two concerns:
29
+ * 1. Avoiding noisy traces when multiple daemons share relays
30
+ * 2. Allowing project discovery (bootstrap problem)
31
+ *
32
+ * The key insight: only trace events that this daemon will actually process.
33
+ * - Project events: Always trace from whitelisted authors (for discovery)
34
+ * - Other events: Only trace if we have a runtime OR event can boot one
35
+ *
36
+ * @param event - The event to check
37
+ * @param knownProjects - Map of project IDs this daemon controls
38
+ * @param knownAgentPubkeys - Set of agent pubkeys from project definitions
39
+ * @param whitelistedPubkeys - Array of pubkeys that can create projects
40
+ * @param activeRuntimes - Map of currently active project runtimes
41
+ * @returns true if the event should be traced by this daemon
42
+ */
43
+ static shouldTraceEvent(
44
+ event: NDKEvent,
45
+ knownProjects: Map<string, NDKProject>,
46
+ knownAgentPubkeys: Set<Hexpubkey>,
47
+ whitelistedPubkeys: Hexpubkey[],
48
+ activeRuntimes: Map<string, ProjectRuntime>
49
+ ): boolean {
50
+ // Never-route kinds don't need tracing at all
51
+ if (AgentEventDecoder.isNeverRouteKind(event)) {
52
+ logger.debug("shouldTraceEvent: never-route kind", { kind: event.kind });
53
+ return false;
54
+ }
55
+
56
+ // Project events from whitelisted authors should always be traced.
57
+ // This includes new projects we haven't seen yet (avoiding bootstrap problem).
58
+ if (AgentEventDecoder.isProjectEvent(event)) {
59
+ const isWhitelisted = whitelistedPubkeys.includes(event.pubkey);
60
+ logger.debug("shouldTraceEvent: project event", {
61
+ kind: event.kind,
62
+ author: event.pubkey.slice(0, 8),
63
+ isWhitelisted,
64
+ whitelistedCount: whitelistedPubkeys.length,
65
+ });
66
+ return isWhitelisted;
67
+ }
68
+
69
+ // Agent config updates (kind 24020) from whitelisted authors are handled
70
+ // at daemon level (no project routing needed for global updates).
71
+ if (AgentEventDecoder.isConfigUpdate(event)) {
72
+ const isWhitelisted = whitelistedPubkeys.includes(event.pubkey);
73
+ return isWhitelisted;
74
+ }
75
+
76
+ // Lesson events from our agents should be traced if we have a runtime
77
+ // for at least one of their projects.
78
+ if (AgentEventDecoder.isLessonEvent(event)) {
79
+ // Check if this agent's project has an active runtime
80
+ for (const [projectId] of activeRuntimes) {
81
+ if (knownAgentPubkeys.has(event.pubkey)) {
82
+ // Agent is known, check if their project is running
83
+ const project = knownProjects.get(projectId);
84
+ if (project) {
85
+ return true;
86
+ }
87
+ }
88
+ }
89
+ return false;
90
+ }
91
+
92
+ // For other events, we need to determine if we'd actually process them.
93
+ // This balances two concerns:
94
+ // 1. Boot events (kind:24000 and kind:1) must be able to start projects
95
+ // 2. Regular events should only trace if we have an active runtime (prevents "other backend" noise)
96
+
97
+ // kind:24000 (TenexBootProject) is an EXPLICIT boot request - always allow if project is known
98
+ // kind:1 (Text) can also boot projects (per routeEventToProject logic)
99
+ const isExplicitBootRequest = event.kind === 24000;
100
+ const canBootProject = event.kind === 1 || event.kind === 24000;
101
+
102
+ if (isExplicitBootRequest) {
103
+ logger.debug("shouldTraceEvent: boot request event", {
104
+ kind: event.kind,
105
+ author: event.pubkey.slice(0, 8),
106
+ aTags: event.tags.filter(t => t[0] === "a").map(t => t[1]),
107
+ });
108
+ }
109
+
110
+ // Check if event is authored by one of our agents with an active runtime
111
+ if (knownAgentPubkeys.has(event.pubkey)) {
112
+ // Find if any of our active runtimes contain this agent
113
+ for (const [, runtime] of activeRuntimes) {
114
+ const context = runtime.getContext();
115
+ if (context) {
116
+ const agent = context.agentRegistry.getAllAgents().find(a => a.pubkey === event.pubkey);
117
+ if (agent) {
118
+ return true;
119
+ }
120
+ }
121
+ }
122
+ // Agent known but no active runtime - don't trace
123
+ return false;
124
+ }
125
+
126
+ // Check for a-tags to our projects (NIP-33 addressable event references)
127
+ const aTags = event.tags.filter((t) => t[0] === "a");
128
+ for (const tag of aTags) {
129
+ const aTagValue = tag[1];
130
+ if (aTagValue && knownProjects.has(aTagValue)) {
131
+ // Project is known - trace if:
132
+ // 1. We have an active runtime, OR
133
+ // 2. This event can boot projects (kind:1 or kind:24000)
134
+ // CRITICAL: kind:1 events with explicit A-tags MUST trace even without runtime
135
+ // to prevent cross-project routing bugs when agents exist in multiple projects
136
+ const hasRuntime = activeRuntimes.has(aTagValue);
137
+ if (hasRuntime || canBootProject) {
138
+ logger.debug("shouldTraceEvent: accepting via A-tag", {
139
+ kind: event.kind,
140
+ projectId: aTagValue.slice(0, 30),
141
+ hasRuntime,
142
+ canBootProject,
143
+ });
144
+ return true;
145
+ }
146
+ // Known project but no active runtime and cannot boot - don't trace
147
+ logger.debug("shouldTraceEvent: rejecting - known project but no runtime", {
148
+ kind: event.kind,
149
+ projectId: aTagValue.slice(0, 30),
150
+ });
151
+ }
152
+ }
153
+
154
+ // Check for P-tags to our agents
155
+ const pTags = event.tags.filter((t) => t[0] === "p");
156
+ for (const tag of pTags) {
157
+ const pubkey = tag[1];
158
+ if (pubkey && knownAgentPubkeys.has(pubkey as Hexpubkey)) {
159
+ // Find if this agent's project has an active runtime
160
+ for (const [, runtime] of activeRuntimes) {
161
+ const context = runtime.getContext();
162
+ if (context) {
163
+ const agent = context.agentRegistry.getAllAgents().find(a => a.pubkey === pubkey);
164
+ if (agent) {
165
+ return true;
166
+ }
167
+ }
168
+ }
169
+ // Agent known but no active runtime - don't trace
170
+ return false;
171
+ }
172
+ }
173
+
174
+ // No match - don't trace
175
+ logger.debug("shouldTraceEvent: no match found", {
176
+ kind: event.kind,
177
+ author: event.pubkey.slice(0, 8),
178
+ aTags: aTags.map(t => t[1]?.slice(0, 20)),
179
+ pTags: pTags.map(t => t[1]?.slice(0, 8)),
180
+ knownProjectsCount: knownProjects.size,
181
+ activeRuntimesCount: activeRuntimes.size,
182
+ });
183
+ return false;
184
+ }
185
+
186
+ /**
187
+ * Determine which project an event should be routed to
188
+ * @param event - The event to route
189
+ * @param knownProjects - Map of known project IDs to NDKProject instances
190
+ * @param agentPubkeyToProjects - Map of agent pubkeys to their project IDs
191
+ * @param activeRuntimes - Map of active project runtimes (for agent lookup)
192
+ * @returns Routing decision with target project or null if no match
193
+ */
194
+ static determineTargetProject(
195
+ event: NDKEvent,
196
+ knownProjects: Map<string, NDKProject>,
197
+ agentPubkeyToProjects: Map<Hexpubkey, Set<string>>,
198
+ activeRuntimes: Map<string, ProjectRuntime>
199
+ ): RoutingDecision {
200
+ // Skip routing for global identity kinds (NIP-01, NIP-02)
201
+ // kind:0 (profile metadata) and kind:3 (contact list) are global user/agent identity
202
+ // and should never be routed to specific projects
203
+ if (event.kind === 0 || event.kind === 3) {
204
+ return {
205
+ projectId: null,
206
+ method: "none",
207
+ matchedTags: [],
208
+ reason: `Global identity kind (${event.kind}) - not project-specific`,
209
+ };
210
+ }
211
+
212
+ // Check for explicit project A-tags first (highest priority)
213
+ const routingByATag = this.routeByATag(event, knownProjects);
214
+ if (routingByATag) {
215
+ return routingByATag;
216
+ }
217
+
218
+ // Check for agent P-tags (find project by agent pubkey)
219
+ const routingByPTag = this.routeByPTag(
220
+ event,
221
+ knownProjects,
222
+ agentPubkeyToProjects,
223
+ activeRuntimes
224
+ );
225
+ if (routingByPTag) {
226
+ return routingByPTag;
227
+ }
228
+
229
+ // No match found
230
+ const aTags = event.tags.filter((t) => t[0] === "a");
231
+ const pTags = event.tags.filter((t) => t[0] === "p");
232
+ const projectATags = aTags.filter((t) => t[1]?.startsWith("31933:"));
233
+
234
+ const reason =
235
+ projectATags.length > 0
236
+ ? `A-tags found but no matching known projects: ${projectATags.map((t) => t[1]).join(", ")}`
237
+ : pTags.length > 0
238
+ ? `P-tags found but no matching agents: ${pTags.map((t) => t[1]?.slice(0, 8)).join(", ")}`
239
+ : "No A-tags or P-tags found";
240
+
241
+ logger.debug("No project match found", {
242
+ eventId: event.id.slice(0, 8),
243
+ reason,
244
+ });
245
+
246
+ return {
247
+ projectId: null,
248
+ method: "none",
249
+ matchedTags: [],
250
+ reason,
251
+ };
252
+ }
253
+
254
+ /**
255
+ * Route event based on `a` tags (explicit project references)
256
+ */
257
+ private static routeByATag(
258
+ event: NDKEvent,
259
+ knownProjects: Map<string, NDKProject>
260
+ ): RoutingDecision | null {
261
+ // NIP-33 addressable events use lowercase 'a' tags only
262
+ const aTags = event.tags.filter((t) => t[0] === "a");
263
+ const projectATags = aTags.filter((t) => t[1]?.startsWith("31933:"));
264
+
265
+ logger.debug("Checking a-tags for project routing", {
266
+ eventId: event.id.slice(0, 8),
267
+ aTagsFound: projectATags.length,
268
+ aTags: projectATags.map((t) => t[1]),
269
+ });
270
+
271
+ for (const tag of projectATags) {
272
+ const aTagValue = tag[1];
273
+ if (aTagValue && knownProjects.has(aTagValue)) {
274
+ const project = knownProjects.get(aTagValue);
275
+ if (!project) {
276
+ throw new Error(
277
+ `Project ${aTagValue} not found in knownProjects despite has() check`
278
+ );
279
+ }
280
+
281
+ logger.info("Routing event to project via a-tag", {
282
+ eventId: event.id.slice(0, 8),
283
+ eventKind: event.kind,
284
+ projectId: aTagValue,
285
+ projectTitle: project.tagValue("title"),
286
+ });
287
+
288
+ return {
289
+ projectId: aTagValue,
290
+ method: "a_tag",
291
+ matchedTags: [aTagValue],
292
+ reason: `Matched project a-tag: ${aTagValue}`,
293
+ };
294
+ }
295
+ }
296
+
297
+ if (projectATags.length > 0) {
298
+ logger.debug("A-tags found but no matching known projects", {
299
+ eventId: event.id.slice(0, 8),
300
+ projectATags: projectATags.map((t) => t[1]),
301
+ knownProjects: Array.from(knownProjects.keys()),
302
+ });
303
+ }
304
+
305
+ return null;
306
+ }
307
+
308
+ /**
309
+ * Route event based on P-tags (agent pubkey references)
310
+ *
311
+ * IMPORTANT: P-tag routing is fallback behavior when A-tag routing fails.
312
+ * When an agent exists in multiple projects, we ONLY route via P-tag if
313
+ * exactly one of those projects has an active runtime. This prevents
314
+ * cross-project routing bugs where an event intended for project A gets
315
+ * routed to project B because B happened to be running.
316
+ */
317
+ private static routeByPTag(
318
+ event: NDKEvent,
319
+ knownProjects: Map<string, NDKProject>,
320
+ agentPubkeyToProjects: Map<Hexpubkey, Set<string>>,
321
+ activeRuntimes: Map<string, ProjectRuntime>
322
+ ): RoutingDecision | null {
323
+ const pTags = event.tags.filter((t) => t[0] === "p");
324
+
325
+ logger.debug("Checking P-tags for agent routing", {
326
+ eventId: event.id.slice(0, 8),
327
+ pTagsFound: pTags.length,
328
+ pTags: pTags.map((t) => t[1]?.slice(0, 8)),
329
+ });
330
+
331
+ for (const tag of pTags) {
332
+ const pubkey = tag[1];
333
+ if (!pubkey) {
334
+ continue;
335
+ }
336
+
337
+ // Check if this pubkey belongs to any project's agents
338
+ const projectIds = agentPubkeyToProjects.get(pubkey as Hexpubkey);
339
+ if (!projectIds || projectIds.size === 0) {
340
+ continue;
341
+ }
342
+
343
+ // Find which of this agent's projects have active runtimes
344
+ const activeProjectsForAgent: Array<{
345
+ projectId: string;
346
+ project: NDKProject;
347
+ runtime: ProjectRuntime;
348
+ agent: { slug: string; pubkey: string };
349
+ }> = [];
350
+
351
+ for (const projectId of projectIds) {
352
+ const runtime = activeRuntimes.get(projectId);
353
+ if (!runtime) {
354
+ continue; // Project not running - skip
355
+ }
356
+
357
+ const project = knownProjects.get(projectId);
358
+ if (!project) {
359
+ logger.warn("routeByPTag: project in agentPubkeyToProjects but not in knownProjects", {
360
+ projectId: projectId.slice(0, 20),
361
+ agentPubkey: pubkey.slice(0, 8),
362
+ });
363
+ continue;
364
+ }
365
+
366
+ const context = runtime.getContext();
367
+ if (!context) {
368
+ logger.warn("routeByPTag: runtime has no context", {
369
+ projectId: projectId.slice(0, 20),
370
+ });
371
+ continue;
372
+ }
373
+
374
+ const agent = context.agentRegistry.getAllAgents().find((a) => a.pubkey === pubkey);
375
+ if (!agent) {
376
+ // Agent might have been removed from this project after mapping was created
377
+ logger.debug("routeByPTag: agent not found in project registry", {
378
+ projectId: projectId.slice(0, 20),
379
+ agentPubkey: pubkey.slice(0, 8),
380
+ });
381
+ continue;
382
+ }
383
+
384
+ activeProjectsForAgent.push({ projectId, project, runtime, agent });
385
+ }
386
+
387
+ // If no active projects found for this agent, skip to next P-tag
388
+ if (activeProjectsForAgent.length === 0) {
389
+ logger.debug("routeByPTag: no active projects for agent", {
390
+ agentPubkey: pubkey.slice(0, 8),
391
+ knownProjectCount: projectIds.size,
392
+ });
393
+ continue;
394
+ }
395
+
396
+ // CRITICAL: Only route via P-tag if there's exactly ONE active project
397
+ // If multiple projects are active with this agent, we can't determine
398
+ // the correct target - the event should have used an A-tag for disambiguation
399
+ if (activeProjectsForAgent.length > 1) {
400
+ logger.warn("routeByPTag: agent exists in multiple active projects - cannot disambiguate without A-tag", {
401
+ eventId: event.id?.slice(0, 8),
402
+ agentPubkey: pubkey.slice(0, 8),
403
+ activeProjects: activeProjectsForAgent.map(p => ({
404
+ projectId: p.projectId.slice(0, 20),
405
+ projectTitle: p.project.tagValue("title"),
406
+ })),
407
+ });
408
+ // Return null to indicate we couldn't route definitively
409
+ return null;
410
+ }
411
+
412
+ // Exactly one active project - safe to route
413
+ const { projectId, project, agent } = activeProjectsForAgent[0];
414
+
415
+ logger.info("Routing event to project via agent P-tag", {
416
+ eventId: event.id.slice(0, 8),
417
+ eventKind: event.kind,
418
+ projectId,
419
+ projectTitle: project.tagValue("title"),
420
+ agentPubkey: pubkey.slice(0, 8),
421
+ agentSlug: agent.slug,
422
+ });
423
+
424
+ return {
425
+ projectId,
426
+ method: "p_tag_agent",
427
+ matchedTags: [pubkey],
428
+ reason: `Matched agent P-tag: ${pubkey.slice(0, 8)}`,
429
+ };
430
+ }
431
+
432
+ return null;
433
+ }
434
+
435
+ /**
436
+ * Check if an event was published by an agent in the system
437
+ * @param event - The event to check
438
+ * @param agentPubkeyToProjects - Map of agent pubkeys to their projects
439
+ * @returns True if the event author is a known agent
440
+ */
441
+ static isAgentEvent(
442
+ event: NDKEvent,
443
+ agentPubkeyToProjects: Map<Hexpubkey, Set<string>>
444
+ ): boolean {
445
+ return agentPubkeyToProjects.has(event.pubkey);
446
+ }
447
+
448
+ /**
449
+ * Check if an event has p-tags pointing to system entities (whitelisted pubkeys or other agents)
450
+ * @param event - The event to check
451
+ * @param whitelistedPubkeys - Set of whitelisted user pubkeys
452
+ * @param agentPubkeyToProjects - Map of agent pubkeys to their projects
453
+ * @returns True if the event has p-tags to system entities
454
+ */
455
+ static hasPTagsToSystemEntities(
456
+ event: NDKEvent,
457
+ whitelistedPubkeys: Hexpubkey[],
458
+ agentPubkeyToProjects: Map<Hexpubkey, Set<string>>
459
+ ): boolean {
460
+ const pTags = event.tags.filter((t) => t[0] === "p");
461
+
462
+ for (const tag of pTags) {
463
+ const pubkey = tag[1];
464
+ if (!pubkey) {
465
+ continue;
466
+ }
467
+
468
+ // Check if p-tag points to a whitelisted pubkey
469
+ if (whitelistedPubkeys.includes(pubkey as Hexpubkey)) {
470
+ return true;
471
+ }
472
+
473
+ // Check if p-tag points to another agent in the system
474
+ if (agentPubkeyToProjects.has(pubkey as Hexpubkey)) {
475
+ return true;
476
+ }
477
+ }
478
+
479
+ return false;
480
+ }
481
+
482
+ /**
483
+ * Build project ID from event
484
+ * Format: "31933:authorPubkey:dTag"
485
+ * @param event - Project event (kind 31933)
486
+ * @returns Project ID string
487
+ */
488
+ static buildProjectId(event: NDKEvent): string {
489
+ return event.tagId();
490
+ }
491
+ }