@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,305 @@
1
+ import type { EventRoutingLogger } from "@/logging/EventRoutingLogger";
2
+ import { logger } from "@/utils/logger";
3
+ import type { Hexpubkey, NDKEvent, NDKFilter, NDKSubscription } from "@nostr-dev-kit/ndk";
4
+ import type NDK from "@nostr-dev-kit/ndk";
5
+ import { SubscriptionFilterBuilder } from "./filters/SubscriptionFilterBuilder";
6
+
7
+ /**
8
+ * Manages independent subscriptions for different event categories.
9
+ *
10
+ * Instead of a single monolithic subscription that is torn down and recreated
11
+ * whenever any tracked set changes, this manager maintains four independent
12
+ * subscription groups:
13
+ *
14
+ * 1. Static — project discovery, config updates, lesson comments (never recreated)
15
+ * 2. Known-projects — events tagged with project a-tags (recreated on project changes)
16
+ * 3. Agent-mentions — events p-tagging agents (recreated on agent pubkey changes)
17
+ * 4. Per-agent lessons — one per agent definition ID (individually managed)
18
+ */
19
+ export class SubscriptionManager {
20
+ private ndk: NDK;
21
+ private eventHandler: (event: NDKEvent) => Promise<void>;
22
+ private routingLogger: EventRoutingLogger;
23
+ private whitelistedPubkeys: Set<Hexpubkey>;
24
+
25
+ // Dedup: multiple subscriptions can deliver the same event
26
+ private recentEventIds = new Set<string>();
27
+ private recentEventTimer: NodeJS.Timeout | null = null;
28
+
29
+ // Independent subscription groups
30
+ private staticSubscription: NDKSubscription | null = null;
31
+ private projectSubscription: NDKSubscription | null = null;
32
+ private agentMentionsSubscription: NDKSubscription | null = null;
33
+ private lessonSubscriptions = new Map<string, NDKSubscription>();
34
+
35
+ // Per-subscription since tracking
36
+ private lastProjectSubCreatedAt: number | null = null;
37
+ private lastAgentMentionsSubCreatedAt: number | null = null;
38
+
39
+ // Debounce for agent mentions updates
40
+ private agentMentionsTimer: NodeJS.Timeout | null = null;
41
+ private pendingAgentMentionsPubkeys: Set<Hexpubkey> | null = null;
42
+
43
+ constructor(
44
+ ndk: NDK,
45
+ eventHandler: (event: NDKEvent) => Promise<void>,
46
+ whitelistedPubkeys: Hexpubkey[],
47
+ routingLogger: EventRoutingLogger
48
+ ) {
49
+ this.ndk = ndk;
50
+ this.eventHandler = eventHandler;
51
+ this.whitelistedPubkeys = new Set(whitelistedPubkeys);
52
+ this.routingLogger = routingLogger;
53
+ }
54
+
55
+ /**
56
+ * Start subscriptions. Creates the static subscription immediately.
57
+ * Project and agent-mentions subscriptions are created later as data arrives.
58
+ */
59
+ async start(): Promise<void> {
60
+ logger.debug("Starting subscription manager", {
61
+ whitelistedPubkeys: Array.from(this.whitelistedPubkeys).map((p) => p.slice(0, 8)),
62
+ });
63
+
64
+ const filters = SubscriptionFilterBuilder.buildStaticFilters(this.whitelistedPubkeys);
65
+ if (filters.length > 0) {
66
+ this.staticSubscription = this.createSub(filters, "static");
67
+ }
68
+
69
+ await this.routingLogger.logSubscriptionFilters({
70
+ filters,
71
+ whitelistedAuthors: this.whitelistedPubkeys.size,
72
+ trackedProjects: 0,
73
+ trackedAgents: 0,
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Update known projects. Recreates the project subscription with new project IDs.
79
+ * Uses `since` on restarts to prevent historical event re-delivery.
80
+ */
81
+ updateKnownProjects(projectIds: string[]): void {
82
+ const knownProjects = new Set(projectIds);
83
+
84
+ // Stop existing project subscription
85
+ if (this.projectSubscription) {
86
+ this.projectSubscription.stop();
87
+ this.projectSubscription = null;
88
+ }
89
+
90
+ if (knownProjects.size === 0) {
91
+ return;
92
+ }
93
+
94
+ const since = this.lastProjectSubCreatedAt ?? undefined;
95
+ this.lastProjectSubCreatedAt = Math.floor(Date.now() / 1000);
96
+
97
+ const filters: NDKFilter[] = [];
98
+
99
+ const taggedFilter = SubscriptionFilterBuilder.buildProjectTaggedFilter(knownProjects, since);
100
+ if (taggedFilter) filters.push(taggedFilter);
101
+
102
+ const reportFilter = SubscriptionFilterBuilder.buildReportFilter(knownProjects);
103
+ if (reportFilter) filters.push(reportFilter);
104
+
105
+ if (filters.length > 0) {
106
+ this.projectSubscription = this.createSub(filters, "projects");
107
+ logger.debug("Project subscription updated", {
108
+ projects: knownProjects.size,
109
+ since,
110
+ });
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Update agent mentions subscription. Debounced with 2s timer since
116
+ * agent additions can batch (e.g. during project boot with multiple agents).
117
+ */
118
+ updateAgentMentions(pubkeys: Hexpubkey[]): void {
119
+ this.pendingAgentMentionsPubkeys = new Set(pubkeys);
120
+
121
+ if (this.agentMentionsTimer) {
122
+ clearTimeout(this.agentMentionsTimer);
123
+ }
124
+
125
+ this.agentMentionsTimer = setTimeout(() => {
126
+ this.agentMentionsTimer = null;
127
+ this.applyAgentMentionsUpdate();
128
+ }, 2000);
129
+ }
130
+
131
+ private applyAgentMentionsUpdate(): void {
132
+ const pubkeys = this.pendingAgentMentionsPubkeys;
133
+ this.pendingAgentMentionsPubkeys = null;
134
+
135
+ if (!pubkeys) return;
136
+
137
+ // Stop existing agent mentions subscription
138
+ if (this.agentMentionsSubscription) {
139
+ this.agentMentionsSubscription.stop();
140
+ this.agentMentionsSubscription = null;
141
+ }
142
+
143
+ if (pubkeys.size === 0) {
144
+ return;
145
+ }
146
+
147
+ const since = this.lastAgentMentionsSubCreatedAt ?? undefined;
148
+ this.lastAgentMentionsSubCreatedAt = Math.floor(Date.now() / 1000);
149
+
150
+ const filter = SubscriptionFilterBuilder.buildAgentMentionsFilter(pubkeys, since);
151
+ if (filter) {
152
+ this.agentMentionsSubscription = this.createSub([filter], "agent-mentions");
153
+ logger.debug("Agent mentions subscription updated", {
154
+ agents: pubkeys.size,
155
+ since,
156
+ });
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Add a lesson subscription for a specific agent definition ID.
162
+ * Uses NDK groupable to merge with other lesson subscriptions.
163
+ */
164
+ addLessonSubscription(definitionId: string): void {
165
+ if (this.lessonSubscriptions.has(definitionId)) {
166
+ return;
167
+ }
168
+
169
+ const filter = SubscriptionFilterBuilder.buildLessonFilter(definitionId);
170
+ const sub = this.ndk.subscribe([filter], {
171
+ closeOnEose: false,
172
+ groupable: true,
173
+ onEvent: (event: NDKEvent) => this.handleEvent(event),
174
+ });
175
+
176
+ this.lessonSubscriptions.set(definitionId, sub);
177
+ logger.debug("Lesson subscription added", {
178
+ definitionId: definitionId.substring(0, 12),
179
+ totalLessonSubs: this.lessonSubscriptions.size,
180
+ });
181
+ }
182
+
183
+ /**
184
+ * Remove a lesson subscription for a specific agent definition ID.
185
+ */
186
+ removeLessonSubscription(definitionId: string): void {
187
+ const sub = this.lessonSubscriptions.get(definitionId);
188
+ if (sub) {
189
+ sub.stop();
190
+ this.lessonSubscriptions.delete(definitionId);
191
+ logger.debug("Lesson subscription removed", {
192
+ definitionId: definitionId.substring(0, 12),
193
+ totalLessonSubs: this.lessonSubscriptions.size,
194
+ });
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Stop all subscriptions.
200
+ */
201
+ stop(): void {
202
+ if (this.agentMentionsTimer) {
203
+ clearTimeout(this.agentMentionsTimer);
204
+ this.agentMentionsTimer = null;
205
+ }
206
+
207
+ if (this.recentEventTimer) {
208
+ clearTimeout(this.recentEventTimer);
209
+ this.recentEventTimer = null;
210
+ }
211
+ this.recentEventIds.clear();
212
+
213
+ if (this.staticSubscription) {
214
+ this.staticSubscription.stop();
215
+ this.staticSubscription = null;
216
+ }
217
+
218
+ if (this.projectSubscription) {
219
+ this.projectSubscription.stop();
220
+ this.projectSubscription = null;
221
+ }
222
+
223
+ if (this.agentMentionsSubscription) {
224
+ this.agentMentionsSubscription.stop();
225
+ this.agentMentionsSubscription = null;
226
+ }
227
+
228
+ for (const [, sub] of this.lessonSubscriptions) {
229
+ sub.stop();
230
+ }
231
+ this.lessonSubscriptions.clear();
232
+
233
+ logger.debug("All subscriptions stopped");
234
+ }
235
+
236
+ /**
237
+ * Get current subscription status.
238
+ */
239
+ getStatus(): {
240
+ active: boolean;
241
+ whitelistedPubkeys: number;
242
+ staticActive: boolean;
243
+ projectActive: boolean;
244
+ agentMentionsActive: boolean;
245
+ lessonSubscriptions: number;
246
+ } {
247
+ return {
248
+ active: this.staticSubscription !== null,
249
+ whitelistedPubkeys: this.whitelistedPubkeys.size,
250
+ staticActive: this.staticSubscription !== null,
251
+ projectActive: this.projectSubscription !== null,
252
+ agentMentionsActive: this.agentMentionsSubscription !== null,
253
+ lessonSubscriptions: this.lessonSubscriptions.size,
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Create an NDK subscription with the shared event handler.
259
+ */
260
+ private createSub(filters: NDKFilter[], label: string): NDKSubscription {
261
+ const sub = this.ndk.subscribe(filters, {
262
+ closeOnEose: false,
263
+ groupable: false,
264
+ onEvent: (event: NDKEvent) => this.handleEvent(event),
265
+ onEose: () => {
266
+ logger.debug(`Subscription EOSE received [${label}]`);
267
+ },
268
+ });
269
+
270
+ return sub;
271
+ }
272
+
273
+ /**
274
+ * Handle incoming events from any subscription.
275
+ * Deduplicates across independent subscriptions — the same event can match
276
+ * both the project (#a) and agent-mentions (#p) filters.
277
+ */
278
+ private async handleEvent(event: NDKEvent): Promise<void> {
279
+ if (this.recentEventIds.has(event.id)) return;
280
+ this.recentEventIds.add(event.id);
281
+ this.scheduleEventIdCleanup();
282
+
283
+ try {
284
+ await this.eventHandler(event);
285
+ } catch (error) {
286
+ logger.error("Error handling event in subscription", {
287
+ error: error instanceof Error ? error.message : String(error),
288
+ eventId: event.id,
289
+ eventKind: event.kind,
290
+ });
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Periodically flush the seen-event set to prevent unbounded growth.
296
+ * Batches cleanup into 60s intervals.
297
+ */
298
+ private scheduleEventIdCleanup(): void {
299
+ if (this.recentEventTimer) return;
300
+ this.recentEventTimer = setTimeout(() => {
301
+ this.recentEventIds.clear();
302
+ this.recentEventTimer = null;
303
+ }, 60_000);
304
+ }
305
+ }
@@ -0,0 +1,318 @@
1
+ import * as net from "net";
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import type { StreamTransport } from "@/llm";
5
+ import type { LocalStreamChunk } from "@/llm";
6
+ import { logger } from "@/utils/logger";
7
+
8
+ const LOG_PREFIX = "[UnixSocketTransport]";
9
+
10
+ /** Extract a brief caller context from stack trace for debugging (only computed when debug logging enabled) */
11
+ function getCallerContext(): string | undefined {
12
+ // Only compute stack trace if debug logging is actually enabled
13
+ // This avoids the expensive stack capture in production
14
+ if (!logger.isLevelEnabled?.("debug")) {
15
+ return undefined;
16
+ }
17
+ const stack = new Error().stack;
18
+ if (!stack) return undefined;
19
+ // Skip first 3 lines: Error, getCallerContext, cleanup/caller
20
+ const lines = stack.split("\n").slice(3, 6);
21
+ return lines.map((l) => l.trim()).join(" <- ");
22
+ }
23
+
24
+ /** Result of checking socket file info */
25
+ type SocketFileInfoResult =
26
+ | { status: "ok"; exists: true; isSocket: boolean; isFile: boolean; mode: string; mtime: string; age: string }
27
+ | { status: "ok"; exists: false }
28
+ | { status: "error"; error: string };
29
+
30
+ /**
31
+ * Unix domain socket transport for local streaming
32
+ * Single client connection model
33
+ */
34
+ export class UnixSocketTransport implements StreamTransport {
35
+ private server: net.Server | null = null;
36
+ private client: net.Socket | null = null;
37
+ private socketPath: string;
38
+
39
+ constructor(socketPath?: string) {
40
+ this.socketPath = socketPath ?? this.defaultSocketPath();
41
+ }
42
+
43
+ private defaultSocketPath(): string {
44
+ const runtimeDir = process.env.XDG_RUNTIME_DIR;
45
+ if (runtimeDir) {
46
+ return path.join(runtimeDir, "tenex-stream.sock");
47
+ }
48
+ return "/tmp/tenex-stream.sock";
49
+ }
50
+
51
+ async start(): Promise<void> {
52
+ logger.info(`${LOG_PREFIX} start() called`, {
53
+ socketPath: this.socketPath,
54
+ });
55
+
56
+ // Check for existing socket and log details
57
+ const existingSocketInfo = this.getSocketFileInfo();
58
+ if (existingSocketInfo.status === "ok" && existingSocketInfo.exists) {
59
+ logger.warn(`${LOG_PREFIX} Stale socket found before start`, {
60
+ socketPath: this.socketPath,
61
+ isSocket: existingSocketInfo.isSocket,
62
+ age: existingSocketInfo.age,
63
+ });
64
+ } else if (existingSocketInfo.status === "error") {
65
+ logger.error(`${LOG_PREFIX} Failed to check socket file before start`, {
66
+ socketPath: this.socketPath,
67
+ error: existingSocketInfo.error,
68
+ });
69
+ }
70
+
71
+ // Clean up stale socket, passing the file info we already have
72
+ this.cleanup("start() - cleaning stale socket before creating new one", existingSocketInfo);
73
+
74
+ return new Promise((resolve, reject) => {
75
+ this.server = net.createServer((socket) => {
76
+ logger.info(`${LOG_PREFIX} Client connected to streaming socket`, {
77
+ socketPath: this.socketPath,
78
+ });
79
+
80
+ // Only one client at a time
81
+ if (this.client) {
82
+ logger.warn(`${LOG_PREFIX} Replacing existing client connection`, {
83
+ socketPath: this.socketPath,
84
+ });
85
+ this.client.destroy();
86
+ }
87
+
88
+ this.client = socket;
89
+
90
+ socket.on("close", () => {
91
+ logger.info(`${LOG_PREFIX} Client disconnected from streaming socket`, {
92
+ socketPath: this.socketPath,
93
+ });
94
+ if (this.client === socket) {
95
+ this.client = null;
96
+ }
97
+ });
98
+
99
+ socket.on("error", (err) => {
100
+ logger.error(`${LOG_PREFIX} Socket client error`, {
101
+ error: err.message,
102
+ socketPath: this.socketPath,
103
+ });
104
+ if (this.client === socket) {
105
+ this.client = null;
106
+ }
107
+ });
108
+ });
109
+
110
+ this.server.on("error", (err) => {
111
+ logger.error(`${LOG_PREFIX} Socket server error`, {
112
+ error: err.message,
113
+ socketPath: this.socketPath,
114
+ });
115
+ reject(err);
116
+ });
117
+
118
+ this.server.listen(this.socketPath, () => {
119
+ logger.info(`${LOG_PREFIX} Streaming socket started and listening`, {
120
+ socketPath: this.socketPath,
121
+ });
122
+ resolve();
123
+ });
124
+ });
125
+ }
126
+
127
+ write(chunk: LocalStreamChunk): void {
128
+ if (!this.client) return;
129
+
130
+ try {
131
+ const line = JSON.stringify(chunk) + "\n";
132
+ this.client.write(line);
133
+ } catch (err) {
134
+ logger.error(`${LOG_PREFIX} Failed to write chunk`, {
135
+ error: err instanceof Error ? err.message : String(err),
136
+ socketPath: this.socketPath,
137
+ });
138
+ }
139
+ }
140
+
141
+ isConnected(): boolean {
142
+ return this.client !== null && !this.client.destroyed;
143
+ }
144
+
145
+ async stop(): Promise<void> {
146
+ const callerContext = getCallerContext();
147
+ logger.info(`${LOG_PREFIX} stop() called`, {
148
+ socketPath: this.socketPath,
149
+ hasClient: !!this.client,
150
+ hasServer: !!this.server,
151
+ ...(callerContext && { callerContext }),
152
+ });
153
+
154
+ if (this.client) {
155
+ logger.info(`${LOG_PREFIX} Destroying client connection in stop()`, {
156
+ socketPath: this.socketPath,
157
+ });
158
+ this.client.destroy();
159
+ this.client = null;
160
+ }
161
+
162
+ return new Promise((resolve) => {
163
+ if (this.server) {
164
+ logger.info(`${LOG_PREFIX} Closing server in stop()`, {
165
+ socketPath: this.socketPath,
166
+ });
167
+ this.server.close(() => {
168
+ logger.info(`${LOG_PREFIX} Server closed, now calling cleanup()`, {
169
+ socketPath: this.socketPath,
170
+ });
171
+ this.cleanup("stop() - server closed callback");
172
+ logger.info(`${LOG_PREFIX} stop() completed`, {
173
+ socketPath: this.socketPath,
174
+ });
175
+ resolve();
176
+ });
177
+ } else {
178
+ logger.info(`${LOG_PREFIX} stop() called but no server to close`, {
179
+ socketPath: this.socketPath,
180
+ });
181
+ resolve();
182
+ }
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Get file info for the socket path (for debugging)
188
+ * Returns discriminated result: ok (exists/not), or error
189
+ */
190
+ private getSocketFileInfo(): SocketFileInfoResult {
191
+ try {
192
+ const stats = fs.lstatSync(this.socketPath);
193
+ const ageMs = Date.now() - stats.mtime.getTime();
194
+ return {
195
+ status: "ok",
196
+ exists: true,
197
+ isSocket: stats.isSocket(),
198
+ isFile: stats.isFile(),
199
+ mode: stats.mode.toString(8),
200
+ mtime: stats.mtime.toISOString(),
201
+ age: `${Math.floor(ageMs / 1000)}s`,
202
+ };
203
+ } catch (err) {
204
+ // ENOENT means file doesn't exist - that's a valid "missing" result
205
+ if (err instanceof Error && "code" in err && (err as NodeJS.ErrnoException).code === "ENOENT") {
206
+ return { status: "ok", exists: false };
207
+ }
208
+ // Any other error (permission, IO, etc.) is an actual error
209
+ return {
210
+ status: "error",
211
+ error: err instanceof Error ? err.message : String(err),
212
+ };
213
+ }
214
+ }
215
+
216
+ /**
217
+ * Check if socket exists and is healthy
218
+ */
219
+ checkSocketHealth(): {
220
+ exists: boolean;
221
+ isSocket: boolean;
222
+ serverRunning: boolean;
223
+ clientConnected: boolean;
224
+ } {
225
+ const info = this.getSocketFileInfo();
226
+ const exists = info.status === "ok" && info.exists;
227
+ const isSocket = info.status === "ok" && info.exists && info.isSocket;
228
+ const result = {
229
+ exists,
230
+ isSocket,
231
+ serverRunning: this.server !== null && this.server.listening,
232
+ clientConnected: this.isConnected(),
233
+ };
234
+ logger.debug(`${LOG_PREFIX} Health check`, {
235
+ socketPath: this.socketPath,
236
+ ...result,
237
+ });
238
+ return result;
239
+ }
240
+
241
+ /**
242
+ * Clean up socket file if it exists and is safe to remove
243
+ * @param reason - Why cleanup is being called (for logging)
244
+ * @param fileInfo - Optional pre-fetched file info to avoid redundant FS calls
245
+ */
246
+ private cleanup(reason: string, fileInfo?: SocketFileInfoResult): void {
247
+ const callerContext = getCallerContext();
248
+
249
+ logger.info(`${LOG_PREFIX} cleanup() called`, {
250
+ socketPath: this.socketPath,
251
+ reason,
252
+ ...(callerContext && { callerContext }),
253
+ });
254
+
255
+ // Use provided file info or fetch it
256
+ const info = fileInfo ?? this.getSocketFileInfo();
257
+
258
+ // Handle error case
259
+ if (info.status === "error") {
260
+ logger.error(`${LOG_PREFIX} cleanup() cannot proceed - failed to check socket file`, {
261
+ socketPath: this.socketPath,
262
+ reason,
263
+ error: info.error,
264
+ });
265
+ return;
266
+ }
267
+
268
+ // Nothing to clean up
269
+ if (!info.exists) {
270
+ logger.debug(`${LOG_PREFIX} cleanup() - socket does not exist, nothing to unlink`, {
271
+ socketPath: this.socketPath,
272
+ reason,
273
+ });
274
+ return;
275
+ }
276
+
277
+ // CRITICAL SAFETY CHECK: Only unlink if it's actually a socket
278
+ if (!info.isSocket) {
279
+ logger.error(`${LOG_PREFIX} cleanup() REFUSED to unlink - path is not a socket`, {
280
+ socketPath: this.socketPath,
281
+ reason,
282
+ isFile: info.isFile,
283
+ mode: info.mode,
284
+ });
285
+ return;
286
+ }
287
+
288
+ // Safe to unlink - it's a socket
289
+ try {
290
+ logger.info(`${LOG_PREFIX} About to unlink socket`, {
291
+ socketPath: this.socketPath,
292
+ reason,
293
+ age: info.age,
294
+ });
295
+
296
+ fs.unlinkSync(this.socketPath);
297
+
298
+ logger.info(`${LOG_PREFIX} Socket unlinked successfully`, {
299
+ socketPath: this.socketPath,
300
+ reason,
301
+ });
302
+ } catch (err) {
303
+ const errorMessage = err instanceof Error ? err.message : String(err);
304
+ const errorCode = err instanceof Error && "code" in err ? (err as NodeJS.ErrnoException).code : undefined;
305
+
306
+ logger.error(`${LOG_PREFIX} cleanup() failed to unlink socket`, {
307
+ socketPath: this.socketPath,
308
+ reason,
309
+ error: errorMessage,
310
+ errorCode,
311
+ });
312
+ }
313
+ }
314
+
315
+ getSocketPath(): string {
316
+ return this.socketPath;
317
+ }
318
+ }