blun-king-cli 9.1.37 → 9.1.38

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.
Files changed (2) hide show
  1. package/blun.mjs +119 -2
  2. package/package.json +1 -1
package/blun.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:0a9b399298f68e4bffadcc1ead801f14012d39becc3a208a737071e6bb201f97
2
+ // BLUN_BUILD_INPUT_SHA256:e0036ad7d958609c5cf630953c5e1b6b6ec22fda3e8c09f26e7c97767acf846b
3
3
  import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
4
4
  import { dirname as __cjsShimDirname } from 'node:path';
5
5
  const __filename = __cjsShimFileURLToPath(import.meta.url);
@@ -3021,6 +3021,8 @@ async function generate(provider, systemPrompt, tools, history, callbacks, optio
3021
3021
  serverDecodeMs,
3022
3022
  clientConsumeMs
3023
3023
  });
3024
+ const hasToolCall = message.toolCalls.length > 0 || pendingPart !== null && pendingPart.type === "function";
3025
+ if (stream.finishReason === null && hasToolCall) throw new APIConnectionError("The provider stream ended before its terminal finish reason. The incomplete response was discarded and no tool call was executed.");
3024
3026
  if (pendingPart !== null) flushPart(message, pendingPart, toolCallIndexMap);
3025
3027
  if (message.content.length === 0 && message.toolCalls.length === 0) throw new APIEmptyResponseError("The API returned an empty response (no content, no tool calls)." + formatFinishReasonHint(stream) + ` Provider: ${provider.name}, model: ${provider.modelName}`, {
3026
3028
  finishReason: stream.finishReason,
@@ -258792,7 +258794,116 @@ var init_read_media = __esmMin((() => {
258792
258794
  //#region ../../packages/agent-core/src/tools/builtin/file/write.md?raw
258793
258795
  var write_default;
258794
258796
  var init_write$1 = __esmMin((() => {
258795
- write_default = "Create, append to, or replace a file entirely.\n\n- Missing parent directories are created automatically (like `mkdir(parents=True, exist_ok=True)`).\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Do not create unsolicited documentation files (`*.md` write-ups, `README`s, summaries) just because a task finished — write one only when the user asks for it, or when a task or project instruction requires it (e.g. the plan-mode plan file, created with Write when plan mode directs you to, or a changeset the repo mandates).\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- Source files may contain at most 500 lines. Split larger implementations into focused files; append cannot bypass the limit.\n- Set `single_file_override=true` only when the latest direct user message explicitly requires one single file. The accepted override is reported visibly.\n- For non-source content too large for one call, overwrite the first chunk, then append subsequent chunks. Never chunk Write to modify an existing file.\n";
258797
+ write_default = "Create, append to, or replace a file entirely.\n\n- Missing parent directories are created automatically (like `mkdir(parents=True, exist_ok=True)`).\n- Mode defaults to overwrite; append adds content at EOF without adding a newline.\n- Write is NOT ALLOWED for incremental changes to existing files, including trivial, one-line, quick, or cosmetic edits. Use Edit instead.\n- Use Write only when the file does not exist, you intend a complete replacement, or the new contents have little continuity with the old contents.\n- Do not create unsolicited documentation files (`*.md` write-ups, `README`s, summaries) just because a task finished — write one only when the user asks for it, or when a task or project instruction requires it (e.g. the plan-mode plan file, created with Write when plan mode directs you to, or a changeset the repo mandates).\n- Read before overwriting an existing file.\n- Write ignores the Read/Edit line-number view. NEVER include line prefixes.\n- Write outputs content literally, including supplied line endings: \\n stays LF, \\r\\n stays CRLF.\n- Source files may contain at most 500 lines. Split larger implementations into focused files; append cannot bypass the limit.\n- Set `single_file_override=true` only when the latest direct user message explicitly requires one single file. The accepted override is reported visibly.\n- For non-source content too large for one call, overwrite the first chunk, then append subsequent chunks. Never chunk Write to modify an existing file.\n- Runaway generated JavaScript/TypeScript identifiers are rejected before disk I/O. Regenerate only the affected section as a smaller focused chunk.\n";
258798
+ }));
258799
+ //#endregion
258800
+ //#region ../../packages/agent-core/src/tools/builtin/file/generated-source-health.ts
258801
+ /**
258802
+ * Find runaway generated identifiers while ignoring comments and strings.
258803
+ * A 512-character identifier is already far beyond normal generated source,
258804
+ * while quoted assets and long comments remain valid input.
258805
+ */
258806
+ function findDegenerateGeneratedIdentifier(path, content) {
258807
+ if (!JAVASCRIPT_LIKE_EXTENSIONS.has(extname$1(path).toLowerCase())) return null;
258808
+ let index = 0;
258809
+ let line = 1;
258810
+ while (index < content.length) {
258811
+ const current = content[index] ?? "";
258812
+ const next = content[index + 1] ?? "";
258813
+ if (current === "\n") {
258814
+ line += 1;
258815
+ index += 1;
258816
+ continue;
258817
+ }
258818
+ if (current === "/" && next === "/") {
258819
+ index = skipLineComment(content, index + 2);
258820
+ continue;
258821
+ }
258822
+ if (current === "/" && next === "*") {
258823
+ const skipped = skipBlockComment(content, index + 2, line);
258824
+ index = skipped.index;
258825
+ line = skipped.line;
258826
+ continue;
258827
+ }
258828
+ if (current === "'" || current === "\"" || current === "`") {
258829
+ const skipped = skipQuoted(content, index + 1, line, current);
258830
+ index = skipped.index;
258831
+ line = skipped.line;
258832
+ continue;
258833
+ }
258834
+ if (isIdentifierStart(current)) {
258835
+ const start = index;
258836
+ index += 1;
258837
+ while (index < content.length && isIdentifierPart(content[index] ?? "")) index += 1;
258838
+ const length = index - start;
258839
+ if (length > 512) return {
258840
+ length,
258841
+ line,
258842
+ preview: content.slice(start, start + 80)
258843
+ };
258844
+ continue;
258845
+ }
258846
+ index += 1;
258847
+ }
258848
+ return null;
258849
+ }
258850
+ function skipLineComment(content, index) {
258851
+ const newline = content.indexOf("\n", index);
258852
+ return newline < 0 ? content.length : newline;
258853
+ }
258854
+ function skipBlockComment(content, start, initialLine) {
258855
+ let index = start;
258856
+ let line = initialLine;
258857
+ while (index < content.length) {
258858
+ if (content[index] === "\n") line += 1;
258859
+ if (content[index] === "*" && content[index + 1] === "/") return {
258860
+ index: index + 2,
258861
+ line
258862
+ };
258863
+ index += 1;
258864
+ }
258865
+ return {
258866
+ index: content.length,
258867
+ line
258868
+ };
258869
+ }
258870
+ function skipQuoted(content, start, initialLine, quote) {
258871
+ let index = start;
258872
+ let line = initialLine;
258873
+ while (index < content.length) {
258874
+ const current = content[index] ?? "";
258875
+ if (current === "\\") {
258876
+ index += 2;
258877
+ continue;
258878
+ }
258879
+ if (current === "\n") line += 1;
258880
+ index += 1;
258881
+ if (current === quote) break;
258882
+ }
258883
+ return {
258884
+ index,
258885
+ line
258886
+ };
258887
+ }
258888
+ function isIdentifierStart(value) {
258889
+ return /[A-Za-z_$]/.test(value);
258890
+ }
258891
+ function isIdentifierPart(value) {
258892
+ return /[A-Za-z0-9_$]/.test(value);
258893
+ }
258894
+ var JAVASCRIPT_LIKE_EXTENSIONS;
258895
+ var init_generated_source_health = __esmMin((() => {
258896
+ init_dist$6();
258897
+ JAVASCRIPT_LIKE_EXTENSIONS = new Set([
258898
+ ".cjs",
258899
+ ".cts",
258900
+ ".js",
258901
+ ".jsx",
258902
+ ".mjs",
258903
+ ".mts",
258904
+ ".ts",
258905
+ ".tsx"
258906
+ ]);
258796
258907
  })), S_IFMT, S_IFDIR, WriteInputSchema, WriteTool;
258797
258908
  var init_write = __esmMin((() => {
258798
258909
  init_dist$6();
@@ -258803,6 +258914,7 @@ var init_write = __esmMin((() => {
258803
258914
  init_rule_match();
258804
258915
  init_source_file_line_limit();
258805
258916
  init_write$1();
258917
+ init_generated_source_health();
258806
258918
  init_lsp_diagnostics();
258807
258919
  S_IFMT = 61440;
258808
258920
  S_IFDIR = 16384;
@@ -258855,6 +258967,11 @@ bytesWritten: number$1().int().nonnegative() });
258855
258967
  }
258856
258968
  async execution(args, safePath) {
258857
258969
  const mode = args.mode ?? "overwrite";
258970
+ const degenerateIdentifier = findDegenerateGeneratedIdentifier(safePath, args.content);
258971
+ if (degenerateIdentifier !== null) return {
258972
+ isError: true,
258973
+ output: `Refused to write ${args.path}: generated source contains a runaway ${String(degenerateIdentifier.length)}-character identifier on line ${String(degenerateIdentifier.line)} (starts with ${JSON.stringify(degenerateIdentifier.preview)}). Regenerate that section in a smaller focused chunk. No file was written.`
258974
+ };
258858
258975
  let currentContent;
258859
258976
  if (isSourceFilePath(safePath)) try {
258860
258977
  currentContent = await this.kaos.readText(safePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.37",
3
+ "version": "9.1.38",
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": {