@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,224 @@
1
+ import { getNDK } from "@/nostr";
2
+ import { TagExtractor } from "@/nostr/TagExtractor";
3
+ import { logger } from "@/utils/logger";
4
+ import type { NDKEvent } from "@nostr-dev-kit/ndk";
5
+ import { SpanStatusCode, context as otelContext, trace } from "@opentelemetry/api";
6
+ import type { NudgeResult, NudgeToolPermissions, NudgeData } from "./types";
7
+
8
+ const tracer = trace.getTracer("tenex.nudge-service");
9
+
10
+ /**
11
+ * Service for fetching and processing Agent Nudge events (kind:4201)
12
+ * Single Responsibility: Retrieve nudge content and concatenate for system prompt injection
13
+ */
14
+ export class NudgeService {
15
+ private static instance: NudgeService;
16
+
17
+ private constructor() {}
18
+
19
+ static getInstance(): NudgeService {
20
+ if (!NudgeService.instance) {
21
+ NudgeService.instance = new NudgeService();
22
+ }
23
+ return NudgeService.instance;
24
+ }
25
+
26
+ /**
27
+ * Fetch nudge events by IDs and concatenate their content
28
+ * @param eventIds Array of nudge event IDs to fetch
29
+ * @returns Concatenated content from all nudges, or empty string if none found
30
+ */
31
+ async fetchNudges(eventIds: string[]): Promise<string> {
32
+ if (eventIds.length === 0) {
33
+ return "";
34
+ }
35
+
36
+ const span = tracer.startSpan("tenex.nudge.fetch_nudges", {
37
+ attributes: {
38
+ "nudge.requested_count": eventIds.length,
39
+ },
40
+ }, otelContext.active());
41
+
42
+ return otelContext.with(trace.setSpan(otelContext.active(), span), async () => {
43
+ try {
44
+ const ndk = getNDK();
45
+ const nudgeEvents = await ndk.fetchEvents({
46
+ ids: eventIds,
47
+ });
48
+
49
+ const nudges = Array.from(nudgeEvents);
50
+ const concatenated = nudges
51
+ .map((nudge) => nudge.content.trim())
52
+ .filter((content) => content.length > 0)
53
+ .join("\n\n");
54
+
55
+ const nudgeTitles = nudges.map((n) => n.tagValue("title") || "untitled").join(", ");
56
+
57
+ span.setAttributes({
58
+ "nudge.fetched_count": nudges.length,
59
+ "nudge.content_length": concatenated.length,
60
+ "nudge.titles": nudgeTitles,
61
+ });
62
+
63
+ span.setStatus({ code: SpanStatusCode.OK });
64
+ span.end();
65
+ return concatenated;
66
+ } catch (error) {
67
+ span.recordException(error as Error);
68
+ span.setStatus({
69
+ code: SpanStatusCode.ERROR,
70
+ message: (error as Error).message,
71
+ });
72
+ span.end();
73
+ return "";
74
+ }
75
+ });
76
+ }
77
+
78
+ /**
79
+ * Fetch a single nudge event by ID
80
+ * @param eventId The nudge event ID
81
+ * @returns The nudge event or null if not found
82
+ */
83
+ async fetchNudge(eventId: string): Promise<NDKEvent | null> {
84
+ try {
85
+ const ndk = getNDK();
86
+ const events = await ndk.fetchEvents({
87
+ ids: [eventId],
88
+ });
89
+
90
+ const nudge = Array.from(events).find((event) => event.kind === 4201);
91
+ return nudge || null;
92
+ } catch (error) {
93
+ logger.error("[NudgeService] Failed to fetch nudge", { error, eventId });
94
+ return null;
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Fetch nudge events and extract both content and tool permissions.
100
+ * This method extracts:
101
+ * - only-tool tags: Highest priority, replaces ALL tools
102
+ * - allow-tool tags: Adds tools to agent's default set
103
+ * - deny-tool tags: Removes tools from agent's default set
104
+ *
105
+ * @param eventIds Array of nudge event IDs to fetch
106
+ * @returns NudgeResult with content and tool permissions
107
+ */
108
+ async fetchNudgesWithPermissions(eventIds: string[]): Promise<NudgeResult> {
109
+ const emptyResult: NudgeResult = {
110
+ nudges: [],
111
+ content: "",
112
+ toolPermissions: {},
113
+ };
114
+
115
+ if (eventIds.length === 0) {
116
+ return emptyResult;
117
+ }
118
+
119
+ const span = tracer.startSpan("tenex.nudge.fetch_nudges_with_permissions", {
120
+ attributes: {
121
+ "nudge.requested_count": eventIds.length,
122
+ },
123
+ }, otelContext.active());
124
+
125
+ return otelContext.with(trace.setSpan(otelContext.active(), span), async () => {
126
+ try {
127
+ const ndk = getNDK();
128
+ const nudgeEvents = await ndk.fetchEvents({
129
+ ids: eventIds,
130
+ });
131
+
132
+ const nudges = Array.from(nudgeEvents);
133
+
134
+ // Build nudge data array
135
+ const nudgeDataArray: NudgeData[] = nudges
136
+ .map((nudge) => ({
137
+ content: nudge.content.trim(),
138
+ title: nudge.tagValue("title") || undefined,
139
+ }))
140
+ .filter((data) => data.content.length > 0);
141
+
142
+ // Concatenate content for backward compatibility
143
+ const concatenated = nudgeDataArray
144
+ .map((data) => data.content)
145
+ .join("\n\n");
146
+
147
+ // Extract tool permissions from all nudges
148
+ const toolPermissions = this.extractToolPermissions(nudges);
149
+
150
+ const nudgeTitles = nudges.map((n) => n.tagValue("title") || "untitled").join(", ");
151
+
152
+ span.setAttributes({
153
+ "nudge.fetched_count": nudges.length,
154
+ "nudge.content_length": concatenated.length,
155
+ "nudge.titles": nudgeTitles,
156
+ "nudge.only_tools_count": toolPermissions.onlyTools?.length ?? 0,
157
+ "nudge.allow_tools_count": toolPermissions.allowTools?.length ?? 0,
158
+ "nudge.deny_tools_count": toolPermissions.denyTools?.length ?? 0,
159
+ });
160
+
161
+ span.setStatus({ code: SpanStatusCode.OK });
162
+ span.end();
163
+
164
+ return {
165
+ nudges: nudgeDataArray,
166
+ content: concatenated,
167
+ toolPermissions,
168
+ };
169
+ } catch (error) {
170
+ span.recordException(error as Error);
171
+ span.setStatus({
172
+ code: SpanStatusCode.ERROR,
173
+ message: (error as Error).message,
174
+ });
175
+ span.end();
176
+ logger.error("[NudgeService] Failed to fetch nudges with permissions", { error });
177
+ return emptyResult;
178
+ }
179
+ });
180
+ }
181
+
182
+ /**
183
+ * Extract tool permissions from nudge events.
184
+ * Collects all only-tool, allow-tool, and deny-tool tags across all nudges.
185
+ *
186
+ * @param nudges Array of nudge events
187
+ * @returns Aggregated tool permissions
188
+ */
189
+ private extractToolPermissions(nudges: NDKEvent[]): NudgeToolPermissions {
190
+ const permissions: NudgeToolPermissions = {};
191
+
192
+ const onlyTools: string[] = [];
193
+ const allowTools: string[] = [];
194
+ const denyTools: string[] = [];
195
+
196
+ for (const nudge of nudges) {
197
+ // Extract only-tool tags
198
+ const onlyToolValues = TagExtractor.getTagValues(nudge, "only-tool");
199
+ onlyTools.push(...onlyToolValues);
200
+
201
+ // Extract allow-tool tags
202
+ const allowToolValues = TagExtractor.getTagValues(nudge, "allow-tool");
203
+ allowTools.push(...allowToolValues);
204
+
205
+ // Extract deny-tool tags
206
+ const denyToolValues = TagExtractor.getTagValues(nudge, "deny-tool");
207
+ denyTools.push(...denyToolValues);
208
+ }
209
+
210
+ // Only set arrays if they have values (to keep the object clean)
211
+ if (onlyTools.length > 0) {
212
+ // Deduplicate and set
213
+ permissions.onlyTools = [...new Set(onlyTools)];
214
+ }
215
+ if (allowTools.length > 0) {
216
+ permissions.allowTools = [...new Set(allowTools)];
217
+ }
218
+ if (denyTools.length > 0) {
219
+ permissions.denyTools = [...new Set(denyTools)];
220
+ }
221
+
222
+ return permissions;
223
+ }
224
+ }
@@ -0,0 +1,382 @@
1
+ import { getNDK } from "@/nostr";
2
+ import { NDKKind } from "@/nostr/kinds";
3
+ import { logger } from "@/utils/logger";
4
+ import type { NDKEvent, NDKSubscription } from "@nostr-dev-kit/ndk";
5
+ import { SpanStatusCode, context as otelContext, trace } from "@opentelemetry/api";
6
+
7
+ const tracer = trace.getTracer("tenex.nudge-whitelist-service");
8
+
9
+ /**
10
+ * Categorized whitelist item - either a nudge or a skill
11
+ */
12
+ export interface WhitelistItem {
13
+ /** The event ID of the whitelisted nudge/skill */
14
+ eventId: string;
15
+ /** The kind of the referenced event (4201 for nudge, 4202 for skill) */
16
+ kind: typeof NDKKind.AgentNudge | typeof NDKKind.AgentSkill;
17
+ /** The name of the nudge/skill (from title tag) */
18
+ name?: string;
19
+ /** Description of the nudge/skill (full content - truncation is done in presentation layer) */
20
+ description?: string;
21
+ /** Pubkeys that have whitelisted this item (multiple whitelist events can reference same item) */
22
+ whitelistedBy: string[];
23
+ }
24
+
25
+ /**
26
+ * Cached whitelist data with fetch timestamp
27
+ */
28
+ interface WhitelistCache {
29
+ /** Whitelisted nudges (kind:4201) */
30
+ nudges: WhitelistItem[];
31
+ /** Whitelisted skills (kind:4202) */
32
+ skills: WhitelistItem[];
33
+ /** When this cache was last updated */
34
+ lastUpdated: number;
35
+ }
36
+
37
+ const REBUILD_DEBOUNCE_MS = 500;
38
+ const FETCH_TIMEOUT_MS = 10_000;
39
+
40
+ /**
41
+ * Service for managing nudge/skill whitelists.
42
+ *
43
+ * This service subscribes to kind:14202 events from whitelisted pubkeys,
44
+ * which are NIP-51-like lists that e-tag nudge (kind:4201) and skill (kind:4202) events.
45
+ *
46
+ * The service maintains a cached list of all whitelisted nudges and skills,
47
+ * categorized by their event kind. Cache is built incrementally as events
48
+ * stream in from the subscription — initialization never blocks on EOSE.
49
+ */
50
+ export class NudgeSkillWhitelistService {
51
+ private static instance: NudgeSkillWhitelistService;
52
+ private cache: WhitelistCache | null = null;
53
+ private subscription: NDKSubscription | null = null;
54
+ private whitelistPubkeys: Set<string> = new Set();
55
+ private initialized = false;
56
+
57
+ /** Latest kind:14202 event per author pubkey (replaceable semantics) */
58
+ private latestWhitelistEvents: Map<string, NDKEvent> = new Map();
59
+ /** Fetched nudge/skill events by ID — avoids re-fetching */
60
+ private referencedEventCache: Map<string, NDKEvent> = new Map();
61
+ /** Debounce timer for coalescing rapid event bursts */
62
+ private rebuildTimer: ReturnType<typeof setTimeout> | null = null;
63
+
64
+ private constructor() {}
65
+
66
+ static getInstance(): NudgeSkillWhitelistService {
67
+ if (!NudgeSkillWhitelistService.instance) {
68
+ NudgeSkillWhitelistService.instance = new NudgeSkillWhitelistService();
69
+ }
70
+ return NudgeSkillWhitelistService.instance;
71
+ }
72
+
73
+ /**
74
+ * Initialize the service with whitelisted pubkeys.
75
+ * Returns immediately — cache starts empty and populates as events stream in.
76
+ */
77
+ initialize(whitelistPubkeys: string[]): void {
78
+ if (this.initialized && this.pubkeysMatch(whitelistPubkeys)) {
79
+ logger.debug("[NudgeSkillWhitelistService] Already initialized with same pubkeys, skipping");
80
+ return;
81
+ }
82
+
83
+ this.whitelistPubkeys = new Set(whitelistPubkeys);
84
+ this.initialized = true;
85
+ this.cache = { nudges: [], skills: [], lastUpdated: Date.now() };
86
+
87
+ this.startSubscription();
88
+
89
+ logger.info("[NudgeSkillWhitelistService] Initialized", {
90
+ pubkeyCount: whitelistPubkeys.length,
91
+ });
92
+ }
93
+
94
+ /**
95
+ * Check if the given pubkeys match the currently configured whitelist
96
+ */
97
+ private pubkeysMatch(newPubkeys: string[]): boolean {
98
+ if (newPubkeys.length !== this.whitelistPubkeys.size) return false;
99
+ return newPubkeys.every(pk => this.whitelistPubkeys.has(pk));
100
+ }
101
+
102
+ /**
103
+ * Start a subscription to kind:14202 events from whitelisted pubkeys.
104
+ * Updates the cache incrementally as events arrive.
105
+ */
106
+ private startSubscription(): void {
107
+ if (this.subscription) {
108
+ this.subscription.stop();
109
+ }
110
+
111
+ if (this.whitelistPubkeys.size === 0) {
112
+ logger.debug("[NudgeSkillWhitelistService] No whitelisted pubkeys, skipping subscription");
113
+ return;
114
+ }
115
+
116
+ const ndk = getNDK();
117
+ const authors = Array.from(this.whitelistPubkeys);
118
+
119
+ this.subscription = ndk.subscribe(
120
+ {
121
+ kinds: [NDKKind.NudgeSkillWhitelist],
122
+ authors,
123
+ },
124
+ {
125
+ closeOnEose: false,
126
+ onEvent: (event: NDKEvent) => {
127
+ this.handleWhitelistEvent(event);
128
+ },
129
+ }
130
+ );
131
+
132
+ logger.debug("[NudgeSkillWhitelistService] Started subscription", {
133
+ pubkeyCount: authors.length,
134
+ });
135
+ }
136
+
137
+ /**
138
+ * Handle an incoming whitelist event. Applies replaceable semantics
139
+ * (only the latest event per author is kept) and schedules a debounced cache rebuild.
140
+ */
141
+ private handleWhitelistEvent(event: NDKEvent): void {
142
+ const existing = this.latestWhitelistEvents.get(event.pubkey);
143
+ if (existing && existing.created_at !== undefined && event.created_at !== undefined
144
+ && existing.created_at >= event.created_at) {
145
+ return;
146
+ }
147
+
148
+ logger.debug("[NudgeSkillWhitelistService] Received whitelist event", {
149
+ eventId: event.id?.substring(0, 12),
150
+ author: event.pubkey.substring(0, 8),
151
+ });
152
+
153
+ this.latestWhitelistEvents.set(event.pubkey, event);
154
+ this.scheduleRebuild();
155
+ }
156
+
157
+ /**
158
+ * Schedule a debounced cache rebuild. Coalesces rapid event bursts
159
+ * (e.g. the initial subscription replay) into a single rebuild.
160
+ */
161
+ private scheduleRebuild(): void {
162
+ if (this.rebuildTimer) {
163
+ clearTimeout(this.rebuildTimer);
164
+ }
165
+ this.rebuildTimer = setTimeout(() => {
166
+ this.rebuildTimer = null;
167
+ this.rebuildCache().catch(error => {
168
+ logger.error("[NudgeSkillWhitelistService] Failed to rebuild cache", { error });
169
+ });
170
+ }, REBUILD_DEBOUNCE_MS);
171
+ }
172
+
173
+ /**
174
+ * Rebuild the cache from all stored whitelist events.
175
+ * Fetches any referenced nudge/skill events not yet in the local cache.
176
+ */
177
+ private async rebuildCache(): Promise<void> {
178
+ const span = tracer.startSpan("tenex.nudge-whitelist.rebuild", {
179
+ attributes: {
180
+ "whitelist.pubkey_count": this.whitelistPubkeys.size,
181
+ },
182
+ }, otelContext.active());
183
+
184
+ return otelContext.with(trace.setSpan(otelContext.active(), span), async () => {
185
+ try {
186
+ if (this.latestWhitelistEvents.size === 0) {
187
+ this.cache = { nudges: [], skills: [], lastUpdated: Date.now() };
188
+ span.setStatus({ code: SpanStatusCode.OK });
189
+ span.end();
190
+ return;
191
+ }
192
+
193
+ // Collect all e-tagged event IDs and track whitelisters per event
194
+ const eventToWhitelisters: Map<string, Set<string>> = new Map();
195
+
196
+ for (const event of this.latestWhitelistEvents.values()) {
197
+ const eTags = event.tags.filter(tag => tag[0] === "e" && tag[1]);
198
+ for (const eTag of eTags) {
199
+ const eventId = eTag[1];
200
+ if (!eventToWhitelisters.has(eventId)) {
201
+ eventToWhitelisters.set(eventId, new Set());
202
+ }
203
+ eventToWhitelisters.get(eventId)!.add(event.pubkey);
204
+ }
205
+ }
206
+
207
+ if (eventToWhitelisters.size === 0) {
208
+ this.cache = { nudges: [], skills: [], lastUpdated: Date.now() };
209
+ span.setAttributes({ "whitelist.item_count": 0 });
210
+ span.setStatus({ code: SpanStatusCode.OK });
211
+ span.end();
212
+ return;
213
+ }
214
+
215
+ // Find IDs not yet in our local cache
216
+ const unfetchedIds: string[] = [];
217
+ for (const id of eventToWhitelisters.keys()) {
218
+ if (!this.referencedEventCache.has(id)) {
219
+ unfetchedIds.push(id);
220
+ }
221
+ }
222
+
223
+ // Batch-fetch unfetched events with a timeout
224
+ if (unfetchedIds.length > 0) {
225
+ try {
226
+ const ndk = getNDK();
227
+ const fetchPromise = ndk.fetchEvents({ ids: unfetchedIds });
228
+ const timeoutPromise = new Promise<Set<NDKEvent>>((_, reject) =>
229
+ setTimeout(() => reject(new Error("fetchEvents timeout")), FETCH_TIMEOUT_MS)
230
+ );
231
+
232
+ const fetched = await Promise.race([fetchPromise, timeoutPromise]);
233
+ for (const event of fetched) {
234
+ this.referencedEventCache.set(event.id, event);
235
+ }
236
+ } catch (error) {
237
+ logger.warn("[NudgeSkillWhitelistService] Fetch timed out or failed, using cached events", {
238
+ unfetchedCount: unfetchedIds.length,
239
+ error: error instanceof Error ? error.message : String(error),
240
+ });
241
+ }
242
+ }
243
+
244
+ // Build cache from referencedEventCache + whitelister tracking
245
+ const nudges: WhitelistItem[] = [];
246
+ const skills: WhitelistItem[] = [];
247
+
248
+ for (const [eventId, whitelisters] of eventToWhitelisters) {
249
+ const event = this.referencedEventCache.get(eventId);
250
+ if (!event) continue;
251
+
252
+ const whitelistedBy = Array.from(whitelisters);
253
+
254
+ if (event.kind === NDKKind.AgentNudge) {
255
+ nudges.push({
256
+ eventId: event.id,
257
+ kind: NDKKind.AgentNudge,
258
+ name: event.tagValue("title") || event.tagValue("name"),
259
+ description: event.content,
260
+ whitelistedBy,
261
+ });
262
+ } else if (event.kind === NDKKind.AgentSkill) {
263
+ skills.push({
264
+ eventId: event.id,
265
+ kind: NDKKind.AgentSkill,
266
+ name: event.tagValue("title") || event.tagValue("name"),
267
+ description: event.content,
268
+ whitelistedBy,
269
+ });
270
+ }
271
+ }
272
+
273
+ this.cache = {
274
+ nudges,
275
+ skills,
276
+ lastUpdated: Date.now(),
277
+ };
278
+
279
+ span.setAttributes({
280
+ "whitelist.nudge_count": nudges.length,
281
+ "whitelist.skill_count": skills.length,
282
+ "whitelist.item_count": nudges.length + skills.length,
283
+ });
284
+
285
+ logger.info("[NudgeSkillWhitelistService] Cache rebuilt", {
286
+ nudgeCount: nudges.length,
287
+ skillCount: skills.length,
288
+ });
289
+
290
+ span.setStatus({ code: SpanStatusCode.OK });
291
+ span.end();
292
+ } catch (error) {
293
+ span.recordException(error as Error);
294
+ span.setStatus({
295
+ code: SpanStatusCode.ERROR,
296
+ message: (error as Error).message,
297
+ });
298
+ span.end();
299
+ logger.error("[NudgeSkillWhitelistService] Failed to rebuild cache", { error });
300
+ }
301
+ });
302
+ }
303
+
304
+ /**
305
+ * Get all whitelisted nudges
306
+ */
307
+ getWhitelistedNudges(): WhitelistItem[] {
308
+ if (!this.initialized) {
309
+ logger.warn("[NudgeSkillWhitelistService] getWhitelistedNudges called before initialize() — returning empty list");
310
+ }
311
+ return this.cache?.nudges || [];
312
+ }
313
+
314
+ /**
315
+ * Get all whitelisted skills
316
+ */
317
+ getWhitelistedSkills(): WhitelistItem[] {
318
+ if (!this.initialized) {
319
+ logger.warn("[NudgeSkillWhitelistService] getWhitelistedSkills called before initialize() — returning empty list");
320
+ }
321
+ return this.cache?.skills || [];
322
+ }
323
+
324
+ /**
325
+ * Get all whitelisted items (both nudges and skills)
326
+ */
327
+ getAllWhitelistedItems(): WhitelistItem[] {
328
+ if (!this.initialized) {
329
+ logger.warn("[NudgeSkillWhitelistService] getAllWhitelistedItems called before initialize() — returning empty list");
330
+ }
331
+ if (!this.cache) return [];
332
+ return [...this.cache.nudges, ...this.cache.skills];
333
+ }
334
+
335
+ /**
336
+ * Check if a nudge event ID is whitelisted
337
+ */
338
+ isNudgeWhitelisted(eventId: string): boolean {
339
+ return this.cache?.nudges.some(n => n.eventId === eventId) || false;
340
+ }
341
+
342
+ /**
343
+ * Check if a skill event ID is whitelisted
344
+ */
345
+ isSkillWhitelisted(eventId: string): boolean {
346
+ return this.cache?.skills.some(s => s.eventId === eventId) || false;
347
+ }
348
+
349
+ /**
350
+ * Get a whitelisted nudge by event ID
351
+ */
352
+ getNudge(eventId: string): WhitelistItem | undefined {
353
+ return this.cache?.nudges.find(n => n.eventId === eventId);
354
+ }
355
+
356
+ /**
357
+ * Get the last cache update time
358
+ */
359
+ getLastUpdated(): number | null {
360
+ return this.cache?.lastUpdated || null;
361
+ }
362
+
363
+ /**
364
+ * Stop the subscription and clear all state.
365
+ * Used for cleanup during tests or shutdown.
366
+ */
367
+ shutdown(): void {
368
+ if (this.subscription) {
369
+ this.subscription.stop();
370
+ this.subscription = null;
371
+ }
372
+ if (this.rebuildTimer) {
373
+ clearTimeout(this.rebuildTimer);
374
+ this.rebuildTimer = null;
375
+ }
376
+ this.cache = null;
377
+ this.initialized = false;
378
+ this.whitelistPubkeys.clear();
379
+ this.latestWhitelistEvents.clear();
380
+ this.referencedEventCache.clear();
381
+ }
382
+ }
@@ -0,0 +1,5 @@
1
+ export { NudgeService } from "./NudgeService";
2
+ export { NudgeSkillWhitelistService, NudgeSkillWhitelistService as NudgeWhitelistService } from "./NudgeWhitelistService";
3
+ export type { NudgeToolPermissions, NudgeResult, NudgeData } from "./types";
4
+ export type { WhitelistItem } from "./NudgeWhitelistService";
5
+ export { isOnlyToolMode, hasToolPermissions } from "./types";
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Nudge Tool Permissions Types
3
+ *
4
+ * Defines the structure for tool permissions specified in nudge events (kind:4201).
5
+ * Nudges can modify an agent's available tools through three tag types:
6
+ *
7
+ * 1. only-tool: Highest priority - REPLACES all tools with only these
8
+ * 2. allow-tool: Adds tools to the agent's default set
9
+ * 3. deny-tool: Removes tools from the agent's default set
10
+ *
11
+ * Precedence: only-tool > allow-tool/deny-tool
12
+ */
13
+
14
+ /**
15
+ * Tool permissions extracted from nudge event tags.
16
+ * Used to modify an agent's available tools during execution.
17
+ */
18
+ export interface NudgeToolPermissions {
19
+ /**
20
+ * If set, the agent gets EXACTLY these tools (and nothing else).
21
+ * This is the highest priority - completely overrides allow/deny and agent defaults.
22
+ * Tag format: ["only-tool", "tool_name"]
23
+ */
24
+ onlyTools?: string[];
25
+
26
+ /**
27
+ * Tools to enable (add to agent's default set).
28
+ * Ignored if onlyTools is set.
29
+ * Tag format: ["allow-tool", "tool_name"]
30
+ */
31
+ allowTools?: string[];
32
+
33
+ /**
34
+ * Tools to disable (remove from agent's default set).
35
+ * Ignored if onlyTools is set.
36
+ * Tag format: ["deny-tool", "tool_name"]
37
+ */
38
+ denyTools?: string[];
39
+ }
40
+
41
+ /**
42
+ * Individual nudge data with content and title
43
+ */
44
+ export interface NudgeData {
45
+ /** The nudge content/prompt */
46
+ content: string;
47
+ /** The nudge title (from "title" tag) */
48
+ title?: string;
49
+ }
50
+
51
+ /**
52
+ * Result from fetching nudges with their tool permissions.
53
+ * Contains both the concatenated content for system prompt injection
54
+ * and the extracted tool permissions.
55
+ */
56
+ export interface NudgeResult {
57
+ /** Individual nudge data for rendering in the fragment */
58
+ nudges: NudgeData[];
59
+
60
+ /** Concatenated content from all nudges (for backward compatibility) */
61
+ content: string;
62
+
63
+ /** Tool permissions extracted from all nudge tags */
64
+ toolPermissions: NudgeToolPermissions;
65
+ }
66
+
67
+ /**
68
+ * Check if nudge permissions are using only-tool mode (highest priority)
69
+ */
70
+ export function isOnlyToolMode(permissions: NudgeToolPermissions): boolean {
71
+ return Array.isArray(permissions.onlyTools) && permissions.onlyTools.length > 0;
72
+ }
73
+
74
+ /**
75
+ * Check if nudge permissions have any tool modifications
76
+ */
77
+ export function hasToolPermissions(permissions: NudgeToolPermissions): boolean {
78
+ return (
79
+ isOnlyToolMode(permissions) ||
80
+ (Array.isArray(permissions.allowTools) && permissions.allowTools.length > 0) ||
81
+ (Array.isArray(permissions.denyTools) && permissions.denyTools.length > 0)
82
+ );
83
+ }