winter-super-cli 2026.6.19 → 2026.6.21
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 +144 -641
- package/package.json +1 -1
- package/src/ai/provider-adapters.js +317 -0
- package/src/ai/providers.js +104 -122
- package/src/cli/repl.js +3484 -3484
- package/src/cli/tool-call-adapter.js +24 -2
- package/src/tools/executor.js +37 -36
|
@@ -39,8 +39,14 @@ export function extractInlineToolCalls(content, idFactory = index => `inline-${D
|
|
|
39
39
|
};
|
|
40
40
|
const pushParsedToolObject = (parsed) => {
|
|
41
41
|
const { name, args } = extractToolPayload(parsed, parseToolArguments);
|
|
42
|
-
if (
|
|
43
|
-
|
|
42
|
+
if (name && typeof name === 'string') {
|
|
43
|
+
pushToolCall(name, args, 'object');
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const inferred = inferSafeToolFromBareArguments(parsed);
|
|
48
|
+
if (!inferred) return false;
|
|
49
|
+
pushToolCall(inferred.name, inferred.args, 'bare-arguments');
|
|
44
50
|
return true;
|
|
45
51
|
};
|
|
46
52
|
|
|
@@ -304,6 +310,22 @@ function extractToolPayload(payload, parseArguments) {
|
|
|
304
310
|
};
|
|
305
311
|
}
|
|
306
312
|
|
|
313
|
+
export function inferSafeToolFromBareArguments(value) {
|
|
314
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
|
|
315
|
+
|
|
316
|
+
const keys = Object.keys(value);
|
|
317
|
+
if (keys.length === 0) return null;
|
|
318
|
+
|
|
319
|
+
const hasGenericPayloadKeys = keys.some(key => /^(arguments?|args?|input|parameters?|params?|tool[_-]?input|function[_-]?arguments?)$/i.test(key));
|
|
320
|
+
if (!hasGenericPayloadKeys) return null;
|
|
321
|
+
|
|
322
|
+
const name = value.name || value.tool || value.tool_name || value.function_name || null;
|
|
323
|
+
if (typeof name !== 'string' || !name.trim()) return null;
|
|
324
|
+
|
|
325
|
+
const args = value.arguments ?? value.args ?? value.input ?? value.parameters ?? value.params ?? value.tool_input ?? value.function_arguments ?? {};
|
|
326
|
+
return { name, args };
|
|
327
|
+
}
|
|
328
|
+
|
|
307
329
|
export function formatToolCallsForMessage(toolCalls) {
|
|
308
330
|
return toolCalls.map((tc) => ({
|
|
309
331
|
id: tc.id,
|
package/src/tools/executor.js
CHANGED
|
@@ -861,20 +861,20 @@ export class ToolExecutor {
|
|
|
861
861
|
|
|
862
862
|
async mcp(serverName, toolName, argumentsObject = {}) {
|
|
863
863
|
if (typeof serverName !== 'string' || serverName.trim() === '') {
|
|
864
|
-
return { success: false, error: 'server is required' };
|
|
864
|
+
return { success: false, error: 'server is required', recovery: 'Example: MCP {"server":"filesystem","tool":"read_file","arguments":{}}' };
|
|
865
865
|
}
|
|
866
866
|
if (typeof toolName !== 'string' || toolName.trim() === '') {
|
|
867
|
-
return { success: false, error: 'tool is required' };
|
|
867
|
+
return { success: false, error: 'tool is required', recovery: 'Example: MCP {"server":"filesystem","tool":"read_file","arguments":{}}' };
|
|
868
868
|
}
|
|
869
869
|
|
|
870
870
|
const allowed = await this.permissionManager.isMcpServerAllowed(serverName);
|
|
871
871
|
if (!allowed) {
|
|
872
|
-
return { success: false, error: `MCP server not allowlisted: ${serverName}
|
|
872
|
+
return { success: false, error: `MCP server not allowlisted: ${serverName}`, recovery: 'Allowlist this MCP server only after verifying it is trusted, then retry the same tool call.' };
|
|
873
873
|
}
|
|
874
874
|
|
|
875
875
|
const client = await this.getMcpClient(serverName);
|
|
876
876
|
if (!client) {
|
|
877
|
-
return { success: false, error: `MCP server not configured: ${serverName}
|
|
877
|
+
return { success: false, error: `MCP server not configured: ${serverName}`, recovery: 'Configure this MCP server in Winter config before calling its tools, or choose a configured server.' };
|
|
878
878
|
}
|
|
879
879
|
|
|
880
880
|
const retryPolicy = await this.getRetryPolicy();
|
|
@@ -882,7 +882,7 @@ export class ToolExecutor {
|
|
|
882
882
|
const result = await withRetry(() => client.callTool(toolName, argumentsObject), retryPolicy);
|
|
883
883
|
return { success: true, server: serverName, tool: toolName, result };
|
|
884
884
|
} catch (error) {
|
|
885
|
-
return { success: false, error: error.message, server: serverName, tool: toolName };
|
|
885
|
+
return { success: false, error: error.message, server: serverName, tool: toolName, recovery: 'Inspect the MCP server error, verify the tool name and arguments, then retry with corrected arguments.' };
|
|
886
886
|
}
|
|
887
887
|
}
|
|
888
888
|
|
|
@@ -1098,7 +1098,7 @@ export class ToolExecutor {
|
|
|
1098
1098
|
|
|
1099
1099
|
async readFile(filePath) {
|
|
1100
1100
|
if (!filePath) {
|
|
1101
|
-
return { success: false, error: 'file_path is required' };
|
|
1101
|
+
return { success: false, error: 'file_path is required', recovery: 'Example: Read {"file_path":"src/app.js"}' };
|
|
1102
1102
|
}
|
|
1103
1103
|
|
|
1104
1104
|
try {
|
|
@@ -1142,7 +1142,7 @@ export class ToolExecutor {
|
|
|
1142
1142
|
].join(' '),
|
|
1143
1143
|
};
|
|
1144
1144
|
}
|
|
1145
|
-
return { success: false, error: error.message, code: error?.code, path: filePath };
|
|
1145
|
+
return { success: false, error: error.message, code: error?.code, path: filePath, recovery: 'Check the path, permissions, and workspace boundary. Use Glob to confirm the file exists before retrying.' };
|
|
1146
1146
|
}
|
|
1147
1147
|
}
|
|
1148
1148
|
|
|
@@ -1210,10 +1210,10 @@ export class ToolExecutor {
|
|
|
1210
1210
|
|
|
1211
1211
|
async writeFile(filePath, content) {
|
|
1212
1212
|
if (!filePath) {
|
|
1213
|
-
return { success: false, error: 'file_path is required' };
|
|
1213
|
+
return { success: false, error: 'file_path is required', recovery: 'Example: Write {"file_path":"src/app.js","content":"..."}' };
|
|
1214
1214
|
}
|
|
1215
1215
|
if (typeof content !== 'string') {
|
|
1216
|
-
return { success: false, error: 'content is required', path: filePath };
|
|
1216
|
+
return { success: false, error: 'content is required', path: filePath, recovery: 'Example: Write {"file_path":"src/app.js","content":"..."}' };
|
|
1217
1217
|
}
|
|
1218
1218
|
|
|
1219
1219
|
try {
|
|
@@ -1236,7 +1236,7 @@ export class ToolExecutor {
|
|
|
1236
1236
|
|
|
1237
1237
|
return { success: true, path: filePath, size: content.length, diff: diffOutput };
|
|
1238
1238
|
} catch (error) {
|
|
1239
|
-
return { success: false, error: error.message, path: filePath };
|
|
1239
|
+
return { success: false, error: error.message, path: filePath, recovery: 'Check that the path is inside the workspace and writable. If editing, use Read first to confirm exact content.' };
|
|
1240
1240
|
}
|
|
1241
1241
|
}
|
|
1242
1242
|
|
|
@@ -1319,7 +1319,7 @@ export class ToolExecutor {
|
|
|
1319
1319
|
|
|
1320
1320
|
async editFile(filePath, oldString, newString) {
|
|
1321
1321
|
if (!filePath) {
|
|
1322
|
-
return { success: false, error: 'file_path is required' };
|
|
1322
|
+
return { success: false, error: 'file_path is required', recovery: 'Example: Read {"file_path":"src/app.js"}' };
|
|
1323
1323
|
}
|
|
1324
1324
|
if (typeof oldString !== 'string' || typeof newString !== 'string') {
|
|
1325
1325
|
return {
|
|
@@ -1355,13 +1355,13 @@ export class ToolExecutor {
|
|
|
1355
1355
|
|
|
1356
1356
|
return { success: true, path: filePath, replacements: 1, diff: diffOutput };
|
|
1357
1357
|
} catch (error) {
|
|
1358
|
-
return { success: false, error: error.message, path: filePath };
|
|
1358
|
+
return { success: false, error: error.message, path: filePath, recovery: 'Check that the path is inside the workspace and writable. If editing, use Read first to confirm exact content.' };
|
|
1359
1359
|
}
|
|
1360
1360
|
}
|
|
1361
1361
|
|
|
1362
1362
|
async bash(command, cwd, timeout = 60000, shell = 'auto') {
|
|
1363
1363
|
if (typeof command !== 'string' || command.trim() === '') {
|
|
1364
|
-
return { success: false, error: 'command is required', exitCode: 1 };
|
|
1364
|
+
return { success: false, error: 'command is required', exitCode: 1, recovery: 'Example: Bash {"command":"npm test"}' };
|
|
1365
1365
|
}
|
|
1366
1366
|
|
|
1367
1367
|
timeout = parseInt(timeout, 10);
|
|
@@ -1402,7 +1402,8 @@ export class ToolExecutor {
|
|
|
1402
1402
|
error: error.message,
|
|
1403
1403
|
stdout: error.stdout || '',
|
|
1404
1404
|
stderr: error.stderr || '',
|
|
1405
|
-
exitCode: error.code || 1
|
|
1405
|
+
exitCode: error.code || 1,
|
|
1406
|
+
recovery: 'Read stderr/stdout, fix the first concrete error, then retry with a corrected command. Do not retry the same failing command unchanged.'
|
|
1406
1407
|
};
|
|
1407
1408
|
}
|
|
1408
1409
|
}
|
|
@@ -1466,7 +1467,7 @@ export class ToolExecutor {
|
|
|
1466
1467
|
cwd = normalizedRequest.cwd;
|
|
1467
1468
|
|
|
1468
1469
|
if (typeof pattern !== 'string' || pattern.trim() === '') {
|
|
1469
|
-
return { success: false, error: 'pattern is required', pattern, cwd };
|
|
1470
|
+
return { success: false, error: 'pattern is required', pattern, cwd, recovery: 'Example: Glob {"pattern":"src/**/*.js"}' };
|
|
1470
1471
|
}
|
|
1471
1472
|
|
|
1472
1473
|
try {
|
|
@@ -1479,7 +1480,7 @@ export class ToolExecutor {
|
|
|
1479
1480
|
count: files.length
|
|
1480
1481
|
};
|
|
1481
1482
|
} catch (error) {
|
|
1482
|
-
return { success: false, error: error.message, pattern, cwd };
|
|
1483
|
+
return { success: false, error: error.message, pattern, cwd, recovery: 'Check the glob pattern and cwd. Example: Glob {"pattern":"src/**/*.js","cwd":"."}' };
|
|
1483
1484
|
}
|
|
1484
1485
|
}
|
|
1485
1486
|
|
|
@@ -1648,7 +1649,7 @@ export class ToolExecutor {
|
|
|
1648
1649
|
|
|
1649
1650
|
async grep(pattern, searchPath, globPattern, outputMode = 'content', options = {}) {
|
|
1650
1651
|
if (typeof pattern !== 'string' || pattern === '') {
|
|
1651
|
-
return { success: false, error: 'pattern is required', pattern, path: searchPath };
|
|
1652
|
+
return { success: false, error: 'pattern is required', pattern, path: searchPath, recovery: 'Example: Grep {"pattern":"TODO","path":"src"}' };
|
|
1652
1653
|
}
|
|
1653
1654
|
|
|
1654
1655
|
const caseInsensitive = options.case_insensitive || options.ignoreCase || false;
|
|
@@ -1750,7 +1751,7 @@ export class ToolExecutor {
|
|
|
1750
1751
|
output_mode: outputMode
|
|
1751
1752
|
};
|
|
1752
1753
|
} catch (error) {
|
|
1753
|
-
return { success: false, error: error.message, pattern, path: searchPath };
|
|
1754
|
+
return { success: false, error: error.message, pattern, path: searchPath, recovery: 'If this is a regex issue, retry with fixed_string: true. Also verify the search path exists.' };
|
|
1754
1755
|
}
|
|
1755
1756
|
}
|
|
1756
1757
|
|
|
@@ -1854,10 +1855,10 @@ export class ToolExecutor {
|
|
|
1854
1855
|
|
|
1855
1856
|
async lsp(operation, input, filePath) {
|
|
1856
1857
|
if (typeof operation !== 'string' || operation.trim() === '') {
|
|
1857
|
-
return { success: false, error: 'operation is required' };
|
|
1858
|
+
return { success: false, error: 'operation is required', recovery: 'Example: LSP {"operation":"definition","file_path":"src/app.js"}' };
|
|
1858
1859
|
}
|
|
1859
1860
|
if (!filePath) {
|
|
1860
|
-
return { success: false, error: 'file_path is required' };
|
|
1861
|
+
return { success: false, error: 'file_path is required', recovery: 'Example: Read {"file_path":"src/app.js"}' };
|
|
1861
1862
|
}
|
|
1862
1863
|
|
|
1863
1864
|
return {
|
|
@@ -1870,10 +1871,10 @@ export class ToolExecutor {
|
|
|
1870
1871
|
|
|
1871
1872
|
async taskCreate(title, description) {
|
|
1872
1873
|
if (typeof title !== 'string' || title.trim() === '') {
|
|
1873
|
-
return { success: false, error: 'title is required' };
|
|
1874
|
+
return { success: false, error: 'title is required', recovery: 'Example: TaskCreate {"title":"Fix failing executor test","description":"Investigate and patch the failing path"}' };
|
|
1874
1875
|
}
|
|
1875
1876
|
if (!this.repl?.session?.createPlan) {
|
|
1876
|
-
return { success: false, error: 'session manager is not available' };
|
|
1877
|
+
return { success: false, error: 'session manager is not available', recovery: 'Task tools require an active Winter REPL session. Use the built-in plan/task UI from an interactive session, or continue without task persistence.' };
|
|
1877
1878
|
}
|
|
1878
1879
|
|
|
1879
1880
|
const task = await this.repl.session.createPlan(title, description);
|
|
@@ -1882,29 +1883,29 @@ export class ToolExecutor {
|
|
|
1882
1883
|
|
|
1883
1884
|
async taskUpdate(taskId, updates) {
|
|
1884
1885
|
if (typeof taskId !== 'string' || taskId.trim() === '') {
|
|
1885
|
-
return { success: false, error: 'task_id is required' };
|
|
1886
|
+
return { success: false, error: 'task_id is required', recovery: 'Example: TaskUpdate {"task_id":"task-123","updates":{"status":"done"}}' };
|
|
1886
1887
|
}
|
|
1887
1888
|
if (!this.repl?.session?.updatePlan) {
|
|
1888
|
-
return { success: false, error: 'session manager is not available' };
|
|
1889
|
+
return { success: false, error: 'session manager is not available', recovery: 'Task tools require an active Winter REPL session. Use the built-in plan/task UI from an interactive session, or continue without task persistence.' };
|
|
1889
1890
|
}
|
|
1890
1891
|
|
|
1891
1892
|
const task = await this.repl.session.updatePlan(taskId, updates);
|
|
1892
1893
|
if (!task) {
|
|
1893
|
-
return { success: false, error: 'Task not found', taskId };
|
|
1894
|
+
return { success: false, error: 'Task not found', taskId, recovery: 'Check the task ID from TaskList or the REPL plan UI, then retry TaskUpdate with the exact task_id.' };
|
|
1894
1895
|
}
|
|
1895
1896
|
return { success: true, task };
|
|
1896
1897
|
}
|
|
1897
1898
|
|
|
1898
1899
|
async taskList() {
|
|
1899
1900
|
if (!this.repl?.session?.getPlans) {
|
|
1900
|
-
return { success: false, error: 'session manager is not available' };
|
|
1901
|
+
return { success: false, error: 'session manager is not available', recovery: 'Task tools require an active Winter REPL session. Use the built-in plan/task UI from an interactive session, or continue without task persistence.' };
|
|
1901
1902
|
}
|
|
1902
1903
|
return { success: true, tasks: this.repl.session.getPlans() };
|
|
1903
1904
|
}
|
|
1904
1905
|
|
|
1905
1906
|
async parallelExecute(calls = [], context = {}) {
|
|
1906
1907
|
if (!Array.isArray(calls) || calls.length === 0) {
|
|
1907
|
-
return { success: false, error: 'tools must be a non-empty array' };
|
|
1908
|
+
return { success: false, error: 'tools must be a non-empty array', recovery: 'Example: Parallel {"tools":[{"name":"Read","input":{"file_path":"src/app.js"}}]}' };
|
|
1908
1909
|
}
|
|
1909
1910
|
|
|
1910
1911
|
const safeCalls = calls.slice(0, 8).map((call, index) => ({
|
|
@@ -1948,7 +1949,7 @@ export class ToolExecutor {
|
|
|
1948
1949
|
|
|
1949
1950
|
async webFetch(url, prompt) {
|
|
1950
1951
|
if (typeof url !== 'string' || url.trim() === '') {
|
|
1951
|
-
return { success: false, error: 'url is required' };
|
|
1952
|
+
return { success: false, error: 'url is required', recovery: 'Example: WebFetch {"url":"https://example.com"}. Include the https:// scheme.' };
|
|
1952
1953
|
}
|
|
1953
1954
|
|
|
1954
1955
|
try {
|
|
@@ -1969,13 +1970,13 @@ export class ToolExecutor {
|
|
|
1969
1970
|
length: cleanText.length
|
|
1970
1971
|
};
|
|
1971
1972
|
} catch (error) {
|
|
1972
|
-
return { success: false, error: error.message, url };
|
|
1973
|
+
return { success: false, error: error.message, url, recovery: 'Verify the URL is reachable and includes https://. If the page needs JavaScript, use BrowserDebug.' };
|
|
1973
1974
|
}
|
|
1974
1975
|
}
|
|
1975
1976
|
|
|
1976
1977
|
async webSearch(query) {
|
|
1977
1978
|
if (typeof query !== 'string' || query.trim() === '') {
|
|
1978
|
-
return { success: false, error: 'query is required' };
|
|
1979
|
+
return { success: false, error: 'query is required', recovery: 'Example: WebSearch {"query":"winter cli"}' };
|
|
1979
1980
|
}
|
|
1980
1981
|
|
|
1981
1982
|
try {
|
|
@@ -2001,7 +2002,7 @@ export class ToolExecutor {
|
|
|
2001
2002
|
count: results.length,
|
|
2002
2003
|
};
|
|
2003
2004
|
} catch (error) {
|
|
2004
|
-
return { success: false, error: error.message, query };
|
|
2005
|
+
return { success: false, error: error.message, query, recovery: 'Check network access, simplify the query, then retry WebSearch.' };
|
|
2005
2006
|
}
|
|
2006
2007
|
}
|
|
2007
2008
|
|
|
@@ -2025,7 +2026,7 @@ export class ToolExecutor {
|
|
|
2025
2026
|
}
|
|
2026
2027
|
|
|
2027
2028
|
async browserDebug(url, action) {
|
|
2028
|
-
if (!url) return { success: false, error: 'url is required' };
|
|
2029
|
+
if (!url) return { success: false, error: 'url is required', recovery: 'Example: WebFetch {"url":"https://example.com"}. Include the https:// scheme.' };
|
|
2029
2030
|
|
|
2030
2031
|
try {
|
|
2031
2032
|
const retryPolicy = await this.getRetryPolicy();
|
|
@@ -2033,7 +2034,7 @@ export class ToolExecutor {
|
|
|
2033
2034
|
try {
|
|
2034
2035
|
puppeteer = (await import('puppeteer')).default;
|
|
2035
2036
|
} catch (e) {
|
|
2036
|
-
return { success: false, error: 'Thư viện puppeteer chưa được cài đặt.
|
|
2037
|
+
return { success: false, error: 'Thư viện puppeteer chưa được cài đặt.', recovery: 'Run Bash {"command":"npm install puppeteer --no-save"} if browser automation is required, or use WebFetch for non-JavaScript pages.' };
|
|
2037
2038
|
}
|
|
2038
2039
|
|
|
2039
2040
|
const browser = await withRetry(() => puppeteer.launch({ headless: 'new' }), retryPolicy);
|
|
@@ -2071,7 +2072,7 @@ export class ToolExecutor {
|
|
|
2071
2072
|
actionResult
|
|
2072
2073
|
};
|
|
2073
2074
|
} catch (e) {
|
|
2074
|
-
return { success: false, error: e.message, url };
|
|
2075
|
+
return { success: false, error: e.message, url, recovery: 'Check that the dev server/page is reachable, then retry BrowserDebug with a valid URL and smaller action.' };
|
|
2075
2076
|
}
|
|
2076
2077
|
}
|
|
2077
2078
|
|
|
@@ -2079,14 +2080,14 @@ export class ToolExecutor {
|
|
|
2079
2080
|
const inputPath = this.resolveInputPath(input.input_path ?? input.inputPath ?? input.input, cwd);
|
|
2080
2081
|
const outputPath = this.resolveInputPath(input.output_path ?? input.outputPath ?? input.output, cwd);
|
|
2081
2082
|
if (!inputPath || !outputPath) {
|
|
2082
|
-
return { success: false, error: 'input_path and output_path are required' };
|
|
2083
|
+
return { success: false, error: 'input_path and output_path are required', recovery: 'Example: HtmlEffectiveness {"input_path":"page.md","output_path":"dist/page.html"}' };
|
|
2083
2084
|
}
|
|
2084
2085
|
|
|
2085
2086
|
const autoInstall = input.auto_install ?? input.autoInstall ?? true;
|
|
2086
2087
|
const info = await this.htmlFxManager.info();
|
|
2087
2088
|
if (!info.binaryReady) {
|
|
2088
2089
|
if (!autoInstall) {
|
|
2089
|
-
return { success: false, error: 'html-effectiveness compiler is not installed. Run winter htmlfx install first.' };
|
|
2090
|
+
return { success: false, error: 'html-effectiveness compiler is not installed. Run winter htmlfx install first.', recovery: 'Run winter htmlfx install first, or retry with auto_install: true.' };
|
|
2090
2091
|
}
|
|
2091
2092
|
await this.htmlFxManager.ensureInstalled({ update: false });
|
|
2092
2093
|
}
|