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 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.52
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.52
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
- hooks: {
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.goal.description",
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 `Work as a self-directing employee: 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.
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.52",
3
+ "version": "9.1.53",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {