notoken-core 1.8.0 → 1.8.1
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/config/entities.json +3 -3
- package/config/intents.json +453 -58
- package/dist/automation/discordPatchright.js +16 -3
- package/dist/handlers/executor.js +441 -6
- package/dist/index.d.ts +4 -1
- package/dist/index.js +5 -1
- package/dist/nlp/llmFallback.d.ts +47 -0
- package/dist/nlp/llmFallback.js +147 -35
- package/dist/nlp/llmParser.d.ts +5 -1
- package/dist/nlp/llmParser.js +43 -24
- package/dist/nlp/parseIntent.js +20 -2
- package/dist/nlp/ruleParser.js +32 -1
- package/dist/utils/discordDiag.js +20 -12
- package/dist/utils/openclawDiag.d.ts +98 -0
- package/dist/utils/openclawDiag.js +501 -1
- package/dist/utils/openclawLogParser.d.ts +65 -0
- package/dist/utils/openclawLogParser.js +168 -0
- package/dist/utils/userContext.d.ts +57 -0
- package/dist/utils/userContext.js +133 -0
- package/package.json +1 -1
|
@@ -219,14 +219,16 @@ const USER_DATA_DIR = 'C:\\\\temp\\\\notoken-browser-profile';
|
|
|
219
219
|
console.log('TOKEN_NOT_FOUND');
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
// Enable intents
|
|
222
|
+
// Enable privileged intents (but NOT Code Grant which is switch index 1)
|
|
223
223
|
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
224
224
|
await page.waitForTimeout(1500);
|
|
225
225
|
await page.locator('text=Privileged Gateway Intents').scrollIntoViewIfNeeded().catch(() => {});
|
|
226
226
|
await page.waitForTimeout(1000);
|
|
227
|
-
const
|
|
227
|
+
const allSwitches = await page.locator('input[role="switch"]').all();
|
|
228
228
|
let toggled = 0;
|
|
229
|
-
|
|
229
|
+
// Skip switches 0 (Public Bot) and 1 (Code Grant) — only toggle intent switches (index 2+)
|
|
230
|
+
for (let idx = 2; idx < allSwitches.length; idx++) {
|
|
231
|
+
const sw = allSwitches[idx];
|
|
230
232
|
if (!await sw.isChecked().catch(() => true)) {
|
|
231
233
|
await sw.locator('..').locator('..').first().click({ force: true }).catch(() => {});
|
|
232
234
|
await page.waitForTimeout(500);
|
|
@@ -236,6 +238,17 @@ const USER_DATA_DIR = 'C:\\\\temp\\\\notoken-browser-profile';
|
|
|
236
238
|
await page.click('button:has-text("Save Changes")', { timeout: 3000 }).catch(() => {});
|
|
237
239
|
console.log('INTENTS_ENABLED:' + toggled);
|
|
238
240
|
|
|
241
|
+
// Ensure Code Grant is OFF (switch index 1)
|
|
242
|
+
if (allSwitches.length >= 2) {
|
|
243
|
+
const codeGrantOn = await allSwitches[1].isChecked().catch(() => false);
|
|
244
|
+
if (codeGrantOn) {
|
|
245
|
+
await allSwitches[1].locator('..').click({ force: true }).catch(() => {});
|
|
246
|
+
await page.waitForTimeout(500);
|
|
247
|
+
await page.click('button:has-text("Save Changes")', { timeout: 3000 }).catch(() => {});
|
|
248
|
+
console.log('CODE_GRANT_DISABLED');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
239
252
|
// Save result
|
|
240
253
|
const result = { token, appId, success: !!token };
|
|
241
254
|
fs.writeFileSync('C:\\\\temp\\\\discord-bot-result.json', JSON.stringify(result));
|
|
@@ -373,10 +373,83 @@ export async function executeIntent(intent) {
|
|
|
373
373
|
return `\x1b[31m✗ Discord diagnostics error: ${err.message.split("\n")[0]}\x1b[0m`;
|
|
374
374
|
}
|
|
375
375
|
}
|
|
376
|
-
// OpenClaw status
|
|
376
|
+
// OpenClaw status — quick summary or detailed
|
|
377
377
|
if (intent.intent === "openclaw.status") {
|
|
378
|
+
const isDetailed = /\b(details?|detailed|verbose|full|deep|all|everything)\b/i.test(intent.rawText);
|
|
378
379
|
const diagRemote = environment !== "local" && environment !== "localhost" && hasRealHost(environment);
|
|
379
|
-
|
|
380
|
+
if (isDetailed) {
|
|
381
|
+
// Full detailed check (existing behavior)
|
|
382
|
+
return diagRemote ? await quickConnectivityCheck((cmd) => runRemoteCommand(environment, cmd)) : await quickConnectivityCheck();
|
|
383
|
+
}
|
|
384
|
+
// Quick summary — fast, one-line-per-item
|
|
385
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
386
|
+
const lines = [];
|
|
387
|
+
lines.push(`\n${cc.bold}${cc.cyan}── OpenClaw ──${cc.reset}\n`);
|
|
388
|
+
// Gateway running?
|
|
389
|
+
const health = await runLocalCommand("curl -sf http://127.0.0.1:18789/health 2>/dev/null").catch(() => "");
|
|
390
|
+
const gwUp = health.includes('"ok"');
|
|
391
|
+
lines.push(` ${gwUp ? cc.green + "✓" : cc.red + "✗"}${cc.reset} Gateway: ${gwUp ? "running" : "not running"}`);
|
|
392
|
+
// Environment
|
|
393
|
+
const { getUserContext } = await import("../utils/userContext.js");
|
|
394
|
+
const ctx = getUserContext();
|
|
395
|
+
lines.push(` ${cc.bold}Env:${cc.reset} ${ctx.isWSL ? "WSL" : ctx.isWindows ? "Windows" : "Linux"} (${ctx.effectiveUser})`);
|
|
396
|
+
// Current model
|
|
397
|
+
const ocConfig = await runLocalCommand("cat /root/.openclaw/openclaw.json 2>/dev/null || cat ~/.openclaw/openclaw.json 2>/dev/null").catch(() => "");
|
|
398
|
+
const modelMatch = ocConfig.match(/"primary"\s*:\s*"([^"]+)"/);
|
|
399
|
+
if (modelMatch)
|
|
400
|
+
lines.push(` ${cc.bold}Model:${cc.reset} ${modelMatch[1]}`);
|
|
401
|
+
// LLM providers — quick check auth profiles
|
|
402
|
+
try {
|
|
403
|
+
const { readFileSync, existsSync } = await import("node:fs");
|
|
404
|
+
const { getAuthProfilesPath } = await import("../utils/userContext.js");
|
|
405
|
+
const authPath = getAuthProfilesPath();
|
|
406
|
+
if (existsSync(authPath)) {
|
|
407
|
+
const auth = JSON.parse(readFileSync(authPath, "utf-8"));
|
|
408
|
+
const providers = [];
|
|
409
|
+
for (const [name, profile] of Object.entries(auth.profiles ?? {})) {
|
|
410
|
+
const expires = profile.expires ?? 0;
|
|
411
|
+
const hoursLeft = (expires - Date.now()) / 3600000;
|
|
412
|
+
const pName = name.split(":")[0];
|
|
413
|
+
if (hoursLeft > 0) {
|
|
414
|
+
providers.push(`${cc.green}✓${cc.reset} ${pName} (${Math.round(hoursLeft)}h)`);
|
|
415
|
+
}
|
|
416
|
+
else if (profile.type === "token" || profile.type === "api_key") {
|
|
417
|
+
providers.push(`${cc.green}✓${cc.reset} ${pName} (static)`);
|
|
418
|
+
}
|
|
419
|
+
else if (expires > 0) {
|
|
420
|
+
providers.push(`${cc.red}✗${cc.reset} ${pName} (expired)`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (providers.length > 0) {
|
|
424
|
+
lines.push(` ${cc.bold}LLMs:${cc.reset} ${providers.join(" ")}`);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
catch { }
|
|
429
|
+
// Channels — check Discord
|
|
430
|
+
const discordToken = ocConfig.includes('"discord"') && ocConfig.includes('"token"');
|
|
431
|
+
if (discordToken) {
|
|
432
|
+
// Quick check if Discord is connected via logs
|
|
433
|
+
const recentLog = await runLocalCommand("tail -20 /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log 2>/dev/null").catch(() => "");
|
|
434
|
+
const discordOk = recentLog.includes("logged in to discord") || recentLog.includes("discord client ready");
|
|
435
|
+
const discordAwaiting = recentLog.includes("awaiting gateway readiness");
|
|
436
|
+
if (discordOk) {
|
|
437
|
+
lines.push(` ${cc.green}✓${cc.reset} Discord: connected`);
|
|
438
|
+
}
|
|
439
|
+
else if (discordAwaiting) {
|
|
440
|
+
lines.push(` ${cc.yellow}⏳${cc.reset} Discord: connecting...`);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
lines.push(` ${cc.yellow}○${cc.reset} Discord: configured`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// Ollama
|
|
447
|
+
const ollamaUp = await runLocalCommand("curl -sf http://localhost:11434/api/tags 2>/dev/null | head -1").catch(() => "");
|
|
448
|
+
if (ollamaUp.includes("models")) {
|
|
449
|
+
lines.push(` ${cc.green}✓${cc.reset} Ollama: running`);
|
|
450
|
+
}
|
|
451
|
+
lines.push(`\n ${cc.dim}Say "openclaw status details" for full diagnostics${cc.reset}`);
|
|
452
|
+
return lines.join("\n");
|
|
380
453
|
}
|
|
381
454
|
// OpenClaw diagnose
|
|
382
455
|
if (intent.intent === "openclaw.diagnose") {
|
|
@@ -1249,6 +1322,22 @@ expect eof
|
|
|
1249
1322
|
return getRandomTip();
|
|
1250
1323
|
}
|
|
1251
1324
|
// Notoken status — comprehensive overview
|
|
1325
|
+
// notoken.versions — show current version and check for updates
|
|
1326
|
+
if (intent.intent === "notoken.versions" || intent.intent === "notoken.version") {
|
|
1327
|
+
try {
|
|
1328
|
+
const { checkForUpdate } = await import("../utils/updater.js");
|
|
1329
|
+
const info = await checkForUpdate();
|
|
1330
|
+
if (!info)
|
|
1331
|
+
return `\x1b[36mNoToken\x1b[0m v1.8.0\n\x1b[2mCould not check for updates.\x1b[0m`;
|
|
1332
|
+
if (info.updateAvailable) {
|
|
1333
|
+
return `\x1b[36mNoToken\x1b[0m v${info.current}\n\x1b[33m⬆ Update available: ${info.current} → ${info.latest}\x1b[0m\n\x1b[2m Run: notoken update or /update\x1b[0m`;
|
|
1334
|
+
}
|
|
1335
|
+
return `\x1b[36mNoToken\x1b[0m v${info.current}\n\x1b[32m✓ You're on the latest version.\x1b[0m`;
|
|
1336
|
+
}
|
|
1337
|
+
catch {
|
|
1338
|
+
return `\x1b[36mNoToken\x1b[0m v1.8.0`;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1252
1341
|
// notoken.jobs — in one-shot mode just say "use interactive mode"
|
|
1253
1342
|
if (intent.intent === "notoken.jobs") {
|
|
1254
1343
|
return `\x1b[32m✓\x1b[0m No background tasks (one-shot mode).\n\x1b[2m Run \x1b[1mnotoken\x1b[0m\x1b[2m for interactive mode with background task support.\x1b[0m`;
|
|
@@ -1397,6 +1486,178 @@ expect eof
|
|
|
1397
1486
|
}
|
|
1398
1487
|
}
|
|
1399
1488
|
}
|
|
1489
|
+
// ── Ollama environment detection — WSL vs Windows host ──
|
|
1490
|
+
// Detects where Ollama is installed and routes commands to the right side.
|
|
1491
|
+
// User can say "on windows" or "on wsl" to override.
|
|
1492
|
+
/**
|
|
1493
|
+
* Run an Ollama command on the right environment.
|
|
1494
|
+
* Detects: WSL local, Windows host, Docker container.
|
|
1495
|
+
* User can override with "on windows" / "on wsl" / "in docker".
|
|
1496
|
+
*/
|
|
1497
|
+
async function runOllama(cmd) {
|
|
1498
|
+
const isWSL = (await runLocalCommand("grep -qi microsoft /proc/version 2>/dev/null && echo wsl || echo native").catch(() => "native")).trim() === "wsl";
|
|
1499
|
+
const raw = intent.rawText.toLowerCase();
|
|
1500
|
+
// Explicit target from user
|
|
1501
|
+
const forceWindows = /\b(on\s+)?windows\b|\bhost\b/i.test(raw);
|
|
1502
|
+
const forceWSL = /\b(on\s+|in\s+)?wsl\b|\blinux\b/i.test(raw);
|
|
1503
|
+
const forceDocker = /\b(in\s+)?docker\b|\bcontainer\b/i.test(raw);
|
|
1504
|
+
// Default: run on current environment (where notoken is running)
|
|
1505
|
+
// Only check other environments if user explicitly asks or local fails
|
|
1506
|
+
const catchErr = (e) => { const err = e; return err.stdout ?? err.stderr ?? err.message ?? "failed"; };
|
|
1507
|
+
// Explicit overrides first
|
|
1508
|
+
if (forceDocker) {
|
|
1509
|
+
const container = (await runLocalCommand("docker ps --format '{{.Names}}' 2>/dev/null | grep -i ollama").catch(() => "")).trim().split("\n")[0];
|
|
1510
|
+
if (container) {
|
|
1511
|
+
console.log(`\x1b[2m[Ollama in Docker: ${container}]\x1b[0m`);
|
|
1512
|
+
return runLocalCommand(`docker exec ${container} ollama ${cmd} 2>&1`, 300_000).catch(catchErr);
|
|
1513
|
+
}
|
|
1514
|
+
return "No Ollama Docker container found. Start one: docker run -d --name ollama ollama/ollama";
|
|
1515
|
+
}
|
|
1516
|
+
if (forceWindows && isWSL) {
|
|
1517
|
+
console.log(`\x1b[2m[Ollama on Windows host]\x1b[0m`);
|
|
1518
|
+
return runLocalCommand(`cmd.exe /c 'ollama ${cmd}' 2>&1`, 300_000).catch(catchErr);
|
|
1519
|
+
}
|
|
1520
|
+
if (forceWSL || !isWSL) {
|
|
1521
|
+
// Current env is WSL or native Linux — run directly
|
|
1522
|
+
return runLocalCommand(`ollama ${cmd} 2>&1`, 300_000).catch(catchErr);
|
|
1523
|
+
}
|
|
1524
|
+
// Default for WSL: try local first, then Windows host
|
|
1525
|
+
const localResult = await runLocalCommand(`ollama ${cmd} 2>&1`, 300_000).catch(() => "");
|
|
1526
|
+
if (localResult && !localResult.includes("not found") && !localResult.includes("command not found")) {
|
|
1527
|
+
return localResult;
|
|
1528
|
+
}
|
|
1529
|
+
// Local failed — try Windows host silently
|
|
1530
|
+
const winResult = await runLocalCommand(`cmd.exe /c 'ollama ${cmd}' 2>&1`, 300_000).catch(() => "");
|
|
1531
|
+
if (winResult && !winResult.includes("not recognized")) {
|
|
1532
|
+
console.log(`\x1b[2m[Using Windows host Ollama]\x1b[0m`);
|
|
1533
|
+
return winResult;
|
|
1534
|
+
}
|
|
1535
|
+
return "Ollama not found. Install: curl -fsSL https://ollama.com/install.sh | sh";
|
|
1536
|
+
}
|
|
1537
|
+
// Ollama status — quick check if running + version
|
|
1538
|
+
if (intent.intent === "ollama.status") {
|
|
1539
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
1540
|
+
const lines = [];
|
|
1541
|
+
lines.push(`\n${cc.bold}${cc.cyan}── Ollama ──${cc.reset}\n`);
|
|
1542
|
+
// Check if installed
|
|
1543
|
+
const version = await runLocalCommand("ollama --version 2>/dev/null").catch(() => "");
|
|
1544
|
+
if (!version) {
|
|
1545
|
+
lines.push(` ${cc.red}✗${cc.reset} Ollama not installed`);
|
|
1546
|
+
lines.push(` ${cc.dim}Install: curl -fsSL https://ollama.com/install.sh | sh${cc.reset}`);
|
|
1547
|
+
return lines.join("\n");
|
|
1548
|
+
}
|
|
1549
|
+
lines.push(` ${cc.green}✓${cc.reset} Installed: ${version.trim()}`);
|
|
1550
|
+
// Check if running
|
|
1551
|
+
const tags = await runLocalCommand("curl -sf http://127.0.0.1:11434/api/tags 2>/dev/null").catch(() => "");
|
|
1552
|
+
if (tags.includes("models")) {
|
|
1553
|
+
const models = JSON.parse(tags).models ?? [];
|
|
1554
|
+
lines.push(` ${cc.green}✓${cc.reset} Running on port 11434`);
|
|
1555
|
+
lines.push(` ${cc.bold}Models:${cc.reset} ${models.length} installed`);
|
|
1556
|
+
for (const m of models.slice(0, 5)) {
|
|
1557
|
+
const size = (m.size / 1024 / 1024 / 1024).toFixed(1);
|
|
1558
|
+
lines.push(` ${cc.green}•${cc.reset} ${m.name} (${size}GB)`);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
else {
|
|
1562
|
+
lines.push(` ${cc.yellow}○${cc.reset} Not running`);
|
|
1563
|
+
lines.push(` ${cc.dim}Start: "start ollama"${cc.reset}`);
|
|
1564
|
+
}
|
|
1565
|
+
// GPU
|
|
1566
|
+
const gpu = await runLocalCommand("nvidia-smi --query-gpu=name,memory.total --format=csv,noheader,nounits 2>/dev/null").catch(() => "");
|
|
1567
|
+
if (gpu.trim()) {
|
|
1568
|
+
const [name, mem] = gpu.trim().split(",").map(s => s.trim());
|
|
1569
|
+
lines.push(` ${cc.bold}GPU:${cc.reset} ${name} (${mem}MB VRAM)`);
|
|
1570
|
+
}
|
|
1571
|
+
lines.push(`\n ${cc.dim}Say: "ollama models" for details, "ollama pull llama3.2" to download${cc.reset}`);
|
|
1572
|
+
return lines.join("\n");
|
|
1573
|
+
}
|
|
1574
|
+
// Ollama uninstall — platform-aware removal
|
|
1575
|
+
if (intent.intent === "ollama.uninstall") {
|
|
1576
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
1577
|
+
const isWSL = (await runLocalCommand("grep -qi microsoft /proc/version 2>/dev/null && echo wsl || echo native").catch(() => "native")).trim() === "wsl";
|
|
1578
|
+
const isWin = process.platform === "win32";
|
|
1579
|
+
const isMac = process.platform === "darwin";
|
|
1580
|
+
const removeModels = /\b(completely|everything|and models|all data)\b/i.test(intent.rawText);
|
|
1581
|
+
const lines = [];
|
|
1582
|
+
lines.push(`\n${cc.bold}${cc.cyan}── Uninstall Ollama ──${cc.reset}\n`);
|
|
1583
|
+
// Check what's installed
|
|
1584
|
+
const version = await runLocalCommand("ollama --version 2>/dev/null").catch(() => "");
|
|
1585
|
+
const models = await runLocalCommand("curl -sf http://127.0.0.1:11434/api/tags 2>/dev/null").catch(() => "");
|
|
1586
|
+
let modelCount = 0;
|
|
1587
|
+
let modelSize = "unknown";
|
|
1588
|
+
try {
|
|
1589
|
+
const parsed = JSON.parse(models);
|
|
1590
|
+
modelCount = parsed.models?.length ?? 0;
|
|
1591
|
+
const totalBytes = parsed.models?.reduce((sum, m) => sum + (m.size ?? 0), 0) ?? 0;
|
|
1592
|
+
modelSize = (totalBytes / 1024 / 1024 / 1024).toFixed(1) + "GB";
|
|
1593
|
+
}
|
|
1594
|
+
catch { }
|
|
1595
|
+
if (!version) {
|
|
1596
|
+
return `${cc.dim}Ollama doesn't appear to be installed.${cc.reset}`;
|
|
1597
|
+
}
|
|
1598
|
+
lines.push(` ${cc.bold}Installed:${cc.reset} ${version.trim()}`);
|
|
1599
|
+
if (modelCount > 0)
|
|
1600
|
+
lines.push(` ${cc.bold}Models:${cc.reset} ${modelCount} installed (${modelSize})`);
|
|
1601
|
+
// Stop the service first
|
|
1602
|
+
lines.push(`\n ${cc.dim}Stopping Ollama service...${cc.reset}`);
|
|
1603
|
+
await runLocalCommand("systemctl stop ollama 2>/dev/null").catch(() => "");
|
|
1604
|
+
await runLocalCommand("pkill -f ollama 2>/dev/null").catch(() => "");
|
|
1605
|
+
if (isWSL || (!isWin && !isMac)) {
|
|
1606
|
+
// Linux / WSL
|
|
1607
|
+
lines.push(` ${cc.bold}Platform:${cc.reset} ${isWSL ? "WSL" : "Linux"}`);
|
|
1608
|
+
// Remove binary
|
|
1609
|
+
await runLocalCommand("sudo rm -f /usr/local/bin/ollama 2>/dev/null").catch(() => "");
|
|
1610
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed /usr/local/bin/ollama`);
|
|
1611
|
+
// Remove systemd service
|
|
1612
|
+
await runLocalCommand("sudo systemctl disable ollama 2>/dev/null").catch(() => "");
|
|
1613
|
+
await runLocalCommand("sudo rm -f /etc/systemd/system/ollama.service 2>/dev/null").catch(() => "");
|
|
1614
|
+
await runLocalCommand("sudo systemctl daemon-reload 2>/dev/null").catch(() => "");
|
|
1615
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed systemd service`);
|
|
1616
|
+
// Remove user
|
|
1617
|
+
await runLocalCommand("sudo userdel -r ollama 2>/dev/null").catch(() => "");
|
|
1618
|
+
await runLocalCommand("sudo groupdel ollama 2>/dev/null").catch(() => "");
|
|
1619
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed ollama user/group`);
|
|
1620
|
+
// Remove models if requested
|
|
1621
|
+
if (removeModels) {
|
|
1622
|
+
const modelDirs = ["/usr/share/ollama", `${process.env.HOME}/.ollama`, process.env.OLLAMA_MODELS].filter(Boolean);
|
|
1623
|
+
for (const dir of modelDirs) {
|
|
1624
|
+
if (dir) {
|
|
1625
|
+
await runLocalCommand(`sudo rm -rf "${dir}" 2>/dev/null`).catch(() => "");
|
|
1626
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed ${dir}`);
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
else {
|
|
1631
|
+
lines.push(`\n ${cc.yellow}⚠${cc.reset} Models kept. To remove: "uninstall ollama completely"`);
|
|
1632
|
+
const modelDir = process.env.OLLAMA_MODELS ?? "/usr/share/ollama/.ollama/models";
|
|
1633
|
+
lines.push(` ${cc.dim}Model directory: ${modelDir}${cc.reset}`);
|
|
1634
|
+
}
|
|
1635
|
+
// Check Windows side too if in WSL
|
|
1636
|
+
if (isWSL) {
|
|
1637
|
+
const winOllama = await runLocalCommand("cmd.exe /c 'where ollama' 2>/dev/null").catch(() => "");
|
|
1638
|
+
if (winOllama.includes("ollama")) {
|
|
1639
|
+
lines.push(`\n ${cc.yellow}⚠${cc.reset} Ollama also installed on Windows host.`);
|
|
1640
|
+
lines.push(` ${cc.dim}To remove from Windows: Settings → Apps → Ollama → Uninstall${cc.reset}`);
|
|
1641
|
+
}
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
else if (isMac) {
|
|
1645
|
+
lines.push(` ${cc.bold}Platform:${cc.reset} macOS`);
|
|
1646
|
+
await runLocalCommand("brew uninstall ollama 2>/dev/null || rm -f /usr/local/bin/ollama").catch(() => "");
|
|
1647
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed Ollama`);
|
|
1648
|
+
if (removeModels) {
|
|
1649
|
+
await runLocalCommand(`rm -rf ${process.env.HOME}/.ollama 2>/dev/null`).catch(() => "");
|
|
1650
|
+
lines.push(` ${cc.green}✓${cc.reset} Removed ~/.ollama`);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
else if (isWin) {
|
|
1654
|
+
lines.push(` ${cc.bold}Platform:${cc.reset} Windows`);
|
|
1655
|
+
lines.push(` ${cc.dim}Use Settings → Apps → Ollama → Uninstall${cc.reset}`);
|
|
1656
|
+
lines.push(` ${cc.dim}Or: winget uninstall ollama${cc.reset}`);
|
|
1657
|
+
}
|
|
1658
|
+
lines.push(`\n ${cc.green}✓${cc.reset} ${cc.bold}Ollama uninstalled.${cc.reset}`);
|
|
1659
|
+
return lines.join("\n");
|
|
1660
|
+
}
|
|
1400
1661
|
// Ollama model management
|
|
1401
1662
|
if (intent.intent === "ollama.models" || intent.intent === "ollama.list") {
|
|
1402
1663
|
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
@@ -1405,8 +1666,8 @@ expect eof
|
|
|
1405
1666
|
const totalRAMGB = Math.round(parseInt(ramOut) / 1073741824);
|
|
1406
1667
|
const freeRamOut = await runLocalCommand("free -b | grep Mem | awk '{print $7}'").catch(() => "0");
|
|
1407
1668
|
const freeRAMGB = Math.round(parseInt(freeRamOut) / 1073741824);
|
|
1408
|
-
// Get installed models
|
|
1409
|
-
const installed = await
|
|
1669
|
+
// Get installed models — checks both WSL and Windows
|
|
1670
|
+
const installed = await runOllama("list").catch(() => "Ollama not running");
|
|
1410
1671
|
const lines = [];
|
|
1411
1672
|
lines.push(`\n${cc.bold}${cc.cyan}── Ollama Models ──${cc.reset}\n`);
|
|
1412
1673
|
lines.push(` ${cc.bold}System:${cc.reset} ${totalRAMGB}GB RAM (${freeRAMGB}GB available)\n`);
|
|
@@ -1526,7 +1787,7 @@ expect eof
|
|
|
1526
1787
|
}
|
|
1527
1788
|
console.log(lines.join("\n"));
|
|
1528
1789
|
console.log(`\n\x1b[2mPulling ${model}... this may take a few minutes.\x1b[0m`);
|
|
1529
|
-
result = await withSpinner(`Pulling ${model}...`, () =>
|
|
1790
|
+
result = await withSpinner(`Pulling ${model}...`, () => runOllama(`pull ${model}`));
|
|
1530
1791
|
return result;
|
|
1531
1792
|
}
|
|
1532
1793
|
// Ollama storage — check location & disk usage
|
|
@@ -1762,7 +2023,7 @@ expect eof
|
|
|
1762
2023
|
const model = fields.model ?? intent.rawText.match(/(?:remove|delete|rm)\s+(?:ollama\s+(?:model\s+)?)?(\S+)/i)?.[1];
|
|
1763
2024
|
if (!model)
|
|
1764
2025
|
return `\x1b[33mUsage: ollama remove <model>\x1b[0m\n\x1b[2m Example: "ollama remove llama3.2"\x1b[0m`;
|
|
1765
|
-
result = await withSpinner(`Removing ${model}...`, () =>
|
|
2026
|
+
result = await withSpinner(`Removing ${model}...`, () => runOllama(`rm ${model}`));
|
|
1766
2027
|
return result.includes("deleted") ? `\x1b[32m✓\x1b[0m Model ${model} removed.` : result;
|
|
1767
2028
|
}
|
|
1768
2029
|
// Codex CLI handlers
|
|
@@ -3104,6 +3365,87 @@ expect eof
|
|
|
3104
3365
|
}
|
|
3105
3366
|
return "";
|
|
3106
3367
|
}
|
|
3368
|
+
// File organization — uses LLM to categorize and move files
|
|
3369
|
+
if (intent.intent === "files.organize") {
|
|
3370
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
3371
|
+
const cwd = process.cwd();
|
|
3372
|
+
const fileList = await runLocalCommand(`ls -1 "${cwd}" 2>/dev/null`).catch(() => "");
|
|
3373
|
+
const fileCount = fileList.trim().split("\n").filter(Boolean).length;
|
|
3374
|
+
if (fileCount === 0)
|
|
3375
|
+
return `${cc.yellow}⚠${cc.reset} No files in current directory.`;
|
|
3376
|
+
if (fileCount < 3)
|
|
3377
|
+
return `${cc.dim}Only ${fileCount} files — not much to organize.${cc.reset}`;
|
|
3378
|
+
console.log(`${cc.cyan}Analyzing ${fileCount} files in ${cwd}...${cc.reset}`);
|
|
3379
|
+
try {
|
|
3380
|
+
const ollamaModel = process.env.NOTOKEN_OLLAMA_MODEL ?? "llama3.2";
|
|
3381
|
+
const prompt = `Files in folder:\n${fileList}\nGive me ONLY shell commands to organize these into directories. No explanation.\nStart with mkdir -p commands, then mv commands. Always include an Uncategorized folder for anything unclear.\nExample:\nmkdir -p photos videos documents Uncategorized\nmv photo.jpg photos/\nmv unknown.dat Uncategorized/\n\nOutput ONLY commands:`;
|
|
3382
|
+
const controller = new AbortController();
|
|
3383
|
+
const timeout = setTimeout(() => controller.abort(), 120_000);
|
|
3384
|
+
const resp = await fetch("http://127.0.0.1:11434/api/generate", {
|
|
3385
|
+
method: "POST",
|
|
3386
|
+
headers: { "Content-Type": "application/json" },
|
|
3387
|
+
signal: controller.signal,
|
|
3388
|
+
body: JSON.stringify({ model: ollamaModel, prompt, stream: false, options: { temperature: 0.1, num_predict: 4096 } }),
|
|
3389
|
+
});
|
|
3390
|
+
clearTimeout(timeout);
|
|
3391
|
+
const data = await resp.json();
|
|
3392
|
+
const commands = (data.response ?? "").split("\n").map((l) => l.trim()).filter((l) => l.startsWith("mkdir") || l.startsWith("mv "));
|
|
3393
|
+
const mkdirs = commands.filter((c) => c.startsWith("mkdir"));
|
|
3394
|
+
const mvs = commands.filter((c) => c.startsWith("mv"));
|
|
3395
|
+
if (commands.length === 0)
|
|
3396
|
+
return `${cc.yellow}⚠${cc.reset} LLM couldn't generate organization commands. Try being more specific.`;
|
|
3397
|
+
const dirs = mkdirs.join(" ").match(/[\w-]+/g)?.filter((d) => d !== "mkdir" && d !== "-p") ?? [];
|
|
3398
|
+
const lines = [`\n${cc.bold}${cc.cyan}── File Organization Plan ──${cc.reset}\n`];
|
|
3399
|
+
lines.push(` ${cc.bold}${fileCount} files${cc.reset} → ${cc.bold}${dirs.length} directories${cc.reset}\n`);
|
|
3400
|
+
lines.push(` ${cc.bold}Directories:${cc.reset} ${dirs.map((d) => `📁 ${d}`).join(" ")}\n`);
|
|
3401
|
+
lines.push(` ${cc.bold}Sample moves:${cc.reset}`);
|
|
3402
|
+
for (const mv of mvs.slice(0, 10)) {
|
|
3403
|
+
const parts = mv.match(/mv\s+(\S+)\s+(\S+)/);
|
|
3404
|
+
if (parts)
|
|
3405
|
+
lines.push(` ${cc.dim}${parts[1]}${cc.reset} → ${cc.cyan}${parts[2]}${cc.reset}`);
|
|
3406
|
+
}
|
|
3407
|
+
if (mvs.length > 10)
|
|
3408
|
+
lines.push(` ${cc.dim}... and ${mvs.length - 10} more moves${cc.reset}`);
|
|
3409
|
+
console.log(lines.join("\n"));
|
|
3410
|
+
suggestAction({ action: `cd "${cwd}" && ${commands.join(" && ")}`, description: `Organize ${fileCount} files into ${dirs.length} folders`, type: "command" });
|
|
3411
|
+
return `\n ${cc.bold}Execute this plan?${cc.reset} Say "yes" to proceed, or "cancel" to abort.`;
|
|
3412
|
+
}
|
|
3413
|
+
catch (err) {
|
|
3414
|
+
return `${cc.red}✗${cc.reset} LLM error: ${err.message?.substring(0, 100)}\n${cc.dim}Make sure Ollama is running.${cc.reset}`;
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
// File placement — suggest where a file should go
|
|
3418
|
+
if (intent.intent === "files.place") {
|
|
3419
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", cyan: "\x1b[36m" };
|
|
3420
|
+
const cwd = process.cwd();
|
|
3421
|
+
const dirStructure = await runLocalCommand(`find "${cwd}" -maxdepth 2 -type d 2>/dev/null | head -30`).catch(() => "");
|
|
3422
|
+
const fileMatch = intent.rawText.match(/(?:put|place|file)\s+(\S+\.\w+)/i) ?? intent.rawText.match(/(\S+\.\w{2,4})$/);
|
|
3423
|
+
const fileName = fileMatch?.[1] ?? "this file";
|
|
3424
|
+
try {
|
|
3425
|
+
const ollamaModel = process.env.NOTOKEN_OLLAMA_MODEL ?? "llama3.2";
|
|
3426
|
+
const prompt = `My directory structure:\n${dirStructure}\n\nWhere should I put "${fileName}"?\n\nComplete this JSON:\n\`\`\`json\n{"file": "${fileName}", "destination": "FILL_best_directory", "reason": "FILL_why", "command": "mv ${fileName} FILL/"}\n\`\`\`\nOutput only JSON:`;
|
|
3427
|
+
const controller = new AbortController();
|
|
3428
|
+
const timeout = setTimeout(() => controller.abort(), 60_000);
|
|
3429
|
+
const resp = await fetch("http://127.0.0.1:11434/api/generate", {
|
|
3430
|
+
method: "POST",
|
|
3431
|
+
headers: { "Content-Type": "application/json" },
|
|
3432
|
+
signal: controller.signal,
|
|
3433
|
+
body: JSON.stringify({ model: ollamaModel, prompt, stream: false, options: { temperature: 0.1, num_predict: 200 } }),
|
|
3434
|
+
});
|
|
3435
|
+
clearTimeout(timeout);
|
|
3436
|
+
const data = await resp.json();
|
|
3437
|
+
const jsonMatch = (data.response ?? "").match(/\{[\s\S]*\}/);
|
|
3438
|
+
if (jsonMatch) {
|
|
3439
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
3440
|
+
suggestAction({ action: parsed.command, description: `Move ${fileName} to ${parsed.destination}`, type: "command" });
|
|
3441
|
+
return `\n ${cc.bold}${parsed.file}${cc.reset} → ${cc.cyan}${parsed.destination}${cc.reset}\n ${cc.dim}${parsed.reason}${cc.reset}\n\n ${cc.dim}Say "yes" to move it.${cc.reset}`;
|
|
3442
|
+
}
|
|
3443
|
+
return `${cc.dim}${(data.response ?? "").substring(0, 200)}${cc.reset}`;
|
|
3444
|
+
}
|
|
3445
|
+
catch (err) {
|
|
3446
|
+
return `${cc.dim}Could not determine placement: ${err.message?.substring(0, 80)}${cc.reset}`;
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3107
3449
|
// Casual chat responses — loaded from config/chat-responses.json
|
|
3108
3450
|
if (intent.intent.startsWith("chat.")) {
|
|
3109
3451
|
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", cyan: "\x1b[36m", yellow: "\x1b[33m" };
|
|
@@ -3185,6 +3527,99 @@ expect eof
|
|
|
3185
3527
|
// Fallback if no JSON responses loaded
|
|
3186
3528
|
return `${cc.cyan}I'm NoToken.${cc.reset} Type "help" to see what I can do.`;
|
|
3187
3529
|
}
|
|
3530
|
+
// ── Tool uninstall ──
|
|
3531
|
+
if (intent.intent === "tool.uninstall") {
|
|
3532
|
+
let toolName = resolveToolName(intent.rawText) || (fields.tool ?? "").toLowerCase();
|
|
3533
|
+
toolName = TOOL_ALIASES[toolName] ?? toolName;
|
|
3534
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
3535
|
+
if (!toolName || !INSTALL_INFO[toolName]) {
|
|
3536
|
+
return `${cc.red}✗ Unknown tool: "${toolName || "?"}"\x1b[0m\n\n ${cc.dim}Available: ${Object.keys(INSTALL_INFO).join(", ")}${cc.reset}`;
|
|
3537
|
+
}
|
|
3538
|
+
const info = INSTALL_INFO[toolName];
|
|
3539
|
+
// Check if installed
|
|
3540
|
+
const existing = await runLocalCommand(info.check + " 2>/dev/null").catch(() => "");
|
|
3541
|
+
if (!existing) {
|
|
3542
|
+
return `${cc.dim}${info.name} is not installed — nothing to uninstall.${cc.reset}`;
|
|
3543
|
+
}
|
|
3544
|
+
console.log(`\n${cc.cyan}Uninstalling ${info.name}...${cc.reset}`);
|
|
3545
|
+
// Determine uninstall command
|
|
3546
|
+
let uninstallCmd = "";
|
|
3547
|
+
if (info.install.startsWith("npm ")) {
|
|
3548
|
+
// npm-based tools — npm uninstall -g
|
|
3549
|
+
const pkg = info.install.replace("npm install -g ", "");
|
|
3550
|
+
uninstallCmd = `npm uninstall -g ${pkg}`;
|
|
3551
|
+
}
|
|
3552
|
+
else if (toolName === "ollama") {
|
|
3553
|
+
if (process.platform === "win32") {
|
|
3554
|
+
uninstallCmd = `powershell -Command "Get-Process ollama -ErrorAction SilentlyContinue | Stop-Process -Force" 2>/dev/null; rm -rf "$(cygpath '$LOCALAPPDATA')/Programs/Ollama" 2>/dev/null; rm -rf "$(cygpath '$LOCALAPPDATA')/Ollama" 2>/dev/null`;
|
|
3555
|
+
}
|
|
3556
|
+
else {
|
|
3557
|
+
uninstallCmd = "sudo systemctl stop ollama 2>/dev/null; sudo rm -f /usr/local/bin/ollama; sudo rm -rf /usr/share/ollama";
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
else if (toolName === "docker") {
|
|
3561
|
+
uninstallCmd = process.platform === "win32"
|
|
3562
|
+
? `powershell -Command "echo 'Uninstall Docker Desktop from Settings > Apps'"`
|
|
3563
|
+
: "sudo apt-get remove -y docker-ce docker-ce-cli containerd.io 2>/dev/null || sudo dnf remove -y docker-ce docker-ce-cli containerd.io 2>/dev/null";
|
|
3564
|
+
}
|
|
3565
|
+
else {
|
|
3566
|
+
uninstallCmd = `echo '${info.name} — uninstall manually'`;
|
|
3567
|
+
}
|
|
3568
|
+
// For openclaw — also stop the gateway first
|
|
3569
|
+
if (toolName === "openclaw") {
|
|
3570
|
+
if (process.platform === "win32") {
|
|
3571
|
+
await runLocalCommand(`powershell -Command "Get-WmiObject Win32_Process -Filter \\"Name='node.exe'\\" | Where-Object { \\$_.CommandLine -match 'openclaw.*gateway' } | ForEach-Object { \\$_.Terminate() }" 2>/dev/null`).catch(() => "");
|
|
3572
|
+
}
|
|
3573
|
+
else {
|
|
3574
|
+
await runLocalCommand("pkill -f openclaw-gateway 2>/dev/null").catch(() => "");
|
|
3575
|
+
}
|
|
3576
|
+
await runLocalCommand("sleep 2").catch(() => { });
|
|
3577
|
+
console.log(`${cc.dim}Gateway stopped${cc.reset}`);
|
|
3578
|
+
}
|
|
3579
|
+
try {
|
|
3580
|
+
result = await withSpinner(`Uninstalling ${info.name}...`, () => runLocalCommand(uninstallCmd + " 2>&1", 120_000));
|
|
3581
|
+
// Verify removal
|
|
3582
|
+
const stillExists = await runLocalCommand(info.check + " 2>/dev/null").catch(() => "");
|
|
3583
|
+
if (!stillExists) {
|
|
3584
|
+
return `${cc.green}✓${cc.reset} ${info.name} uninstalled successfully.`;
|
|
3585
|
+
}
|
|
3586
|
+
return `${cc.yellow}⚠${cc.reset} Uninstall ran but ${info.name} may still be present.\n ${cc.dim}Try manually: ${uninstallCmd}${cc.reset}`;
|
|
3587
|
+
}
|
|
3588
|
+
catch (err) {
|
|
3589
|
+
return `${cc.red}✗ Uninstall failed:${cc.reset} ${err.message.split("\n")[0]}\n ${cc.dim}Try manually: ${uninstallCmd}${cc.reset}`;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
// ── Tool reinstall (uninstall + install) ──
|
|
3593
|
+
if (intent.intent === "tool.reinstall") {
|
|
3594
|
+
let toolName = resolveToolName(intent.rawText) || (fields.tool ?? "").toLowerCase();
|
|
3595
|
+
toolName = TOOL_ALIASES[toolName] ?? toolName;
|
|
3596
|
+
const cc = { reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m", green: "\x1b[32m", yellow: "\x1b[33m", red: "\x1b[31m", cyan: "\x1b[36m" };
|
|
3597
|
+
if (!toolName || !INSTALL_INFO[toolName]) {
|
|
3598
|
+
return `${cc.red}✗ Unknown tool: "${toolName || "?"}"\x1b[0m\n\n ${cc.dim}Available: ${Object.keys(INSTALL_INFO).join(", ")}${cc.reset}`;
|
|
3599
|
+
}
|
|
3600
|
+
const info = INSTALL_INFO[toolName];
|
|
3601
|
+
console.log(`\n${cc.cyan}Reinstalling ${info.name}...${cc.reset}\n`);
|
|
3602
|
+
// Uninstall first
|
|
3603
|
+
if (info.install.startsWith("npm ")) {
|
|
3604
|
+
const pkg = info.install.replace("npm install -g ", "");
|
|
3605
|
+
console.log(`${cc.dim}Uninstalling...${cc.reset}`);
|
|
3606
|
+
// Stop openclaw gateway if reinstalling openclaw
|
|
3607
|
+
if (toolName === "openclaw") {
|
|
3608
|
+
if (process.platform === "win32") {
|
|
3609
|
+
await runLocalCommand(`powershell -Command "Get-WmiObject Win32_Process -Filter \\"Name='node.exe'\\" | Where-Object { \\$_.CommandLine -match 'openclaw.*gateway' } | ForEach-Object { \\$_.Terminate() }" 2>/dev/null`).catch(() => "");
|
|
3610
|
+
}
|
|
3611
|
+
else {
|
|
3612
|
+
await runLocalCommand("pkill -f openclaw-gateway 2>/dev/null").catch(() => "");
|
|
3613
|
+
}
|
|
3614
|
+
await runLocalCommand("sleep 2").catch(() => { });
|
|
3615
|
+
}
|
|
3616
|
+
await withSpinner(`Uninstalling ${info.name}...`, () => runLocalCommand(`npm uninstall -g ${pkg} 2>&1`, 60_000)).catch(() => "");
|
|
3617
|
+
}
|
|
3618
|
+
// Install fresh — reuse the tool.install intent
|
|
3619
|
+
console.log(`${cc.dim}Installing fresh...${cc.reset}`);
|
|
3620
|
+
const fakeIntent = { ...intent, intent: "tool.install" };
|
|
3621
|
+
return executeIntent(fakeIntent);
|
|
3622
|
+
}
|
|
3188
3623
|
// Entity define/list
|
|
3189
3624
|
if (intent.intent === "entity.define")
|
|
3190
3625
|
return learnEntity(intent.rawText) ?? "Could not understand. Try: 'metroplex is 66.94.115.165'";
|
package/dist/index.d.ts
CHANGED
|
@@ -16,13 +16,16 @@ export { findSimilarIntents, phraseSimilarity, expandWithCooccurrences } from ".
|
|
|
16
16
|
export { loadKnowledgeGraph, saveKnowledgeGraph, addEntity, addRelation, getEntity, getRelated, resolveReference, resolveCandidates, inferIntent, queryGraph, rebuildGraph, learnFromExecution, flushGraph } from "./nlp/knowledgeGraph.js";
|
|
17
17
|
export { expandQuery, findCluster, suggestIntents, clusterWords } from "./nlp/conceptExpansion.js";
|
|
18
18
|
export { analyzeUncertainty, getUncoveredSpans } from "./nlp/uncertainty.js";
|
|
19
|
-
export { llmFallback, isLLMConfigured, getLLMBackend, formatLLMFallback } from "./nlp/llmFallback.js";
|
|
19
|
+
export { llmFallback, llmMultiTurn, isLLMConfigured, getLLMBackend, formatLLMFallback, addLLMContext, clearLLMContext } from "./nlp/llmFallback.js";
|
|
20
20
|
export { suggestEntityCorrection, correctEntities, resolveDescription, resetEntityVocab } from "./nlp/entitySpellCorrect.js";
|
|
21
21
|
export { recordOutcome, getMultiplier, calibrateVotes, recordCorrection, getCalibrationStats, flushCalibration } from "./nlp/confidenceCalibrator.js";
|
|
22
22
|
export { detectBatch, expandBatch, expandEnvironmentBatch } from "./nlp/batchParser.js";
|
|
23
23
|
export { getCurrentTopic, suggestFollowups, getTopicDefault } from "./conversation/topicTracker.js";
|
|
24
24
|
export { progressReporter, reportProgress, reportStep } from "./utils/progressReporter.js";
|
|
25
25
|
export { loadHistory as loadCommandHistory, addToHistory, searchHistory as searchCommandHistory, getRecentCommands, getReadlineHistory } from "./utils/commandHistory.js";
|
|
26
|
+
export { getUserContext, findFreshestClaudeToken, detectUserMismatch, getAuthProfilesPath, resetUserContext } from "./utils/userContext.js";
|
|
27
|
+
export { parseOpenclawModels, parseOpenclawStatus, parseOpenclawDeepStatus } from "./utils/openclawDiag.js";
|
|
28
|
+
export { parseLogLine, analyzeLogs, formatLogAnalysis } from "./utils/openclawLogParser.js";
|
|
26
29
|
export { recordCommand, getAchievements, getUsageStats, flushStats } from "./utils/achievements.js";
|
|
27
30
|
export { teachCommand, getLearnedCommand, listLearnedCommands, forgetCommand, parseTeachStatement } from "./utils/teachMode.js";
|
|
28
31
|
export { executeIntent, getRandomTip } from "./handlers/executor.js";
|
package/dist/index.js
CHANGED
|
@@ -17,7 +17,7 @@ export { findSimilarIntents, phraseSimilarity, expandWithCooccurrences } from ".
|
|
|
17
17
|
export { loadKnowledgeGraph, saveKnowledgeGraph, addEntity, addRelation, getEntity, getRelated, resolveReference, resolveCandidates, inferIntent, queryGraph, rebuildGraph, learnFromExecution, flushGraph } from "./nlp/knowledgeGraph.js";
|
|
18
18
|
export { expandQuery, findCluster, suggestIntents, clusterWords } from "./nlp/conceptExpansion.js";
|
|
19
19
|
export { analyzeUncertainty, getUncoveredSpans } from "./nlp/uncertainty.js";
|
|
20
|
-
export { llmFallback, isLLMConfigured, getLLMBackend, formatLLMFallback } from "./nlp/llmFallback.js";
|
|
20
|
+
export { llmFallback, llmMultiTurn, isLLMConfigured, getLLMBackend, formatLLMFallback, addLLMContext, clearLLMContext } from "./nlp/llmFallback.js";
|
|
21
21
|
export { suggestEntityCorrection, correctEntities, resolveDescription, resetEntityVocab } from "./nlp/entitySpellCorrect.js";
|
|
22
22
|
export { recordOutcome, getMultiplier, calibrateVotes, recordCorrection, getCalibrationStats, flushCalibration } from "./nlp/confidenceCalibrator.js";
|
|
23
23
|
export { detectBatch, expandBatch, expandEnvironmentBatch } from "./nlp/batchParser.js";
|
|
@@ -25,6 +25,10 @@ export { getCurrentTopic, suggestFollowups, getTopicDefault } from "./conversati
|
|
|
25
25
|
// ── Progress & History ──
|
|
26
26
|
export { progressReporter, reportProgress, reportStep } from "./utils/progressReporter.js";
|
|
27
27
|
export { loadHistory as loadCommandHistory, addToHistory, searchHistory as searchCommandHistory, getRecentCommands, getReadlineHistory } from "./utils/commandHistory.js";
|
|
28
|
+
// ── User Context & OpenClaw Parsing ──
|
|
29
|
+
export { getUserContext, findFreshestClaudeToken, detectUserMismatch, getAuthProfilesPath, resetUserContext } from "./utils/userContext.js";
|
|
30
|
+
export { parseOpenclawModels, parseOpenclawStatus, parseOpenclawDeepStatus } from "./utils/openclawDiag.js";
|
|
31
|
+
export { parseLogLine, analyzeLogs, formatLogAnalysis } from "./utils/openclawLogParser.js";
|
|
28
32
|
// ── Achievements & Teach ──
|
|
29
33
|
export { recordCommand, getAchievements, getUsageStats, flushStats } from "./utils/achievements.js";
|
|
30
34
|
export { teachCommand, getLearnedCommand, listLearnedCommands, forgetCommand, parseTeachStatement } from "./utils/teachMode.js";
|
|
@@ -22,8 +22,27 @@ export interface LLMFallbackResult {
|
|
|
22
22
|
intent?: string;
|
|
23
23
|
command?: string;
|
|
24
24
|
}>;
|
|
25
|
+
/** Raw shell commands to run if no intent matches */
|
|
26
|
+
shellCommands?: string[];
|
|
27
|
+
/** Questions to ask the user for clarification */
|
|
25
28
|
missingInfo?: string[];
|
|
29
|
+
/** Commands to run first to gather info before answering (multi-turn) */
|
|
30
|
+
gatherCommands?: Array<{
|
|
31
|
+
command: string;
|
|
32
|
+
purpose: string;
|
|
33
|
+
}>;
|
|
34
|
+
/** Whether the LLM needs more info from command outputs before it can answer */
|
|
35
|
+
needsMoreInfo?: boolean;
|
|
26
36
|
}
|
|
37
|
+
/** Add a turn to the LLM conversation for multi-turn context */
|
|
38
|
+
export declare function addLLMContext(role: "user" | "assistant", content: string): void;
|
|
39
|
+
/** Clear LLM conversation when topic changes */
|
|
40
|
+
export declare function clearLLMContext(): void;
|
|
41
|
+
/** Get conversation for context in multi-turn */
|
|
42
|
+
export declare function getLLMContext(): Array<{
|
|
43
|
+
role: "user" | "assistant";
|
|
44
|
+
content: string;
|
|
45
|
+
}>;
|
|
27
46
|
/**
|
|
28
47
|
* Check if any LLM is configured.
|
|
29
48
|
*/
|
|
@@ -47,6 +66,34 @@ export declare function llmFallback(rawText: string, context: {
|
|
|
47
66
|
type: string;
|
|
48
67
|
}>;
|
|
49
68
|
uncertainTokens?: string[];
|
|
69
|
+
nearMisses?: Array<{
|
|
70
|
+
intent: string;
|
|
71
|
+
score: number;
|
|
72
|
+
source: string;
|
|
73
|
+
}>;
|
|
74
|
+
}): Promise<LLMFallbackResult | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Multi-turn LLM disambiguation.
|
|
77
|
+
*
|
|
78
|
+
* 1. Ask the LLM what to do
|
|
79
|
+
* 2. If it needs more info → run gatherCommands → feed results back
|
|
80
|
+
* 3. Repeat up to maxTurns times
|
|
81
|
+
* 4. Return the final result
|
|
82
|
+
*/
|
|
83
|
+
export declare function llmMultiTurn(rawText: string, context: {
|
|
84
|
+
recentIntents?: string[];
|
|
85
|
+
knownEntities?: Array<{
|
|
86
|
+
entity: string;
|
|
87
|
+
type: string;
|
|
88
|
+
}>;
|
|
89
|
+
nearMisses?: Array<{
|
|
90
|
+
intent: string;
|
|
91
|
+
score: number;
|
|
92
|
+
source: string;
|
|
93
|
+
}>;
|
|
94
|
+
}, options?: {
|
|
95
|
+
maxTurns?: number;
|
|
96
|
+
onProgress?: (msg: string) => void;
|
|
50
97
|
}): Promise<LLMFallbackResult | null>;
|
|
51
98
|
/**
|
|
52
99
|
* Check if Ollama is installed (not just running).
|