blun-king-cli 9.1.225 → 9.1.227
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.
|
@@ -12,7 +12,9 @@ const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
|
12
12
|
'current', 'inbox', 'latest', 'message', 'messages', 'nachricht', 'nachrichten', 'queue', 'queued',
|
|
13
13
|
'recent', 'update', 'updates',
|
|
14
14
|
]),
|
|
15
|
-
Object.freeze([
|
|
15
|
+
Object.freeze([
|
|
16
|
+
'chat', 'conversation', 'history', 'log', 'logs', 'processed', 'protokoll', 'transcript', 'verlauf',
|
|
17
|
+
]),
|
|
16
18
|
Object.freeze([
|
|
17
19
|
'fact', 'facts', 'fakt', 'fakten', 'memory', 'memories', 'merk', 'merken', 'note', 'notes',
|
|
18
20
|
'persist', 'persistent', 'profile', 'remember', 'save', 'speichern', 'store',
|
|
@@ -20,7 +22,7 @@ const TOOL_SEARCH_RELATED_TERM_GROUPS = Object.freeze([
|
|
|
20
22
|
]);
|
|
21
23
|
const TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS = new Set([
|
|
22
24
|
'fact', 'facts', 'fakt', 'fakten', 'memory', 'memories', 'merk', 'merken', 'note', 'notes',
|
|
23
|
-
'persist', 'persistent', 'profile', 'remember', 'save', 'speichern', 'store',
|
|
25
|
+
'persist', 'persistent', 'profile', 'remember', 'save', 'speichern', 'store', 'transcript',
|
|
24
26
|
]);
|
|
25
27
|
const CORE_TOOL_NAMES = Object.freeze([
|
|
26
28
|
'Bash',
|
|
@@ -129,18 +131,26 @@ function relatedSearchTerms(token) {
|
|
|
129
131
|
return group || [token];
|
|
130
132
|
}
|
|
131
133
|
|
|
132
|
-
function searchRelatedDeferredTools(tools, query) {
|
|
134
|
+
function searchRelatedDeferredTools(tools, query, options = {}) {
|
|
133
135
|
const normalized = String(query || '').trim().toLowerCase();
|
|
134
136
|
if (!normalized || normalized.startsWith('select:')) return [];
|
|
135
137
|
const tokens = normalized.split(/\s+/).filter(Boolean);
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
.
|
|
138
|
+
const requestedNameTokens = tokens
|
|
139
|
+
.filter((token) => token.startsWith('+'))
|
|
140
|
+
.map((token) => token.slice(1))
|
|
141
|
+
.filter(Boolean);
|
|
142
|
+
const relaxRequiredNameTokens = options.relaxRequiredNameTokens === true
|
|
143
|
+
&& requestedNameTokens.length > 0;
|
|
144
|
+
const requiredNameTokens = relaxRequiredNameTokens ? [] : requestedNameTokens;
|
|
145
|
+
const searchTokens = [
|
|
146
|
+
...tokens.filter((token) => !token.startsWith('+')),
|
|
147
|
+
...(relaxRequiredNameTokens ? requestedNameTokens : []),
|
|
148
|
+
]
|
|
139
149
|
.filter((token) => !TOOL_SEARCH_INTENT_WORDS.has(token));
|
|
140
150
|
if (searchTokens.length < 2 && !TOOL_SEARCH_SINGLE_TERM_RELATED_FALLBACKS.has(searchTokens[0])) return [];
|
|
141
151
|
const minimumMatchedTokens = searchTokens.length === 1 ? 1 : Math.max(2, Math.ceil(searchTokens.length * 0.75));
|
|
142
152
|
|
|
143
|
-
|
|
153
|
+
const ranked = tools.map((tool) => {
|
|
144
154
|
const name = String(tool?.name || '').toLowerCase();
|
|
145
155
|
const description = String(tool?.description || '').toLowerCase();
|
|
146
156
|
if (!requiredNameTokens.every((token) => name.includes(token))) return null;
|
|
@@ -171,7 +181,14 @@ function searchRelatedDeferredTools(tools, query) {
|
|
|
171
181
|
right.matchedTokens - left.matchedTokens
|
|
172
182
|
|| right.score - left.score
|
|
173
183
|
|| String(left.tool.name).localeCompare(String(right.tool.name))
|
|
174
|
-
))
|
|
184
|
+
));
|
|
185
|
+
if (relaxRequiredNameTokens && ranked.length > 0) {
|
|
186
|
+
const best = ranked[0];
|
|
187
|
+
return ranked.filter((entry) => (
|
|
188
|
+
entry.matchedTokens === best.matchedTokens && entry.score === best.score
|
|
189
|
+
)).slice(0, 5).map((entry) => entry.tool);
|
|
190
|
+
}
|
|
191
|
+
return ranked.slice(0, 5).map((entry) => entry.tool);
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
function rememberLoadedTool(loadedToolNames, name) {
|
|
@@ -223,6 +240,12 @@ function createDeferredToolLoader(selectedTools, deferredTools, loadedToolNames
|
|
|
223
240
|
matches = searchRelatedDeferredTools([...available.values()], query);
|
|
224
241
|
relatedFallback = matches.length > 0;
|
|
225
242
|
}
|
|
243
|
+
if (matches.length === 0) {
|
|
244
|
+
matches = searchRelatedDeferredTools([...available.values()], query, {
|
|
245
|
+
relaxRequiredNameTokens: true,
|
|
246
|
+
});
|
|
247
|
+
relatedFallback = matches.length > 0;
|
|
248
|
+
}
|
|
226
249
|
if (matches.length === 0) {
|
|
227
250
|
const alreadyLoaded = query.toLowerCase().startsWith('select:')
|
|
228
251
|
? searchDeferredTools(
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CANDIDATE_ID = /^vl-[a-f0-9]{32}$/iu;
|
|
4
|
+
const COMMAND_HASH = /^[a-f0-9]{64}$/iu;
|
|
5
|
+
const TOOL_NAME = /^[a-z0-9._ -]{1,64}$/iu;
|
|
6
|
+
|
|
7
|
+
function safeLatestCandidate(candidate) {
|
|
8
|
+
const id = typeof candidate?.id === 'string' && CANDIDATE_ID.test(candidate.id)
|
|
9
|
+
? candidate.id
|
|
10
|
+
: 'unknown';
|
|
11
|
+
const toolName = typeof candidate?.verification?.toolName === 'string'
|
|
12
|
+
&& TOOL_NAME.test(candidate.verification.toolName)
|
|
13
|
+
? candidate.verification.toolName
|
|
14
|
+
: 'unknown';
|
|
15
|
+
const commandHash = typeof candidate?.verification?.commandHash === 'string'
|
|
16
|
+
&& COMMAND_HASH.test(candidate.verification.commandHash)
|
|
17
|
+
? candidate.verification.commandHash.slice(0, 12)
|
|
18
|
+
: 'unknown';
|
|
19
|
+
return { id, toolName, commandHash };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function buildValidatedLearningInsight(candidates) {
|
|
23
|
+
const insight = {
|
|
24
|
+
pending: 0,
|
|
25
|
+
recorded: 0,
|
|
26
|
+
expired: 0,
|
|
27
|
+
latestPending: null,
|
|
28
|
+
};
|
|
29
|
+
let latestCandidate = null;
|
|
30
|
+
let latestTime = Number.NEGATIVE_INFINITY;
|
|
31
|
+
|
|
32
|
+
for (const candidate of Array.isArray(candidates) ? candidates : []) {
|
|
33
|
+
if (!candidate || typeof candidate !== 'object') continue;
|
|
34
|
+
if (candidate.status === 'recorded') {
|
|
35
|
+
insight.recorded += 1;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (candidate.status === 'expired') {
|
|
39
|
+
insight.expired += 1;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (candidate.status !== 'pending') continue;
|
|
43
|
+
|
|
44
|
+
insight.pending += 1;
|
|
45
|
+
const candidateTime = Date.parse(candidate.createdAt);
|
|
46
|
+
if (latestCandidate === null || (Number.isFinite(candidateTime) && candidateTime >= latestTime)) {
|
|
47
|
+
latestCandidate = candidate;
|
|
48
|
+
latestTime = Number.isFinite(candidateTime) ? candidateTime : latestTime;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (latestCandidate !== null) insight.latestPending = safeLatestCandidate(latestCandidate);
|
|
53
|
+
return insight;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
buildValidatedLearningInsight,
|
|
58
|
+
};
|
package/blun.mjs
CHANGED
|
@@ -340810,7 +340810,13 @@ registerUiCatalogFragment({
|
|
|
340810
340810
|
en: {
|
|
340811
340811
|
"command.update.description": "Configure updates",
|
|
340812
340812
|
"command.premortem.description": "Stress-test a plan before execution",
|
|
340813
|
+
"command.improve.description": "Show validated learning status",
|
|
340813
340814
|
"premortem.usage": "Usage: /premortem <plan or decision>",
|
|
340815
|
+
"learning.panel.title": "Validated learning",
|
|
340816
|
+
"learning.counts": "Pending: {pending} · Recorded: {recorded} · Expired: {expired}",
|
|
340817
|
+
"learning.latest": "Latest candidate",
|
|
340818
|
+
"learning.verification": "Verification",
|
|
340819
|
+
"learning.empty": "No validated learning candidates yet.",
|
|
340814
340820
|
"update.title": "Update behavior",
|
|
340815
340821
|
"update.hint": "↑↓ navigate · Enter select · Esc cancel",
|
|
340816
340822
|
"update.manual.label": "Manual updates",
|
|
@@ -340827,7 +340833,13 @@ registerUiCatalogFragment({
|
|
|
340827
340833
|
de: {
|
|
340828
340834
|
"command.update.description": "Updates konfigurieren",
|
|
340829
340835
|
"command.premortem.description": "Einen Plan vor der Umsetzung auf Schwachstellen prüfen",
|
|
340836
|
+
"command.improve.description": "Status des validierten Lernens anzeigen",
|
|
340830
340837
|
"premortem.usage": "Verwendung: /premortem <Plan oder Entscheidung>",
|
|
340838
|
+
"learning.panel.title": "Validiertes Lernen",
|
|
340839
|
+
"learning.counts": "Offen: {pending} · Übernommen: {recorded} · Abgelaufen: {expired}",
|
|
340840
|
+
"learning.latest": "Neuester Kandidat",
|
|
340841
|
+
"learning.verification": "Prüfung",
|
|
340842
|
+
"learning.empty": "Noch keine validierten Lernkandidaten vorhanden.",
|
|
340831
340843
|
"update.title": "Update-Verhalten",
|
|
340832
340844
|
"update.hint": "↑↓ navigieren · Enter auswählen · Esc abbrechen",
|
|
340833
340845
|
"update.manual.label": "Updates von Hand",
|
|
@@ -340844,7 +340856,13 @@ registerUiCatalogFragment({
|
|
|
340844
340856
|
es: {
|
|
340845
340857
|
"command.update.description": "Configurar actualizaciones",
|
|
340846
340858
|
"command.premortem.description": "Someter un plan a una prueba de estrés antes de ejecutarlo",
|
|
340859
|
+
"command.improve.description": "Mostrar el estado del aprendizaje validado",
|
|
340847
340860
|
"premortem.usage": "Uso: /premortem <plan o decisión>",
|
|
340861
|
+
"learning.panel.title": "Aprendizaje validado",
|
|
340862
|
+
"learning.counts": "Pendientes: {pending} · Registrados: {recorded} · Caducados: {expired}",
|
|
340863
|
+
"learning.latest": "Candidato más reciente",
|
|
340864
|
+
"learning.verification": "Verificación",
|
|
340865
|
+
"learning.empty": "Todavía no hay candidatos de aprendizaje validados.",
|
|
340848
340866
|
"update.title": "Comportamiento de las actualizaciones",
|
|
340849
340867
|
"update.hint": "↑↓ navegar · Enter seleccionar · Esc cancelar",
|
|
340850
340868
|
"update.manual.label": "Actualizaciones manuales",
|
|
@@ -340861,7 +340879,13 @@ registerUiCatalogFragment({
|
|
|
340861
340879
|
fr: {
|
|
340862
340880
|
"command.update.description": "Configurer les mises à jour",
|
|
340863
340881
|
"command.premortem.description": "Mettre un plan à l’épreuve avant son exécution",
|
|
340882
|
+
"command.improve.description": "Afficher l’état de l’apprentissage validé",
|
|
340864
340883
|
"premortem.usage": "Utilisation : /premortem <plan ou décision>",
|
|
340884
|
+
"learning.panel.title": "Apprentissage validé",
|
|
340885
|
+
"learning.counts": "En attente : {pending} · Enregistrés : {recorded} · Expirés : {expired}",
|
|
340886
|
+
"learning.latest": "Candidat le plus récent",
|
|
340887
|
+
"learning.verification": "Vérification",
|
|
340888
|
+
"learning.empty": "Aucun candidat d’apprentissage validé pour le moment.",
|
|
340865
340889
|
"update.title": "Comportement des mises à jour",
|
|
340866
340890
|
"update.hint": "↑↓ naviguer · Entrée sélectionner · Échap annuler",
|
|
340867
340891
|
"update.manual.label": "Mises à jour manuelles",
|
|
@@ -340878,7 +340902,13 @@ registerUiCatalogFragment({
|
|
|
340878
340902
|
sv: {
|
|
340879
340903
|
"command.update.description": "Konfigurera uppdateringar",
|
|
340880
340904
|
"command.premortem.description": "Stresstesta en plan före genomförandet",
|
|
340905
|
+
"command.improve.description": "Visa status för validerat lärande",
|
|
340881
340906
|
"premortem.usage": "Användning: /premortem <plan eller beslut>",
|
|
340907
|
+
"learning.panel.title": "Validerat lärande",
|
|
340908
|
+
"learning.counts": "Väntande: {pending} · Registrerade: {recorded} · Utgångna: {expired}",
|
|
340909
|
+
"learning.latest": "Senaste kandidaten",
|
|
340910
|
+
"learning.verification": "Verifiering",
|
|
340911
|
+
"learning.empty": "Det finns inga validerade inlärningskandidater ännu.",
|
|
340882
340912
|
"update.title": "Uppdateringsbeteende",
|
|
340883
340913
|
"update.hint": "↑↓ navigera · Enter välj · Esc avbryt",
|
|
340884
340914
|
"update.manual.label": "Manuella uppdateringar",
|
|
@@ -340895,7 +340925,13 @@ registerUiCatalogFragment({
|
|
|
340895
340925
|
cs: {
|
|
340896
340926
|
"command.update.description": "Nastavit aktualizace",
|
|
340897
340927
|
"command.premortem.description": "Prověřit plán před provedením zátěžovým testem",
|
|
340928
|
+
"command.improve.description": "Zobrazit stav ověřeného učení",
|
|
340898
340929
|
"premortem.usage": "Použití: /premortem <plán nebo rozhodnutí>",
|
|
340930
|
+
"learning.panel.title": "Ověřené učení",
|
|
340931
|
+
"learning.counts": "Čekající: {pending} · Zaznamenané: {recorded} · Prošlé: {expired}",
|
|
340932
|
+
"learning.latest": "Nejnovější kandidát",
|
|
340933
|
+
"learning.verification": "Ověření",
|
|
340934
|
+
"learning.empty": "Zatím nejsou k dispozici žádní kandidáti ověřeného učení.",
|
|
340899
340935
|
"update.title": "Chování aktualizací",
|
|
340900
340936
|
"update.hint": "↑↓ navigace · Enter vybrat · Esc zrušit",
|
|
340901
340937
|
"update.manual.label": "Ruční aktualizace",
|
|
@@ -403162,6 +403198,13 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
403162
403198
|
priority: 65,
|
|
403163
403199
|
availability: "always"
|
|
403164
403200
|
},
|
|
403201
|
+
{
|
|
403202
|
+
name: "improve",
|
|
403203
|
+
aliases: ["learning"],
|
|
403204
|
+
descriptionKey: "command.improve.description",
|
|
403205
|
+
priority: 64,
|
|
403206
|
+
availability: "always"
|
|
403207
|
+
},
|
|
403165
403208
|
{
|
|
403166
403209
|
name: "status",
|
|
403167
403210
|
aliases: [],
|
|
@@ -416901,6 +416944,8 @@ function buildManagedUsageReportLines(options) {
|
|
|
416901
416944
|
var { buildApprovalRejectionStop } = createRequire(import.meta.url)("./bin/approval-rejection-stop.cjs");
|
|
416902
416945
|
var { reconcileContextBudget } = createRequire(import.meta.url)("./bin/context-budget-ledger.cjs");
|
|
416903
416946
|
var { buildContextInsight } = createRequire(import.meta.url)("./bin/context-insight-policy.cjs");
|
|
416947
|
+
var { buildValidatedLearningInsight } = createRequire(import.meta.url)("./bin/validated-learning-insight-policy.cjs");
|
|
416948
|
+
var { readValidatedLearningCandidates } = createRequire(import.meta.url)("./bin/validated-learning-signal.cjs");
|
|
416904
416949
|
function buildUsageReportLines(options) {
|
|
416905
416950
|
const accent = (text) => currentTheme.boldFg("primary", text);
|
|
416906
416951
|
const value = (text) => currentTheme.fg("text", text);
|
|
@@ -417962,6 +418007,29 @@ function buildContextInsightLines(insight) {
|
|
|
417962
418007
|
];
|
|
417963
418008
|
return lines;
|
|
417964
418009
|
}
|
|
418010
|
+
function buildValidatedLearningInsightLines(insight) {
|
|
418011
|
+
const value = (text) => currentTheme.fg("text", text);
|
|
418012
|
+
const muted = (text) => currentTheme.fg("textDim", text);
|
|
418013
|
+
const lines = [
|
|
418014
|
+
` ${value(uiText("learning.counts", insight))}`
|
|
418015
|
+
];
|
|
418016
|
+
if (insight.latestPending === null) {
|
|
418017
|
+
lines.push(` ${muted(uiText("learning.empty"))}`);
|
|
418018
|
+
return lines;
|
|
418019
|
+
}
|
|
418020
|
+
lines.push(` ${muted(`${uiText("learning.latest")}:`)} ${value(insight.latestPending.id)}`);
|
|
418021
|
+
lines.push(` ${muted(`${uiText("learning.verification")}:`)} ${value(`${insight.latestPending.toolName} · ${insight.latestPending.commandHash}`)}`);
|
|
418022
|
+
return lines;
|
|
418023
|
+
}
|
|
418024
|
+
function showValidatedLearningInsight(host) {
|
|
418025
|
+
const homeDir = process.env["BLUN_SHARED_HOME"] ?? process.env["BLUN_HOME"] ?? "";
|
|
418026
|
+
const profile = process.env["BLUN_PROFILE"] ?? "default";
|
|
418027
|
+
const candidates = readValidatedLearningCandidates({ homeDir, profile });
|
|
418028
|
+
const insight = buildValidatedLearningInsight(candidates);
|
|
418029
|
+
const panel = new UsagePanelComponent(() => buildValidatedLearningInsightLines(insight), "primary", uiText("learning.panel.title"));
|
|
418030
|
+
host.state.transcriptContainer.addChild(panel);
|
|
418031
|
+
host.state.ui.requestRender();
|
|
418032
|
+
}
|
|
417965
418033
|
async function showContextInsight(host) {
|
|
417966
418034
|
const insight = buildContextInsight(await host.requireSession().getContext());
|
|
417967
418035
|
const panel = new UsagePanelComponent(() => buildContextInsightLines(insight), "primary", uiText("usage.context.title"));
|
|
@@ -495178,6 +495246,9 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
495178
495246
|
case "premortem":
|
|
495179
495247
|
await handlePremortemCommand(host, args);
|
|
495180
495248
|
return;
|
|
495249
|
+
case "improve":
|
|
495250
|
+
showValidatedLearningInsight(host);
|
|
495251
|
+
return;
|
|
495181
495252
|
case "context":
|
|
495182
495253
|
await showContextInsight(host);
|
|
495183
495254
|
return;
|