@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,198 @@
1
+ import { getDaemon } from "@/daemon";
2
+ import { getNDK, initNDK } from "@/nostr/ndkClient";
3
+ import { config } from "@/services/ConfigService";
4
+ import { llmOpsRegistry } from "@/services/LLMOperationsRegistry";
5
+ import { SchedulerService } from "@/services/scheduling";
6
+ import { eventLoopMonitor } from "@/telemetry/EventLoopMonitor";
7
+ import { logger } from "@/utils/logger";
8
+ import { runInteractiveSetup } from "./setup/interactive";
9
+ import chalk from "chalk";
10
+ import { Command } from "commander";
11
+
12
+ /**
13
+ * Daemon command - runs all projects in a single process
14
+ */
15
+ export const daemonCommand = new Command("daemon")
16
+ .description("Start the TENEX daemon to manage all projects")
17
+ .option("-w, --whitelist <pubkeys>", "Comma-separated list of whitelisted pubkeys")
18
+ .option("-c, --config <path>", "Path to config file")
19
+ .option("-v, --verbose", "Enable verbose logging")
20
+ .option("-b, --boot <pattern>", "Auto-boot projects whose d-tag contains this pattern (can be used multiple times)", (value: string, prev: string[]) => {
21
+ return prev ? [...prev, value] : [value];
22
+ }, [])
23
+ .option("--supervised", "Run in supervised mode (enables graceful restart via SIGHUP)")
24
+ .action(async (options) => {
25
+ // Enable verbose logging if requested
26
+ if (options.verbose) {
27
+ process.env.LOG_LEVEL = "debug";
28
+ }
29
+
30
+ // Load configuration (MCP config will be loaded later per-project with metadataPath)
31
+ const { config: globalConfig, llms: globalLLMs } = await config.loadConfig();
32
+
33
+ // Initialize daemon logging
34
+ await logger.initDaemonLogging();
35
+
36
+ // Get whitelisted pubkeys
37
+ const whitelistedPubkeys = config.getWhitelistedPubkeys(
38
+ options.whitelist,
39
+ globalConfig
40
+ );
41
+
42
+ // Check for required configurations
43
+ const needsSetup =
44
+ whitelistedPubkeys.length === 0 ||
45
+ !globalLLMs.configurations ||
46
+ Object.keys(globalLLMs.configurations).length === 0;
47
+
48
+ if (needsSetup) {
49
+ if (whitelistedPubkeys.length === 0) {
50
+ logger.info("No whitelisted pubkeys found. Starting interactive setup...");
51
+ }
52
+ if (!globalLLMs.configurations || Object.keys(globalLLMs.configurations).length === 0) {
53
+ logger.info("No LLM configurations found. Starting interactive setup...");
54
+ }
55
+
56
+ // Run interactive setup
57
+ const setupConfig = await runInteractiveSetup();
58
+
59
+ // Save the setup configuration and reload
60
+ await config.saveGlobalConfig(setupConfig);
61
+ }
62
+
63
+ console.log(chalk.cyan("╔════════════════════════════════════════╗"));
64
+ console.log(chalk.cyan("║ TENEX Daemon Starting ║"));
65
+ console.log(chalk.cyan("╚════════════════════════════════════════╝"));
66
+ console.log();
67
+
68
+ // Initialize NDK for Nostr communication
69
+ console.log(chalk.gray("🔌 Initializing Nostr connection..."));
70
+ await initNDK();
71
+ console.log(chalk.gray("✓ Nostr connected"));
72
+
73
+ // Get scheduler service instance (initialization deferred until callbacks are registered)
74
+ const schedulerService = SchedulerService.getInstance();
75
+
76
+ // DIAGNOSTIC: Start event loop monitoring for concurrent streaming bottleneck analysis
77
+ eventLoopMonitor.start(
78
+ () => llmOpsRegistry.getActiveOperationsCount(),
79
+ 100, // Sample every 100ms
80
+ 50 // Consider >50ms lag as blocked
81
+ );
82
+ console.log(chalk.gray("📊 Event loop monitoring enabled"));
83
+
84
+ // Get the daemon instance
85
+ console.log(chalk.gray("🚀 Starting daemon..."));
86
+ const daemon = getDaemon();
87
+
88
+ // Set supervised mode if enabled
89
+ if (options.supervised) {
90
+ daemon.setSupervisedMode(true);
91
+ console.log(chalk.yellow("🔄 Supervised mode enabled (SIGHUP triggers graceful restart)"));
92
+ }
93
+
94
+ // Set boot patterns if provided
95
+ const bootPatterns: string[] = options.boot || [];
96
+ if (bootPatterns.length > 0) {
97
+ daemon.setAutoBootPatterns(bootPatterns);
98
+ console.log(chalk.yellow(`🚀 Auto-boot patterns: ${bootPatterns.join(", ")}`));
99
+ }
100
+
101
+ // Register scheduler shutdown with daemon's shutdown handlers
102
+ daemon.addShutdownHandler(async () => {
103
+ schedulerService.shutdown();
104
+ // Stop event loop monitor and log final stats
105
+ const stats = eventLoopMonitor.getStats();
106
+ logger.info("[EventLoopMonitor] Final stats on shutdown", {
107
+ peakLagMs: stats.peakLagMs,
108
+ avgLagMs: Math.round(stats.avgLagMs * 100) / 100,
109
+ sampleCount: stats.sampleCount,
110
+ blockedCount: stats.blockedCount,
111
+ blockedPercentage: stats.sampleCount > 0
112
+ ? Math.round((stats.blockedCount / stats.sampleCount) * 10000) / 100
113
+ : 0,
114
+ });
115
+ eventLoopMonitor.stop();
116
+ });
117
+
118
+ try {
119
+ // Start the daemon
120
+ await daemon.start();
121
+ console.log(chalk.gray("✓ Daemon core started"));
122
+
123
+ // Load restart state if this is a restart (auto-boot previously booted projects)
124
+ if (options.supervised) {
125
+ await daemon.loadRestartState();
126
+ }
127
+
128
+ // Register project callbacks with scheduler service (dependency injection)
129
+ // This enables Layer 3 (SchedulerService) to use Layer 4 (Daemon) functionality
130
+ // without direct imports, maintaining architectural separation
131
+ schedulerService.setProjectCallbacks(
132
+ // Boot handler: called when a scheduled task needs to boot a project
133
+ async (projectId: string) => {
134
+ await daemon.startRuntime(projectId);
135
+ },
136
+ // State resolver: called to check if a project is already running
137
+ (projectId: string) => {
138
+ return daemon.getActiveRuntimes().has(projectId);
139
+ },
140
+ // Target resolver: called to resolve the target pubkey (may reroute to PM)
141
+ (projectId: string, originalTargetPubkey: string) => {
142
+ const runtime = daemon.getActiveRuntimes().get(projectId);
143
+ if (!runtime) {
144
+ // Project not running, use original target
145
+ return originalTargetPubkey;
146
+ }
147
+
148
+ const context = runtime.getContext();
149
+ if (!context) {
150
+ // No context available, use original target
151
+ return originalTargetPubkey;
152
+ }
153
+
154
+ // Check if the target agent is in this project
155
+ const targetAgent = context.getAgentByPubkey(originalTargetPubkey);
156
+ if (targetAgent) {
157
+ // Target agent exists in project, use original target
158
+ return originalTargetPubkey;
159
+ }
160
+
161
+ // Target agent is NOT in this project - route to PM instead
162
+ const pm = context.projectManager;
163
+ if (!pm) {
164
+ // No PM available, use original target
165
+ return originalTargetPubkey;
166
+ }
167
+
168
+ return pm.pubkey;
169
+ }
170
+ );
171
+ console.log(chalk.gray("✓ Scheduler callbacks registered"));
172
+
173
+ // Initialize scheduler AFTER callbacks are registered
174
+ // This ensures catch-up tasks can use ensureProjectRunning() for auto-boot
175
+ console.log(chalk.gray("⚙️ Initializing scheduler service..."));
176
+ await schedulerService.initialize(getNDK(), ".tenex");
177
+ console.log(chalk.gray("✓ Scheduler initialized"));
178
+
179
+ console.log(chalk.green("✅ Daemon started successfully"));
180
+
181
+ // Log initial status
182
+ const status = daemon.getStatus();
183
+ console.log(chalk.blue("📊 Initial Status:"));
184
+ console.log(chalk.gray(` Known Projects: ${status.knownProjects}`));
185
+ console.log(chalk.gray(` Active Projects: ${status.activeProjects}`));
186
+ console.log(chalk.gray(` Total Agents: ${status.totalAgents}`));
187
+ console.log();
188
+
189
+ // Keep the process alive
190
+ await new Promise(() => {
191
+ // This promise never resolves, keeping the daemon running
192
+ });
193
+ } catch (error) {
194
+ logger.error("Failed to start daemon", { error });
195
+ console.error(chalk.red("❌ Failed to start daemon:"), error);
196
+ process.exit(1);
197
+ }
198
+ });
@@ -0,0 +1,134 @@
1
+ import { Command } from "commander";
2
+ import chalk from "chalk";
3
+ import { agentStorage, type StoredAgent } from "@/agents/AgentStorage";
4
+ import { NDKAgentDefinition } from "@/events/NDKAgentDefinition";
5
+ import { initNDK, getNDK } from "@/nostr/ndkClient";
6
+ import { NDKPrivateKeySigner } from "@nostr-dev-kit/ndk";
7
+
8
+ const refetchCommand = new Command("refetch")
9
+ .description("Refetch and update all agent definitions from Nostr")
10
+ .action(repairAgents);
11
+
12
+ const orphansCommand = new Command("orphans")
13
+ .description("List agents not assigned to any project")
14
+ .option("--purge", "Delete orphaned agents")
15
+ .action(async (options) => {
16
+ await findOrphanedAgents(!!options.purge);
17
+ });
18
+
19
+ const agentsCommand = new Command("agents")
20
+ .description("Agent diagnostics and repair")
21
+ .addCommand(refetchCommand)
22
+ .addCommand(orphansCommand);
23
+
24
+ export const doctorCommand = new Command("doctor")
25
+ .description("Diagnose and repair TENEX state")
26
+ .addCommand(agentsCommand);
27
+
28
+ function agentChanged(before: StoredAgent, after: StoredAgent): boolean {
29
+ if (before.name !== after.name) return true;
30
+ if (before.role !== after.role) return true;
31
+ if (before.description !== after.description) return true;
32
+ if (before.instructions !== after.instructions) return true;
33
+ if (before.useCriteria !== after.useCriteria) return true;
34
+ const oldTools = before.default?.tools?.slice().sort().join("\0") ?? "";
35
+ const newTools = after.default?.tools?.slice().sort().join("\0") ?? "";
36
+ return oldTools !== newTools;
37
+ }
38
+
39
+ async function repairAgents(): Promise<void> {
40
+ await agentStorage.initialize();
41
+ await initNDK();
42
+ const ndk = getNDK();
43
+
44
+ const agents = await agentStorage.getAllAgents();
45
+ const nostrAgents = agents.filter((a) => a.eventId);
46
+ const skipped = agents.length - nostrAgents.length;
47
+
48
+ console.log(chalk.blue(`Checking ${nostrAgents.length} Nostr agent(s)...`));
49
+
50
+ let updated = 0;
51
+ let failed = 0;
52
+
53
+ for (const agent of nostrAgents) {
54
+ const pubkey = new NDKPrivateKeySigner(agent.nsec).pubkey;
55
+ const label = `${agent.slug} (${pubkey.substring(0, 8)}...)`;
56
+
57
+ const event = await ndk.fetchEvent(agent.eventId!, { groupable: false });
58
+ if (!event) {
59
+ console.log(chalk.yellow(` ⚠ ${label}: event not found on relays, skipping`));
60
+ failed++;
61
+ continue;
62
+ }
63
+
64
+ const agentDef = NDKAgentDefinition.from(event);
65
+ const toolTags = event.tags
66
+ .filter((t) => t[0] === "tool" && t[1])
67
+ .map((t) => t[1] as string);
68
+
69
+ const newDefault = {
70
+ ...agent.default,
71
+ tools: toolTags.length > 0 ? toolTags : undefined,
72
+ };
73
+ const updatedAgent = {
74
+ ...agent,
75
+ name: agentDef.title || agent.name,
76
+ role: agentDef.role || agent.role,
77
+ description: agentDef.description ?? agent.description,
78
+ instructions: agentDef.instructions ?? agent.instructions,
79
+ useCriteria: agentDef.useCriteria ?? agent.useCriteria,
80
+ default: Object.values(newDefault).some((v) => v !== undefined) ? newDefault : undefined,
81
+ };
82
+
83
+ const toolsDisplay = toolTags.length > 0 ? toolTags.join(", ") : "(none)";
84
+ const suffix = chalk.gray(` [tools: ${toolsDisplay}]`);
85
+
86
+ if (agentChanged(agent, updatedAgent)) {
87
+ await agentStorage.saveAgent(updatedAgent);
88
+ console.log(chalk.green(` ✓ ${label}: updated`) + suffix);
89
+ updated++;
90
+ } else {
91
+ console.log(chalk.gray(` ${label}: ok`) + suffix);
92
+ }
93
+ }
94
+
95
+ console.log(
96
+ chalk.blue(
97
+ `\nDone: ${updated} updated, ${skipped} skipped (no eventId), ${failed} failed`
98
+ )
99
+ );
100
+ }
101
+
102
+ async function findOrphanedAgents(purge: boolean): Promise<void> {
103
+ await agentStorage.initialize();
104
+ const agents = await agentStorage.getAllAgents();
105
+
106
+ const orphans: Array<{ agent: StoredAgent; pubkey: string }> = [];
107
+ for (const agent of agents) {
108
+ const pubkey = new NDKPrivateKeySigner(agent.nsec).pubkey;
109
+ const projects = await agentStorage.getAgentProjects(pubkey);
110
+ if (projects.length === 0) {
111
+ orphans.push({ agent, pubkey });
112
+ }
113
+ }
114
+
115
+ if (orphans.length === 0) {
116
+ console.log(chalk.green("No orphaned agents found."));
117
+ return;
118
+ }
119
+
120
+ console.log(chalk.yellow(`Found ${orphans.length} orphaned agent(s):`));
121
+ for (const { agent, pubkey } of orphans) {
122
+ const source = agent.eventId ? `nostr:${agent.eventId.substring(0, 8)}...` : "local";
123
+ console.log(chalk.gray(` ${agent.slug} (${pubkey.substring(0, 8)}...) [${source}]`));
124
+ }
125
+
126
+ if (!purge) return;
127
+
128
+ console.log(chalk.blue(`\nPurging ${orphans.length} orphaned agent(s)...`));
129
+ for (const { agent, pubkey } of orphans) {
130
+ await agentStorage.deleteAgent(pubkey);
131
+ console.log(chalk.green(` ✓ deleted ${agent.slug}`));
132
+ }
133
+ console.log(chalk.blue(`Done: ${orphans.length} deleted`));
134
+ }
@@ -0,0 +1,228 @@
1
+ import * as fileSystem from "@/lib/fs";
2
+ import { PROVIDER_IDS } from "@/llm/providers/provider-ids";
3
+ import {
4
+ type EmbeddingConfig,
5
+ EmbeddingProviderFactory,
6
+ } from "@/services/rag/EmbeddingProviderFactory";
7
+ import { config as configService } from "@/services/ConfigService";
8
+ import { logger } from "@/utils/logger";
9
+ import { Command } from "commander";
10
+ import inquirer from "inquirer";
11
+
12
+ /**
13
+ * Providers that support embeddings (OpenAI-compatible API)
14
+ */
15
+ const EMBEDDING_CAPABLE_PROVIDERS = [
16
+ PROVIDER_IDS.OPENAI,
17
+ PROVIDER_IDS.OPENROUTER,
18
+ ] as const;
19
+
20
+ /**
21
+ * Display names for providers
22
+ */
23
+ const PROVIDER_DISPLAY_NAMES: Record<string, string> = {
24
+ [PROVIDER_IDS.OPENAI]: "OpenAI",
25
+ [PROVIDER_IDS.OPENROUTER]: "OpenRouter",
26
+ };
27
+
28
+ /**
29
+ * Common embedding models by provider
30
+ */
31
+ const EMBEDDING_MODELS: Record<string, Array<{ name: string; value: string }>> = {
32
+ [PROVIDER_IDS.OPENAI]: [
33
+ { name: "text-embedding-3-small (fast, good quality)", value: "text-embedding-3-small" },
34
+ { name: "text-embedding-3-large (slower, best quality)", value: "text-embedding-3-large" },
35
+ { name: "text-embedding-ada-002 (legacy)", value: "text-embedding-ada-002" },
36
+ ],
37
+ [PROVIDER_IDS.OPENROUTER]: [
38
+ { name: "openai/text-embedding-3-small", value: "openai/text-embedding-3-small" },
39
+ { name: "openai/text-embedding-3-large", value: "openai/text-embedding-3-large" },
40
+ { name: "openai/text-embedding-ada-002", value: "openai/text-embedding-ada-002" },
41
+ ],
42
+ };
43
+
44
+ /**
45
+ * Command for configuring embedding provider
46
+ */
47
+ export const embedCommand = new Command("embed")
48
+ .description(
49
+ "Configure embedding model for RAG (global by default, --project for current project)"
50
+ )
51
+ .option("--project", "Use project-specific configuration instead of global")
52
+ .action(async (options) => {
53
+ try {
54
+ const scope: "global" | "project" = options.project ? "project" : "global";
55
+ const projectPath = process.cwd();
56
+ const baseDir =
57
+ scope === "project"
58
+ ? configService.getProjectPath(projectPath)
59
+ : configService.getGlobalPath();
60
+
61
+ if (scope === "project") {
62
+ // Check if we're in a TENEX project
63
+ if (!(await fileSystem.directoryExists(baseDir))) {
64
+ logger.error(
65
+ "No .tenex directory found. Make sure you're in a TENEX project directory."
66
+ );
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+ } else {
71
+ // Ensure global config directory exists
72
+ await fileSystem.ensureDirectory(baseDir);
73
+ }
74
+
75
+ // Load existing configuration
76
+ const existing = await EmbeddingProviderFactory.loadConfiguration({
77
+ scope,
78
+ projectPath: scope === "project" ? projectPath : undefined,
79
+ });
80
+
81
+ // Load configured providers from providers.json
82
+ const providersConfig = await configService.loadTenexProviders(configService.getGlobalPath());
83
+ if (Object.keys(providersConfig.providers).length === 0) {
84
+ logger.error(
85
+ "No providers configured. Run `tenex setup providers` before configuring embeddings."
86
+ );
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ const configuredProviders = Object.keys(providersConfig.providers);
91
+
92
+ // Build provider choices: local + any configured embedding-capable providers
93
+ const providerChoices: Array<{ name: string; value: string }> = [
94
+ { name: "Local Transformers (runs on your machine)", value: "local" },
95
+ ];
96
+
97
+ for (const providerId of EMBEDDING_CAPABLE_PROVIDERS) {
98
+ if (configuredProviders.includes(providerId)) {
99
+ const displayName = PROVIDER_DISPLAY_NAMES[providerId] || providerId;
100
+ providerChoices.push({
101
+ name: `${displayName} (configured)`,
102
+ value: providerId,
103
+ });
104
+ }
105
+ }
106
+
107
+ // Prompt for provider selection
108
+ const { provider } = await inquirer.prompt([
109
+ {
110
+ type: "select",
111
+ name: "provider",
112
+ message: "Select embedding provider:",
113
+ choices: providerChoices,
114
+ default: existing?.provider || "local",
115
+ },
116
+ ]);
117
+
118
+ let model: string;
119
+
120
+ if (provider !== "local") {
121
+ // OpenAI-compatible provider configuration
122
+ const displayName = PROVIDER_DISPLAY_NAMES[provider] || provider;
123
+ const modelChoices = EMBEDDING_MODELS[provider] || [
124
+ { name: "Enter custom model ID", value: "custom" },
125
+ ];
126
+
127
+ // Add custom model option if not already present
128
+ if (!modelChoices.some((c) => c.value === "custom")) {
129
+ modelChoices.push({ name: "Enter custom model ID", value: "custom" });
130
+ }
131
+
132
+ const providerAnswers = await inquirer.prompt([
133
+ {
134
+ type: "select",
135
+ name: "model",
136
+ message: `Select ${displayName} embedding model:`,
137
+ choices: modelChoices,
138
+ default: existing?.provider === provider ? existing?.model : modelChoices[0]?.value,
139
+ },
140
+ ]);
141
+
142
+ if (providerAnswers.model === "custom") {
143
+ const customAnswer = await inquirer.prompt([
144
+ {
145
+ type: "input",
146
+ name: "customModel",
147
+ message: "Enter model ID:",
148
+ validate: (input: string) =>
149
+ input.trim().length > 0 || "Model ID cannot be empty",
150
+ },
151
+ ]);
152
+ model = customAnswer.customModel;
153
+ } else {
154
+ model = providerAnswers.model;
155
+ }
156
+ } else {
157
+ // Local transformer configuration
158
+ const localAnswers = await inquirer.prompt([
159
+ {
160
+ type: "select",
161
+ name: "model",
162
+ message: "Select local embedding model:",
163
+ choices: [
164
+ {
165
+ name: "all-MiniLM-L6-v2 (default, fast, good for general use)",
166
+ value: "Xenova/all-MiniLM-L6-v2",
167
+ },
168
+ {
169
+ name: "all-mpnet-base-v2 (larger, better quality)",
170
+ value: "Xenova/all-mpnet-base-v2",
171
+ },
172
+ {
173
+ name: "paraphrase-multilingual-MiniLM-L12-v2 (multilingual support)",
174
+ value: "Xenova/paraphrase-multilingual-MiniLM-L12-v2",
175
+ },
176
+ {
177
+ name: "Custom model (enter HuggingFace model ID)",
178
+ value: "custom",
179
+ },
180
+ ],
181
+ default: existing?.model || "Xenova/all-MiniLM-L6-v2",
182
+ },
183
+ ]);
184
+
185
+ if (localAnswers.model === "custom") {
186
+ const customAnswer = await inquirer.prompt([
187
+ {
188
+ type: "input",
189
+ name: "customModel",
190
+ message:
191
+ "Enter HuggingFace model ID (e.g., sentence-transformers/all-MiniLM-L6-v2):",
192
+ validate: (input: string) =>
193
+ input.trim().length > 0 || "Model ID cannot be empty",
194
+ },
195
+ ]);
196
+ model = customAnswer.customModel;
197
+ } else {
198
+ model = localAnswers.model;
199
+ }
200
+ }
201
+
202
+ // Save configuration (API key comes from providers.json, not stored here)
203
+ const embeddingConfig: EmbeddingConfig = {
204
+ provider,
205
+ model,
206
+ };
207
+
208
+ // Save model selection to embed.json
209
+ await EmbeddingProviderFactory.saveConfiguration(embeddingConfig, scope, {
210
+ projectPath: scope === "project" ? projectPath : undefined,
211
+ });
212
+
213
+ logger.info(
214
+ `✅ Embedding configuration saved to ${scope} config\n` +
215
+ ` Provider: ${provider}\n` +
216
+ ` Model: ${model}`
217
+ );
218
+ } catch (error: unknown) {
219
+ // Handle SIGINT (Ctrl+C) gracefully
220
+ const errorMessage = error instanceof Error ? error.message : String(error);
221
+ if (errorMessage?.includes("SIGINT") || errorMessage?.includes("force closed")) {
222
+ return;
223
+ }
224
+
225
+ logger.error(`Failed to configure embedding model: ${error}`);
226
+ process.exitCode = 1;
227
+ }
228
+ });