bortexcode 1.2.4 → 1.2.6
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/bin/bortex.js +145 -8
- package/package.json +1 -1
package/bin/bortex.js
CHANGED
|
@@ -1156,17 +1156,96 @@ function classifyLocalPromptIntent(text) {
|
|
|
1156
1156
|
if (wantsStatus && (/(whoami|username|user name|hostname|host name|machine|computer|system|sistema|platform|os|runtime|shell|environment|env|path)/.test(t) || /(\bnode\b|\bnpm\b)/.test(t))) {
|
|
1157
1157
|
return { command: '/sys-status' };
|
|
1158
1158
|
}
|
|
1159
|
-
if (wantsStatus && /(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(t)) {
|
|
1159
|
+
if (wantsStatus && /(\bprocess\b|\bprocesso\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(t)) {
|
|
1160
1160
|
const processMatch = t.match(/(?:process(?:o|i)?|pid)\s+(?:di\s+|of\s+)?([a-z0-9._-]{2,})/i) || t.match(/([a-z0-9._-]{2,})\s+(?:process(?:o|i)?|pid)/i);
|
|
1161
1161
|
return { command: processMatch ? `/process-status ${processMatch[1]}` : '/process-status' };
|
|
1162
1162
|
}
|
|
1163
|
-
if (wantsStatus && /(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(t)) {
|
|
1163
|
+
if (wantsStatus && /(\bport\b|\bporta\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(t)) {
|
|
1164
1164
|
const portMatch = t.match(/\b(\d{2,5})\b/);
|
|
1165
1165
|
return { command: portMatch ? `/port-status ${portMatch[1]}` : '/port-status' };
|
|
1166
1166
|
}
|
|
1167
1167
|
return null;
|
|
1168
1168
|
}
|
|
1169
1169
|
|
|
1170
|
+
function stripMatchingQuotes(value) {
|
|
1171
|
+
const s = String(value || '').trim();
|
|
1172
|
+
if (s.length >= 2 && ((s[0] === '"' && s[s.length - 1] === '"') || (s[0] === '\'' && s[s.length - 1] === '\'') || (s[0] === '`' && s[s.length - 1] === '`'))) {
|
|
1173
|
+
return s.slice(1, -1);
|
|
1174
|
+
}
|
|
1175
|
+
return s;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
function extractNaturalFilePath(text) {
|
|
1179
|
+
const raw = String(text || '');
|
|
1180
|
+
const quotedAfterFile = raw.match(/(?:file|path|percorso)\s+["'`]([^"'`]+)["'`]/i);
|
|
1181
|
+
if (quotedAfterFile?.[1]) return quotedAfterFile[1].trim();
|
|
1182
|
+
const tokenAfterFile = raw.match(/(?:file|path|percorso)\s+([^\s,;]+)/i);
|
|
1183
|
+
if (tokenAfterFile?.[1]) return stripMatchingQuotes(tokenAfterFile[1]);
|
|
1184
|
+
const absoluteOrRelative = raw.match(/["'`]?((?:[A-Za-z]:[\\/]|\/|~\/|\.{1,2}[\\/])[^"'`\s,;:]+)["'`]?/);
|
|
1185
|
+
if (absoluteOrRelative?.[1]) return absoluteOrRelative[1].trim();
|
|
1186
|
+
return '';
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function extractNaturalFileContent(text, filePath) {
|
|
1190
|
+
const raw = String(text || '').trim();
|
|
1191
|
+
const marker = raw.match(/(?:con\s+(?:contenuto|testo)|contenente|with\s+(?:content|text)|containing)\s+([\s\S]+)$/i);
|
|
1192
|
+
let content = marker?.[1] || '';
|
|
1193
|
+
if (!content && filePath) {
|
|
1194
|
+
const beforeFile = raw.slice(0, raw.toLowerCase().indexOf(filePath.toLowerCase())).trim();
|
|
1195
|
+
const writePrefix = beforeFile.match(/(?:scrivi|write|salva|metti)\s+([\s\S]+?)(?:\s+(?:nel|nella|in|su|to)\s+(?:file|path|percorso)?\s*)?$/i);
|
|
1196
|
+
if (writePrefix?.[1]) content = writePrefix[1];
|
|
1197
|
+
}
|
|
1198
|
+
content = String(content || '').trim();
|
|
1199
|
+
if (!content) return '';
|
|
1200
|
+
if ((content[0] === '"' || content[0] === '\'' || content[0] === '`')) {
|
|
1201
|
+
const quote = content[0];
|
|
1202
|
+
const end = content.indexOf(quote, 1);
|
|
1203
|
+
if (end > 0) return content.slice(1, end);
|
|
1204
|
+
}
|
|
1205
|
+
content = content
|
|
1206
|
+
.replace(/\s+(?:e|and|poi|then)\s+(?:rispondi|reply|dimmi|dillo|fammi sapere|tell me)\b[\s\S]*$/i, '')
|
|
1207
|
+
.replace(/\s+(?:rispondi|reply)\b[\s\S]*$/i, '')
|
|
1208
|
+
.trim();
|
|
1209
|
+
return stripMatchingQuotes(content);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
function buildNaturalLocalFileActionCalls(text) {
|
|
1213
|
+
const raw = String(text || '').trim();
|
|
1214
|
+
const lower = raw.toLowerCase();
|
|
1215
|
+
if (!raw) return null;
|
|
1216
|
+
const filePath = extractNaturalFilePath(raw);
|
|
1217
|
+
if (!filePath) return null;
|
|
1218
|
+
|
|
1219
|
+
if (/(?:^|\b)(leggi|mostra|apri|read|show|cat)(?:\b|$)/i.test(raw) && /(?:file|path|percorso|\/|\\|\.\.?[\\/])/.test(raw)) {
|
|
1220
|
+
return [{ tool: 'read', path: filePath }];
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
const wantsAppend = /(?:^|\b)(appendi|accoda|aggiungi|append|add)(?:\b|$)/i.test(raw) && /(?:file|path|percorso|\/|\\|\.\.?[\\/])/.test(raw);
|
|
1224
|
+
const wantsWrite = /(?:^|\b)(crea|creare|scrivi|write|create|salva|metti)(?:\b|$)/i.test(raw) && /(?:file|path|percorso|\/|\\|\.\.?[\\/])/.test(raw);
|
|
1225
|
+
if (!wantsAppend && !wantsWrite) return null;
|
|
1226
|
+
|
|
1227
|
+
const textValue = extractNaturalFileContent(raw, filePath);
|
|
1228
|
+
if (!textValue && !/(?:^|\b)(crea|create)(?:\b|$)/i.test(raw)) return null;
|
|
1229
|
+
return [{
|
|
1230
|
+
tool: wantsAppend ? 'append' : 'write',
|
|
1231
|
+
path: filePath,
|
|
1232
|
+
text: textValue,
|
|
1233
|
+
confirm: true
|
|
1234
|
+
}];
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
async function runNaturalLocalFileAction(opts, prompt) {
|
|
1238
|
+
const calls = buildNaturalLocalFileActionCalls(prompt);
|
|
1239
|
+
if (!calls) return { handled: false };
|
|
1240
|
+
opts.lastToolRunReport = await executeStructuredToolBatch(opts, calls, {
|
|
1241
|
+
continueOnError: true,
|
|
1242
|
+
goal: prompt,
|
|
1243
|
+
source: 'natural-local-file-action',
|
|
1244
|
+
reportLabel: 'natural-local-action'
|
|
1245
|
+
});
|
|
1246
|
+
return { handled: true, data: opts.lastToolRunReport };
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1170
1249
|
async function runSshStatusCommand(opts, { quiet = false } = {}) {
|
|
1171
1250
|
const cwd = opts?.cwd || process.cwd();
|
|
1172
1251
|
const platform = os.platform();
|
|
@@ -1389,11 +1468,11 @@ function suggestCommandsForStep(stepText, opts) {
|
|
|
1389
1468
|
if ((/(whoami|username|user name|hostname|host name|machine|computer|system|sistema|platform|os|runtime|shell|environment|env|path)/.test(t) || /(\bnode\b|\bnpm\b)/.test(t)) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1390
1469
|
return ['/sys-status', '/status'];
|
|
1391
1470
|
}
|
|
1392
|
-
if (/(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(t) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1471
|
+
if (/(\bprocess\b|\bprocesso\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(t) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1393
1472
|
const processMatch = t.match(/(?:process(?:o|i)?|pid)\s+(?:di\s+|of\s+)?([a-z0-9._-]{2,})/i) || t.match(/([a-z0-9._-]{2,})\s+(?:process(?:o|i)?|pid)/i);
|
|
1394
1473
|
return [processMatch ? `/process-status ${processMatch[1]}` : '/process-status', '/status'];
|
|
1395
1474
|
}
|
|
1396
|
-
if (/(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(t) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1475
|
+
if (/(\bport\b|\bporta\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(t) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1397
1476
|
const portMatch = t.match(/\b(\d{2,5})\b/);
|
|
1398
1477
|
return [portMatch ? `/port-status ${portMatch[1]}` : '/port-status', '/status'];
|
|
1399
1478
|
}
|
|
@@ -2644,6 +2723,50 @@ async function executeStructuredBuiltinTool(opts, call) {
|
|
|
2644
2723
|
error: res.ok ? null : `${label} exit ${res.code == null ? 'null' : res.code}`
|
|
2645
2724
|
};
|
|
2646
2725
|
};
|
|
2726
|
+
if (tool === 'read') {
|
|
2727
|
+
const filePath = resolveCliPath(opts, call.path);
|
|
2728
|
+
try {
|
|
2729
|
+
const text = fs.readFileSync(filePath, 'utf8');
|
|
2730
|
+
process.stdout.write(text.endsWith('\n') ? text : `${text}\n`);
|
|
2731
|
+
return {
|
|
2732
|
+
ok: true,
|
|
2733
|
+
stdout: text,
|
|
2734
|
+
stderr: null,
|
|
2735
|
+
data: { path: filePath, bytes: Buffer.byteLength(text, 'utf8') }
|
|
2736
|
+
};
|
|
2737
|
+
} catch (err) {
|
|
2738
|
+
return { ok: false, stdout: null, stderr: err.message, data: { path: filePath }, error: err.message };
|
|
2739
|
+
}
|
|
2740
|
+
}
|
|
2741
|
+
if (tool === 'mkdir') {
|
|
2742
|
+
const dirPath = resolveCliPath(opts, call.path || '.');
|
|
2743
|
+
try {
|
|
2744
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
2745
|
+
console.log(`Mkdir ok -> ${dirPath}`);
|
|
2746
|
+
return { ok: true, stdout: `Mkdir ok -> ${dirPath}\n`, stderr: null, data: { path: dirPath } };
|
|
2747
|
+
} catch (err) {
|
|
2748
|
+
return { ok: false, stdout: null, stderr: err.message, data: { path: dirPath }, error: err.message };
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
if (tool === 'write' || tool === 'append') {
|
|
2752
|
+
const filePath = resolveCliPath(opts, call.path);
|
|
2753
|
+
const text = String(call.text ?? '');
|
|
2754
|
+
try {
|
|
2755
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
2756
|
+
if (tool === 'append') fs.appendFileSync(filePath, text, 'utf8');
|
|
2757
|
+
else fs.writeFileSync(filePath, text, 'utf8');
|
|
2758
|
+
const label = tool === 'append' ? 'Append' : 'Write';
|
|
2759
|
+
console.log(`${label} ok -> ${filePath}`);
|
|
2760
|
+
return {
|
|
2761
|
+
ok: true,
|
|
2762
|
+
stdout: `${label} ok -> ${filePath}\n`,
|
|
2763
|
+
stderr: null,
|
|
2764
|
+
data: { path: filePath, bytes: Buffer.byteLength(text, 'utf8'), mode: tool }
|
|
2765
|
+
};
|
|
2766
|
+
} catch (err) {
|
|
2767
|
+
return { ok: false, stdout: null, stderr: err.message, data: { path: filePath, mode: tool }, error: err.message };
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2647
2770
|
if (tool === 'gitStatus') {
|
|
2648
2771
|
const res = await runChild('git', ['status', '--short', ...(call.branch ? ['-b'] : [])], { cwd: opts.cwd, shell: false });
|
|
2649
2772
|
const entries = parseGitStatusShortEntries(res.stdout || '');
|
|
@@ -3222,6 +3345,11 @@ function buildStructuredToolPlanFromGoal(opts, goal) {
|
|
|
3222
3345
|
{ tool: 'review', mode: 'all', fixSuggestions: true }
|
|
3223
3346
|
];
|
|
3224
3347
|
|
|
3348
|
+
const naturalFileCalls = buildNaturalLocalFileActionCalls(g);
|
|
3349
|
+
if (naturalFileCalls) {
|
|
3350
|
+
return naturalFileCalls;
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3225
3353
|
const wantsStatus = /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/.test(lower);
|
|
3226
3354
|
if (wantsStatus && /(\bssh\b|sshd|remote login)/.test(lower)) {
|
|
3227
3355
|
return [{ tool: 'project' }, { tool: 'sshStatus' }];
|
|
@@ -3229,12 +3357,12 @@ function buildStructuredToolPlanFromGoal(opts, goal) {
|
|
|
3229
3357
|
if (wantsStatus && (/(whoami|username|user name|hostname|host name|machine|computer|system|sistema|platform|os|runtime|shell|environment|env|path)/.test(lower) || /(\bnode\b|\bnpm\b)/.test(lower))) {
|
|
3230
3358
|
return [{ tool: 'project' }, { tool: 'systemStatus' }];
|
|
3231
3359
|
}
|
|
3232
|
-
if (wantsStatus && /(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(lower)) {
|
|
3360
|
+
if (wantsStatus && /(\bprocess\b|\bprocesso\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(lower)) {
|
|
3233
3361
|
const processMatch = g.match(/(?:process(?:o|i)?|pid)\s+(?:di\s+|of\s+)?([a-z0-9._-]{2,})/i) || g.match(/([a-z0-9._-]{2,})\s+(?:process(?:o|i)?|pid)/i);
|
|
3234
3362
|
const filter = processMatch ? processMatch[1] : '';
|
|
3235
3363
|
return [{ tool: 'project' }, { tool: 'processStatus', ...(filter ? { name: filter } : {}) }];
|
|
3236
3364
|
}
|
|
3237
|
-
if (wantsStatus && /(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(lower)) {
|
|
3365
|
+
if (wantsStatus && /(\bport\b|\bporta\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(lower)) {
|
|
3238
3366
|
const portMatch = g.match(/\b(\d{2,5})\b/);
|
|
3239
3367
|
const port = portMatch ? portMatch[1] : '';
|
|
3240
3368
|
return [{ tool: 'project' }, { tool: 'portStatus', ...(port ? { port } : {}) }];
|
|
@@ -3763,7 +3891,7 @@ function makeSimplePlan(goal) {
|
|
|
3763
3891
|
"Riporta l'esito del controllo"
|
|
3764
3892
|
];
|
|
3765
3893
|
}
|
|
3766
|
-
if (/(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3894
|
+
if (/(\bprocess\b|\bprocesso\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3767
3895
|
const processMatch = g.match(/(?:process(?:o|i)?|pid)\s+(?:di\s+|of\s+)?([a-z0-9._-]{2,})/i) || g.match(/([a-z0-9._-]{2,})\s+(?:process(?:o|i)?|pid)/i);
|
|
3768
3896
|
const target = processMatch ? processMatch[1] : '';
|
|
3769
3897
|
return [
|
|
@@ -3771,7 +3899,7 @@ function makeSimplePlan(goal) {
|
|
|
3771
3899
|
"Riporta l'esito del controllo"
|
|
3772
3900
|
];
|
|
3773
3901
|
}
|
|
3774
|
-
if (/(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3902
|
+
if (/(\bport\b|\bporta\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3775
3903
|
const portMatch = g.match(/\b(\d{2,5})\b/);
|
|
3776
3904
|
const target = portMatch ? portMatch[1] : '';
|
|
3777
3905
|
return [
|
|
@@ -6397,6 +6525,8 @@ async function runSinglePrompt(opts) {
|
|
|
6397
6525
|
const localResult = await handleLocalCommand(opts, opts.prompt);
|
|
6398
6526
|
if (localResult.handled) return;
|
|
6399
6527
|
}
|
|
6528
|
+
const naturalFileAction = await runNaturalLocalFileAction(opts, opts.prompt);
|
|
6529
|
+
if (naturalFileAction.handled) return;
|
|
6400
6530
|
const localIntent = classifyLocalPromptIntent(opts.prompt);
|
|
6401
6531
|
if (localIntent?.command) {
|
|
6402
6532
|
const localResult = await handleLocalCommand(opts, localIntent.command);
|
|
@@ -6495,6 +6625,13 @@ async function runRepl(opts) {
|
|
|
6495
6625
|
continue;
|
|
6496
6626
|
}
|
|
6497
6627
|
}
|
|
6628
|
+
try {
|
|
6629
|
+
const naturalFileAction = await runNaturalLocalFileAction(opts, line);
|
|
6630
|
+
if (naturalFileAction.handled) continue;
|
|
6631
|
+
} catch (err) {
|
|
6632
|
+
console.error(`Local tool error: ${err.message}`);
|
|
6633
|
+
continue;
|
|
6634
|
+
}
|
|
6498
6635
|
if (opts.offline) {
|
|
6499
6636
|
console.log('Offline mode: use /help for local tools or restart without --offline to use the server.');
|
|
6500
6637
|
continue;
|