@tyvm/knowhow 0.0.108 → 0.0.109-dev.e88af1e

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 (214) 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 +0 -2
  9. package/src/chat/CliChatService.ts +10 -1
  10. package/src/chat/modules/AgentModule.ts +61 -31
  11. package/src/chat/modules/SessionsModule.ts +47 -3
  12. package/src/chat/renderer/CompactRenderer.ts +20 -0
  13. package/src/chat/renderer/ConsoleRenderer.ts +19 -0
  14. package/src/chat/renderer/FancyRenderer.ts +19 -0
  15. package/src/chat/renderer/types.ts +11 -0
  16. package/src/cli.ts +91 -659
  17. package/src/clients/anthropic.ts +17 -16
  18. package/src/clients/index.ts +6 -5
  19. package/src/clients/types.ts +19 -4
  20. package/src/cloudWorker.ts +175 -113
  21. package/src/commands/agent.ts +246 -0
  22. package/src/commands/misc.ts +174 -0
  23. package/src/commands/modules.ts +217 -0
  24. package/src/commands/services.ts +77 -0
  25. package/src/commands/workers.ts +168 -0
  26. package/src/config.ts +37 -0
  27. package/src/fileSync.ts +70 -29
  28. package/src/hashes.ts +35 -13
  29. package/src/index.ts +18 -0
  30. package/src/logger.ts +197 -0
  31. package/src/plugins/embedding.ts +11 -6
  32. package/src/plugins/plugins.ts +0 -21
  33. package/src/plugins/vim.ts +5 -16
  34. package/src/processors/JsonCompressor.ts +6 -6
  35. package/src/services/EventService.ts +61 -1
  36. package/src/services/KnowhowClient.ts +34 -4
  37. package/src/services/modules/index.ts +95 -51
  38. package/src/services/modules/types.ts +6 -0
  39. package/src/tunnel.ts +216 -0
  40. package/src/types.ts +0 -1
  41. package/src/worker.ts +105 -312
  42. package/src/workers/auth/WsMiddleware.ts +99 -0
  43. package/src/workers/auth/authMiddleware.ts +104 -0
  44. package/src/workers/auth/types.ts +14 -2
  45. package/src/workers/tools/index.ts +2 -0
  46. package/src/workers/tools/reloadConfig.ts +84 -0
  47. package/tests/services/WorkerReloadConfig.test.ts +141 -0
  48. package/tests/unit/commands/github-credentials.test.ts +211 -0
  49. package/tests/unit/modules/moduleLoading.test.ts +39 -37
  50. package/tests/unit/plugins/pluginLoading.test.ts +0 -85
  51. package/ts_build/package.json +9 -4
  52. package/ts_build/src/agents/base/base.js +11 -0
  53. package/ts_build/src/agents/base/base.js.map +1 -1
  54. package/ts_build/src/agents/tools/execCommand.d.ts +1 -1
  55. package/ts_build/src/agents/tools/execCommand.js +39 -5
  56. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  57. package/ts_build/src/agents/tools/index.d.ts +0 -1
  58. package/ts_build/src/agents/tools/index.js +0 -1
  59. package/ts_build/src/agents/tools/index.js.map +1 -1
  60. package/ts_build/src/agents/tools/list.js +0 -2
  61. package/ts_build/src/agents/tools/list.js.map +1 -1
  62. package/ts_build/src/chat/CliChatService.js +13 -1
  63. package/ts_build/src/chat/CliChatService.js.map +1 -1
  64. package/ts_build/src/chat/modules/AgentModule.d.ts +1 -1
  65. package/ts_build/src/chat/modules/AgentModule.js +43 -20
  66. package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
  67. package/ts_build/src/chat/modules/SessionsModule.js +37 -3
  68. package/ts_build/src/chat/modules/SessionsModule.js.map +1 -1
  69. package/ts_build/src/chat/renderer/CompactRenderer.d.ts +4 -0
  70. package/ts_build/src/chat/renderer/CompactRenderer.js +16 -0
  71. package/ts_build/src/chat/renderer/CompactRenderer.js.map +1 -1
  72. package/ts_build/src/chat/renderer/ConsoleRenderer.d.ts +4 -0
  73. package/ts_build/src/chat/renderer/ConsoleRenderer.js +16 -0
  74. package/ts_build/src/chat/renderer/ConsoleRenderer.js.map +1 -1
  75. package/ts_build/src/chat/renderer/FancyRenderer.d.ts +4 -0
  76. package/ts_build/src/chat/renderer/FancyRenderer.js +16 -0
  77. package/ts_build/src/chat/renderer/FancyRenderer.js.map +1 -1
  78. package/ts_build/src/chat/renderer/types.d.ts +2 -0
  79. package/ts_build/src/cli.js +47 -519
  80. package/ts_build/src/cli.js.map +1 -1
  81. package/ts_build/src/clients/anthropic.d.ts +5 -5
  82. package/ts_build/src/clients/anthropic.js +17 -16
  83. package/ts_build/src/clients/anthropic.js.map +1 -1
  84. package/ts_build/src/clients/index.js +2 -4
  85. package/ts_build/src/clients/index.js.map +1 -1
  86. package/ts_build/src/clients/types.d.ts +3 -2
  87. package/ts_build/src/cloudWorker.d.ts +14 -0
  88. package/ts_build/src/cloudWorker.js +105 -66
  89. package/ts_build/src/cloudWorker.js.map +1 -1
  90. package/ts_build/src/commands/agent.d.ts +6 -0
  91. package/ts_build/src/commands/agent.js +229 -0
  92. package/ts_build/src/commands/agent.js.map +1 -0
  93. package/ts_build/src/commands/misc.d.ts +10 -0
  94. package/ts_build/src/commands/misc.js +197 -0
  95. package/ts_build/src/commands/misc.js.map +1 -0
  96. package/ts_build/src/commands/modules.d.ts +3 -0
  97. package/ts_build/src/commands/modules.js +207 -0
  98. package/ts_build/src/commands/modules.js.map +1 -0
  99. package/ts_build/src/commands/services.d.ts +5 -0
  100. package/ts_build/src/commands/services.js +87 -0
  101. package/ts_build/src/commands/services.js.map +1 -0
  102. package/ts_build/src/commands/workers.d.ts +6 -0
  103. package/ts_build/src/commands/workers.js +168 -0
  104. package/ts_build/src/commands/workers.js.map +1 -0
  105. package/ts_build/src/config.d.ts +1 -0
  106. package/ts_build/src/config.js +32 -0
  107. package/ts_build/src/config.js.map +1 -1
  108. package/ts_build/src/fileSync.d.ts +6 -0
  109. package/ts_build/src/fileSync.js +50 -23
  110. package/ts_build/src/fileSync.js.map +1 -1
  111. package/ts_build/src/hashes.d.ts +2 -2
  112. package/ts_build/src/hashes.js +35 -9
  113. package/ts_build/src/hashes.js.map +1 -1
  114. package/ts_build/src/index.d.ts +1 -0
  115. package/ts_build/src/index.js +17 -1
  116. package/ts_build/src/index.js.map +1 -1
  117. package/ts_build/src/logger.d.ts +21 -0
  118. package/ts_build/src/logger.js +106 -0
  119. package/ts_build/src/logger.js.map +1 -0
  120. package/ts_build/src/plugins/embedding.js +4 -3
  121. package/ts_build/src/plugins/embedding.js.map +1 -1
  122. package/ts_build/src/plugins/plugins.d.ts +0 -2
  123. package/ts_build/src/plugins/plugins.js +0 -11
  124. package/ts_build/src/plugins/plugins.js.map +1 -1
  125. package/ts_build/src/plugins/vim.js +3 -9
  126. package/ts_build/src/plugins/vim.js.map +1 -1
  127. package/ts_build/src/processors/JsonCompressor.js +4 -4
  128. package/ts_build/src/processors/JsonCompressor.js.map +1 -1
  129. package/ts_build/src/services/EventService.d.ts +6 -1
  130. package/ts_build/src/services/EventService.js +29 -0
  131. package/ts_build/src/services/EventService.js.map +1 -1
  132. package/ts_build/src/services/KnowhowClient.d.ts +13 -1
  133. package/ts_build/src/services/KnowhowClient.js +19 -2
  134. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  135. package/ts_build/src/services/modules/index.d.ts +33 -0
  136. package/ts_build/src/services/modules/index.js +67 -47
  137. package/ts_build/src/services/modules/index.js.map +1 -1
  138. package/ts_build/src/services/modules/types.d.ts +6 -0
  139. package/ts_build/src/tunnel.d.ts +27 -0
  140. package/ts_build/src/tunnel.js +112 -0
  141. package/ts_build/src/tunnel.js.map +1 -0
  142. package/ts_build/src/types.d.ts +0 -1
  143. package/ts_build/src/types.js.map +1 -1
  144. package/ts_build/src/worker.d.ts +1 -4
  145. package/ts_build/src/worker.js +59 -227
  146. package/ts_build/src/worker.js.map +1 -1
  147. package/ts_build/src/workers/auth/WsMiddleware.d.ts +8 -0
  148. package/ts_build/src/workers/auth/WsMiddleware.js +65 -0
  149. package/ts_build/src/workers/auth/WsMiddleware.js.map +1 -0
  150. package/ts_build/src/workers/auth/authMiddleware.d.ts +3 -0
  151. package/ts_build/src/workers/auth/authMiddleware.js +60 -0
  152. package/ts_build/src/workers/auth/authMiddleware.js.map +1 -0
  153. package/ts_build/src/workers/auth/types.d.ts +8 -1
  154. package/ts_build/src/workers/tools/index.d.ts +2 -0
  155. package/ts_build/src/workers/tools/index.js +4 -1
  156. package/ts_build/src/workers/tools/index.js.map +1 -1
  157. package/ts_build/src/workers/tools/reloadConfig.d.ts +14 -0
  158. package/ts_build/src/workers/tools/reloadConfig.js +48 -0
  159. package/ts_build/src/workers/tools/reloadConfig.js.map +1 -0
  160. package/ts_build/tests/services/WorkerReloadConfig.test.d.ts +1 -0
  161. package/ts_build/tests/services/WorkerReloadConfig.test.js +86 -0
  162. package/ts_build/tests/services/WorkerReloadConfig.test.js.map +1 -0
  163. package/ts_build/tests/unit/commands/github-credentials.test.d.ts +1 -0
  164. package/ts_build/tests/unit/commands/github-credentials.test.js +146 -0
  165. package/ts_build/tests/unit/commands/github-credentials.test.js.map +1 -0
  166. package/ts_build/tests/unit/modules/moduleLoading.test.js +20 -26
  167. package/ts_build/tests/unit/modules/moduleLoading.test.js.map +1 -1
  168. package/ts_build/tests/unit/plugins/pluginLoading.test.js +0 -65
  169. package/ts_build/tests/unit/plugins/pluginLoading.test.js.map +1 -1
  170. package/src/agents/tools/executeScript/README.md +0 -94
  171. package/src/agents/tools/executeScript/definition.ts +0 -79
  172. package/src/agents/tools/executeScript/examples/dependency-injection-validation.ts +0 -272
  173. package/src/agents/tools/executeScript/examples/quick-test.ts +0 -74
  174. package/src/agents/tools/executeScript/examples/serialization-test.ts +0 -321
  175. package/src/agents/tools/executeScript/examples/test-runner.ts +0 -197
  176. package/src/agents/tools/executeScript/index.ts +0 -98
  177. package/src/services/script-execution/SandboxContext.ts +0 -282
  178. package/src/services/script-execution/ScriptExecutor.ts +0 -441
  179. package/src/services/script-execution/ScriptPolicy.ts +0 -194
  180. package/src/services/script-execution/ScriptTracer.ts +0 -249
  181. package/src/services/script-execution/types.ts +0 -134
  182. package/ts_build/src/agents/tools/executeScript/definition.d.ts +0 -2
  183. package/ts_build/src/agents/tools/executeScript/definition.js +0 -76
  184. package/ts_build/src/agents/tools/executeScript/definition.js.map +0 -1
  185. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.d.ts +0 -18
  186. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.js +0 -192
  187. package/ts_build/src/agents/tools/executeScript/examples/dependency-injection-validation.js.map +0 -1
  188. package/ts_build/src/agents/tools/executeScript/examples/quick-test.d.ts +0 -3
  189. package/ts_build/src/agents/tools/executeScript/examples/quick-test.js +0 -64
  190. package/ts_build/src/agents/tools/executeScript/examples/quick-test.js.map +0 -1
  191. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.d.ts +0 -15
  192. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.js +0 -266
  193. package/ts_build/src/agents/tools/executeScript/examples/serialization-test.js.map +0 -1
  194. package/ts_build/src/agents/tools/executeScript/examples/test-runner.d.ts +0 -4
  195. package/ts_build/src/agents/tools/executeScript/examples/test-runner.js +0 -208
  196. package/ts_build/src/agents/tools/executeScript/examples/test-runner.js.map +0 -1
  197. package/ts_build/src/agents/tools/executeScript/index.d.ts +0 -28
  198. package/ts_build/src/agents/tools/executeScript/index.js +0 -72
  199. package/ts_build/src/agents/tools/executeScript/index.js.map +0 -1
  200. package/ts_build/src/services/script-execution/SandboxContext.d.ts +0 -34
  201. package/ts_build/src/services/script-execution/SandboxContext.js +0 -189
  202. package/ts_build/src/services/script-execution/SandboxContext.js.map +0 -1
  203. package/ts_build/src/services/script-execution/ScriptExecutor.d.ts +0 -19
  204. package/ts_build/src/services/script-execution/ScriptExecutor.js +0 -269
  205. package/ts_build/src/services/script-execution/ScriptExecutor.js.map +0 -1
  206. package/ts_build/src/services/script-execution/ScriptPolicy.d.ts +0 -28
  207. package/ts_build/src/services/script-execution/ScriptPolicy.js +0 -115
  208. package/ts_build/src/services/script-execution/ScriptPolicy.js.map +0 -1
  209. package/ts_build/src/services/script-execution/ScriptTracer.d.ts +0 -19
  210. package/ts_build/src/services/script-execution/ScriptTracer.js +0 -186
  211. package/ts_build/src/services/script-execution/ScriptTracer.js.map +0 -1
  212. package/ts_build/src/services/script-execution/types.d.ts +0 -108
  213. package/ts_build/src/services/script-execution/types.js +0 -3
  214. package/ts_build/src/services/script-execution/types.js.map +0 -1
@@ -0,0 +1,246 @@
1
+ import { Command } from "commander";
2
+ import { readPromptFile } from "../ai";
3
+ import { AgentModule } from "../chat/modules/AgentModule";
4
+ import { AskModule } from "../chat/modules/AskModule";
5
+ import { SearchModule } from "../chat/modules/SearchModule";
6
+ import { SessionsModule } from "../chat/modules/SessionsModule";
7
+ import { SetupModule } from "../chat/modules/SetupModule";
8
+
9
+ async function readStdin(): Promise<string> {
10
+ return new Promise((resolve) => {
11
+ let data = "";
12
+ process.stdin.setEncoding("utf8");
13
+
14
+ if (process.stdin.isTTY) {
15
+ resolve("");
16
+ return;
17
+ }
18
+
19
+ process.stdin.on("readable", () => {
20
+ const chunk = process.stdin.read();
21
+ if (chunk !== null) data += chunk;
22
+ });
23
+
24
+ process.stdin.on("end", () => resolve(data.trim()));
25
+ });
26
+ }
27
+
28
+ export function addAgentCommand(program: Command, getChatService: () => any): void {
29
+ program
30
+ .command("agent")
31
+ .description("Spin up agents directly from CLI")
32
+ .option(
33
+ "--provider <provider>",
34
+ "AI provider (openai, anthropic, google, xai)"
35
+ )
36
+ .option("--model <model>", "Specific model for the provider")
37
+ .option("--agent-name <name>", "Which agent to use", "Patcher")
38
+ .option(
39
+ "--max-time-limit <minutes>",
40
+ "Time limit for agent execution (minutes)",
41
+ "30"
42
+ )
43
+ .option(
44
+ "--max-spend-limit <dollars>",
45
+ "Cost limit for agent execution (dollars)",
46
+ "10"
47
+ )
48
+ .option("--message-id <messageId>", "Knowhow message ID for task tracking")
49
+ .option("--sync-fs", "Enable filesystem-based synchronization")
50
+ .option(
51
+ "--task-id <taskId>",
52
+ "Pre-generated task ID (used with --sync-fs for predictable agent directory path)"
53
+ )
54
+ .option("--prompt-file <path>", "Custom prompt template file with {text}")
55
+ .option("--input <text>", "Task input (fallback to stdin if not provided)")
56
+ .option(
57
+ "--resume",
58
+ "Resume a previously started task using the --task-id (local FS or remote)"
59
+ )
60
+ .action(async (options) => {
61
+ try {
62
+ const { setupServices } = await import("./services");
63
+ await setupServices();
64
+ const chatService = getChatService();
65
+ const agentModule = new AgentModule();
66
+
67
+ if (options.resume) {
68
+ const threads = await agentModule.loadThreadsForTask(
69
+ options.taskId,
70
+ options.messageId
71
+ );
72
+ const resumeInput =
73
+ options.input || "Please continue from where you left off.";
74
+
75
+ await agentModule.initialize(chatService);
76
+ const { taskCompleted: resumed } =
77
+ await agentModule.resumeFromMessages({
78
+ agentName: options.agentName || "Patcher",
79
+ input: resumeInput,
80
+ threads,
81
+ messageId: options.messageId,
82
+ taskId: options.taskId,
83
+ });
84
+ await resumed;
85
+ return;
86
+ }
87
+
88
+ let input = options.input;
89
+
90
+ if (!input && !options.promptFile) {
91
+ input = await readStdin();
92
+ }
93
+
94
+ input = readPromptFile(options.promptFile, input);
95
+
96
+ if (!input) {
97
+ console.error(
98
+ "Error: No input provided. Use --input flag, pipe input via stdin, or provide --prompt-file."
99
+ );
100
+ process.exit(1);
101
+ }
102
+
103
+ await agentModule.initialize(chatService);
104
+ const { taskCompleted } = await agentModule.setupAgent({
105
+ ...options,
106
+ input,
107
+ maxTimeLimit: parseInt(options.maxTimeLimit, 10),
108
+ maxSpendLimit: parseFloat(options.maxSpendLimit),
109
+ run: true,
110
+ });
111
+ await taskCompleted;
112
+ } catch (error) {
113
+ console.error("Error running agent:", error);
114
+ process.exit(1);
115
+ }
116
+ });
117
+ }
118
+
119
+ export function addAskCommand(program: Command, getChatService: () => any, getConfig: () => any): void {
120
+ program
121
+ .command("ask")
122
+ .description("Direct AI questioning without agent overhead")
123
+ .option("--provider <provider>", "AI provider to use")
124
+ .option("--model <model>", "Specific model")
125
+ .option("--input <text>", "Question (fallback to stdin if not provided)")
126
+ .option("--prompt-file <path>", "Custom prompt template file")
127
+ .action(async (options) => {
128
+ try {
129
+ const { setupServices } = await import("./services");
130
+ await setupServices();
131
+ const chatService = getChatService();
132
+ const config = getConfig();
133
+ let input = options.input;
134
+
135
+ if (!input && !options.promptFile) {
136
+ input = await readStdin();
137
+ }
138
+
139
+ input = readPromptFile(options.promptFile, input);
140
+
141
+ if (!input) {
142
+ console.error(
143
+ "Error: No question provided. Use --input flag, pipe input via stdin, or provide --prompt-file."
144
+ );
145
+ process.exit(1);
146
+ }
147
+
148
+ const askModule = new AskModule();
149
+ await askModule.initialize(chatService);
150
+ await askModule.processAIQuery(input, {
151
+ plugins: config.plugins.enabled,
152
+ currentModel: options.model,
153
+ currentProvider: options.provider,
154
+ chatHistory: [],
155
+ });
156
+ } catch (error) {
157
+ console.error("Error asking AI:", error);
158
+ process.exit(1);
159
+ }
160
+ });
161
+ }
162
+
163
+ export function addSetupCommand(program: Command, getChatService: () => any): void {
164
+ program
165
+ .command("setup")
166
+ .description("Ask the agent to configure knowhow")
167
+ .action(async () => {
168
+ try {
169
+ const { setupServices } = await import("./services");
170
+ await setupServices();
171
+ const chatService = getChatService();
172
+ const agentModule = new AgentModule();
173
+ await agentModule.initialize(chatService);
174
+ const setupModule = new SetupModule(agentModule);
175
+ await setupModule.initialize(chatService);
176
+ await setupModule.handleSetupCommand([]);
177
+ } catch (error) {
178
+ console.error("Error running agent:", error);
179
+ process.exit(1);
180
+ }
181
+ });
182
+ }
183
+
184
+ export function addSearchCommand(program: Command): void {
185
+ program
186
+ .command("search")
187
+ .description("Search embeddings directly from CLI")
188
+ .option(
189
+ "--input <text>",
190
+ "Search query (fallback to stdin if not provided)"
191
+ )
192
+ .option(
193
+ "-e, --embedding <path>",
194
+ "Specific embedding path (default: all)",
195
+ "all"
196
+ )
197
+ .action(async (options) => {
198
+ try {
199
+ const { setupServices } = await import("./services");
200
+ await setupServices();
201
+ let input = options.input;
202
+ if (!input) {
203
+ input = await readStdin();
204
+ if (!input) {
205
+ console.error(
206
+ "Error: No search query provided. Use --input flag or pipe input via stdin."
207
+ );
208
+ process.exit(1);
209
+ }
210
+ }
211
+
212
+ await new SearchModule().searchEmbeddingsCLI(input, options.embedding);
213
+ } catch (error) {
214
+ console.error("Error searching embeddings:", error);
215
+ process.exit(1);
216
+ }
217
+ });
218
+ }
219
+
220
+ export function addSessionsCommand(program: Command, getChatService: () => any): void {
221
+ program
222
+ .command("sessions")
223
+ .description("Manage agent sessions from CLI")
224
+ .option(
225
+ "--all",
226
+ "Show all historical sessions (default: current process only)"
227
+ )
228
+ .option("--csv", "Output sessions as CSV")
229
+ .action(async (options) => {
230
+ try {
231
+ const chatService = getChatService();
232
+ const agentModule = new AgentModule();
233
+ await agentModule.initialize(chatService);
234
+ const sessionsModule = new SessionsModule(agentModule);
235
+ await sessionsModule.initialize(chatService);
236
+ await sessionsModule.logSessionTable(
237
+ options.all || false,
238
+ options.csv || false,
239
+ true
240
+ );
241
+ } catch (error) {
242
+ console.error("Error listing sessions:", error);
243
+ process.exit(1);
244
+ }
245
+ });
246
+ }
@@ -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
+ }