tune-basic-toolset 0.1.12 → 0.1.14
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/cmd.tool.js +1 -1
- package/src/curry.proc.js +6 -22
- package/src/grep.tool.js +1 -1
- package/src/jina_r.tool.js +2 -2
- package/src/js.tool.js +2 -2
- package/src/log.proc.js +16 -11
- package/src/patch.tool.js +45 -21
- package/src/powershell.tool.js +1 -1
- package/src/proc.proc.js +1 -109
- package/src/rf.schema.json +2 -1
- package/src/rf.tool.js +3 -3
- package/src/sh.tool.js +2 -2
- package/src/shp.proc.js +1 -1
- package/src/sqlite.tool.js +1 -1
- package/src/utils.js +112 -0
package/package.json
CHANGED
package/src/cmd.tool.js
CHANGED
package/src/curry.proc.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { parseArgs } = require('./utils.js')
|
|
2
|
+
|
|
1
3
|
module.exports = async function curry(node, args, ctx) {
|
|
2
4
|
if (!node || node.type !== 'tool' ) {
|
|
3
5
|
throw Error('curry can only modify tool')
|
|
@@ -6,25 +8,7 @@ module.exports = async function curry(node, args, ctx) {
|
|
|
6
8
|
// parse args string to object
|
|
7
9
|
// supports key=value pairs where value can be quoted string
|
|
8
10
|
// keys can optionally start with $
|
|
9
|
-
|
|
10
|
-
const parsedArgs = {};
|
|
11
|
-
// regex to split on spaces but keep quoted substrings together
|
|
12
|
-
const regex = /([^\s"']+|"[^"]*"|'[^']*')+/g;
|
|
13
|
-
const tokens = args.match(regex) || [];
|
|
14
|
-
|
|
15
|
-
tokens.forEach(token => {
|
|
16
|
-
const equalIndex = token.indexOf('=');
|
|
17
|
-
if (equalIndex > 0) {
|
|
18
|
-
const key = token.substring(0, equalIndex);
|
|
19
|
-
let value = token.substring(equalIndex + 1);
|
|
20
|
-
|
|
21
|
-
// strip double or single quotes from value if present
|
|
22
|
-
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
23
|
-
value = value.substring(1, value.length - 1);
|
|
24
|
-
}
|
|
25
|
-
parsedArgs[key] = value;
|
|
26
|
-
}
|
|
27
|
-
});
|
|
11
|
+
const parsedArgs = parseArgs(args.trim())
|
|
28
12
|
const schema = { ...node.schema }
|
|
29
13
|
const curryParams = {}
|
|
30
14
|
const newNode = {
|
|
@@ -35,10 +19,10 @@ module.exports = async function curry(node, args, ctx) {
|
|
|
35
19
|
for(const key in parsedArgs) {
|
|
36
20
|
if (key.indexOf("$") === -1) {
|
|
37
21
|
curryParams[key] = parsedArgs[key]
|
|
38
|
-
if (
|
|
39
|
-
throw Error(`parameter ${key} is not defined in ${node.name}'s schema`)
|
|
22
|
+
if (schema.parameters.properties[key]) {
|
|
23
|
+
// throw Error(`parameter ${key} is not defined in ${node.name}'s schema`)
|
|
24
|
+
delete schema.parameters.properties[key]
|
|
40
25
|
}
|
|
41
|
-
delete schema.parameters.properties[key]
|
|
42
26
|
const idx = (schema.parameters.required || []).indexOf(key)
|
|
43
27
|
if (idx !== -1) {
|
|
44
28
|
schema.parameters.required.splice(idx, 1)
|
package/src/grep.tool.js
CHANGED
|
@@ -12,5 +12,5 @@ module.exports = async function grep({filename, text, regex, regex_flags}, ctx)
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
const r = new RegExp(regex, regex_flags)
|
|
15
|
-
return text.split(/\r?\n/).filter(line => r.test(line)).join("\n")
|
|
15
|
+
return text.split(/\r?\n/).filter(line => r.test(line)).join("\n")
|
|
16
16
|
}
|
package/src/jina_r.tool.js
CHANGED
package/src/js.tool.js
CHANGED
|
@@ -53,8 +53,8 @@ module.exports = async function execute({ text, inputType }, ctx) {
|
|
|
53
53
|
input: modifiedCode,
|
|
54
54
|
});
|
|
55
55
|
|
|
56
|
-
return (res.stderr + res.stdout).trim()
|
|
56
|
+
return (res.stderr + res.stdout).trim()
|
|
57
57
|
} finally {
|
|
58
58
|
unlinkSync(filename);
|
|
59
59
|
}
|
|
60
|
-
};
|
|
60
|
+
};
|
package/src/log.proc.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
const fs = require("fs")
|
|
2
2
|
const path = require("path")
|
|
3
3
|
|
|
4
|
-
module.exports = async (node, args, ctx) =>
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const res = await node.exec(payload, ctx)
|
|
8
|
-
const body = JSON.parse(res.body)
|
|
9
|
-
payload = {...res, body};
|
|
10
|
-
const filename = args.trim() || "log.json"
|
|
11
|
-
const content = path.extname(filename) == ".chat" ? ctx.msg2text(payload.body.messages, true) : JSON.stringify(payload, null, " ")
|
|
12
|
-
fs.writeFileSync(filename, content);
|
|
13
|
-
return res
|
|
4
|
+
module.exports = async (node, args, ctx) => {
|
|
5
|
+
if (!node || node.type !== 'llm') {
|
|
6
|
+
throw Error("llm required for 'log' processor")
|
|
14
7
|
}
|
|
15
|
-
|
|
8
|
+
return ({
|
|
9
|
+
...node,
|
|
10
|
+
exec: async function(payload, ctx) {
|
|
11
|
+
const res = await node.exec(payload, ctx)
|
|
12
|
+
const body = JSON.parse(res.body)
|
|
13
|
+
payload = {...res, body};
|
|
14
|
+
const filename = args.trim() || "log.json"
|
|
15
|
+
const content = path.extname(filename) == ".chat" ? ctx.msg2text(payload.body.messages, true) : JSON.stringify(payload, null, " ")
|
|
16
|
+
fs.writeFileSync(filename, content);
|
|
17
|
+
return res
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
}
|
package/src/patch.tool.js
CHANGED
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
const fs = require('fs').promises;
|
|
2
2
|
|
|
3
3
|
// Patch tool to apply custom diffs marked with <<<<<<< ORIGINAL and >>>>>>> UPDATED
|
|
4
|
-
//
|
|
5
|
-
|
|
4
|
+
// More tolerant to whitespace differences on each line and reports per-block success.
|
|
6
5
|
module.exports = async function patch({ text, filename }, ctx) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const patchRegex = /<{6,}\s*ORIGINAL[^\n]*\n([\s\S]*?)=+\n([\s\S]*?)>{6,}\s*UPDATED[^\n]*(?:\n|$)/g;
|
|
11
|
-
const patches = [];
|
|
12
|
-
let match;
|
|
6
|
+
if (!text || !filename) {
|
|
7
|
+
return "No patch text or filename provided";
|
|
8
|
+
}
|
|
13
9
|
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
// Match: <<<<<<< ORIGINAL ... ======= ... >>>>>>> UPDATED
|
|
11
|
+
// Be tolerant to CRLF/LF and optional trailing text/spaces on the markers.
|
|
12
|
+
const patchRegex = /<{6,}\s*ORIGINAL[^\n]*\r?\n([\s\S]*?)=+[^\n]*\r?\n([\s\S]*?)>{6,}\s*UPDATED[^\n]*(?:\r?\n|$)/g;
|
|
13
|
+
|
|
14
|
+
const patches = [];
|
|
15
|
+
let m;
|
|
16
|
+
while ((m = patchRegex.exec(text)) !== null) {
|
|
17
|
+
const oldPart = String(m[1]).replace(/^\s*\r?\n+|\r?\n+\s*$/g, "");
|
|
18
|
+
const newPart = String(m[2]).replace(/^\s*\r?\n+|\r?\n+\s*$/g, "");
|
|
18
19
|
patches.push({ oldPart, newPart });
|
|
19
20
|
}
|
|
20
21
|
|
|
@@ -24,18 +25,41 @@ module.exports = async function patch({ text, filename }, ctx) {
|
|
|
24
25
|
|
|
25
26
|
let fileContent = await ctx.read(filename);
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
// Escape regex
|
|
29
|
-
|
|
30
|
-
//
|
|
31
|
-
let escaped = oldPart.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
28
|
+
function buildPattern(oldStr) {
|
|
29
|
+
// Escape special regex chars
|
|
30
|
+
let escaped = oldStr.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
// Normalize line endings to \r?\n so CRLF/LF both match
|
|
32
32
|
escaped = escaped.replace(/\r?\n/g, "\\r?\\n");
|
|
33
|
-
|
|
33
|
+
// Tolerate indentation/space differences (spaces or tabs), zero-or-more
|
|
34
|
+
// Keep newlines strict so structure must still match.
|
|
35
|
+
escaped = escaped.replace(/[ \t]+/g, "[ \\t]*");
|
|
36
|
+
return new RegExp(escaped, "g");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const totalSegments = patches.length;
|
|
40
|
+
let appliedSegments = 0;
|
|
41
|
+
let totalReplacements = 0;
|
|
34
42
|
|
|
35
|
-
|
|
36
|
-
|
|
43
|
+
for (const { oldPart, newPart } of patches) {
|
|
44
|
+
const re = buildPattern(oldPart);
|
|
45
|
+
let matches = 0;
|
|
46
|
+
fileContent = fileContent.replace(re, () => {
|
|
47
|
+
matches += 1;
|
|
48
|
+
return newPart;
|
|
49
|
+
});
|
|
50
|
+
if (matches > 0) {
|
|
51
|
+
appliedSegments += 1;
|
|
52
|
+
totalReplacements += matches;
|
|
53
|
+
}
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
await ctx.write(filename, fileContent);
|
|
40
|
-
|
|
57
|
+
|
|
58
|
+
if (appliedSegments === 0) {
|
|
59
|
+
return `no matches applied (0/${totalSegments})`;
|
|
60
|
+
}
|
|
61
|
+
if (appliedSegments < totalSegments) {
|
|
62
|
+
return `patched partially (${appliedSegments}/${totalSegments}), replacements: ${totalReplacements}`;
|
|
63
|
+
}
|
|
64
|
+
return `patched (${appliedSegments}/${totalSegments}), replacements: ${totalReplacements}`;
|
|
41
65
|
};
|
package/src/powershell.tool.js
CHANGED
package/src/proc.proc.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { parseCommandLine } = require('./utils.js')
|
|
1
2
|
|
|
2
3
|
module.exports = async function proc(node, args, ctx) {
|
|
3
4
|
/*
|
|
@@ -25,113 +26,4 @@ module.exports = async function proc(node, args, ctx) {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
// Examples:
|
|
29
|
-
// parseCommandLine('command hello world bla bla')
|
|
30
|
-
// -> ["command", { text: "hello world bla bla" }]
|
|
31
|
-
//
|
|
32
|
-
// parseCommandLine('cmd hello=world num=8 text="bla \\"bla"')
|
|
33
|
-
// -> ["cmd", { hello: "world", num: 8, text: 'bla "bla' }]
|
|
34
|
-
//
|
|
35
|
-
// parseCommandLine('cmd')
|
|
36
|
-
// -> ["cmd", {}]
|
|
37
29
|
|
|
38
|
-
function parseCommandLine(input) {
|
|
39
|
-
const s = String(input);
|
|
40
|
-
let i = 0, len = s.length;
|
|
41
|
-
|
|
42
|
-
function skipWS() { while (i < len && /\s/.test(s[i])) i++; }
|
|
43
|
-
|
|
44
|
-
// 1) Parse leading alphanumeric command
|
|
45
|
-
skipWS();
|
|
46
|
-
const cmdStart = i;
|
|
47
|
-
while (i < len && /[A-Za-z0-9_\-]/.test(s[i])) i++;
|
|
48
|
-
const command = s.slice(cmdStart, i);
|
|
49
|
-
if (!command) return [null, {}];
|
|
50
|
-
|
|
51
|
-
// 2) Parse the remainder as args
|
|
52
|
-
skipWS();
|
|
53
|
-
const r = s.slice(i);
|
|
54
|
-
if (!r.trim()) return [command, {}];
|
|
55
|
-
|
|
56
|
-
function parseArgs(str) {
|
|
57
|
-
if (!/^\s*[A-Za-z0-9]+=/.test(str)) {
|
|
58
|
-
return { text: str.trim() };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
let j = 0;
|
|
62
|
-
const L = str.length;
|
|
63
|
-
const out = {};
|
|
64
|
-
|
|
65
|
-
function skipW() { while (j < L && /\s/.test(str[j])) j++; }
|
|
66
|
-
|
|
67
|
-
function parseKey() {
|
|
68
|
-
const start = j;
|
|
69
|
-
while (j < L && str[j] !== '=' && !/\s/.test(str[j])) j++;
|
|
70
|
-
return str.slice(start, j);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function parseQuotedValue(q) {
|
|
74
|
-
j++; // skip opening quote
|
|
75
|
-
let val = '';
|
|
76
|
-
while (j < L) {
|
|
77
|
-
const ch = str[j++];
|
|
78
|
-
if (ch === '\\') {
|
|
79
|
-
if (j >= L) break;
|
|
80
|
-
const esc = str[j++];
|
|
81
|
-
if (esc === 'n') val += '\n';
|
|
82
|
-
else if (esc === 't') val += '\t';
|
|
83
|
-
else if (esc === 'r') val += '\r';
|
|
84
|
-
else val += esc; // includes \" \\ \'
|
|
85
|
-
} else if (ch === q) {
|
|
86
|
-
return val;
|
|
87
|
-
} else {
|
|
88
|
-
val += ch;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return val; // best-effort if unclosed
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function parseUnquotedValue() {
|
|
95
|
-
const start = j;
|
|
96
|
-
while (j < L && !/\s/.test(str[j])) j++;
|
|
97
|
-
return str.slice(start, j);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function coerce(v) {
|
|
101
|
-
if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v);
|
|
102
|
-
const low = v.toLowerCase();
|
|
103
|
-
if (low === 'true') return true;
|
|
104
|
-
if (low === 'false') return false;
|
|
105
|
-
if (low === 'null') return null;
|
|
106
|
-
return v;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
while (j < L) {
|
|
110
|
-
skipW();
|
|
111
|
-
if (j >= L) break;
|
|
112
|
-
|
|
113
|
-
const key = parseKey();
|
|
114
|
-
if (!key) return { text: str.trim() };
|
|
115
|
-
|
|
116
|
-
skipW();
|
|
117
|
-
if (j < L && str[j] === '=') {
|
|
118
|
-
j++; // skip '='
|
|
119
|
-
skipW();
|
|
120
|
-
let valueStr = '';
|
|
121
|
-
if (j < L && (str[j] === '"' || str[j] === "'")) {
|
|
122
|
-
valueStr = parseQuotedValue(str[j]);
|
|
123
|
-
} else {
|
|
124
|
-
valueStr = parseUnquotedValue();
|
|
125
|
-
}
|
|
126
|
-
out[key] = coerce(valueStr);
|
|
127
|
-
} else {
|
|
128
|
-
// If a non key=value token appears, treat the whole remainder as text
|
|
129
|
-
return { text: str.trim() };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return out;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return [command, parseArgs(r)];
|
|
137
|
-
}
|
package/src/rf.schema.json
CHANGED
package/src/rf.tool.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const { relative, dirname } = require('path');
|
|
2
2
|
|
|
3
|
-
module.exports = async function readFile({ filename, linenum }, ctx) {
|
|
3
|
+
module.exports = async function readFile({ filename, linenum, autotext }, ctx) {
|
|
4
4
|
const resolved = await ctx.resolve(filename);
|
|
5
5
|
if (!resolved) {
|
|
6
6
|
return "File not found";
|
|
7
7
|
}
|
|
8
8
|
const relFile = relative(process.cwd(), filename);
|
|
9
9
|
const pathArr = [ relFile ];
|
|
10
|
-
if (resolved.type !== 'text') {
|
|
10
|
+
if (resolved.type !== 'text' && ((typeof autotext === 'undefined') || autotext) && resolved.read) {
|
|
11
11
|
pathArr.push('text');
|
|
12
12
|
}
|
|
13
13
|
if (linenum) {
|
|
@@ -19,5 +19,5 @@ module.exports = async function readFile({ filename, linenum }, ctx) {
|
|
|
19
19
|
if (relFile.match(/\s+/)) {
|
|
20
20
|
return `@{${relFile}}`;
|
|
21
21
|
}
|
|
22
|
-
return `@${relFile}`;
|
|
22
|
+
return `@${relFile||"."}`;
|
|
23
23
|
};
|
package/src/sh.tool.js
CHANGED
package/src/shp.proc.js
CHANGED
package/src/sqlite.tool.js
CHANGED
package/src/utils.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
function parseArgs(str) {
|
|
2
|
+
if (!/^\s*[_$A-Za-z0-9]+=/.test(str)) {
|
|
3
|
+
return { text: str.trim() };
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
let j = 0;
|
|
7
|
+
const L = str.length;
|
|
8
|
+
const out = {};
|
|
9
|
+
|
|
10
|
+
function skipW() { while (j < L && /\s/.test(str[j])) j++; }
|
|
11
|
+
|
|
12
|
+
function parseKey() {
|
|
13
|
+
const start = j;
|
|
14
|
+
while (j < L && str[j] !== '=' && !/\s/.test(str[j])) j++;
|
|
15
|
+
return str.slice(start, j);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parseQuotedValue(q) {
|
|
19
|
+
j++; // skip opening quote
|
|
20
|
+
let val = '';
|
|
21
|
+
while (j < L) {
|
|
22
|
+
const ch = str[j++];
|
|
23
|
+
if (ch === '\\') {
|
|
24
|
+
if (j >= L) break;
|
|
25
|
+
const esc = str[j++];
|
|
26
|
+
if (esc === 'n') val += '\n';
|
|
27
|
+
else if (esc === 't') val += '\t';
|
|
28
|
+
else if (esc === 'r') val += '\r';
|
|
29
|
+
else val += esc; // includes \" \\ \'
|
|
30
|
+
} else if (ch === q) {
|
|
31
|
+
return val;
|
|
32
|
+
} else {
|
|
33
|
+
val += ch;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return val; // best-effort if unclosed
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function parseUnquotedValue() {
|
|
40
|
+
const start = j;
|
|
41
|
+
while (j < L && !/\s/.test(str[j])) j++;
|
|
42
|
+
return str.slice(start, j);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function coerce(v) {
|
|
46
|
+
if (/^-?\d+(\.\d+)?$/.test(v)) return Number(v);
|
|
47
|
+
const low = v.toLowerCase();
|
|
48
|
+
if (low === 'true') return true;
|
|
49
|
+
if (low === 'false') return false;
|
|
50
|
+
if (low === 'null') return null;
|
|
51
|
+
return v;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
while (j < L) {
|
|
55
|
+
skipW();
|
|
56
|
+
if (j >= L) break;
|
|
57
|
+
|
|
58
|
+
const key = parseKey();
|
|
59
|
+
if (!key) return { text: str.trim() };
|
|
60
|
+
|
|
61
|
+
skipW();
|
|
62
|
+
if (j < L && str[j] === '=') {
|
|
63
|
+
j++; // skip '='
|
|
64
|
+
skipW();
|
|
65
|
+
let valueStr = '';
|
|
66
|
+
if (j < L && (str[j] === '"' || str[j] === "'")) {
|
|
67
|
+
valueStr = parseQuotedValue(str[j]);
|
|
68
|
+
} else {
|
|
69
|
+
valueStr = parseUnquotedValue();
|
|
70
|
+
}
|
|
71
|
+
out[key] = coerce(valueStr);
|
|
72
|
+
} else {
|
|
73
|
+
// If a non key=value token appears, treat the whole remainder as text
|
|
74
|
+
return { text: str.trim() };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Examples:
|
|
82
|
+
// parseCommandLine('command hello world bla bla')
|
|
83
|
+
// -> ["command", { text: "hello world bla bla" }]
|
|
84
|
+
//
|
|
85
|
+
// parseCommandLine('cmd hello=world num=8 text="bla \\"bla"')
|
|
86
|
+
// -> ["cmd", { hello: "world", num: 8, text: 'bla "bla' }]
|
|
87
|
+
//
|
|
88
|
+
// parseCommandLine('cmd')
|
|
89
|
+
// -> ["cmd", {}]
|
|
90
|
+
|
|
91
|
+
function parseCommandLine(input) {
|
|
92
|
+
const s = String(input);
|
|
93
|
+
let i = 0, len = s.length;
|
|
94
|
+
|
|
95
|
+
function skipWS() { while (i < len && /\s/.test(s[i])) i++; }
|
|
96
|
+
|
|
97
|
+
// 1) Parse leading alphanumeric command
|
|
98
|
+
skipWS();
|
|
99
|
+
const cmdStart = i;
|
|
100
|
+
while (i < len && /[A-Za-z0-9_\-]/.test(s[i])) i++;
|
|
101
|
+
const command = s.slice(cmdStart, i);
|
|
102
|
+
if (!command) return [null, {}];
|
|
103
|
+
|
|
104
|
+
// 2) Parse the remainder as args
|
|
105
|
+
skipWS();
|
|
106
|
+
const r = s.slice(i);
|
|
107
|
+
if (!r.trim()) return [command, {}];
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
return [command, parseArgs(r)];
|
|
111
|
+
}
|
|
112
|
+
module.exports = { parseCommandLine, parseArgs }
|