codemini-cli 0.2.6 → 0.2.7
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 +4 -1
- package/src/core/tools.js +33 -6
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { handleConfig } from './commands/config.js';
|
|
|
4
4
|
import { handleDoctor } from './commands/doctor.js';
|
|
5
5
|
import { handleSkill } from './commands/skill.js';
|
|
6
6
|
|
|
7
|
-
const VERSION = '0.2.
|
|
7
|
+
const VERSION = '0.2.7';
|
|
8
8
|
|
|
9
9
|
function printHelp() {
|
|
10
10
|
console.log(`codemini ${VERSION}
|
package/src/core/agent-loop.js
CHANGED
package/src/core/tools.js
CHANGED
|
@@ -755,7 +755,7 @@ async function readFile(root, args) {
|
|
|
755
755
|
}
|
|
756
756
|
|
|
757
757
|
async function writeFile(root, args) {
|
|
758
|
-
const rawPath = String(args?.path || '').trim();
|
|
758
|
+
const rawPath = String(args?.path || args?.file_path || '').trim();
|
|
759
759
|
if (!rawPath) {
|
|
760
760
|
throw new Error('write requires a file path like weather/WeatherForecast.js');
|
|
761
761
|
}
|
|
@@ -1536,7 +1536,7 @@ async function openTarget(root, args) {
|
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
1538
|
function normalizeEditTargetArgs(args = {}) {
|
|
1539
|
-
const file = String(args?.file || args?.path || '').trim();
|
|
1539
|
+
const file = String(args?.file || args?.path || args?.file_path || '').trim();
|
|
1540
1540
|
const nestedEdit = args?.edit && typeof args.edit === 'object' ? args.edit : null;
|
|
1541
1541
|
if (nestedEdit) {
|
|
1542
1542
|
const normalizedEdit = { ...nestedEdit };
|
|
@@ -1561,6 +1561,8 @@ function normalizeEditTargetArgs(args = {}) {
|
|
|
1561
1561
|
new_content: args?.new_content ?? args?.content,
|
|
1562
1562
|
old_text: args?.old_text,
|
|
1563
1563
|
new_text: args?.new_text,
|
|
1564
|
+
old_string: args?.old_string,
|
|
1565
|
+
new_string: args?.new_string,
|
|
1564
1566
|
anchor_text: args?.anchor_text,
|
|
1565
1567
|
content: args?.content
|
|
1566
1568
|
}
|
|
@@ -1573,6 +1575,12 @@ async function editTarget(root, args) {
|
|
|
1573
1575
|
const astTarget = normalized.ast_target;
|
|
1574
1576
|
const edit = normalized.edit || {};
|
|
1575
1577
|
let kind = String(edit.kind || '').trim();
|
|
1578
|
+
if (edit.old_text == null && edit.old_string != null) {
|
|
1579
|
+
edit.old_text = edit.old_string;
|
|
1580
|
+
}
|
|
1581
|
+
if (edit.new_text == null && edit.new_string != null) {
|
|
1582
|
+
edit.new_text = edit.new_string;
|
|
1583
|
+
}
|
|
1576
1584
|
const hasContent = edit.new_content != null || edit.content != null;
|
|
1577
1585
|
const hasTargetHint = Boolean(edit.symbol || args?.symbol || edit.line || args?.line || edit.target);
|
|
1578
1586
|
if (!kind) {
|
|
@@ -1586,7 +1594,14 @@ async function editTarget(root, args) {
|
|
|
1586
1594
|
kind = 'rewrite_file';
|
|
1587
1595
|
}
|
|
1588
1596
|
}
|
|
1589
|
-
if (!file || !kind)
|
|
1597
|
+
if (!file || !kind) {
|
|
1598
|
+
const recentFile = String(args?.recent_file || '').trim();
|
|
1599
|
+
const rawArgs = typeof args?._raw === 'string' && args._raw.trim() ? ` Raw tool arguments: ${args._raw.trim()}.` : '';
|
|
1600
|
+
const hint = recentFile
|
|
1601
|
+
? ` If you meant the recently read file ${recentFile}, use edit with {file:"${recentFile}", old_text:"...", new_text:"..."} for a text replacement, or {file:"${recentFile}", edit:{kind:"rewrite_file", new_content:"..."}} for a full rewrite.`
|
|
1602
|
+
: ' Use edit with {file:"path", old_text:"...", new_text:"..."} for a text replacement, or {file:"path", edit:{kind:"rewrite_file", new_content:"..."}} for a full rewrite.';
|
|
1603
|
+
throw new Error(`edit requires file and edit.kind.${rawArgs}${hint}`);
|
|
1604
|
+
}
|
|
1590
1605
|
if (astTarget) {
|
|
1591
1606
|
if (kind !== 'replace_block') {
|
|
1592
1607
|
throw new Error('AST-scoped edit only supports replace_block');
|
|
@@ -1659,6 +1674,7 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1659
1674
|
};
|
|
1660
1675
|
const astSelectionCache = new Map();
|
|
1661
1676
|
let lastAstTarget = null;
|
|
1677
|
+
let lastReadPath = '';
|
|
1662
1678
|
const rememberAstSelection = (filePath, astTarget) => {
|
|
1663
1679
|
const key = String(filePath || '').trim();
|
|
1664
1680
|
if (!key || !astTarget) return;
|
|
@@ -1812,15 +1828,18 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1812
1828
|
function: {
|
|
1813
1829
|
name: 'edit',
|
|
1814
1830
|
description:
|
|
1815
|
-
'Edit existing files.
|
|
1831
|
+
'Edit existing files. Prefer one of these shapes: 1) {file, old_text, new_text} for exact text replacement, 2) {file, symbol, edit:{kind:"replace_block", new_content:"..."}} for block replacement, 3) {file, anchor_text, position:"before"|"after", content:"..."} for inserts. Demo-style aliases {file_path, old_string, new_string} are also accepted. Read first unless the exact target is already known. Prefer this over write for existing code changes.',
|
|
1816
1832
|
parameters: {
|
|
1817
1833
|
type: 'object',
|
|
1818
1834
|
properties: {
|
|
1819
1835
|
file: { type: 'string', description: 'File path to edit' },
|
|
1820
1836
|
path: { type: 'string', description: 'Alias for file' },
|
|
1837
|
+
file_path: { type: 'string', description: 'Alias for file, compatible with simpler demo-style tool calls' },
|
|
1821
1838
|
new_content: { type: 'string', description: 'Replacement content' },
|
|
1822
1839
|
old_text: { type: 'string', description: 'Exact text to replace' },
|
|
1823
1840
|
new_text: { type: 'string', description: 'Replacement text' },
|
|
1841
|
+
old_string: { type: 'string', description: 'Alias for old_text' },
|
|
1842
|
+
new_string: { type: 'string', description: 'Alias for new_text' },
|
|
1824
1843
|
anchor_text: { type: 'string', description: 'Anchor text for inserts' },
|
|
1825
1844
|
content: { type: 'string', description: 'Content to insert or append' },
|
|
1826
1845
|
position: { type: 'string', description: 'before or after' },
|
|
@@ -1840,11 +1859,12 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
1840
1859
|
function: {
|
|
1841
1860
|
name: 'write',
|
|
1842
1861
|
description:
|
|
1843
|
-
'Create a new file or overwrite a file. Always include path and content. Use this for new files or explicit full rewrites only. If the file path is not decided yet, do not call write yet. Prefer edit for existing code changes.',
|
|
1862
|
+
'Create a new file or overwrite a file. Always include path (or file_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.',
|
|
1844
1863
|
parameters: {
|
|
1845
1864
|
type: 'object',
|
|
1846
1865
|
properties: {
|
|
1847
1866
|
path: { type: 'string', description: 'Required file path like src/app.js or pages/index.html. Never omit this.' },
|
|
1867
|
+
file_path: { type: 'string', description: 'Alias for path, compatible with simpler demo-style tool calls' },
|
|
1848
1868
|
content: { type: 'string', description: 'Content to write' },
|
|
1849
1869
|
append: { type: 'boolean', description: 'Append instead of overwrite' },
|
|
1850
1870
|
full_file_rewrite: { type: 'boolean', description: 'Set true for whole-file rewrites' }
|
|
@@ -2049,6 +2069,10 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2049
2069
|
typeof args?.max_chars === 'number'
|
|
2050
2070
|
? args.max_chars
|
|
2051
2071
|
: config.context?.read_file_max_chars ?? 24000
|
|
2072
|
+
}).then((result) => {
|
|
2073
|
+
const readPath = String(result?.path || args?.path || '').trim();
|
|
2074
|
+
if (readPath) lastReadPath = readPath;
|
|
2075
|
+
return result;
|
|
2052
2076
|
}),
|
|
2053
2077
|
grep: (args) => grep(workspaceRoot, args),
|
|
2054
2078
|
glob: (args) => glob(workspaceRoot, args),
|
|
@@ -2069,7 +2093,10 @@ export function getBuiltinTools({ workspaceRoot = process.cwd(), config, onSyste
|
|
|
2069
2093
|
await ensureProjectIndex();
|
|
2070
2094
|
const normalizedKind = String(args?.edit?.kind || args?.kind || '').trim();
|
|
2071
2095
|
const astTarget = resolveCachedAstTarget(args, { requireAstScope: normalizedKind === 'replace_block' });
|
|
2072
|
-
const result = await editTarget(
|
|
2096
|
+
const result = await editTarget(
|
|
2097
|
+
workspaceRoot,
|
|
2098
|
+
astTarget ? { ...args, ast_target: astTarget, recent_file: lastReadPath } : { ...args, recent_file: lastReadPath }
|
|
2099
|
+
);
|
|
2073
2100
|
if (result?.path) await refreshProjectFile(result.path);
|
|
2074
2101
|
return result;
|
|
2075
2102
|
},
|