@tritard/waterbrother 0.14.4 → 0.14.6

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/package.json +1 -1
  2. package/src/cli.js +33 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tritard/waterbrother",
3
- "version": "0.14.4",
3
+ "version": "0.14.6",
4
4
  "description": "Waterbrother: Grok-powered coding CLI with local tools, sessions, operator modes, and approval controls",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -33,7 +33,7 @@ import { runBuildWorkflow, startFeatureTask, runChallengeWorkflow } from "./work
33
33
  import { createPanelRenderer, buildPanelState } from "./panel.js";
34
34
  import { deriveTaskNameFromPrompt, nextActionsForState, routeNaturalInput } from "./router.js";
35
35
  import { compressEpisode, compressSessionEpisode, saveEpisode, loadRecentEpisodes, findRelevantEpisodes, buildEpisodicMemoryBlock, buildReminderBlock } from "./episodic.js";
36
- import { formatScorecardSummary } from "./scorecard.js";
36
+ import { formatScorecardSummary, computeScorecard as computeSc, saveScorecard as saveSc } from "./scorecard.js";
37
37
  import { createProduct, loadProduct, saveProduct, hasProduct, generateBlueprint, buildProductContext, detectProductRequest, parseProductIntent, addSurface, createCampaign, getActiveCampaign, matchTemplate, applyTemplate, startPreview, killPreview } from "./product.js";
38
38
  import { runQualityChecks, formatQualityFindings, buildQualityFixPrompt } from "./quality.js";
39
39
  import { scanForInitiatives, formatInitiatives, buildInitiativeFixPrompt } from "./initiative.js";
@@ -4774,9 +4774,20 @@ async function readInteractiveLine(options = {}) {
4774
4774
  });
4775
4775
  }
4776
4776
 
4777
- // Ensure stdin is in a clean state before attaching listeners.
4778
- // The interrupt listener may have paused stdin and toggled raw mode
4779
- // between turns, leaving readline's internal keypress emitter stale.
4777
+ // Nuclear stdin reset force a completely clean state every time.
4778
+ // The readline keypress emitter guards with a Symbol and only attaches once.
4779
+ // After interrupt listeners, promptLine, and approval prompts mess with stdin,
4780
+ // the internal handler gets stale. Force it to re-attach by clearing the guard.
4781
+ const kEmit = Symbol.for("readline.emitKeypressEvents");
4782
+ if (input[kEmit]) {
4783
+ // Remove the old internal data listener that readline attached
4784
+ const oldListeners = input.rawListeners("data").slice();
4785
+ for (const fn of oldListeners) {
4786
+ // readline's internal listener is not our onData — remove all, re-add ours after
4787
+ input.removeListener("data", fn);
4788
+ }
4789
+ delete input[kEmit];
4790
+ }
4780
4791
  if (input.isTTY) {
4781
4792
  try { input.setRawMode(false); } catch {}
4782
4793
  }
@@ -5225,6 +5236,9 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
5225
5236
  } catch (error) {
5226
5237
  spinner.stop();
5227
5238
  console.log(`build failed: ${error instanceof Error ? error.message : String(error)}`);
5239
+ } finally {
5240
+ // Always restore autonomy mode, even on failure
5241
+ agent.toolRuntime.setAutonomyMode(prevAutonomy);
5228
5242
  }
5229
5243
  return true;
5230
5244
  }
@@ -5285,6 +5299,8 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
5285
5299
  } catch (error) {
5286
5300
  spinner.stop();
5287
5301
  console.log(`deploy failed: ${error instanceof Error ? error.message : String(error)}`);
5302
+ } finally {
5303
+ agent.toolRuntime.setAutonomyMode(prevAutonomy);
5288
5304
  }
5289
5305
  return true;
5290
5306
  }
@@ -6845,13 +6861,12 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
6845
6861
  },
6846
6862
  onScorecard({ attempt, metric: metricInfo, baseline: bl, currentBest: cb }) {
6847
6863
  try {
6848
- const { computeScorecard: compSc, saveScorecard: saveSc } = require("./scorecard.js");
6849
- const sc = compSc({
6864
+ const sc = computeSc({
6850
6865
  task: { id: `exp-${attempt.number}`, name: `experiment attempt ${attempt.number}`, chosenOption: attempt.hypothesis },
6851
6866
  receipt: { changedFiles: [], verification: [{ ok: attempt.status === "keep", command: metricInfo.command }], review: { verdict: attempt.status === "keep" ? "ship" : "block", concerns: [] }, mutated: attempt.status !== "crash" },
6852
6867
  userAction: attempt.status === "keep" ? "accepted" : "redo"
6853
6868
  });
6854
- saveSc({ cwd: context.cwd, scorecard: sc });
6869
+ saveSc({ cwd: context.cwd, scorecard: sc }).catch(() => {});
6855
6870
  } catch {}
6856
6871
  },
6857
6872
  onDone() {
@@ -7078,7 +7093,13 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
7078
7093
  if (line === "/memory reload") {
7079
7094
  const memoryState = await readProjectMemory(context.cwd);
7080
7095
  context.runtime.projectMemory = memoryState;
7081
- agent.setMemory(memoryState.promptText);
7096
+ // Preserve all memory layers — don't drop episodic or product context
7097
+ const fullMemory = [
7098
+ memoryState.promptText || "",
7099
+ context.runtime.episodicMemory || "",
7100
+ context.runtime.product ? buildProductContext(context.runtime.product) : ""
7101
+ ].filter(Boolean).join("\n\n");
7102
+ agent.setMemory(fullMemory);
7082
7103
  console.log(`memory reloaded from ${memoryState.path} (${memoryState.exists ? "found" : "missing"})`);
7083
7104
  continue;
7084
7105
  }
@@ -7088,7 +7109,8 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
7088
7109
  const result = await initProjectMemory(context.cwd);
7089
7110
  const memoryState = await readProjectMemory(context.cwd);
7090
7111
  context.runtime.projectMemory = memoryState;
7091
- agent.setMemory(memoryState.promptText);
7112
+ const fullMemory = [memoryState.promptText || "", context.runtime.episodicMemory || "", context.runtime.product ? buildProductContext(context.runtime.product) : ""].filter(Boolean).join("\n\n");
7113
+ agent.setMemory(fullMemory);
7092
7114
  console.log(`${result.created ? "created" : "already exists"} ${result.path}`);
7093
7115
  } catch (error) {
7094
7116
  console.log(`memory init failed: ${error instanceof Error ? error.message : String(error)}`);
@@ -7102,7 +7124,8 @@ Be concrete about surfaces — name actual pages/flows. Choose the best stack fo
7102
7124
  const memoryPath = await appendProjectMemoryNote(context.cwd, note);
7103
7125
  const memoryState = await readProjectMemory(context.cwd);
7104
7126
  context.runtime.projectMemory = memoryState;
7105
- agent.setMemory(memoryState.promptText);
7127
+ const fullMemory = [memoryState.promptText || "", context.runtime.episodicMemory || "", context.runtime.product ? buildProductContext(context.runtime.product) : ""].filter(Boolean).join("\n\n");
7128
+ agent.setMemory(fullMemory);
7106
7129
  console.log(`memory updated: ${memoryPath}`);
7107
7130
  } catch (error) {
7108
7131
  console.log(`memory add failed: ${error instanceof Error ? error.message : String(error)}`);