blun-king-cli 9.1.52 → 9.1.53
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/LIESMICH.txt +5 -1
- package/README.md +5 -1
- package/blun.mjs +83 -3
- package/package.json +1 -1
package/LIESMICH.txt
CHANGED
|
@@ -9,7 +9,7 @@ Installation
|
|
|
9
9
|
------------
|
|
10
10
|
Die geprüfte Version exakt global installieren:
|
|
11
11
|
|
|
12
|
-
npm install -g blun-king-cli@9.1.
|
|
12
|
+
npm install -g blun-king-cli@9.1.53
|
|
13
13
|
|
|
14
14
|
Start
|
|
15
15
|
-----
|
|
@@ -59,6 +59,10 @@ lokale Schritte um und fragt gezielt nach, wenn eine Entscheidung oder ein Zugan
|
|
|
59
59
|
fehlt. Blockierte, auf Freigabe wartende und abgebrochene Schritte bleiben mit
|
|
60
60
|
ihrem tatsächlichen Zustand sichtbar.
|
|
61
61
|
|
|
62
|
+
Der erste Werkzeugaufruf muss den sichtbaren Plan setzen. Ausgehende Aktionen
|
|
63
|
+
werden zusätzlich pro Werkzeugaufruf geprüft und bei fehlender Kanal- oder
|
|
64
|
+
Zugangsfreigabe angehalten.
|
|
65
|
+
|
|
62
66
|
Im automatisch angebundenen Telegram-Kanal werden ausschließlich /loop, /goal,
|
|
63
67
|
/idea und /befehle als Befehle ausgeführt. Ist der Agent beschäftigt, bleiben
|
|
64
68
|
sie in der Warteschlange. Andere Slash-Eingaben werden aus Sicherheitsgründen
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Voraussetzung ist Node.js 24.15 oder neuer. Die geprüfte Version wird exakt
|
|
|
9
9
|
installiert:
|
|
10
10
|
|
|
11
11
|
```powershell
|
|
12
|
-
npm install -g blun-king-cli@9.1.
|
|
12
|
+
npm install -g blun-king-cli@9.1.53
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Reproduzierbares Staging und Packen
|
|
@@ -74,6 +74,10 @@ lokale Schritte um und fragt gezielt nach, wenn eine Entscheidung oder ein Zugan
|
|
|
74
74
|
fehlt. Blockierte, auf Freigabe wartende und abgebrochene Schritte bleiben mit
|
|
75
75
|
ihrem tatsächlichen Zustand sichtbar.
|
|
76
76
|
|
|
77
|
+
Der erste Werkzeugaufruf muss den sichtbaren Plan setzen. Ausgehende Aktionen
|
|
78
|
+
werden zusätzlich pro Werkzeugaufruf geprüft und bei fehlender Kanal- oder
|
|
79
|
+
Zugangsfreigabe angehalten.
|
|
80
|
+
|
|
77
81
|
Im automatisch angebundenen Telegram-Kanal werden ausschließlich `/loop`,
|
|
78
82
|
`/goal`, `/idea` und `/befehle` als Befehle ausgeführt. Ist der Agent
|
|
79
83
|
beschäftigt, bleiben sie in der Warteschlange. Andere Slash-Eingaben werden aus
|
package/blun.mjs
CHANGED
|
@@ -260655,7 +260655,7 @@ var init_turn = __esmMin((() => {
|
|
|
260655
260655
|
this.agent.log.warn("goal token accounting failed", { error });
|
|
260656
260656
|
}
|
|
260657
260657
|
},
|
|
260658
|
-
|
|
260658
|
+
hooks: {
|
|
260659
260659
|
beforeStep: async ({ signal: stepSignal, llm }) => {
|
|
260660
260660
|
this.agent.microCompaction.detect();
|
|
260661
260661
|
await this.agent.injection.inject();
|
|
@@ -260705,6 +260705,8 @@ var init_turn = __esmMin((() => {
|
|
|
260705
260705
|
return { continue: false };
|
|
260706
260706
|
},
|
|
260707
260707
|
prepareToolExecution: async (ctx) => {
|
|
260708
|
+
const ideaPolicy = enforceIdeaToolPolicy(this.agent, ctx);
|
|
260709
|
+
if (ideaPolicy !== void 0) return ideaPolicy;
|
|
260708
260710
|
const cached = deduper.checkSameStep(ctx.toolCall.id, ctx.toolCall.name, ctx.args);
|
|
260709
260711
|
if (cached !== null) return { syntheticResult: cached };
|
|
260710
260712
|
},
|
|
@@ -400692,6 +400694,7 @@ registerUiCatalogFragment({
|
|
|
400692
400694
|
"command.reload-tui.description": "Reload interface settings only",
|
|
400693
400695
|
"command.compact.description": "Compact the conversation context",
|
|
400694
400696
|
"command.goal.description": "Start or manage an autonomous goal",
|
|
400697
|
+
"command.idea.description": "Start or manage an autonomous idea",
|
|
400695
400698
|
"command.loop.description": "Start or manage a recurring prompt",
|
|
400696
400699
|
"command.init.description": "Analyze the codebase and generate AGENTS.md",
|
|
400697
400700
|
"command.fork.description": "Fork the current session",
|
|
@@ -400749,6 +400752,7 @@ registerUiCatalogFragment({
|
|
|
400749
400752
|
"command.reload-tui.description": "Nur Oberflächeneinstellungen neu laden",
|
|
400750
400753
|
"command.compact.description": "Konversationskontext komprimieren",
|
|
400751
400754
|
"command.goal.description": "Autonomes Ziel starten oder verwalten",
|
|
400755
|
+
"command.idea.description": "Autonome Idee starten oder verwalten",
|
|
400752
400756
|
"command.loop.description": "Wiederkehrenden Prompt starten oder verwalten",
|
|
400753
400757
|
"command.init.description": "Codebasis analysieren und AGENTS.md erstellen",
|
|
400754
400758
|
"command.fork.description": "Aktuelle Sitzung abzweigen",
|
|
@@ -400806,6 +400810,7 @@ registerUiCatalogFragment({
|
|
|
400806
400810
|
"command.reload-tui.description": "Recargar solo los ajustes de la interfaz",
|
|
400807
400811
|
"command.compact.description": "Compactar el contexto de la conversación",
|
|
400808
400812
|
"command.goal.description": "Iniciar o gestionar un objetivo autónomo",
|
|
400813
|
+
"command.idea.description": "Iniciar o gestionar una idea autónoma",
|
|
400809
400814
|
"command.loop.description": "Iniciar o gestionar una instrucción recurrente",
|
|
400810
400815
|
"command.init.description": "Analizar el código base y generar AGENTS.md",
|
|
400811
400816
|
"command.fork.description": "Bifurcar la sesión actual",
|
|
@@ -400863,6 +400868,7 @@ registerUiCatalogFragment({
|
|
|
400863
400868
|
"command.reload-tui.description": "Recharger uniquement les paramètres de l’interface",
|
|
400864
400869
|
"command.compact.description": "Compacter le contexte de la conversation",
|
|
400865
400870
|
"command.goal.description": "Démarrer ou gérer un objectif autonome",
|
|
400871
|
+
"command.idea.description": "Démarrer ou gérer une idée autonome",
|
|
400866
400872
|
"command.loop.description": "Démarrer ou gérer une demande récurrente",
|
|
400867
400873
|
"command.init.description": "Analyser la base de code et générer AGENTS.md",
|
|
400868
400874
|
"command.fork.description": "Créer une branche de la session actuelle",
|
|
@@ -400920,6 +400926,7 @@ registerUiCatalogFragment({
|
|
|
400920
400926
|
"command.reload-tui.description": "Läs bara in gränssnittsinställningarna på nytt",
|
|
400921
400927
|
"command.compact.description": "Komprimera konversationskontexten",
|
|
400922
400928
|
"command.goal.description": "Starta eller hantera ett autonomt mål",
|
|
400929
|
+
"command.idea.description": "Starta eller hantera en självständig idé",
|
|
400923
400930
|
"command.loop.description": "Starta eller hantera en återkommande prompt",
|
|
400924
400931
|
"command.init.description": "Analysera kodbasen och skapa AGENTS.md",
|
|
400925
400932
|
"command.fork.description": "Förgrena den aktuella sessionen",
|
|
@@ -400977,6 +400984,7 @@ registerUiCatalogFragment({
|
|
|
400977
400984
|
"command.reload-tui.description": "Znovu načíst pouze nastavení rozhraní",
|
|
400978
400985
|
"command.compact.description": "Komprimovat kontext konverzace",
|
|
400979
400986
|
"command.goal.description": "Spustit nebo spravovat autonomní cíl",
|
|
400987
|
+
"command.idea.description": "Spustit nebo spravovat autonomní nápad",
|
|
400980
400988
|
"command.loop.description": "Spustit nebo spravovat opakované zadání",
|
|
400981
400989
|
"command.init.description": "Analyzovat kódovou základnu a vygenerovat AGENTS.md",
|
|
400982
400990
|
"command.fork.description": "Vytvořit větev aktuální relace",
|
|
@@ -401389,7 +401397,7 @@ const BUILTIN_SLASH_COMMAND_DEFINITIONS = [
|
|
|
401389
401397
|
{
|
|
401390
401398
|
name: "idea",
|
|
401391
401399
|
aliases: [],
|
|
401392
|
-
descriptionKey: "command.
|
|
401400
|
+
descriptionKey: "command.idea.description",
|
|
401393
401401
|
priority: 80,
|
|
401394
401402
|
argumentHint: "<objective>",
|
|
401395
401403
|
availability: (args) => {
|
|
@@ -420130,6 +420138,7 @@ async function handleGoalCommand(host, args) {
|
|
|
420130
420138
|
return;
|
|
420131
420139
|
}
|
|
420132
420140
|
}
|
|
420141
|
+
const IDEA_CONTRACT_MARKER = "Work as a self-directing employee:";
|
|
420133
420142
|
const IDEA_ALLOWED_CHANNELS = Object.freeze([]);
|
|
420134
420143
|
const IDEA_TERMINAL_TODO_STATUSES = Object.freeze([
|
|
420135
420144
|
"done",
|
|
@@ -420137,6 +420146,77 @@ const IDEA_TERMINAL_TODO_STATUSES = Object.freeze([
|
|
|
420137
420146
|
"waiting_approval",
|
|
420138
420147
|
"aborted"
|
|
420139
420148
|
]);
|
|
420149
|
+
const IDEA_OUTBOUND_TOOL_LEAF = /(?:^|_)(?:send|reply|post|publish|upload|purchase|buy|register|signup|merge|push|deploy|create_(?:account|user|issue|pull|pr|comment|post|order|campaign|repo(?:sitory)?)|update_(?:issue|pull|pr|comment|post)|delete_(?:issue|pull|pr|comment|post|account|user)|release)(?:_|$)/iu;
|
|
420150
|
+
const IDEA_OUTBOUND_SHELL = /(?:\bgit\s+push\b|\bnpm\s+publish\b|\bgh\s+(?:pr|issue|release)\s+(?:create|edit|comment|merge|delete)\b|\b(?:ssh|scp|rsync)\b|\bSend-MailMessage\b|\b(?:curl|wget)\b[^\r\n]*(?:-X|--request)\s*(?:POST|PUT|PATCH|DELETE)\b|\bInvoke-(?:WebRequest|RestMethod)\b[^\r\n]*-Method\s+(?:POST|PUT|PATCH|DELETE)\b)/iu;
|
|
420151
|
+
function isIdeaGoal(agent) {
|
|
420152
|
+
const goal = agent.goal.getActiveGoal();
|
|
420153
|
+
return goal !== null && goal.completionCriterion?.includes(IDEA_CONTRACT_MARKER) === true;
|
|
420154
|
+
}
|
|
420155
|
+
function ideaTodos(agent) {
|
|
420156
|
+
const value = agent.tools.store?.["todo"];
|
|
420157
|
+
return Array.isArray(value) ? value : [];
|
|
420158
|
+
}
|
|
420159
|
+
function validInitialIdeaPlan(value) {
|
|
420160
|
+
if (!Array.isArray(value) || value.length === 0) return false;
|
|
420161
|
+
let active = 0;
|
|
420162
|
+
for (const todo of value) {
|
|
420163
|
+
if (typeof todo !== "object" || todo === null || typeof todo.title !== "string" || todo.title.trim().length === 0) return false;
|
|
420164
|
+
if (todo.status === "in_progress") active += 1;
|
|
420165
|
+
else if (todo.status !== "pending") return false;
|
|
420166
|
+
}
|
|
420167
|
+
return active === 1;
|
|
420168
|
+
}
|
|
420169
|
+
function ideaOutboundChannel(toolName, args) {
|
|
420170
|
+
if (toolName === "Bash") {
|
|
420171
|
+
const command = typeof args?.command === "string" ? args.command : "";
|
|
420172
|
+
return IDEA_OUTBOUND_SHELL.test(command) ? "shell-external" : void 0;
|
|
420173
|
+
}
|
|
420174
|
+
if (!toolName.startsWith("mcp__")) return void 0;
|
|
420175
|
+
const lower = toolName.toLowerCase();
|
|
420176
|
+
if (lower.includes("blun_language_guard")) return void 0;
|
|
420177
|
+
const leaf = lower.split("__").at(-1) ?? lower;
|
|
420178
|
+
if (!IDEA_OUTBOUND_TOOL_LEAF.test(leaf)) return void 0;
|
|
420179
|
+
for (const channel of ["telegram", "github", "reddit", "linkedin", "instagram", "facebook", "youtube", "gmail", "email", "smtp", "canva"]) if (lower.includes(channel)) return channel;
|
|
420180
|
+
return lower.split("__")[1] ?? "external";
|
|
420181
|
+
}
|
|
420182
|
+
function enforceIdeaToolPolicy(agent, context) {
|
|
420183
|
+
if (!isIdeaGoal(agent)) return;
|
|
420184
|
+
const todos = ideaTodos(agent);
|
|
420185
|
+
const batchKey = `${String(context.turnId)}:${String(context.stepNumber)}`;
|
|
420186
|
+
if (todos.length === 0) {
|
|
420187
|
+
const firstCall = context.toolCalls[0];
|
|
420188
|
+
if (context.toolCall.id !== firstCall?.id || context.toolCall.name !== "TodoList") return {
|
|
420189
|
+
block: true,
|
|
420190
|
+
reason: "Idea mode requires TodoList to be the first tool call. Publish the visible plan before research or action."
|
|
420191
|
+
};
|
|
420192
|
+
if (!validInitialIdeaPlan(context.args?.todos)) return {
|
|
420193
|
+
block: true,
|
|
420194
|
+
reason: "The first Idea TodoList must contain at least one item, exactly one in_progress item, and only pending items otherwise."
|
|
420195
|
+
};
|
|
420196
|
+
agent.ideaPlanBatchKey = batchKey;
|
|
420197
|
+
return;
|
|
420198
|
+
}
|
|
420199
|
+
if (agent.ideaPlanBatchKey === batchKey && context.toolCall.name !== "TodoList") return {
|
|
420200
|
+
block: true,
|
|
420201
|
+
reason: "Idea mode publishes its plan in a separate first step. Continue research or action in the next step."
|
|
420202
|
+
};
|
|
420203
|
+
if (context.toolCall.name === "UpdateGoal" && (context.args?.status === "complete" || context.args?.status === "blocked")) {
|
|
420204
|
+
if (todos.some((todo) => !IDEA_TERMINAL_TODO_STATUSES.includes(todo.status))) return {
|
|
420205
|
+
block: true,
|
|
420206
|
+
reason: "Idea mode cannot finish while a plan item has no truthful terminal status."
|
|
420207
|
+
};
|
|
420208
|
+
if (context.args.status === "complete" && todos.some((todo) => todo.status !== "done")) return {
|
|
420209
|
+
block: true,
|
|
420210
|
+
reason: "Idea mode can complete only when every plan item is done. Use blocked when any item is blocked, waiting_approval, or aborted."
|
|
420211
|
+
};
|
|
420212
|
+
}
|
|
420213
|
+
const channel = ideaOutboundChannel(context.toolCall.name, context.args);
|
|
420214
|
+
if (channel === void 0 || IDEA_ALLOWED_CHANNELS.includes(channel)) return;
|
|
420215
|
+
return {
|
|
420216
|
+
block: true,
|
|
420217
|
+
reason: `Idea mode blocked an external action on channel "${channel}". Prepare the result, mark the step waiting_approval with the required access or approval, and ask the user.`
|
|
420218
|
+
};
|
|
420219
|
+
}
|
|
420140
420220
|
function buildIdeaPrompt(objective) {
|
|
420141
420221
|
const allowedChannels = IDEA_ALLOWED_CHANNELS.length === 0 ? "none" : IDEA_ALLOWED_CHANNELS.join(", ");
|
|
420142
420222
|
return `<idea-mode>
|
|
@@ -420149,7 +420229,7 @@ ${buildIdeaContract(allowedChannels)}
|
|
|
420149
420229
|
</idea-mode>`;
|
|
420150
420230
|
}
|
|
420151
420231
|
function buildIdeaContract(allowedChannels = IDEA_ALLOWED_CHANNELS.length === 0 ? "none" : IDEA_ALLOWED_CHANNELS.join(", ")) {
|
|
420152
|
-
return
|
|
420232
|
+
return `${IDEA_CONTRACT_MARKER} discover a useful route, research current examples and real user problems when relevant, decide, implement reversible local work, verify results, and keep going without waiting for step-by-step instructions.
|
|
420153
420233
|
|
|
420154
420234
|
Maintain the task-specific plan in TodoList. Keep exactly one item in_progress. Every plan item must end in exactly one truthful terminal status from: ${IDEA_TERMINAL_TODO_STATUSES.join(", ")}. A blocked title must include the reason and what would unblock it. A waiting_approval title must include the prepared result and the exact approval needed. An aborted title must include the last reached state.
|
|
420155
420235
|
|