@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,165 @@
1
+ import type { NDKEvent } from "@nostr-dev-kit/ndk";
2
+ import { NDKArticle } from "@nostr-dev-kit/ndk";
3
+ import { trace } from "@opentelemetry/api";
4
+ import chalk from "chalk";
5
+ import type { AgentExecutor } from "../agents/execution/AgentExecutor";
6
+ import { createExecutionContext } from "../agents/execution/ExecutionContextFactory";
7
+ import { ConversationStore } from "../conversations/ConversationStore";
8
+ import type { ConversationMetadata } from "../conversations/types";
9
+ import { AgentEventDecoder } from "../nostr/AgentEventDecoder";
10
+ import { getNDK } from "../nostr/ndkClient";
11
+ import { TagExtractor } from "../nostr/TagExtractor";
12
+ import { getProjectContext } from "@/services/projects";
13
+ import { formatAnyError } from "@/lib/error-formatter";
14
+ import { logger } from "../utils/logger";
15
+ import { AgentRouter } from "@/services/dispatch/AgentRouter";
16
+
17
+ /**
18
+ * Fetch a kind 30023 (NDKArticle) from an a-tag reference.
19
+ * @param aTagValue - The a-tag value in format "30023:pubkey:d-tag"
20
+ * @returns The article metadata or null if not found
21
+ */
22
+ async function fetchReferencedArticle(
23
+ aTagValue: string
24
+ ): Promise<ConversationMetadata["referencedArticle"] | null> {
25
+ try {
26
+ const parts = aTagValue.split(":");
27
+ if (parts.length < 3 || parts[0] !== "30023") {
28
+ return null;
29
+ }
30
+
31
+ const [, pubkey, ...dTagParts] = parts;
32
+ const dTag = dTagParts.join(":"); // Handle d-tags that contain colons
33
+
34
+ const ndk = getNDK();
35
+ const filter = {
36
+ kinds: [30023],
37
+ authors: [pubkey],
38
+ "#d": [dTag],
39
+ };
40
+
41
+ const events = await ndk.fetchEvents(filter);
42
+ if (events.size === 0) {
43
+ logger.debug(chalk.yellow(`Referenced article not found: ${aTagValue}`));
44
+ return null;
45
+ }
46
+
47
+ const event = Array.from(events)[0];
48
+ const article = NDKArticle.from(event);
49
+
50
+ logger.info(chalk.cyan(`📄 Fetched referenced article: "${article.title || dTag}"`));
51
+
52
+ return {
53
+ title: article.title || dTag,
54
+ content: article.content || "",
55
+ dTag,
56
+ };
57
+ } catch (error) {
58
+ logger.debug(chalk.yellow(`Failed to fetch referenced article: ${formatAnyError(error)}`));
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Extract and fetch the first kind 30023 article reference from an event's a-tags.
65
+ * @param event - The event to extract article references from
66
+ * @returns The article metadata or null if none found
67
+ */
68
+ async function extractReferencedArticle(
69
+ event: NDKEvent
70
+ ): Promise<ConversationMetadata["referencedArticle"] | null> {
71
+ const aTags = TagExtractor.getATags(event);
72
+
73
+ // Find the first a-tag referencing a kind 30023 (article)
74
+ const articleATag = aTags.find((tag) => tag.startsWith("30023:"));
75
+ if (!articleATag) {
76
+ return null;
77
+ }
78
+
79
+ return fetchReferencedArticle(articleATag);
80
+ }
81
+
82
+ interface EventHandlerContext {
83
+ agentExecutor: AgentExecutor;
84
+ /**
85
+ * Project directory (normal git repository root).
86
+ * Worktrees are in .worktrees/ subdirectory.
87
+ */
88
+ projectBasePath: string;
89
+ }
90
+
91
+ export const handleNewConversation = async (
92
+ event: NDKEvent,
93
+ context: EventHandlerContext
94
+ ): Promise<void> => {
95
+ try {
96
+ // Create conversation
97
+ const conversation = await ConversationStore.create(event);
98
+
99
+ // Check for referenced kind 30023 articles and populate metadata
100
+ const referencedArticle = await extractReferencedArticle(event);
101
+ if (referencedArticle) {
102
+ conversation.updateMetadata({ referencedArticle });
103
+ await conversation.save();
104
+
105
+ const activeSpan = trace.getActiveSpan();
106
+ if (activeSpan) {
107
+ activeSpan.addEvent("referenced_article_loaded", {
108
+ "article.title": referencedArticle.title,
109
+ "article.dTag": referencedArticle.dTag,
110
+ "article.content_length": referencedArticle.content.length,
111
+ });
112
+ }
113
+ }
114
+
115
+ // Get project context
116
+ const projectCtx = getProjectContext();
117
+
118
+ // Use AgentRouter to resolve target agents (includes project validation for global agents)
119
+ const targetAgents = AgentRouter.resolveTargetAgents(event, projectCtx);
120
+
121
+ // Add telemetry for routing decision
122
+ const activeSpan = trace.getActiveSpan();
123
+ if (activeSpan) {
124
+ const mentionedPubkeys = AgentEventDecoder.getMentionedPubkeys(event);
125
+ activeSpan.addEvent("agent_routing", {
126
+ "routing.mentioned_pubkeys_count": mentionedPubkeys.length,
127
+ "routing.resolved_agent_count": targetAgents.length,
128
+ "routing.agent_names": targetAgents.map((a) => a.name).join(", "),
129
+ "routing.agent_roles": targetAgents.map((a) => a.role).join(", "),
130
+ });
131
+ }
132
+
133
+ // If no valid agents found (filtered by project context), return
134
+ if (targetAgents.length === 0) {
135
+ logger.info(
136
+ chalk.gray(
137
+ "New conversation - no valid agents to route to (may have been filtered by project context)"
138
+ )
139
+ );
140
+ if (activeSpan) {
141
+ activeSpan.addEvent("agent_routing_failed", { reason: "no_agents_resolved" });
142
+ }
143
+ return;
144
+ }
145
+
146
+ // Use first agent for new conversation
147
+ const targetAgent = targetAgents[0];
148
+
149
+ // Create execution context (new conversations don't have branch tags)
150
+ const executionContext = await createExecutionContext({
151
+ agent: targetAgent,
152
+ conversationId: conversation.id,
153
+ projectBasePath: context.projectBasePath,
154
+ triggeringEvent: event,
155
+ mcpManager: projectCtx.mcpManager,
156
+ });
157
+
158
+ // Execute with the appropriate agent
159
+ await context.agentExecutor.execute(executionContext);
160
+
161
+ logger.info(chalk.green("✅ Conversation routed successfully"));
162
+ } catch (error) {
163
+ logger.info(chalk.red(`❌ Failed to route conversation: ${formatAnyError(error)}`));
164
+ }
165
+ };
@@ -0,0 +1,166 @@
1
+ import type { NDKEvent, NDKProject } from "@nostr-dev-kit/ndk";
2
+ import { NDKMCPTool } from "../events/NDKMCPTool";
3
+ import { getNDK } from "../nostr";
4
+ import { TagExtractor } from "../nostr/TagExtractor";
5
+ import { getProjectContext } from "@/services/projects";
6
+ import {
7
+ getInstalledMCPEventIds,
8
+ installMCPServerFromEvent,
9
+ removeMCPServerByEventId,
10
+ } from "../services/mcp/mcpInstaller";
11
+ import { installAgentFromNostr } from "../agents/agent-installer";
12
+ import { logger } from "../utils/logger";
13
+ import { trace } from "@opentelemetry/api";
14
+
15
+ /**
16
+ * Handles project update events by syncing agent and MCP tool definitions.
17
+ * When a project event is received, this function:
18
+ * 1. Checks if the event is for the currently loaded project
19
+ * 2. Identifies new agents and MCP tools that have been added to the project
20
+ * 3. Fetches definitions from Nostr for new agents and MCP tools
21
+ * 4. Saves definitions to disk and registers them
22
+ * 5. Updates the ProjectContext with the new configuration
23
+ */
24
+ export async function handleProjectEvent(event: NDKEvent): Promise<void> {
25
+ const title = TagExtractor.getTagValue(event, "title") || "Untitled";
26
+
27
+ // Extract agent event IDs from the project
28
+ const agentEventIds = TagExtractor.getTagValues(event, "agent")
29
+ .filter((id): id is string => typeof id === "string");
30
+
31
+ // Extract MCP tool event IDs from the project
32
+ const mcpEventIds = TagExtractor.getTagValues(event, "mcp")
33
+ .filter((id): id is string => typeof id === "string");
34
+
35
+ trace.getActiveSpan()?.addEvent("project.update_received", {
36
+ "project.title": title,
37
+ "project.agent_count": agentEventIds.length,
38
+ "project.mcp_count": mcpEventIds.length,
39
+ });
40
+
41
+ try {
42
+ const currentContext = getProjectContext();
43
+ const metadataPath = currentContext.agentRegistry.getMetadataPath();
44
+
45
+ // Check if this is the same project that's currently loaded
46
+ const currentProjectDTag = currentContext.project.dTag;
47
+ const eventDTag = TagExtractor.getDTag(event);
48
+
49
+ if (currentProjectDTag !== eventDTag) {
50
+ return;
51
+ }
52
+
53
+ const ndkProject = event as NDKProject;
54
+
55
+ // Track which agents need to be added or updated
56
+ const currentAgentEventIds = new Set<string>();
57
+ for (const agent of currentContext.agents.values()) {
58
+ if (agent.eventId) {
59
+ currentAgentEventIds.add(agent.eventId);
60
+ }
61
+ }
62
+
63
+ // Find new agents that need to be fetched
64
+ const newAgentEventIds = agentEventIds.filter(
65
+ (id) => !!id && !currentAgentEventIds.has(id)
66
+ );
67
+
68
+ // Find agents that need to be removed (exist locally but not in the project)
69
+ const newAgentEventIdsSet = new Set(agentEventIds);
70
+ const agentsToRemove = Array.from(currentAgentEventIds).filter(
71
+ (id) => !newAgentEventIdsSet.has(id)
72
+ );
73
+
74
+ // Handle agent removals first
75
+ if (agentsToRemove.length > 0) {
76
+ const agentRegistry = currentContext.agentRegistry;
77
+
78
+ for (const eventId of agentsToRemove) {
79
+ // Find agent by eventId
80
+ const agent = Array.from(currentContext.agents.values()).find(
81
+ (a) => a.eventId === eventId
82
+ );
83
+
84
+ if (agent) {
85
+ try {
86
+ await agentRegistry.removeAgentFromProject(agent.slug);
87
+ } catch (error) {
88
+ logger.error(`Error removing agent ${agent.slug}`, { error });
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ // Process agent and MCP tool changes
95
+ const ndk = getNDK();
96
+
97
+ // Fetch and install new agent definitions using shared function
98
+ if (newAgentEventIds.length > 0) {
99
+ for (const eventId of newAgentEventIds) {
100
+ try {
101
+ await installAgentFromNostr(eventId, undefined, ndk);
102
+ } catch (error) {
103
+ logger.error("Failed to install agent from event", { eventId, error });
104
+ }
105
+ }
106
+ // Reload the agent registry to pick up new agents
107
+ await currentContext.agentRegistry.loadFromProject(ndkProject);
108
+ }
109
+
110
+ // Process MCP tool changes
111
+
112
+ // Get currently installed MCP event IDs (only those with event IDs)
113
+ const installedMCPEventIds = await getInstalledMCPEventIds(metadataPath);
114
+
115
+ // Find new MCP tools that need to be fetched
116
+ const newMCPEventIds = mcpEventIds.filter((id) => !!id && !installedMCPEventIds.has(id));
117
+
118
+ // Find MCP tools that need to be removed (exist locally but not in the project)
119
+ const newMCPEventIdsSet = new Set(mcpEventIds);
120
+ const mcpToolsToRemove = Array.from(installedMCPEventIds).filter(
121
+ (id) => !newMCPEventIdsSet.has(id)
122
+ );
123
+
124
+ // Handle MCP tool removals first
125
+ for (const eventId of mcpToolsToRemove) {
126
+ try {
127
+ await removeMCPServerByEventId(metadataPath, eventId);
128
+ } catch (error) {
129
+ logger.error("Failed to remove MCP tool", { error, eventId });
130
+ }
131
+ }
132
+
133
+ // Fetch and install new MCP tools
134
+ for (const eventId of newMCPEventIds) {
135
+ try {
136
+ const mcpEvent = await ndk.fetchEvent(eventId);
137
+ if (mcpEvent) {
138
+ const mcpTool = NDKMCPTool.from(mcpEvent);
139
+ await installMCPServerFromEvent(metadataPath, mcpTool);
140
+ }
141
+ } catch (error) {
142
+ logger.error("Failed to fetch or install MCP tool", { error, eventId });
143
+ }
144
+ }
145
+
146
+ // Reload MCP service if there were any MCP tool changes
147
+ const hasMCPChanges = newMCPEventIds.length > 0 || mcpToolsToRemove.length > 0;
148
+ if (hasMCPChanges && currentContext.mcpManager) {
149
+ await currentContext.mcpManager.reload(metadataPath);
150
+ }
151
+
152
+ // Update the existing project context atomically
153
+ // This will reload agents from the project
154
+ await currentContext.updateProjectData(ndkProject);
155
+
156
+ trace.getActiveSpan()?.addEvent("project.updated", {
157
+ "project.total_agents": currentContext.agents.size,
158
+ "project.agents_added": newAgentEventIds.length,
159
+ "project.agents_removed": agentsToRemove.length,
160
+ "project.mcp_added": newMCPEventIds.length,
161
+ "project.mcp_removed": mcpToolsToRemove.length,
162
+ });
163
+ } catch (error) {
164
+ logger.error("Failed to update project from event", { error });
165
+ }
166
+ }
@@ -0,0 +1,18 @@
1
+ import type { AgentExecutor } from "@/agents/execution/AgentExecutor";
2
+ import { AgentDispatchService } from "@/services/dispatch/AgentDispatchService";
3
+ import type { NDKEvent } from "@nostr-dev-kit/ndk";
4
+
5
+ interface EventHandlerContext {
6
+ agentExecutor: AgentExecutor;
7
+ }
8
+
9
+ /**
10
+ * Main entry point for handling chat messages.
11
+ */
12
+ export const handleChatMessage = async (
13
+ event: NDKEvent,
14
+ context: EventHandlerContext
15
+ ): Promise<void> => {
16
+ const dispatcher = AgentDispatchService.getInstance();
17
+ await dispatcher.dispatch(event, context);
18
+ };
@@ -0,0 +1,292 @@
1
+ import type NDK from "@nostr-dev-kit/ndk";
2
+ import { NDKEvent, type NDKRawEvent } from "@nostr-dev-kit/ndk";
3
+
4
+ /**
5
+ * Tuple type for e-tags: ["e", eventId, relayUrl, marker]
6
+ */
7
+ export type ETag = [marker: "e", eventId: string, relayUrl: string, tagMarker: string];
8
+
9
+ /**
10
+ * Parsed e-tag reference with typed fields
11
+ */
12
+ export interface ETagReference {
13
+ eventId: string;
14
+ relayUrl?: string;
15
+ marker?: string;
16
+ }
17
+
18
+ export class NDKAgentDefinition extends NDKEvent {
19
+ static kind = 4199;
20
+ static kinds = [4199];
21
+
22
+ constructor(ndk?: NDK, event?: NDKEvent | NDKRawEvent) {
23
+ super(ndk, event);
24
+ this.kind ??= 4199;
25
+ }
26
+
27
+ static from(event: NDKEvent): NDKAgentDefinition {
28
+ return new NDKAgentDefinition(event.ndk, event);
29
+ }
30
+
31
+ /**
32
+ * The canonical title/name of the agent.
33
+ * Maps to the "title" tag.
34
+ */
35
+ get title(): string | undefined {
36
+ return this.tagValue("title");
37
+ }
38
+
39
+ set title(value: string | undefined) {
40
+ this.setOptionalTag("title", value);
41
+ }
42
+
43
+ /**
44
+ * Alias for `title`. Prefer using `title` directly.
45
+ * @deprecated Use `title` instead. Will be removed in a future version.
46
+ */
47
+ get name(): string | undefined {
48
+ return this.title;
49
+ }
50
+
51
+ /**
52
+ * @deprecated Use `title` instead. Will be removed in a future version.
53
+ */
54
+ set name(value: string | undefined) {
55
+ this.title = value;
56
+ }
57
+
58
+ get description(): string | undefined {
59
+ return this.tagValue("description");
60
+ }
61
+
62
+ /**
63
+ * A one-liner description of the agent's purpose or functionality.
64
+ */
65
+ set description(value: string | undefined) {
66
+ this.setOptionalTag("description", value);
67
+ }
68
+
69
+ /**
70
+ * Extended markdown description from the event content field.
71
+ * MAY contain markdown-formatted extended description of the agent.
72
+ */
73
+ get markdownDescription(): string | undefined {
74
+ return this.content || undefined;
75
+ }
76
+
77
+ /**
78
+ * Set the extended markdown description in the event content field.
79
+ */
80
+ set markdownDescription(value: string | undefined) {
81
+ this.content = value ?? "";
82
+ }
83
+
84
+ get role(): string | undefined {
85
+ return this.tagValue("role");
86
+ }
87
+
88
+ /**
89
+ * The expertise and personality for this agent.
90
+ * This shapes how the agent interacts with users and other agents.
91
+ */
92
+ set role(value: string | undefined) {
93
+ this.setOptionalTag("role", value);
94
+ }
95
+
96
+ get instructions(): string | undefined {
97
+ return this.tagValue("instructions");
98
+ }
99
+
100
+ /**
101
+ * Detailed instructions or guidelines for the agent's operation.
102
+ */
103
+ set instructions(value: string | undefined) {
104
+ this.setOptionalTag("instructions", value);
105
+ }
106
+
107
+ get version(): number {
108
+ const val = this.tagValue("ver");
109
+ if (val === undefined) return 1; // Default version if not specified
110
+ const parsed = Number.parseInt(val, 10);
111
+ return Number.isNaN(parsed) ? 1 : parsed; // Fallback to 1 if parsing fails
112
+ }
113
+
114
+ set version(value: number) {
115
+ this.removeTag("ver");
116
+ this.tags.push(["ver", value.toString()]);
117
+ }
118
+
119
+ get useCriteria(): string | undefined {
120
+ return this.tagValue("use-criteria");
121
+ }
122
+
123
+ /**
124
+ * Criteria for when this agent should be selected or used.
125
+ * This helps with agent routing and selection.
126
+ */
127
+ set useCriteria(value: string | undefined) {
128
+ this.setOptionalTag("use-criteria", value);
129
+ }
130
+
131
+ get category(): string | undefined {
132
+ return this.tagValue("category");
133
+ }
134
+
135
+ /**
136
+ * Category for the agent (e.g., 'developer', 'analyst', 'assistant').
137
+ */
138
+ set category(value: string | undefined) {
139
+ this.setOptionalTag("category", value);
140
+ }
141
+
142
+ get slug(): string | undefined {
143
+ return this.tagValue("d");
144
+ }
145
+
146
+ /**
147
+ * The slug identifier for this agent definition.
148
+ * This is used to find different versions from the same author of the same agent
149
+ * (e.g., version 1, 2, 3 of a 'human-replica' agent would all share ["d", "human-replica"]).
150
+ *
151
+ * Note: Unlike other setters, this uses `value !== undefined` instead of truthy check
152
+ * because empty string is a valid d-tag value per Nostr conventions. Only `undefined`
153
+ * should clear the tag. This is intentionally different from setOptionalTag behavior.
154
+ */
155
+ set slug(value: string | undefined) {
156
+ this.removeTag("d");
157
+ if (value !== undefined) this.tags.push(["d", value]);
158
+ }
159
+
160
+ /**
161
+ * Get script e-tags from the agent definition.
162
+ * Script e-tags reference kind 1063 (NIP-94 file metadata) events
163
+ * that contain files bundled with the agent.
164
+ *
165
+ * @returns Array of parsed e-tag references
166
+ * @deprecated Use getFileETags() instead, which returns all e-tags (not just "script" marker)
167
+ */
168
+ getScriptETags(): ETagReference[] {
169
+ return this.parseETags("script");
170
+ }
171
+
172
+ /**
173
+ * Get all e-tags from the agent definition.
174
+ * E-tags may reference kind 1063 (NIP-94 file metadata) events
175
+ * that contain files bundled with the agent, or other related events.
176
+ *
177
+ * Unlike getScriptETags(), this method returns ALL e-tags, not just
178
+ * those with a specific marker, allowing for general event references.
179
+ *
180
+ * @returns Array of parsed e-tag references
181
+ */
182
+ getETags(): ETagReference[] {
183
+ return this.parseETags();
184
+ }
185
+
186
+ /**
187
+ * Get e-tags with the "file" marker.
188
+ * These reference kind 1063 (NIP-94 file metadata) events that contain
189
+ * files bundled with this agent definition.
190
+ *
191
+ * @returns Array of parsed e-tag references
192
+ */
193
+ getFileETags(): ETagReference[] {
194
+ return this.parseETags("file");
195
+ }
196
+
197
+ /**
198
+ * Get e-tags with the "fork" marker.
199
+ * These reference the source kind 4199 agent definition event that
200
+ * this agent was forked from.
201
+ *
202
+ * @returns Array of parsed e-tag references
203
+ */
204
+ getForkETags(): ETagReference[] {
205
+ return this.parseETags("fork");
206
+ }
207
+
208
+ /**
209
+ * Get the source agent definition this was forked from (if any).
210
+ * Returns the first fork e-tag, or undefined if this is not a fork.
211
+ *
212
+ * @returns Object with eventId and optional relayUrl, or undefined
213
+ */
214
+ getForkSource(): { eventId: string; relayUrl?: string } | undefined {
215
+ const forks = this.getForkETags();
216
+ return forks.length > 0 ? forks[0] : undefined;
217
+ }
218
+
219
+ /**
220
+ * Add a file reference e-tag with the "file" marker.
221
+ * References a kind 1063 (NIP-94 file metadata) event.
222
+ *
223
+ * @param eventId - The event ID of the kind 1063 file metadata event
224
+ * @param relayUrl - Optional relay hint URL
225
+ */
226
+ addFileReference(eventId: string, relayUrl?: string): void {
227
+ this.tags.push(this.buildETag(eventId, relayUrl, "file"));
228
+ }
229
+
230
+ /**
231
+ * Set the fork source for this agent definition.
232
+ * Removes any existing fork e-tags and adds a new one.
233
+ *
234
+ * @param eventId - The event ID of the source kind 4199 agent definition
235
+ * @param relayUrl - Optional relay hint URL
236
+ */
237
+ setForkSource(eventId: string, relayUrl?: string): void {
238
+ // Remove existing fork tags
239
+ this.tags = this.tags.filter((tag) => !(tag[0] === "e" && tag[3] === "fork"));
240
+
241
+ // Add new fork tag
242
+ this.tags.push(this.buildETag(eventId, relayUrl, "fork"));
243
+ }
244
+
245
+ /**
246
+ * Build an e-tag tuple with the standard format: ["e", eventId, relayUrl, marker]
247
+ *
248
+ * @param eventId - The event ID to reference
249
+ * @param relayUrl - Optional relay hint URL (defaults to empty string if not provided)
250
+ * @param marker - The marker for the e-tag (e.g., "file", "fork", "script")
251
+ * @returns The constructed e-tag tuple
252
+ */
253
+ private buildETag(eventId: string, relayUrl: string | undefined, marker: string): ETag {
254
+ return ["e", eventId, relayUrl ?? "", marker];
255
+ }
256
+
257
+ /**
258
+ * Parse e-tags from the event, optionally filtering by marker.
259
+ * Consolidates the common filter/map logic for e-tag extraction.
260
+ *
261
+ * @param marker - Optional marker to filter by (e.g., "file", "fork", "script").
262
+ * If not provided, returns all e-tags.
263
+ * @returns Array of parsed e-tag references with eventId, relayUrl, and marker
264
+ */
265
+ private parseETags(marker?: string): ETagReference[] {
266
+ return this.tags
267
+ .filter((tag) => tag[0] === "e" && !!tag[1] && (marker === undefined || tag[3] === marker))
268
+ .map((tag) => ({
269
+ eventId: tag[1],
270
+ relayUrl: tag[2] || undefined,
271
+ marker: tag[3] || undefined,
272
+ }));
273
+ }
274
+
275
+ /**
276
+ * Set an optional tag value with consistent semantics.
277
+ * Removes any existing tag with the same name, then adds it back only if value is truthy.
278
+ * This means empty strings, undefined, and null all clear the tag.
279
+ *
280
+ * Note: For tags where empty string is a valid value (like the "d" tag for slug),
281
+ * use direct tag manipulation with `value !== undefined` check instead of this helper.
282
+ *
283
+ * @param tagName - The tag name to set
284
+ * @param value - The value to set, or falsy value to clear the tag
285
+ */
286
+ private setOptionalTag(tagName: string, value: string | undefined): void {
287
+ this.removeTag(tagName);
288
+ if (value) {
289
+ this.tags.push([tagName, value]);
290
+ }
291
+ }
292
+ }