@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,260 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { promisify } from "node:util";
4
+ import { exec } from "node:child_process";
5
+ import { logger } from "@/utils/logger";
6
+ import { ensureWorktreesGitignore } from "./gitignore";
7
+
8
+ const execAsync = promisify(exec);
9
+
10
+ /** Directory name for worktrees (relative to project root) */
11
+ export const WORKTREES_DIR = ".worktrees";
12
+
13
+ /**
14
+ * Sanitize a branch name for use as a directory name.
15
+ * Replaces forward slashes with underscores to avoid nested directories.
16
+ * @example sanitizeBranchName("feature/whatever") => "feature_whatever"
17
+ */
18
+ export function sanitizeBranchName(branch: string): string {
19
+ return branch.replace(/\//g, "_");
20
+ }
21
+
22
+ /**
23
+ * Metadata for a git worktree
24
+ */
25
+ export interface WorktreeMetadata {
26
+ path: string;
27
+ branch: string;
28
+ createdBy: string; // Agent pubkey
29
+ conversationId: string;
30
+ parentBranch: string;
31
+ createdAt: number;
32
+ mergedAt?: number;
33
+ deletedAt?: number;
34
+ }
35
+
36
+ // ============================================================================
37
+ // Core Worktree Operations
38
+ // ============================================================================
39
+
40
+ /**
41
+ * List all git worktrees for a project.
42
+ * The main repository is always included as the first entry.
43
+ * Additional worktrees are located in .worktrees/ subdirectory.
44
+ *
45
+ * @param projectPath - Root project directory (normal git repo)
46
+ * @returns Array of worktrees with branch name and path
47
+ */
48
+ export async function listWorktrees(projectPath: string): Promise<Array<{ branch: string; path: string }>> {
49
+ try {
50
+ const { stdout } = await execAsync("git worktree list --porcelain", { cwd: projectPath });
51
+
52
+ const worktrees: Array<{ branch: string; path: string }> = [];
53
+ const lines = stdout.trim().split("\n");
54
+
55
+ let currentWorktree: { path?: string; branch?: string } = {};
56
+
57
+ for (const line of lines) {
58
+ if (line.startsWith("worktree ")) {
59
+ currentWorktree.path = line.substring(9);
60
+ } else if (line.startsWith("branch ")) {
61
+ currentWorktree.branch = line.substring(7).replace("refs/heads/", "");
62
+ } else if (line === "") {
63
+ // Empty line marks end of worktree entry
64
+ if (currentWorktree.path && currentWorktree.branch) {
65
+ worktrees.push({
66
+ path: currentWorktree.path,
67
+ branch: currentWorktree.branch,
68
+ });
69
+ }
70
+ currentWorktree = {};
71
+ }
72
+ }
73
+
74
+ // Handle last entry if no trailing newline
75
+ if (currentWorktree.path && currentWorktree.branch) {
76
+ worktrees.push({
77
+ path: currentWorktree.path,
78
+ branch: currentWorktree.branch,
79
+ });
80
+ }
81
+
82
+ return worktrees;
83
+ } catch (error) {
84
+ logger.error("Failed to list worktrees", { projectPath, error });
85
+ return [];
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Create a new git worktree in the .worktrees/ directory.
91
+ * Branch names are sanitized (slashes replaced with underscores) for directory names.
92
+ * Also ensures .worktrees is added to .gitignore.
93
+ *
94
+ * @param projectPath - Root project directory (normal git repo)
95
+ * @param branchName - Name for the new branch (can contain slashes)
96
+ * @param baseBranch - Branch to create from (typically current branch)
97
+ * @returns Path to the new worktree
98
+ *
99
+ * @example
100
+ * // Creates worktree at ~/tenex/project/.worktrees/feature_auth/
101
+ * await createWorktree("~/tenex/project", "feature/auth", "main");
102
+ */
103
+ export async function createWorktree(
104
+ projectPath: string,
105
+ branchName: string,
106
+ baseBranch: string
107
+ ): Promise<string> {
108
+ try {
109
+ // Ensure .worktrees is in .gitignore before creating any worktrees
110
+ await ensureWorktreesGitignore(projectPath);
111
+
112
+ // Create .worktrees directory if it doesn't exist
113
+ const worktreesDir = path.join(projectPath, WORKTREES_DIR);
114
+ await fs.mkdir(worktreesDir, { recursive: true });
115
+
116
+ // Sanitize branch name for directory (feature/whatever -> feature_whatever)
117
+ const sanitizedName = sanitizeBranchName(branchName);
118
+ const worktreePath = path.join(worktreesDir, sanitizedName);
119
+
120
+ // Check if worktree already exists
121
+ const existingWorktrees = await listWorktrees(projectPath);
122
+ if (existingWorktrees.some((wt) => wt.branch === branchName)) {
123
+ logger.info("Worktree already exists", { branchName, path: worktreePath });
124
+ return worktreePath;
125
+ }
126
+
127
+ // Check if path exists on filesystem
128
+ try {
129
+ await fs.access(worktreePath);
130
+ // Path exists but not in worktree list - this is an error state
131
+ throw new Error(
132
+ `Directory "${worktreePath}" exists but is not a registered git worktree. ` +
133
+ "Remove it manually or use a different branch name."
134
+ );
135
+ } catch (err: unknown) {
136
+ if (err instanceof Error && "code" in err && err.code !== "ENOENT") throw err;
137
+ // Path doesn't exist - safe to create
138
+ }
139
+
140
+ // Create worktree from repository
141
+ // Wrap in try-catch to handle race conditions where another process creates the worktree
142
+ try {
143
+ await execAsync(
144
+ `git worktree add -b ${JSON.stringify(branchName)} ${JSON.stringify(worktreePath)} ${JSON.stringify(baseBranch)}`,
145
+ { cwd: projectPath }
146
+ );
147
+ } catch (createError: unknown) {
148
+ // Check if worktree was created by another process (race condition)
149
+ const refreshedWorktrees = await listWorktrees(projectPath);
150
+ if (refreshedWorktrees.some((wt) => wt.branch === branchName)) {
151
+ logger.info("Worktree was created by another process", { branchName, path: worktreePath });
152
+ return worktreePath;
153
+ }
154
+ // Re-throw if it's a different error
155
+ throw createError;
156
+ }
157
+
158
+ logger.info("Created worktree", {
159
+ branchName,
160
+ sanitizedName,
161
+ path: worktreePath,
162
+ baseBranch
163
+ });
164
+ return worktreePath;
165
+ } catch (error) {
166
+ logger.error("Failed to create worktree", { projectPath, branchName, baseBranch, error });
167
+ throw error;
168
+ }
169
+ }
170
+
171
+ // ============================================================================
172
+ // Worktree Metadata Management
173
+ // ============================================================================
174
+
175
+ /**
176
+ * Get the path to the worktree metadata file for a project
177
+ * @param projectPath - The base project directory
178
+ * @param projectsConfigPath - The base path for project configs (e.g., ~/.tenex/projects)
179
+ * @returns Path to the worktree metadata JSON file
180
+ */
181
+ export async function getWorktreeMetadataPath(projectPath: string, projectsConfigPath: string): Promise<string> {
182
+ // Extract dTag from project path (last segment of path)
183
+ const dTag = path.basename(projectPath);
184
+ const metadataDir = path.join(projectsConfigPath, dTag);
185
+
186
+ // Ensure the metadata directory exists
187
+ await fs.mkdir(metadataDir, { recursive: true });
188
+
189
+ return path.join(metadataDir, "worktrees.json");
190
+ }
191
+
192
+ /**
193
+ * Load worktree metadata for a project
194
+ * @param projectPath - The base project directory
195
+ * @param projectsConfigPath - The base path for project configs (e.g., ~/.tenex/projects)
196
+ * @returns Map of branch names to metadata
197
+ */
198
+ export async function loadWorktreeMetadata(
199
+ projectPath: string,
200
+ projectsConfigPath: string
201
+ ): Promise<Record<string, WorktreeMetadata>> {
202
+ try {
203
+ const metadataPath = await getWorktreeMetadataPath(projectPath, projectsConfigPath);
204
+ const content = await fs.readFile(metadataPath, "utf-8");
205
+ return JSON.parse(content);
206
+ } catch (error) {
207
+ // File doesn't exist or invalid JSON - return empty object
208
+ if (error && typeof error === "object" && "code" in error && error.code !== "ENOENT") {
209
+ logger.warn("Failed to load worktree metadata", {
210
+ projectPath,
211
+ error: error instanceof Error ? error.message : String(error)
212
+ });
213
+ }
214
+ return {};
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Save worktree metadata for a project
220
+ * @param projectPath - The base project directory
221
+ * @param projectsConfigPath - The base path for project configs
222
+ * @param metadata - Map of branch names to metadata
223
+ */
224
+ async function saveWorktreeMetadata(
225
+ projectPath: string,
226
+ projectsConfigPath: string,
227
+ metadata: Record<string, WorktreeMetadata>
228
+ ): Promise<void> {
229
+ const metadataPath = await getWorktreeMetadataPath(projectPath, projectsConfigPath);
230
+ await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
231
+ }
232
+
233
+ /**
234
+ * Track the creation of a new worktree
235
+ * @param projectPath - The base project directory
236
+ * @param projectsConfigPath - The base path for project configs
237
+ * @param metadata - The worktree metadata
238
+ */
239
+ export async function trackWorktreeCreation(
240
+ projectPath: string,
241
+ projectsConfigPath: string,
242
+ metadata: Omit<WorktreeMetadata, "createdAt">
243
+ ): Promise<void> {
244
+ const allMetadata = await loadWorktreeMetadata(projectPath, projectsConfigPath);
245
+
246
+ // Add timestamp and save
247
+ allMetadata[metadata.branch] = {
248
+ ...metadata,
249
+ createdAt: Date.now()
250
+ };
251
+
252
+ await saveWorktreeMetadata(projectPath, projectsConfigPath, allMetadata);
253
+
254
+ logger.info("Tracked worktree creation", {
255
+ branch: metadata.branch,
256
+ createdBy: metadata.createdBy.substring(0, 8),
257
+ conversationId: metadata.conversationId.substring(0, 8)
258
+ });
259
+ }
260
+
@@ -0,0 +1,70 @@
1
+ import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
2
+ import { logger } from "@/utils/logger";
3
+
4
+ /**
5
+ * Format agent lessons into a concise string without using LLM
6
+ * This is a simple concatenation with minimal formatting
7
+ */
8
+ export function formatLessonsForAgent(lessons: NDKAgentLesson[]): string {
9
+ if (lessons.length === 0) {
10
+ return "";
11
+ }
12
+
13
+ logger.debug("Formatting lessons for agent", {
14
+ lessonsCount: lessons.length,
15
+ });
16
+
17
+ // Format each lesson concisely - ALL OF THEM!
18
+ const formattedLessons = lessons
19
+ .map((lesson, index) => {
20
+ const title = lesson.title || "Untitled Lesson";
21
+ const content = lesson.lesson;
22
+ const category = lesson.category;
23
+ const hashtags = lesson.hashtags;
24
+ const hasDetailed = !!lesson.detailed;
25
+ // Get 12-char prefix for convenient lookup (lesson_get accepts prefixes)
26
+ const idPrefix = lesson.id ? lesson.id.substring(0, 12) : null;
27
+
28
+ // Build metadata line
29
+ let metadata = "";
30
+ if (category) metadata += ` [${category}]`;
31
+ if (hasDetailed) metadata += " [detailed available]";
32
+ if (hashtags && hashtags.length > 0) metadata += ` #${hashtags.join(" #")}`;
33
+
34
+ // Create a concise format for each lesson
35
+ // Show ID prefix for lesson_get if detailed version available
36
+ const detailedHint = hasDetailed && idPrefix
37
+ ? `\n↳ Use lesson_get("${idPrefix}") for detailed version`
38
+ : "";
39
+ return `#${index + 1}: ${title} ${metadata}\n${content}${detailedHint}`;
40
+ })
41
+ .join("\n\n");
42
+
43
+ // Add header for context
44
+ const header = `## Lessons Learned (${lessons.length} total)\n\n`;
45
+
46
+ return header + formattedLessons;
47
+ }
48
+
49
+ /**
50
+ * The standard lesson_learn tool reminder to encourage agents to continue learning.
51
+ */
52
+ export const LESSON_LEARN_REMINDER =
53
+ "Remember to use the `lesson_learn` tool when you discover new insights or patterns.";
54
+
55
+ /**
56
+ * Format lessons for inclusion in a system prompt.
57
+ * Includes the formatted lessons + the lesson_learn tool reminder.
58
+ * This is the single source of truth for lesson prompt formatting.
59
+ *
60
+ * @param lessons The agent's lessons
61
+ * @returns Formatted lessons with reminder, or empty string if no lessons
62
+ */
63
+ export function formatLessonsWithReminder(lessons: NDKAgentLesson[]): string {
64
+ if (lessons.length === 0) {
65
+ return "";
66
+ }
67
+
68
+ const formattedLessons = formatLessonsForAgent(lessons);
69
+ return `${formattedLessons}\n\n${LESSON_LEARN_REMINDER}`;
70
+ }
@@ -0,0 +1,24 @@
1
+ import type { NDKAgentLesson } from "@/events/NDKAgentLesson";
2
+ import type { Hexpubkey } from "@nostr-dev-kit/ndk";
3
+
4
+ /**
5
+ * Assess whether to trust a pubkey publishing a lesson event.
6
+ *
7
+ * This function determines if a lesson should be accepted and stored based on:
8
+ * - The pubkey that published the lesson
9
+ * - The lesson content and metadata
10
+ * - The agent definition the lesson is for
11
+ *
12
+ * @param _lesson The lesson event to assess (currently unused)
13
+ * @param _publisherPubkey The pubkey that published the lesson (currently unused)
14
+ * @returns true if the lesson should be trusted and stored, false otherwise
15
+ */
16
+ export function shouldTrustLesson(_lesson: NDKAgentLesson, _publisherPubkey: Hexpubkey): boolean {
17
+ // For now, trust all lessons
18
+ // Future implementations may add:
19
+ // - Whitelist/blacklist checks
20
+ // - Reputation scoring
21
+ // - Cryptographic verification
22
+ // - Content validation
23
+ return true;
24
+ }
@@ -0,0 +1,123 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import { logger } from "./logger";
4
+
5
+ /**
6
+ * Lockfile information
7
+ */
8
+ interface LockInfo {
9
+ pid: number;
10
+ hostname: string;
11
+ startedAt: number;
12
+ }
13
+
14
+ /**
15
+ * Lockfile manager for preventing multiple daemon instances
16
+ */
17
+ export class Lockfile {
18
+ private lockfilePath: string;
19
+ private currentPid: number;
20
+
21
+ constructor(lockfilePath: string) {
22
+ this.lockfilePath = lockfilePath;
23
+ this.currentPid = process.pid;
24
+ }
25
+
26
+ /**
27
+ * Acquire the lock. Throws if lock cannot be acquired.
28
+ */
29
+ async acquire(): Promise<void> {
30
+ // Check if lockfile exists using fs.stat
31
+ let lockfileExists = false;
32
+ try {
33
+ await fs.stat(this.lockfilePath);
34
+ lockfileExists = true;
35
+ } catch (error) {
36
+ const err = error as NodeJS.ErrnoException;
37
+ if (err.code !== "ENOENT") {
38
+ // Unexpected error accessing lockfile
39
+ throw error;
40
+ }
41
+ // File doesn't exist - we can proceed to create it
42
+ }
43
+
44
+ // If lockfile exists, check if the process is still running
45
+ if (lockfileExists) {
46
+ const content = await fs.readFile(this.lockfilePath, "utf-8");
47
+ const lockInfo: LockInfo = JSON.parse(content);
48
+
49
+ if (this.isProcessRunning(lockInfo.pid)) {
50
+ // Process is running - cannot acquire lock
51
+ throw new Error(
52
+ `Daemon is already running (PID: ${lockInfo.pid}, started at: ${new Date(lockInfo.startedAt).toISOString()})`
53
+ );
54
+ }
55
+
56
+ // Stale lockfile - previous process crashed or was killed
57
+ logger.warn("Found stale lockfile, removing it", {
58
+ stalePid: lockInfo.pid,
59
+ startedAt: new Date(lockInfo.startedAt).toISOString(),
60
+ });
61
+ await this.release();
62
+ }
63
+
64
+ // Create new lockfile
65
+ const lockInfo: LockInfo = {
66
+ pid: this.currentPid,
67
+ hostname: os.hostname(),
68
+ startedAt: Date.now(),
69
+ };
70
+
71
+ await fs.writeFile(this.lockfilePath, JSON.stringify(lockInfo, null, 2), "utf-8");
72
+
73
+ logger.debug("Lockfile acquired", {
74
+ lockfilePath: this.lockfilePath,
75
+ pid: this.currentPid,
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Release the lock
81
+ */
82
+ async release(): Promise<void> {
83
+ try {
84
+ await fs.unlink(this.lockfilePath);
85
+ logger.debug("Lockfile released", { lockfilePath: this.lockfilePath });
86
+ } catch (error) {
87
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
88
+ logger.warn("Failed to remove lockfile", {
89
+ lockfilePath: this.lockfilePath,
90
+ error: error instanceof Error ? error.message : String(error),
91
+ });
92
+ }
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Check if a process is running by PID
98
+ */
99
+ private isProcessRunning(pid: number): boolean {
100
+ try {
101
+ // Sending signal 0 doesn't actually send a signal,
102
+ // it just checks if the process exists
103
+ process.kill(pid, 0);
104
+ return true;
105
+ } catch (error) {
106
+ const err = error as NodeJS.ErrnoException;
107
+
108
+ // ESRCH means process doesn't exist
109
+ if (err.code === "ESRCH") {
110
+ return false;
111
+ }
112
+
113
+ // EPERM means process exists but we lack permission to signal it
114
+ if (err.code === "EPERM") {
115
+ return true;
116
+ }
117
+
118
+ // Unexpected error - re-throw
119
+ throw error;
120
+ }
121
+ }
122
+
123
+ }
@@ -0,0 +1,149 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import chalk from "chalk";
4
+
5
+ const levels: Record<string, number> = {
6
+ silent: 0,
7
+ error: 1,
8
+ warn: 2,
9
+ info: 3,
10
+ debug: 4,
11
+ };
12
+
13
+ // Helper to get current log level dynamically
14
+ function getCurrentLevel(): number {
15
+ const LOG_LEVEL = process.env.LOG_LEVEL || "info";
16
+ return levels[LOG_LEVEL] || levels.info;
17
+ }
18
+
19
+ // Helper to check if debug is enabled
20
+ function isDebugEnabled(): boolean {
21
+ return process.env.DEBUG === "true";
22
+ }
23
+
24
+ // Color configuration for consistent output
25
+ const colors = {
26
+ error: chalk.red,
27
+ warn: chalk.yellow,
28
+ info: chalk.blue,
29
+ success: chalk.green,
30
+ debug: chalk.gray,
31
+ };
32
+
33
+ const emojis = {
34
+ error: "❌",
35
+ warn: "⚠️",
36
+ info: "ℹ️",
37
+ success: "✅",
38
+ debug: "🔍",
39
+ };
40
+
41
+ // File logging state
42
+ let logFilePath: string | null = null;
43
+
44
+ // Helper to format timestamp for file output
45
+ function formatTimestamp(): string {
46
+ const now = new Date();
47
+ return now.toISOString().replace("T", " ").split(".")[0];
48
+ }
49
+
50
+ // Helper to write to log file
51
+ function writeToFile(level: string, message: string, args: unknown[]): void {
52
+ if (!logFilePath) return;
53
+
54
+ const timestamp = formatTimestamp();
55
+ const argsStr =
56
+ args.length > 0
57
+ ? ` ${args
58
+ .map((arg) => (typeof arg === "object" ? JSON.stringify(arg) : String(arg)))
59
+ .join(" ")}`
60
+ : "";
61
+
62
+ const logLine = `[${timestamp}] ${level.toUpperCase()}: ${message}${argsStr}\n`;
63
+
64
+ fs.appendFileSync(logFilePath, logLine);
65
+ }
66
+
67
+ // Initialize daemon logging
68
+ async function initDaemonLogging(): Promise<void> {
69
+ // Lazy-load config to avoid circular dependency
70
+ const { config } = await import("@/services/ConfigService");
71
+
72
+ const tenexConfig = config.getConfig();
73
+ const defaultLogPath = path.join(config.getConfigPath("daemon"), "daemon.log");
74
+ logFilePath = tenexConfig.logging?.logFile || defaultLogPath;
75
+
76
+ // Ensure directory exists
77
+ const logDir = path.dirname(logFilePath);
78
+ fs.mkdirSync(logDir, { recursive: true });
79
+ }
80
+
81
+ // Main logger object
82
+ export const logger = {
83
+ initDaemonLogging,
84
+
85
+ /**
86
+ * Check if a specific log level is enabled
87
+ * Useful for conditional expensive operations (e.g., stack traces)
88
+ */
89
+ isLevelEnabled: (level: "error" | "warn" | "info" | "debug"): boolean => {
90
+ if (level === "debug") {
91
+ return isDebugEnabled() && getCurrentLevel() >= levels.debug;
92
+ }
93
+ return getCurrentLevel() >= levels[level];
94
+ },
95
+
96
+ error: (message: string, error?: unknown) => {
97
+ if (getCurrentLevel() >= levels.error) {
98
+ if (logFilePath) {
99
+ writeToFile("error", message, error ? [error] : []);
100
+ } else {
101
+ console.error(colors.error(`${emojis.error} ${message}`), error || "");
102
+ }
103
+ }
104
+ },
105
+
106
+ warn: (message: string, ...args: unknown[]) => {
107
+ if (getCurrentLevel() >= levels.warn) {
108
+ if (logFilePath) {
109
+ writeToFile("warn", message, args);
110
+ } else {
111
+ console.warn(colors.warn(`${emojis.warn} ${message}`), ...args);
112
+ }
113
+ }
114
+ },
115
+
116
+ warning: (message: string, ...args: unknown[]) => {
117
+ logger.warn(message, ...args);
118
+ },
119
+
120
+ info: (message: string, ...args: unknown[]) => {
121
+ if (getCurrentLevel() >= levels.info) {
122
+ if (logFilePath) {
123
+ writeToFile("info", message, args);
124
+ } else {
125
+ console.log(colors.info(`${emojis.info} ${message}`), ...args);
126
+ }
127
+ }
128
+ },
129
+
130
+ success: (message: string, ...args: unknown[]) => {
131
+ if (getCurrentLevel() >= levels.info) {
132
+ if (logFilePath) {
133
+ writeToFile("success", message, args);
134
+ } else {
135
+ console.log(colors.success(`${emojis.success} ${message}`), ...args);
136
+ }
137
+ }
138
+ },
139
+
140
+ debug: (message: string, ...args: unknown[]) => {
141
+ if (isDebugEnabled() && getCurrentLevel() >= levels.debug) {
142
+ if (logFilePath) {
143
+ writeToFile("debug", message, args);
144
+ } else {
145
+ console.log(colors.debug(`${emojis.debug} ${message}`), ...args);
146
+ }
147
+ }
148
+ },
149
+ };