gnhf 0.1.38 → 0.1.40

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/dist/cli.mjs +56 -8
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -14476,6 +14476,29 @@ var CodexAgent = class {
14476
14476
  };
14477
14477
  //#endregion
14478
14478
  //#region src/core/agents/opencode.ts
14479
+ const RETRYABLE_PROVIDER_ERROR_CODES = new Set(["server_is_overloaded"]);
14480
+ const RETRYABLE_PROVIDER_ERROR_TYPES = new Set(["service_unavailable_error", "overloaded_error"]);
14481
+ function extractStreamError(event, sessionId) {
14482
+ if (event.type === "error" && event.error) return event.error;
14483
+ const payload = event.payload;
14484
+ if (!payload) return null;
14485
+ if (payload.type === "error" || payload.type === "session.error") {
14486
+ if (payload.properties?.sessionID !== sessionId) return null;
14487
+ return payload.error ?? payload.properties?.error ?? null;
14488
+ }
14489
+ return null;
14490
+ }
14491
+ function isRetryableProviderError(error) {
14492
+ if (error.code && RETRYABLE_PROVIDER_ERROR_CODES.has(error.code)) return true;
14493
+ if (error.type && RETRYABLE_PROVIDER_ERROR_TYPES.has(error.type)) return true;
14494
+ return false;
14495
+ }
14496
+ function buildProviderErrorMessage(error) {
14497
+ const detail = error.message ?? error.type ?? error.code ?? "unknown error";
14498
+ if (error.code === "server_is_overloaded") return `OpenCode provider overloaded: ${detail}`;
14499
+ if (isRetryableProviderError(error)) return `OpenCode provider error: ${detail}`;
14500
+ return `OpenCode provider error: ${detail}`;
14501
+ }
14479
14502
  const BLANKET_PERMISSION_RULESET = [{
14480
14503
  permission: "*",
14481
14504
  pattern: "*",
@@ -14855,10 +14878,10 @@ var OpenCodeAgent = class {
14855
14878
  };
14856
14879
  const usageByMessageId = /* @__PURE__ */ new Map();
14857
14880
  const textParts = /* @__PURE__ */ new Map();
14858
- let lastText = null;
14859
14881
  let lastFinalAnswerText = null;
14860
14882
  let lastUsageSignature = "0:0:0:0";
14861
14883
  let structuredOutputFromSSE = null;
14884
+ let streamErrorInfo = null;
14862
14885
  const eventCounts = {};
14863
14886
  let firstEventAtMs = null;
14864
14887
  let lastEventAtMs = null;
@@ -15000,11 +15023,22 @@ var OpenCodeAgent = class {
15000
15023
  });
15001
15024
  notePhase(phase);
15002
15025
  if (!trimmed) return;
15003
- lastText = nextText;
15004
15026
  if (phase === "final_answer") lastFinalAnswerText = nextText;
15005
15027
  onMessage?.(trimmed);
15006
15028
  };
15007
15029
  const handleEvent = (event) => {
15030
+ const errorInfo = extractStreamError(event, sessionId);
15031
+ if (errorInfo) {
15032
+ streamErrorInfo = errorInfo;
15033
+ appendDebugLog("opencode:stream:provider-error", {
15034
+ sessionId,
15035
+ type: errorInfo.type ?? null,
15036
+ code: errorInfo.code ?? null,
15037
+ message: errorInfo.message ?? null,
15038
+ retryable: isRetryableProviderError(errorInfo)
15039
+ });
15040
+ return true;
15041
+ }
15008
15042
  const payload = event.payload;
15009
15043
  const properties = payload?.properties;
15010
15044
  if (!properties || properties.sessionID !== sessionId) return false;
@@ -15156,20 +15190,20 @@ var OpenCodeAgent = class {
15156
15190
  usage
15157
15191
  };
15158
15192
  }
15159
- const outputText = toNonEmptyString(lastFinalAnswerText) ?? toNonEmptyString(lastText);
15160
- if (outputText === null) {
15193
+ if (streamErrorInfo) throw new Error(buildProviderErrorMessage(streamErrorInfo));
15194
+ const finalOutputText = toNonEmptyString(lastFinalAnswerText);
15195
+ if (finalOutputText === null) {
15161
15196
  appendDebugLog("opencode:output:missing", {
15162
15197
  sessionId,
15163
15198
  hasStructuredOutput: structuredOutputFromSSE !== null
15164
15199
  });
15165
- throw new Error("opencode returned no text output");
15200
+ throw new Error("OpenCode produced no final answer");
15166
15201
  }
15167
- const finalOutputText = outputText;
15168
15202
  try {
15169
15203
  const output = JSON.parse(finalOutputText);
15170
15204
  appendDebugLog("opencode:output:structured", {
15171
15205
  sessionId,
15172
- source: lastFinalAnswerText ? "final_answer" : "last_text",
15206
+ source: "final_answer",
15173
15207
  outputTextLength: finalOutputText.length
15174
15208
  });
15175
15209
  return {
@@ -17702,6 +17736,18 @@ function meteorCountForFrequency(frequency) {
17702
17736
  function meteorsStartingBefore(meteors, rowOffset, maxStartRow) {
17703
17737
  return meteors.filter((meteor) => rowOffset + meteor.y < maxStartRow);
17704
17738
  }
17739
+ function generateSideMeteorShower(terminalWidth, sideWidth, height, count, seed) {
17740
+ if (sideWidth <= 0 || height <= 0 || count <= 0) return [];
17741
+ const leftCount = Math.max(1, Math.ceil(count / 2));
17742
+ const rightCount = count - leftCount;
17743
+ const leftMeteors = generateMeteorShower(sideWidth, height, leftCount, seed);
17744
+ const rightXOffset = terminalWidth - sideWidth;
17745
+ const rightMeteors = generateMeteorShower(sideWidth, height, rightCount, seed + 1).map((meteor) => ({
17746
+ ...meteor,
17747
+ x: meteor.x + rightXOffset
17748
+ }));
17749
+ return [...leftMeteors, ...rightMeteors];
17750
+ }
17705
17751
  function placeStarsInCells(cells, stars, row, xMin, xMax, xOffset, now) {
17706
17752
  for (const star of stars) {
17707
17753
  if (star.y !== row || star.x < xMin || star.x >= xMax) continue;
@@ -17900,6 +17946,7 @@ var Renderer = class {
17900
17946
  sideStars = [];
17901
17947
  topMeteors = [];
17902
17948
  bottomMeteors = [];
17949
+ sideMeteors = [];
17903
17950
  cachedWidth = 0;
17904
17951
  cachedHeight = 0;
17905
17952
  meteorFrequency;
@@ -17995,6 +18042,7 @@ var Renderer = class {
17995
18042
  this.topStars = generateStarField(w, h, STAR_DENSITY, this.seedTop).map((s) => shrinkBig(s, s.y >= topHeight - proximityRows));
17996
18043
  this.bottomStars = generateStarField(w, h, STAR_DENSITY, this.seedBottom).map((s) => shrinkBig(s, s.y < proximityRows));
17997
18044
  this.sideStars = generateStarField(w, Math.max(BASE_CONTENT_ROWS, availableHeight), STAR_DENSITY, this.seedSide);
18045
+ this.sideMeteors = generateSideMeteorShower(w, Math.max(0, Math.floor((w - CONTENT_WIDTH) / 2)), Math.min(BASE_CONTENT_ROWS, availableHeight), meteorCountForFrequency(this.meteorFrequency), this.seedSide + METEOR_SEED_OFFSET);
17998
18046
  this.topMeteors = generateMeteorShower(w, topHeight, topHeight > 0 ? meteorCountForFrequency(this.meteorFrequency) : 0, this.seedTop + METEOR_SEED_OFFSET);
17999
18047
  this.bottomMeteors = generateMeteorShower(w, bottomHeight, bottomHeight > 0 ? meteorCountForFrequency(this.meteorFrequency) : 0, this.seedBottom + METEOR_SEED_OFFSET);
18000
18048
  return true;
@@ -18007,7 +18055,7 @@ var Renderer = class {
18007
18055
  const h = process$1.stdout.rows || 24;
18008
18056
  const resized = this.ensureStarFields(w, h);
18009
18057
  this.updateTerminalTitle(now);
18010
- const nextCells = buildFrameCells(this.prompt, this.agentName, this.state, this.topStars, this.bottomStars, this.sideStars, now, w, h, this.topMeteors, this.bottomMeteors);
18058
+ const nextCells = buildFrameCells(this.prompt, this.agentName, this.state, this.topStars, this.bottomStars, this.sideStars, now, w, h, this.topMeteors, this.bottomMeteors, this.sideMeteors);
18011
18059
  if (this.isFirstFrame || resized) {
18012
18060
  process$1.stdout.write("\x1B[H" + nextCells.map(rowToString).join("\n"));
18013
18061
  this.isFirstFrame = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gnhf",
3
- "version": "0.1.38",
3
+ "version": "0.1.40",
4
4
  "description": "Before I go to bed, I tell my agents: good night, have fun",
5
5
  "type": "module",
6
6
  "bin": {