@tyvm/knowhow 0.0.105 → 0.0.106

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 (209) hide show
  1. package/CONFIG.md +8 -5
  2. package/package.json +3 -2
  3. package/scripts/check-model-pricing.ts +509 -0
  4. package/scripts/compare-openrouter-coverage.ts +576 -0
  5. package/src/agents/base/base.ts +127 -2
  6. package/src/agents/tools/execCommand.ts +4 -0
  7. package/src/agents/tools/executeScript/definition.ts +1 -1
  8. package/src/agents/tools/index.ts +0 -1
  9. package/src/agents/tools/list.ts +3 -43
  10. package/src/agents/tools/writeFile.ts +1 -1
  11. package/src/auth/browserLogin.ts +9 -4
  12. package/src/chat/modules/RemoteSyncModule.ts +3 -0
  13. package/src/cli.ts +31 -1
  14. package/src/clients/cerebras.ts +10 -0
  15. package/src/clients/contextLimits.ts +7 -2
  16. package/src/clients/copilot.ts +23 -0
  17. package/src/clients/deepseek.ts +16 -0
  18. package/src/clients/fireworks.ts +15 -0
  19. package/src/clients/gemini.ts +45 -2
  20. package/src/clients/github.ts +16 -0
  21. package/src/clients/groq.ts +15 -0
  22. package/src/clients/http.ts +190 -6
  23. package/src/clients/index.ts +116 -4
  24. package/src/clients/llama.ts +16 -0
  25. package/src/clients/mistral.ts +16 -0
  26. package/src/clients/nvidia.ts +16 -0
  27. package/src/clients/openai.ts +41 -11
  28. package/src/clients/openrouter.ts +17 -0
  29. package/src/clients/pricing/anthropic.ts +105 -78
  30. package/src/clients/pricing/cerebras.ts +11 -0
  31. package/src/clients/pricing/copilot.ts +60 -0
  32. package/src/clients/pricing/deepseek.ts +15 -0
  33. package/src/clients/pricing/fireworks.ts +32 -0
  34. package/src/clients/pricing/github.ts +69 -0
  35. package/src/clients/pricing/google.ts +245 -206
  36. package/src/clients/pricing/groq.ts +56 -0
  37. package/src/clients/pricing/index.ts +42 -5
  38. package/src/clients/pricing/llama.ts +18 -0
  39. package/src/clients/pricing/mistral.ts +34 -0
  40. package/src/clients/pricing/models.ts +7 -236
  41. package/src/clients/pricing/nvidia.ts +102 -0
  42. package/src/clients/pricing/openai.ts +347 -171
  43. package/src/clients/pricing/openrouter.ts +36 -0
  44. package/src/clients/pricing/types.ts +83 -2
  45. package/src/clients/pricing/xai.ts +121 -65
  46. package/src/clients/types.ts +4 -0
  47. package/src/clients/xai.ts +150 -0
  48. package/src/fileSync.ts +8 -2
  49. package/src/login.ts +11 -3
  50. package/src/services/AgentSyncFs.ts +36 -12
  51. package/src/services/KnowhowClient.ts +11 -0
  52. package/src/services/LazyToolsService.ts +6 -0
  53. package/src/services/S3.ts +0 -7
  54. package/src/services/modules/index.ts +11 -2
  55. package/src/types.ts +56 -279
  56. package/src/worker.ts +174 -0
  57. package/tests/clients/pricing.test.ts +37 -0
  58. package/tests/manual/clients/completions.json +838 -226
  59. package/tests/manual/clients/completions.test.ts +46 -31
  60. package/ts_build/package.json +3 -2
  61. package/ts_build/src/agents/base/base.d.ts +17 -1
  62. package/ts_build/src/agents/base/base.js +82 -1
  63. package/ts_build/src/agents/base/base.js.map +1 -1
  64. package/ts_build/src/agents/tools/execCommand.js +3 -0
  65. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  66. package/ts_build/src/agents/tools/executeScript/definition.js +1 -1
  67. package/ts_build/src/agents/tools/executeScript/definition.js.map +1 -1
  68. package/ts_build/src/agents/tools/index.d.ts +0 -1
  69. package/ts_build/src/agents/tools/index.js +0 -1
  70. package/ts_build/src/agents/tools/index.js.map +1 -1
  71. package/ts_build/src/agents/tools/list.js +3 -38
  72. package/ts_build/src/agents/tools/list.js.map +1 -1
  73. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  74. package/ts_build/src/agents/tools/writeFile.js +1 -1
  75. package/ts_build/src/agents/tools/writeFile.js.map +1 -1
  76. package/ts_build/src/ai.d.ts +1 -1
  77. package/ts_build/src/auth/browserLogin.d.ts +2 -1
  78. package/ts_build/src/auth/browserLogin.js +10 -3
  79. package/ts_build/src/auth/browserLogin.js.map +1 -1
  80. package/ts_build/src/chat/modules/RemoteSyncModule.js +1 -0
  81. package/ts_build/src/chat/modules/RemoteSyncModule.js.map +1 -1
  82. package/ts_build/src/cli.js +19 -0
  83. package/ts_build/src/cli.js.map +1 -1
  84. package/ts_build/src/clients/anthropic.d.ts +1 -82
  85. package/ts_build/src/clients/cerebras.d.ts +4 -0
  86. package/ts_build/src/clients/cerebras.js +14 -0
  87. package/ts_build/src/clients/cerebras.js.map +1 -0
  88. package/ts_build/src/clients/contextLimits.js +7 -2
  89. package/ts_build/src/clients/contextLimits.js.map +1 -1
  90. package/ts_build/src/clients/copilot.d.ts +4 -0
  91. package/ts_build/src/clients/copilot.js +15 -0
  92. package/ts_build/src/clients/copilot.js.map +1 -0
  93. package/ts_build/src/clients/deepseek.d.ts +4 -0
  94. package/ts_build/src/clients/deepseek.js +15 -0
  95. package/ts_build/src/clients/deepseek.js.map +1 -0
  96. package/ts_build/src/clients/fireworks.d.ts +4 -0
  97. package/ts_build/src/clients/fireworks.js +15 -0
  98. package/ts_build/src/clients/fireworks.js.map +1 -0
  99. package/ts_build/src/clients/gemini.d.ts +1 -0
  100. package/ts_build/src/clients/gemini.js +28 -1
  101. package/ts_build/src/clients/gemini.js.map +1 -1
  102. package/ts_build/src/clients/github.d.ts +4 -0
  103. package/ts_build/src/clients/github.js +15 -0
  104. package/ts_build/src/clients/github.js.map +1 -0
  105. package/ts_build/src/clients/groq.d.ts +4 -0
  106. package/ts_build/src/clients/groq.js +15 -0
  107. package/ts_build/src/clients/groq.js.map +1 -0
  108. package/ts_build/src/clients/http.d.ts +22 -1
  109. package/ts_build/src/clients/http.js +132 -7
  110. package/ts_build/src/clients/http.js.map +1 -1
  111. package/ts_build/src/clients/index.d.ts +14 -0
  112. package/ts_build/src/clients/index.js +94 -4
  113. package/ts_build/src/clients/index.js.map +1 -1
  114. package/ts_build/src/clients/llama.d.ts +4 -0
  115. package/ts_build/src/clients/llama.js +15 -0
  116. package/ts_build/src/clients/llama.js.map +1 -0
  117. package/ts_build/src/clients/mistral.d.ts +4 -0
  118. package/ts_build/src/clients/mistral.js +15 -0
  119. package/ts_build/src/clients/mistral.js.map +1 -0
  120. package/ts_build/src/clients/nvidia.d.ts +4 -0
  121. package/ts_build/src/clients/nvidia.js +15 -0
  122. package/ts_build/src/clients/nvidia.js.map +1 -0
  123. package/ts_build/src/clients/openai.d.ts +4 -206
  124. package/ts_build/src/clients/openai.js +27 -9
  125. package/ts_build/src/clients/openai.js.map +1 -1
  126. package/ts_build/src/clients/openrouter.d.ts +4 -0
  127. package/ts_build/src/clients/openrouter.js +15 -0
  128. package/ts_build/src/clients/openrouter.js.map +1 -0
  129. package/ts_build/src/clients/pricing/anthropic.d.ts +26 -78
  130. package/ts_build/src/clients/pricing/anthropic.js +75 -78
  131. package/ts_build/src/clients/pricing/anthropic.js.map +1 -1
  132. package/ts_build/src/clients/pricing/cerebras.d.ts +4 -0
  133. package/ts_build/src/clients/pricing/cerebras.js +11 -0
  134. package/ts_build/src/clients/pricing/cerebras.js.map +1 -0
  135. package/ts_build/src/clients/pricing/copilot.d.ts +5 -0
  136. package/ts_build/src/clients/pricing/copilot.js +35 -0
  137. package/ts_build/src/clients/pricing/copilot.js.map +1 -0
  138. package/ts_build/src/clients/pricing/deepseek.d.ts +5 -0
  139. package/ts_build/src/clients/pricing/deepseek.js +10 -0
  140. package/ts_build/src/clients/pricing/deepseek.js.map +1 -0
  141. package/ts_build/src/clients/pricing/fireworks.d.ts +5 -0
  142. package/ts_build/src/clients/pricing/fireworks.js +21 -0
  143. package/ts_build/src/clients/pricing/fireworks.js.map +1 -0
  144. package/ts_build/src/clients/pricing/github.d.ts +4 -0
  145. package/ts_build/src/clients/pricing/github.js +58 -0
  146. package/ts_build/src/clients/pricing/github.js.map +1 -0
  147. package/ts_build/src/clients/pricing/google.d.ts +59 -6
  148. package/ts_build/src/clients/pricing/google.js +214 -167
  149. package/ts_build/src/clients/pricing/google.js.map +1 -1
  150. package/ts_build/src/clients/pricing/groq.d.ts +5 -0
  151. package/ts_build/src/clients/pricing/groq.js +41 -0
  152. package/ts_build/src/clients/pricing/groq.js.map +1 -0
  153. package/ts_build/src/clients/pricing/index.d.ts +16 -5
  154. package/ts_build/src/clients/pricing/index.js +62 -7
  155. package/ts_build/src/clients/pricing/index.js.map +1 -1
  156. package/ts_build/src/clients/pricing/llama.d.ts +4 -0
  157. package/ts_build/src/clients/pricing/llama.js +14 -0
  158. package/ts_build/src/clients/pricing/llama.js.map +1 -0
  159. package/ts_build/src/clients/pricing/mistral.d.ts +5 -0
  160. package/ts_build/src/clients/pricing/mistral.js +23 -0
  161. package/ts_build/src/clients/pricing/mistral.js.map +1 -0
  162. package/ts_build/src/clients/pricing/models.d.ts +5 -4
  163. package/ts_build/src/clients/pricing/models.js +8 -162
  164. package/ts_build/src/clients/pricing/models.js.map +1 -1
  165. package/ts_build/src/clients/pricing/nvidia.d.ts +8 -0
  166. package/ts_build/src/clients/pricing/nvidia.js +96 -0
  167. package/ts_build/src/clients/pricing/nvidia.js.map +1 -0
  168. package/ts_build/src/clients/pricing/openai.d.ts +86 -197
  169. package/ts_build/src/clients/pricing/openai.js +294 -168
  170. package/ts_build/src/clients/pricing/openai.js.map +1 -1
  171. package/ts_build/src/clients/pricing/openrouter.d.ts +4 -0
  172. package/ts_build/src/clients/pricing/openrouter.js +29 -0
  173. package/ts_build/src/clients/pricing/openrouter.js.map +1 -0
  174. package/ts_build/src/clients/pricing/types.d.ts +27 -2
  175. package/ts_build/src/clients/pricing/types.js +46 -0
  176. package/ts_build/src/clients/pricing/types.js.map +1 -1
  177. package/ts_build/src/clients/pricing/xai.d.ts +37 -57
  178. package/ts_build/src/clients/pricing/xai.js +92 -59
  179. package/ts_build/src/clients/pricing/xai.js.map +1 -1
  180. package/ts_build/src/clients/types.d.ts +1 -0
  181. package/ts_build/src/clients/xai.d.ts +2 -62
  182. package/ts_build/src/clients/xai.js +121 -0
  183. package/ts_build/src/clients/xai.js.map +1 -1
  184. package/ts_build/src/fileSync.js +7 -2
  185. package/ts_build/src/fileSync.js.map +1 -1
  186. package/ts_build/src/login.js +8 -2
  187. package/ts_build/src/login.js.map +1 -1
  188. package/ts_build/src/services/AgentSyncFs.js +1 -0
  189. package/ts_build/src/services/AgentSyncFs.js.map +1 -1
  190. package/ts_build/src/services/KnowhowClient.d.ts +1 -0
  191. package/ts_build/src/services/KnowhowClient.js +7 -0
  192. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  193. package/ts_build/src/services/LazyToolsService.d.ts +1 -0
  194. package/ts_build/src/services/LazyToolsService.js +3 -0
  195. package/ts_build/src/services/LazyToolsService.js.map +1 -1
  196. package/ts_build/src/services/S3.js +0 -7
  197. package/ts_build/src/services/S3.js.map +1 -1
  198. package/ts_build/src/services/modules/index.js +41 -1
  199. package/ts_build/src/services/modules/index.js.map +1 -1
  200. package/ts_build/src/types.d.ts +163 -124
  201. package/ts_build/src/types.js +33 -213
  202. package/ts_build/src/types.js.map +1 -1
  203. package/ts_build/src/worker.d.ts +4 -0
  204. package/ts_build/src/worker.js +140 -0
  205. package/ts_build/src/worker.js.map +1 -1
  206. package/ts_build/tests/clients/pricing.test.js +21 -0
  207. package/ts_build/tests/clients/pricing.test.js.map +1 -1
  208. package/ts_build/tests/manual/clients/completions.test.js +27 -24
  209. package/ts_build/tests/manual/clients/completions.test.js.map +1 -1
package/src/worker.ts CHANGED
@@ -578,3 +578,177 @@ export async function worker(options?: {
578
578
  await wait(5000);
579
579
  }
580
580
  }
581
+
582
+ /**
583
+ * Run tunnel-only mode: connects to the Knowhow tunnel WebSocket without
584
+ * registering any MCP tools. Useful for users who only want the web tunnel
585
+ * feature to expose local ports to the cloud.
586
+ */
587
+ export async function tunnel(options?: {
588
+ share?: boolean;
589
+ unshare?: boolean;
590
+ }) {
591
+ const config = await getConfig();
592
+
593
+ const isInsideDocker = process.env.KNOWHOW_DOCKER === "true";
594
+
595
+ // Determine localHost based on environment
596
+ let tunnelLocalHost = config.worker?.tunnel?.localHost;
597
+ if (!tunnelLocalHost) {
598
+ if (isInsideDocker) {
599
+ tunnelLocalHost = "host.docker.internal";
600
+ console.log(
601
+ "🐳 Docker detected: tunnel will use host.docker.internal to reach host services"
602
+ );
603
+ } else {
604
+ tunnelLocalHost = "127.0.0.1";
605
+ }
606
+ }
607
+
608
+ // Check for port mapping configuration
609
+ const portMapping = config.worker?.tunnel?.portMapping || {};
610
+ if (Object.keys(portMapping).length > 0) {
611
+ console.log("🔀 Port mapping configured:");
612
+ for (const [containerPort, hostPort] of Object.entries(portMapping)) {
613
+ console.log(` Container port ${containerPort} → Host port ${hostPort}`);
614
+ }
615
+ }
616
+
617
+ const tunnelPorts = config.worker?.tunnel?.allowedPorts || [];
618
+ if (tunnelPorts.length === 0) {
619
+ console.warn(
620
+ "⚠️ No allowedPorts configured. Add worker.tunnel.allowedPorts to knowhow.json"
621
+ );
622
+ } else {
623
+ console.log(`🌐 Tunnel mode for ports: ${tunnelPorts.join(", ")}`);
624
+ }
625
+
626
+ // Extract tunnel domain from API_URL
627
+ function extractTunnelDomain(apiUrl: string): {
628
+ domain: string;
629
+ useHttps: boolean;
630
+ } {
631
+ try {
632
+ const url = new URL(apiUrl);
633
+ const useHttps = url.protocol === "https:";
634
+ if (url.hostname === "localhost" || url.hostname === "127.0.0.1") {
635
+ return {
636
+ domain: `worker.${url.hostname}:${url.port || "80"}`,
637
+ useHttps,
638
+ };
639
+ }
640
+ return { domain: `worker.${url.hostname}`, useHttps };
641
+ } catch (err) {
642
+ console.error("Failed to parse API_URL for tunnel domain:", err);
643
+ return { domain: "worker.localhost:4000", useHttps: false };
644
+ }
645
+ }
646
+
647
+ let connected = false;
648
+ let tunnelHandler: TunnelHandler | null = null;
649
+ let lastJwt: string | null = null;
650
+ let unauthorizedJwt: string | null = null;
651
+
652
+ async function connectTunnel() {
653
+ const jwt = await loadJwt();
654
+ lastJwt = jwt;
655
+ console.log(`Connecting tunnel to ${API_URL}`);
656
+
657
+ const dir = process.cwd();
658
+ const homedir = os.homedir();
659
+ const hostname = process.env.WORKER_HOSTNAME || os.hostname();
660
+ const root =
661
+ process.env.WORKER_ROOT ||
662
+ (dir === homedir ? "~" : dir.replace(homedir, "~"));
663
+
664
+ const headers: Record<string, string> = {
665
+ Authorization: `Bearer ${jwt}`,
666
+ "User-Agent": `knowhow-tunnel/1.0.0/${hostname}`,
667
+ Root: root,
668
+ };
669
+
670
+ if (options?.share) {
671
+ headers.Shared = "true";
672
+ console.log("🔓 Tunnel shared with organization");
673
+ } else if (options?.unshare) {
674
+ headers.Shared = "false";
675
+ console.log("🔒 Tunnel is now private (unshared)");
676
+ } else {
677
+ console.log("🔒 Tunnel is private (only you can use it)");
678
+ }
679
+
680
+ const { domain: tunnelDomain, useHttps: tunnelUseHttps } =
681
+ extractTunnelDomain(API_URL);
682
+
683
+ const tunnelConnection = new WebSocket(`${API_URL}/ws/tunnel`, { headers });
684
+
685
+ tunnelConnection.on("open", () => {
686
+ console.log("🌐 Tunnel WebSocket connected");
687
+ connected = true;
688
+
689
+ const allowedPorts = config.worker?.tunnel?.allowedPorts || [];
690
+ const urlRewriter = (port: number, metadata?: any) => {
691
+ const workerId = metadata?.workerId;
692
+ const secret = metadata?.secret;
693
+ const subdomain = secret ? `${secret}-p${port}` : `${workerId}-p${port}`;
694
+ return `${subdomain}.${tunnelDomain}`;
695
+ };
696
+
697
+ const tunnelConfig = {
698
+ allowedPorts,
699
+ maxConcurrentStreams: config.worker?.tunnel?.maxConcurrentStreams || 50,
700
+ tunnelUseHttps,
701
+ localHost: tunnelLocalHost,
702
+ urlRewriter,
703
+ enableUrlRewriting: config.worker?.tunnel?.enableUrlRewriting !== false,
704
+ portMapping,
705
+ logLevel: "debug" as const,
706
+ };
707
+
708
+ tunnelHandler = createTunnelHandler(tunnelConnection, tunnelConfig);
709
+ console.log("🌐 Tunnel handler initialized");
710
+ console.log(tunnelConfig);
711
+ });
712
+
713
+ tunnelConnection.on("close", (code, reason) => {
714
+ console.log(`Tunnel WebSocket closed. Code: ${code}, Reason: ${reason.toString()}`);
715
+ if (code === 1008) {
716
+ unauthorizedJwt = lastJwt;
717
+ console.error("❌ Tunnel received Unauthorized (1008). The JWT may be expired.");
718
+ console.error(" Run 'knowhow login' to refresh your token, then restart.");
719
+ console.error(" Pausing reconnection until JWT changes...");
720
+ } else {
721
+ console.log("Tunnel connection will reconnect on next cycle...");
722
+ }
723
+ if (tunnelHandler) {
724
+ tunnelHandler.cleanup();
725
+ tunnelHandler = null;
726
+ }
727
+ connected = false;
728
+ });
729
+
730
+ tunnelConnection.on("error", (error) => {
731
+ console.error("Tunnel WebSocket error:", error);
732
+ connected = false;
733
+ });
734
+
735
+ return tunnelConnection;
736
+ }
737
+
738
+ while (true) {
739
+ if (!connected) {
740
+ if (unauthorizedJwt !== null) {
741
+ const currentJwt = await loadJwt().catch(() => null);
742
+ if (currentJwt === unauthorizedJwt) {
743
+ await wait(5000);
744
+ continue;
745
+ }
746
+ console.log("🔄 JWT has changed, attempting to reconnect tunnel...");
747
+ unauthorizedJwt = null;
748
+ }
749
+ console.log("Attempting to connect tunnel...");
750
+ await connectTunnel();
751
+ }
752
+ await wait(5000);
753
+ }
754
+ }
@@ -5,6 +5,9 @@
5
5
  * Models that are image-only, video-only, TTS, transcription, realtime, or live streaming
6
6
  * are exempt from text pricing requirements — they should have their own pricing entries
7
7
  * in the appropriate pricing tables (image, video, audio, etc.).
8
+ *
9
+ * Also verifies that every model in Models.* and EmbeddingModels.* has a catalog entry,
10
+ * ensuring the catalog stays in sync with the model definitions.
8
11
  */
9
12
 
10
13
  import {
@@ -27,6 +30,7 @@ import {
27
30
  GeminiTextPricing,
28
31
  AnthropicTextPricing,
29
32
  XaiTextPricing,
33
+ ALL_MODEL_CATALOG,
30
34
  XaiImagePricing,
31
35
  XaiVideoPricing,
32
36
  } from "../../src/clients/pricing";
@@ -140,5 +144,38 @@ describe("Model Pricing Coverage", () => {
140
144
  expect(entry).toBeDefined();
141
145
  });
142
146
  }
147
+
148
+ describe("Model Catalog Coverage", () => {
149
+ /**
150
+ * Every model defined in Models.* and EmbeddingModels.* must have an entry
151
+ * in ALL_MODEL_CATALOG. This ensures the catalog stays in sync and is the
152
+ * single source of truth for model metadata and pricing.
153
+ */
154
+ const catalogIds = new Set(ALL_MODEL_CATALOG.map((m) => m.id));
155
+
156
+ describe("All Models.* entries are in the catalog", () => {
157
+ for (const [provider, providerModels] of Object.entries(Models)) {
158
+ for (const [modelKey, modelId] of Object.entries(
159
+ providerModels as Record<string, string>
160
+ )) {
161
+ it(`Models.${provider}.${modelKey} (${modelId}) is in ALL_MODEL_CATALOG`, () => {
162
+ expect(catalogIds.has(modelId)).toBe(true);
163
+ });
164
+ }
165
+ }
166
+ });
167
+
168
+ describe("All EmbeddingModels.* entries are in the catalog", () => {
169
+ for (const [provider, providerModels] of Object.entries(EmbeddingModels)) {
170
+ for (const [modelKey, modelId] of Object.entries(
171
+ providerModels as Record<string, string>
172
+ )) {
173
+ it(`EmbeddingModels.${provider}.${modelKey} (${modelId}) is in ALL_MODEL_CATALOG`, () => {
174
+ expect(catalogIds.has(modelId)).toBe(true);
175
+ });
176
+ }
177
+ }
178
+ });
179
+ });
143
180
  });
144
181
  });