codemini-cli 0.2.7 → 0.2.9
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 +1 -1
- package/src/cli.js +1 -1
- package/src/core/agent-loop.js +101 -3
- package/src/core/default-system-prompt.js +38 -0
- package/src/core/provider/openai-compatible.js +34 -4
- package/src/core/shell-profile.js +14 -3
- package/src/core/tools.js +163 -55
- package/src/tui/chat-app.js +515 -193
- package/src/tui/skill-activity/index.js +20 -0
- package/src/tui/tool-activity/common.js +29 -0
- package/src/tui/tool-activity/index.js +17 -0
- package/src/tui/tool-activity/presenters/command.js +29 -0
- package/src/tui/tool-activity/presenters/files.js +26 -0
- package/src/tui/tool-activity/presenters/misc.js +19 -0
- package/src/tui/tool-activity/presenters/system.js +14 -0
- package/src/tui/tool-narration/common.js +37 -0
- package/src/tui/tool-narration/presenters/change.js +109 -0
- package/src/tui/tool-narration/presenters/edit.js +3 -0
- package/src/tui/tool-narration/presenters/generic.js +10 -0
- package/src/tui/tool-narration/presenters/glob.js +11 -0
- package/src/tui/tool-narration/presenters/grep.js +11 -0
- package/src/tui/tool-narration/presenters/list.js +11 -0
- package/src/tui/tool-narration/presenters/patch.js +3 -0
- package/src/tui/tool-narration/presenters/read.js +11 -0
- package/src/tui/tool-narration/presenters/run.js +29 -0
- package/src/tui/tool-narration/presenters/write.js +3 -0
- package/src/tui/tool-narration.js +67 -0
package/src/core/tools.js
CHANGED
|
@@ -119,6 +119,111 @@ function splitLines(text) {
|
|
|
119
119
|
return String(text || '').split('\n');
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
function parseInlineReadRange(value) {
|
|
123
|
+
const text = String(value || '').trim();
|
|
124
|
+
if (!text) return null;
|
|
125
|
+
const match = text.match(/^(.*?):(\d+)(?:-(\d+))?$/);
|
|
126
|
+
if (!match) return null;
|
|
127
|
+
const [, maybePath, startRaw, endRaw] = match;
|
|
128
|
+
if (!maybePath || /^(?:[A-Za-z])$/.test(maybePath)) return null;
|
|
129
|
+
const startLine = Number(startRaw);
|
|
130
|
+
const endLine = Number(endRaw || startRaw);
|
|
131
|
+
if (!Number.isFinite(startLine) || startLine <= 0) return null;
|
|
132
|
+
if (!Number.isFinite(endLine) || endLine < startLine) return null;
|
|
133
|
+
return {
|
|
134
|
+
path: maybePath,
|
|
135
|
+
start_line: startLine,
|
|
136
|
+
end_line: endLine
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function normalizeReadArgs(rawArgs) {
|
|
141
|
+
const source =
|
|
142
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
143
|
+
? { ...rawArgs }
|
|
144
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
145
|
+
|
|
146
|
+
const normalized = { ...source };
|
|
147
|
+
const aliasPath = String(source.path || source.file_path || source.file || source.target || '').trim();
|
|
148
|
+
if (aliasPath) normalized.path = aliasPath;
|
|
149
|
+
|
|
150
|
+
if (!Number.isFinite(Number(normalized.start_line)) && Number.isFinite(Number(source.offset))) {
|
|
151
|
+
normalized.start_line = Number(source.offset);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (!Number.isFinite(Number(normalized.end_line)) && Number.isFinite(Number(source.limit))) {
|
|
155
|
+
const startLine = Number(normalized.start_line);
|
|
156
|
+
const limit = Number(source.limit);
|
|
157
|
+
if (startLine > 0 && limit > 0) {
|
|
158
|
+
normalized.end_line = startLine + limit - 1;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const inlineRange = parseInlineReadRange(normalized.path);
|
|
163
|
+
if (inlineRange) {
|
|
164
|
+
normalized.path = inlineRange.path;
|
|
165
|
+
if (!Number.isFinite(Number(normalized.start_line))) normalized.start_line = inlineRange.start_line;
|
|
166
|
+
if (!Number.isFinite(Number(normalized.end_line))) normalized.end_line = inlineRange.end_line;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return normalized;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function normalizePathArgs(rawArgs, aliases = []) {
|
|
173
|
+
const source =
|
|
174
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
175
|
+
? { ...rawArgs }
|
|
176
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
177
|
+
const normalized = { ...source };
|
|
178
|
+
const keys = ['path', ...aliases];
|
|
179
|
+
for (const key of keys) {
|
|
180
|
+
const value = String(source?.[key] || '').trim();
|
|
181
|
+
if (value) {
|
|
182
|
+
normalized.path = value;
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return normalized;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function normalizePatternArgs(rawArgs, aliases = [], defaultPathAliases = []) {
|
|
190
|
+
const source =
|
|
191
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
192
|
+
? { ...rawArgs }
|
|
193
|
+
: { pattern: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
194
|
+
const normalized = { ...source };
|
|
195
|
+
for (const key of ['pattern', ...aliases]) {
|
|
196
|
+
const value = String(source?.[key] || '').trim();
|
|
197
|
+
if (value) {
|
|
198
|
+
normalized.pattern = value;
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
for (const key of ['path', ...defaultPathAliases]) {
|
|
203
|
+
const value = String(source?.[key] || '').trim();
|
|
204
|
+
if (value) {
|
|
205
|
+
normalized.path = value;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return normalized;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function normalizeWriteArgs(rawArgs) {
|
|
213
|
+
const source =
|
|
214
|
+
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
215
|
+
? { ...rawArgs }
|
|
216
|
+
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
217
|
+
const normalized = { ...source };
|
|
218
|
+
const filePath = String(source.path || source.file_path || source.file || '').trim();
|
|
219
|
+
if (filePath) normalized.path = filePath;
|
|
220
|
+
if (normalized.content == null) {
|
|
221
|
+
if (source.text != null) normalized.content = source.text;
|
|
222
|
+
if (source.new_content != null) normalized.content = source.new_content;
|
|
223
|
+
}
|
|
224
|
+
return normalized;
|
|
225
|
+
}
|
|
226
|
+
|
|
122
227
|
function findUniqueLineBlock(lines, blockContent) {
|
|
123
228
|
const probeLines = splitLines(blockContent);
|
|
124
229
|
if (probeLines.length === 0 || (probeLines.length === 1 && probeLines[0] === '')) return null;
|
|
@@ -665,16 +770,17 @@ async function getFileState(root, relativePath) {
|
|
|
665
770
|
}
|
|
666
771
|
|
|
667
772
|
async function readFile(root, args) {
|
|
668
|
-
const
|
|
773
|
+
const normalizedArgs = normalizeReadArgs(args);
|
|
774
|
+
const target = resolveInWorkspace(root, normalizedArgs?.path);
|
|
669
775
|
const stat = await fs.stat(target);
|
|
670
776
|
const text = await fs.readFile(target, 'utf8');
|
|
671
777
|
const lines = splitLines(text);
|
|
672
778
|
const totalLines = lines.length;
|
|
673
|
-
const startLineRaw = Number(
|
|
674
|
-
const endLineRaw = Number(
|
|
675
|
-
const defaultLines = Number(
|
|
676
|
-
const maxChars = Number(
|
|
677
|
-
const
|
|
779
|
+
const startLineRaw = Number(normalizedArgs?.start_line);
|
|
780
|
+
const endLineRaw = Number(normalizedArgs?.end_line);
|
|
781
|
+
const defaultLines = Number(normalizedArgs?.default_lines || 220);
|
|
782
|
+
const maxChars = Number(normalizedArgs?.max_chars || 24000);
|
|
783
|
+
const wantsMetadataOnly = normalizedArgs?.metadata_only === true || normalizedArgs?.include_content === false;
|
|
678
784
|
|
|
679
785
|
let startLine = Number.isFinite(startLineRaw) && startLineRaw > 0 ? startLineRaw : 1;
|
|
680
786
|
let endLine =
|
|
@@ -684,12 +790,12 @@ async function readFile(root, args) {
|
|
|
684
790
|
startLine = Math.max(1, Math.min(startLine, totalLines));
|
|
685
791
|
endLine = Math.max(startLine, Math.min(endLine, totalLines));
|
|
686
792
|
|
|
687
|
-
const tokenSeed = `${
|
|
793
|
+
const tokenSeed = `${normalizedArgs?.path}|${stat.size}|${stat.mtimeMs}|${startLine}|${endLine}`;
|
|
688
794
|
const readToken = sha1(tokenSeed).slice(0, 16);
|
|
689
795
|
|
|
690
|
-
if (
|
|
796
|
+
if (wantsMetadataOnly) {
|
|
691
797
|
return {
|
|
692
|
-
path:
|
|
798
|
+
path: normalizedArgs?.path,
|
|
693
799
|
phase: 'metadata',
|
|
694
800
|
size_bytes: stat.size,
|
|
695
801
|
modified_at: new Date(stat.mtimeMs).toISOString(),
|
|
@@ -701,21 +807,6 @@ async function readFile(root, args) {
|
|
|
701
807
|
};
|
|
702
808
|
}
|
|
703
809
|
|
|
704
|
-
if (String(args?.read_token || '') !== readToken) {
|
|
705
|
-
return {
|
|
706
|
-
path: args?.path,
|
|
707
|
-
phase: 'metadata',
|
|
708
|
-
error: 'read_token mismatch or missing',
|
|
709
|
-
size_bytes: stat.size,
|
|
710
|
-
modified_at: new Date(stat.mtimeMs).toISOString(),
|
|
711
|
-
total_lines: totalLines,
|
|
712
|
-
suggested_start_line: startLine,
|
|
713
|
-
suggested_end_line: endLine,
|
|
714
|
-
read_token: readToken,
|
|
715
|
-
next: 'Retry with include_content=true and read_token from latest metadata'
|
|
716
|
-
};
|
|
717
|
-
}
|
|
718
|
-
|
|
719
810
|
let content = lines.slice(startLine - 1, endLine).join('\n');
|
|
720
811
|
let truncated = false;
|
|
721
812
|
if (maxChars > 0 && content.length > maxChars) {
|
|
@@ -725,14 +816,14 @@ async function readFile(root, args) {
|
|
|
725
816
|
|
|
726
817
|
// Read deduplication: if same path+range+mtime was read before, return a short stub
|
|
727
818
|
const isDuplicate = checkReadDedup(
|
|
728
|
-
|
|
819
|
+
normalizedArgs?.path,
|
|
729
820
|
startLine,
|
|
730
821
|
endLine,
|
|
731
822
|
stat.mtimeMs
|
|
732
823
|
);
|
|
733
824
|
if (isDuplicate) {
|
|
734
825
|
return {
|
|
735
|
-
path:
|
|
826
|
+
path: normalizedArgs?.path,
|
|
736
827
|
phase: 'content',
|
|
737
828
|
start_line: startLine,
|
|
738
829
|
end_line: endLine,
|
|
@@ -744,7 +835,7 @@ async function readFile(root, args) {
|
|
|
744
835
|
}
|
|
745
836
|
|
|
746
837
|
return {
|
|
747
|
-
path:
|
|
838
|
+
path: normalizedArgs?.path,
|
|
748
839
|
phase: 'content',
|
|
749
840
|
start_line: startLine,
|
|
750
841
|
end_line: endLine,
|
|
@@ -755,7 +846,8 @@ async function readFile(root, args) {
|
|
|
755
846
|
}
|
|
756
847
|
|
|
757
848
|
async function writeFile(root, args) {
|
|
758
|
-
const
|
|
849
|
+
const normalizedArgs = normalizeWriteArgs(args);
|
|
850
|
+
const rawPath = String(normalizedArgs?.path || '').trim();
|
|
759
851
|
if (!rawPath) {
|
|
760
852
|
throw new Error('write requires a file path like weather/WeatherForecast.js');
|
|
761
853
|
}
|
|
@@ -778,18 +870,18 @@ async function writeFile(root, args) {
|
|
|
778
870
|
} catch {
|
|
779
871
|
existed = false;
|
|
780
872
|
}
|
|
781
|
-
if (existed && !
|
|
873
|
+
if (existed && !normalizedArgs?.append && !normalizedArgs?.full_file_rewrite && isCodeLikePath(rawPath)) {
|
|
782
874
|
throw new Error(
|
|
783
875
|
'write blocks full overwrite for existing code files by default. Use grep/read -> edit for minimal edits, or pass full_file_rewrite=true when a whole-file rewrite is truly intended.'
|
|
784
876
|
);
|
|
785
877
|
}
|
|
786
878
|
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
787
|
-
if (
|
|
788
|
-
await fs.appendFile(target,
|
|
879
|
+
if (normalizedArgs?.append) {
|
|
880
|
+
await fs.appendFile(target, normalizedArgs?.content || '', 'utf8');
|
|
789
881
|
} else {
|
|
790
|
-
await fs.writeFile(target,
|
|
882
|
+
await fs.writeFile(target, normalizedArgs?.content || '', 'utf8');
|
|
791
883
|
}
|
|
792
|
-
const after =
|
|
884
|
+
const after = normalizedArgs?.append ? `${before}${normalizedArgs?.content || ''}` : normalizedArgs?.content || '';
|
|
793
885
|
const beforeLines = splitLines(before);
|
|
794
886
|
const afterLines = splitLines(after);
|
|
795
887
|
let changeLine = 0;
|
|
@@ -805,7 +897,7 @@ async function writeFile(root, args) {
|
|
|
805
897
|
return {
|
|
806
898
|
ok: true,
|
|
807
899
|
path: rawPath,
|
|
808
|
-
action:
|
|
900
|
+
action: normalizedArgs?.append ? 'append' : existed ? 'overwrite' : 'create',
|
|
809
901
|
changed_line: changeLine || Math.max(1, afterLines.length),
|
|
810
902
|
diff_preview: previewLines.map((line, idx) => `${previewStart + idx + 1}| ${line}`).join('\n')
|
|
811
903
|
};
|
|
@@ -1208,12 +1300,13 @@ async function searchCode(root, args) {
|
|
|
1208
1300
|
}
|
|
1209
1301
|
|
|
1210
1302
|
async function grep(root, args) {
|
|
1211
|
-
const
|
|
1303
|
+
const normalizedArgs = normalizePatternArgs(args, ['query', 'symbol', 'q'], ['directory', 'dir', 'cwd']);
|
|
1304
|
+
const pattern = String(normalizedArgs?.pattern || '').trim();
|
|
1212
1305
|
if (!pattern) throw new Error('grep requires pattern');
|
|
1213
|
-
const maxResults = Math.max(1, Math.min(200, Number(
|
|
1214
|
-
const caseSensitive = Boolean(
|
|
1215
|
-
const files = await walkTextFiles(root,
|
|
1216
|
-
const regex =
|
|
1306
|
+
const maxResults = Math.max(1, Math.min(200, Number(normalizedArgs?.max_results || 50)));
|
|
1307
|
+
const caseSensitive = Boolean(normalizedArgs?.case_sensitive);
|
|
1308
|
+
const files = await walkTextFiles(root, normalizedArgs?.path || '.', normalizeFileTypes(normalizedArgs));
|
|
1309
|
+
const regex = normalizedArgs?.regex
|
|
1217
1310
|
? new RegExp(pattern, caseSensitive ? 'g' : 'gi')
|
|
1218
1311
|
: new RegExp(escapeRegex(pattern), caseSensitive ? 'g' : 'gi');
|
|
1219
1312
|
const matches = [];
|
|
@@ -1242,12 +1335,13 @@ async function grep(root, args) {
|
|
|
1242
1335
|
}
|
|
1243
1336
|
|
|
1244
1337
|
async function glob(root, args) {
|
|
1245
|
-
const
|
|
1338
|
+
const normalizedArgs = normalizePatternArgs(args, ['glob', 'query'], ['directory', 'dir', 'cwd']);
|
|
1339
|
+
const pattern = String(normalizedArgs?.pattern || '').trim();
|
|
1246
1340
|
if (!pattern) throw new Error('glob requires pattern');
|
|
1247
|
-
const maxResults = Math.max(1, Math.min(500, Number(
|
|
1341
|
+
const maxResults = Math.max(1, Math.min(500, Number(normalizedArgs?.max_results || 200)));
|
|
1248
1342
|
const regex = globToRegex(pattern);
|
|
1249
|
-
const entries = await walkWorkspaceEntries(root,
|
|
1250
|
-
includeHidden: Boolean(
|
|
1343
|
+
const entries = await walkWorkspaceEntries(root, normalizedArgs?.path || '.', {
|
|
1344
|
+
includeHidden: Boolean(normalizedArgs?.include_hidden)
|
|
1251
1345
|
});
|
|
1252
1346
|
const matches = entries
|
|
1253
1347
|
.filter((entry) => entry.type === 'file' && regex.test(entry.path))
|
|
@@ -1261,10 +1355,11 @@ async function glob(root, args) {
|
|
|
1261
1355
|
}
|
|
1262
1356
|
|
|
1263
1357
|
async function list(root, args) {
|
|
1264
|
-
const
|
|
1358
|
+
const normalizedArgs = normalizePathArgs(args, ['dir', 'directory', 'target']);
|
|
1359
|
+
const relativePath = String(normalizedArgs?.path || '.').trim() || '.';
|
|
1265
1360
|
const target = resolveInWorkspace(root, relativePath);
|
|
1266
1361
|
const entries = await fs.readdir(target, { withFileTypes: true });
|
|
1267
|
-
const includeHidden = Boolean(
|
|
1362
|
+
const includeHidden = Boolean(normalizedArgs?.include_hidden);
|
|
1268
1363
|
const items = entries
|
|
1269
1364
|
.filter((entry) => includeHidden || !entry.name.startsWith('.'))
|
|
1270
1365
|
.map((entry) => ({
|
|
@@ -1552,6 +1647,8 @@ function normalizeEditTargetArgs(args = {}) {
|
|
|
1552
1647
|
edit: normalizedEdit
|
|
1553
1648
|
};
|
|
1554
1649
|
}
|
|
1650
|
+
const topLevelOldText = args?.old_text ?? args?.old_string;
|
|
1651
|
+
const topLevelContent = args?.content;
|
|
1555
1652
|
return {
|
|
1556
1653
|
file,
|
|
1557
1654
|
ast_target: args?.ast_target,
|
|
@@ -1560,7 +1657,7 @@ function normalizeEditTargetArgs(args = {}) {
|
|
|
1560
1657
|
target: args?.target,
|
|
1561
1658
|
new_content: args?.new_content ?? args?.content,
|
|
1562
1659
|
old_text: args?.old_text,
|
|
1563
|
-
new_text: args?.new_text,
|
|
1660
|
+
new_text: args?.new_text ?? (topLevelOldText != null && topLevelContent != null ? topLevelContent : undefined),
|
|
1564
1661
|
old_string: args?.old_string,
|
|
1565
1662
|
new_string: args?.new_string,
|
|
1566
1663
|
anchor_text: args?.anchor_text,
|
|
@@ -1754,18 +1851,22 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1754
1851
|
function: {
|
|
1755
1852
|
name: 'read',
|
|
1756
1853
|
description:
|
|
1757
|
-
'Inspect a file
|
|
1854
|
+
'Inspect a file and return content directly by default. Demo-style aliases like file_path, offset, and limit are accepted. Use metadata_only=true only when you want file metadata without content. Do not use run with cat, head, or tail for file reads.',
|
|
1758
1855
|
parameters: {
|
|
1759
1856
|
type: 'object',
|
|
1760
1857
|
properties: {
|
|
1761
|
-
path: { type: 'string', description: 'File path to read' },
|
|
1858
|
+
path: { type: 'string', description: 'File path to read. You can also include an inline range like src/app.ts:10-40.' },
|
|
1859
|
+
file_path: { type: 'string', description: 'Alias for path' },
|
|
1762
1860
|
start_line: { type: 'number', description: '1-based start line' },
|
|
1763
1861
|
end_line: { type: 'number', description: 'Inclusive end line' },
|
|
1862
|
+
offset: { type: 'number', description: 'Alias for start_line' },
|
|
1863
|
+
limit: { type: 'number', description: 'Number of lines to read starting from offset/start_line' },
|
|
1764
1864
|
max_chars: { type: 'number', description: 'Max chars to return' },
|
|
1765
|
-
include_content: { type: 'boolean', description: '
|
|
1766
|
-
read_token: { type: 'string', description: '
|
|
1865
|
+
include_content: { type: 'boolean', description: 'Legacy compatibility flag. Content is returned by default.' },
|
|
1866
|
+
read_token: { type: 'string', description: 'Legacy compatibility token. No longer required for content reads.' },
|
|
1867
|
+
metadata_only: { type: 'boolean', description: 'Set true to return metadata without content.' }
|
|
1767
1868
|
},
|
|
1768
|
-
required: [
|
|
1869
|
+
required: []
|
|
1769
1870
|
}
|
|
1770
1871
|
}
|
|
1771
1872
|
},
|
|
@@ -1774,13 +1875,14 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1774
1875
|
function: {
|
|
1775
1876
|
name: 'grep',
|
|
1776
1877
|
description:
|
|
1777
|
-
'Search file contents. Use this for code search before read or edit. Do not use run with grep or rg for normal code search.',
|
|
1878
|
+
'Search file contents. Use this for code search before read or edit. Aliases like query and directory are accepted. Do not use run with grep or rg for normal code search.',
|
|
1778
1879
|
parameters: {
|
|
1779
1880
|
type: 'object',
|
|
1780
1881
|
properties: {
|
|
1781
1882
|
pattern: { type: 'string', description: 'Search pattern' },
|
|
1782
1883
|
query: { type: 'string', description: 'Alias for pattern' },
|
|
1783
1884
|
path: { type: 'string', description: 'Directory or file to search' },
|
|
1885
|
+
directory: { type: 'string', description: 'Alias for path' },
|
|
1784
1886
|
regex: { type: 'boolean', description: 'Treat pattern as regex' },
|
|
1785
1887
|
case_sensitive: { type: 'boolean', description: 'Case-sensitive matching' },
|
|
1786
1888
|
max_results: { type: 'number', description: 'Max matches to return' },
|
|
@@ -1796,12 +1898,14 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1796
1898
|
function: {
|
|
1797
1899
|
name: 'glob',
|
|
1798
1900
|
description:
|
|
1799
|
-
'Find files by glob pattern. Use this for file discovery before read. Do not use run with find for normal file lookup.',
|
|
1901
|
+
'Find files by glob pattern. Use this for file discovery before read. Aliases like query and directory are accepted. Do not use run with find for normal file lookup.',
|
|
1800
1902
|
parameters: {
|
|
1801
1903
|
type: 'object',
|
|
1802
1904
|
properties: {
|
|
1803
1905
|
pattern: { type: 'string', description: 'Glob pattern' },
|
|
1804
1906
|
path: { type: 'string', description: 'Directory to search' },
|
|
1907
|
+
query: { type: 'string', description: 'Alias for pattern' },
|
|
1908
|
+
directory: { type: 'string', description: 'Alias for path' },
|
|
1805
1909
|
include_hidden: { type: 'boolean', description: 'Include dotfiles' },
|
|
1806
1910
|
max_results: { type: 'number', description: 'Max results' }
|
|
1807
1911
|
},
|
|
@@ -1813,11 +1917,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1813
1917
|
type: 'function',
|
|
1814
1918
|
function: {
|
|
1815
1919
|
name: 'list',
|
|
1816
|
-
description: 'List files and directories in a workspace path. Use this for quick directory discovery before deeper reads.',
|
|
1920
|
+
description: 'List files and directories in a workspace path. Use this for quick directory discovery before deeper reads. Aliases like directory are accepted, and plain string paths are tolerated by the runtime.',
|
|
1817
1921
|
parameters: {
|
|
1818
1922
|
type: 'object',
|
|
1819
1923
|
properties: {
|
|
1820
1924
|
path: { type: 'string', description: 'Directory path to list' },
|
|
1925
|
+
directory: { type: 'string', description: 'Alias for path' },
|
|
1821
1926
|
include_hidden: { type: 'boolean', description: 'Include dotfiles' }
|
|
1822
1927
|
}
|
|
1823
1928
|
}
|
|
@@ -1859,13 +1964,16 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1859
1964
|
function: {
|
|
1860
1965
|
name: 'write',
|
|
1861
1966
|
description:
|
|
1862
|
-
'Create a new file or overwrite a file. Always include path
|
|
1967
|
+
'Create a new file or overwrite a file. Always include path and content. Aliases like file, file_path, text, and new_content are accepted. Use this for new files or explicit full rewrites only. Example: {path:"src/page.html", content:"..."} . If the file path is not decided yet, do not call write yet. Prefer edit for existing code changes.',
|
|
1863
1968
|
parameters: {
|
|
1864
1969
|
type: 'object',
|
|
1865
1970
|
properties: {
|
|
1866
1971
|
path: { type: 'string', description: 'Required file path like src/app.js or pages/index.html. Never omit this.' },
|
|
1867
1972
|
file_path: { type: 'string', description: 'Alias for path, compatible with simpler demo-style tool calls' },
|
|
1973
|
+
file: { type: 'string', description: 'Alias for path' },
|
|
1868
1974
|
content: { type: 'string', description: 'Content to write' },
|
|
1975
|
+
text: { type: 'string', description: 'Alias for content' },
|
|
1976
|
+
new_content: { type: 'string', description: 'Alias for content' },
|
|
1869
1977
|
append: { type: 'boolean', description: 'Append instead of overwrite' },
|
|
1870
1978
|
full_file_rewrite: { type: 'boolean', description: 'Set true for whole-file rewrites' }
|
|
1871
1979
|
},
|