@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,672 @@
1
+ import type { AgentRegistry } from "@/agents/AgentRegistry";
2
+ import type { AgentInstance } from "@/agents/types";
3
+ import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
4
+ import type { MCPManager } from "@/services/mcp/MCPManager";
5
+ import { NudgeWhitelistService, type WhitelistItem } from "@/services/nudge";
6
+ import type { LessonComment } from "@/services/prompt-compiler";
7
+ import type { LocalReportStore } from "@/services/reports/LocalReportStore";
8
+ import type { ReportInfo } from "@/services/reports/ReportService";
9
+ import { articleToReportInfo } from "@/services/reports/articleUtils";
10
+ import type { ProjectStatusService } from "@/services/status/ProjectStatusService";
11
+ import { logger } from "@/utils/logger";
12
+ import type { Hexpubkey, NDKProject, NDKArticle } from "@nostr-dev-kit/ndk";
13
+
14
+ /**
15
+ * Resolve the Project Manager for a project.
16
+ *
17
+ * Priority order:
18
+ * 1. Global PM designation via kind 24020 event ["pm"] tag without a-tag (highest priority)
19
+ * 2. Project-scoped PM designation via kind 24020 event ["pm"] tag WITH a-tag (projectOverrides[dTag].isPM)
20
+ * 3. Local PM override for this specific project (pmOverrides) - legacy, for backward compatibility
21
+ * 4. Explicit PM designation in 31933 project tags (role="pm")
22
+ * 5. First agent from project tags
23
+ * 6. First agent in registry (fallback for projects with no agent tags)
24
+ *
25
+ * @param project - The NDKProject event
26
+ * @param agents - Map of agent slug to AgentInstance
27
+ * @param projectDTag - The project's dTag for checking project-scoped PM overrides
28
+ * @returns The resolved PM agent or undefined if no agents exist
29
+ * @throws Error if PM is designated but not loaded in registry
30
+ */
31
+ export function resolveProjectManager(
32
+ project: NDKProject,
33
+ agents: Map<string, AgentInstance>,
34
+ projectDTag: string | undefined
35
+ ): AgentInstance | undefined {
36
+ // Step 1: Check for global PM designation via kind 24020 ["pm"] tag (highest priority)
37
+ // Collect all agents with isPM=true to detect conflicts
38
+ const globalPMAgents: AgentInstance[] = [];
39
+ for (const agent of agents.values()) {
40
+ if (agent.isPM === true) {
41
+ globalPMAgents.push(agent);
42
+ }
43
+ }
44
+
45
+ if (globalPMAgents.length > 0) {
46
+ if (globalPMAgents.length > 1) {
47
+ // Warn about multiple global PM agents - this is a configuration issue
48
+ logger.warn("Multiple agents have global PM designation (isPM=true). Using first found.", {
49
+ pmAgents: globalPMAgents.map((a) => ({ slug: a.slug, name: a.name })),
50
+ selectedAgent: globalPMAgents[0].slug,
51
+ });
52
+ }
53
+
54
+ logger.info("Found global PM designation via kind 24020 event", {
55
+ agentName: globalPMAgents[0].name,
56
+ agentSlug: globalPMAgents[0].slug,
57
+ });
58
+ return globalPMAgents[0];
59
+ }
60
+
61
+ // Step 2: Check for project-scoped PM designation via kind 24020 with a-tag
62
+ if (projectDTag) {
63
+ for (const agent of agents.values()) {
64
+ if (agent.projectOverrides?.[projectDTag]?.isPM === true) {
65
+ logger.info("Found project-scoped PM designation via kind 24020 event", {
66
+ agentName: agent.name,
67
+ agentSlug: agent.slug,
68
+ projectDTag,
69
+ });
70
+ return agent;
71
+ }
72
+ }
73
+ }
74
+
75
+ // Step 3: Check for local PM override for this specific project (pmOverrides)
76
+ if (projectDTag) {
77
+ for (const agent of agents.values()) {
78
+ if (agent.pmOverrides?.[projectDTag] === true) {
79
+ logger.info("Found legacy PM override for project", {
80
+ agentName: agent.name,
81
+ agentSlug: agent.slug,
82
+ projectDTag,
83
+ });
84
+ return agent;
85
+ }
86
+ }
87
+ }
88
+
89
+ // Step 4: Check for explicit "pm" role in project tags
90
+ const pmAgentTag = project.tags.find(
91
+ (tag: string[]) => tag[0] === "agent" && tag[2] === "pm"
92
+ );
93
+
94
+ if (pmAgentTag?.[1]) {
95
+ const pmEventId = pmAgentTag[1];
96
+ logger.debug("Found explicit PM designation in project tags", { pmEventId });
97
+
98
+ for (const agent of agents.values()) {
99
+ if (agent.eventId === pmEventId) {
100
+ return agent;
101
+ }
102
+ }
103
+
104
+ throw new Error(
105
+ `Project Manager agent not found. PM agent (eventId: ${pmEventId}) not loaded in registry.`
106
+ );
107
+ }
108
+
109
+ // Step 5: Fallback to first agent from project tags
110
+ const firstAgentTag = project.tags.find(
111
+ (tag: string[]) => tag[0] === "agent" && tag[1]
112
+ );
113
+
114
+ if (firstAgentTag?.[1]) {
115
+ const pmEventId = firstAgentTag[1];
116
+ logger.debug("No explicit PM found, using first agent from project tags");
117
+
118
+ for (const agent of agents.values()) {
119
+ if (agent.eventId === pmEventId) {
120
+ return agent;
121
+ }
122
+ }
123
+
124
+ throw new Error(
125
+ `Project Manager agent not found. First agent (eventId: ${pmEventId}) not loaded in registry.`
126
+ );
127
+ }
128
+
129
+ // Step 6: No agent tags in project, use first from registry if any exist
130
+ if (agents.size > 0) {
131
+ const firstAgent = agents.values().next().value;
132
+ if (firstAgent) {
133
+ logger.info(
134
+ "No agent tags in project event, using first agent from registry as PM",
135
+ {
136
+ agentName: firstAgent.name,
137
+ agentSlug: firstAgent.slug,
138
+ }
139
+ );
140
+ return firstAgent;
141
+ }
142
+ }
143
+
144
+ // No agents at all
145
+ logger.warn(
146
+ "No agents found in project or registry. Project will run without a project manager."
147
+ );
148
+ return undefined;
149
+ }
150
+
151
+ /**
152
+ * ProjectContext provides system-wide access to loaded project and agents
153
+ * Initialized during "tenex project run" by ProjectManager
154
+ */
155
+ export class ProjectContext {
156
+ /**
157
+ * Event that represents this project, note that this is SIGNED
158
+ * by the USER, so this.project.pubkey is NOT the project's pubkey but the
159
+ * USER OWNER'S pubkey.
160
+ */
161
+ public project: NDKProject;
162
+
163
+ /**
164
+ * The project manager agent for this project
165
+ */
166
+ public projectManager?: AgentInstance;
167
+
168
+ /**
169
+ * Agent registry - single source of truth for all agents
170
+ */
171
+ public readonly agentRegistry: AgentRegistry;
172
+
173
+ /**
174
+ * Getter for agents map to maintain compatibility
175
+ */
176
+ get agents(): Map<string, AgentInstance> {
177
+ return this.agentRegistry.getAllAgentsMap();
178
+ }
179
+
180
+ /**
181
+ * Lessons learned by agents in this project
182
+ * Key: agent pubkey, Value: array of lessons (limited to most recent 50 per agent)
183
+ */
184
+ public readonly agentLessons: Map<string, NDKAgentLesson[]>;
185
+
186
+ /**
187
+ * Comments on agent lessons (kind 1111 events per NIP-22)
188
+ * Key: agent pubkey, Value: array of comments (limited to most recent 100 per agent)
189
+ */
190
+ public readonly agentComments: Map<string, LessonComment[]>;
191
+
192
+ /**
193
+ * Reports cache for this project
194
+ * Key: compound key "author:slug", Value: ReportInfo object
195
+ * Using compound key allows efficient lookup by both slug and author
196
+ */
197
+ public readonly reports: Map<string, ReportInfo>;
198
+
199
+ /**
200
+ * Maximum number of reports to cache per project (memory efficiency)
201
+ */
202
+ private static readonly MAX_REPORTS_CACHE_SIZE = 200;
203
+
204
+ /**
205
+ * Status publisher for immediately publishing project status updates
206
+ */
207
+ public statusPublisher?: ProjectStatusService;
208
+
209
+ /**
210
+ * MCP manager for this project's MCP tool access
211
+ */
212
+ public mcpManager?: MCPManager;
213
+
214
+ /**
215
+ * Local report store for this project's report storage.
216
+ * Each project has its own store to ensure isolation.
217
+ */
218
+ public localReportStore?: LocalReportStore;
219
+
220
+ /**
221
+ * @deprecated Nudge whitelist is now user-scoped, not project-scoped.
222
+ * Use NudgeSkillWhitelistService.getInstance() directly instead.
223
+ * Retained as a backward-compatible shim; callers should migrate to the singleton.
224
+ */
225
+ public nudgeWhitelist: NudgeWhitelistService;
226
+
227
+ /**
228
+ * Callback invoked when a new agent is added to this project's registry.
229
+ * Used by Daemon to synchronize its routing map (agentPubkeyToProjects).
230
+ *
231
+ * Set via setOnAgentAdded() - typically by the Daemon during runtime startup.
232
+ */
233
+ private onAgentAddedCallback?: (agent: AgentInstance) => void;
234
+
235
+ constructor(project: NDKProject, agentRegistry: AgentRegistry) {
236
+ this.project = project;
237
+ this.agentRegistry = agentRegistry;
238
+
239
+ const agents = agentRegistry.getAllAgentsMap();
240
+ const projectDTag = project.dTag || project.tagValue("d");
241
+
242
+ // Debug logging
243
+ logger.debug("Initializing ProjectContext", {
244
+ projectId: project.id,
245
+ projectTitle: project.tagValue("title"),
246
+ projectDTag,
247
+ agentsCount: agents.size,
248
+ agentSlugs: Array.from(agents.keys()),
249
+ agentDetails: Array.from(agents.entries()).map(([slug, agent]) => ({
250
+ slug,
251
+ name: agent.name,
252
+ eventId: agent.eventId,
253
+ })),
254
+ });
255
+
256
+ // Use consolidated PM resolution logic
257
+ const projectManagerAgent = resolveProjectManager(project, agents, projectDTag);
258
+
259
+ if (projectManagerAgent) {
260
+ logger.info(`Using "${projectManagerAgent.name}" as Project Manager`);
261
+ this.projectManager = projectManagerAgent;
262
+ }
263
+
264
+ this.agentLessons = new Map();
265
+ this.agentComments = new Map();
266
+ this.reports = new Map();
267
+
268
+ // Reference the daemon-scoped nudge whitelist singleton
269
+ this.nudgeWhitelist = NudgeWhitelistService.getInstance();
270
+ }
271
+
272
+ /**
273
+ * @deprecated Nudge whitelist is now initialized at daemon level (user-scoped).
274
+ * This method is a no-op. See Daemon.ts step 6d.
275
+ */
276
+ initializeNudgeWhitelist(_additionalPubkeys: string[] = []): void {
277
+ logger.debug("initializeNudgeWhitelist is deprecated — nudge whitelist is now initialized at daemon level");
278
+ }
279
+
280
+ /**
281
+ * @deprecated Use NudgeSkillWhitelistService.getInstance().getWhitelistedNudges() directly.
282
+ * Nudges are user-scoped, not project-scoped.
283
+ */
284
+ getAvailableNudges(): WhitelistItem[] {
285
+ return this.nudgeWhitelist.getWhitelistedNudges();
286
+ }
287
+
288
+ // =====================================================================================
289
+ // AGENT ACCESS HELPERS
290
+ // =====================================================================================
291
+
292
+ getAgent(slug: string): AgentInstance | undefined {
293
+ return this.agentRegistry.getAgent(slug);
294
+ }
295
+
296
+ getAgentByPubkey(pubkey: Hexpubkey): AgentInstance | undefined {
297
+ return this.agentRegistry.getAgentByPubkey(pubkey);
298
+ }
299
+
300
+ getProjectManager(): AgentInstance {
301
+ if (!this.projectManager) {
302
+ throw new Error("Project manager not initialized");
303
+ }
304
+ return this.projectManager;
305
+ }
306
+
307
+ getAgentSlugs(): string[] {
308
+ return Array.from(this.agentRegistry.getAllAgentsMap().keys());
309
+ }
310
+
311
+ hasAgent(slug: string): boolean {
312
+ return this.agentRegistry.getAgent(slug) !== undefined;
313
+ }
314
+
315
+ /**
316
+ * Register a callback to be invoked when a new agent is added to this project.
317
+ * Used by the Daemon to keep its routing map (agentPubkeyToProjects) synchronized.
318
+ *
319
+ * @param callback - Function to invoke with the newly added agent
320
+ */
321
+ setOnAgentAdded(callback: (agent: AgentInstance) => void): void {
322
+ this.onAgentAddedCallback = callback;
323
+ }
324
+
325
+ /**
326
+ * Notify that a new agent has been added to the registry.
327
+ * This triggers the onAgentAdded callback if one is registered.
328
+ *
329
+ * Called by AgentRegistry.addAgent() when running within this context.
330
+ */
331
+ notifyAgentAdded(agent: AgentInstance): void {
332
+ if (this.onAgentAddedCallback) {
333
+ this.onAgentAddedCallback(agent);
334
+ }
335
+ }
336
+
337
+ // =====================================================================================
338
+ // LESSON MANAGEMENT
339
+ // =====================================================================================
340
+
341
+ /**
342
+ * Add a lesson for an agent, maintaining the 50-lesson limit per agent.
343
+ */
344
+ addLesson(agentPubkey: string, lesson: NDKAgentLesson): void {
345
+ const existingLessons = this.agentLessons.get(agentPubkey) || [];
346
+
347
+ // Add the new lesson at the beginning (most recent first)
348
+ const updatedLessons = [lesson, ...existingLessons];
349
+
350
+ // Keep only the most recent 50 lessons
351
+ const limitedLessons = updatedLessons.slice(0, 50);
352
+
353
+ this.agentLessons.set(agentPubkey, limitedLessons);
354
+ }
355
+
356
+ /**
357
+ * Remove a lesson for an agent by event ID.
358
+ * @returns true if the lesson was found and removed, false otherwise
359
+ */
360
+ removeLesson(agentPubkey: string, eventId: string): boolean {
361
+ const lessons = this.agentLessons.get(agentPubkey);
362
+ if (!lessons) {
363
+ return false;
364
+ }
365
+
366
+ const index = lessons.findIndex((l) => l.id === eventId);
367
+ if (index === -1) {
368
+ return false;
369
+ }
370
+
371
+ const newLessons = [...lessons.slice(0, index), ...lessons.slice(index + 1)];
372
+ this.agentLessons.set(agentPubkey, newLessons);
373
+
374
+ logger.debug("ProjectContext: removed lesson from cache", {
375
+ agentPubkey: agentPubkey.substring(0, 8),
376
+ eventId: eventId.substring(0, 8),
377
+ remainingLessons: newLessons.length,
378
+ });
379
+
380
+ return true;
381
+ }
382
+
383
+ /**
384
+ * Get lessons for a specific agent
385
+ */
386
+ getLessonsForAgent(agentPubkey: string): NDKAgentLesson[] {
387
+ return this.agentLessons.get(agentPubkey) || [];
388
+ }
389
+
390
+ /**
391
+ * Get all lessons across all agents
392
+ */
393
+ getAllLessons(): NDKAgentLesson[] {
394
+ return Array.from(this.agentLessons.values()).flat();
395
+ }
396
+
397
+ // =====================================================================================
398
+ // COMMENT MANAGEMENT (kind 1111 NIP-22 comments on lessons)
399
+ // =====================================================================================
400
+
401
+ /**
402
+ * Maximum number of comments to store per agent (memory efficiency)
403
+ */
404
+ private static readonly MAX_COMMENTS_PER_AGENT = 100;
405
+
406
+ /**
407
+ * Add a comment for an agent, maintaining the 100-comment limit per agent.
408
+ * Comments are de-duplicated by event ID.
409
+ */
410
+ addComment(agentPubkey: string, comment: LessonComment): void {
411
+ const existingComments = this.agentComments.get(agentPubkey) || [];
412
+
413
+ // Check for duplicates
414
+ if (existingComments.some((c) => c.id === comment.id)) {
415
+ return;
416
+ }
417
+
418
+ // Add the new comment at the beginning (most recent first)
419
+ const updatedComments = [comment, ...existingComments];
420
+
421
+ // Keep only the most recent comments
422
+ const limitedComments = updatedComments.slice(0, ProjectContext.MAX_COMMENTS_PER_AGENT);
423
+
424
+ this.agentComments.set(agentPubkey, limitedComments);
425
+
426
+ logger.debug("ProjectContext: added comment for agent", {
427
+ agentPubkey: agentPubkey.substring(0, 8),
428
+ commentId: comment.id.substring(0, 8),
429
+ lessonEventId: comment.lessonEventId.substring(0, 8),
430
+ totalComments: limitedComments.length,
431
+ });
432
+ }
433
+
434
+ /**
435
+ * Get comments for a specific agent
436
+ */
437
+ getCommentsForAgent(agentPubkey: string): LessonComment[] {
438
+ return this.agentComments.get(agentPubkey) || [];
439
+ }
440
+
441
+ /**
442
+ * Get comments for a specific lesson event ID
443
+ */
444
+ getCommentsForLesson(agentPubkey: string, lessonEventId: string): LessonComment[] {
445
+ const comments = this.agentComments.get(agentPubkey) || [];
446
+ return comments.filter((c) => c.lessonEventId === lessonEventId);
447
+ }
448
+
449
+ // =====================================================================================
450
+ // REPORT MANAGEMENT
451
+ // =====================================================================================
452
+
453
+ /**
454
+ * Generate a compound key for report storage
455
+ */
456
+ private static reportKey(authorPubkey: string, slug: string): string {
457
+ return `${authorPubkey}:${slug}`;
458
+ }
459
+
460
+ /**
461
+ * Add or update a report in the cache
462
+ * @param report The report info to add/update
463
+ */
464
+ addReport(report: ReportInfo): void {
465
+ // Get author hex pubkey from report
466
+ const authorPubkey = this.extractPubkeyFromReport(report);
467
+ if (!authorPubkey) {
468
+ logger.warn("Cannot add report without author pubkey", { slug: report.slug });
469
+ return;
470
+ }
471
+
472
+ const key = ProjectContext.reportKey(authorPubkey, report.slug);
473
+
474
+ // Check if this is a deleted report
475
+ if (report.isDeleted) {
476
+ // Remove from cache instead of adding
477
+ this.reports.delete(key);
478
+ logger.debug("📰 Removed deleted report from cache", {
479
+ slug: report.slug,
480
+ author: authorPubkey.substring(0, 8),
481
+ });
482
+ return;
483
+ }
484
+
485
+ // Add/update the report
486
+ this.reports.set(key, report);
487
+
488
+ // Enforce cache size limit (LRU-style: oldest entries first based on Map insertion order)
489
+ if (this.reports.size > ProjectContext.MAX_REPORTS_CACHE_SIZE) {
490
+ const oldestKey = this.reports.keys().next().value;
491
+ if (oldestKey) {
492
+ this.reports.delete(oldestKey);
493
+ logger.debug("📰 Evicted oldest report from cache due to size limit");
494
+ }
495
+ }
496
+
497
+ logger.debug("📰 Added/updated report in cache", {
498
+ slug: report.slug,
499
+ author: authorPubkey.substring(0, 8),
500
+ cacheSize: this.reports.size,
501
+ });
502
+ }
503
+
504
+ /**
505
+ * Add a report directly from an NDKArticle event
506
+ * Converts the article to ReportInfo and adds to cache
507
+ */
508
+ addReportFromArticle(article: NDKArticle): void {
509
+ const report = articleToReportInfo(article);
510
+ this.addReport(report);
511
+ }
512
+
513
+ /**
514
+ * Get a report by slug for a specific agent
515
+ */
516
+ getReport(agentPubkey: string, slug: string): ReportInfo | undefined {
517
+ const key = ProjectContext.reportKey(agentPubkey, slug);
518
+ return this.reports.get(key);
519
+ }
520
+
521
+ /**
522
+ * Get a report by slug (searches all authors)
523
+ * Returns the first match found
524
+ */
525
+ getReportBySlug(slug: string): ReportInfo | undefined {
526
+ for (const report of this.reports.values()) {
527
+ if (report.slug === slug) {
528
+ return report;
529
+ }
530
+ }
531
+ return undefined;
532
+ }
533
+
534
+ /**
535
+ * Get all reports from the cache
536
+ */
537
+ getAllReports(): ReportInfo[] {
538
+ return Array.from(this.reports.values());
539
+ }
540
+
541
+ /**
542
+ * Get reports for a specific agent by pubkey
543
+ */
544
+ getReportsForAgent(agentPubkey: string): ReportInfo[] {
545
+ const reports: ReportInfo[] = [];
546
+ const prefix = `${agentPubkey}:`;
547
+ for (const [key, report] of this.reports) {
548
+ if (key.startsWith(prefix)) {
549
+ reports.push(report);
550
+ }
551
+ }
552
+ return reports;
553
+ }
554
+
555
+ /**
556
+ * Get all memorized reports (reports tagged with memorize=true)
557
+ */
558
+ getMemorizedReports(): ReportInfo[] {
559
+ return Array.from(this.reports.values()).filter((report) => report.isMemorized);
560
+ }
561
+
562
+ /**
563
+ * Get memorized reports for a specific agent
564
+ */
565
+ getMemorizedReportsForAgent(agentPubkey: string): ReportInfo[] {
566
+ return this.getReportsForAgent(agentPubkey).filter((report) => report.isMemorized);
567
+ }
568
+
569
+ /**
570
+ * Get all team-memorized reports (reports tagged with memorize_team=true).
571
+ * These reports are injected into ALL agents' system prompts.
572
+ */
573
+ getTeamMemorizedReports(): ReportInfo[] {
574
+ return Array.from(this.reports.values()).filter((report) => report.isMemorizedTeam);
575
+ }
576
+
577
+ /**
578
+ * Get reports by hashtag
579
+ */
580
+ getReportsByHashtag(hashtag: string): ReportInfo[] {
581
+ return Array.from(this.reports.values()).filter(
582
+ (report) => report.hashtags?.includes(hashtag)
583
+ );
584
+ }
585
+
586
+ /**
587
+ * Get report cache statistics
588
+ */
589
+ getReportCacheStats(): { total: number; memorized: number; byAuthor: Record<string, number> } {
590
+ const byAuthor: Record<string, number> = {};
591
+ let memorized = 0;
592
+
593
+ for (const report of this.reports.values()) {
594
+ const author = this.extractPubkeyFromReport(report) || "unknown";
595
+ byAuthor[author.substring(0, 8)] = (byAuthor[author.substring(0, 8)] || 0) + 1;
596
+ if (report.isMemorized) memorized++;
597
+ }
598
+
599
+ return {
600
+ total: this.reports.size,
601
+ memorized,
602
+ byAuthor,
603
+ };
604
+ }
605
+
606
+ /**
607
+ * Clear all reports from cache
608
+ */
609
+ clearReports(): void {
610
+ this.reports.clear();
611
+ }
612
+
613
+ /**
614
+ * Extract pubkey from report. Author is stored as hex pubkey.
615
+ */
616
+ private extractPubkeyFromReport(report: ReportInfo): string | undefined {
617
+ return report.author;
618
+ }
619
+
620
+ /**
621
+ * Safely update project data without creating a new instance.
622
+ * This ensures all parts of the system work with consistent state.
623
+ */
624
+ async updateProjectData(newProject: NDKProject): Promise<void> {
625
+ this.project = newProject;
626
+
627
+ // Reload agents from project
628
+ await this.agentRegistry.loadFromProject(newProject);
629
+
630
+ const agents = this.agentRegistry.getAllAgentsMap();
631
+ const projectDTag = newProject.dTag || newProject.tagValue("d");
632
+
633
+ // Use consolidated PM resolution logic (same as constructor)
634
+ try {
635
+ const newPM = resolveProjectManager(newProject, agents, projectDTag);
636
+ if (newPM) {
637
+ this.projectManager = newPM;
638
+ }
639
+ } catch (error) {
640
+ logger.error("Failed to resolve project manager in updateProjectData", { error });
641
+ // Keep existing PM if resolution fails
642
+ }
643
+
644
+ logger.info("ProjectContext updated with new data", {
645
+ projectId: newProject.id,
646
+ projectTitle: newProject.tagValue("title"),
647
+ totalAgents: agents.size,
648
+ agentSlugs: Array.from(agents.keys()),
649
+ projectManager: this.projectManager?.slug,
650
+ });
651
+ }
652
+ }
653
+
654
+ import { projectContextStore } from "./ProjectContextStore";
655
+
656
+ /**
657
+ * Get the current project context from AsyncLocalStorage.
658
+ * This is the ONLY way to access project context - it must be set via
659
+ * projectContextStore.run(context, async () => {...})
660
+ *
661
+ * @throws Error if no context is available (not inside a .run() call)
662
+ */
663
+ export function getProjectContext(): ProjectContext {
664
+ return projectContextStore.getContextOrThrow();
665
+ }
666
+
667
+ /**
668
+ * Check if project context is initialized in current async context
669
+ */
670
+ export function isProjectContextInitialized(): boolean {
671
+ return projectContextStore.hasContext();
672
+ }