@travisennis/acai 0.0.5 → 0.0.6
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/README.md +4 -2
- package/dist/agent/index.d.ts +119 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +406 -0
- package/dist/agent/manual-loop.d.ts +41 -0
- package/dist/agent/manual-loop.d.ts.map +1 -0
- package/dist/agent/manual-loop.js +278 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +27 -33
- package/dist/commands/add-directory-command.d.ts +3 -0
- package/dist/commands/add-directory-command.d.ts.map +1 -0
- package/dist/commands/add-directory-command.js +85 -0
- package/dist/commands/application-log-command.d.ts.map +1 -1
- package/dist/commands/application-log-command.js +34 -0
- package/dist/commands/clear-command.d.ts.map +1 -1
- package/dist/commands/clear-command.js +8 -0
- package/dist/commands/compact-command.d.ts.map +1 -1
- package/dist/commands/compact-command.js +15 -2
- package/dist/commands/context-command.d.ts +3 -0
- package/dist/commands/context-command.d.ts.map +1 -0
- package/dist/commands/context-command.js +183 -0
- package/dist/commands/copy-command.d.ts.map +1 -1
- package/dist/commands/copy-command.js +28 -0
- package/dist/commands/edit-command.d.ts.map +1 -1
- package/dist/commands/edit-command.js +33 -0
- package/dist/commands/edit-prompt-command.d.ts.map +1 -1
- package/dist/commands/edit-prompt-command.js +28 -0
- package/dist/commands/exit-command.d.ts.map +1 -1
- package/dist/commands/exit-command.js +20 -0
- package/dist/commands/files-command.d.ts.map +1 -1
- package/dist/commands/files-command.js +57 -0
- package/dist/commands/generate-rules-command.d.ts.map +1 -1
- package/dist/commands/generate-rules-command.js +311 -1
- package/dist/commands/handoff-command.d.ts +3 -0
- package/dist/commands/handoff-command.d.ts.map +1 -0
- package/dist/commands/handoff-command.js +202 -0
- package/dist/commands/health-command.d.ts.map +1 -1
- package/dist/commands/health-command.js +119 -2
- package/dist/commands/help-command.d.ts.map +1 -1
- package/dist/commands/help-command.js +28 -0
- package/dist/commands/history-command.d.ts +3 -0
- package/dist/commands/history-command.d.ts.map +1 -0
- package/dist/commands/history-command.js +534 -0
- package/dist/commands/init-command.d.ts +1 -1
- package/dist/commands/init-command.d.ts.map +1 -1
- package/dist/commands/init-command.js +55 -18
- package/dist/commands/last-log-command.d.ts.map +1 -1
- package/dist/commands/last-log-command.js +27 -0
- package/dist/commands/list-directories-command.d.ts +3 -0
- package/dist/commands/list-directories-command.d.ts.map +1 -0
- package/dist/commands/list-directories-command.js +48 -0
- package/dist/commands/list-tools-command.d.ts.map +1 -1
- package/dist/commands/list-tools-command.js +66 -3
- package/dist/commands/manager.d.ts +15 -3
- package/dist/commands/manager.d.ts.map +1 -1
- package/dist/commands/manager.js +86 -26
- package/dist/commands/model-command.d.ts +22 -0
- package/dist/commands/model-command.d.ts.map +1 -1
- package/dist/commands/model-command.js +256 -0
- package/dist/commands/paste-command.d.ts.map +1 -1
- package/dist/commands/paste-command.js +92 -0
- package/dist/commands/pickup-command.d.ts +3 -0
- package/dist/commands/pickup-command.d.ts.map +1 -0
- package/dist/commands/pickup-command.js +161 -0
- package/dist/commands/prompt-command.d.ts +1 -1
- package/dist/commands/prompt-command.d.ts.map +1 -1
- package/dist/commands/prompt-command.js +117 -2
- package/dist/commands/remove-directory-command.d.ts +3 -0
- package/dist/commands/remove-directory-command.d.ts.map +1 -0
- package/dist/commands/remove-directory-command.js +87 -0
- package/dist/commands/reset-command.d.ts +1 -1
- package/dist/commands/reset-command.d.ts.map +1 -1
- package/dist/commands/reset-command.js +13 -2
- package/dist/commands/rules-command.d.ts.map +1 -1
- package/dist/commands/rules-command.js +65 -0
- package/dist/commands/save-command.d.ts.map +1 -1
- package/dist/commands/save-command.js +12 -0
- package/dist/commands/shell-command.d.ts.map +1 -1
- package/dist/commands/shell-command.js +68 -0
- package/dist/commands/types.d.ts +9 -4
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/usage-command.d.ts.map +1 -1
- package/dist/commands/usage-command.js +22 -0
- package/dist/config.d.ts +6 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -29
- package/dist/formatting.d.ts +108 -0
- package/dist/formatting.d.ts.map +1 -1
- package/dist/formatting.js +147 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +140 -38
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +47 -18
- package/dist/mentions.d.ts +2 -1
- package/dist/mentions.d.ts.map +1 -1
- package/dist/mentions.js +16 -1
- package/dist/messages.d.ts +8 -0
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +56 -19
- package/dist/middleware/cache.d.ts +3 -0
- package/dist/middleware/cache.d.ts.map +1 -0
- package/dist/middleware/cache.js +53 -0
- package/dist/middleware/index.d.ts +1 -0
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -0
- package/dist/models/ai-config.d.ts +4 -2
- package/dist/models/ai-config.d.ts.map +1 -1
- package/dist/models/ai-config.js +12 -2
- package/dist/models/anthropic-provider.d.ts.map +1 -1
- package/dist/models/anthropic-provider.js +3 -60
- package/dist/models/manager.d.ts +2 -1
- package/dist/models/manager.d.ts.map +1 -1
- package/dist/models/manager.js +26 -2
- package/dist/models/openrouter-provider.d.ts +7 -14
- package/dist/models/openrouter-provider.d.ts.map +1 -1
- package/dist/models/openrouter-provider.js +114 -169
- package/dist/models/providers.d.ts +1 -1
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/prompts.d.ts +1 -0
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +53 -4
- package/dist/repl/display-tool-messages.d.ts +1 -1
- package/dist/repl/display-tool-messages.d.ts.map +1 -1
- package/dist/repl/display-tool-messages.js +47 -44
- package/dist/repl/get-prompt-header.d.ts.map +1 -1
- package/dist/repl/get-prompt-header.js +1 -30
- package/dist/repl/project-status-line.d.ts +2 -0
- package/dist/repl/project-status-line.d.ts.map +1 -0
- package/dist/repl/project-status-line.js +31 -0
- package/dist/repl/prompt.d.ts +21 -0
- package/dist/repl/prompt.d.ts.map +1 -0
- package/dist/{repl-prompt.js → repl/prompt.js} +119 -22
- package/dist/repl/tool-call-repair.d.ts.map +1 -1
- package/dist/repl/tool-call-repair.js +8 -4
- package/dist/repl-new.d.ts +53 -0
- package/dist/repl-new.d.ts.map +1 -0
- package/dist/repl-new.js +374 -0
- package/dist/repl.d.ts +3 -5
- package/dist/repl.d.ts.map +1 -1
- package/dist/repl.js +74 -166
- package/dist/terminal/checkbox-prompt.d.ts.map +1 -1
- package/dist/terminal/checkbox-prompt.js +10 -4
- package/dist/terminal/index.d.ts +7 -0
- package/dist/terminal/index.d.ts.map +1 -1
- package/dist/terminal/index.js +94 -0
- package/dist/terminal/input-prompt.d.ts +2 -1
- package/dist/terminal/input-prompt.d.ts.map +1 -1
- package/dist/terminal/markdown.js +3 -0
- package/dist/terminal/search-prompt.d.ts.map +1 -1
- package/dist/terminal/search-prompt.js +11 -10
- package/dist/terminal/select-prompt.d.ts +2 -2
- package/dist/terminal/select-prompt.d.ts.map +1 -1
- package/dist/terminal/select-prompt.js +47 -39
- package/dist/tokens/threshold.d.ts +35 -0
- package/dist/tokens/threshold.d.ts.map +1 -0
- package/dist/tokens/threshold.js +85 -0
- package/dist/tools/advanced-edit-file.d.ts +69 -0
- package/dist/tools/advanced-edit-file.d.ts.map +1 -0
- package/dist/tools/advanced-edit-file.js +281 -0
- package/dist/tools/agent.d.ts +16 -5
- package/dist/tools/agent.d.ts.map +1 -1
- package/dist/tools/agent.js +71 -58
- package/dist/tools/bash-utils.d.ts +1 -1
- package/dist/tools/bash-utils.d.ts.map +1 -1
- package/dist/tools/bash-utils.js +14 -6
- package/dist/tools/bash.d.ts +21 -12
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +88 -135
- package/dist/tools/code-interpreter.d.ts +21 -9
- package/dist/tools/code-interpreter.d.ts.map +1 -1
- package/dist/tools/code-interpreter.js +138 -137
- package/dist/tools/delete-file.d.ts +17 -10
- package/dist/tools/delete-file.d.ts.map +1 -1
- package/dist/tools/delete-file.js +51 -95
- package/dist/tools/directory-tree.d.ts +17 -6
- package/dist/tools/directory-tree.d.ts.map +1 -1
- package/dist/tools/directory-tree.js +47 -49
- package/dist/tools/dynamic-tool-loader.d.ts +18 -8
- package/dist/tools/dynamic-tool-loader.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-loader.js +121 -129
- package/dist/tools/dynamic-tool-parser.d.ts +1 -0
- package/dist/tools/dynamic-tool-parser.d.ts.map +1 -1
- package/dist/tools/dynamic-tool-parser.js +1 -0
- package/dist/tools/edit-file.d.ts +35 -15
- package/dist/tools/edit-file.d.ts.map +1 -1
- package/dist/tools/edit-file.js +112 -112
- package/dist/tools/filesystem-utils.d.ts +2 -1
- package/dist/tools/filesystem-utils.d.ts.map +1 -1
- package/dist/tools/filesystem-utils.js +31 -17
- package/dist/tools/glob.d.ts +36 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +143 -0
- package/dist/tools/grep.d.ts +73 -12
- package/dist/tools/grep.d.ts.map +1 -1
- package/dist/tools/grep.js +413 -168
- package/dist/tools/index.d.ts +204 -124
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +242 -135
- package/dist/tools/llm-edit-fixer.d.ts +25 -0
- package/dist/tools/llm-edit-fixer.d.ts.map +1 -0
- package/dist/tools/llm-edit-fixer.js +150 -0
- package/dist/tools/move-file.d.ts +19 -7
- package/dist/tools/move-file.d.ts.map +1 -1
- package/dist/tools/move-file.js +40 -33
- package/dist/tools/read-file.d.ts +47 -9
- package/dist/tools/read-file.d.ts.map +1 -1
- package/dist/tools/read-file.js +74 -69
- package/dist/tools/read-multiple-files.d.ts +17 -6
- package/dist/tools/read-multiple-files.d.ts.map +1 -1
- package/dist/tools/read-multiple-files.js +76 -73
- package/dist/tools/save-file.d.ts +45 -12
- package/dist/tools/save-file.d.ts.map +1 -1
- package/dist/tools/save-file.js +58 -101
- package/dist/tools/think.d.ts +15 -7
- package/dist/tools/think.d.ts.map +1 -1
- package/dist/tools/think.js +30 -22
- package/dist/tools/types.d.ts +4 -10
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/types.js +9 -0
- package/dist/tools/utils.d.ts +14 -0
- package/dist/tools/utils.d.ts.map +1 -0
- package/dist/tools/utils.js +16 -0
- package/dist/tools/web-fetch.d.ts +11 -4
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +39 -38
- package/dist/tools/web-search.d.ts +15 -6
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +50 -32
- package/dist/tui/autocomplete.d.ts +44 -0
- package/dist/tui/autocomplete.d.ts.map +1 -0
- package/dist/tui/autocomplete.js +466 -0
- package/dist/tui/components/assistant-message.d.ts +18 -0
- package/dist/tui/components/assistant-message.d.ts.map +1 -0
- package/dist/tui/components/assistant-message.js +29 -0
- package/dist/tui/components/editor.d.ts +51 -0
- package/dist/tui/components/editor.d.ts.map +1 -0
- package/dist/tui/components/editor.js +758 -0
- package/dist/tui/components/footer.d.ts +24 -0
- package/dist/tui/components/footer.d.ts.map +1 -0
- package/dist/tui/components/footer.js +197 -0
- package/dist/tui/components/input.d.ts +14 -0
- package/dist/tui/components/input.d.ts.map +1 -0
- package/dist/tui/components/input.js +122 -0
- package/dist/tui/components/loader.d.ts +19 -0
- package/dist/tui/components/loader.d.ts.map +1 -0
- package/dist/tui/components/loader.js +45 -0
- package/dist/tui/components/markdown.d.ts +103 -0
- package/dist/tui/components/markdown.d.ts.map +1 -0
- package/dist/tui/components/markdown.js +533 -0
- package/dist/tui/components/modal.d.ts +40 -0
- package/dist/tui/components/modal.d.ts.map +1 -0
- package/dist/tui/components/modal.js +292 -0
- package/dist/tui/components/prompt-status.d.ts +16 -0
- package/dist/tui/components/prompt-status.d.ts.map +1 -0
- package/dist/tui/components/prompt-status.js +21 -0
- package/dist/tui/components/select-list.d.ts +22 -0
- package/dist/tui/components/select-list.d.ts.map +1 -0
- package/dist/tui/components/select-list.js +143 -0
- package/dist/tui/components/spacer.d.ts +16 -0
- package/dist/tui/components/spacer.d.ts.map +1 -0
- package/dist/tui/components/spacer.js +27 -0
- package/dist/tui/components/text.d.ts +26 -0
- package/dist/tui/components/text.d.ts.map +1 -0
- package/dist/tui/components/text.js +143 -0
- package/dist/tui/components/thinking-block.d.ts +14 -0
- package/dist/tui/components/thinking-block.d.ts.map +1 -0
- package/dist/tui/components/thinking-block.js +30 -0
- package/dist/tui/components/tool-execution.d.ts +17 -0
- package/dist/tui/components/tool-execution.d.ts.map +1 -0
- package/dist/tui/components/tool-execution.js +153 -0
- package/dist/tui/components/user-message.d.ts +9 -0
- package/dist/tui/components/user-message.d.ts.map +1 -0
- package/dist/tui/components/user-message.js +21 -0
- package/dist/tui/components/welcome.d.ts +6 -0
- package/dist/tui/components/welcome.d.ts.map +1 -0
- package/dist/tui/components/welcome.js +30 -0
- package/dist/tui/index.d.ts +14 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +18 -0
- package/dist/tui/terminal.d.ts +37 -0
- package/dist/tui/terminal.d.ts.map +1 -0
- package/dist/tui/terminal.js +104 -0
- package/dist/tui/tui.d.ts +67 -0
- package/dist/tui/tui.d.ts.map +1 -0
- package/dist/tui/tui.js +184 -0
- package/dist/tui/utils.d.ts +19 -0
- package/dist/tui/utils.d.ts.map +1 -0
- package/dist/tui/utils.js +31 -0
- package/dist/utils/generators.d.ts +3 -0
- package/dist/utils/generators.d.ts.map +1 -0
- package/dist/utils/generators.js +25 -0
- package/dist/utils/iterables.d.ts +2 -0
- package/dist/utils/iterables.d.ts.map +1 -0
- package/dist/utils/iterables.js +6 -0
- package/package.json +16 -16
- package/dist/conversation-analyzer.d.ts +0 -11
- package/dist/conversation-analyzer.d.ts.map +0 -1
- package/dist/conversation-analyzer.js +0 -88
- package/dist/repl-prompt.d.ts +0 -15
- package/dist/repl-prompt.d.ts.map +0 -1
- package/dist/tokens/manage-output.d.ts +0 -34
- package/dist/tokens/manage-output.d.ts.map +0 -1
- package/dist/tokens/manage-output.js +0 -44
- package/dist/tool-executor.d.ts +0 -28
- package/dist/tool-executor.d.ts.map +0 -1
- package/dist/tool-executor.js +0 -74
- package/dist/tools/file-editing-utils.d.ts +0 -2
- package/dist/tools/file-editing-utils.d.ts.map +0 -1
- package/dist/tools/file-editing-utils.js +0 -135
|
@@ -67,10 +67,14 @@ function findLastEnabledIndex(choices) {
|
|
|
67
67
|
}
|
|
68
68
|
return choices.length - 1;
|
|
69
69
|
}
|
|
70
|
-
function render(choices, pointerIndex, pageStart, pageSize, prompt, typed) {
|
|
70
|
+
function render(choices, pointerIndex, pageStart, pageSize, prompt, typed, totalChoices) {
|
|
71
71
|
const visible = choices.slice(pageStart, pageStart + pageSize);
|
|
72
72
|
const lines = [];
|
|
73
|
-
|
|
73
|
+
const searchInfo = typed ? ` (search: ${typed})` : "";
|
|
74
|
+
const filterInfo = typed && choices.length !== totalChoices
|
|
75
|
+
? ` [${choices.length}/${totalChoices}]`
|
|
76
|
+
: "";
|
|
77
|
+
lines.push(`${prompt}${searchInfo}${filterInfo}`);
|
|
74
78
|
for (let i = 0; i < visible.length; i++) {
|
|
75
79
|
const actualIndex = pageStart + i;
|
|
76
80
|
const ch = visible[i];
|
|
@@ -110,13 +114,20 @@ export async function select({ message = "Select", choices, initial = 0, pageSiz
|
|
|
110
114
|
if (!stdin.isTTY)
|
|
111
115
|
throw new Error("TTY required");
|
|
112
116
|
let searchBuffer = "";
|
|
113
|
-
|
|
114
|
-
|
|
117
|
+
const searchTimer = null;
|
|
118
|
+
let filteredChoices = [...normalized];
|
|
119
|
+
const clearSearchBuffer = () => {
|
|
120
|
+
searchBuffer = "";
|
|
121
|
+
filteredChoices = [...normalized];
|
|
122
|
+
// Reset pointer to first enabled choice when clearing search
|
|
123
|
+
pointer = findFirstEnabledIndex(filteredChoices);
|
|
124
|
+
pageStart = updatePageStart(pointer, pageSize, filteredChoices.length);
|
|
125
|
+
renderToScreen();
|
|
126
|
+
};
|
|
127
|
+
const resetSearchTimer = () => {
|
|
115
128
|
if (searchTimer)
|
|
116
129
|
clearTimeout(searchTimer);
|
|
117
|
-
|
|
118
|
-
searchBuffer = "";
|
|
119
|
-
}, 800);
|
|
130
|
+
// Don't auto-clear the search buffer - let user clear it explicitly
|
|
120
131
|
};
|
|
121
132
|
let previousOutputLines = 0;
|
|
122
133
|
function clearPreviousOutput(lineCount) {
|
|
@@ -129,30 +140,26 @@ export async function select({ message = "Select", choices, initial = 0, pageSiz
|
|
|
129
140
|
stdout.write(ANSI.moveToStart);
|
|
130
141
|
stdout.write(ANSI.clearFromCursor);
|
|
131
142
|
clearPreviousOutput(previousOutputLines);
|
|
132
|
-
const out = render(
|
|
143
|
+
const out = render(filteredChoices, pointer, pageStart, pageSize, message, searchBuffer, normalized.length);
|
|
133
144
|
previousOutputLines = out.split("\n").length;
|
|
134
145
|
stdout.write(`${out}\n`);
|
|
135
146
|
}
|
|
136
147
|
function move(delta) {
|
|
137
|
-
pointer = findNextEnabledIndex(
|
|
138
|
-
pageStart = updatePageStart(pointer, pageSize,
|
|
148
|
+
pointer = findNextEnabledIndex(filteredChoices, pointer, delta);
|
|
149
|
+
pageStart = updatePageStart(pointer, pageSize, filteredChoices.length);
|
|
139
150
|
renderToScreen();
|
|
140
151
|
}
|
|
141
|
-
function
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
145
|
-
const idx = (start + i) % normalized.length;
|
|
146
|
-
if (normalized[idx].disabled)
|
|
147
|
-
continue;
|
|
148
|
-
if (normalized[idx].name.toLowerCase().startsWith(lowerPref)) {
|
|
149
|
-
pointer = idx;
|
|
150
|
-
pageStart = updatePageStart(pointer, pageSize, normalized.length);
|
|
151
|
-
renderToScreen();
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
152
|
+
function filterChoices(search) {
|
|
153
|
+
if (!search) {
|
|
154
|
+
filteredChoices = [...normalized];
|
|
154
155
|
}
|
|
155
|
-
|
|
156
|
+
else {
|
|
157
|
+
const lowerSearch = search.toLowerCase();
|
|
158
|
+
filteredChoices = normalized.filter((choice) => choice.name.toLowerCase().includes(lowerSearch));
|
|
159
|
+
}
|
|
160
|
+
// Reset pointer to first enabled choice
|
|
161
|
+
pointer = findFirstEnabledIndex(filteredChoices);
|
|
162
|
+
pageStart = updatePageStart(pointer, pageSize, filteredChoices.length);
|
|
156
163
|
}
|
|
157
164
|
return new Promise((resolve, reject) => {
|
|
158
165
|
let resolved = false;
|
|
@@ -192,7 +199,7 @@ export async function select({ message = "Select", choices, initial = 0, pageSiz
|
|
|
192
199
|
}
|
|
193
200
|
if (key === Keys.enter || key === Keys.newline) {
|
|
194
201
|
cleanup();
|
|
195
|
-
const chosen =
|
|
202
|
+
const chosen = filteredChoices[pointer];
|
|
196
203
|
stdout.write("\n");
|
|
197
204
|
resolve(chosen.value);
|
|
198
205
|
return;
|
|
@@ -206,35 +213,34 @@ export async function select({ message = "Select", choices, initial = 0, pageSiz
|
|
|
206
213
|
return;
|
|
207
214
|
}
|
|
208
215
|
if (key === Keys.home || key === Keys.homeAlt) {
|
|
209
|
-
pointer = findFirstEnabledIndex(
|
|
210
|
-
pageStart = updatePageStart(pointer, pageSize,
|
|
216
|
+
pointer = findFirstEnabledIndex(filteredChoices);
|
|
217
|
+
pageStart = updatePageStart(pointer, pageSize, filteredChoices.length);
|
|
211
218
|
renderToScreen();
|
|
212
219
|
return;
|
|
213
220
|
}
|
|
214
221
|
if (key === Keys.end || key === Keys.endAlt) {
|
|
215
|
-
pointer = findLastEnabledIndex(
|
|
216
|
-
pageStart = updatePageStart(pointer, pageSize,
|
|
222
|
+
pointer = findLastEnabledIndex(filteredChoices);
|
|
223
|
+
pageStart = updatePageStart(pointer, pageSize, filteredChoices.length);
|
|
217
224
|
renderToScreen();
|
|
218
225
|
return;
|
|
219
226
|
}
|
|
220
227
|
if (key === Keys.backspace || key === Keys.backspaceAlt) {
|
|
221
228
|
if (searchBuffer.length > 0) {
|
|
222
229
|
searchBuffer = searchBuffer.slice(0, -1);
|
|
223
|
-
if (searchBuffer.length === 0)
|
|
224
|
-
|
|
225
|
-
|
|
230
|
+
if (searchBuffer.length === 0) {
|
|
231
|
+
clearSearchBuffer();
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
filterChoices(searchBuffer);
|
|
235
|
+
renderToScreen();
|
|
236
|
+
}
|
|
226
237
|
}
|
|
227
238
|
return;
|
|
228
239
|
}
|
|
229
240
|
if (key && key >= " " && key <= "~") {
|
|
230
241
|
searchBuffer += key;
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (!found) {
|
|
234
|
-
searchBuffer = key;
|
|
235
|
-
resetSearchBuffer();
|
|
236
|
-
jumpToIndexStartingWith(searchBuffer);
|
|
237
|
-
}
|
|
242
|
+
resetSearchTimer();
|
|
243
|
+
filterChoices(searchBuffer);
|
|
238
244
|
renderToScreen();
|
|
239
245
|
return;
|
|
240
246
|
}
|
|
@@ -244,6 +250,8 @@ export async function select({ message = "Select", choices, initial = 0, pageSiz
|
|
|
244
250
|
stdin.resume();
|
|
245
251
|
stdin.setEncoding("utf8");
|
|
246
252
|
stdout.write(ANSI.hideCursor);
|
|
253
|
+
// Reset previous output lines counter to ensure clean start
|
|
254
|
+
previousOutputLines = 0;
|
|
247
255
|
renderToScreen();
|
|
248
256
|
stdin.on("data", onData);
|
|
249
257
|
const exitHandler = () => {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { TokenCounter } from "./counter.ts";
|
|
2
|
+
export declare function clearTokenCache(): void;
|
|
3
|
+
/**
|
|
4
|
+
* Standardized result when token limit is exceeded
|
|
5
|
+
*/
|
|
6
|
+
interface TokenLimitResult {
|
|
7
|
+
content: string;
|
|
8
|
+
tokenCount: number;
|
|
9
|
+
truncated: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Generates a standardized token limit message for LLM tools
|
|
13
|
+
* @param toolName - Name of the tool (e.g., "ReadFile", "Bash")
|
|
14
|
+
* @param tokenCount - Actual token count of content
|
|
15
|
+
* @param maxTokens - Maximum allowed tokens
|
|
16
|
+
* @param additionalGuidance - Optional specific guidance for this tool
|
|
17
|
+
* @returns TokenLimitResult with message and metadata
|
|
18
|
+
*/
|
|
19
|
+
export declare function createTokenLimitResult(toolName: string, tokenCount: number, additionalGuidance?: string): TokenLimitResult;
|
|
20
|
+
/**
|
|
21
|
+
* Check if content should be truncated and return appropriate result
|
|
22
|
+
* @param content - The content to check
|
|
23
|
+
* @param tokenCounter - Token counter instance
|
|
24
|
+
* @param toolName - Name of the tool for messages
|
|
25
|
+
* @param additionalGuidance - Optional tool-specific guidance
|
|
26
|
+
* @param encoding - Optional encoding type for non-text file handling
|
|
27
|
+
* @returns Either the original content or token limit message
|
|
28
|
+
*/
|
|
29
|
+
export declare function manageTokenLimit<T extends string>(content: T, tokenCounter: TokenCounter, toolName: string, additionalGuidance?: string, encoding?: string): Promise<{
|
|
30
|
+
content: T | string;
|
|
31
|
+
tokenCount: number;
|
|
32
|
+
truncated: boolean;
|
|
33
|
+
}>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=threshold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threshold.d.ts","sourceRoot":"","sources":["../../source/tokens/threshold.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAQjD,wBAAgB,eAAe,SAG9B;AAyBD;;GAEG;AACH,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,kBAAkB,CAAC,EAAE,MAAM,GAC1B,gBAAgB,CAgBlB;AAED;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EACrD,OAAO,EAAE,CAAC,EACV,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,MAAM,EAChB,kBAAkB,CAAC,EAAE,MAAM,EAC3B,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC,GAAG,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAAC,CA+B1E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
// Cache for maxTokens config to avoid repeated async calls
|
|
3
|
+
let maxTokensCache = null;
|
|
4
|
+
let cacheExpiry = 0;
|
|
5
|
+
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
|
6
|
+
// Export cache management for testing
|
|
7
|
+
export function clearTokenCache() {
|
|
8
|
+
maxTokensCache = null;
|
|
9
|
+
cacheExpiry = 0;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Get maxTokens from config with caching
|
|
13
|
+
*/
|
|
14
|
+
async function getMaxTokens() {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
if (maxTokensCache !== null && now < cacheExpiry) {
|
|
17
|
+
return maxTokensCache;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const projectConfig = await config.readProjectConfig();
|
|
21
|
+
maxTokensCache = projectConfig.tools.maxTokens;
|
|
22
|
+
cacheExpiry = now + CACHE_DURATION;
|
|
23
|
+
return maxTokensCache;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
console.info("Failed to read config for maxTokens, using default:", error);
|
|
27
|
+
maxTokensCache = 8000; // Default fallback
|
|
28
|
+
cacheExpiry = now + CACHE_DURATION;
|
|
29
|
+
return maxTokensCache;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generates a standardized token limit message for LLM tools
|
|
34
|
+
* @param toolName - Name of the tool (e.g., "ReadFile", "Bash")
|
|
35
|
+
* @param tokenCount - Actual token count of content
|
|
36
|
+
* @param maxTokens - Maximum allowed tokens
|
|
37
|
+
* @param additionalGuidance - Optional specific guidance for this tool
|
|
38
|
+
* @returns TokenLimitResult with message and metadata
|
|
39
|
+
*/
|
|
40
|
+
export function createTokenLimitResult(toolName, tokenCount, additionalGuidance) {
|
|
41
|
+
const truncated = true;
|
|
42
|
+
const baseMessage = `${toolName}: Content (${tokenCount} tokens) exceeds maximum allowed tokens`;
|
|
43
|
+
const guidance = additionalGuidance ??
|
|
44
|
+
"Please adjust your parameters to reduce content size";
|
|
45
|
+
const content = `${baseMessage}. ${guidance}`;
|
|
46
|
+
return {
|
|
47
|
+
content,
|
|
48
|
+
tokenCount,
|
|
49
|
+
truncated,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if content should be truncated and return appropriate result
|
|
54
|
+
* @param content - The content to check
|
|
55
|
+
* @param tokenCounter - Token counter instance
|
|
56
|
+
* @param toolName - Name of the tool for messages
|
|
57
|
+
* @param additionalGuidance - Optional tool-specific guidance
|
|
58
|
+
* @param encoding - Optional encoding type for non-text file handling
|
|
59
|
+
* @returns Either the original content or token limit message
|
|
60
|
+
*/
|
|
61
|
+
export async function manageTokenLimit(content, tokenCounter, toolName, additionalGuidance, encoding) {
|
|
62
|
+
// For non-text files, return content directly without token management
|
|
63
|
+
if (encoding && !encoding.startsWith("utf")) {
|
|
64
|
+
return { content, tokenCount: 0, truncated: false };
|
|
65
|
+
}
|
|
66
|
+
let tokenCount = 0;
|
|
67
|
+
try {
|
|
68
|
+
tokenCount = tokenCounter.count(content);
|
|
69
|
+
}
|
|
70
|
+
catch (tokenError) {
|
|
71
|
+
console.info("Error calculating token count:", tokenError);
|
|
72
|
+
// Return content if token counting fails
|
|
73
|
+
return { content, tokenCount: 0, truncated: false };
|
|
74
|
+
}
|
|
75
|
+
const maxTokens = await getMaxTokens();
|
|
76
|
+
if (tokenCount <= maxTokens) {
|
|
77
|
+
return { content, tokenCount, truncated: false };
|
|
78
|
+
}
|
|
79
|
+
const limitResult = createTokenLimitResult(toolName, tokenCount, additionalGuidance);
|
|
80
|
+
return {
|
|
81
|
+
content: limitResult.content,
|
|
82
|
+
tokenCount,
|
|
83
|
+
truncated: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ToolCallOptions } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { ToolResult } from "./types.ts";
|
|
4
|
+
export declare const AdvancedEditFileTool: {
|
|
5
|
+
name: "advancedEditFile";
|
|
6
|
+
};
|
|
7
|
+
declare const inputSchema: z.ZodObject<{
|
|
8
|
+
path: z.ZodString;
|
|
9
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
10
|
+
exact: "exact";
|
|
11
|
+
regex: "regex";
|
|
12
|
+
ast: "ast";
|
|
13
|
+
}>>;
|
|
14
|
+
operations: z.ZodArray<z.ZodObject<{
|
|
15
|
+
type: z.ZodEnum<{
|
|
16
|
+
replace: "replace";
|
|
17
|
+
"insert-before": "insert-before";
|
|
18
|
+
"insert-after": "insert-after";
|
|
19
|
+
delete: "delete";
|
|
20
|
+
}>;
|
|
21
|
+
pattern: z.ZodString;
|
|
22
|
+
replacement: z.ZodOptional<z.ZodString>;
|
|
23
|
+
flags: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
astPattern: z.ZodOptional<z.ZodString>;
|
|
26
|
+
astReplacement: z.ZodOptional<z.ZodString>;
|
|
27
|
+
dryRun: z.ZodDefault<z.ZodBoolean>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
type AdvancedEditFileInputSchema = z.infer<typeof inputSchema>;
|
|
30
|
+
interface FileOperation {
|
|
31
|
+
type: "replace" | "insert-before" | "insert-after" | "delete";
|
|
32
|
+
pattern: string;
|
|
33
|
+
replacement?: string;
|
|
34
|
+
flags?: string;
|
|
35
|
+
}
|
|
36
|
+
export declare const createAdvancedEditFileTool: ({ workingDir, allowedDirs, }: {
|
|
37
|
+
workingDir: string;
|
|
38
|
+
allowedDirs?: string[];
|
|
39
|
+
}) => Promise<{
|
|
40
|
+
toolDef: {
|
|
41
|
+
description: string;
|
|
42
|
+
inputSchema: z.ZodObject<{
|
|
43
|
+
path: z.ZodString;
|
|
44
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
45
|
+
exact: "exact";
|
|
46
|
+
regex: "regex";
|
|
47
|
+
ast: "ast";
|
|
48
|
+
}>>;
|
|
49
|
+
operations: z.ZodArray<z.ZodObject<{
|
|
50
|
+
type: z.ZodEnum<{
|
|
51
|
+
replace: "replace";
|
|
52
|
+
"insert-before": "insert-before";
|
|
53
|
+
"insert-after": "insert-after";
|
|
54
|
+
delete: "delete";
|
|
55
|
+
}>;
|
|
56
|
+
pattern: z.ZodString;
|
|
57
|
+
replacement: z.ZodOptional<z.ZodString>;
|
|
58
|
+
flags: z.ZodOptional<z.ZodString>;
|
|
59
|
+
}, z.core.$strip>>;
|
|
60
|
+
astPattern: z.ZodOptional<z.ZodString>;
|
|
61
|
+
astReplacement: z.ZodOptional<z.ZodString>;
|
|
62
|
+
dryRun: z.ZodDefault<z.ZodBoolean>;
|
|
63
|
+
}, z.core.$strip>;
|
|
64
|
+
};
|
|
65
|
+
execute({ path, mode, operations, astPattern, astReplacement, dryRun, }: AdvancedEditFileInputSchema, { toolCallId, abortSignal }: ToolCallOptions): AsyncGenerator<ToolResult>;
|
|
66
|
+
}>;
|
|
67
|
+
export declare function applyAdvancedFileEdits(filePath: string, mode: "exact" | "regex" | "ast", operations: FileOperation[], astPattern?: string, astReplacement?: string, dryRun?: boolean, abortSignal?: AbortSignal): Promise<string>;
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=advanced-edit-file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"advanced-edit-file.d.ts","sourceRoot":"","sources":["../../source/tools/advanced-edit-file.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,oBAAoB;;CAEhC,CAAC;AAEF,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;iBAuCf,CAAC;AAEH,KAAK,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAE/D,UAAU,aAAa;IACrB,IAAI,EAAE,SAAS,GAAG,eAAe,GAAG,cAAc,GAAG,QAAQ,CAAC;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,0BAA0B,GAAU,8BAG9C;IACD,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;;;;;;;;;;;;;;;;;;;;;;;;;;6EAiBQ,2BAA2B,+BACD,eAAe,GAC3C,cAAc,CAAC,UAAU,CAAC;EAgDhC,CAAC;AA2MF,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,GAAG,OAAO,GAAG,KAAK,EAC/B,UAAU,EAAE,aAAa,EAAE,EAC3B,UAAU,CAAC,EAAE,MAAM,EACnB,cAAc,CAAC,EAAE,MAAM,EACvB,MAAM,UAAQ,EACd,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,MAAM,CAAC,CAyEjB"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { createTwoFilesPatch } from "diff";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import style from "../terminal/style.js";
|
|
6
|
+
import { joinWorkingDir, validatePath } from "./filesystem-utils.js";
|
|
7
|
+
export const AdvancedEditFileTool = {
|
|
8
|
+
name: "advancedEditFile",
|
|
9
|
+
};
|
|
10
|
+
const inputSchema = z.object({
|
|
11
|
+
path: z.string().describe("The path of the file to edit."),
|
|
12
|
+
mode: z
|
|
13
|
+
.enum(["exact", "regex", "ast"])
|
|
14
|
+
.default("exact")
|
|
15
|
+
.describe("Editing mode: exact (literal text), regex (pattern matching), or ast (AST-aware)"),
|
|
16
|
+
operations: z.array(z.object({
|
|
17
|
+
type: z
|
|
18
|
+
.enum(["replace", "insert-before", "insert-after", "delete"])
|
|
19
|
+
.describe("Type of operation to perform"),
|
|
20
|
+
pattern: z
|
|
21
|
+
.string()
|
|
22
|
+
.describe("Pattern to match (text, regex, or AST pattern depending on mode)"),
|
|
23
|
+
replacement: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Replacement text (required for replace operations)"),
|
|
27
|
+
flags: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Regex flags for regex mode (e.g., 'g', 'i', 'm')"),
|
|
31
|
+
})),
|
|
32
|
+
astPattern: z
|
|
33
|
+
.string()
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("AST-grep search pattern for AST mode (e.g., 'var $V = $VAL')"),
|
|
36
|
+
astReplacement: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("AST-grep replacement pattern for AST mode (e.g., 'let $V = $VAL')"),
|
|
40
|
+
dryRun: z.boolean().default(false).describe("Show changes without writing"),
|
|
41
|
+
});
|
|
42
|
+
export const createAdvancedEditFileTool = async ({ workingDir, allowedDirs, }) => {
|
|
43
|
+
const allowedDirectory = allowedDirs ?? [workingDir];
|
|
44
|
+
return {
|
|
45
|
+
toolDef: {
|
|
46
|
+
description: "Advanced file editing with multiple modes: exact text matching, regex pattern matching, and AST-aware editing. " +
|
|
47
|
+
"Supports replace, insert-before, insert-after, and delete operations. AST mode requires ast-grep to be installed.",
|
|
48
|
+
inputSchema,
|
|
49
|
+
},
|
|
50
|
+
async *execute({ path, mode, operations, astPattern, astReplacement, dryRun, }, { toolCallId, abortSignal }) {
|
|
51
|
+
try {
|
|
52
|
+
if (abortSignal?.aborted) {
|
|
53
|
+
throw new Error("File editing aborted");
|
|
54
|
+
}
|
|
55
|
+
yield {
|
|
56
|
+
name: AdvancedEditFileTool.name,
|
|
57
|
+
id: toolCallId,
|
|
58
|
+
event: "tool-init",
|
|
59
|
+
data: `${style.cyan(path)} (mode: ${mode})`,
|
|
60
|
+
};
|
|
61
|
+
const validPath = await validatePath(joinWorkingDir(path, workingDir), allowedDirectory, { abortSignal });
|
|
62
|
+
const result = await applyAdvancedFileEdits(validPath, mode, operations, astPattern, astReplacement, dryRun, abortSignal);
|
|
63
|
+
yield {
|
|
64
|
+
name: AdvancedEditFileTool.name,
|
|
65
|
+
id: toolCallId,
|
|
66
|
+
event: "tool-completion",
|
|
67
|
+
data: `Applied ${operations.length} edits`,
|
|
68
|
+
};
|
|
69
|
+
yield result;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
yield {
|
|
73
|
+
name: AdvancedEditFileTool.name,
|
|
74
|
+
event: "tool-error",
|
|
75
|
+
id: toolCallId,
|
|
76
|
+
data: error.message,
|
|
77
|
+
};
|
|
78
|
+
yield `Failed to edit file: ${error.message}`;
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
// file editing and diffing utilities
|
|
84
|
+
function normalizeLineEndings(text) {
|
|
85
|
+
return text.replace(/\r\n/g, "\n");
|
|
86
|
+
}
|
|
87
|
+
function createUnifiedDiff(originalContent, newContent, filepath = "file") {
|
|
88
|
+
// Ensure consistent line endings for diff
|
|
89
|
+
const normalizedOriginal = normalizeLineEndings(originalContent);
|
|
90
|
+
const normalizedNew = normalizeLineEndings(newContent);
|
|
91
|
+
return createTwoFilesPatch(filepath, filepath, normalizedOriginal, normalizedNew, "original", "modified");
|
|
92
|
+
}
|
|
93
|
+
function applyExactModeEdits(content, operations) {
|
|
94
|
+
let modifiedContent = content;
|
|
95
|
+
for (const op of operations) {
|
|
96
|
+
switch (op.type) {
|
|
97
|
+
case "replace": {
|
|
98
|
+
if (!op.replacement) {
|
|
99
|
+
throw new Error("Replacement text required for replace operation");
|
|
100
|
+
}
|
|
101
|
+
// Exact text replacement (global)
|
|
102
|
+
let currentIndex = 0;
|
|
103
|
+
let matchCount = 0;
|
|
104
|
+
while (currentIndex < modifiedContent.length) {
|
|
105
|
+
const matchIndex = modifiedContent.indexOf(op.pattern, currentIndex);
|
|
106
|
+
if (matchIndex === -1) {
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
matchCount++;
|
|
110
|
+
modifiedContent =
|
|
111
|
+
modifiedContent.slice(0, matchIndex) +
|
|
112
|
+
op.replacement +
|
|
113
|
+
modifiedContent.slice(matchIndex + op.pattern.length);
|
|
114
|
+
currentIndex = matchIndex + op.replacement.length;
|
|
115
|
+
}
|
|
116
|
+
if (matchCount === 0) {
|
|
117
|
+
throw new Error(`Pattern not found in content: ${op.pattern}`);
|
|
118
|
+
}
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case "insert-before": {
|
|
122
|
+
if (!op.replacement) {
|
|
123
|
+
throw new Error("Replacement text required for insert-before operation");
|
|
124
|
+
}
|
|
125
|
+
const beforeIndex = modifiedContent.indexOf(op.pattern);
|
|
126
|
+
if (beforeIndex === -1) {
|
|
127
|
+
throw new Error(`Pattern not found for insert-before: ${op.pattern}`);
|
|
128
|
+
}
|
|
129
|
+
modifiedContent =
|
|
130
|
+
modifiedContent.slice(0, beforeIndex) +
|
|
131
|
+
op.replacement +
|
|
132
|
+
"\n" +
|
|
133
|
+
modifiedContent.slice(beforeIndex);
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
case "insert-after": {
|
|
137
|
+
if (!op.replacement) {
|
|
138
|
+
throw new Error("Replacement text required for insert-after operation");
|
|
139
|
+
}
|
|
140
|
+
const afterIndex = modifiedContent.indexOf(op.pattern);
|
|
141
|
+
if (afterIndex === -1) {
|
|
142
|
+
throw new Error(`Pattern not found for insert-after: ${op.pattern}`);
|
|
143
|
+
}
|
|
144
|
+
const insertPosition = afterIndex + op.pattern.length;
|
|
145
|
+
modifiedContent =
|
|
146
|
+
modifiedContent.slice(0, insertPosition) +
|
|
147
|
+
"\n" +
|
|
148
|
+
op.replacement +
|
|
149
|
+
modifiedContent.slice(insertPosition);
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
case "delete": {
|
|
153
|
+
// For delete operations, use line-based approach to handle newlines properly
|
|
154
|
+
const lines = modifiedContent.split("\n");
|
|
155
|
+
const filteredLines = lines.filter((line) => !line.includes(op.pattern));
|
|
156
|
+
if (filteredLines.length === lines.length) {
|
|
157
|
+
throw new Error(`Pattern not found for delete: ${op.pattern}`);
|
|
158
|
+
}
|
|
159
|
+
modifiedContent = filteredLines.join("\n");
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return modifiedContent;
|
|
165
|
+
}
|
|
166
|
+
function applyRegexModeEdits(content, operations) {
|
|
167
|
+
let modifiedContent = content;
|
|
168
|
+
for (const op of operations) {
|
|
169
|
+
const flags = op.flags || "g";
|
|
170
|
+
const regex = new RegExp(op.pattern, flags);
|
|
171
|
+
switch (op.type) {
|
|
172
|
+
case "replace":
|
|
173
|
+
if (!op.replacement) {
|
|
174
|
+
throw new Error("Replacement text required for replace operation");
|
|
175
|
+
}
|
|
176
|
+
modifiedContent = modifiedContent.replace(regex, op.replacement);
|
|
177
|
+
break;
|
|
178
|
+
case "insert-before":
|
|
179
|
+
if (!op.replacement) {
|
|
180
|
+
throw new Error("Replacement text required for insert-before operation");
|
|
181
|
+
}
|
|
182
|
+
modifiedContent = modifiedContent.replace(regex, `${op.replacement}\n$&`);
|
|
183
|
+
break;
|
|
184
|
+
case "insert-after":
|
|
185
|
+
if (!op.replacement) {
|
|
186
|
+
throw new Error("Replacement text required for insert-after operation");
|
|
187
|
+
}
|
|
188
|
+
modifiedContent = modifiedContent.replace(regex, `$&\n${op.replacement}`);
|
|
189
|
+
break;
|
|
190
|
+
case "delete":
|
|
191
|
+
modifiedContent = modifiedContent.replace(regex, "");
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return modifiedContent;
|
|
196
|
+
}
|
|
197
|
+
function applyAstModeEdits(filePath, astPattern, astReplacement, dryRun) {
|
|
198
|
+
if (!astPattern || !astReplacement) {
|
|
199
|
+
throw new Error("AST mode requires both astPattern and astReplacement");
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const cmd = [
|
|
203
|
+
"ast-grep",
|
|
204
|
+
"--pattern",
|
|
205
|
+
`"${astPattern}"`,
|
|
206
|
+
"--rewrite",
|
|
207
|
+
`"${astReplacement}"`,
|
|
208
|
+
dryRun ? "--dry-run" : "--write",
|
|
209
|
+
filePath,
|
|
210
|
+
].join(" ");
|
|
211
|
+
if (dryRun) {
|
|
212
|
+
const output = execSync(cmd, { encoding: "utf-8" });
|
|
213
|
+
return `AST edit preview:\n${output}`;
|
|
214
|
+
}
|
|
215
|
+
execSync(cmd, { stdio: "inherit" });
|
|
216
|
+
return `AST edit applied to ${filePath}`;
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
throw new Error(`AST edit failed: ${err.message}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export async function applyAdvancedFileEdits(filePath, mode, operations, astPattern, astReplacement, dryRun = false, abortSignal) {
|
|
223
|
+
if (abortSignal?.aborted) {
|
|
224
|
+
throw new Error("File edit operation aborted");
|
|
225
|
+
}
|
|
226
|
+
// Read file content literally with signal
|
|
227
|
+
const originalContent = await readFile(filePath, {
|
|
228
|
+
encoding: "utf-8",
|
|
229
|
+
signal: abortSignal,
|
|
230
|
+
});
|
|
231
|
+
let modifiedContent = originalContent;
|
|
232
|
+
let resultMessage = "";
|
|
233
|
+
if (mode === "ast") {
|
|
234
|
+
// AST mode uses external ast-grep tool
|
|
235
|
+
if (!astPattern || !astReplacement) {
|
|
236
|
+
throw new Error("AST mode requires both astPattern and astReplacement");
|
|
237
|
+
}
|
|
238
|
+
resultMessage = applyAstModeEdits(filePath, astPattern, astReplacement, dryRun);
|
|
239
|
+
if (dryRun) {
|
|
240
|
+
return resultMessage;
|
|
241
|
+
}
|
|
242
|
+
// For actual AST edits, read the modified content back
|
|
243
|
+
modifiedContent = await readFile(filePath, {
|
|
244
|
+
encoding: "utf-8",
|
|
245
|
+
signal: abortSignal,
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// Text-based modes (exact and regex)
|
|
250
|
+
if (operations.length === 0) {
|
|
251
|
+
throw new Error("No operations specified for text-based editing mode");
|
|
252
|
+
}
|
|
253
|
+
switch (mode) {
|
|
254
|
+
case "exact":
|
|
255
|
+
modifiedContent = applyExactModeEdits(originalContent, operations);
|
|
256
|
+
break;
|
|
257
|
+
case "regex":
|
|
258
|
+
modifiedContent = applyRegexModeEdits(originalContent, operations);
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
// Create unified diff
|
|
262
|
+
const diff = createUnifiedDiff(originalContent, modifiedContent, filePath);
|
|
263
|
+
// Format diff with appropriate number of backticks
|
|
264
|
+
let numBackticks = 3;
|
|
265
|
+
while (diff.includes("`".repeat(numBackticks))) {
|
|
266
|
+
numBackticks++;
|
|
267
|
+
}
|
|
268
|
+
resultMessage = `${"`".repeat(numBackticks)}diff\n${diff}${"`".repeat(numBackticks)}\n\n`;
|
|
269
|
+
if (!dryRun) {
|
|
270
|
+
if (abortSignal?.aborted) {
|
|
271
|
+
throw new Error("File edit operation aborted before writing");
|
|
272
|
+
}
|
|
273
|
+
// Write the modified content with signal
|
|
274
|
+
await writeFile(filePath, modifiedContent, {
|
|
275
|
+
encoding: "utf-8",
|
|
276
|
+
signal: abortSignal,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return resultMessage;
|
|
281
|
+
}
|
package/dist/tools/agent.d.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
|
+
import { type ToolCallOptions } from "ai";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import type { WorkspaceContext } from "../index.ts";
|
|
1
4
|
import type { ModelManager } from "../models/manager.ts";
|
|
2
5
|
import type { TokenCounter } from "../tokens/counter.ts";
|
|
3
6
|
import type { TokenTracker } from "../tokens/tracker.ts";
|
|
4
|
-
import type {
|
|
7
|
+
import type { ToolResult } from "./types.ts";
|
|
5
8
|
export declare const AgentTool: {
|
|
6
9
|
name: "agent";
|
|
7
10
|
};
|
|
11
|
+
declare const inputSchema: z.ZodObject<{
|
|
12
|
+
prompt: z.ZodString;
|
|
13
|
+
}, z.core.$strip>;
|
|
8
14
|
export declare const createAgentTools: (options: {
|
|
9
15
|
modelManager: ModelManager;
|
|
10
16
|
tokenTracker: TokenTracker;
|
|
11
17
|
tokenCounter: TokenCounter;
|
|
12
|
-
|
|
18
|
+
workspace: WorkspaceContext;
|
|
13
19
|
}) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
toolDef: {
|
|
21
|
+
description: string;
|
|
22
|
+
inputSchema: z.ZodObject<{
|
|
23
|
+
prompt: z.ZodString;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
};
|
|
26
|
+
execute: ({ prompt }: z.infer<typeof inputSchema>, { toolCallId, abortSignal }: ToolCallOptions) => AsyncGenerator<ToolResult>;
|
|
17
27
|
};
|
|
28
|
+
export {};
|
|
18
29
|
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../source/tools/agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../source/tools/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,IAAI,CAAC;AACrE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAO,MAAM,SAAS;;CAErB,CAAC;AAiCF,QAAA,MAAM,WAAW;;iBAEf,CAAC;AAEH,eAAO,MAAM,gBAAgB,GAAI,SAAS;IACxC,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,gBAAgB,CAAC;CAC7B;;;;;;;0BASe,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,+BACV,eAAe,KAC3C,cAAc,CAAC,UAAU,CAAC;CA8D9B,CAAC"}
|