bortexcode 1.2.1 → 1.2.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/bin/bortex.js +373 -2
- package/package.json +2 -1
package/bin/bortex.js
CHANGED
|
@@ -170,7 +170,7 @@ function usage() {
|
|
|
170
170
|
console.log(' -h, --help Show help');
|
|
171
171
|
console.log('');
|
|
172
172
|
console.log('REPL commands: /agent on|off, /status, /exit, /help, /llm-config');
|
|
173
|
-
console.log('Local tools: /pwd, /cd, /ls, /tree, /read, /write, /append, /mkdir, /git, /sh');
|
|
173
|
+
console.log('Local tools: /pwd, /cd, /ls, /tree, /read, /write, /append, /mkdir, /git, /ssh-status, /sh');
|
|
174
174
|
console.log('');
|
|
175
175
|
console.log('Environment:');
|
|
176
176
|
console.log(' BORTEX_URL Server URL');
|
|
@@ -1147,10 +1147,257 @@ function detectWorkspaceProfile(opts) {
|
|
|
1147
1147
|
return profile;
|
|
1148
1148
|
}
|
|
1149
1149
|
|
|
1150
|
+
function classifyLocalPromptIntent(text) {
|
|
1151
|
+
const t = String(text || '').toLowerCase();
|
|
1152
|
+
if (!t) return null;
|
|
1153
|
+
const wantsStatus = /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t);
|
|
1154
|
+
if (wantsStatus && (/(\bssh\b|sshd|remote login)/.test(t))) {
|
|
1155
|
+
return { command: '/ssh-status' };
|
|
1156
|
+
}
|
|
1157
|
+
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))) {
|
|
1158
|
+
return { command: '/sys-status' };
|
|
1159
|
+
}
|
|
1160
|
+
if (wantsStatus && /(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(t)) {
|
|
1161
|
+
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);
|
|
1162
|
+
return { command: processMatch ? `/process-status ${processMatch[1]}` : '/process-status' };
|
|
1163
|
+
}
|
|
1164
|
+
if (wantsStatus && /(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(t)) {
|
|
1165
|
+
const portMatch = t.match(/\b(\d{2,5})\b/);
|
|
1166
|
+
return { command: portMatch ? `/port-status ${portMatch[1]}` : '/port-status' };
|
|
1167
|
+
}
|
|
1168
|
+
return null;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
async function runSshStatusCommand(opts, { quiet = false } = {}) {
|
|
1172
|
+
const cwd = opts?.cwd || process.cwd();
|
|
1173
|
+
const platform = os.platform();
|
|
1174
|
+
let command = '';
|
|
1175
|
+
let stdout = '';
|
|
1176
|
+
let stderr = '';
|
|
1177
|
+
let enabled = null;
|
|
1178
|
+
let active = null;
|
|
1179
|
+
|
|
1180
|
+
if (platform === 'darwin') {
|
|
1181
|
+
command = 'launchctl print-disabled system | grep com.openssh.sshd';
|
|
1182
|
+
const res = await runChild('bash', ['-lc', 'launchctl print-disabled system 2>/dev/null | grep -i "com.openssh.sshd" || true'], { cwd, shell: false });
|
|
1183
|
+
stdout = String(res.stdout || '').trim();
|
|
1184
|
+
stderr = String(res.stderr || '').trim();
|
|
1185
|
+
const match = stdout.match(/com\.openssh\.sshd"\s*=>\s*(enabled|disabled)/i);
|
|
1186
|
+
if (match) {
|
|
1187
|
+
enabled = match[1].toLowerCase() === 'enabled';
|
|
1188
|
+
active = enabled;
|
|
1189
|
+
}
|
|
1190
|
+
} else if (platform === 'win32') {
|
|
1191
|
+
command = 'Get-Service sshd';
|
|
1192
|
+
const res = await runChild('powershell.exe', [
|
|
1193
|
+
'-NoProfile',
|
|
1194
|
+
'-Command',
|
|
1195
|
+
'if (Get-Service sshd -ErrorAction SilentlyContinue) { (Get-Service sshd).Status } else { "Missing" }'
|
|
1196
|
+
], { cwd, shell: false });
|
|
1197
|
+
stdout = String(res.stdout || '').trim();
|
|
1198
|
+
stderr = String(res.stderr || '').trim();
|
|
1199
|
+
if (/running/i.test(stdout)) active = true;
|
|
1200
|
+
else if (/stopped/i.test(stdout)) active = false;
|
|
1201
|
+
} else {
|
|
1202
|
+
command = 'systemctl is-active sshd || systemctl is-active ssh';
|
|
1203
|
+
const res = await runChild('bash', [
|
|
1204
|
+
'-lc',
|
|
1205
|
+
'if command -v systemctl >/dev/null 2>&1; then if systemctl is-active sshd >/dev/null 2>&1 || systemctl is-active ssh >/dev/null 2>&1; then echo active; elif systemctl is-enabled sshd >/dev/null 2>&1 || systemctl is-enabled ssh >/dev/null 2>&1; then echo enabled; else echo inactive; fi; elif pgrep -x sshd >/dev/null 2>&1; then echo active; else echo unknown; fi'
|
|
1206
|
+
], { cwd, shell: false });
|
|
1207
|
+
stdout = String(res.stdout || '').trim();
|
|
1208
|
+
stderr = String(res.stderr || '').trim();
|
|
1209
|
+
if (/active/i.test(stdout)) active = true;
|
|
1210
|
+
else if (/enabled/i.test(stdout)) active = true;
|
|
1211
|
+
else if (/inactive|stopped/i.test(stdout)) active = false;
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
const statusText = platform === 'darwin'
|
|
1215
|
+
? `macOS Remote Login: ${enabled === true ? 'On' : enabled === false ? 'Off' : 'Unknown'}`
|
|
1216
|
+
: platform === 'win32'
|
|
1217
|
+
? `Windows SSH service: ${stdout || 'Unknown'}`
|
|
1218
|
+
: `SSH service: ${active === true ? 'active' : active === false ? 'inactive' : stdout || 'unknown'}`;
|
|
1219
|
+
|
|
1220
|
+
if (!quiet) console.log(statusText);
|
|
1221
|
+
return {
|
|
1222
|
+
ok: true,
|
|
1223
|
+
stdout: statusText,
|
|
1224
|
+
stderr: stderr || null,
|
|
1225
|
+
data: {
|
|
1226
|
+
platform,
|
|
1227
|
+
command,
|
|
1228
|
+
enabled,
|
|
1229
|
+
active,
|
|
1230
|
+
raw: stdout || null,
|
|
1231
|
+
stderr: stderr || null
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
async function runSystemStatusCommand(opts) {
|
|
1237
|
+
const cwd = opts?.cwd || process.cwd();
|
|
1238
|
+
const platform = os.platform();
|
|
1239
|
+
const arch = os.arch();
|
|
1240
|
+
const release = os.release();
|
|
1241
|
+
const shell = String(process.env.SHELL || process.env.ComSpec || '').trim() || null;
|
|
1242
|
+
|
|
1243
|
+
const runText = async (command, args, fallback = '') => {
|
|
1244
|
+
const res = await runChild(command, args, { cwd, shell: false });
|
|
1245
|
+
const text = String(res.stdout || '').trim();
|
|
1246
|
+
if (text) return text.split(/\r?\n/)[0].trim();
|
|
1247
|
+
return fallback;
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
let user = null;
|
|
1251
|
+
let host = null;
|
|
1252
|
+
if (platform === 'win32') {
|
|
1253
|
+
user = await runText('powershell.exe', ['-NoProfile', '-Command', '$env:USERNAME'], 'unknown');
|
|
1254
|
+
host = await runText('powershell.exe', ['-NoProfile', '-Command', '$env:COMPUTERNAME'], 'unknown');
|
|
1255
|
+
} else {
|
|
1256
|
+
user = await runText('bash', ['-lc', 'whoami'], 'unknown');
|
|
1257
|
+
host = await runText('bash', ['-lc', 'hostname'], 'unknown');
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
const nodeRes = await runChild('node', ['--version'], { cwd, shell: false });
|
|
1261
|
+
const npmRes = await runChild('npm', ['--version'], { cwd, shell: false });
|
|
1262
|
+
const gitRes = await runChild('git', ['--version'], { cwd, shell: false });
|
|
1263
|
+
const sshRes = await runSshStatusCommand(opts, { quiet: true });
|
|
1264
|
+
const lines = [
|
|
1265
|
+
`Platform: ${platform} ${release} ${arch}`,
|
|
1266
|
+
`User: ${user}`,
|
|
1267
|
+
`Host: ${host}`,
|
|
1268
|
+
`Shell: ${shell || 'unknown'}`,
|
|
1269
|
+
`Node: ${nodeRes.ok ? String(nodeRes.stdout || '').trim() : 'not found'}`,
|
|
1270
|
+
`npm: ${npmRes.ok ? String(npmRes.stdout || '').trim() : 'not found'}`,
|
|
1271
|
+
`Git: ${gitRes.ok ? String(gitRes.stdout || '').trim() : 'not found'}`,
|
|
1272
|
+
sshRes?.stdout ? `SSH: ${sshRes.stdout}` : 'SSH: unknown'
|
|
1273
|
+
];
|
|
1274
|
+
const summary = lines.join('\n');
|
|
1275
|
+
console.log(summary);
|
|
1276
|
+
return {
|
|
1277
|
+
ok: true,
|
|
1278
|
+
stdout: summary,
|
|
1279
|
+
stderr: null,
|
|
1280
|
+
data: {
|
|
1281
|
+
platform,
|
|
1282
|
+
release,
|
|
1283
|
+
arch,
|
|
1284
|
+
user,
|
|
1285
|
+
host,
|
|
1286
|
+
shell,
|
|
1287
|
+
nodeVersion: nodeRes.ok ? String(nodeRes.stdout || '').trim() : null,
|
|
1288
|
+
npmVersion: npmRes.ok ? String(npmRes.stdout || '').trim() : null,
|
|
1289
|
+
gitVersion: gitRes.ok ? String(gitRes.stdout || '').trim() : null,
|
|
1290
|
+
ssh: sshRes?.data || null
|
|
1291
|
+
}
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
async function runProcessStatusCommand(opts, call = {}) {
|
|
1296
|
+
const cwd = opts?.cwd || process.cwd();
|
|
1297
|
+
const platform = os.platform();
|
|
1298
|
+
const filter = String(call.name || call.filter || '').trim();
|
|
1299
|
+
const filterLabel = filter || null;
|
|
1300
|
+
let command = '';
|
|
1301
|
+
let stdout = '';
|
|
1302
|
+
let stderr = '';
|
|
1303
|
+
|
|
1304
|
+
if (platform === 'win32') {
|
|
1305
|
+
const escaped = filter.replace(/'/g, "''");
|
|
1306
|
+
const ps = filter
|
|
1307
|
+
? `Get-Process | Where-Object { $_.ProcessName -like '*${escaped}*' } | Select-Object -First 20 Id,ProcessName,CPU,WS | Format-Table -AutoSize`
|
|
1308
|
+
: 'Get-Process | Sort-Object CPU -Descending | Select-Object -First 12 Id,ProcessName,CPU,WS | Format-Table -AutoSize';
|
|
1309
|
+
command = ps;
|
|
1310
|
+
const res = await runChild('powershell.exe', ['-NoProfile', '-Command', ps], { cwd, shell: false });
|
|
1311
|
+
stdout = String(res.stdout || '').trim();
|
|
1312
|
+
stderr = String(res.stderr || '').trim();
|
|
1313
|
+
} else {
|
|
1314
|
+
const quoted = JSON.stringify(filter);
|
|
1315
|
+
const bashCmd = filter
|
|
1316
|
+
? `pgrep -af ${quoted} || true`
|
|
1317
|
+
: 'ps -ax -o pid=,ppid=,comm=,%cpu=,%mem= | head -n 12';
|
|
1318
|
+
command = bashCmd;
|
|
1319
|
+
const res = await runChild('bash', ['-lc', bashCmd], { cwd, shell: false });
|
|
1320
|
+
stdout = String(res.stdout || '').trim();
|
|
1321
|
+
stderr = String(res.stderr || '').trim();
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
const text = stdout || '(no matching processes)';
|
|
1325
|
+
console.log(text);
|
|
1326
|
+
return {
|
|
1327
|
+
ok: true,
|
|
1328
|
+
stdout: text,
|
|
1329
|
+
stderr: stderr || null,
|
|
1330
|
+
data: {
|
|
1331
|
+
platform,
|
|
1332
|
+
filter: filterLabel,
|
|
1333
|
+
command,
|
|
1334
|
+
raw: stdout || null,
|
|
1335
|
+
stderr: stderr || null
|
|
1336
|
+
}
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
async function runPortStatusCommand(opts, call = {}) {
|
|
1341
|
+
const cwd = opts?.cwd || process.cwd();
|
|
1342
|
+
const platform = os.platform();
|
|
1343
|
+
const target = String(call.port || call.target || '').trim();
|
|
1344
|
+
const isPort = /^\d+$/.test(target);
|
|
1345
|
+
let command = '';
|
|
1346
|
+
let stdout = '';
|
|
1347
|
+
let stderr = '';
|
|
1348
|
+
|
|
1349
|
+
if (platform === 'win32') {
|
|
1350
|
+
const ps = isPort
|
|
1351
|
+
? `Get-NetTCPConnection -State Listen -LocalPort ${Number(target)} | Select-Object LocalAddress,LocalPort,OwningProcess | Format-Table -AutoSize`
|
|
1352
|
+
: 'Get-NetTCPConnection -State Listen | Select-Object -First 20 LocalAddress,LocalPort,OwningProcess | Format-Table -AutoSize';
|
|
1353
|
+
command = ps;
|
|
1354
|
+
const res = await runChild('powershell.exe', ['-NoProfile', '-Command', ps], { cwd, shell: false });
|
|
1355
|
+
stdout = String(res.stdout || '').trim();
|
|
1356
|
+
stderr = String(res.stderr || '').trim();
|
|
1357
|
+
} else {
|
|
1358
|
+
const bashCmd = isPort
|
|
1359
|
+
? `if command -v lsof >/dev/null 2>&1; then lsof -nP -iTCP:${Number(target)} -sTCP:LISTEN || true; elif command -v ss >/dev/null 2>&1; then ss -ltnp | grep ":${Number(target)} " || true; else netstat -an 2>/dev/null | grep "${Number(target)}" || true; fi`
|
|
1360
|
+
: 'if command -v lsof >/dev/null 2>&1; then lsof -nP -iTCP -sTCP:LISTEN | head -n 20; elif command -v ss >/dev/null 2>&1; then ss -ltnp | head -n 20; else netstat -an 2>/dev/null | grep LISTEN | head -n 20; fi';
|
|
1361
|
+
command = bashCmd;
|
|
1362
|
+
const res = await runChild('bash', ['-lc', bashCmd], { cwd, shell: false });
|
|
1363
|
+
stdout = String(res.stdout || '').trim();
|
|
1364
|
+
stderr = String(res.stderr || '').trim();
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
const text = stdout || (isPort ? `(port ${target} not listening)` : '(no listening ports found)');
|
|
1368
|
+
console.log(text);
|
|
1369
|
+
return {
|
|
1370
|
+
ok: true,
|
|
1371
|
+
stdout: text,
|
|
1372
|
+
stderr: stderr || null,
|
|
1373
|
+
data: {
|
|
1374
|
+
platform,
|
|
1375
|
+
target: target || null,
|
|
1376
|
+
command,
|
|
1377
|
+
raw: stdout || null,
|
|
1378
|
+
stderr: stderr || null
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1150
1383
|
function suggestCommandsForStep(stepText, opts) {
|
|
1151
1384
|
const t = String(stepText || '').toLowerCase();
|
|
1152
1385
|
const profile = opts ? detectWorkspaceProfile(opts) : { suggested: { test: [] } };
|
|
1153
1386
|
const testCmds = Array.isArray(profile.suggested?.test) ? profile.suggested.test.slice(0, 2) : [];
|
|
1387
|
+
if (/(\bssh\b|sshd|remote login)/.test(t) && /(verifica|controlla|check|show|mostra|stato|status|attivo|active|running|enabled|on)/.test(t)) {
|
|
1388
|
+
return ['/ssh-status', '/status'];
|
|
1389
|
+
}
|
|
1390
|
+
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)) {
|
|
1391
|
+
return ['/sys-status', '/status'];
|
|
1392
|
+
}
|
|
1393
|
+
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)) {
|
|
1394
|
+
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);
|
|
1395
|
+
return [processMatch ? `/process-status ${processMatch[1]}` : '/process-status', '/status'];
|
|
1396
|
+
}
|
|
1397
|
+
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)) {
|
|
1398
|
+
const portMatch = t.match(/\b(\d{2,5})\b/);
|
|
1399
|
+
return [portMatch ? `/port-status ${portMatch[1]}` : '/port-status', '/status'];
|
|
1400
|
+
}
|
|
1154
1401
|
if (/analizza|contesto|file/.test(t)) return ['/ls', '/tree . 2', '/git status -sb', '/diff all'];
|
|
1155
1402
|
if (/riproduci|problema|causa/.test(t)) return ['/git status -sb', '/read <file>', ...(testCmds[0] ? [`/sh ${testCmds[0]}`] : ['/sh <cmd test/run>'])];
|
|
1156
1403
|
if (/fix|modifiche|implementa/.test(t)) return ['/read <file>', '/write <file> <text> | /patch-apply-inline', '/diff unstaged'];
|
|
@@ -1194,6 +1441,10 @@ function isReadMostlyCommandForAuto(cmd) {
|
|
|
1194
1441
|
c.startsWith('/hunks') ||
|
|
1195
1442
|
c.startsWith('/show-hunk') ||
|
|
1196
1443
|
c.startsWith('/status') ||
|
|
1444
|
+
c.startsWith('/ssh-status') ||
|
|
1445
|
+
c.startsWith('/sys-status') ||
|
|
1446
|
+
c.startsWith('/process-status') ||
|
|
1447
|
+
c.startsWith('/port-status') ||
|
|
1197
1448
|
c.startsWith('/history') ||
|
|
1198
1449
|
c.startsWith('/artifacts') ||
|
|
1199
1450
|
c.startsWith('/project') ||
|
|
@@ -2456,6 +2707,18 @@ async function executeStructuredBuiltinTool(opts, call) {
|
|
|
2456
2707
|
};
|
|
2457
2708
|
return { ok: true, stdout: stdout || null, stderr: null, data };
|
|
2458
2709
|
}
|
|
2710
|
+
if (tool === 'sshStatus') {
|
|
2711
|
+
return runSshStatusCommand(opts);
|
|
2712
|
+
}
|
|
2713
|
+
if (tool === 'systemStatus') {
|
|
2714
|
+
return runSystemStatusCommand(opts);
|
|
2715
|
+
}
|
|
2716
|
+
if (tool === 'processStatus') {
|
|
2717
|
+
return runProcessStatusCommand(opts, call);
|
|
2718
|
+
}
|
|
2719
|
+
if (tool === 'portStatus') {
|
|
2720
|
+
return runPortStatusCommand(opts, call);
|
|
2721
|
+
}
|
|
2459
2722
|
if (tool === 'search') {
|
|
2460
2723
|
const pattern = String(call.pattern || '').trim();
|
|
2461
2724
|
const searchPath = String(call.path || '.');
|
|
@@ -2596,6 +2859,8 @@ function validateStructuredToolCall(raw) {
|
|
|
2596
2859
|
case 'pwd':
|
|
2597
2860
|
case 'project':
|
|
2598
2861
|
case 'gitStatus':
|
|
2862
|
+
case 'systemStatus':
|
|
2863
|
+
case 'sshStatus':
|
|
2599
2864
|
break;
|
|
2600
2865
|
case 'runTest':
|
|
2601
2866
|
case 'runBuild':
|
|
@@ -2666,6 +2931,14 @@ function validateStructuredToolCall(raw) {
|
|
|
2666
2931
|
break;
|
|
2667
2932
|
case 'commitSuggest':
|
|
2668
2933
|
break;
|
|
2934
|
+
case 'processStatus':
|
|
2935
|
+
if (call.name != null && typeof call.name !== 'string') return { ok: false, error: '`name` deve essere stringa.' };
|
|
2936
|
+
if (call.filter != null && typeof call.filter !== 'string') return { ok: false, error: '`filter` deve essere stringa.' };
|
|
2937
|
+
break;
|
|
2938
|
+
case 'portStatus':
|
|
2939
|
+
if (call.port != null && typeof call.port !== 'string' && !Number.isFinite(Number(call.port))) return { ok: false, error: '`port` deve essere stringa o numero.' };
|
|
2940
|
+
if (call.target != null && typeof call.target !== 'string' && !Number.isFinite(Number(call.target))) return { ok: false, error: '`target` deve essere stringa o numero.' };
|
|
2941
|
+
break;
|
|
2669
2942
|
default:
|
|
2670
2943
|
return { ok: false, error: `Tool non supportato: ${tool}` };
|
|
2671
2944
|
}
|
|
@@ -2693,6 +2966,10 @@ function structuredToolCallToLocalCommand(call) {
|
|
|
2693
2966
|
case 'gitDiff': return `gitDiff(${call.mode || 'all'}${call.statOnly === false ? ',patch' : ',stat'})`;
|
|
2694
2967
|
case 'search': return `search(${call.pattern}${call.path ? ` in ${call.path}` : ''}${call.glob ? ` glob=${call.glob}` : ''})`;
|
|
2695
2968
|
case 'git': return `/git ${call.args.join(' ')}`;
|
|
2969
|
+
case 'sshStatus': return '/ssh-status';
|
|
2970
|
+
case 'systemStatus': return '/sys-status';
|
|
2971
|
+
case 'processStatus': return `/process-status${call.name || call.filter ? ` ${call.name || call.filter}` : ''}`;
|
|
2972
|
+
case 'portStatus': return `/port-status${call.port || call.target ? ` ${call.port || call.target}` : ''}`;
|
|
2696
2973
|
case 'sh': return `/sh ${call.cmd}`;
|
|
2697
2974
|
case 'review': {
|
|
2698
2975
|
const mode = call.mode ? ` --${call.mode}` : '';
|
|
@@ -2946,6 +3223,23 @@ function buildStructuredToolPlanFromGoal(opts, goal) {
|
|
|
2946
3223
|
{ tool: 'review', mode: 'all', fixSuggestions: true }
|
|
2947
3224
|
];
|
|
2948
3225
|
|
|
3226
|
+
const wantsStatus = /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/.test(lower);
|
|
3227
|
+
if (wantsStatus && /(\bssh\b|sshd|remote login)/.test(lower)) {
|
|
3228
|
+
return [{ tool: 'project' }, { tool: 'sshStatus' }];
|
|
3229
|
+
}
|
|
3230
|
+
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))) {
|
|
3231
|
+
return [{ tool: 'project' }, { tool: 'systemStatus' }];
|
|
3232
|
+
}
|
|
3233
|
+
if (wantsStatus && /(\bprocess\b|\bprocessi\b|\bpid\b|\bcpu\b|\bram\b|\bmemory\b|\bmem\b)/.test(lower)) {
|
|
3234
|
+
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);
|
|
3235
|
+
const filter = processMatch ? processMatch[1] : '';
|
|
3236
|
+
return [{ tool: 'project' }, { tool: 'processStatus', ...(filter ? { name: filter } : {}) }];
|
|
3237
|
+
}
|
|
3238
|
+
if (wantsStatus && /(\bport\b|\bporte\b|\bsocket\b|\blisten\b|\blistening\b)/.test(lower)) {
|
|
3239
|
+
const portMatch = g.match(/\b(\d{2,5})\b/);
|
|
3240
|
+
const port = portMatch ? portMatch[1] : '';
|
|
3241
|
+
return [{ tool: 'project' }, { tool: 'portStatus', ...(port ? { port } : {}) }];
|
|
3242
|
+
}
|
|
2949
3243
|
if (/bug|errore|fix/.test(lower)) {
|
|
2950
3244
|
const extractedKeyword = g.split(/\s+/).filter((w) => w.length >= 4).slice(-1)[0];
|
|
2951
3245
|
if (extractedKeyword) plan.push({ tool: 'search', pattern: extractedKeyword, path: '.', maxResults: 20 });
|
|
@@ -3064,7 +3358,7 @@ async function buildStructuredToolPlanWithLlm(opts, goal, llmOptions = {}) {
|
|
|
3064
3358
|
const profile = detectWorkspaceProfile(opts);
|
|
3065
3359
|
const supportedTools = [
|
|
3066
3360
|
'project', 'pwd', 'ls', 'tree', 'glob', 'read', 'readMany', 'mkdir', 'write', 'append',
|
|
3067
|
-
'diff', 'git', 'gitStatus', 'gitDiff', 'search', 'runTest', 'runBuild', 'runLint', 'sh', 'review', 'commitSuggest'
|
|
3361
|
+
'diff', 'git', 'gitStatus', 'gitDiff', 'search', 'runTest', 'runBuild', 'runLint', 'sshStatus', 'systemStatus', 'processStatus', 'portStatus', 'sh', 'review', 'commitSuggest'
|
|
3068
3362
|
];
|
|
3069
3363
|
const testCmd = profile.suggested.test?.[0] || '';
|
|
3070
3364
|
const buildCmd = profile.suggested.build?.[0] || '';
|
|
@@ -3155,6 +3449,7 @@ async function buildStructuredToolPlanWithLlm(opts, goal, llmOptions = {}) {
|
|
|
3155
3449
|
'Usa solo campi validi per tool.',
|
|
3156
3450
|
'Regole:',
|
|
3157
3451
|
'- Preferisci tool read-only prima dei tool rischiosi',
|
|
3452
|
+
'- Per controlli di stato locale usa sshStatus/systemStatus/processStatus/portStatus invece di sh quando possibile',
|
|
3158
3453
|
'- Includi review e commitSuggest verso la fine',
|
|
3159
3454
|
'- Se proponi `runTest`/`runBuild`/`runLint` preferiscili a `sh` quando possibile',
|
|
3160
3455
|
'- Se proponi `sh`, usa comandi test/build/lint concreti se disponibili',
|
|
@@ -3368,6 +3663,10 @@ function printLocalHelp() {
|
|
|
3368
3663
|
console.log(' /append <file> <text>');
|
|
3369
3664
|
console.log(' /mkdir <path>');
|
|
3370
3665
|
console.log(' /git <args...> es: /git status -sb');
|
|
3666
|
+
console.log(' /ssh-status check SSH / Remote Login status');
|
|
3667
|
+
console.log(' /sys-status check system / runtime status');
|
|
3668
|
+
console.log(' /process-status check running processes');
|
|
3669
|
+
console.log(' /port-status check listening ports');
|
|
3371
3670
|
console.log(' /diff [unstaged|staged|all]');
|
|
3372
3671
|
console.log(' /stage <file>|--all');
|
|
3373
3672
|
console.log(' /unstage <file>|--all');
|
|
@@ -3453,6 +3752,34 @@ function printTodoList(opts) {
|
|
|
3453
3752
|
function makeSimplePlan(goal) {
|
|
3454
3753
|
const g = String(goal || '').trim();
|
|
3455
3754
|
if (!g) return [];
|
|
3755
|
+
if (/(\bssh\b|sshd|remote login)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3756
|
+
return [
|
|
3757
|
+
'Verifica stato SSH / Remote Login',
|
|
3758
|
+
"Riporta l'esito del controllo"
|
|
3759
|
+
];
|
|
3760
|
+
}
|
|
3761
|
+
if (/(whoami|username|user name|hostname|host name|machine|computer|system|sistema|platform|os|runtime|shell|environment|env|path|\bnode\b|\bnpm\b)/i.test(g) && /(verifica|controlla|check|mostra|stato|status|attivo|active|running|enabled|on)/i.test(g)) {
|
|
3762
|
+
return [
|
|
3763
|
+
'Verifica stato del sistema locale',
|
|
3764
|
+
"Riporta l'esito del controllo"
|
|
3765
|
+
];
|
|
3766
|
+
}
|
|
3767
|
+
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)) {
|
|
3768
|
+
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);
|
|
3769
|
+
const target = processMatch ? processMatch[1] : '';
|
|
3770
|
+
return [
|
|
3771
|
+
target ? `Verifica il processo ${target}` : 'Verifica i processi attivi o il processo indicato',
|
|
3772
|
+
"Riporta l'esito del controllo"
|
|
3773
|
+
];
|
|
3774
|
+
}
|
|
3775
|
+
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)) {
|
|
3776
|
+
const portMatch = g.match(/\b(\d{2,5})\b/);
|
|
3777
|
+
const target = portMatch ? portMatch[1] : '';
|
|
3778
|
+
return [
|
|
3779
|
+
target ? `Verifica la porta ${target} in ascolto` : 'Verifica le porte in ascolto',
|
|
3780
|
+
"Riporta l'esito del controllo"
|
|
3781
|
+
];
|
|
3782
|
+
}
|
|
3456
3783
|
const steps = ['Analizza contesto e file coinvolti'];
|
|
3457
3784
|
if (/bug|errore|fix/i.test(g)) {
|
|
3458
3785
|
steps.push('Riproduci il problema e isola la causa');
|
|
@@ -5567,6 +5894,31 @@ async function handleLocalCommand(opts, line) {
|
|
|
5567
5894
|
}
|
|
5568
5895
|
};
|
|
5569
5896
|
}
|
|
5897
|
+
if (lc === '/sys-status') {
|
|
5898
|
+
recordArtifact(opts, 'sys-status', 'check');
|
|
5899
|
+
const data = await runSystemStatusCommand(opts);
|
|
5900
|
+
try { saveCliWorkspaceState(opts); } catch (_err) { }
|
|
5901
|
+
return { handled: true, data };
|
|
5902
|
+
}
|
|
5903
|
+
if (lc === '/process-status') {
|
|
5904
|
+
recordArtifact(opts, 'process-status', rest.join(' ') || 'check');
|
|
5905
|
+
const data = await runProcessStatusCommand(opts, { name: rest.join(' ') });
|
|
5906
|
+
try { saveCliWorkspaceState(opts); } catch (_err) { }
|
|
5907
|
+
return { handled: true, data };
|
|
5908
|
+
}
|
|
5909
|
+
if (lc === '/port-status') {
|
|
5910
|
+
const target = String(rest[0] || '').trim();
|
|
5911
|
+
recordArtifact(opts, 'port-status', target || 'check');
|
|
5912
|
+
const data = await runPortStatusCommand(opts, { port: target });
|
|
5913
|
+
try { saveCliWorkspaceState(opts); } catch (_err) { }
|
|
5914
|
+
return { handled: true, data };
|
|
5915
|
+
}
|
|
5916
|
+
if (lc === '/ssh-status') {
|
|
5917
|
+
recordArtifact(opts, 'ssh-status', 'check');
|
|
5918
|
+
const data = await runSshStatusCommand(opts);
|
|
5919
|
+
try { saveCliWorkspaceState(opts); } catch (_err) { }
|
|
5920
|
+
return { handled: true, data };
|
|
5921
|
+
}
|
|
5570
5922
|
if (lc === '/agent-run') {
|
|
5571
5923
|
const sub = String(rest[0] || '').toLowerCase();
|
|
5572
5924
|
if (sub === 'policy') {
|
|
@@ -5932,6 +6284,10 @@ const SLASH_COMMANDS = [
|
|
|
5932
6284
|
['/write <file> <text>', 'Write a file'],
|
|
5933
6285
|
['/append <file> <text>', 'Append to a file'],
|
|
5934
6286
|
['/git <args>', 'Run a git command'],
|
|
6287
|
+
['/ssh-status', 'Check SSH/Remote Login status'],
|
|
6288
|
+
['/sys-status', 'Check local system/runtime status'],
|
|
6289
|
+
['/process-status', 'Check running processes'],
|
|
6290
|
+
['/port-status', 'Check listening ports'],
|
|
5935
6291
|
['/diff [unstaged|staged|all]', 'Show git diff'],
|
|
5936
6292
|
['/review [--staged|--all]', 'Review local changes'],
|
|
5937
6293
|
['/commit-suggest [--staged]', 'Suggest a commit message'],
|
|
@@ -6038,6 +6394,11 @@ function printWelcomeCard(opts) {
|
|
|
6038
6394
|
}
|
|
6039
6395
|
|
|
6040
6396
|
async function runSinglePrompt(opts) {
|
|
6397
|
+
const localIntent = classifyLocalPromptIntent(opts.prompt);
|
|
6398
|
+
if (localIntent?.command) {
|
|
6399
|
+
const localResult = await handleLocalCommand(opts, localIntent.command);
|
|
6400
|
+
if (localResult.handled) return;
|
|
6401
|
+
}
|
|
6041
6402
|
if (opts.offline) {
|
|
6042
6403
|
console.error('Modalita --offline: usa REPL interattiva e comandi locali (/help).');
|
|
6043
6404
|
process.exit(1);
|
|
@@ -6121,6 +6482,16 @@ async function runRepl(opts) {
|
|
|
6121
6482
|
console.error(`Local tool error: ${err.message}`);
|
|
6122
6483
|
continue;
|
|
6123
6484
|
}
|
|
6485
|
+
const localIntent = classifyLocalPromptIntent(line);
|
|
6486
|
+
if (localIntent?.command) {
|
|
6487
|
+
try {
|
|
6488
|
+
const localResult = await handleLocalCommand(opts, localIntent.command);
|
|
6489
|
+
if (localResult.handled) continue;
|
|
6490
|
+
} catch (err) {
|
|
6491
|
+
console.error(`Local tool error: ${err.message}`);
|
|
6492
|
+
continue;
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6124
6495
|
if (opts.offline) {
|
|
6125
6496
|
console.log('Offline mode: use /help for local tools or restart without --offline to use the server.');
|
|
6126
6497
|
continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bortexcode",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "Bortex Code CLI - AI coding assistant powered by bortex.site",
|
|
5
5
|
"homepage": "https://bortex.site",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"node": ">=18.0.0"
|
|
18
18
|
},
|
|
19
19
|
"bin": {
|
|
20
|
+
"bortex": "bin/bortexcode.js",
|
|
20
21
|
"bortexcode": "bin/bortexcode.js",
|
|
21
22
|
"bortex-code": "bin/bortexcode.js",
|
|
22
23
|
"bortex-agent": "bin/bortexcode-agent.js"
|