blun-king-cli 9.1.596 → 9.1.599

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.596",
3
+ "version": "9.1.599",
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": {
package/worker-host.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // BLUN_BUILD_INPUT_SHA256:2c4b3f451c41d328bb5eb43ffb226f0f3b0c458270217cecb6e1ffc63287e8bd
2
+ // BLUN_BUILD_INPUT_SHA256:25c271186c418490335e30ef395705d13d90d816c66cac47bb57835f2482f093
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);
@@ -1311,7 +1311,7 @@ function normalizeBlunToolSchema(schema) {
1311
1311
  }
1312
1312
  function ensureBlunPropertyTypes(schema) {
1313
1313
  const normalized = cloneJsonValue(schema);
1314
- if (!isRecord$9(normalized)) throw new Error("JSON Schema root must normalize to an object.");
1314
+ if (!isRecord$10(normalized)) throw new Error("JSON Schema root must normalize to an object.");
1315
1315
  recurseSchema(normalized);
1316
1316
  return normalized;
1317
1317
  }
@@ -1372,7 +1372,7 @@ function resolveLocalJsonPointer(root, ref) {
1372
1372
  let current = root;
1373
1373
  for (const rawPart of ref.slice(2).split("/")) {
1374
1374
  const part = unescapeJsonPointerPart(rawPart);
1375
- if (isRecord$9(current)) {
1375
+ if (isRecord$10(current)) {
1376
1376
  if (!hasOwn(current, part)) return { found: false };
1377
1377
  current = current[part];
1378
1378
  } else if (Array.isArray(current)) {
@@ -1394,20 +1394,20 @@ function parseJsonPointerArrayIndex(part) {
1394
1394
  return Number(part);
1395
1395
  }
1396
1396
  function recurseSchema(node) {
1397
- if (!isRecord$9(node)) return;
1397
+ if (!isRecord$10(node)) return;
1398
1398
  visitChildSchemas(node, normalizeProperty);
1399
1399
  }
1400
1400
  function visitChildSchemas(node, visit) {
1401
1401
  for (const { key, kind } of CHILD_SCHEMA_SLOTS) {
1402
1402
  const value = node[key];
1403
1403
  if (kind === "single") {
1404
- if (isRecord$9(value)) visit(value);
1404
+ if (isRecord$10(value)) visit(value);
1405
1405
  } else if (kind === "array") {
1406
1406
  if (Array.isArray(value)) for (const item of value) visit(item);
1407
1407
  } else if (kind === "map") {
1408
- if (isRecord$9(value)) for (const item of Object.values(value)) visit(item);
1408
+ if (isRecord$10(value)) for (const item of Object.values(value)) visit(item);
1409
1409
  } else if (kind === "schema-or-array") {
1410
- if (isRecord$9(value)) visit(value);
1410
+ if (isRecord$10(value)) visit(value);
1411
1411
  else if (Array.isArray(value)) for (const item of value) visit(item);
1412
1412
  }
1413
1413
  }
@@ -1419,7 +1419,7 @@ function childSchemaKeysForParentType(parentType) {
1419
1419
  });
1420
1420
  }
1421
1421
  function normalizeProperty(node) {
1422
- if (!isRecord$9(node)) return;
1422
+ if (!isRecord$10(node)) return;
1423
1423
  if (!hasOwn(node, "type") && !hasAnyKey(node, TYPE_COMPLETION_SKIP_KEYS)) {
1424
1424
  const enumValues = node["enum"];
1425
1425
  if (Array.isArray(enumValues) && enumValues.length > 0) node["type"] = inferTypeFromValues(enumValues);
@@ -1503,14 +1503,14 @@ function hasAnyKey(obj, keys) {
1503
1503
  }
1504
1504
  function cloneJsonValue(value) {
1505
1505
  if (Array.isArray(value)) return value.map((item) => cloneJsonValue(item));
1506
- if (isRecord$9(value)) {
1506
+ if (isRecord$10(value)) {
1507
1507
  const cloned = {};
1508
1508
  for (const [key, child] of Object.entries(value)) cloned[key] = cloneJsonValue(child);
1509
1509
  return cloned;
1510
1510
  }
1511
1511
  return value;
1512
1512
  }
1513
- function isRecord$9(value) {
1513
+ function isRecord$10(value) {
1514
1514
  return typeof value === "object" && value !== null && !Array.isArray(value);
1515
1515
  }
1516
1516
  function hasOwn(obj, key) {
@@ -1664,6 +1664,7 @@ var CompactionStallError$1 = class extends ChatProviderError {
1664
1664
  }
1665
1665
  };
1666
1666
  function isRetryableGenerateError(error) {
1667
+ if (error instanceof APIContextOverflowError) return false;
1667
1668
  if (error instanceof CompactionStallError$1) return true;
1668
1669
  if (error instanceof APIConnectionError || error instanceof APITimeoutError) return true;
1669
1670
  if (error instanceof APIEmptyResponseError) return true;
@@ -1728,7 +1729,8 @@ function isProviderQuotaExhaustedMessage(message) {
1728
1729
  return PROVIDER_QUOTA_EXHAUSTED_MESSAGE_PATTERN.test(lowerMessage) && PROVIDER_QUOTA_EXHAUSTED_CONTEXT_PATTERNS.some((pattern) => pattern.test(lowerMessage));
1729
1730
  }
1730
1731
  function isContextOverflowStatusError(statusCode, message) {
1731
- if (statusCode !== 400 && statusCode !== 413 && statusCode !== 422) return false;
1732
+ const wrappedRejection = statusCode === 502 && /\bHTTP(?: Error)? (?:400|413|422):/i.test(message);
1733
+ if (statusCode !== 400 && statusCode !== 413 && statusCode !== 422 && !wrappedRejection) return false;
1732
1734
  const lowerMessage = message.toLowerCase();
1733
1735
  return CONTEXT_OVERFLOW_MESSAGE_PATTERNS.some((pattern) => pattern.test(lowerMessage));
1734
1736
  }
@@ -1854,7 +1856,8 @@ var FetchTransport = class {
1854
1856
  const startedAt = performance.now();
1855
1857
  try {
1856
1858
  const response = await this.fetch(`${this.baseUrl}${pathname}`, init);
1857
- const willRetry = attempt < maxRetries && shouldRetryResponse(response);
1859
+ const gatewayError = response.status === 502 ? await responseError(response) : void 0;
1860
+ const willRetry = attempt < maxRetries && shouldRetryResponse(response) && !(gatewayError instanceof APIContextOverflowError);
1858
1861
  notifyTransportAttempt(requestOptions?.onTransportAttempt, {
1859
1862
  transportAttempt: attempt + 1,
1860
1863
  ...requestBytes === void 0 ? {} : { requestBytes },
@@ -1866,12 +1869,12 @@ var FetchTransport = class {
1866
1869
  if (response.ok) return response;
1867
1870
  if (willRetry) {
1868
1871
  const delayMs = retryDelayMs(response.headers, attempt);
1869
- await response.body?.cancel();
1872
+ if (gatewayError === void 0) await response.body?.cancel();
1870
1873
  await waitForRetry(delayMs, init.signal);
1871
1874
  attempt += 1;
1872
1875
  continue;
1873
1876
  }
1874
- throw await responseError(response);
1877
+ throw gatewayError ?? await responseError(response);
1875
1878
  } catch (error) {
1876
1879
  if (error instanceof ChatProviderError) throw error;
1877
1880
  const willRetry = attempt < maxRetries && init.signal?.aborted !== true && isRetryableTransportFailure(error);
@@ -2698,6 +2701,19 @@ var BlunStreamedMessage = class {
2698
2701
  }
2699
2702
  }
2700
2703
  };
2704
+ function contextOverflowOutputCap(error, currentCap) {
2705
+ const maxContext = error.maxContextTokens;
2706
+ const counts = /requested ([\d,_]+) output tokens and your prompt contains (at least )?([\d,_]+) input tokens/i.exec(error.message);
2707
+ if (maxContext === void 0 || counts === null || !Number.isSafeInteger(maxContext) || maxContext <= 0) return;
2708
+ const requestedOutput = Number(counts[1].replaceAll(/[,_]/g, ""));
2709
+ const input = Number(counts[3].replaceAll(/[,_]/g, ""));
2710
+ if (!Number.isSafeInteger(input) || input < 0 || !Number.isSafeInteger(requestedOutput) || requestedOutput <= 0 || !Number.isSafeInteger(input + requestedOutput) || input + requestedOutput <= maxContext) return;
2711
+ const available = maxContext - input;
2712
+ const headroom = Math.min(1024, Math.max(1, Math.ceil(available * .01)));
2713
+ const cap = Math.min(counts[2] === void 0 ? requestedOutput - 1 : Math.floor(requestedOutput / 2), available - headroom);
2714
+ if (cap < 1 || currentCap !== void 0 && (typeof currentCap !== "number" || !Number.isSafeInteger(currentCap) || cap >= currentCap)) return;
2715
+ return cap;
2716
+ }
2701
2717
  var BlunChatProvider = class {
2702
2718
  name = "blun";
2703
2719
  _model;
@@ -2852,8 +2868,23 @@ var BlunChatProvider = class {
2852
2868
  ...options.onTransportAttempt !== void 0 ? { onTransportAttempt: options.onTransportAttempt } : {}
2853
2869
  } : void 0;
2854
2870
  options?.onRequestSent?.();
2855
- return new BlunStreamedMessage(await client.chat.completions.create(createParams, requestOptions), this._stream, reasoningRequested);
2871
+ let response;
2872
+ try {
2873
+ response = await client.chat.completions.create(createParams, requestOptions);
2874
+ } catch (error) {
2875
+ const rejection = normalizeFetchHttpError(error);
2876
+ const cap = rejection instanceof APIContextOverflowError ? contextOverflowOutputCap(rejection, createParams["max_completion_tokens"]) : void 0;
2877
+ if (cap === void 0) throw rejection;
2878
+ options?.signal?.throwIfAborted();
2879
+ options?.onRequestSent?.();
2880
+ response = await client.chat.completions.create({
2881
+ ...createParams,
2882
+ max_completion_tokens: cap
2883
+ }, requestOptions);
2884
+ }
2885
+ return new BlunStreamedMessage(response, this._stream, reasoningRequested);
2856
2886
  } catch (error) {
2887
+ if (options?.signal?.aborted === true) throw options.signal.reason ?? error;
2857
2888
  throw normalizeFetchHttpError(error);
2858
2889
  }
2859
2890
  }
@@ -10248,7 +10279,7 @@ function tokenFromWire(wire) {
10248
10279
  }
10249
10280
  //#endregion
10250
10281
  //#region ../../packages/oauth/src/utils.ts
10251
- function isRecord$8(value) {
10282
+ function isRecord$9(value) {
10252
10283
  return typeof value === "object" && value !== null && !Array.isArray(value);
10253
10284
  }
10254
10285
  //#endregion
@@ -10563,7 +10594,7 @@ var FileTokenStorage = class {
10563
10594
  } catch {
10564
10595
  return;
10565
10596
  }
10566
- if (!isRecord$8(parsed)) return void 0;
10597
+ if (!isRecord$9(parsed)) return void 0;
10567
10598
  return tokenFromWire(parsed);
10568
10599
  }
10569
10600
  async save(name, token) {
@@ -10668,7 +10699,7 @@ function extractApiErrorMessage(value) {
10668
10699
  }
10669
10700
  return;
10670
10701
  }
10671
- if (!isRecord$8(value)) return void 0;
10702
+ if (!isRecord$9(value)) return void 0;
10672
10703
  for (const key of DIRECT_ERROR_KEYS) {
10673
10704
  const message = stringField$1(value, key);
10674
10705
  if (message !== void 0) return message;
@@ -10676,7 +10707,7 @@ function extractApiErrorMessage(value) {
10676
10707
  const error = value["error"];
10677
10708
  const errorString = nonEmptyString$6(error);
10678
10709
  if (errorString !== void 0) return errorString;
10679
- if (isRecord$8(error)) for (const key of NESTED_ERROR_KEYS) {
10710
+ if (isRecord$9(error)) for (const key of NESTED_ERROR_KEYS) {
10680
10711
  const message = stringField$1(error, key);
10681
10712
  if (message !== void 0) return message;
10682
10713
  }
@@ -10770,7 +10801,7 @@ async function postForm(url, params, deviceHeaders, options) {
10770
10801
  let data = {};
10771
10802
  try {
10772
10803
  const parsed = await response.json();
10773
- if (isRecord$8(parsed)) data = parsed;
10804
+ if (isRecord$9(parsed)) data = parsed;
10774
10805
  } catch {}
10775
10806
  return {
10776
10807
  status,
@@ -12687,9 +12718,9 @@ function blunContextWindowsUrl(oauthHost) {
12687
12718
  return `${(oauthHost ?? process.env["BLUN_OAUTH_HOST"] ?? "https://account.blun.ai").replace(/\/+$/, "")}/api/verbrauch/tarife`;
12688
12719
  }
12689
12720
  function parseManagedContextWindow(payload, plan) {
12690
- if (!isRecord$8(payload)) return void 0;
12721
+ if (!isRecord$9(payload)) return void 0;
12691
12722
  const contextWindows = payload["kontext"];
12692
- if (!isRecord$8(contextWindows)) return void 0;
12723
+ if (!isRecord$9(contextWindows)) return void 0;
12693
12724
  const value = contextWindows[plan];
12694
12725
  return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
12695
12726
  }
@@ -12724,7 +12755,7 @@ function parseManagedUsagePayload(payload) {
12724
12755
  const plan = typeof rec["plan"] === "string" && rec["plan"].trim().length > 0 ? rec["plan"].trim() : void 0;
12725
12756
  const contextWindowTokens = managedContextWindowFrom(rec);
12726
12757
  const unlimited = rec["unlimited"] === true;
12727
- const stand = isRecord$8(rec["stand"]) ? rec["stand"] : void 0;
12758
+ const stand = isRecord$9(rec["stand"]) ? rec["stand"] : void 0;
12728
12759
  if (stand !== void 0) for (const [sourceKey, id, label] of ACCOUNT_USAGE_WINDOWS) {
12729
12760
  const row = toAccountUsageRow(stand[sourceKey], id, label, unlimited);
12730
12761
  if (row !== null) limits.push(row);
@@ -12734,9 +12765,9 @@ function parseManagedUsagePayload(payload) {
12734
12765
  const item = rawLimits[idx];
12735
12766
  if (!item || typeof item !== "object") continue;
12736
12767
  const detailRaw = item["detail"];
12737
- const detail = isRecord$8(detailRaw) ? detailRaw : item;
12768
+ const detail = isRecord$9(detailRaw) ? detailRaw : item;
12738
12769
  const windowRaw = item["window"];
12739
- const row = toUsageRow(detail, limitLabel(item, detail, isRecord$8(windowRaw) ? windowRaw : {}, idx));
12770
+ const row = toUsageRow(detail, limitLabel(item, detail, isRecord$9(windowRaw) ? windowRaw : {}, idx));
12740
12771
  if (row !== null) limits.push(row);
12741
12772
  }
12742
12773
  return {
@@ -12777,7 +12808,7 @@ const ACCOUNT_USAGE_WINDOWS = [
12777
12808
  ]
12778
12809
  ];
12779
12810
  function toAccountUsageRow(raw, id, label, accountUnlimited) {
12780
- if (!isRecord$8(raw)) return null;
12811
+ if (!isRecord$9(raw)) return null;
12781
12812
  const used = toInt(raw["verbraucht"]);
12782
12813
  const unlimited = accountUnlimited || raw["unlimited"] === true;
12783
12814
  const fraction = raw["anteil"];
@@ -12810,7 +12841,7 @@ function toAccountUsageRow(raw, id, label, accountUnlimited) {
12810
12841
  };
12811
12842
  }
12812
12843
  function toUsageRow(raw, defaultLabel) {
12813
- if (!isRecord$8(raw)) return null;
12844
+ if (!isRecord$9(raw)) return null;
12814
12845
  const unlimited = raw["unlimited"] === true;
12815
12846
  const limit = toInt(raw["limit"]);
12816
12847
  let used = toInt(raw["used"]);
@@ -12931,7 +12962,7 @@ function isManagedQuotaErrorMessage(message) {
12931
12962
  return /you(?:'|’)?ve reached your usage limit/.test(normalized) && /billing cycle|quota will be (?:refreshed|reset)|purchase extra usage/.test(normalized);
12932
12963
  }
12933
12964
  function hasManagedUsageShape(payload) {
12934
- if (!isRecord$8(payload)) return false;
12965
+ if (!isRecord$9(payload)) return false;
12935
12966
  let recognized = false;
12936
12967
  if ("context_window_tokens" in payload || "contextWindowTokens" in payload) {
12937
12968
  recognized = true;
@@ -12947,15 +12978,15 @@ function hasManagedUsageShape(payload) {
12947
12978
  if (!Array.isArray(limits)) return false;
12948
12979
  for (let index = 0; index < limits.length; index++) {
12949
12980
  const item = limits[index];
12950
- if (!isRecord$8(item)) return false;
12951
- const detail = isRecord$8(item["detail"]) ? item["detail"] : item;
12952
- if (toUsageRow(detail, limitLabel(item, detail, isRecord$8(item["window"]) ? item["window"] : {}, index)) === null) return false;
12981
+ if (!isRecord$9(item)) return false;
12982
+ const detail = isRecord$9(item["detail"]) ? item["detail"] : item;
12983
+ if (toUsageRow(detail, limitLabel(item, detail, isRecord$9(item["window"]) ? item["window"] : {}, index)) === null) return false;
12953
12984
  }
12954
12985
  }
12955
12986
  if ("stand" in payload) {
12956
12987
  recognized = true;
12957
12988
  const stand = payload["stand"];
12958
- if (!isRecord$8(stand)) return false;
12989
+ if (!isRecord$9(stand)) return false;
12959
12990
  const windows = ACCOUNT_USAGE_WINDOWS.filter(([sourceKey]) => sourceKey in stand);
12960
12991
  if (windows.length === 0) return false;
12961
12992
  const unlimited = payload["unlimited"] === true;
@@ -13038,8 +13069,8 @@ function userExtras(existing, remoteOwnedFields) {
13038
13069
  return out;
13039
13070
  }
13040
13071
  function mergeRefreshedModelAlias(existing, remote, remoteOwnedFields) {
13041
- const current = isRecord$8(existing) ? existing : {};
13042
- const overrides = cloneOverrides(isRecord$8(current["overrides"]) ? current["overrides"] : void 0);
13072
+ const current = isRecord$9(existing) ? existing : {};
13073
+ const overrides = cloneOverrides(isRecord$9(current["overrides"]) ? current["overrides"] : void 0);
13043
13074
  return {
13044
13075
  ...userExtras(current, remoteOwnedFields),
13045
13076
  ...remote,
@@ -13241,7 +13272,7 @@ function parseModelContextLength(item, modelId) {
13241
13272
  return values[0];
13242
13273
  }
13243
13274
  function toModelInfo(item) {
13244
- if (!isRecord$8(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
13275
+ if (!isRecord$9(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
13245
13276
  const contextLength = parseModelContextLength(item, item["id"]);
13246
13277
  const displayName = item["display_name"];
13247
13278
  const normalizedDisplayName = typeof displayName === "string" && displayName.length > 0 ? displayName : void 0;
@@ -13328,7 +13359,7 @@ async function fetchManagedBlunCodeModels(options) {
13328
13359
  throw new Error(message);
13329
13360
  }
13330
13361
  const payload = await response.json();
13331
- if (!isRecord$8(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${baseUrl}.`);
13362
+ if (!isRecord$9(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${baseUrl}.`);
13332
13363
  return payload["data"].map((item) => toModelInfo(item)).filter((item) => item !== void 0);
13333
13364
  }
13334
13365
  throw new Error(`Failed to list BLUN models for ${baseUrl}.`);
@@ -13371,11 +13402,11 @@ function applyManagedBlunCodeConfig(config, options) {
13371
13402
  apiKey
13372
13403
  };
13373
13404
  const upstreamKeys = new Set(options.models.map((m) => managedModelKey(m.id)));
13374
- for (const [key, model] of Object.entries(existingModels)) if (RETIRED_BLUN_MODEL_KEYS.has(key) || isRecord$8(model) && model["provider"] === "managed:blun" && !upstreamKeys.has(key)) delete existingModels[key];
13405
+ for (const [key, model] of Object.entries(existingModels)) if (RETIRED_BLUN_MODEL_KEYS.has(key) || isRecord$9(model) && model["provider"] === "managed:blun" && !upstreamKeys.has(key)) delete existingModels[key];
13375
13406
  for (const model of options.models) {
13376
13407
  const capabilities = capabilitiesForModel(model);
13377
13408
  const key = managedModelKey(model.id);
13378
- const existing = isRecord$8(existingModels[key]) ? existingModels[key] : {};
13409
+ const existing = isRecord$9(existingModels[key]) ? existingModels[key] : {};
13379
13410
  const supportsAdaptiveThinking = capabilities?.includes("thinking") === true || capabilities?.includes("always_thinking") === true;
13380
13411
  existingModels[key] = mergeRefreshedModelAlias(existing, {
13381
13412
  provider: BLUN_PROVIDER_NAME$1,
@@ -13423,7 +13454,7 @@ function applyManagedBlunCodeLogoutConfig(config) {
13423
13454
  let removedDefaultModel = false;
13424
13455
  const existingModels = config.models ?? {};
13425
13456
  for (const [key, model] of Object.entries(existingModels)) {
13426
- if (!isRecord$8(model) || model["provider"] !== "managed:blun") continue;
13457
+ if (!isRecord$9(model) || model["provider"] !== "managed:blun") continue;
13427
13458
  delete existingModels[key];
13428
13459
  if (config.defaultModel === key) removedDefaultModel = true;
13429
13460
  }
@@ -13463,7 +13494,7 @@ function selectDefaultModel(config, models, options) {
13463
13494
  function canPreserveDefaultModel(existingModels, defaultModel, managedModels) {
13464
13495
  if (managedModels.has(defaultModel)) return true;
13465
13496
  const existing = existingModels[defaultModel];
13466
- return isRecord$8(existing) && existing["provider"] !== "managed:blun";
13497
+ return isRecord$9(existing) && existing["provider"] !== "managed:blun";
13467
13498
  }
13468
13499
  function assertPositiveContextLength(model) {
13469
13500
  if (!Number.isInteger(model.contextLength) || model.contextLength <= 0) throw new Error(`BLUN model "${model.id}" must include a positive context_length.`);
@@ -13501,13 +13532,13 @@ function blunManagedQuotaUrl(oauthHost) {
13501
13532
  return `${(oauthHost ?? process.env["BLUN_OAUTH_HOST"] ?? "https://account.blun.ai").replace(/\/+$/, "")}${MANAGED_QUOTA_PATH}`;
13502
13533
  }
13503
13534
  function parseManagedQuotaPayload(payload) {
13504
- if (!isRecord$8(payload)) return void 0;
13535
+ if (!isRecord$9(payload)) return void 0;
13505
13536
  const plan = nonEmptyString$5(payload["plan"]);
13506
13537
  const paid = payload["bezahlt"];
13507
13538
  const creditCents = payload["guthaben_cent"];
13508
13539
  const billingKind = nonEmptyString$5(payload["art"]);
13509
13540
  const globalUnlimited = payload["unlimited"];
13510
- if (plan === void 0 || typeof paid !== "boolean" || !Number.isSafeInteger(creditCents) || creditCents < 0 || billingKind === void 0 || globalUnlimited !== void 0 && typeof globalUnlimited !== "boolean" || !isRecord$8(payload["stand"])) return;
13541
+ if (plan === void 0 || typeof paid !== "boolean" || !Number.isSafeInteger(creditCents) || creditCents < 0 || billingKind === void 0 || globalUnlimited !== void 0 && typeof globalUnlimited !== "boolean" || !isRecord$9(payload["stand"])) return;
13511
13542
  if (!hasStrictQuotaStand(payload["stand"], globalUnlimited === true)) return void 0;
13512
13543
  const limits = parseManagedUsagePayload(payload).limits;
13513
13544
  if (limits.length !== REQUIRED_WINDOWS.length || REQUIRED_WINDOWS.some(([, id]) => limits.filter((row) => row.id === id).length !== 1)) return;
@@ -13577,7 +13608,7 @@ function nonEmptyString$5(value) {
13577
13608
  function hasStrictQuotaStand(stand, globalUnlimited) {
13578
13609
  return REQUIRED_WINDOWS.every(([sourceKey]) => {
13579
13610
  const row = stand[sourceKey];
13580
- if (!isRecord$8(row)) return false;
13611
+ if (!isRecord$9(row)) return false;
13581
13612
  const used = row["verbraucht"];
13582
13613
  const rowUnlimited = row["unlimited"];
13583
13614
  if (rowUnlimited !== void 0 && typeof rowUnlimited !== "boolean") return false;
@@ -20674,7 +20705,7 @@ function parseSkillText(options) {
20674
20705
  throw error;
20675
20706
  }
20676
20707
  const frontmatter = parsed.data ?? {};
20677
- if (!isRecord$7(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
20708
+ if (!isRecord$8(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
20678
20709
  const metadata = normalizeMetadata(frontmatter);
20679
20710
  if (!isSupportedSkillType(metadata.type)) throw new UnsupportedSkillTypeError(metadata.type ?? String(frontmatter["type"]));
20680
20711
  const name = nonEmptyString$3(metadata.name);
@@ -20787,7 +20818,7 @@ function tokenizeArgs(raw) {
20787
20818
  function nonEmptyString$3(value) {
20788
20819
  return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
20789
20820
  }
20790
- function isRecord$7(value) {
20821
+ function isRecord$8(value) {
20791
20822
  return typeof value === "object" && value !== null && !Array.isArray(value);
20792
20823
  }
20793
20824
  //#endregion
@@ -20795,7 +20826,7 @@ function isRecord$7(value) {
20795
20826
  function parseCommandText(input) {
20796
20827
  const { text, commandPath, pluginId } = input;
20797
20828
  const parsed = parseFrontmatter(text);
20798
- const frontmatter = isRecord$6(parsed.data) ? parsed.data : {};
20829
+ const frontmatter = isRecord$7(parsed.data) ? parsed.data : {};
20799
20830
  const baseName = input.fallbackName ?? path.basename(commandPath).replace(/\.md$/i, "");
20800
20831
  const name = nonEmptyString$2(frontmatter["name"]) ?? baseName;
20801
20832
  const body = parsed.body.trim();
@@ -20837,7 +20868,7 @@ function descriptionFromBody(body) {
20837
20868
  if (firstLine === void 0) return "No description provided.";
20838
20869
  return firstLine.length > 240 ? `${firstLine.slice(0, 239)}…` : firstLine;
20839
20870
  }
20840
- function isRecord$6(value) {
20871
+ function isRecord$7(value) {
20841
20872
  return typeof value === "object" && value !== null && !Array.isArray(value);
20842
20873
  }
20843
20874
  //#endregion
@@ -28345,7 +28376,7 @@ const ResumeIntentSchema = object({
28345
28376
  startedAt: timestamp$2.nullable()
28346
28377
  }).strict();
28347
28378
  const hash$2 = (value) => createHash("sha256").update(value).digest("hex");
28348
- const isRecord$5 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
28379
+ const isRecord$6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
28349
28380
  /** Explicit resume intents, isolated from ordinary task status and output files. */
28350
28381
  var TaskResumeStore = class {
28351
28382
  home;
@@ -28401,9 +28432,9 @@ var TaskResumeStore = class {
28401
28432
  }
28402
28433
  async readOwnedTask(taskId) {
28403
28434
  const task = await this.read("tasks", taskId);
28404
- if (!isRecord$5(task)) throw new Error("Task has no persisted local record.");
28435
+ if (!isRecord$6(task)) throw new Error("Task has no persisted local record.");
28405
28436
  const owner = task["resumeOwnership"];
28406
- if (!isRecord$5(owner) || owner["version"] !== 1 || owner["scope"] !== hash$2(await this.root()) || owner["taskId"] !== taskId || task["taskId"] !== taskId || task["kind"] !== "agent" || owner["agentId"] !== task["agentId"] || owner["startedAt"] !== task["startedAt"]) throw new Error("Task ownership is unverified; historical or foreign records cannot be resumed automatically.");
28437
+ if (!isRecord$6(owner) || owner["version"] !== 1 || owner["scope"] !== hash$2(await this.root()) || owner["taskId"] !== taskId || task["taskId"] !== taskId || task["kind"] !== "agent" || owner["agentId"] !== task["agentId"] || owner["startedAt"] !== task["startedAt"]) throw new Error("Task ownership is unverified; historical or foreign records cannot be resumed automatically.");
28407
28438
  const { resumeOwnership: _ownership, ...info } = task;
28408
28439
  return info;
28409
28440
  }
@@ -28655,12 +28686,12 @@ function legacyStatusToCurrent(task) {
28655
28686
  return task.status;
28656
28687
  }
28657
28688
  function isReadablePersistedTask(obj) {
28658
- return isRecord$4(obj) && (typeof obj["taskId"] === "string" || typeof obj["task_id"] === "string");
28689
+ return isRecord$5(obj) && (typeof obj["taskId"] === "string" || typeof obj["task_id"] === "string");
28659
28690
  }
28660
28691
  function isLegacyPersistedTask(task) {
28661
28692
  return "task_id" in task;
28662
28693
  }
28663
- function isRecord$4(value) {
28694
+ function isRecord$5(value) {
28664
28695
  return typeof value === "object" && value !== null;
28665
28696
  }
28666
28697
  function optionalNonEmptyString(value) {
@@ -227987,7 +228018,7 @@ var HttpVisionReader = class {
227987
228018
  reason: "malformed"
227988
228019
  };
227989
228020
  }
227990
- if (!isRecord$3(payload) || payload["done"] !== true || typeof payload["response"] !== "string" || !isNonNegativeInteger(payload["prompt_eval_count"]) || !isNonNegativeInteger(payload["eval_count"])) return {
228021
+ if (!isRecord$4(payload) || payload["done"] !== true || typeof payload["response"] !== "string" || !isNonNegativeInteger(payload["prompt_eval_count"]) || !isNonNegativeInteger(payload["eval_count"])) return {
227991
228022
  ok: false,
227992
228023
  reason: "malformed"
227993
228024
  };
@@ -228411,7 +228442,7 @@ function escapeXml(value) {
228411
228442
  function locationKey(messageIndex, partIndex) {
228412
228443
  return `${String(messageIndex)}:${String(partIndex)}`;
228413
228444
  }
228414
- function isRecord$3(value) {
228445
+ function isRecord$4(value) {
228415
228446
  return value !== null && typeof value === "object" && !Array.isArray(value);
228416
228447
  }
228417
228448
  function isNonNegativeInteger(value) {
@@ -234208,7 +234239,7 @@ const OptionalStringSchema = preprocess((value) => {
234208
234239
  if (typeof value === "string") return value;
234209
234240
  if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
234210
234241
  }, string().optional());
234211
- const HookSpecificOutputSchema = preprocess((value) => isRecord$2(value) ? value : void 0, looseObject({
234242
+ const HookSpecificOutputSchema = preprocess((value) => isRecord$3(value) ? value : void 0, looseObject({
234212
234243
  message: OptionalStringSchema,
234213
234244
  additionalContext: OptionalStringSchema,
234214
234245
  permissionDecision: unknown().optional(),
@@ -234360,7 +234391,7 @@ function structuredOutput(stdout, input) {
234360
234391
  return {
234361
234392
  ...result,
234362
234393
  additionalContext: input["hook_event_name"] === "UserPromptSubmit" && hookSpecificOutput?.hookEventName === "UserPromptSubmit" ? hookSpecificOutput.additionalContext : void 0,
234363
- updatedInput: input["hook_event_name"] === "PreToolUse" && hookSpecificOutput?.hookEventName === "PreToolUse" && isRecord$2(hookSpecificOutput.updatedInput) ? hookSpecificOutput.updatedInput : void 0
234394
+ updatedInput: input["hook_event_name"] === "PreToolUse" && hookSpecificOutput?.hookEventName === "PreToolUse" && isRecord$3(hookSpecificOutput.updatedInput) ? hookSpecificOutput.updatedInput : void 0
234364
234395
  };
234365
234396
  }
234366
234397
  return {
@@ -234429,7 +234460,7 @@ function killProcessTreeWindows(child, force) {
234429
234460
  } catch {}
234430
234461
  }
234431
234462
  }
234432
- function isRecord$2(value) {
234463
+ function isRecord$3(value) {
234433
234464
  return typeof value === "object" && value !== null && !Array.isArray(value);
234434
234465
  }
234435
234466
  function errorMessage$3(error) {
@@ -234550,7 +234581,16 @@ var HookEngine = class {
234550
234581
  };
234551
234582
  }
234552
234583
  if (this.admissionClosed) return void 0;
234553
- return runHook(hook.command, inputData, {
234584
+ let hookInput;
234585
+ try {
234586
+ hookInput = this.options.runtimeInput?.(hook, inputData) ?? inputData;
234587
+ } catch {
234588
+ return {
234589
+ action: "block",
234590
+ reason: "Hook input preparation failed."
234591
+ };
234592
+ }
234593
+ return runHook(hook.command, hookInput, {
234554
234594
  timeout: hook.timeout ?? DEFAULT_HOOK_TIMEOUT_SECONDS,
234555
234595
  cwd: hook.cwd ?? (this.options.cwd === "" ? void 0 : this.options.cwd),
234556
234596
  env: hook.env,
@@ -235785,7 +235825,7 @@ function parsePersonalMemoryRecall(output) {
235785
235825
  } catch {
235786
235826
  return { kind: "invalid" };
235787
235827
  }
235788
- if (!isRecord$1(parsed) || !isRecord$1(parsed["personal_memory"])) return { kind: "invalid" };
235828
+ if (!isRecord$2(parsed) || !isRecord$2(parsed["personal_memory"])) return { kind: "invalid" };
235789
235829
  const memory = parsed["personal_memory"];
235790
235830
  const savedRaw = memory["saved"];
235791
235831
  const threadsRaw = memory["threads"];
@@ -235794,7 +235834,7 @@ function parsePersonalMemoryRecall(output) {
235794
235834
  if (savedRaw.length > MAX_SAVED_MEMORIES || threadsRaw.length > MAX_THREADS || historyRaw.length > 0) return { kind: "invalid" };
235795
235835
  const saved = [];
235796
235836
  for (const value of savedRaw) {
235797
- if (!isRecord$1(value)) return { kind: "invalid" };
235837
+ if (!isRecord$2(value)) return { kind: "invalid" };
235798
235838
  const text = boundedTrimmedString(value["text"], MAX_MEMORY_TEXT_CHARS);
235799
235839
  const confidence = value["confidence"];
235800
235840
  if (text === void 0 || typeof confidence !== "string" || !CONFIDENCE_VALUES.has(confidence)) return { kind: "invalid" };
@@ -235805,7 +235845,7 @@ function parsePersonalMemoryRecall(output) {
235805
235845
  }
235806
235846
  const threads = [];
235807
235847
  for (const value of threadsRaw) {
235808
- if (!isRecord$1(value)) return { kind: "invalid" };
235848
+ if (!isRecord$2(value)) return { kind: "invalid" };
235809
235849
  const title = boundedTrimmedString(value["title"], MAX_THREAD_TITLE_CHARS);
235810
235850
  const summary = boundedTrimmedString(value["summary"], MAX_THREAD_SUMMARY_CHARS);
235811
235851
  if (title === void 0 || summary === void 0) return { kind: "invalid" };
@@ -235859,7 +235899,7 @@ function boundedTrimmedString(value, maxChars) {
235859
235899
  const trimmed = value.trim();
235860
235900
  return trimmed.length > 0 ? trimmed : void 0;
235861
235901
  }
235862
- function isRecord$1(value) {
235902
+ function isRecord$2(value) {
235863
235903
  return typeof value === "object" && value !== null && !Array.isArray(value);
235864
235904
  }
235865
235905
  //#endregion
@@ -299908,6 +299948,36 @@ function mergeCallerMcpServers(base, callerServers) {
299908
299948
  }
299909
299949
  //#endregion
299910
299950
  //#region ../../packages/agent-core/src/plugin/agent-spine-runtime.ts
299951
+ const PROMPT_EVENTS = new Set([
299952
+ "UserPromptSubmit",
299953
+ "TurnStart",
299954
+ "SubagentStart"
299955
+ ]);
299956
+ /** AgentSpine reads prompt text; binary media stays in the original model input. */
299957
+ function projectAgentSpinePrompt(input) {
299958
+ if (typeof input["hook_event_name"] !== "string" || !PROMPT_EVENTS.has(input["hook_event_name"]) || !Array.isArray(input["prompt"])) return input;
299959
+ let changed = false;
299960
+ const prompt = input["prompt"].map((part) => {
299961
+ if (!isRecord$1(part)) return part;
299962
+ const field = part["type"] === "image_url" ? "imageUrl" : part["type"] === "audio_url" ? "audioUrl" : part["type"] === "video_url" ? "videoUrl" : void 0;
299963
+ if (field === void 0 || !isRecord$1(part[field]) || typeof part[field]["url"] !== "string") return part;
299964
+ const serialized = JSON.stringify(part);
299965
+ changed = true;
299966
+ return {
299967
+ type: "media_reference",
299968
+ media_type: part["type"],
299969
+ sha256: createHash("sha256").update(serialized).digest("hex"),
299970
+ original_bytes: Buffer.byteLength(serialized)
299971
+ };
299972
+ });
299973
+ return changed ? {
299974
+ ...input,
299975
+ prompt
299976
+ } : input;
299977
+ }
299978
+ function isRecord$1(value) {
299979
+ return typeof value === "object" && value !== null && !Array.isArray(value);
299980
+ }
299911
299981
  const EMPTY_RUNTIME = Object.freeze({
299912
299982
  AGENTSPINE_KING_TIMELINE_SOURCE: "",
299913
299983
  AGENTSPINE_KING_WIRE_PROTOCOL_VERSION: "",
@@ -300454,9 +300524,11 @@ var Session$1 = class {
300454
300524
  this.experimentalFlags = options.experimentalFlags ?? new FlagResolver();
300455
300525
  this.agentSpineRuntime = this.experimentalFlags.enabled("agent_spine_timeline") ? new AgentSpineSessionRuntime(options.agentSpineRuntime) : void 0;
300456
300526
  this.visionReader = (this.experimentalFlags.enabled("vision_reader") ? createVisionReader(options.config?.services?.visionReader) : void 0) ?? createManagedMediaVisionReader(options.toolServices?.media);
300527
+ const agentSpineHooks = new Set(options.agentSpineRuntime?.hooks);
300457
300528
  this.hookEngine = new HookEngine(options.hooks, {
300458
300529
  cwd: options.kaos.getcwd(),
300459
300530
  sessionId: options.id,
300531
+ runtimeInput: (hook, input) => agentSpineHooks.has(hook) ? projectAgentSpinePrompt(input) : input,
300460
300532
  runtimeEnv: (hook) => {
300461
300533
  const hostEnv = options.hookRuntimeEnv?.(hook);
300462
300534
  const timelineEnv = this.agentSpineRuntime?.forHook(hook);
@@ -335738,7 +335810,6 @@ var BlunCore = class {
335738
335810
  };
335739
335811
  }
335740
335812
  agentSpineRuntimeRecipients(pluginHooks, mcpConfig) {
335741
- if (!this.experimentalFlags.enabled("agent_spine_timeline")) return void 0;
335742
335813
  const plugin = this.plugins.get("agent-spine");
335743
335814
  if (plugin?.state !== "ok" || !plugin.enabled) return void 0;
335744
335815
  const hooks = pluginHooks.filter((hook) => hook.env?.["BLUN_PLUGIN_ROOT"] === plugin.root);