@kernel.chat/kbot 3.99.18 → 3.99.20
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/dist/auth.js +8 -1
- package/dist/cli.js +23 -0
- package/dist/memory-prune.d.ts +19 -0
- package/dist/memory-prune.js +77 -0
- package/package.json +1 -1
package/dist/auth.js
CHANGED
|
@@ -881,7 +881,14 @@ export function classifyComplexity(message) {
|
|
|
881
881
|
return 'complex';
|
|
882
882
|
}
|
|
883
883
|
// Moderate: code generation, file modifications, research
|
|
884
|
-
if (/\b(create|write|add|implement|update|modify|change|fix|search|research|find|analyze|generate|test)\b/i.test(lower)) {
|
|
884
|
+
if (/\b(create|write|add|implement|update|modify|change|fix|search|research|find|analyze|generate|test|read|look|check|show|tell|describe|audit|inspect)\b/i.test(lower)) {
|
|
885
|
+
return 'moderate';
|
|
886
|
+
}
|
|
887
|
+
// Any reference to a file path or directory requires tool use, which needs
|
|
888
|
+
// the default (larger) model. The fast model is for stateless chitchat only.
|
|
889
|
+
if (/\b[\w./-]+\.(ts|tsx|js|jsx|json|md|py|rs|go|toml|yaml|yml|sh|html|css|sql)\b/i.test(lower)
|
|
890
|
+
|| /(?:\.\/|src\/|packages\/|tools\/|supabase\/|\.kbot\/|\.claude\/|~\/|\/users\/)/i.test(lower)
|
|
891
|
+
|| /\b(file|directory|folder|path|repo|codebase|package\.json|readme)\b/i.test(lower)) {
|
|
885
892
|
return 'moderate';
|
|
886
893
|
}
|
|
887
894
|
// Simple: questions, lookups, short tasks
|
package/dist/cli.js
CHANGED
|
@@ -879,6 +879,29 @@ async function main() {
|
|
|
879
879
|
printInfo(` ${result.skipped} skipped (existing user-authored files preserved)`);
|
|
880
880
|
printInfo(` → ${result.destination}`);
|
|
881
881
|
});
|
|
882
|
+
const memoryCmd = program.command('memory').description('Inspect or prune kbot\'s memory store');
|
|
883
|
+
memoryCmd
|
|
884
|
+
.command('prune')
|
|
885
|
+
.description('Compact ~/.kbot/memory/solutions.json — removes stale, unused, or obsolete entries')
|
|
886
|
+
.option('--max-age-days <n>', 'Drop entries older than N days with zero reuses', '30')
|
|
887
|
+
.option('--obsolete-version <prefix>', 'Drop entries whose solution mentions this version prefix')
|
|
888
|
+
.option('--dry-run', 'Count what would be pruned without writing')
|
|
889
|
+
.action(async (opts) => {
|
|
890
|
+
const { pruneSolutions } = await import('./memory-prune.js');
|
|
891
|
+
const result = pruneSolutions({
|
|
892
|
+
maxAgeDays: opts.maxAgeDays ? parseInt(opts.maxAgeDays, 10) : undefined,
|
|
893
|
+
obsoleteVersionPrefix: opts.obsoleteVersion,
|
|
894
|
+
dryRun: opts.dryRun,
|
|
895
|
+
});
|
|
896
|
+
printInfo(`Total: ${result.total} · Kept: ${result.kept} · Pruned: ${result.pruned}`);
|
|
897
|
+
for (const [reason, count] of Object.entries(result.reasons)) {
|
|
898
|
+
printInfo(` ${reason}: ${count}`);
|
|
899
|
+
}
|
|
900
|
+
if (result.backup)
|
|
901
|
+
printSuccess(`Backup written: ${result.backup}`);
|
|
902
|
+
if (opts.dryRun)
|
|
903
|
+
printInfo('(dry run — no changes written)');
|
|
904
|
+
});
|
|
882
905
|
program
|
|
883
906
|
.command('design <brief...>')
|
|
884
907
|
.description('Local-first alternative to Claude Design. Reads your repo\'s design tokens and generates an HTML prototype applying your visual system.')
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface PruneOptions {
|
|
2
|
+
/** Drop entries older than this many days (default: 30) */
|
|
3
|
+
maxAgeDays?: number;
|
|
4
|
+
/** Drop entries whose solution mentions versions below this (e.g. "3.99.0") */
|
|
5
|
+
obsoleteVersionPrefix?: string;
|
|
6
|
+
/** Drop entries with confidence < this and reuses === 0 (default: 0.3) */
|
|
7
|
+
minConfidenceIfUnused?: number;
|
|
8
|
+
/** Dry run — count what would be pruned without writing */
|
|
9
|
+
dryRun?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface PruneResult {
|
|
12
|
+
total: number;
|
|
13
|
+
kept: number;
|
|
14
|
+
pruned: number;
|
|
15
|
+
reasons: Record<string, number>;
|
|
16
|
+
backup?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function pruneSolutions(opts?: PruneOptions): PruneResult;
|
|
19
|
+
//# sourceMappingURL=memory-prune.d.ts.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Memory prune — compact ~/.kbot/memory/solutions.json by removing entries
|
|
2
|
+
// that are likely stale: outdated version references, old timestamps, or low
|
|
3
|
+
// confidence + zero reuses. Lightweight, safe, reversible (writes a .bak file).
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, copyFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { homedir } from 'node:os';
|
|
7
|
+
export function pruneSolutions(opts = {}) {
|
|
8
|
+
const maxAgeDays = opts.maxAgeDays ?? 30;
|
|
9
|
+
const minConf = opts.minConfidenceIfUnused ?? 0.3;
|
|
10
|
+
const obsoletePrefix = opts.obsoleteVersionPrefix;
|
|
11
|
+
const path = join(homedir(), '.kbot', 'memory', 'solutions.json');
|
|
12
|
+
if (!existsSync(path)) {
|
|
13
|
+
return { total: 0, kept: 0, pruned: 0, reasons: {} };
|
|
14
|
+
}
|
|
15
|
+
const raw = readFileSync(path, 'utf-8');
|
|
16
|
+
let entries;
|
|
17
|
+
try {
|
|
18
|
+
entries = JSON.parse(raw);
|
|
19
|
+
if (!Array.isArray(entries))
|
|
20
|
+
throw new Error('not array');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { total: 0, kept: 0, pruned: 0, reasons: { parse_error: 1 } };
|
|
24
|
+
}
|
|
25
|
+
const cutoff = Date.now() - maxAgeDays * 24 * 60 * 60 * 1000;
|
|
26
|
+
const reasons = {};
|
|
27
|
+
const kept = [];
|
|
28
|
+
for (const e of entries) {
|
|
29
|
+
const createdMs = toMillis(e.created);
|
|
30
|
+
const reuses = e.reuses ?? 0;
|
|
31
|
+
const conf = e.confidence ?? 0.5;
|
|
32
|
+
const solution = String(e.solution ?? '');
|
|
33
|
+
// Age: anything older than cutoff AND never reused gets pruned
|
|
34
|
+
if (createdMs > 0 && createdMs < cutoff && reuses === 0) {
|
|
35
|
+
reasons.stale_and_unused = (reasons.stale_and_unused || 0) + 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
// Obsolete version references
|
|
39
|
+
if (obsoletePrefix && solution.includes(obsoletePrefix)) {
|
|
40
|
+
reasons.obsolete_version = (reasons.obsolete_version || 0) + 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Low confidence and never reused — likely wrong from the start
|
|
44
|
+
if (conf < minConf && reuses === 0) {
|
|
45
|
+
reasons.low_confidence_unused = (reasons.low_confidence_unused || 0) + 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
// Empty or tiny solution content
|
|
49
|
+
if (solution.trim().length < 20) {
|
|
50
|
+
reasons.empty_solution = (reasons.empty_solution || 0) + 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
kept.push(e);
|
|
54
|
+
}
|
|
55
|
+
const result = {
|
|
56
|
+
total: entries.length,
|
|
57
|
+
kept: kept.length,
|
|
58
|
+
pruned: entries.length - kept.length,
|
|
59
|
+
reasons,
|
|
60
|
+
};
|
|
61
|
+
if (!opts.dryRun && result.pruned > 0) {
|
|
62
|
+
const backup = path + '.bak';
|
|
63
|
+
copyFileSync(path, backup);
|
|
64
|
+
writeFileSync(path, JSON.stringify(kept, null, 2));
|
|
65
|
+
result.backup = backup;
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function toMillis(created) {
|
|
70
|
+
if (!created)
|
|
71
|
+
return 0;
|
|
72
|
+
if (typeof created === 'number')
|
|
73
|
+
return created > 1e12 ? created : created * 1000;
|
|
74
|
+
const parsed = Date.parse(created);
|
|
75
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=memory-prune.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kernel.chat/kbot",
|
|
3
|
-
"version": "3.99.
|
|
3
|
+
"version": "3.99.20",
|
|
4
4
|
"description": "Open-source terminal AI agent. 787+ tools, 35 agents, 20 providers. Dreams, learns, watches your system. Controls your phone. Fully local, fully sovereign. MIT.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|