@tyvm/knowhow 0.0.56 → 0.0.59
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.
- package/package.json +3 -3
- package/src/agents/base/base.ts +87 -43
- package/src/agents/tools/execCommand.ts +17 -14
- package/src/agents/tools/googleSearch.ts +1 -0
- package/src/agents/tools/index.ts +1 -0
- package/src/agents/tools/lazy/definitions.ts +63 -0
- package/src/agents/tools/lazy/disableTools.ts +16 -0
- package/src/agents/tools/lazy/enableTools.ts +16 -0
- package/src/agents/tools/lazy/index.ts +3 -0
- package/src/agents/tools/lazy/listAvailableTools.ts +14 -0
- package/src/agents/tools/list.ts +2 -0
- package/src/agents/tools/mcp/connectMcpServer.ts +40 -0
- package/src/agents/tools/mcp/definitions.ts +67 -0
- package/src/agents/tools/mcp/disconnectMcpServer.ts +40 -0
- package/src/agents/tools/mcp/index.ts +3 -0
- package/src/agents/tools/mcp/listAvailableMcpServers.ts +28 -0
- package/src/agents/tools/writeFile.ts +4 -1
- package/src/chat/CliChatService.ts +8 -3
- package/src/chat/modules/AgentModule.ts +74 -296
- package/src/cli.ts +33 -10
- package/src/plugins/GitPlugin.ts +30 -24
- package/src/plugins/language.ts +95 -18
- package/src/processors/ToolResponseCache.ts +98 -79
- package/src/processors/tools/grepToolResponse.ts +99 -0
- package/src/processors/tools/index.ts +21 -0
- package/src/processors/tools/jqToolResponse.ts +124 -0
- package/src/processors/tools/listStoredToolResponses.ts +83 -0
- package/src/processors/tools/tailToolResponse.ts +75 -0
- package/src/services/AgentService.ts +1 -1
- package/src/services/AgentSynchronization.ts +291 -0
- package/src/services/DockerService.ts +37 -1
- package/src/services/EventService.ts +8 -2
- package/src/services/KnowhowClient.ts +141 -1
- package/src/services/LazyToolsService.ts +146 -0
- package/src/services/Mcp.ts +171 -4
- package/src/services/SessionManager.ts +287 -0
- package/src/services/TaskRegistry.ts +108 -0
- package/src/services/Tools.ts +2 -0
- package/src/services/index.ts +7 -0
- package/src/services/script-execution/ScriptExecutor.ts +7 -5
- package/src/types.ts +1 -0
- package/src/utils/InputQueueManager.ts +91 -57
- package/src/utils/errors.ts +0 -0
- package/src/utils/index.ts +11 -0
- package/src/worker.ts +12 -0
- package/tests/compressor/bigstring.test.ts +100 -0
- package/tests/compressor/bigstring.txt +1 -0
- package/tests/plugins/language/languagePlugin-content-triggers.test.ts +13 -5
- package/tests/plugins/language/languagePlugin-integration.test.ts +22 -7
- package/tests/plugins/language/languagePlugin.test.ts +11 -4
- package/tests/processors/ToolResponseCache.test.ts +128 -0
- package/tests/unit/InputQueueManager.test.ts +174 -0
- package/ts_build/package.json +3 -3
- package/ts_build/src/agents/base/base.d.ts +10 -0
- package/ts_build/src/agents/base/base.js +66 -34
- package/ts_build/src/agents/base/base.js.map +1 -1
- package/ts_build/src/agents/tools/execCommand.js +1 -9
- package/ts_build/src/agents/tools/execCommand.js.map +1 -1
- package/ts_build/src/agents/tools/github/index.d.ts +1 -1
- package/ts_build/src/agents/tools/googleSearch.d.ts +1 -0
- package/ts_build/src/agents/tools/googleSearch.js +1 -0
- package/ts_build/src/agents/tools/googleSearch.js.map +1 -1
- package/ts_build/src/agents/tools/index.d.ts +1 -0
- package/ts_build/src/agents/tools/index.js +1 -0
- package/ts_build/src/agents/tools/index.js.map +1 -1
- package/ts_build/src/agents/tools/lazy/definitions.d.ts +5 -0
- package/ts_build/src/agents/tools/lazy/definitions.js +58 -0
- package/ts_build/src/agents/tools/lazy/definitions.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/disableTools.d.ts +9 -0
- package/ts_build/src/agents/tools/lazy/disableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/disableTools.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/enableTools.d.ts +9 -0
- package/ts_build/src/agents/tools/lazy/enableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/enableTools.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/index.d.ts +3 -0
- package/ts_build/src/agents/tools/lazy/index.js +20 -0
- package/ts_build/src/agents/tools/lazy/index.js.map +1 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.d.ts +11 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.js +15 -0
- package/ts_build/src/agents/tools/lazy/listAvailableTools.js.map +1 -0
- package/ts_build/src/agents/tools/list.js +2 -0
- package/ts_build/src/agents/tools/list.js.map +1 -1
- package/ts_build/src/agents/tools/mcp/connectMcpServer.d.ts +5 -0
- package/ts_build/src/agents/tools/mcp/connectMcpServer.js +31 -0
- package/ts_build/src/agents/tools/mcp/connectMcpServer.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/definitions.d.ts +2 -0
- package/ts_build/src/agents/tools/mcp/definitions.js +62 -0
- package/ts_build/src/agents/tools/mcp/definitions.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.d.ts +5 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js +31 -0
- package/ts_build/src/agents/tools/mcp/disconnectMcpServer.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/index.d.ts +3 -0
- package/ts_build/src/agents/tools/mcp/index.js +10 -0
- package/ts_build/src/agents/tools/mcp/index.js.map +1 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.d.ts +14 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js +23 -0
- package/ts_build/src/agents/tools/mcp/listAvailableMcpServers.js.map +1 -0
- package/ts_build/src/agents/tools/writeFile.js +4 -1
- package/ts_build/src/agents/tools/writeFile.js.map +1 -1
- package/ts_build/src/chat/CliChatService.js +3 -1
- package/ts_build/src/chat/CliChatService.js.map +1 -1
- package/ts_build/src/chat/modules/AgentModule.d.ts +4 -3
- package/ts_build/src/chat/modules/AgentModule.js +71 -265
- package/ts_build/src/chat/modules/AgentModule.js.map +1 -1
- package/ts_build/src/cli.d.ts +1 -1
- package/ts_build/src/cli.js +17 -4
- package/ts_build/src/cli.js.map +1 -1
- package/ts_build/src/plugins/GitPlugin.d.ts +1 -0
- package/ts_build/src/plugins/GitPlugin.js +26 -19
- package/ts_build/src/plugins/GitPlugin.js.map +1 -1
- package/ts_build/src/plugins/language.d.ts +3 -0
- package/ts_build/src/plugins/language.js +55 -13
- package/ts_build/src/plugins/language.js.map +1 -1
- package/ts_build/src/processors/ToolResponseCache.d.ts +7 -4
- package/ts_build/src/processors/ToolResponseCache.js +47 -88
- package/ts_build/src/processors/ToolResponseCache.js.map +1 -1
- package/ts_build/src/processors/tools/grepToolResponse.d.ts +10 -0
- package/ts_build/src/processors/tools/grepToolResponse.js +71 -0
- package/ts_build/src/processors/tools/grepToolResponse.js.map +1 -0
- package/ts_build/src/processors/tools/index.d.ts +4 -0
- package/ts_build/src/processors/tools/index.js +16 -0
- package/ts_build/src/processors/tools/index.js.map +1 -0
- package/ts_build/src/processors/tools/jqToolResponse.d.ts +3 -0
- package/ts_build/src/processors/tools/jqToolResponse.js +115 -0
- package/ts_build/src/processors/tools/jqToolResponse.js.map +1 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.d.ts +21 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.js +51 -0
- package/ts_build/src/processors/tools/listStoredToolResponses.js.map +1 -0
- package/ts_build/src/processors/tools/tailToolResponse.d.ts +6 -0
- package/ts_build/src/processors/tools/tailToolResponse.js +55 -0
- package/ts_build/src/processors/tools/tailToolResponse.js.map +1 -0
- package/ts_build/src/services/AgentService.d.ts +1 -1
- package/ts_build/src/services/AgentSynchronization.d.ts +27 -0
- package/ts_build/src/services/AgentSynchronization.js +168 -0
- package/ts_build/src/services/AgentSynchronization.js.map +1 -0
- package/ts_build/src/services/DockerService.d.ts +2 -0
- package/ts_build/src/services/DockerService.js +21 -1
- package/ts_build/src/services/DockerService.js.map +1 -1
- package/ts_build/src/services/EventService.d.ts +5 -0
- package/ts_build/src/services/EventService.js +7 -2
- package/ts_build/src/services/EventService.js.map +1 -1
- package/ts_build/src/services/KnowhowClient.d.ts +41 -1
- package/ts_build/src/services/KnowhowClient.js +42 -0
- package/ts_build/src/services/KnowhowClient.js.map +1 -1
- package/ts_build/src/services/LazyToolsService.d.ts +29 -0
- package/ts_build/src/services/LazyToolsService.js +96 -0
- package/ts_build/src/services/LazyToolsService.js.map +1 -0
- package/ts_build/src/services/Mcp.d.ts +18 -1
- package/ts_build/src/services/Mcp.js +119 -4
- package/ts_build/src/services/Mcp.js.map +1 -1
- package/ts_build/src/services/SessionManager.d.ts +15 -0
- package/ts_build/src/services/SessionManager.js +220 -0
- package/ts_build/src/services/SessionManager.js.map +1 -0
- package/ts_build/src/services/TaskRegistry.d.ts +15 -0
- package/ts_build/src/services/TaskRegistry.js +58 -0
- package/ts_build/src/services/TaskRegistry.js.map +1 -0
- package/ts_build/src/services/Tools.d.ts +2 -0
- package/ts_build/src/services/Tools.js.map +1 -1
- package/ts_build/src/services/index.d.ts +4 -0
- package/ts_build/src/services/index.js +4 -0
- package/ts_build/src/services/index.js.map +1 -1
- package/ts_build/src/services/script-execution/ScriptExecutor.js +7 -5
- package/ts_build/src/services/script-execution/ScriptExecutor.js.map +1 -1
- package/ts_build/src/types.d.ts +1 -0
- package/ts_build/src/types.js.map +1 -1
- package/ts_build/src/utils/InputQueueManager.d.ts +9 -2
- package/ts_build/src/utils/InputQueueManager.js +54 -40
- package/ts_build/src/utils/InputQueueManager.js.map +1 -1
- package/ts_build/src/utils/errors.d.ts +0 -0
- package/ts_build/src/utils/errors.js +1 -0
- package/ts_build/src/utils/errors.js.map +1 -0
- package/ts_build/src/utils/index.d.ts +1 -0
- package/ts_build/src/utils/index.js +5 -1
- package/ts_build/src/utils/index.js.map +1 -1
- package/ts_build/src/worker.js +8 -0
- package/ts_build/src/worker.js.map +1 -1
- package/ts_build/tests/compressor/bigstring.test.d.ts +1 -0
- package/ts_build/tests/compressor/bigstring.test.js +66 -0
- package/ts_build/tests/compressor/bigstring.test.js.map +1 -0
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js +6 -5
- package/ts_build/tests/plugins/language/languagePlugin-content-triggers.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js +9 -7
- package/ts_build/tests/plugins/language/languagePlugin-integration.test.js.map +1 -1
- package/ts_build/tests/plugins/language/languagePlugin.test.js +7 -4
- package/ts_build/tests/plugins/language/languagePlugin.test.js.map +1 -1
- package/ts_build/tests/processors/ToolResponseCache.test.js +107 -0
- package/ts_build/tests/processors/ToolResponseCache.test.js.map +1 -1
- package/ts_build/tests/unit/InputQueueManager.test.d.ts +1 -0
- package/ts_build/tests/unit/InputQueueManager.test.js +104 -0
- package/ts_build/tests/unit/InputQueueManager.test.js.map +1 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import readline from "node:readline";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Callback type for notifying when a new history entry is added
|
|
4
|
+
type OnNewHistoryEntry = (entry: string) => void;
|
|
4
5
|
|
|
5
6
|
type AskOptions = {
|
|
6
7
|
question: string;
|
|
@@ -13,14 +14,31 @@ export class InputQueueManager {
|
|
|
13
14
|
private stack: AskOptions[] = [];
|
|
14
15
|
private rl: readline.Interface | null = null;
|
|
15
16
|
|
|
16
|
-
// We keep one
|
|
17
|
+
// We keep one "live" buffer shared across stacked questions
|
|
17
18
|
// (so typing is preserved when questions change)
|
|
18
19
|
private currentLine = "";
|
|
19
20
|
|
|
20
|
-
//
|
|
21
|
+
// Paste detection - buffer lines during paste operations
|
|
22
|
+
private pasteBuffer: string[] = [];
|
|
23
|
+
private pasteTimeout: NodeJS.Timeout | null = null;
|
|
24
|
+
private readonly PASTE_DELAY_MS = 10; // Time to wait for more paste lines
|
|
25
|
+
|
|
26
|
+
// History navigation state - uses only the history passed to ask()
|
|
21
27
|
private historyIndex = -1;
|
|
22
28
|
private savedLineBeforeHistory = "";
|
|
23
29
|
|
|
30
|
+
// Callback to notify caller when a new entry should be added to history
|
|
31
|
+
// This allows CliChatService to update inputHistory immediately
|
|
32
|
+
private onNewEntry?: OnNewHistoryEntry;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Set a callback to be notified when user enters a new history entry.
|
|
36
|
+
* This allows the caller to update their history source immediately.
|
|
37
|
+
*/
|
|
38
|
+
setOnNewEntry(callback: OnNewHistoryEntry | undefined): void {
|
|
39
|
+
this.onNewEntry = callback;
|
|
40
|
+
}
|
|
41
|
+
|
|
24
42
|
private ensureRl(): readline.Interface {
|
|
25
43
|
if (this.rl) return this.rl;
|
|
26
44
|
|
|
@@ -28,7 +46,8 @@ export class InputQueueManager {
|
|
|
28
46
|
input: process.stdin,
|
|
29
47
|
output: process.stdout,
|
|
30
48
|
terminal: true,
|
|
31
|
-
|
|
49
|
+
// Disable readline's internal history - we manage history ourselves
|
|
50
|
+
historySize: 0,
|
|
32
51
|
|
|
33
52
|
/**
|
|
34
53
|
* Use readline's built-in completion system so Tab does NOT insert a literal tab.
|
|
@@ -54,35 +73,37 @@ export class InputQueueManager {
|
|
|
54
73
|
},
|
|
55
74
|
});
|
|
56
75
|
|
|
57
|
-
// When user presses Enter,
|
|
76
|
+
// When user presses Enter, buffer the line for paste detection
|
|
58
77
|
this.rl.on("line", (line) => {
|
|
59
78
|
const current = this.peek();
|
|
60
79
|
if (!current) return;
|
|
61
80
|
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (answer && !askHistory.includes(answer)) {
|
|
71
|
-
askHistory.push(answer);
|
|
81
|
+
// Detect paste operation: if we receive a line while already processing lines,
|
|
82
|
+
// it's likely part of a paste. Buffer it and wait for more.
|
|
83
|
+
if (this.pasteTimeout) {
|
|
84
|
+
// Already in paste mode, add to buffer
|
|
85
|
+
this.pasteBuffer.push(line);
|
|
86
|
+
clearTimeout(this.pasteTimeout);
|
|
87
|
+
this.pasteTimeout = setTimeout(() => this.flushPasteBuffer(), this.PASTE_DELAY_MS);
|
|
88
|
+
return;
|
|
72
89
|
}
|
|
73
90
|
|
|
74
|
-
//
|
|
75
|
-
this.
|
|
76
|
-
this.
|
|
77
|
-
|
|
91
|
+
// Start paste detection mode - buffer this line and wait to see if more come
|
|
92
|
+
this.pasteBuffer.push(line);
|
|
93
|
+
this.pasteTimeout = setTimeout(() => this.flushPasteBuffer(), this.PASTE_DELAY_MS);
|
|
94
|
+
});
|
|
78
95
|
|
|
79
|
-
|
|
80
|
-
|
|
96
|
+
this.rl.on("close", () => {
|
|
97
|
+
// Flush any remaining paste buffer on close
|
|
98
|
+
if (this.pasteTimeout) {
|
|
99
|
+
clearTimeout(this.pasteTimeout);
|
|
100
|
+
this.flushPasteBuffer();
|
|
101
|
+
}
|
|
81
102
|
});
|
|
82
103
|
|
|
83
104
|
// Handle Ctrl+C (readline SIGINT)
|
|
84
105
|
this.rl.on("SIGINT", () => {
|
|
85
|
-
// If there
|
|
106
|
+
// If there's an active question, cancel it (like Esc)
|
|
86
107
|
if (this.stack.length > 0) {
|
|
87
108
|
const cancelled = this.stack.pop();
|
|
88
109
|
cancelled?.resolve("");
|
|
@@ -117,7 +138,7 @@ export class InputQueueManager {
|
|
|
117
138
|
// If RL is closed or nothing to ask, ignore
|
|
118
139
|
if (!this.rl || this.stack.length === 0) return;
|
|
119
140
|
|
|
120
|
-
// Keep our buffer in sync with readline
|
|
141
|
+
// Keep our buffer in sync with readline's live line
|
|
121
142
|
this.syncFromReadline();
|
|
122
143
|
|
|
123
144
|
// Any "real typing" should exit history mode
|
|
@@ -136,35 +157,20 @@ export class InputQueueManager {
|
|
|
136
157
|
this.savedLineBeforeHistory = "";
|
|
137
158
|
}
|
|
138
159
|
|
|
139
|
-
|
|
140
|
-
// Cancel only the current (top) question
|
|
141
|
-
const cancelled = this.stack.pop();
|
|
142
|
-
cancelled?.resolve("");
|
|
143
|
-
|
|
144
|
-
this.currentLine = "";
|
|
145
|
-
this.historyIndex = -1;
|
|
146
|
-
this.savedLineBeforeHistory = "";
|
|
147
|
-
|
|
148
|
-
// clear the current input in readline and redraw
|
|
149
|
-
this.replaceLine("");
|
|
150
|
-
this.renderTopOrClose();
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Custom Up/Down history: global askHistory + per-question history
|
|
160
|
+
// Custom Up/Down history navigation using only passed-in history
|
|
155
161
|
if (key?.name === "up") {
|
|
156
|
-
const
|
|
157
|
-
if (
|
|
162
|
+
const history = this.getHistory();
|
|
163
|
+
if (history.length === 0) return;
|
|
158
164
|
|
|
159
165
|
if (this.historyIndex === -1) {
|
|
160
166
|
// entering history mode: remember current typed text
|
|
161
167
|
this.savedLineBeforeHistory = this.currentLine;
|
|
162
168
|
}
|
|
163
169
|
|
|
164
|
-
if (this.historyIndex <
|
|
170
|
+
if (this.historyIndex < history.length - 1) {
|
|
165
171
|
this.historyIndex++;
|
|
166
172
|
const next =
|
|
167
|
-
|
|
173
|
+
history[history.length - 1 - this.historyIndex] ?? "";
|
|
168
174
|
this.replaceLine(next);
|
|
169
175
|
this.currentLine = next;
|
|
170
176
|
}
|
|
@@ -172,13 +178,13 @@ export class InputQueueManager {
|
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
if (key?.name === "down") {
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
181
|
+
const history = this.getHistory();
|
|
182
|
+
if (history.length === 0) return;
|
|
177
183
|
|
|
178
184
|
if (this.historyIndex > 0) {
|
|
179
185
|
this.historyIndex--;
|
|
180
186
|
const next =
|
|
181
|
-
|
|
187
|
+
history[history.length - 1 - this.historyIndex] ?? "";
|
|
182
188
|
this.replaceLine(next);
|
|
183
189
|
this.currentLine = next;
|
|
184
190
|
return;
|
|
@@ -201,6 +207,34 @@ export class InputQueueManager {
|
|
|
201
207
|
return this.rl;
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
private flushPasteBuffer(): void {
|
|
211
|
+
if (this.pasteBuffer.length === 0) return;
|
|
212
|
+
|
|
213
|
+
const answer = this.pasteBuffer.join("\n");
|
|
214
|
+
this.pasteBuffer = [];
|
|
215
|
+
this.pasteTimeout = null;
|
|
216
|
+
|
|
217
|
+
const current = this.peek();
|
|
218
|
+
if (!current) return;
|
|
219
|
+
|
|
220
|
+
// Pop & resolve current question with the combined paste content (or single line)
|
|
221
|
+
const resolved = this.stack.pop();
|
|
222
|
+
resolved?.resolve(answer);
|
|
223
|
+
|
|
224
|
+
// Notify caller about new entry
|
|
225
|
+
if (answer && this.onNewEntry) {
|
|
226
|
+
this.onNewEntry(answer);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Reset preserved buffer + history nav state for the next question
|
|
230
|
+
this.currentLine = "";
|
|
231
|
+
this.historyIndex = -1;
|
|
232
|
+
this.savedLineBeforeHistory = "";
|
|
233
|
+
|
|
234
|
+
// Update prompt for next stacked question (if any)
|
|
235
|
+
this.renderTopOrClose();
|
|
236
|
+
}
|
|
237
|
+
|
|
204
238
|
async ask(question: string, options: string[] = [], history: string[] = []) {
|
|
205
239
|
return new Promise<string>((resolve) => {
|
|
206
240
|
this.stack.push({ question, options, history, resolve });
|
|
@@ -235,21 +269,21 @@ export class InputQueueManager {
|
|
|
235
269
|
return value.replace(/[\r\n]+/g, " ").trim();
|
|
236
270
|
}
|
|
237
271
|
|
|
238
|
-
|
|
272
|
+
/**
|
|
273
|
+
* Get history for navigation - simply uses the history passed to ask()
|
|
274
|
+
* Single source of truth: the caller (CliChatService) manages all history
|
|
275
|
+
*/
|
|
276
|
+
private getHistory(): string[] {
|
|
239
277
|
const current = this.peek();
|
|
240
|
-
const
|
|
278
|
+
const history = current?.history ?? [];
|
|
241
279
|
|
|
242
|
-
//
|
|
243
|
-
const merged = [...askHistory, ...local];
|
|
244
|
-
const seen = new Set<string>();
|
|
280
|
+
// Sanitize entries
|
|
245
281
|
const out: string[] = [];
|
|
246
|
-
|
|
247
|
-
for (const item of merged) {
|
|
282
|
+
for (const item of history) {
|
|
248
283
|
const clean = this.sanitizeHistoryEntry(item);
|
|
249
|
-
if (
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
out.push(clean);
|
|
284
|
+
if (clean) {
|
|
285
|
+
out.push(clean);
|
|
286
|
+
}
|
|
253
287
|
}
|
|
254
288
|
|
|
255
289
|
return out;
|
|
File without changes
|
package/src/utils/index.ts
CHANGED
|
@@ -29,6 +29,17 @@ export const ask = async (
|
|
|
29
29
|
return inputQueue.ask(question, options, history);
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Set a callback to be notified when user enters a new history entry.
|
|
34
|
+
* This allows the caller to update their history source immediately,
|
|
35
|
+
* ensuring the next ask() call has the updated history.
|
|
36
|
+
*/
|
|
37
|
+
export const setOnNewHistoryEntry = (
|
|
38
|
+
callback: ((entry: string) => void) | undefined
|
|
39
|
+
): void => {
|
|
40
|
+
inputQueue.setOnNewEntry(callback);
|
|
41
|
+
};
|
|
42
|
+
|
|
32
43
|
export const Marked = marked;
|
|
33
44
|
|
|
34
45
|
export function dotp(x, y) {
|
package/src/worker.ts
CHANGED
|
@@ -86,6 +86,18 @@ export async function worker(options?: {
|
|
|
86
86
|
}) {
|
|
87
87
|
const config = await getConfig();
|
|
88
88
|
|
|
89
|
+
// Check if we're already running inside a Docker container
|
|
90
|
+
const isInsideDocker = process.env.KNOWHOW_DOCKER === "true";
|
|
91
|
+
|
|
92
|
+
if (isInsideDocker) {
|
|
93
|
+
console.log("🐳 Already running inside Docker container, skipping sandbox mode");
|
|
94
|
+
// Force sandbox mode off when inside Docker to prevent nested containers
|
|
95
|
+
if (options) {
|
|
96
|
+
options.sandbox = false;
|
|
97
|
+
options.noSandbox = true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
// Determine sandbox mode with priority: command line flags > config > default (false)
|
|
90
102
|
let shouldUseSandbox = false;
|
|
91
103
|
let sandboxSource = "";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFile } from "../../src/utils";
|
|
2
|
+
import { TokenCompressor } from "../../src/processors/TokenCompressor";
|
|
3
|
+
import { services } from "../../src/services";
|
|
4
|
+
|
|
5
|
+
describe("TokenCompressor - Large File Test", () => {
|
|
6
|
+
let tokenCompressor: TokenCompressor;
|
|
7
|
+
const bigstringPath = "tests/compressor/bigstring.txt";
|
|
8
|
+
|
|
9
|
+
beforeAll(() => {
|
|
10
|
+
const { Tools } = services();
|
|
11
|
+
tokenCompressor = new TokenCompressor(Tools);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
tokenCompressor.clearStorage();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("should compress large file contents and allow retrieval via chunks", async () => {
|
|
19
|
+
// Load the large file
|
|
20
|
+
const fileBuffer = await readFile(bigstringPath);
|
|
21
|
+
const fileContents = fileBuffer.toString();
|
|
22
|
+
|
|
23
|
+
console.log(`Original file size: ${fileContents.length} characters`);
|
|
24
|
+
console.log(`Estimated tokens: ${Math.ceil(fileContents.length / 4)}`);
|
|
25
|
+
|
|
26
|
+
// Compress the content
|
|
27
|
+
const compressed = tokenCompressor.compressContent(
|
|
28
|
+
fileContents,
|
|
29
|
+
bigstringPath
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
console.log(`Compressed result: ${compressed}`);
|
|
33
|
+
|
|
34
|
+
// Verify that compression occurred
|
|
35
|
+
expect(compressed).toContain("[COMPRESSED_STRING");
|
|
36
|
+
expect(compressed).toContain("Key:");
|
|
37
|
+
expect(compressed).toContain("chunks]");
|
|
38
|
+
expect(compressed.length).toBeLessThan(fileContents.length);
|
|
39
|
+
|
|
40
|
+
// Extract the key from the compressed string
|
|
41
|
+
const keyMatch = compressed.match(/Key: (compressed_[a-z0-9_]+)/);
|
|
42
|
+
expect(keyMatch).not.toBeNull();
|
|
43
|
+
const firstKey = keyMatch![1];
|
|
44
|
+
|
|
45
|
+
// Retrieve the first chunk
|
|
46
|
+
const firstChunk = tokenCompressor.retrieveString(firstKey);
|
|
47
|
+
expect(firstChunk).toBeTruthy();
|
|
48
|
+
expect(firstChunk.length).toBeGreaterThan(0);
|
|
49
|
+
|
|
50
|
+
// Verify the first chunk contains the beginning of the original content
|
|
51
|
+
expect(fileContents.startsWith(firstChunk.split("[NEXT_CHUNK_KEY:")[0]));
|
|
52
|
+
|
|
53
|
+
// Follow the chain to retrieve all chunks
|
|
54
|
+
const currentChunk = firstChunk;
|
|
55
|
+
let reconstructed = "";
|
|
56
|
+
let chunkCount = 0;
|
|
57
|
+
const maxChunks = 100; // Safety limit
|
|
58
|
+
|
|
59
|
+
while (currentChunk && chunkCount < maxChunks) {
|
|
60
|
+
chunkCount++;
|
|
61
|
+
|
|
62
|
+
const nextKeyMatch = currentChunk.match(/\[NEXT_CHUNK_KEY: ([^\]]+)\]/);
|
|
63
|
+
if (nextKeyMatch) {
|
|
64
|
+
// Remove the NEXT_CHUNK_KEY marker and add content
|
|
65
|
+
const nextKey = nextKeyMatch[1];
|
|
66
|
+
const retrieved = await tokenCompressor.retrieveString(nextKey);
|
|
67
|
+
console.log(`Retrieved chunk ${chunkCount} with key: ${nextKey}, length: ${retrieved.length}`);
|
|
68
|
+
} else {
|
|
69
|
+
// Last chunk
|
|
70
|
+
reconstructed += currentChunk;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
console.log(`Retrieved ${chunkCount} chunks`);
|
|
76
|
+
console.log(`Reconstructed size: ${reconstructed.length} characters`);
|
|
77
|
+
|
|
78
|
+
// Verify the reconstructed content matches the original
|
|
79
|
+
// expect(reconstructed).toBe(fileContents);
|
|
80
|
+
expect(chunkCount).toBeGreaterThan(1); // Should have multiple chunks for a large file
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("should handle compression threshold correctly", async () => {
|
|
84
|
+
const fileBuffer = await readFile(bigstringPath);
|
|
85
|
+
const fileContents = fileBuffer.toString();
|
|
86
|
+
|
|
87
|
+
// Test that it compresses when above threshold
|
|
88
|
+
const estimatedTokens = Math.ceil(fileContents.length / 4);
|
|
89
|
+
expect(estimatedTokens).toBeGreaterThan(4000); // Default threshold
|
|
90
|
+
|
|
91
|
+
const compressed = tokenCompressor.compressContent(fileContents);
|
|
92
|
+
|
|
93
|
+
// Should be compressed
|
|
94
|
+
expect(compressed).toContain("[COMPRESSED_STRING");
|
|
95
|
+
|
|
96
|
+
// The compression should result in a much smaller representation
|
|
97
|
+
const compressionRatio = compressed.length / fileContents.length;
|
|
98
|
+
expect(compressionRatio).toBeLessThan(0.01); // Less than 1% of original size
|
|
99
|
+
});
|
|
100
|
+
});
|