codemini-cli 0.4.0 → 0.4.2
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/OPERATIONS.md +4 -2
- package/README.md +89 -11
- package/deployment.md +14 -7
- package/package.json +1 -2
- package/src/cli.js +1 -1
- package/src/commands/skill.js +145 -53
- package/src/core/agent-loop.js +18 -311
- package/src/core/chat-runtime.js +389 -53
- package/src/core/command-loader.js +12 -5
- package/src/core/config-store.js +2 -0
- package/src/core/context-compact.js +34 -9
- package/src/core/default-system-prompt.js +5 -5
- package/src/core/dream-audit.js +12 -0
- package/src/core/dream-consolidate.js +131 -59
- package/src/core/dream-evaluator.js +86 -0
- package/src/core/fff-adapter.js +1 -1
- package/src/core/memory-store.js +145 -10
- package/src/core/provider/openai-compatible.js +40 -5
- package/src/core/reflect-skill.js +178 -0
- package/src/core/shell-profile.js +8 -8
- package/src/core/tool-args.js +181 -0
- package/src/core/tool-result-store.js +206 -0
- package/src/core/tools.js +144 -190
- package/src/tui/chat-app.js +270 -28
- package/src/tui/tool-activity/presenters/misc.js +14 -0
- package/src/core/provider/anthropic.sdk-backup.js +0 -439
- package/src/core/provider/openai-compatible.sdk-backup.js +0 -412
package/src/core/tools.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { evaluateCommandPolicy } from './command-policy.js';
|
|
16
16
|
import { findEnclosingSymbol, queryAst, readAstNode, resolveAstTarget } from './ast.js';
|
|
17
17
|
import { initializeProjectIndex, queryProjectIndex, refreshIndexedFile } from './project-index.js';
|
|
18
|
-
import { checkReadDedup } from './
|
|
18
|
+
import { checkReadDedup } from './tool-result-store.js';
|
|
19
19
|
import { TOOL_SKIP_DIRS as SKIP_DIRS, TEXT_EXTENSIONS, CODE_WRITE_GUARD_EXTENSIONS, LANGUAGE_FILE_TYPES } from './constants.js';
|
|
20
20
|
import { sha256Prefixed as sha256, sha256 as sha256Hash } from './crypto-utils.js';
|
|
21
21
|
import { forgetMemory, listMemories, rememberMemory, searchMemories, captureToInbox } from './memory-store.js';
|
|
@@ -29,6 +29,14 @@ import {
|
|
|
29
29
|
sanitizeTextForModel,
|
|
30
30
|
summarizeRunOutput
|
|
31
31
|
} from './tool-output.js';
|
|
32
|
+
import {
|
|
33
|
+
normalizePathArgs,
|
|
34
|
+
normalizePatternArgs,
|
|
35
|
+
normalizeReadArgs,
|
|
36
|
+
normalizeWebFetchArgs,
|
|
37
|
+
normalizeWebSearchArgs,
|
|
38
|
+
normalizeWriteArgs
|
|
39
|
+
} from './tool-args.js';
|
|
32
40
|
const BACKGROUND_TASK_RECENT_OUTPUT_LIMIT = 80;
|
|
33
41
|
const BACKGROUND_TASK_POLL_MS = 150;
|
|
34
42
|
const MAX_AST_ENCLOSING_BYTES = 300_000;
|
|
@@ -100,133 +108,6 @@ function splitLines(text) {
|
|
|
100
108
|
return String(text || '').split('\n');
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
function parseInlineReadRange(value) {
|
|
104
|
-
const text = String(value || '').trim();
|
|
105
|
-
if (!text) return null;
|
|
106
|
-
const match = text.match(/^(.*?):(\d+)(?:-(\d+))?$/);
|
|
107
|
-
if (!match) return null;
|
|
108
|
-
const [, maybePath, startRaw, endRaw] = match;
|
|
109
|
-
if (!maybePath || /^(?:[A-Za-z])$/.test(maybePath)) return null;
|
|
110
|
-
const startLine = Number(startRaw);
|
|
111
|
-
const endLine = Number(endRaw || startRaw);
|
|
112
|
-
if (!Number.isFinite(startLine) || startLine <= 0) return null;
|
|
113
|
-
if (!Number.isFinite(endLine) || endLine < startLine) return null;
|
|
114
|
-
return {
|
|
115
|
-
path: maybePath,
|
|
116
|
-
start_line: startLine,
|
|
117
|
-
end_line: endLine
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function normalizeReadArgs(rawArgs) {
|
|
122
|
-
const source =
|
|
123
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
124
|
-
? { ...rawArgs }
|
|
125
|
-
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
126
|
-
|
|
127
|
-
const normalized = { ...source };
|
|
128
|
-
const aliasPath = String(source.path || source.file_path || source.file || source.target || '').trim();
|
|
129
|
-
if (aliasPath) normalized.path = aliasPath;
|
|
130
|
-
|
|
131
|
-
if (!Number.isFinite(Number(normalized.start_line)) && Number.isFinite(Number(source.offset))) {
|
|
132
|
-
normalized.start_line = Number(source.offset);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (!Number.isFinite(Number(normalized.end_line)) && Number.isFinite(Number(source.limit))) {
|
|
136
|
-
const startLine = Number(normalized.start_line);
|
|
137
|
-
const limit = Number(source.limit);
|
|
138
|
-
if (startLine > 0 && limit > 0) {
|
|
139
|
-
normalized.end_line = startLine + limit - 1;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const inlineRange = parseInlineReadRange(normalized.path);
|
|
144
|
-
if (inlineRange) {
|
|
145
|
-
normalized.path = inlineRange.path;
|
|
146
|
-
if (!Number.isFinite(Number(normalized.start_line))) normalized.start_line = inlineRange.start_line;
|
|
147
|
-
if (!Number.isFinite(Number(normalized.end_line))) normalized.end_line = inlineRange.end_line;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return normalized;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function normalizePathArgs(rawArgs, aliases = []) {
|
|
154
|
-
const source =
|
|
155
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
156
|
-
? { ...rawArgs }
|
|
157
|
-
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
158
|
-
const normalized = { ...source };
|
|
159
|
-
const keys = ['path', ...aliases];
|
|
160
|
-
for (const key of keys) {
|
|
161
|
-
const value = String(source?.[key] || '').trim();
|
|
162
|
-
if (value) {
|
|
163
|
-
normalized.path = value;
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
return normalized;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function normalizePatternArgs(rawArgs, aliases = [], defaultPathAliases = []) {
|
|
171
|
-
const source =
|
|
172
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
173
|
-
? { ...rawArgs }
|
|
174
|
-
: { pattern: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
175
|
-
const normalized = { ...source };
|
|
176
|
-
for (const key of ['pattern', ...aliases]) {
|
|
177
|
-
const value = String(source?.[key] || '').trim();
|
|
178
|
-
if (value) {
|
|
179
|
-
normalized.pattern = value;
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
for (const key of ['path', ...defaultPathAliases]) {
|
|
184
|
-
const value = String(source?.[key] || '').trim();
|
|
185
|
-
if (value) {
|
|
186
|
-
normalized.path = value;
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
return normalized;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function normalizeWriteArgs(rawArgs) {
|
|
194
|
-
const source =
|
|
195
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
196
|
-
? { ...rawArgs }
|
|
197
|
-
: { path: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
198
|
-
const normalized = { ...source };
|
|
199
|
-
const filePath = String(source.path || source.file_path || source.file || '').trim();
|
|
200
|
-
if (filePath) normalized.path = filePath;
|
|
201
|
-
if (normalized.content == null) {
|
|
202
|
-
if (source.text != null) normalized.content = source.text;
|
|
203
|
-
if (source.new_content != null) normalized.content = source.new_content;
|
|
204
|
-
}
|
|
205
|
-
return normalized;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function normalizeWebFetchArgs(rawArgs) {
|
|
209
|
-
const source =
|
|
210
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
211
|
-
? { ...rawArgs }
|
|
212
|
-
: { url: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
213
|
-
const normalized = { ...source };
|
|
214
|
-
const url = String(source.url || source.href || source.link || source.target || '').trim();
|
|
215
|
-
if (url) normalized.url = url;
|
|
216
|
-
return normalized;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function normalizeWebSearchArgs(rawArgs) {
|
|
220
|
-
const source =
|
|
221
|
-
rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs)
|
|
222
|
-
? { ...rawArgs }
|
|
223
|
-
: { query: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
224
|
-
const normalized = { ...source };
|
|
225
|
-
const query = String(source.query || source.q || source.keyword || '').trim();
|
|
226
|
-
if (query) normalized.query = query;
|
|
227
|
-
return normalized;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
111
|
function clampNumber(value, min, max, fallback) {
|
|
231
112
|
const num = Number(value);
|
|
232
113
|
if (!Number.isFinite(num)) return fallback;
|
|
@@ -291,6 +172,55 @@ function collectPageLinks($, pageUrl, maxLinks = 20) {
|
|
|
291
172
|
return links;
|
|
292
173
|
}
|
|
293
174
|
|
|
175
|
+
function extractPageContent(cheerio, html, pageUrl, { maxLinks, status = null, contentType = '', fetchMode = 'static' } = {}) {
|
|
176
|
+
const $ = cheerio.load(html);
|
|
177
|
+
$('script, style, noscript').remove();
|
|
178
|
+
const bodyText = $('body').text() || $.root().text();
|
|
179
|
+
const text = String(bodyText || '').replace(/[^\S\n]+/g, ' ').replace(/\n{3,}/g, '\n\n').trim();
|
|
180
|
+
const title = trimPreview($('title').first().text(), 240);
|
|
181
|
+
const description = extractHtmlMeta($, 'description') || extractHtmlMeta($, 'og:description');
|
|
182
|
+
const links = collectPageLinks($, pageUrl, maxLinks);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
final_url: pageUrl,
|
|
186
|
+
title,
|
|
187
|
+
description,
|
|
188
|
+
text,
|
|
189
|
+
links,
|
|
190
|
+
metadata: {
|
|
191
|
+
status,
|
|
192
|
+
fetched_at: new Date().toISOString(),
|
|
193
|
+
content_type: contentType,
|
|
194
|
+
fetch_mode: fetchMode,
|
|
195
|
+
lang: String($('html').attr('lang') || '').trim()
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function shouldTryBrowserRender(html, text) {
|
|
201
|
+
if (String(text || '').trim().length >= 120) return false;
|
|
202
|
+
return /<script\b/i.test(html) ||
|
|
203
|
+
/id=["']__(?:next|nuxt)["']/i.test(html) ||
|
|
204
|
+
/data-reactroot|ng-version|window\.__/i.test(html);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function playwrightInstallHint() {
|
|
208
|
+
return 'For JavaScript-rendered pages, install Playwright for richer web_fetch results: npm install -g playwright && playwright install chromium';
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async function loadOptionalPlaywright() {
|
|
212
|
+
try {
|
|
213
|
+
return await import('playwright');
|
|
214
|
+
} catch (error) {
|
|
215
|
+
const code = String(error?.code || '');
|
|
216
|
+
const message = String(error?.message || '');
|
|
217
|
+
if (code === 'ERR_MODULE_NOT_FOUND' || /Cannot find package 'playwright'|Cannot find module 'playwright'/i.test(message)) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
294
224
|
async function buildPlaywrightLaunchEnv() {
|
|
295
225
|
const localLibDir = path.join(
|
|
296
226
|
process.env.HOME || '',
|
|
@@ -323,44 +253,85 @@ async function webFetchPage(args = {}) {
|
|
|
323
253
|
? String(normalizedArgs.wait_until).trim()
|
|
324
254
|
: 'domcontentloaded';
|
|
325
255
|
|
|
326
|
-
const
|
|
256
|
+
const cheerio = await import('cheerio');
|
|
257
|
+
let staticResult = null;
|
|
258
|
+
let staticHtml = '';
|
|
259
|
+
let staticError = null;
|
|
260
|
+
try {
|
|
261
|
+
const controller = new AbortController();
|
|
262
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
263
|
+
let response;
|
|
264
|
+
try {
|
|
265
|
+
response = await fetch(url, {
|
|
266
|
+
redirect: 'follow',
|
|
267
|
+
signal: controller.signal,
|
|
268
|
+
headers: {
|
|
269
|
+
'user-agent': 'CodeMiniCLI/0.4 web_fetch'
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
} finally {
|
|
273
|
+
clearTimeout(timeout);
|
|
274
|
+
}
|
|
275
|
+
staticHtml = await response.text();
|
|
276
|
+
staticResult = {
|
|
277
|
+
url,
|
|
278
|
+
...extractPageContent(cheerio, staticHtml, response.url || url, {
|
|
279
|
+
maxLinks,
|
|
280
|
+
status: response.status,
|
|
281
|
+
contentType: response.headers.get('content-type') || '',
|
|
282
|
+
fetchMode: 'static'
|
|
283
|
+
})
|
|
284
|
+
};
|
|
285
|
+
if (!shouldTryBrowserRender(staticHtml, staticResult.text)) {
|
|
286
|
+
return staticResult;
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
staticError = error;
|
|
290
|
+
}
|
|
327
291
|
|
|
328
|
-
|
|
329
|
-
|
|
292
|
+
const playwright = await loadOptionalPlaywright();
|
|
293
|
+
if (!playwright) {
|
|
294
|
+
if (staticResult) {
|
|
295
|
+
return {
|
|
296
|
+
...staticResult,
|
|
297
|
+
warnings: [playwrightInstallHint()]
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
throw new Error(`web_fetch failed and browser rendering is unavailable. ${playwrightInstallHint()}. Static fetch error: ${staticError?.message || staticError}`);
|
|
301
|
+
}
|
|
330
302
|
|
|
331
|
-
|
|
332
|
-
headless: true,
|
|
333
|
-
env: await buildPlaywrightLaunchEnv()
|
|
334
|
-
});
|
|
303
|
+
let browser;
|
|
335
304
|
try {
|
|
305
|
+
browser = await playwright.chromium.launch({
|
|
306
|
+
headless: true,
|
|
307
|
+
env: await buildPlaywrightLaunchEnv()
|
|
308
|
+
});
|
|
336
309
|
const page = await browser.newPage();
|
|
337
310
|
const response = await page.goto(url, { waitUntil, timeout: timeoutMs });
|
|
338
311
|
const finalUrl = page.url();
|
|
339
312
|
const html = await page.content();
|
|
340
|
-
const
|
|
341
|
-
const bodyText = $('body').text() || $.root().text();
|
|
342
|
-
const text = String(bodyText || '').replace(/[^\S\n]+/g, ' ').replace(/\n{3,}/g, '\n\n').trim();
|
|
343
|
-
const title = trimPreview($('title').first().text() || (await page.title()), 240);
|
|
344
|
-
const description = extractHtmlMeta($, 'description') || extractHtmlMeta($, 'og:description');
|
|
345
|
-
const links = collectPageLinks($, finalUrl, maxLinks);
|
|
346
|
-
|
|
347
|
-
return {
|
|
313
|
+
const rendered = {
|
|
348
314
|
url,
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
description,
|
|
352
|
-
text,
|
|
353
|
-
links,
|
|
354
|
-
metadata: {
|
|
315
|
+
...extractPageContent(cheerio, html, finalUrl, {
|
|
316
|
+
maxLinks,
|
|
355
317
|
status: response?.status?.() ?? null,
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
lang: String($('html').attr('lang') || '').trim()
|
|
360
|
-
}
|
|
318
|
+
contentType: response?.headers?.()['content-type'] || '',
|
|
319
|
+
fetchMode: 'browser'
|
|
320
|
+
})
|
|
361
321
|
};
|
|
322
|
+
rendered.metadata.wait_until = waitUntil;
|
|
323
|
+
rendered.title = rendered.title || trimPreview(await page.title(), 240);
|
|
324
|
+
return rendered;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
if (staticResult) {
|
|
327
|
+
return {
|
|
328
|
+
...staticResult,
|
|
329
|
+
warnings: [`Browser rendering fallback failed: ${error?.message || error}`]
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
throw error;
|
|
362
333
|
} finally {
|
|
363
|
-
await browser.close();
|
|
334
|
+
if (browser) await browser.close();
|
|
364
335
|
}
|
|
365
336
|
}
|
|
366
337
|
|
|
@@ -1819,20 +1790,14 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1819
1790
|
function: {
|
|
1820
1791
|
name: 'read',
|
|
1821
1792
|
description:
|
|
1822
|
-
'Inspect code or text files. Use read(path) for normal file or line-window reads
|
|
1793
|
+
'Inspect code or text files. Use read(path) for normal file or line-window reads. Use start_line and end_line for ranges, or path:"src/app.ts:10-40" for inline ranges. Prefer this over run with cat, head, or tail.',
|
|
1823
1794
|
parameters: {
|
|
1824
1795
|
type: 'object',
|
|
1825
1796
|
properties: {
|
|
1826
1797
|
path: { type: 'string', description: 'File path to read. You can also include an inline range like src/app.ts:10-40.' },
|
|
1827
|
-
file_path: { type: 'string', description: 'Alias for path' },
|
|
1828
1798
|
start_line: { type: 'number', description: '1-based start line' },
|
|
1829
1799
|
end_line: { type: 'number', description: 'Inclusive end line' },
|
|
1830
|
-
offset: { type: 'number', description: 'Alias for start_line' },
|
|
1831
|
-
limit: { type: 'number', description: 'Number of lines to read starting from offset/start_line' },
|
|
1832
1800
|
max_chars: { type: 'number', description: 'Max chars to return' },
|
|
1833
|
-
include_content: { type: 'boolean', description: 'Legacy compatibility flag. Content is returned by default.' },
|
|
1834
|
-
read_token: { type: 'string', description: 'Legacy compatibility token. No longer required for content reads.' },
|
|
1835
|
-
metadata_only: { type: 'boolean', description: 'Set true to return metadata without content.' },
|
|
1836
1801
|
ast_target: { type: 'object', description: 'AST target from ast_query or a prior AST selection. When provided, read returns that node instead of a line window.' },
|
|
1837
1802
|
query: { type: 'string', description: 'Optional Tree-sitter query to run inline before reading the first matched AST node. Use with path for one-shot function/class/method reads.' },
|
|
1838
1803
|
capture_name: { type: 'string', description: 'Optional capture name to select when query is provided.' },
|
|
@@ -1847,14 +1812,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1847
1812
|
function: {
|
|
1848
1813
|
name: 'grep',
|
|
1849
1814
|
description:
|
|
1850
|
-
'Search file contents. Use this for code search before read or edit.
|
|
1815
|
+
'Search file contents. Use this for code search before read or edit. Do not use run with grep or rg for normal code search.',
|
|
1851
1816
|
parameters: {
|
|
1852
1817
|
type: 'object',
|
|
1853
1818
|
properties: {
|
|
1854
1819
|
pattern: { type: 'string', description: 'Search pattern' },
|
|
1855
|
-
query: { type: 'string', description: 'Alias for pattern' },
|
|
1856
1820
|
path: { type: 'string', description: 'Directory or file to search' },
|
|
1857
|
-
directory: { type: 'string', description: 'Alias for path' },
|
|
1858
1821
|
regex: { type: 'boolean', description: 'Treat pattern as regex' },
|
|
1859
1822
|
case_sensitive: { type: 'boolean', description: 'Case-sensitive matching' },
|
|
1860
1823
|
max_results: { type: 'number', description: 'Max matches to return' },
|
|
@@ -1869,12 +1832,11 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1869
1832
|
type: 'function',
|
|
1870
1833
|
function: {
|
|
1871
1834
|
name: 'list',
|
|
1872
|
-
description: 'List files and directories in a workspace path. Use this for quick directory discovery before deeper reads.
|
|
1835
|
+
description: 'List files and directories in a workspace path. Use this for quick directory discovery before deeper reads.',
|
|
1873
1836
|
parameters: {
|
|
1874
1837
|
type: 'object',
|
|
1875
1838
|
properties: {
|
|
1876
1839
|
path: { type: 'string', description: 'Directory path to list' },
|
|
1877
|
-
directory: { type: 'string', description: 'Alias for path' },
|
|
1878
1840
|
include_hidden: { type: 'boolean', description: 'Include dotfiles' }
|
|
1879
1841
|
}
|
|
1880
1842
|
}
|
|
@@ -1885,14 +1847,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1885
1847
|
function: {
|
|
1886
1848
|
name: 'glob',
|
|
1887
1849
|
description:
|
|
1888
|
-
'Find files by glob pattern. Use this when you already know a filename pattern such as src/**/*.ts.
|
|
1850
|
+
'Find files by glob pattern. Use this when you already know a filename pattern such as src/**/*.ts.',
|
|
1889
1851
|
parameters: {
|
|
1890
1852
|
type: 'object',
|
|
1891
1853
|
properties: {
|
|
1892
1854
|
pattern: { type: 'string', description: 'Glob pattern' },
|
|
1893
1855
|
path: { type: 'string', description: 'Directory to search' },
|
|
1894
|
-
query: { type: 'string', description: 'Alias for pattern' },
|
|
1895
|
-
directory: { type: 'string', description: 'Alias for path' },
|
|
1896
1856
|
include_hidden: { type: 'boolean', description: 'Include dotfiles' },
|
|
1897
1857
|
max_results: { type: 'number', description: 'Max results' }
|
|
1898
1858
|
},
|
|
@@ -1923,18 +1883,14 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1923
1883
|
function: {
|
|
1924
1884
|
name: 'edit',
|
|
1925
1885
|
description:
|
|
1926
|
-
'Edit existing files. Prefer one of these shapes: 1) {
|
|
1886
|
+
'Edit existing files. Prefer one of these shapes: 1) {path, old_text, new_text} for exact text replacement, 2) {path, symbol, edit:{kind:"replace_block", new_content:"..."}} for block replacement, 3) {path, anchor_text, position:"before"|"after", content:"..."} for inserts. Read first unless the exact target is already known. Prefer this over write for existing code changes.',
|
|
1927
1887
|
parameters: {
|
|
1928
1888
|
type: 'object',
|
|
1929
1889
|
properties: {
|
|
1930
|
-
|
|
1931
|
-
path: { type: 'string', description: 'Alias for file' },
|
|
1932
|
-
file_path: { type: 'string', description: 'Alias for file, compatible with simpler demo-style tool calls' },
|
|
1890
|
+
path: { type: 'string', description: 'File path to edit' },
|
|
1933
1891
|
new_content: { type: 'string', description: 'Replacement content' },
|
|
1934
1892
|
old_text: { type: 'string', description: 'Exact text to replace' },
|
|
1935
1893
|
new_text: { type: 'string', description: 'Replacement text' },
|
|
1936
|
-
old_string: { type: 'string', description: 'Alias for old_text' },
|
|
1937
|
-
new_string: { type: 'string', description: 'Alias for new_text' },
|
|
1938
1894
|
anchor_text: { type: 'string', description: 'Anchor text for inserts' },
|
|
1939
1895
|
content: { type: 'string', description: 'Content to insert or append' },
|
|
1940
1896
|
position: { type: 'string', description: 'before or after' },
|
|
@@ -1945,7 +1901,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1945
1901
|
line: { type: 'number', description: 'Line to target' },
|
|
1946
1902
|
edit: { type: 'object', description: 'Structured edit input' }
|
|
1947
1903
|
},
|
|
1948
|
-
required: ['
|
|
1904
|
+
required: ['path']
|
|
1949
1905
|
}
|
|
1950
1906
|
}
|
|
1951
1907
|
},
|
|
@@ -1954,16 +1910,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1954
1910
|
function: {
|
|
1955
1911
|
name: 'write',
|
|
1956
1912
|
description:
|
|
1957
|
-
'Create a new file or overwrite a file. Always include path and content.
|
|
1913
|
+
'Create a new file or overwrite a file. Always include path and content. 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.',
|
|
1958
1914
|
parameters: {
|
|
1959
1915
|
type: 'object',
|
|
1960
1916
|
properties: {
|
|
1961
1917
|
path: { type: 'string', description: 'Required file path like src/app.js or pages/index.html. Never omit this.' },
|
|
1962
|
-
file_path: { type: 'string', description: 'Alias for path, compatible with simpler demo-style tool calls' },
|
|
1963
|
-
file: { type: 'string', description: 'Alias for path' },
|
|
1964
1918
|
content: { type: 'string', description: 'Content to write' },
|
|
1965
|
-
text: { type: 'string', description: 'Alias for content' },
|
|
1966
|
-
new_content: { type: 'string', description: 'Alias for content' },
|
|
1967
1919
|
append: { type: 'boolean', description: 'Append instead of overwrite' },
|
|
1968
1920
|
full_file_rewrite: { type: 'boolean', description: 'Set true for whole-file rewrites' }
|
|
1969
1921
|
},
|
|
@@ -1976,15 +1928,11 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1976
1928
|
function: {
|
|
1977
1929
|
name: 'delete',
|
|
1978
1930
|
description:
|
|
1979
|
-
'Delete a file or directory inside the workspace.
|
|
1931
|
+
'Delete a file or directory inside the workspace. Missing targets fail. Workspace escape attempts are rejected.',
|
|
1980
1932
|
parameters: {
|
|
1981
1933
|
type: 'object',
|
|
1982
1934
|
properties: {
|
|
1983
|
-
path: { type: 'string', description: 'File or directory path to delete' }
|
|
1984
|
-
file: { type: 'string', description: 'Alias for path' },
|
|
1985
|
-
file_path: { type: 'string', description: 'Alias for path' },
|
|
1986
|
-
directory: { type: 'string', description: 'Alias for path' },
|
|
1987
|
-
dir: { type: 'string', description: 'Alias for path' }
|
|
1935
|
+
path: { type: 'string', description: 'File or directory path to delete' }
|
|
1988
1936
|
},
|
|
1989
1937
|
required: ['path']
|
|
1990
1938
|
}
|
|
@@ -2178,7 +2126,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2178
2126
|
function: {
|
|
2179
2127
|
name: 'web_fetch',
|
|
2180
2128
|
description:
|
|
2181
|
-
'Fetch and read a live web page. Uses
|
|
2129
|
+
'Fetch and read a live web page. Uses a lightweight fetch + Cheerio reader by default, then falls back to optional Playwright browser rendering for JavaScript-heavy pages when Playwright is installed. Use this for direct URL reads, not for keyword search.',
|
|
2182
2130
|
parameters: {
|
|
2183
2131
|
type: 'object',
|
|
2184
2132
|
properties: {
|
|
@@ -2282,7 +2230,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2282
2230
|
function: {
|
|
2283
2231
|
name: 'dream_consolidate',
|
|
2284
2232
|
description:
|
|
2285
|
-
'Run a dream loop
|
|
2233
|
+
'Run a dream loop pass over inbox entries and existing memory buckets. Reads recent inbox items, deduplicates, evaluates lifecycle progression (observed → candidate → operational/longterm), promotes stable patterns into persistent memory, then uses LLM maintenance to merge/summarize/clean stale user/global/project memories when their bucket changed since the last maintenance marker. Writes an audit report. Use during off-hours or explicit maintenance.',
|
|
2286
2234
|
parameters: {
|
|
2287
2235
|
type: 'object',
|
|
2288
2236
|
properties: {
|
|
@@ -2884,6 +2832,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2884
2832
|
if (result.title) lines.push(`title: ${result.title}`);
|
|
2885
2833
|
if (result.description) lines.push(`description: ${trimPreview(result.description, 200)}`);
|
|
2886
2834
|
if (result.metadata?.status) lines.push(`status: ${result.metadata.status}`);
|
|
2835
|
+
if (result.metadata?.fetch_mode) lines.push(`mode: ${result.metadata.fetch_mode}`);
|
|
2836
|
+
if (Array.isArray(result.warnings)) {
|
|
2837
|
+
for (const warning of result.warnings.slice(0, 3)) {
|
|
2838
|
+
if (warning) lines.push(`warning: ${warning}`);
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2887
2841
|
if (Array.isArray(result.links) && result.links.length > 0) {
|
|
2888
2842
|
lines.push(`links: ${result.links.slice(0, 5).map((item) => item.href).join(', ')}`);
|
|
2889
2843
|
}
|