@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,320 @@
1
+ /**
2
+ * ConversationIndexingJob - Automatic batch indexing service
3
+ *
4
+ * This service runs periodically (every 5 minutes) to automatically index
5
+ * conversations that need embedding updates. It tracks which conversations
6
+ * have been indexed and ensures new/updated conversations are processed
7
+ * without requiring manual agent intervention.
8
+ *
9
+ * Key features:
10
+ * - Runs every 5 minutes as a background job
11
+ * - Indexes conversations across all projects
12
+ * - Tracks indexing state durably to avoid redundant work
13
+ * - Re-indexes when conversation metadata changes
14
+ * - Graceful error handling - failures don't break the service
15
+ * - Prevents overlapping batches
16
+ * - Decoupled from ConversationRegistry for multi-project support
17
+ */
18
+
19
+ import { logger } from "@/utils/logger";
20
+ import { getTenexBasePath } from "@/constants";
21
+ import { join } from "path";
22
+ import { getConversationEmbeddingService } from "./ConversationEmbeddingService";
23
+ import type { BuildDocumentResult } from "./ConversationEmbeddingService";
24
+ import { IndexingStateManager } from "./IndexingStateManager";
25
+ import { listProjectIdsFromDisk, listConversationIdsFromDiskForProject } from "@/conversations/ConversationDiskReader";
26
+ import { RAGService, type RAGDocument } from "@/services/rag/RAGService";
27
+
28
+ /** Default interval: 5 minutes (in milliseconds) */
29
+ const DEFAULT_INTERVAL_MS = 5 * 60 * 1000;
30
+
31
+ /**
32
+ * Automatic conversation indexing job service
33
+ */
34
+ export class ConversationIndexingJob {
35
+ private static instance: ConversationIndexingJob | null = null;
36
+ private timer: NodeJS.Timeout | null = null;
37
+ private isRunning = false;
38
+ private isBatchRunning = false; // Prevent overlapping batches
39
+ private intervalMs: number;
40
+ private projectsBasePath: string;
41
+ private stateManager: IndexingStateManager;
42
+
43
+ private constructor(intervalMs: number = DEFAULT_INTERVAL_MS) {
44
+ this.intervalMs = intervalMs;
45
+ // Use stable projects root from config, not mutable registry
46
+ this.projectsBasePath = join(getTenexBasePath(), "projects");
47
+ this.stateManager = new IndexingStateManager(this.projectsBasePath);
48
+ }
49
+
50
+ /**
51
+ * Get singleton instance
52
+ */
53
+ public static getInstance(intervalMs?: number): ConversationIndexingJob {
54
+ if (!ConversationIndexingJob.instance) {
55
+ ConversationIndexingJob.instance = new ConversationIndexingJob(intervalMs);
56
+ }
57
+ return ConversationIndexingJob.instance;
58
+ }
59
+
60
+ /**
61
+ * Start the periodic indexing job
62
+ */
63
+ public start(): void {
64
+ if (this.isRunning) {
65
+ logger.warn("ConversationIndexingJob is already running");
66
+ return;
67
+ }
68
+
69
+ this.isRunning = true;
70
+ logger.info("Starting ConversationIndexingJob", {
71
+ intervalMs: this.intervalMs,
72
+ intervalMinutes: this.intervalMs / 60000,
73
+ projectsBasePath: this.projectsBasePath,
74
+ });
75
+
76
+ // Run immediately on start
77
+ this.scheduleNextBatch(0);
78
+ }
79
+
80
+ /**
81
+ * Schedule the next batch run (self-scheduling to prevent overlaps)
82
+ */
83
+ private scheduleNextBatch(delayMs: number): void {
84
+ if (!this.isRunning) return;
85
+
86
+ this.timer = setTimeout(async () => {
87
+ try {
88
+ await this.runIndexingBatch();
89
+ } catch (error) {
90
+ logger.error("Indexing batch failed", { error });
91
+ } finally {
92
+ // Schedule next run only after this one completes
93
+ this.scheduleNextBatch(this.intervalMs);
94
+ }
95
+ }, delayMs);
96
+ }
97
+
98
+ /**
99
+ * Stop the periodic indexing job
100
+ */
101
+ public stop(): void {
102
+ if (!this.isRunning) {
103
+ logger.warn("ConversationIndexingJob is not running");
104
+ return;
105
+ }
106
+
107
+ if (this.timer) {
108
+ clearTimeout(this.timer);
109
+ this.timer = null;
110
+ }
111
+
112
+ this.isRunning = false;
113
+
114
+ // Save state before stopping
115
+ this.stateManager.dispose();
116
+
117
+ logger.info("ConversationIndexingJob stopped");
118
+ }
119
+
120
+ /**
121
+ * Run a single indexing batch.
122
+ *
123
+ * Collects all conversations needing re-indexing across all projects,
124
+ * builds RAGDocuments for each, then flushes them via bulkUpsert
125
+ * (mergeInsert). This creates one LanceDB version per chunk of
126
+ * BATCH_SIZE instead of 2N versions (delete+insert per conversation).
127
+ *
128
+ * Failures are isolated per chunk: documents in a successful chunk are
129
+ * marked indexed even when other chunks fail. Only truly failed
130
+ * documents are retried next cycle.
131
+ */
132
+ private async runIndexingBatch(): Promise<void> {
133
+ // Prevent overlapping batches
134
+ if (this.isBatchRunning) {
135
+ logger.warn("Skipping indexing batch - previous batch still running");
136
+ return;
137
+ }
138
+
139
+ this.isBatchRunning = true;
140
+ logger.debug("Running conversation indexing batch");
141
+
142
+ const conversationEmbeddingService = getConversationEmbeddingService();
143
+
144
+ try {
145
+ // Ensure the embedding service is initialized
146
+ await conversationEmbeddingService.initialize();
147
+
148
+ let totalChecked = 0;
149
+ let totalSkipped = 0;
150
+ let totalFailed = 0;
151
+
152
+ // Collect all documents that need indexing across all projects
153
+ const pendingDocuments: RAGDocument[] = [];
154
+ // Track which conversations were successfully built (for marking indexed after flush)
155
+ // Indices into pendingDocuments correspond 1:1 with pendingMarkIndexed
156
+ const pendingMarkIndexed: Array<{ projectId: string; conversationId: string }> = [];
157
+ const pendingMarkNoContent: Array<{ projectId: string; conversationId: string }> = [];
158
+
159
+ // Get all projects directly from disk
160
+ const projectIds = listProjectIdsFromDisk(this.projectsBasePath);
161
+
162
+ for (const projectId of projectIds) {
163
+ try {
164
+ const conversationIds = listConversationIdsFromDiskForProject(
165
+ this.projectsBasePath,
166
+ projectId
167
+ );
168
+
169
+ for (const conversationId of conversationIds) {
170
+ totalChecked++;
171
+
172
+ // Check if conversation needs indexing using durable state
173
+ const needsIndexing = this.stateManager.needsIndexing(
174
+ this.projectsBasePath,
175
+ projectId,
176
+ conversationId
177
+ );
178
+
179
+ if (!needsIndexing) {
180
+ totalSkipped++;
181
+ continue;
182
+ }
183
+
184
+ // Build document without writing
185
+ const result: BuildDocumentResult = conversationEmbeddingService.buildDocument(
186
+ conversationId,
187
+ projectId
188
+ );
189
+
190
+ switch (result.kind) {
191
+ case "ok":
192
+ pendingDocuments.push(result.document);
193
+ pendingMarkIndexed.push({ projectId, conversationId });
194
+ break;
195
+ case "noContent":
196
+ pendingMarkNoContent.push({ projectId, conversationId });
197
+ break;
198
+ case "error":
199
+ // Transient error — leave unmarked so it retries next cycle
200
+ totalFailed++;
201
+ logger.warn("Transient error building document, will retry", {
202
+ conversationId: conversationId.substring(0, 8),
203
+ projectId,
204
+ reason: result.reason,
205
+ });
206
+ break;
207
+ }
208
+ }
209
+ } catch (error) {
210
+ const message = error instanceof Error ? error.message : String(error);
211
+ logger.error("Failed to process project conversations", {
212
+ projectId,
213
+ error: message,
214
+ });
215
+ }
216
+ }
217
+
218
+ // Flush all pending documents via bulkUpsert (per-chunk failure isolation)
219
+ let totalIndexed = 0;
220
+ if (pendingDocuments.length > 0) {
221
+ const ragService = RAGService.getInstance();
222
+ const collectionName = conversationEmbeddingService.getCollectionName();
223
+ const { upsertedCount, failedIndices } = await ragService.bulkUpsert(
224
+ collectionName,
225
+ pendingDocuments
226
+ );
227
+
228
+ totalIndexed = upsertedCount;
229
+
230
+ // Build a set of failed indices for O(1) lookup
231
+ const failedSet = new Set(failedIndices);
232
+ totalFailed += failedIndices.length;
233
+
234
+ // Mark only successfully flushed conversations as indexed
235
+ for (let i = 0; i < pendingMarkIndexed.length; i++) {
236
+ if (failedSet.has(i)) {
237
+ // This document's chunk failed — leave unmarked for retry
238
+ continue;
239
+ }
240
+ const { projectId, conversationId } = pendingMarkIndexed[i];
241
+ this.stateManager.markIndexed(
242
+ this.projectsBasePath,
243
+ projectId,
244
+ conversationId
245
+ );
246
+ }
247
+ }
248
+
249
+ // Mark no-content conversations to avoid re-trying every batch
250
+ for (const { projectId, conversationId } of pendingMarkNoContent) {
251
+ this.stateManager.markIndexed(
252
+ this.projectsBasePath,
253
+ projectId,
254
+ conversationId,
255
+ true
256
+ );
257
+ }
258
+
259
+ if (totalChecked > 0) {
260
+ logger.info("Conversation indexing batch complete", {
261
+ projectsProcessed: projectIds.length,
262
+ conversationsChecked: totalChecked,
263
+ newlyIndexed: totalIndexed,
264
+ skipped: totalSkipped,
265
+ failed: totalFailed,
266
+ });
267
+ } else {
268
+ logger.debug("No conversations to index in this batch");
269
+ }
270
+ } catch (error) {
271
+ const message = error instanceof Error ? error.message : String(error);
272
+ logger.error("Conversation indexing batch failed", { error: message });
273
+ // Don't throw - we want the job to keep running even if one batch fails
274
+ } finally {
275
+ this.isBatchRunning = false;
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Force a full re-index of all conversations
281
+ * This clears the tracking state and re-indexes everything
282
+ */
283
+ public async forceFullReindex(): Promise<void> {
284
+ logger.info("Forcing full conversation re-index");
285
+ this.stateManager.clearAllState();
286
+ await this.runIndexingBatch();
287
+ }
288
+
289
+ /**
290
+ * Get current job status
291
+ */
292
+ public getStatus(): {
293
+ isRunning: boolean;
294
+ isBatchRunning: boolean;
295
+ intervalMs: number;
296
+ stateStats: ReturnType<IndexingStateManager["getStats"]>;
297
+ } {
298
+ return {
299
+ isRunning: this.isRunning,
300
+ isBatchRunning: this.isBatchRunning,
301
+ intervalMs: this.intervalMs,
302
+ stateStats: this.stateManager.getStats(),
303
+ };
304
+ }
305
+
306
+ /**
307
+ * Reset singleton instance (for testing)
308
+ */
309
+ public static resetInstance(): void {
310
+ if (ConversationIndexingJob.instance) {
311
+ ConversationIndexingJob.instance.stop();
312
+ ConversationIndexingJob.instance = null;
313
+ }
314
+ }
315
+ }
316
+
317
+ // Export lazy getter to avoid eagerly initializing at module load time
318
+ export function getConversationIndexingJob(): ConversationIndexingJob {
319
+ return ConversationIndexingJob.getInstance();
320
+ }
@@ -0,0 +1,338 @@
1
+ /**
2
+ * IndexingStateManager - Durable per-conversation indexing state
3
+ *
4
+ * This manager tracks the indexing state of conversations to determine when
5
+ * they need to be re-indexed. It uses a hash-based approach to detect changes
6
+ * in conversation metadata (title, summary, last_user_message, lastActivity).
7
+ *
8
+ * Key features:
9
+ * - Durable state: persisted to disk in a KV store
10
+ * - Detects metadata changes via hash comparison
11
+ * - Bounded memory: only loads state for active projects
12
+ * - No unbounded growth: old entries naturally expire
13
+ */
14
+
15
+ import { createHash } from "crypto";
16
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
17
+ import { join } from "path";
18
+ import { logger } from "@/utils/logger";
19
+ import { readLightweightMetadata } from "@/conversations/ConversationDiskReader";
20
+
21
+ /**
22
+ * State for a single conversation
23
+ */
24
+ interface ConversationIndexState {
25
+ /** Hash of indexed metadata */
26
+ metadataHash: string;
27
+ /** Timestamp of last indexing */
28
+ lastIndexedAt: number;
29
+ /** Last known activity timestamp */
30
+ lastActivity?: number;
31
+ /** Whether this conversation has no indexable content */
32
+ noContent?: boolean;
33
+ }
34
+
35
+ /**
36
+ * State file structure
37
+ */
38
+ interface StateFile {
39
+ version: number;
40
+ states: Record<string, ConversationIndexState>; // Key: "projectId:conversationId"
41
+ }
42
+
43
+ /**
44
+ * Manager for conversation indexing state with bounded storage
45
+ * Eviction strategy: FIFO based on lastIndexedAt timestamp
46
+ */
47
+ export class IndexingStateManager {
48
+ private static readonly STATE_VERSION = 1;
49
+ private static readonly MAX_ENTRIES = 10000; // Prevent unbounded growth
50
+ private static readonly EVICTION_BATCH_SIZE = 1000; // Remove oldest 10% when full
51
+
52
+ private stateFilePath: string;
53
+ private states: Map<string, ConversationIndexState> = new Map();
54
+ private dirty = false;
55
+ private saveTimer: NodeJS.Timeout | null = null;
56
+
57
+ constructor(baseDir: string) {
58
+ // Store state file in the projects directory
59
+ this.stateFilePath = join(baseDir, "indexing-state.json");
60
+ this.loadState();
61
+ }
62
+
63
+ /**
64
+ * Load state from disk
65
+ */
66
+ private loadState(): void {
67
+ try {
68
+ if (!existsSync(this.stateFilePath)) {
69
+ logger.debug("No indexing state file found, starting fresh");
70
+ return;
71
+ }
72
+
73
+ const content = readFileSync(this.stateFilePath, "utf-8");
74
+ const stateFile: StateFile = JSON.parse(content);
75
+
76
+ if (stateFile.version !== IndexingStateManager.STATE_VERSION) {
77
+ logger.warn("Indexing state version mismatch, resetting state");
78
+ return;
79
+ }
80
+
81
+ // Load into map
82
+ for (const [key, value] of Object.entries(stateFile.states)) {
83
+ this.states.set(key, value);
84
+ }
85
+
86
+ logger.info(`Loaded indexing state: ${this.states.size} entries`);
87
+ } catch (error) {
88
+ logger.error("Failed to load indexing state, starting fresh", { error });
89
+ this.states.clear();
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Save state to disk (debounced)
95
+ */
96
+ private scheduleSave(): void {
97
+ if (!this.dirty) {
98
+ this.dirty = true;
99
+ }
100
+
101
+ // Clear existing timer
102
+ if (this.saveTimer) {
103
+ clearTimeout(this.saveTimer);
104
+ }
105
+
106
+ // Schedule save in 5 seconds
107
+ this.saveTimer = setTimeout(() => {
108
+ this.saveNow();
109
+ }, 5000);
110
+ }
111
+
112
+ /**
113
+ * Immediately save state to disk
114
+ */
115
+ public saveNow(): void {
116
+ if (!this.dirty) return;
117
+
118
+ try {
119
+ // Ensure directory exists
120
+ const dir = join(this.stateFilePath, "..");
121
+ if (!existsSync(dir)) {
122
+ mkdirSync(dir, { recursive: true });
123
+ }
124
+
125
+ // Evict old entries if needed
126
+ if (this.states.size > IndexingStateManager.MAX_ENTRIES) {
127
+ this.evictOldEntries();
128
+ }
129
+
130
+ // Convert map to object
131
+ const statesObj: Record<string, ConversationIndexState> = {};
132
+ for (const [key, value] of this.states.entries()) {
133
+ statesObj[key] = value;
134
+ }
135
+
136
+ const stateFile: StateFile = {
137
+ version: IndexingStateManager.STATE_VERSION,
138
+ states: statesObj,
139
+ };
140
+
141
+ writeFileSync(this.stateFilePath, JSON.stringify(stateFile, null, 2), "utf-8");
142
+ this.dirty = false;
143
+
144
+ logger.debug(`Saved indexing state: ${this.states.size} entries`);
145
+ } catch (error) {
146
+ logger.error("Failed to save indexing state", { error });
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Evict oldest entries when reaching max size
152
+ * Uses FIFO eviction based on lastIndexedAt timestamp (oldest indexed first)
153
+ */
154
+ private evictOldEntries(): void {
155
+ // Sort by lastIndexedAt (oldest first)
156
+ const entries = Array.from(this.states.entries()).sort(
157
+ (a, b) => a[1].lastIndexedAt - b[1].lastIndexedAt
158
+ );
159
+
160
+ // Remove oldest batch (FIFO)
161
+ const toRemove = entries.slice(0, IndexingStateManager.EVICTION_BATCH_SIZE);
162
+ for (const [key] of toRemove) {
163
+ this.states.delete(key);
164
+ }
165
+
166
+ logger.info(
167
+ `Evicted ${toRemove.length} old indexing state entries via FIFO (max: ${IndexingStateManager.MAX_ENTRIES})`
168
+ );
169
+ }
170
+
171
+ /**
172
+ * Build a composite key for state lookup
173
+ */
174
+ private buildKey(projectId: string, conversationId: string): string {
175
+ return `${projectId}:${conversationId}`;
176
+ }
177
+
178
+ /**
179
+ * Calculate metadata hash for a conversation
180
+ * Hash includes: title, summary, lastUserMessage, lastActivity
181
+ * Returns both hash and lastActivity to avoid double reads
182
+ */
183
+ private calculateMetadataHash(
184
+ basePath: string,
185
+ projectId: string,
186
+ conversationId: string
187
+ ): { hash: string; lastActivity: number } | null {
188
+ try {
189
+ const metadata = readLightweightMetadata(basePath, projectId, conversationId);
190
+ if (!metadata) return null;
191
+
192
+ // Build a stable string representation
193
+ const parts: string[] = [
194
+ metadata.title || "",
195
+ metadata.summary || "",
196
+ metadata.lastUserMessage || "",
197
+ String(metadata.lastActivity || 0),
198
+ ];
199
+
200
+ const hashInput = parts.join("|");
201
+ const hash = createHash("sha256").update(hashInput).digest("hex");
202
+
203
+ return {
204
+ hash,
205
+ lastActivity: metadata.lastActivity || 0,
206
+ };
207
+ } catch (error) {
208
+ logger.debug(`Failed to calculate metadata hash for ${conversationId.substring(0, 8)}`, {
209
+ error,
210
+ });
211
+ return null;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Check if a conversation needs indexing
217
+ * Returns true if:
218
+ * - Never indexed before
219
+ * - Metadata has changed (different hash)
220
+ * - Activity timestamp advanced (only if conversation had content before)
221
+ */
222
+ public needsIndexing(
223
+ basePath: string,
224
+ projectId: string,
225
+ conversationId: string
226
+ ): boolean {
227
+ const key = this.buildKey(projectId, conversationId);
228
+ const currentState = this.states.get(key);
229
+
230
+ // Calculate current metadata hash (includes lastActivity to avoid double read)
231
+ const result = this.calculateMetadataHash(basePath, projectId, conversationId);
232
+ if (!result) {
233
+ // Can't read metadata - skip
234
+ return false;
235
+ }
236
+
237
+ const { hash: currentHash, lastActivity: currentActivity } = result;
238
+
239
+ // Never indexed before
240
+ if (!currentState) {
241
+ return true;
242
+ }
243
+
244
+ // If previously marked as no-content, check if activity changed
245
+ // (which might mean new messages were added)
246
+ if (currentState.noContent) {
247
+ const lastActivity = currentState.lastActivity || 0;
248
+ return currentActivity > lastActivity;
249
+ }
250
+
251
+ // Metadata changed
252
+ if (currentState.metadataHash !== currentHash) {
253
+ return true;
254
+ }
255
+
256
+ // Check if activity advanced
257
+ const lastActivity = currentState.lastActivity || 0;
258
+ if (currentActivity > lastActivity) {
259
+ return true;
260
+ }
261
+
262
+ // Already indexed and unchanged
263
+ return false;
264
+ }
265
+
266
+ /**
267
+ * Mark a conversation as indexed
268
+ * @param noContent - Set to true if the conversation has no indexable content
269
+ */
270
+ public markIndexed(
271
+ basePath: string,
272
+ projectId: string,
273
+ conversationId: string,
274
+ noContent = false
275
+ ): void {
276
+ const key = this.buildKey(projectId, conversationId);
277
+ const result = this.calculateMetadataHash(basePath, projectId, conversationId);
278
+
279
+ if (!result) {
280
+ logger.debug(`Cannot mark ${conversationId.substring(0, 8)} as indexed - no metadata`);
281
+ return;
282
+ }
283
+
284
+ const { hash, lastActivity } = result;
285
+
286
+ this.states.set(key, {
287
+ metadataHash: hash,
288
+ lastIndexedAt: Date.now(),
289
+ lastActivity,
290
+ noContent,
291
+ });
292
+
293
+ this.scheduleSave();
294
+ }
295
+
296
+ /**
297
+ * Clear a conversation's indexing state (forces re-index)
298
+ */
299
+ public clearState(projectId: string, conversationId: string): void {
300
+ const key = this.buildKey(projectId, conversationId);
301
+ this.states.delete(key);
302
+ this.scheduleSave();
303
+ }
304
+
305
+ /**
306
+ * Clear all state (forces full re-index)
307
+ */
308
+ public clearAllState(): void {
309
+ this.states.clear();
310
+ this.scheduleSave();
311
+ }
312
+
313
+ /**
314
+ * Get statistics about the state
315
+ */
316
+ public getStats(): {
317
+ totalEntries: number;
318
+ maxEntries: number;
319
+ isDirty: boolean;
320
+ } {
321
+ return {
322
+ totalEntries: this.states.size,
323
+ maxEntries: IndexingStateManager.MAX_ENTRIES,
324
+ isDirty: this.dirty,
325
+ };
326
+ }
327
+
328
+ /**
329
+ * Cleanup and save before shutdown
330
+ */
331
+ public dispose(): void {
332
+ if (this.saveTimer) {
333
+ clearTimeout(this.saveTimer);
334
+ this.saveTimer = null;
335
+ }
336
+ this.saveNow();
337
+ }
338
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Conversation Embeddings Module
3
+ *
4
+ * Provides semantic search capabilities for conversations using RAG.
5
+ */
6
+
7
+ export {
8
+ ConversationEmbeddingService,
9
+ getConversationEmbeddingService,
10
+ type ConversationEmbeddingDocument,
11
+ type SemanticSearchResult,
12
+ type SemanticSearchOptions,
13
+ } from "./ConversationEmbeddingService";
14
+
15
+ export {
16
+ ConversationIndexingJob,
17
+ getConversationIndexingJob,
18
+ } from "./ConversationIndexingJob";