@tyvm/knowhow 0.0.108 → 0.0.109-dev.86123ed

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 (236) hide show
  1. package/README.md +45 -0
  2. package/package.json +9 -4
  3. package/scripts/build-for-node.sh +10 -24
  4. package/scripts/publish.sh +86 -0
  5. package/src/agents/base/base.ts +10 -0
  6. package/src/agents/tools/execCommand.ts +49 -6
  7. package/src/agents/tools/index.ts +0 -1
  8. package/src/agents/tools/list.ts +2 -4
  9. package/src/chat/CliChatService.ts +11 -2
  10. package/src/chat/modules/AgentModule.ts +61 -31
  11. package/src/chat/modules/SessionsModule.ts +47 -3
  12. package/src/chat/modules/SystemModule.ts +2 -2
  13. package/src/chat/renderer/CompactRenderer.ts +20 -0
  14. package/src/chat/renderer/ConsoleRenderer.ts +19 -0
  15. package/src/chat/renderer/FancyRenderer.ts +19 -0
  16. package/src/chat/renderer/types.ts +11 -0
  17. package/src/cli.ts +91 -659
  18. package/src/clients/anthropic.ts +18 -17
  19. package/src/clients/index.ts +31 -11
  20. package/src/clients/openai.ts +8 -5
  21. package/src/clients/types.ts +48 -10
  22. package/src/clients/withRetry.ts +89 -0
  23. package/src/cloudWorker.ts +175 -113
  24. package/src/commands/agent.ts +246 -0
  25. package/src/commands/misc.ts +174 -0
  26. package/src/commands/modules.ts +217 -0
  27. package/src/commands/services.ts +77 -0
  28. package/src/commands/workers.ts +168 -0
  29. package/src/config.ts +38 -1
  30. package/src/fileSync.ts +70 -29
  31. package/src/hashes.ts +35 -13
  32. package/src/index.ts +18 -0
  33. package/src/logger.ts +197 -0
  34. package/src/plugins/embedding.ts +11 -6
  35. package/src/plugins/plugins.ts +0 -21
  36. package/src/plugins/vim.ts +5 -16
  37. package/src/processors/JsonCompressor.ts +6 -6
  38. package/src/services/EventService.ts +61 -1
  39. package/src/services/KnowhowClient.ts +34 -4
  40. package/src/services/MediaProcessorService.ts +3 -2
  41. package/src/services/modules/index.ts +95 -51
  42. package/src/services/modules/types.ts +6 -0
  43. package/src/tunnel.ts +216 -0
  44. package/src/types.ts +0 -1
  45. package/src/worker.ts +105 -312
  46. package/src/workers/auth/WsMiddleware.ts +99 -0
  47. package/src/workers/auth/authMiddleware.ts +104 -0
  48. package/src/workers/auth/types.ts +14 -2
  49. package/src/workers/tools/index.ts +2 -0
  50. package/src/workers/tools/reloadConfig.ts +84 -0
  51. package/tests/services/WorkerReloadConfig.test.ts +141 -0
  52. package/tests/unit/clients/AIClient.test.ts +446 -0
  53. package/tests/unit/clients/withRetry.test.ts +319 -0
  54. package/tests/unit/commands/github-credentials.test.ts +210 -0
  55. package/tests/unit/modules/moduleLoading.test.ts +39 -37
  56. package/tests/unit/plugins/pluginLoading.test.ts +0 -85
  57. package/ts_build/package.json +9 -4
  58. package/ts_build/src/agents/base/base.js +11 -0
  59. package/ts_build/src/agents/base/base.js.map +1 -1
  60. package/ts_build/src/agents/tools/execCommand.d.ts +1 -1
  61. package/ts_build/src/agents/tools/execCommand.js +39 -5
  62. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  63. package/ts_build/src/agents/tools/index.d.ts +0 -1
  64. package/ts_build/src/agents/tools/index.js +0 -1
  65. package/ts_build/src/agents/tools/index.js.map +1 -1
  66. package/ts_build/src/agents/tools/list.js +2 -4
  67. package/ts_build/src/agents/tools/list.js.map +1 -1
  68. package/ts_build/src/chat/CliChatService.js +14 -2
  69. package/ts_build/src/chat/CliChatService.js.map +1 -1
  70. package/ts_build/src/chat/modules/AgentModule.d.ts +1 -1
  71. package/ts_build/src/chat/modules/AgentModule.js +43 -20
  72. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  73. package/ts_build/src/chat/modules/SessionsModule.js +37 -3
  74. package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
  75. package/ts_build/src/chat/modules/SystemModule.js +2 -2
  76. package/ts_build/src/chat/modules/SystemModule.js.map +1 -1
  77. package/ts_build/src/chat/renderer/CompactRenderer.d.ts +4 -0
  78. package/ts_build/src/chat/renderer/CompactRenderer.js +16 -0
  79. package/ts_build/src/chat/renderer/CompactRenderer.js.map +1 -1
  80. package/ts_build/src/chat/renderer/ConsoleRenderer.d.ts +4 -0
  81. package/ts_build/src/chat/renderer/ConsoleRenderer.js +16 -0
  82. package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -1
  83. package/ts_build/src/chat/renderer/FancyRenderer.d.ts +4 -0
  84. package/ts_build/src/chat/renderer/FancyRenderer.js +16 -0
  85. package/ts_build/src/chat/renderer/FancyRenderer.js.map +1 -1
  86. package/ts_build/src/chat/renderer/types.d.ts +2 -0
  87. package/ts_build/src/cli.js +47 -519
  88. package/ts_build/src/cli.js.map +1 -1
  89. package/ts_build/src/clients/anthropic.d.ts +5 -5
  90. package/ts_build/src/clients/anthropic.js +18 -17
  91. package/ts_build/src/clients/anthropic.js.map +1 -1
  92. package/ts_build/src/clients/index.js +9 -10
  93. package/ts_build/src/clients/index.js.map +1 -1
  94. package/ts_build/src/clients/openai.js +4 -4
  95. package/ts_build/src/clients/openai.js.map +1 -1
  96. package/ts_build/src/clients/types.d.ts +15 -8
  97. package/ts_build/src/clients/withRetry.d.ts +2 -0
  98. package/ts_build/src/clients/withRetry.js +60 -0
  99. package/ts_build/src/clients/withRetry.js.map +1 -0
  100. package/ts_build/src/cloudWorker.d.ts +14 -0
  101. package/ts_build/src/cloudWorker.js +105 -66
  102. package/ts_build/src/cloudWorker.js.map +1 -1
  103. package/ts_build/src/commands/agent.d.ts +6 -0
  104. package/ts_build/src/commands/agent.js +229 -0
  105. package/ts_build/src/commands/agent.js.map +1 -0
  106. package/ts_build/src/commands/misc.d.ts +10 -0
  107. package/ts_build/src/commands/misc.js +197 -0
  108. package/ts_build/src/commands/misc.js.map +1 -0
  109. package/ts_build/src/commands/modules.d.ts +3 -0
  110. package/ts_build/src/commands/modules.js +207 -0
  111. package/ts_build/src/commands/modules.js.map +1 -0
  112. package/ts_build/src/commands/services.d.ts +5 -0
  113. package/ts_build/src/commands/services.js +87 -0
  114. package/ts_build/src/commands/services.js.map +1 -0
  115. package/ts_build/src/commands/workers.d.ts +6 -0
  116. package/ts_build/src/commands/workers.js +168 -0
  117. package/ts_build/src/commands/workers.js.map +1 -0
  118. package/ts_build/src/config.d.ts +1 -0
  119. package/ts_build/src/config.js +33 -1
  120. package/ts_build/src/config.js.map +1 -1
  121. package/ts_build/src/fileSync.d.ts +6 -0
  122. package/ts_build/src/fileSync.js +50 -23
  123. package/ts_build/src/fileSync.js.map +1 -1
  124. package/ts_build/src/hashes.d.ts +2 -2
  125. package/ts_build/src/hashes.js +35 -9
  126. package/ts_build/src/hashes.js.map +1 -1
  127. package/ts_build/src/index.d.ts +1 -0
  128. package/ts_build/src/index.js +17 -1
  129. package/ts_build/src/index.js.map +1 -1
  130. package/ts_build/src/logger.d.ts +21 -0
  131. package/ts_build/src/logger.js +106 -0
  132. package/ts_build/src/logger.js.map +1 -0
  133. package/ts_build/src/plugins/embedding.js +4 -3
  134. package/ts_build/src/plugins/embedding.js.map +1 -1
  135. package/ts_build/src/plugins/plugins.d.ts +0 -2
  136. package/ts_build/src/plugins/plugins.js +0 -11
  137. package/ts_build/src/plugins/plugins.js.map +1 -1
  138. package/ts_build/src/plugins/vim.js +3 -9
  139. package/ts_build/src/plugins/vim.js.map +1 -1
  140. package/ts_build/src/processors/JsonCompressor.js +4 -4
  141. package/ts_build/src/processors/JsonCompressor.js.map +1 -1
  142. package/ts_build/src/services/EventService.d.ts +6 -1
  143. package/ts_build/src/services/EventService.js +29 -0
  144. package/ts_build/src/services/EventService.js.map +1 -1
  145. package/ts_build/src/services/KnowhowClient.d.ts +13 -1
  146. package/ts_build/src/services/KnowhowClient.js +19 -2
  147. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  148. package/ts_build/src/services/MediaProcessorService.d.ts +2 -1
  149. package/ts_build/src/services/MediaProcessorService.js +2 -1
  150. package/ts_build/src/services/MediaProcessorService.js.map +1 -1
  151. package/ts_build/src/services/modules/index.d.ts +33 -0
  152. package/ts_build/src/services/modules/index.js +67 -47
  153. package/ts_build/src/services/modules/index.js.map +1 -1
  154. package/ts_build/src/services/modules/types.d.ts +6 -0
  155. package/ts_build/src/tunnel.d.ts +27 -0
  156. package/ts_build/src/tunnel.js +112 -0
  157. package/ts_build/src/tunnel.js.map +1 -0
  158. package/ts_build/src/types.d.ts +0 -1
  159. package/ts_build/src/types.js.map +1 -1
  160. package/ts_build/src/worker.d.ts +1 -4
  161. package/ts_build/src/worker.js +59 -227
  162. package/ts_build/src/worker.js.map +1 -1
  163. package/ts_build/src/workers/auth/WsMiddleware.d.ts +8 -0
  164. package/ts_build/src/workers/auth/WsMiddleware.js +65 -0
  165. package/ts_build/src/workers/auth/WsMiddleware.js.map +1 -0
  166. package/ts_build/src/workers/auth/authMiddleware.d.ts +3 -0
  167. package/ts_build/src/workers/auth/authMiddleware.js +60 -0
  168. package/ts_build/src/workers/auth/authMiddleware.js.map +1 -0
  169. package/ts_build/src/workers/auth/types.d.ts +8 -1
  170. package/ts_build/src/workers/tools/index.d.ts +2 -0
  171. package/ts_build/src/workers/tools/index.js +4 -1
  172. package/ts_build/src/workers/tools/index.js.map +1 -1
  173. package/ts_build/src/workers/tools/reloadConfig.d.ts +14 -0
  174. package/ts_build/src/workers/tools/reloadConfig.js +48 -0
  175. package/ts_build/src/workers/tools/reloadConfig.js.map +1 -0
  176. package/ts_build/tests/services/WorkerReloadConfig.test.d.ts +1 -0
  177. package/ts_build/tests/services/WorkerReloadConfig.test.js +86 -0
  178. package/ts_build/tests/services/WorkerReloadConfig.test.js.map +1 -0
  179. package/ts_build/tests/unit/clients/AIClient.test.d.ts +1 -0
  180. package/ts_build/tests/unit/clients/AIClient.test.js +339 -0
  181. package/ts_build/tests/unit/clients/AIClient.test.js.map +1 -0
  182. package/ts_build/tests/unit/clients/withRetry.test.d.ts +1 -0
  183. package/ts_build/tests/unit/clients/withRetry.test.js +225 -0
  184. package/ts_build/tests/unit/clients/withRetry.test.js.map +1 -0
  185. package/ts_build/tests/unit/commands/github-credentials.test.d.ts +1 -0
  186. package/ts_build/tests/unit/commands/github-credentials.test.js +145 -0
  187. package/ts_build/tests/unit/commands/github-credentials.test.js.map +1 -0
  188. package/ts_build/tests/unit/modules/moduleLoading.test.js +20 -26
  189. package/ts_build/tests/unit/modules/moduleLoading.test.js.map +1 -1
  190. package/ts_build/tests/unit/plugins/pluginLoading.test.js +0 -65
  191. package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -1
  192. package/src/agents/tools/executeScript/README.md +0 -94
  193. package/src/agents/tools/executeScript/definition.ts +0 -79
  194. package/src/agents/tools/executeScript/examples/dependency-injection-validation.ts +0 -272
  195. package/src/agents/tools/executeScript/examples/quick-test.ts +0 -74
  196. package/src/agents/tools/executeScript/examples/serialization-test.ts +0 -321
  197. package/src/agents/tools/executeScript/examples/test-runner.ts +0 -197
  198. package/src/agents/tools/executeScript/index.ts +0 -98
  199. package/src/services/script-execution/SandboxContext.ts +0 -282
  200. package/src/services/script-execution/ScriptExecutor.ts +0 -441
  201. package/src/services/script-execution/ScriptPolicy.ts +0 -194
  202. package/src/services/script-execution/ScriptTracer.ts +0 -249
  203. package/src/services/script-execution/types.ts +0 -134
  204. package/ts_build/src/agents/tools/executeScript/definition.d.ts +0 -2
  205. package/ts_build/src/agents/tools/executeScript/definition.js +0 -76
  206. package/ts_build/src/agents/tools/executeScript/definition.js.map +0 -1
  207. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.d.ts +0 -18
  208. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.js +0 -192
  209. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.js.map +0 -1
  210. package/ts_build/src/agents/tools/executeScript/examples/quick-test.d.ts +0 -3
  211. package/ts_build/src/agents/tools/executeScript/examples/quick-test.js +0 -64
  212. package/ts_build/src/agents/tools/executeScript/examples/quick-test.js.map +0 -1
  213. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.d.ts +0 -15
  214. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.js +0 -266
  215. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.js.map +0 -1
  216. package/ts_build/src/agents/tools/executeScript/examples/test-runner.d.ts +0 -4
  217. package/ts_build/src/agents/tools/executeScript/examples/test-runner.js +0 -208
  218. package/ts_build/src/agents/tools/executeScript/examples/test-runner.js.map +0 -1
  219. package/ts_build/src/agents/tools/executeScript/index.d.ts +0 -28
  220. package/ts_build/src/agents/tools/executeScript/index.js +0 -72
  221. package/ts_build/src/agents/tools/executeScript/index.js.map +0 -1
  222. package/ts_build/src/services/script-execution/SandboxContext.d.ts +0 -34
  223. package/ts_build/src/services/script-execution/SandboxContext.js +0 -189
  224. package/ts_build/src/services/script-execution/SandboxContext.js.map +0 -1
  225. package/ts_build/src/services/script-execution/ScriptExecutor.d.ts +0 -19
  226. package/ts_build/src/services/script-execution/ScriptExecutor.js +0 -269
  227. package/ts_build/src/services/script-execution/ScriptExecutor.js.map +0 -1
  228. package/ts_build/src/services/script-execution/ScriptPolicy.d.ts +0 -28
  229. package/ts_build/src/services/script-execution/ScriptPolicy.js +0 -115
  230. package/ts_build/src/services/script-execution/ScriptPolicy.js.map +0 -1
  231. package/ts_build/src/services/script-execution/ScriptTracer.d.ts +0 -19
  232. package/ts_build/src/services/script-execution/ScriptTracer.js +0 -186
  233. package/ts_build/src/services/script-execution/ScriptTracer.js.map +0 -1
  234. package/ts_build/src/services/script-execution/types.d.ts +0 -108
  235. package/ts_build/src/services/script-execution/types.js +0 -3
  236. package/ts_build/src/services/script-execution/types.js.map +0 -1
@@ -0,0 +1,174 @@
1
+ import { Command } from "commander";
2
+ import { execSync } from "child_process";
3
+ import { version } from "../../package.json";
4
+ import { logger } from "../logger";
5
+ import { generate, embed, upload, download, purge } from "../index";
6
+ import { init } from "../config";
7
+ import { login } from "../login";
8
+ import { KnowhowSimpleClient } from "../services/KnowhowClient";
9
+ import { startChat } from "../chat";
10
+
11
+ export function addInitCommand(program: Command): void {
12
+ program
13
+ .command("init")
14
+ .description("Initialize knowhow configuration")
15
+ .action(async () => {
16
+ await init();
17
+ });
18
+ }
19
+
20
+ export function addLoginCommand(program: Command): void {
21
+ program
22
+ .command("login")
23
+ .description("Login to knowhow")
24
+ .option("--jwt", "Use manual JWT input instead of browser login")
25
+ .action(async (opts) => {
26
+ await login(opts.jwt);
27
+ });
28
+ }
29
+
30
+ export function addUpdateCommand(program: Command): void {
31
+ program
32
+ .command("update")
33
+ .description("Update knowhow to the latest version from npm")
34
+ .action(async () => {
35
+ try {
36
+ console.log("🔄 Checking for knowhow updates...");
37
+ console.log(`Current version: ${version}`);
38
+ console.log("📦 Installing latest version from npm...");
39
+ execSync("npm install -g @tyvm/knowhow@latest", {
40
+ stdio: "inherit",
41
+ encoding: "utf-8",
42
+ });
43
+ console.log("✓ knowhow has been updated successfully!");
44
+ console.log("Run 'knowhow --version' to see the new version.");
45
+ } catch (error) {
46
+ console.error("Error updating knowhow:", error.message);
47
+ process.exit(1);
48
+ }
49
+ });
50
+ }
51
+
52
+ export function addGenerateCommand(program: Command): void {
53
+ program
54
+ .command("generate")
55
+ .description("Generate documentation")
56
+ .action(async () => {
57
+ const { setupServices } = await import("./services");
58
+ await setupServices();
59
+ await generate();
60
+ });
61
+ }
62
+
63
+ export function addEmbedCommands(program: Command): void {
64
+ program
65
+ .command("embed")
66
+ .description("Create embeddings")
67
+ .action(async () => {
68
+ const { setupServices } = await import("./services");
69
+ await setupServices();
70
+ await embed();
71
+ });
72
+
73
+ program
74
+ .command("embed:purge")
75
+ .description("Purge embeddings matching a glob pattern")
76
+ .argument("<pattern>", "Glob pattern to match files for purging")
77
+ .action(async (pattern) => {
78
+ await purge(pattern);
79
+ });
80
+ }
81
+
82
+ export function addUploadCommand(program: Command): void {
83
+ program
84
+ .command("upload")
85
+ .description("Upload data")
86
+ .action(async () => {
87
+ await upload();
88
+ });
89
+ }
90
+
91
+ export function addDownloadCommand(program: Command): void {
92
+ program
93
+ .command("download")
94
+ .description("Download data")
95
+ .action(async () => {
96
+ await download();
97
+ });
98
+ }
99
+
100
+ export function addChatCommand(program: Command): void {
101
+ program
102
+ .command("chat")
103
+ .description("Start new chat interface")
104
+ .action(async () => {
105
+ const { setupServices } = await import("./services");
106
+ await setupServices();
107
+ await startChat();
108
+ });
109
+ }
110
+
111
+ export function addGithubCredentialsCommand(program: Command): void {
112
+ program
113
+ .command("github-credentials [action]")
114
+ .description(
115
+ "Git credential helper for GitHub. Use as: git config credential.helper 'knowhow github-credentials'"
116
+ )
117
+ .option(
118
+ "--repo <repo>",
119
+ "Repository in owner/repo format (e.g. myorg/myrepo)"
120
+ )
121
+ .action(async (action: string | undefined, options: { repo?: string }) => {
122
+ // Silence ALL output immediately — git credential helpers must produce
123
+ // only the protocol=.../host=.../username=.../password=... lines on stdout.
124
+ logger.silence();
125
+
126
+ const client = new KnowhowSimpleClient();
127
+
128
+ let repo = options.repo;
129
+
130
+ if (action === "get") {
131
+ const lines: string[] = [];
132
+ const readline = await import("readline");
133
+ const rl = readline.createInterface({
134
+ input: process.stdin,
135
+ terminal: false,
136
+ });
137
+ await new Promise<void>((resolve) => {
138
+ rl.on("line", (line) => {
139
+ if (line.trim()) lines.push(line.trim());
140
+ });
141
+ rl.on("close", resolve);
142
+ });
143
+ } else if (action === "store" || action === "erase") {
144
+ process.exit(0);
145
+ }
146
+
147
+ if (!repo) {
148
+ try {
149
+ const remoteUrl = execSync("git remote get-url origin", {
150
+ encoding: "utf-8",
151
+ stdio: ["pipe", "pipe", "pipe"],
152
+ }).trim();
153
+ const match =
154
+ remoteUrl.match(/github\.com[/:]([^/]+\/[^/]+?)(?:\.git)?$/) ||
155
+ remoteUrl.match(/github\.com\/([^/]+\/[^/]+)/);
156
+ if (match) {
157
+ repo = match[1];
158
+ }
159
+ } catch {
160
+ // Not in a git repo or no remote — proceed without repo
161
+ }
162
+ }
163
+
164
+ try {
165
+ const credential = await client.getGitCredential(repo || "");
166
+ process.stdout.write(
167
+ `protocol=${credential.protocol}\nhost=${credential.host}\nusername=${credential.username}\npassword=${credential.password}\n`
168
+ );
169
+ } catch (error) {
170
+ console.error("Failed to get git credentials:", error.message);
171
+ process.exit(1);
172
+ }
173
+ });
174
+ }
@@ -0,0 +1,217 @@
1
+ import { Command } from "commander";
2
+ import { execSync } from "child_process";
3
+ import * as fs from "fs";
4
+ import * as path from "path";
5
+ import * as os from "os";
6
+ import { getConfig, getGlobalConfig, updateConfig, updateGlobalConfig } from "../config";
7
+
8
+ // Default built-in modules that `knowhow modules setup` adds to the config.
9
+ export const BUILTIN_MODULES = [
10
+ "@tyvm/knowhow-module-script",
11
+ "@tyvm/knowhow-module-terminal",
12
+ ];
13
+
14
+ /**
15
+ * Returns the path to the .knowhow directory (used as npm install prefix).
16
+ * For global: ~/.knowhow
17
+ * For local: <cwd>/.knowhow
18
+ */
19
+ function getKnowhowDir(isGlobal: boolean): string {
20
+ if (isGlobal) {
21
+ return path.join(os.homedir(), ".knowhow");
22
+ }
23
+ return path.join(process.cwd(), ".knowhow");
24
+ }
25
+
26
+ /**
27
+ * Ensures the .knowhow directory has a minimal package.json so
28
+ * `npm install --prefix` works cleanly without polluting the project root.
29
+ */
30
+ function ensureKnowhowPackageJson(knowhowDir: string): void {
31
+ const pkgPath = path.join(knowhowDir, "package.json");
32
+ if (!fs.existsSync(pkgPath)) {
33
+ fs.mkdirSync(knowhowDir, { recursive: true });
34
+ fs.writeFileSync(
35
+ pkgPath,
36
+ JSON.stringify({ name: "knowhow-modules", private: true, version: "1.0.0" }, null, 2)
37
+ );
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Run `npm install --prefix <knowhowDir> <mod>` so that modules land in
43
+ * .knowhow/node_modules rather than the project's node_modules.
44
+ */
45
+ function npmInstallToKnowhow(mod: string, knowhowDir: string): void {
46
+ execSync(`npm install --prefix "${knowhowDir}" ${mod}`, {
47
+ stdio: "inherit",
48
+ encoding: "utf-8",
49
+ });
50
+ }
51
+
52
+ export function addModulesCommand(program: Command): void {
53
+ const modulesCmd = program
54
+ .command("modules")
55
+ .description("Manage knowhow modules (install, add to config, list)");
56
+
57
+ modulesCmd
58
+ .command("setup")
59
+ .description(
60
+ "Add default built-in modules to your config and install them into .knowhow/node_modules"
61
+ )
62
+ .option("--global", "Use the global config (~/.knowhow/knowhow.json)")
63
+ .action(async (opts) => {
64
+ try {
65
+ const isGlobal: boolean = opts.global ?? false;
66
+ const cfg = isGlobal ? await getGlobalConfig() : await getConfig();
67
+ const configLabel = isGlobal
68
+ ? "~/.knowhow/knowhow.json"
69
+ : ".knowhow/knowhow.json";
70
+
71
+ if (!cfg.modules) cfg.modules = [];
72
+
73
+ const toAdd = BUILTIN_MODULES.filter(
74
+ (m) => !cfg.modules!.includes(m)
75
+ );
76
+
77
+ if (toAdd.length === 0) {
78
+ console.log(
79
+ `✅ All default modules are already in ${configLabel}. Nothing to do.`
80
+ );
81
+ return;
82
+ }
83
+
84
+ const knowhowDir = getKnowhowDir(isGlobal);
85
+ ensureKnowhowPackageJson(knowhowDir);
86
+
87
+ // Install packages that are not local file paths
88
+ for (const mod of toAdd) {
89
+ if (!mod.startsWith(".") && !mod.startsWith("/")) {
90
+ console.log(`📦 Installing ${mod}...`);
91
+ npmInstallToKnowhow(mod, knowhowDir);
92
+ }
93
+ cfg.modules!.push(mod);
94
+ console.log(`✅ Added ${mod} to ${configLabel}`);
95
+ }
96
+
97
+ if (isGlobal) {
98
+ await updateGlobalConfig(cfg);
99
+ } else {
100
+ await updateConfig(cfg);
101
+ }
102
+
103
+ console.log(
104
+ `\n🎉 Setup complete! ${toAdd.length} module(s) added to ${configLabel}`
105
+ );
106
+ } catch (error: any) {
107
+ console.error("Error during modules setup:", error.message ?? error);
108
+ process.exit(1);
109
+ }
110
+ });
111
+
112
+ modulesCmd
113
+ .command("install [module]")
114
+ .description(
115
+ "Install a module into .knowhow/node_modules and add it to your config. " +
116
+ "If no module name is given, installs all modules already in the config."
117
+ )
118
+ .option("--global", "Use the global config (~/.knowhow/knowhow.json)")
119
+ .action(async (moduleName: string | undefined, opts) => {
120
+ try {
121
+ const isGlobal: boolean = opts.global ?? false;
122
+ const cfg = isGlobal ? await getGlobalConfig() : await getConfig();
123
+ const configLabel = isGlobal
124
+ ? "~/.knowhow/knowhow.json"
125
+ : ".knowhow/knowhow.json";
126
+
127
+ if (!cfg.modules) cfg.modules = [];
128
+
129
+ const knowhowDir = getKnowhowDir(isGlobal);
130
+ ensureKnowhowPackageJson(knowhowDir);
131
+
132
+ if (!moduleName) {
133
+ // No module specified — install everything already in the config
134
+ const installable = cfg.modules.filter(
135
+ (m) => !m.startsWith(".") && !m.startsWith("/")
136
+ );
137
+ if (installable.length === 0) {
138
+ console.log(
139
+ `ℹ No installable modules found in ${configLabel}.`
140
+ );
141
+ return;
142
+ }
143
+ console.log(
144
+ `📦 Installing ${installable.length} module(s) from ${configLabel} into ${knowhowDir}/node_modules...`
145
+ );
146
+ for (const mod of installable) {
147
+ console.log(` 📦 Installing ${mod}...`);
148
+ npmInstallToKnowhow(mod, knowhowDir);
149
+ console.log(` ✅ Installed ${mod}`);
150
+ }
151
+ console.log(`\n🎉 All modules installed!`);
152
+ return;
153
+ }
154
+
155
+ // Install the specified module
156
+ console.log(`📦 Installing ${moduleName} into ${knowhowDir}/node_modules...`);
157
+ npmInstallToKnowhow(moduleName, knowhowDir);
158
+ console.log(`✅ Installed ${moduleName}`);
159
+
160
+ // Add to config if not already there
161
+ if (!cfg.modules.includes(moduleName)) {
162
+ cfg.modules.push(moduleName);
163
+ if (isGlobal) {
164
+ await updateGlobalConfig(cfg);
165
+ } else {
166
+ await updateConfig(cfg);
167
+ }
168
+ console.log(`✅ Added ${moduleName} to ${configLabel}`);
169
+ } else {
170
+ console.log(`ℹ ${moduleName} is already in ${configLabel}`);
171
+ }
172
+ } catch (error: any) {
173
+ console.error("Error during module install:", error.message ?? error);
174
+ process.exit(1);
175
+ }
176
+ });
177
+
178
+ modulesCmd
179
+ .command("list")
180
+ .description("List all modules in your config")
181
+ .option("--global", "Show global config modules only")
182
+ .action(async (opts) => {
183
+ try {
184
+ const isGlobal: boolean = opts.global ?? false;
185
+ const globalCfg = await getGlobalConfig();
186
+ const localCfg = isGlobal ? null : await getConfig();
187
+
188
+ const globalModules = globalCfg.modules || [];
189
+ const localModules = localCfg?.modules || [];
190
+
191
+ if (isGlobal) {
192
+ console.log(`\n🌐 Global modules (~/.knowhow/knowhow.json):`);
193
+ if (globalModules.length === 0) {
194
+ console.log(" (none)");
195
+ } else {
196
+ globalModules.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
197
+ }
198
+ } else {
199
+ console.log(`\n🌐 Global modules (~/.knowhow/knowhow.json):`);
200
+ if (globalModules.length === 0) {
201
+ console.log(" (none)");
202
+ } else {
203
+ globalModules.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
204
+ }
205
+ console.log(`\n📁 Local modules (.knowhow/knowhow.json):`);
206
+ if (localModules.length === 0) {
207
+ console.log(" (none)");
208
+ } else {
209
+ localModules.forEach((m, i) => console.log(` ${i + 1}. ${m}`));
210
+ }
211
+ }
212
+ } catch (error: any) {
213
+ console.error("Error listing modules:", error.message ?? error);
214
+ process.exit(1);
215
+ }
216
+ });
217
+ }
@@ -0,0 +1,77 @@
1
+ import { includedTools } from "../agents/tools/list";
2
+ import * as allTools from "../agents/tools";
3
+ import { LazyToolsService, services } from "../services";
4
+ import { agents } from "../agents";
5
+ import { ModulesService } from "../services/modules";
6
+
7
+ /**
8
+ * Shared service setup used by commands that need full services (chat, agent, worker, etc.)
9
+ */
10
+ export async function setupServices() {
11
+ const {
12
+ Agents,
13
+ Mcp,
14
+ Clients,
15
+ Tools: AllTools,
16
+ Embeddings,
17
+ Plugins,
18
+ Events,
19
+ MediaProcessor,
20
+ } = services();
21
+
22
+
23
+ // cli uses LazyTools to keep context slim
24
+ const Tools = new LazyToolsService();
25
+
26
+ Tools.setContext({
27
+ ...AllTools.getContext(),
28
+ });
29
+
30
+ const agentContext: import("../agents/base/base").AgentContext = {
31
+ ...services(),
32
+ Tools,
33
+ };
34
+
35
+ const { Researcher, Developer, Patcher, Setup } = agents({
36
+ ...agentContext,
37
+ });
38
+
39
+ Agents.registerAgent(Researcher);
40
+ Agents.registerAgent(Patcher);
41
+ Agents.registerAgent(Developer);
42
+ Agents.registerAgent(Setup);
43
+ Agents.loadAgentsFromConfig(agentContext);
44
+
45
+ Tools.defineTools(includedTools, allTools);
46
+
47
+ Tools.addContext("Mcp", Mcp);
48
+
49
+ Agents.setAgentContext(agentContext);
50
+
51
+ console.log("🔌 Connecting to MCP...");
52
+ try {
53
+ await Mcp.connectToConfigured(Tools);
54
+ } catch (mcpError) {
55
+ const msg = mcpError instanceof Error ? mcpError.message : String(mcpError);
56
+ console.warn(
57
+ `⚠ Some MCP servers failed to connect (continuing without them): ${msg}`
58
+ );
59
+ }
60
+ console.log("Connecting to clients...");
61
+ await Clients.registerConfiguredModels();
62
+ console.log("✓ Services are set up and ready to go!");
63
+
64
+ console.log("📦 Loading modules from config...");
65
+ const modulesService = new ModulesService();
66
+ await modulesService.loadModulesFromConfig({
67
+ Agents,
68
+ Embeddings,
69
+ Plugins,
70
+ Clients,
71
+ Tools,
72
+ MediaProcessor,
73
+ Events
74
+ });
75
+
76
+ return { Tools, Clients };
77
+ }
@@ -0,0 +1,168 @@
1
+ import { Command } from "commander";
2
+ import { worker } from "../worker";
3
+ import { TUNNEL_MINIMAL_TOOLS } from "../tunnel";
4
+ import { fileSync } from "../fileSync";
5
+ import {
6
+ startAllWorkers,
7
+ listWorkerPaths,
8
+ unregisterWorkerPath,
9
+ clearWorkerRegistry,
10
+ } from "../workerRegistry";
11
+
12
+ export function addWorkerCommand(program: Command): void {
13
+ program
14
+ .command("worker")
15
+ .description(
16
+ "Start worker process and optionally register current directory"
17
+ )
18
+ .option("--register", "Register current directory as a worker path")
19
+ .option(
20
+ "--share",
21
+ "Share this worker with your organization (allows other users to use it)"
22
+ )
23
+ .option("--unshare", "Make this worker private (only you can use it)")
24
+ .option("--sandbox", "Run worker in a Docker container for isolation")
25
+ .option(
26
+ "--no-sandbox",
27
+ "Run worker directly on host (disable sandbox mode)"
28
+ )
29
+ .option("--passkey", "Set up passkey authentication for this worker")
30
+ .option("--passkey-reset", "Remove passkey authentication requirement")
31
+ .action(async (options) => {
32
+ const { setupServices } = await import("./services");
33
+ await setupServices();
34
+ await worker(options);
35
+ });
36
+ }
37
+
38
+ export function addWorkersCommand(program: Command): void {
39
+ program
40
+ .command("workers")
41
+ .description("Manage and start all registered workers")
42
+ .option("--list", "List all registered worker paths")
43
+ .option("--unregister <path>", "Unregister a worker path")
44
+ .option("--clear", "Clear all registered worker paths")
45
+ .action(async (options) => {
46
+ try {
47
+ if (options.list) {
48
+ const workers = await listWorkerPaths();
49
+ if (workers.length === 0) {
50
+ console.log("No workers registered.");
51
+ console.log(
52
+ "\nTo register a worker, run 'knowhow worker --register' from the worker directory."
53
+ );
54
+ } else {
55
+ console.log(`Registered workers (${workers.length}):`);
56
+ workers.forEach((workerPath, index) => {
57
+ console.log(` ${index + 1}. ${workerPath}`);
58
+ });
59
+ }
60
+ return;
61
+ }
62
+
63
+ if (options.unregister) {
64
+ await unregisterWorkerPath(options.unregister);
65
+ return;
66
+ }
67
+
68
+ if (options.clear) {
69
+ await clearWorkerRegistry();
70
+ return;
71
+ }
72
+
73
+ // Default action: start all workers
74
+ const { setupServices } = await import("./services");
75
+ await setupServices();
76
+ await startAllWorkers();
77
+ } catch (error) {
78
+ console.error("Error managing workers:", error);
79
+ process.exit(1);
80
+ }
81
+ });
82
+ }
83
+
84
+ export function addTunnelCommand(program: Command): void {
85
+ program
86
+ .command("tunnel")
87
+ .description(
88
+ "Start a minimal worker with tunnel enabled: exposes local ports to the cloud. " +
89
+ "Registers essential tools (unlock, lock, listAllowedPorts) so the backend is aware of the worker and ports. " +
90
+ "If passkey auth is configured, the tunnel is locked until unlocked via tool call or WebSocket auth protocol."
91
+ )
92
+ .option(
93
+ "--share",
94
+ "Share this tunnel with your organization (allows other users to use it)"
95
+ )
96
+ .option("--unshare", "Make this tunnel private (only you can use it)")
97
+ .action(async (options) => {
98
+ console.log("🌐 Starting tunnel (minimal worker) mode...");
99
+ console.log(` Tools: ${TUNNEL_MINIMAL_TOOLS.join(", ")}`);
100
+ await worker({
101
+ ...options,
102
+ allowedTools: TUNNEL_MINIMAL_TOOLS,
103
+ });
104
+ });
105
+ }
106
+
107
+ export function addFilesCommand(program: Command): void {
108
+ program
109
+ .command("files")
110
+ .description(
111
+ "Sync files between local filesystem and Knowhow FS (uses fileMounts config)"
112
+ )
113
+ .option("--upload", "Force upload direction for all mounts")
114
+ .option("--download", "Force download direction for all mounts")
115
+ .option("--config <path>", "Path to knowhow.json", "./knowhow.json")
116
+ .option("--dry-run", "Print what would be synced without doing it")
117
+ .action(async (options) => {
118
+ try {
119
+ await fileSync(options);
120
+ } catch (error) {
121
+ console.error("Error syncing files:", error);
122
+ process.exit(1);
123
+ }
124
+ });
125
+ }
126
+
127
+ export function addCloudWorkerCommand(program: Command): void {
128
+ program
129
+ .command("cloudworker")
130
+ .description("Create or sync a cloud worker with your local knowhow config")
131
+ .option(
132
+ "--init",
133
+ "Initialize config.files entries based on what exists in .knowhow/ (run once before --push)"
134
+ )
135
+ .option(
136
+ "--create",
137
+ "Create a new cloud worker with synced config and files"
138
+ )
139
+ .option(
140
+ "--push <uid>",
141
+ "Push/sync local config and files to an existing cloud worker"
142
+ )
143
+ .option(
144
+ "--pull <id>",
145
+ "Pull the latest workerConfigJson from a cloud worker and update local config"
146
+ )
147
+ .option("--name <name>", "Name for the cloud worker (used with --create)")
148
+ .option("--dry-run", "Print what would be synced without doing it")
149
+ .action(async (options) => {
150
+ try {
151
+ const { cloudWorker, pullCloudWorkerConfig, initCloudWorker } = await import(
152
+ "../cloudWorker"
153
+ );
154
+ if (options.init) {
155
+ await initCloudWorker({ dryRun: options.dryRun });
156
+ return;
157
+ }
158
+ if (options.pull) {
159
+ await pullCloudWorkerConfig({ id: options.pull });
160
+ } else {
161
+ await cloudWorker(options);
162
+ }
163
+ } catch (error) {
164
+ console.error("Error running cloudworker:", error);
165
+ process.exit(1);
166
+ }
167
+ });
168
+ }
package/src/config.ts CHANGED
@@ -74,7 +74,7 @@ const defaultConfig = {
74
74
  description:
75
75
  "You can define agents in the config. They will have access to all tools.",
76
76
  instructions: "Reply to the user saying 'Hello, world!'",
77
- model: "gpt-4o-2024-08-06",
77
+ model: "gpt-5.4-nano",
78
78
  provider: "openai",
79
79
  },
80
80
  ],
@@ -168,6 +168,27 @@ export async function init() {
168
168
  console.log("Initializing global knowhow config at ~/.knowhow");
169
169
  const globalConfigDir = await ensureGlobalConfigDir();
170
170
 
171
+ // Ensure the script module is registered in the global config so that
172
+ // `knowhow script` and the `executeScript` tool are available everywhere.
173
+ const SCRIPT_MODULE = "@tyvm/knowhow-module-script";
174
+ const globalConfigPath = path.join(globalConfigDir, "knowhow.json");
175
+ try {
176
+ const rawGlobal = fs.existsSync(globalConfigPath)
177
+ ? fs.readFileSync(globalConfigPath, "utf8")
178
+ : JSON.stringify(defaultConfig, null, 2);
179
+ const globalConf = JSON.parse(rawGlobal) as Config;
180
+ if (!globalConf.modules) {
181
+ globalConf.modules = [];
182
+ }
183
+ if (!globalConf.modules.includes(SCRIPT_MODULE)) {
184
+ globalConf.modules.push(SCRIPT_MODULE);
185
+ fs.writeFileSync(globalConfigPath, JSON.stringify(globalConf, null, 2));
186
+ console.log(`✅ Added ${SCRIPT_MODULE} to ~/.knowhow/knowhow.json modules`);
187
+ }
188
+ } catch (e) {
189
+ console.warn(`⚠ Could not update global config to add script module:`, e);
190
+ }
191
+
171
192
  // create the folder structure
172
193
  console.log("Initializing local knowhow config at ./.knowhow");
173
194
  await mkdir(".knowhow", { recursive: true });
@@ -287,6 +308,22 @@ export async function getGlobalConfig(): Promise<Config> {
287
308
  }
288
309
  }
289
310
 
311
+ export async function updateGlobalConfig(config: Config) {
312
+ if (!config || typeof config !== "object") {
313
+ throw new Error("Invalid config object");
314
+ }
315
+
316
+ const globalConfigDir = getGlobalConfigDir();
317
+ await mkdir(globalConfigDir, { recursive: true });
318
+ const globalConfigPath = path.join(globalConfigDir, "knowhow.json");
319
+
320
+ if (fs.existsSync(globalConfigPath)) {
321
+ await fs.promises.copyFile(globalConfigPath, globalConfigPath + ".bak");
322
+ }
323
+
324
+ await writeFile(globalConfigPath, JSON.stringify(config, null, 2));
325
+ }
326
+
290
327
  export async function migrateConfig() {
291
328
  // Apply migrations, used to keep config structure up to date.
292
329
  if (!fs.existsSync(".knowhow/knowhow.json")) {