@tyvm/knowhow 0.0.145 → 0.0.147

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 (320) hide show
  1. package/autodoc/cli-reference.md +36 -7
  2. package/bin/knowhow.js +8 -6
  3. package/package.json +1 -1
  4. package/src/agents/base/base.ts +24 -0
  5. package/src/agents/historyRollback.ts +36 -0
  6. package/src/agents/tools/startAgentTask.ts +41 -9
  7. package/src/auth/browserLogin.ts +9 -3
  8. package/src/auth/keyAuth.ts +115 -0
  9. package/src/auth/keyManager.ts +166 -0
  10. package/src/chat/CliChatService.ts +16 -0
  11. package/src/chat/modules/AgentModule.ts +144 -56
  12. package/src/chat/modules/AskModule.ts +2 -0
  13. package/src/chat/modules/BaseChatModule.ts +0 -1
  14. package/src/chat/modules/CustomCommandsModule.ts +2 -0
  15. package/src/chat/modules/InternalChatModule.ts +2 -0
  16. package/src/chat/modules/RemoteSyncModule.ts +4 -0
  17. package/src/chat/modules/RendererModule.ts +2 -0
  18. package/src/chat/modules/SearchModule.ts +2 -0
  19. package/src/chat/modules/SessionsModule.ts +110 -39
  20. package/src/chat/modules/SetupModule.ts +2 -0
  21. package/src/chat/modules/ShellCommandModule.ts +2 -0
  22. package/src/chat/modules/SystemModule.ts +2 -0
  23. package/src/chat/types.ts +5 -2
  24. package/src/cli.ts +1 -1
  25. package/src/clients/anthropic.ts +24 -0
  26. package/src/clients/fireworks.ts +3 -0
  27. package/src/clients/gemini.ts +8 -0
  28. package/src/clients/index.ts +2 -0
  29. package/src/clients/openai.ts +7 -4
  30. package/src/clients/types.ts +30 -7
  31. package/src/clients/xai.ts +23 -4
  32. package/src/commands/agent.ts +11 -39
  33. package/src/commands/agents.ts +403 -53
  34. package/src/commands/misc.ts +3 -2
  35. package/src/commands/services.ts +49 -3
  36. package/src/login.ts +89 -28
  37. package/src/plugins/plugins.ts +16 -0
  38. package/src/processors/TokenCompressor.ts +40 -8
  39. package/src/processors/ToolResponseCache.ts +17 -8
  40. package/src/processors/tools/boundedToolResponse.ts +49 -0
  41. package/src/processors/tools/grepToolResponse.ts +164 -38
  42. package/src/processors/tools/index.ts +2 -0
  43. package/src/processors/tools/jqToolResponse.ts +40 -10
  44. package/src/processors/tools/listStoredToolResponses.ts +51 -10
  45. package/src/processors/tools/tailToolResponse.ts +85 -17
  46. package/src/services/AgentService.ts +2 -0
  47. package/src/services/AgentSyncFs.ts +65 -0
  48. package/src/services/AgentSyncKnowhowWeb.ts +22 -4
  49. package/src/services/BehaviorsService.ts +2 -0
  50. package/src/services/DockerService.ts +2 -0
  51. package/src/services/EmbeddingService.ts +2 -0
  52. package/src/services/EmbeddingsService.ts +3 -0
  53. package/src/services/KnowhowClient.ts +68 -7
  54. package/src/services/LazyToolsService.ts +16 -0
  55. package/src/services/Mcp.ts +11 -2
  56. package/src/services/McpServer.ts +2 -0
  57. package/src/services/MessageProcessor.ts +2 -0
  58. package/src/services/MinimalToolsService.ts +2 -0
  59. package/src/services/RuntimeReloadService.ts +31 -0
  60. package/src/services/SessionManager.ts +5 -0
  61. package/src/services/SkillsService.ts +2 -0
  62. package/src/services/SyncedAgentWatcher.ts +2 -0
  63. package/src/services/SyncerService.ts +23 -8
  64. package/src/services/TaskRegistry.ts +2 -0
  65. package/src/services/Tools.ts +13 -0
  66. package/src/services/TracingService.ts +116 -0
  67. package/src/services/index.ts +10 -0
  68. package/src/services/modules/index.ts +49 -3
  69. package/src/services/modules/types.ts +8 -0
  70. package/src/types.ts +2 -0
  71. package/src/util/Trace.ts +236 -0
  72. package/src/utils/http.ts +18 -2
  73. package/tests/clients/fireworks.test.ts +65 -0
  74. package/tests/clients/reasoningEffort.test.ts +79 -0
  75. package/tests/compressor/toolResponseCache.test.ts +2 -1
  76. package/tests/manual/clients/completions.test.ts +27 -10
  77. package/tests/processors/TokenCompressor.test.ts +17 -3
  78. package/tests/processors/tools/boundedRetrievalTools.test.ts +68 -0
  79. package/tests/processors/tools/grepToolResponse.test.ts +88 -1
  80. package/tests/unit/agents/historyRollback.test.ts +53 -0
  81. package/tests/unit/auth/keyAuth.test.ts +102 -0
  82. package/tests/unit/auth/keyManager.test.ts +67 -0
  83. package/tests/unit/chat/historyCommandArgs.test.ts +37 -0
  84. package/tests/unit/commands/agents.test.ts +68 -0
  85. package/tests/unit/login.test.ts +119 -0
  86. package/tests/unit/plugins/pluginLoading.test.ts +31 -0
  87. package/tests/unit/services/AgentSyncKnowhowWeb.test.ts +38 -0
  88. package/tests/unit/services/LazyToolsService.test.ts +29 -0
  89. package/tests/unit/services/RuntimeReloadService.test.ts +29 -0
  90. package/tests/unit/services/SessionManager.test.ts +43 -0
  91. package/tests/unit/services/SyncerService.test.ts +45 -0
  92. package/tests/unit/util/Trace.test.ts +119 -0
  93. package/tests/unit/utils/http.test.ts +43 -0
  94. package/ts_build/package.json +1 -1
  95. package/ts_build/src/agents/base/base.d.ts +1 -0
  96. package/ts_build/src/agents/base/base.js +31 -2
  97. package/ts_build/src/agents/base/base.js.map +1 -1
  98. package/ts_build/src/agents/historyRollback.d.ts +2 -0
  99. package/ts_build/src/agents/historyRollback.js +22 -0
  100. package/ts_build/src/agents/historyRollback.js.map +1 -0
  101. package/ts_build/src/agents/tools/startAgentTask.d.ts +2 -0
  102. package/ts_build/src/agents/tools/startAgentTask.js +36 -9
  103. package/ts_build/src/agents/tools/startAgentTask.js.map +1 -1
  104. package/ts_build/src/auth/browserLogin.d.ts +1 -0
  105. package/ts_build/src/auth/browserLogin.js +5 -2
  106. package/ts_build/src/auth/browserLogin.js.map +1 -1
  107. package/ts_build/src/auth/keyAuth.d.ts +5 -0
  108. package/ts_build/src/auth/keyAuth.js +79 -0
  109. package/ts_build/src/auth/keyAuth.js.map +1 -0
  110. package/ts_build/src/auth/keyManager.d.ts +14 -0
  111. package/ts_build/src/auth/keyManager.js +145 -0
  112. package/ts_build/src/auth/keyManager.js.map +1 -0
  113. package/ts_build/src/chat/CliChatService.js +15 -0
  114. package/ts_build/src/chat/CliChatService.js.map +1 -1
  115. package/ts_build/src/chat/modules/AgentModule.d.ts +13 -1
  116. package/ts_build/src/chat/modules/AgentModule.js +96 -43
  117. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  118. package/ts_build/src/chat/modules/AskModule.js +12 -2
  119. package/ts_build/src/chat/modules/AskModule.js.map +1 -1
  120. package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -1
  121. package/ts_build/src/chat/modules/CustomCommandsModule.js +12 -2
  122. package/ts_build/src/chat/modules/CustomCommandsModule.js.map +1 -1
  123. package/ts_build/src/chat/modules/InternalChatModule.js +16 -2
  124. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -1
  125. package/ts_build/src/chat/modules/RemoteSyncModule.js +19 -2
  126. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  127. package/ts_build/src/chat/modules/RendererModule.js +17 -2
  128. package/ts_build/src/chat/modules/RendererModule.js.map +1 -1
  129. package/ts_build/src/chat/modules/SearchModule.js +12 -2
  130. package/ts_build/src/chat/modules/SearchModule.js.map +1 -1
  131. package/ts_build/src/chat/modules/SessionsModule.d.ts +6 -0
  132. package/ts_build/src/chat/modules/SessionsModule.js +114 -24
  133. package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
  134. package/ts_build/src/chat/modules/SetupModule.js +17 -2
  135. package/ts_build/src/chat/modules/SetupModule.js.map +1 -1
  136. package/ts_build/src/chat/modules/ShellCommandModule.js +12 -2
  137. package/ts_build/src/chat/modules/ShellCommandModule.js.map +1 -1
  138. package/ts_build/src/chat/modules/SystemModule.js +12 -2
  139. package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
  140. package/ts_build/src/chat/types.d.ts +5 -2
  141. package/ts_build/src/cli.js +1 -1
  142. package/ts_build/src/cli.js.map +1 -1
  143. package/ts_build/src/clients/anthropic.d.ts +1 -0
  144. package/ts_build/src/clients/anthropic.js +12 -0
  145. package/ts_build/src/clients/anthropic.js.map +1 -1
  146. package/ts_build/src/clients/fireworks.js +1 -0
  147. package/ts_build/src/clients/fireworks.js.map +1 -1
  148. package/ts_build/src/clients/gemini.js +8 -0
  149. package/ts_build/src/clients/gemini.js.map +1 -1
  150. package/ts_build/src/clients/index.js +19 -4
  151. package/ts_build/src/clients/index.js.map +1 -1
  152. package/ts_build/src/clients/openai.js +4 -2
  153. package/ts_build/src/clients/openai.js.map +1 -1
  154. package/ts_build/src/clients/types.d.ts +4 -1
  155. package/ts_build/src/clients/types.js +14 -0
  156. package/ts_build/src/clients/types.js.map +1 -1
  157. package/ts_build/src/clients/xai.d.ts +1 -0
  158. package/ts_build/src/clients/xai.js +23 -4
  159. package/ts_build/src/clients/xai.js.map +1 -1
  160. package/ts_build/src/commands/agent.js +7 -22
  161. package/ts_build/src/commands/agent.js.map +1 -1
  162. package/ts_build/src/commands/agents.d.ts +1 -1
  163. package/ts_build/src/commands/agents.js +174 -16
  164. package/ts_build/src/commands/agents.js.map +1 -1
  165. package/ts_build/src/commands/misc.js +3 -2
  166. package/ts_build/src/commands/misc.js.map +1 -1
  167. package/ts_build/src/commands/services.d.ts +2 -0
  168. package/ts_build/src/commands/services.js +45 -3
  169. package/ts_build/src/commands/services.js.map +1 -1
  170. package/ts_build/src/login.d.ts +1 -1
  171. package/ts_build/src/login.js +53 -15
  172. package/ts_build/src/login.js.map +1 -1
  173. package/ts_build/src/plugins/plugins.d.ts +1 -0
  174. package/ts_build/src/plugins/plugins.js +14 -0
  175. package/ts_build/src/plugins/plugins.js.map +1 -1
  176. package/ts_build/src/processors/TokenCompressor.js +15 -6
  177. package/ts_build/src/processors/TokenCompressor.js.map +1 -1
  178. package/ts_build/src/processors/ToolResponseCache.d.ts +3 -3
  179. package/ts_build/src/processors/ToolResponseCache.js +8 -8
  180. package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
  181. package/ts_build/src/processors/tools/boundedToolResponse.d.ts +7 -0
  182. package/ts_build/src/processors/tools/boundedToolResponse.js +27 -0
  183. package/ts_build/src/processors/tools/boundedToolResponse.js.map +1 -0
  184. package/ts_build/src/processors/tools/grepToolResponse.d.ts +4 -0
  185. package/ts_build/src/processors/tools/grepToolResponse.js +101 -25
  186. package/ts_build/src/processors/tools/grepToolResponse.js.map +1 -1
  187. package/ts_build/src/processors/tools/index.d.ts +2 -2
  188. package/ts_build/src/processors/tools/index.js.map +1 -1
  189. package/ts_build/src/processors/tools/jqToolResponse.d.ts +5 -1
  190. package/ts_build/src/processors/tools/jqToolResponse.js +26 -9
  191. package/ts_build/src/processors/tools/jqToolResponse.js.map +1 -1
  192. package/ts_build/src/processors/tools/listStoredToolResponses.d.ts +7 -1
  193. package/ts_build/src/processors/tools/listStoredToolResponses.js +39 -9
  194. package/ts_build/src/processors/tools/listStoredToolResponses.js.map +1 -1
  195. package/ts_build/src/processors/tools/tailToolResponse.d.ts +5 -0
  196. package/ts_build/src/processors/tools/tailToolResponse.js +56 -13
  197. package/ts_build/src/processors/tools/tailToolResponse.js.map +1 -1
  198. package/ts_build/src/services/AgentService.js +18 -2
  199. package/ts_build/src/services/AgentService.js.map +1 -1
  200. package/ts_build/src/services/AgentSyncFs.d.ts +3 -0
  201. package/ts_build/src/services/AgentSyncFs.js +62 -15
  202. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  203. package/ts_build/src/services/AgentSyncKnowhowWeb.d.ts +2 -0
  204. package/ts_build/src/services/AgentSyncKnowhowWeb.js +28 -6
  205. package/ts_build/src/services/AgentSyncKnowhowWeb.js.map +1 -1
  206. package/ts_build/src/services/BehaviorsService.js +12 -2
  207. package/ts_build/src/services/BehaviorsService.js.map +1 -1
  208. package/ts_build/src/services/DockerService.js +20 -8
  209. package/ts_build/src/services/DockerService.js.map +1 -1
  210. package/ts_build/src/services/EmbeddingService.js +16 -2
  211. package/ts_build/src/services/EmbeddingService.js.map +1 -1
  212. package/ts_build/src/services/EmbeddingsService.js +12 -2
  213. package/ts_build/src/services/EmbeddingsService.js.map +1 -1
  214. package/ts_build/src/services/KnowhowClient.d.ts +7 -2
  215. package/ts_build/src/services/KnowhowClient.js +108 -10
  216. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  217. package/ts_build/src/services/LazyToolsService.d.ts +2 -0
  218. package/ts_build/src/services/LazyToolsService.js +26 -2
  219. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  220. package/ts_build/src/services/Mcp.js +20 -4
  221. package/ts_build/src/services/Mcp.js.map +1 -1
  222. package/ts_build/src/services/McpServer.js +17 -2
  223. package/ts_build/src/services/McpServer.js.map +1 -1
  224. package/ts_build/src/services/MessageProcessor.js +16 -2
  225. package/ts_build/src/services/MessageProcessor.js.map +1 -1
  226. package/ts_build/src/services/MinimalToolsService.js +16 -2
  227. package/ts_build/src/services/MinimalToolsService.js.map +1 -1
  228. package/ts_build/src/services/RuntimeReloadService.d.ts +12 -0
  229. package/ts_build/src/services/RuntimeReloadService.js +26 -0
  230. package/ts_build/src/services/RuntimeReloadService.js.map +1 -0
  231. package/ts_build/src/services/SessionManager.js +19 -2
  232. package/ts_build/src/services/SessionManager.js.map +1 -1
  233. package/ts_build/src/services/SkillsService.js +16 -2
  234. package/ts_build/src/services/SkillsService.js.map +1 -1
  235. package/ts_build/src/services/SyncedAgentWatcher.js +16 -2
  236. package/ts_build/src/services/SyncedAgentWatcher.js.map +1 -1
  237. package/ts_build/src/services/SyncerService.d.ts +1 -0
  238. package/ts_build/src/services/SyncerService.js +27 -5
  239. package/ts_build/src/services/SyncerService.js.map +1 -1
  240. package/ts_build/src/services/TaskRegistry.js +12 -2
  241. package/ts_build/src/services/TaskRegistry.js.map +1 -1
  242. package/ts_build/src/services/Tools.d.ts +1 -0
  243. package/ts_build/src/services/Tools.js +21 -2
  244. package/ts_build/src/services/Tools.js.map +1 -1
  245. package/ts_build/src/services/TracingService.d.ts +16 -0
  246. package/ts_build/src/services/TracingService.js +35 -0
  247. package/ts_build/src/services/TracingService.js.map +1 -0
  248. package/ts_build/src/services/index.d.ts +8 -0
  249. package/ts_build/src/services/index.js +9 -1
  250. package/ts_build/src/services/index.js.map +1 -1
  251. package/ts_build/src/services/modules/index.d.ts +6 -0
  252. package/ts_build/src/services/modules/index.js +29 -3
  253. package/ts_build/src/services/modules/index.js.map +1 -1
  254. package/ts_build/src/services/modules/types.d.ts +3 -0
  255. package/ts_build/src/types.d.ts +1 -0
  256. package/ts_build/src/types.js.map +1 -1
  257. package/ts_build/src/util/Trace.d.ts +11 -0
  258. package/ts_build/src/util/Trace.js +107 -0
  259. package/ts_build/src/util/Trace.js.map +1 -0
  260. package/ts_build/src/utils/http.d.ts +6 -2
  261. package/ts_build/src/utils/http.js +8 -2
  262. package/ts_build/src/utils/http.js.map +1 -1
  263. package/ts_build/tests/clients/fireworks.test.d.ts +1 -0
  264. package/ts_build/tests/clients/fireworks.test.js +65 -0
  265. package/ts_build/tests/clients/fireworks.test.js.map +1 -0
  266. package/ts_build/tests/clients/reasoningEffort.test.d.ts +1 -0
  267. package/ts_build/tests/clients/reasoningEffort.test.js +68 -0
  268. package/ts_build/tests/clients/reasoningEffort.test.js.map +1 -0
  269. package/ts_build/tests/compressor/toolResponseCache.test.js +1 -1
  270. package/ts_build/tests/compressor/toolResponseCache.test.js.map +1 -1
  271. package/ts_build/tests/manual/clients/completions.test.js +19 -6
  272. package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
  273. package/ts_build/tests/processors/TokenCompressor.test.js +11 -2
  274. package/ts_build/tests/processors/TokenCompressor.test.js.map +1 -1
  275. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.d.ts +1 -0
  276. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js +57 -0
  277. package/ts_build/tests/processors/tools/boundedRetrievalTools.test.js.map +1 -0
  278. package/ts_build/tests/processors/tools/grepToolResponse.test.js +37 -0
  279. package/ts_build/tests/processors/tools/grepToolResponse.test.js.map +1 -1
  280. package/ts_build/tests/unit/agents/historyRollback.test.d.ts +1 -0
  281. package/ts_build/tests/unit/agents/historyRollback.test.js +42 -0
  282. package/ts_build/tests/unit/agents/historyRollback.test.js.map +1 -0
  283. package/ts_build/tests/unit/auth/keyAuth.test.d.ts +1 -0
  284. package/ts_build/tests/unit/auth/keyAuth.test.js +77 -0
  285. package/ts_build/tests/unit/auth/keyAuth.test.js.map +1 -0
  286. package/ts_build/tests/unit/auth/keyManager.test.d.ts +1 -0
  287. package/ts_build/tests/unit/auth/keyManager.test.js +52 -0
  288. package/ts_build/tests/unit/auth/keyManager.test.js.map +1 -0
  289. package/ts_build/tests/unit/chat/historyCommandArgs.test.d.ts +1 -0
  290. package/ts_build/tests/unit/chat/historyCommandArgs.test.js +29 -0
  291. package/ts_build/tests/unit/chat/historyCommandArgs.test.js.map +1 -0
  292. package/ts_build/tests/unit/commands/agents.test.d.ts +1 -0
  293. package/ts_build/tests/unit/commands/agents.test.js +91 -0
  294. package/ts_build/tests/unit/commands/agents.test.js.map +1 -0
  295. package/ts_build/tests/unit/login.test.d.ts +1 -0
  296. package/ts_build/tests/unit/login.test.js +97 -0
  297. package/ts_build/tests/unit/login.test.js.map +1 -0
  298. package/ts_build/tests/unit/plugins/pluginLoading.test.js +59 -0
  299. package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -1
  300. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.d.ts +1 -0
  301. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js +32 -0
  302. package/ts_build/tests/unit/services/AgentSyncKnowhowWeb.test.js.map +1 -0
  303. package/ts_build/tests/unit/services/LazyToolsService.test.d.ts +1 -0
  304. package/ts_build/tests/unit/services/LazyToolsService.test.js +27 -0
  305. package/ts_build/tests/unit/services/LazyToolsService.test.js.map +1 -0
  306. package/ts_build/tests/unit/services/RuntimeReloadService.test.d.ts +1 -0
  307. package/ts_build/tests/unit/services/RuntimeReloadService.test.js +26 -0
  308. package/ts_build/tests/unit/services/RuntimeReloadService.test.js.map +1 -0
  309. package/ts_build/tests/unit/services/SessionManager.test.d.ts +1 -0
  310. package/ts_build/tests/unit/services/SessionManager.test.js +72 -0
  311. package/ts_build/tests/unit/services/SessionManager.test.js.map +1 -0
  312. package/ts_build/tests/unit/services/SyncerService.test.d.ts +1 -0
  313. package/ts_build/tests/unit/services/SyncerService.test.js +40 -0
  314. package/ts_build/tests/unit/services/SyncerService.test.js.map +1 -0
  315. package/ts_build/tests/unit/util/Trace.test.d.ts +1 -0
  316. package/ts_build/tests/unit/util/Trace.test.js +107 -0
  317. package/ts_build/tests/unit/util/Trace.test.js.map +1 -0
  318. package/ts_build/tests/unit/utils/http.test.d.ts +1 -0
  319. package/ts_build/tests/unit/utils/http.test.js +69 -0
  320. package/ts_build/tests/unit/utils/http.test.js.map +1 -0
@@ -1,6 +1,6 @@
1
1
  import { includedTools } from "../agents/tools/list";
2
2
  import * as allTools from "../agents/tools";
3
- import { LazyToolsService, services, MinimalToolsService } from "../services";
3
+ import { LazyToolsService, services, MinimalToolsService, TracingService } from "../services";
4
4
  import { agents } from "../agents";
5
5
  import { ModulesService } from "../services/modules";
6
6
  import { getConfig } from "../config";
@@ -19,8 +19,10 @@ export async function setupServices() {
19
19
  Events,
20
20
  MediaProcessor,
21
21
  Behaviors,
22
+ RuntimeReload,
22
23
  } = services();
23
24
 
25
+ await Plugins.refreshConfiguredState();
24
26
  // cli uses LazyTools to keep context slim
25
27
  const Tools = new LazyToolsService();
26
28
  await Behaviors.initFromConfig();
@@ -80,7 +82,7 @@ export async function setupServices() {
80
82
 
81
83
  console.log("📦 Loading modules from config...");
82
84
  const modulesService = new ModulesService();
83
- await modulesService.loadModulesFromConfig({
85
+ const moduleContext = {
84
86
  Agents,
85
87
  Embeddings,
86
88
  Plugins,
@@ -89,7 +91,51 @@ export async function setupServices() {
89
91
  MediaProcessor,
90
92
  Behaviors,
91
93
  Events,
94
+ Tracing: TracingService,
95
+ };
96
+
97
+ // Call destroy() on all modules when the process is shutting down so they
98
+ // can flush buffers (e.g. OTEL spans), close connections, etc.
99
+ const destroyAll = async () => {
100
+ await modulesService.destroyModules();
101
+ };
102
+ process.on("beforeExit", destroyAll);
103
+ process.on("SIGINT", async () => {
104
+ await destroyAll();
105
+ process.exit(0);
106
+ });
107
+ await modulesService.loadModulesFromConfig(moduleContext);
108
+
109
+ RuntimeReload.configure(async () => {
110
+ await modulesService.destroyModules();
111
+ await Plugins.refreshConfiguredState();
112
+ await Mcp.closeAll();
113
+
114
+ Tools.resetTools();
115
+ Tools.defineTools(includedTools, allTools);
116
+ try {
117
+ const agentCallDef = AllTools.getTool?.("agentCall");
118
+ const agentCallFn = AllTools.getFunction?.("agentCall");
119
+ if (agentCallDef) Tools.addTool(agentCallDef);
120
+ if (agentCallFn) Tools.setFunction("agentCall", agentCallFn);
121
+ } catch (_) {}
122
+
123
+ await Behaviors.initFromConfig();
124
+ await Mcp.connectToConfigured(Tools);
125
+ await Clients.registerConfiguredModels();
126
+ await modulesService.loadModulesFromConfig(moduleContext);
127
+
128
+ const config = await getConfig();
129
+ return {
130
+ tools: Tools.getTools().length,
131
+ mcps: (config.mcps || []).length,
132
+ modules: (config.modules || []).length,
133
+ };
134
+ });
135
+ process.on("SIGTERM", async () => {
136
+ await destroyAll();
137
+ process.exit(0);
92
138
  });
93
139
 
94
- return { Tools, Clients };
140
+ return { Tools, Clients, modulesService };
95
141
  }
package/src/login.ts CHANGED
@@ -1,13 +1,28 @@
1
1
  import http from "./utils/http";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
- import { chmod } from "fs/promises";
5
4
  import { ask } from "./utils";
6
5
  import { getConfig, updateConfig } from "./config";
7
6
  import { KNOWHOW_API_URL } from "./services/KnowhowClient";
8
7
  import { BrowserLoginService } from "./auth/browserLogin";
9
-
10
- export async function login(jwtFlag?: boolean): Promise<void> {
8
+ import { authenticateWithKey, hasKeyPair, registerPublicKey } from "./auth/keyAuth";
9
+ import { getOrCreatePublicKey } from "./auth/keyManager";
10
+
11
+ /**
12
+ * Log in to Knowhow.
13
+ *
14
+ * Strategy (in order):
15
+ * 1. `--jwt` flag: prompt for a raw JWT and write it to disk.
16
+ * 2. Key auth: if an Ed25519 key and configured organization exist, sign a
17
+ * server challenge and exchange it for an organization-bound JWT.
18
+ * 3. Browser: open the browser approval flow (first-time login or key not yet registered).
19
+ *
20
+ * After any successful login the local config is updated with the current user's orgId.
21
+ *
22
+ * @param jwtFlag True when --jwt flag is passed.
23
+ * @param identityPath Optional path to a specific private key file (--identity flag).
24
+ */
25
+ export async function login(jwtFlag?: boolean, identityPath?: string): Promise<void> {
11
26
  if (!KNOWHOW_API_URL) {
12
27
  throw new Error("Error: KNOWHOW_API_URL environment variable not set.");
13
28
  }
@@ -15,9 +30,8 @@ export async function login(jwtFlag?: boolean): Promise<void> {
15
30
  if (jwtFlag) {
16
31
  const jwt = await ask("Enter your JWT: ");
17
32
 
18
- // Update the JWT file
19
33
  const configDir = path.join(process.cwd(), ".knowhow");
20
- const jwtFile = path.join(process.cwd(), ".knowhow", ".jwt");
34
+ const jwtFile = path.join(configDir, ".jwt");
21
35
 
22
36
  if (!fs.existsSync(configDir)) {
23
37
  fs.mkdirSync(configDir, { recursive: true });
@@ -26,23 +40,69 @@ export async function login(jwtFlag?: boolean): Promise<void> {
26
40
  fs.chmodSync(jwtFile, 0o600);
27
41
  console.log("JWT updated successfully.");
28
42
  } else {
29
- // Use browser login as default method
30
- console.log("Starting browser-based authentication...");
43
+ const config = await getConfig();
44
+ const orgId = config.orgId;
45
+
46
+ // A local key is not proof of registration. Let the selected environment
47
+ // check it, but only when an organization is available to bind the attempt.
48
+ if (orgId && hasKeyPair(identityPath)) {
49
+ console.log("Found CLI identity — authenticating with public key...");
50
+ try {
51
+ const success = await authenticateWithKey(orgId, KNOWHOW_API_URL, identityPath);
52
+ if (success) {
53
+ console.log("✅ Successfully authenticated via public key!");
54
+ return await postLoginConfigUpdate(identityPath);
55
+ }
56
+ console.warn("Key authentication returned no JWT, falling back to browser login...");
57
+ } catch (error: unknown) {
58
+ const message = error instanceof Error ? error.message : String(error);
59
+ console.warn(`Key authentication failed (${message}), falling back to browser login...`);
60
+ }
61
+ }
62
+
63
+ // Fall back when no org/key is configured or when key auth is unavailable.
64
+ await doBrowserLogin(identityPath);
65
+ }
66
+
67
+ await postLoginConfigUpdate(identityPath);
68
+ }
69
+
70
+ /** Complete browser PKCE, then best-effort bootstrap the selected identity. */
71
+ async function doBrowserLogin(identityPath?: string): Promise<void> {
72
+ console.log("Starting browser-based authentication...");
73
+ try {
74
+ const existingConfig = await getConfig();
75
+ const existingOrgId = existingConfig?.orgId;
76
+ const browserLoginService = new BrowserLoginService(undefined, existingOrgId);
77
+ await browserLoginService.login();
78
+ console.log("✅ Successfully authenticated via browser!");
79
+
31
80
  try {
32
- // Pass existing orgId from config (if any) so the browser pre-selects the right org
33
- const existingConfig = await getConfig();
34
- const existingOrgId = existingConfig?.orgId;
35
- const browserLoginService = new BrowserLoginService(undefined, existingOrgId);
36
- await browserLoginService.login();
37
- console.log("Successfully authenticated via browser!");
38
- } catch (error) {
39
- console.error("Browser authentication failed:", error.message);
40
- console.log("You can try manual JWT login with: knowhow login --jwt");
41
- throw error;
81
+ const keyPair = getOrCreatePublicKey(identityPath);
82
+ await registerPublicKey(
83
+ await loadJwt(),
84
+ keyPair.publicKeyBase64,
85
+ KNOWHOW_API_URL
86
+ );
87
+ console.log(`Registered CLI identity ${keyPair.fingerprint}`);
88
+ } catch (registrationError: unknown) {
89
+ // Browser login remains valid when key registration is unavailable (for
90
+ // example during a rolling backend deployment or for a partial identity).
91
+ const message = registrationError instanceof Error
92
+ ? registrationError.message
93
+ : String(registrationError);
94
+ console.warn(`Could not register CLI identity (${message}). Browser login is still active.`);
42
95
  }
96
+ } catch (error: unknown) {
97
+ const msg = error instanceof Error ? error.message : String(error);
98
+ console.error("Browser authentication failed:", msg);
99
+ console.log("You can try manual JWT login with: knowhow login --jwt");
100
+ throw error;
43
101
  }
102
+ }
44
103
 
45
- // Get current user/org information
104
+ /** After any successful login, update the local config with the current user/org. */
105
+ async function postLoginConfigUpdate(identityPath?: string): Promise<void> {
46
106
  try {
47
107
  const storedJwt = await loadJwt();
48
108
  const { user, currentOrg } = await checkJwt(storedJwt);
@@ -59,25 +119,26 @@ export async function login(jwtFlag?: boolean): Promise<void> {
59
119
  }
60
120
 
61
121
  const hasProvider = config.modelProviders.find(
62
- (provider) => provider.provider === "knowhow"
122
+ (provider: { provider: string }) => provider.provider === "knowhow"
63
123
  );
64
124
  if (!hasProvider) {
65
- config.modelProviders.push({
66
- provider: "knowhow",
67
- });
125
+ config.modelProviders.push({ provider: "knowhow" });
68
126
  }
69
- // Save orgId to config so sync:remote and other features use the correct org
127
+
70
128
  if (orgId) {
71
129
  config.orgId = orgId;
72
130
  }
73
131
 
132
+ if (identityPath) {
133
+ config.cliIdentityPath = path.resolve(identityPath);
134
+ }
135
+
74
136
  await updateConfig(config);
75
- } catch (error) {
137
+ } catch (error: unknown) {
76
138
  if (http.isHttpError(error) && error.response) {
77
- // error.body is the parsed JSON response body (set by http.ts when response is not ok)
78
- const errData = error.body ?? { message: "Unknown error" };
139
+ const errData = (error as any).body ?? { message: "Unknown error" };
79
140
  throw new Error(
80
- `Error: ${error.status} - ${errData?.message || "Unknown error"}`
141
+ `Error: ${(error as any).status} - ${errData?.message || "Unknown error"}`
81
142
  );
82
143
  }
83
144
  console.log(
@@ -112,7 +173,7 @@ export async function checkJwt(storedJwt: string) {
112
173
  const orgs = user.orgs;
113
174
  const orgId = response.data.orgId;
114
175
 
115
- const currentOrg = orgs.find((org) => {
176
+ const currentOrg = orgs.find((org: { organizationId: string }) => {
116
177
  return org.organizationId === orgId;
117
178
  });
118
179
 
@@ -52,6 +52,22 @@ export class PluginService {
52
52
  return true;
53
53
  }
54
54
 
55
+ /** Apply the enabled/disabled state from the current Knowhow config. */
56
+ async refreshConfiguredState(): Promise<void> {
57
+ const config = await getConfig();
58
+ const disabled = new Set(getDisabledPlugins(config.plugins));
59
+
60
+ for (const [key, plugin] of this.pluginMap) {
61
+ if (disabled.has(key)) {
62
+ plugin.disable();
63
+ } else {
64
+ // Configuration is authoritative when services start or reload. This
65
+ // also re-enables a plugin after it is removed from `disabled`.
66
+ plugin.enable();
67
+ }
68
+ }
69
+ }
70
+
55
71
  /* -------- existing public API (updated for compatibility) ---------------------- */
56
72
 
57
73
  listPlugins() {
@@ -7,6 +7,7 @@ import {
7
7
  CompressionMetadata,
8
8
  JsonCompressorStorage,
9
9
  } from "./JsonCompressor";
10
+ import { paginateToolResponse } from "./tools/boundedToolResponse";
10
11
 
11
12
  export interface KeyInfo {
12
13
  key: string;
@@ -419,15 +420,25 @@ export class TokenCompressor implements JsonCompressorStorage {
419
420
  if (toolsService) {
420
421
  toolsService.addTools([expandTokensDefinition]);
421
422
  toolsService.addFunctions({
422
- [this.toolName]: (key: string, fromLine?: number, toLine?: number) => {
423
+ [this.toolName]: (
424
+ key: string,
425
+ fromLine?: number,
426
+ toLine?: number,
427
+ characterOffset?: number,
428
+ maxCharacters?: number
429
+ ) => {
423
430
  // Auto-stitch: follow any NEXT_CHUNK_KEY chain and return the full,
424
431
  // reassembled content so the agent never has to chase nested keys.
425
432
  const data = this.retrieveFullString(key);
426
433
 
427
434
  if (data === null) {
428
- return `Error: No data found for key "${key}". Available keys: ${this.getStorageKeys().join(
429
- ", "
430
- )}`;
435
+ return paginateToolResponse(
436
+ `Error: No data found for key "${key}". Available keys: ${this.getStorageKeys().join(
437
+ ", "
438
+ )}`,
439
+ { characterOffset, maxCharacters },
440
+ "available-key list"
441
+ );
431
442
  }
432
443
 
433
444
  // Optional ranged read: return only the requested 1-based, inclusive
@@ -435,7 +446,11 @@ export class TokenCompressor implements JsonCompressorStorage {
435
446
  const hasRange =
436
447
  typeof fromLine === "number" || typeof toLine === "number";
437
448
  if (!hasRange) {
438
- return data;
449
+ return paginateToolResponse(
450
+ data,
451
+ { characterOffset, maxCharacters },
452
+ `expanded value for ${key}`
453
+ );
439
454
  }
440
455
 
441
456
  const lines = data.split("\n");
@@ -447,14 +462,22 @@ export class TokenCompressor implements JsonCompressorStorage {
447
462
  );
448
463
 
449
464
  if (start > end) {
450
- return `Error: Invalid line range for key "${key}": fromLine (${start}) is greater than toLine (${end}). Content has ${totalLines} lines.`;
465
+ return paginateToolResponse(
466
+ `Error: Invalid line range for key "${key}": fromLine (${start}) is greater than toLine (${end}). Content has ${totalLines} lines.`,
467
+ { characterOffset, maxCharacters },
468
+ "line-range error"
469
+ );
451
470
  }
452
471
 
453
472
  const numbered: string[] = [];
454
473
  for (let i = start; i <= end; i++) {
455
474
  numbered.push(`${i}: ${lines[i - 1]}`);
456
475
  }
457
- return numbered.join("\n");
476
+ return paginateToolResponse(
477
+ numbered.join("\n"),
478
+ { characterOffset, maxCharacters },
479
+ `expanded lines ${start}-${end} for ${key}`
480
+ );
458
481
  },
459
482
  });
460
483
  }
@@ -559,7 +582,7 @@ export const expandTokensDefinition: Tool = {
559
582
  function: {
560
583
  name: "expandTokens",
561
584
  description:
562
- "Retrieve compressed data that was stored during message processing. The full content is automatically reassembled (any chunk chain is followed for you, so you never need to chase NEXT_CHUNK_KEY references). Optionally pass fromLine/toLine (1-based, inclusive) to return just a range of lines, prefixed with real line numbers. NOTE: Can also use jqToolResponse, grepToolResponse, tailToolResponse to access/filter/search compressed content without needing to expand all tokens.",
585
+ "Retrieve a bounded page of compressed data. Chunk chains are automatically reassembled, but output is limited to 20,000 characters by default. Use characterOffset to continue, or fromLine/toLine for line-based selection. Prefer jqToolResponse, grepToolResponse, or tailToolResponse when possible.",
563
586
  parameters: {
564
587
  type: "object",
565
588
  positional: true,
@@ -578,6 +601,15 @@ export const expandTokensDefinition: Tool = {
578
601
  description:
579
602
  "Optional 1-based end line (inclusive). Defaults to the end of the content when omitted.",
580
603
  },
604
+ characterOffset: {
605
+ type: "number",
606
+ description:
607
+ "Optional zero-based character offset within the expanded value or selected line range.",
608
+ },
609
+ maxCharacters: {
610
+ type: "number",
611
+ description: "Response size (default 20000, hard maximum 50000).",
612
+ },
581
613
  },
582
614
  required: ["key"],
583
615
  },
@@ -5,6 +5,7 @@ import { JsonCompressor } from "./JsonCompressor";
5
5
  import {
6
6
  jqToolResponseDefinition,
7
7
  executeJqQuery,
8
+ JqOptions,
8
9
  grepToolResponseDefinition,
9
10
  executeGrep,
10
11
  GrepOptions,
@@ -13,6 +14,7 @@ import {
13
14
  TailOptions,
14
15
  listStoredToolResponsesDefinition,
15
16
  executeListStoredToolResponses,
17
+ ListStoredToolResponsesOptions,
16
18
  } from "./tools";
17
19
 
18
20
  interface ToolResponseStorage {
@@ -196,11 +198,12 @@ export class ToolResponseCache {
196
198
  */
197
199
  async queryToolResponse(
198
200
  toolCallId: string,
199
- jqQuery: string
201
+ jqQuery: string,
202
+ options?: JqOptions
200
203
  ): Promise<string> {
201
204
  const data = this.storage[toolCallId];
202
205
  const availableIds = Object.keys(this.storage);
203
- return executeJqQuery(data, toolCallId, jqQuery, availableIds, this.toolNameMap);
206
+ return executeJqQuery(data, toolCallId, jqQuery, availableIds, this.toolNameMap, options);
204
207
  }
205
208
 
206
209
  /**
@@ -231,11 +234,14 @@ export class ToolResponseCache {
231
234
  /**
232
235
  * List all stored tool responses with metadata
233
236
  */
234
- async listStoredToolResponses(): Promise<string> {
237
+ async listStoredToolResponses(
238
+ options?: ListStoredToolResponsesOptions
239
+ ): Promise<string> {
235
240
  return executeListStoredToolResponses(
236
241
  this.storage,
237
242
  this.metadataStorage,
238
- this.toolNameMap
243
+ this.toolNameMap,
244
+ options
239
245
  );
240
246
  }
241
247
 
@@ -281,9 +287,10 @@ export class ToolResponseCache {
281
287
  toolsService.addFunctions({
282
288
  [jqToolResponseDefinition.function.name]: async (
283
289
  toolCallId: string,
284
- jqQuery: string
290
+ jqQuery: string,
291
+ options?: JqOptions
285
292
  ) => {
286
- return await this.queryToolResponse(toolCallId, jqQuery);
293
+ return await this.queryToolResponse(toolCallId, jqQuery, options);
287
294
  },
288
295
  [grepToolResponseDefinition.function.name]: async (
289
296
  toolCallId: string,
@@ -298,8 +305,10 @@ export class ToolResponseCache {
298
305
  ) => {
299
306
  return await this.tailToolResponse(toolCallId, options);
300
307
  },
301
- [listStoredToolResponsesDefinition.function.name]: async () => {
302
- return await this.listStoredToolResponses();
308
+ [listStoredToolResponsesDefinition.function.name]: async (
309
+ options?: ListStoredToolResponsesOptions
310
+ ) => {
311
+ return await this.listStoredToolResponses(options);
303
312
  },
304
313
  });
305
314
  }
@@ -0,0 +1,49 @@
1
+ export const DEFAULT_TOOL_RESPONSE_CHARACTERS = 20_000;
2
+ export const MAX_TOOL_RESPONSE_CHARACTERS = 50_000;
3
+
4
+ export function boundedInteger(
5
+ value: number | undefined,
6
+ fallback: number,
7
+ min: number,
8
+ max: number
9
+ ): number {
10
+ return Math.min(
11
+ max,
12
+ Math.max(min, Number.isFinite(value) ? Math.floor(value as number) : fallback)
13
+ );
14
+ }
15
+
16
+ /** Return a bounded character page with instructions for retrieving the next page. */
17
+ export function paginateToolResponse(
18
+ value: string,
19
+ options?: { characterOffset?: number; maxCharacters?: number },
20
+ label = "response"
21
+ ): string {
22
+ const characterOffset = boundedInteger(
23
+ options?.characterOffset,
24
+ 0,
25
+ 0,
26
+ Number.MAX_SAFE_INTEGER
27
+ );
28
+ const maxCharacters = boundedInteger(
29
+ options?.maxCharacters,
30
+ DEFAULT_TOOL_RESPONSE_CHARACTERS,
31
+ 1_000,
32
+ MAX_TOOL_RESPONSE_CHARACTERS
33
+ );
34
+ const footerReserve = 300;
35
+ const contentLimit = Math.max(1, maxCharacters - footerReserve);
36
+ const page = value.slice(characterOffset, characterOffset + contentLimit);
37
+ const end = characterOffset + page.length;
38
+ if (characterOffset === 0 && end >= value.length) {
39
+ return page;
40
+ }
41
+
42
+ const safeLabel = label.slice(0, 200);
43
+ const footer =
44
+ end < value.length
45
+ ? `\n\n[${safeLabel} characters ${characterOffset}-${Math.max(characterOffset, end - 1)} of ${value.length}. Repeat with characterOffset=${end} to continue; maxCharacters=${maxCharacters}.]`
46
+ : `\n\n[End of ${safeLabel}; characters ${characterOffset}-${Math.max(characterOffset, end - 1)} of ${value.length}.]`;
47
+
48
+ return (page + footer).slice(0, maxCharacters);
49
+ }