@tritard/waterbrother 0.10.1 → 0.10.2

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": "@tritard/waterbrother",
3
- "version": "0.10.1",
3
+ "version": "0.10.2",
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
@@ -32,7 +32,7 @@ import { runDecisionPass, runInventPass, formatDecisionForDisplay, formatDecisio
32
32
  import { runBuildWorkflow, startFeatureTask, runChallengeWorkflow } from "./workflow.js";
33
33
  import { createPanelRenderer, buildPanelState } from "./panel.js";
34
34
  import { deriveTaskNameFromPrompt, nextActionsForState, routeNaturalInput } from "./router.js";
35
- import { compressEpisode, saveEpisode, loadRecentEpisodes, findRelevantEpisodes, buildEpisodicMemoryBlock, buildReminderBlock } from "./episodic.js";
35
+ import { compressEpisode, compressSessionEpisode, saveEpisode, loadRecentEpisodes, findRelevantEpisodes, buildEpisodicMemoryBlock, buildReminderBlock } from "./episodic.js";
36
36
  import { formatPlanForDisplay } from "./planner.js";
37
37
  import { parseCharterFromGoal, runExperimentLoop, formatExperimentSummary, gitReturnToBranch } from "./experiment.js";
38
38
 
@@ -6976,6 +6976,21 @@ async function promptLoop(agent, session, context) {
6976
6976
  }
6977
6977
  }
6978
6978
 
6979
+ // Save CC-mode session episode on exit (if any files were touched)
6980
+ if (!context.runtime.activeTask) {
6981
+ try {
6982
+ const receipts = await agent.toolRuntime.listReceipts(50);
6983
+ const userMessages = agent.getSessionMessages()
6984
+ .filter((m) => m.role === "user")
6985
+ .map((m) => String(m.content || "").trim())
6986
+ .filter(Boolean);
6987
+ const episode = compressSessionEpisode({ receipts, userMessages });
6988
+ if (episode) {
6989
+ await saveEpisode({ cwd: context.cwd, episode });
6990
+ }
6991
+ } catch {}
6992
+ }
6993
+
6979
6994
  return currentSession;
6980
6995
  }
6981
6996
 
package/src/episodic.js CHANGED
@@ -133,6 +133,56 @@ export function compressEpisode({ task, receipt }) {
133
133
  };
134
134
  }
135
135
 
136
+ export function compressSessionEpisode({ receipts = [], userMessages = [] }) {
137
+ // Collect all changed files across all receipts
138
+ const allFiles = [];
139
+ const allConcerns = [];
140
+ const keyFacts = [];
141
+ let hasMutations = false;
142
+
143
+ for (const r of receipts) {
144
+ if (r.changedFiles?.length) allFiles.push(...r.changedFiles);
145
+ if (r.mutated) hasMutations = true;
146
+ if (r.review?.concerns?.length) allConcerns.push(...r.review.concerns);
147
+ if (r.review?.verdict) keyFacts.push(`Sentinel: ${r.review.verdict}`);
148
+ }
149
+
150
+ // Don't save empty sessions (no mutations, nothing to remember)
151
+ if (!hasMutations && allFiles.length === 0) return null;
152
+
153
+ const filesChanged = [...new Set(allFiles)].slice(0, MAX_FILES_PER_EPISODE);
154
+ const filePatterns = deriveFilePatterns(filesChanged);
155
+
156
+ // Extract a summary from user messages
157
+ const meaningful = userMessages
158
+ .filter((m) => m.length > 5 && !m.startsWith("/"))
159
+ .slice(0, 5);
160
+ if (meaningful.length > 0) {
161
+ keyFacts.unshift(`Worked on: ${meaningful[0].slice(0, 100)}`);
162
+ }
163
+
164
+ const sentinelConcerns = [...new Set(allConcerns)].slice(0, 5);
165
+ const tagSource = [...meaningful.slice(0, 2), ...filesChanged].join(" ");
166
+ const tags = deriveTags(tagSource);
167
+ const name = meaningful[0]?.slice(0, 40) || "cc-session";
168
+
169
+ return {
170
+ id: makeEpisodeId(name),
171
+ taskId: null,
172
+ taskName: `[session] ${name}`,
173
+ closedAt: new Date().toISOString(),
174
+ goal: meaningful[0] || "",
175
+ chosenOption: null,
176
+ outcome: hasMutations ? "session-complete" : "session-readonly",
177
+ filesChanged,
178
+ filePatterns,
179
+ keyFacts: keyFacts.slice(0, 8),
180
+ warnings: [],
181
+ sentinelConcerns,
182
+ tags
183
+ };
184
+ }
185
+
136
186
  export async function saveEpisode({ cwd, episode }) {
137
187
  await fs.mkdir(memoryDir(cwd), { recursive: true });
138
188
  await fs.writeFile(episodePath(cwd, episode.id), `${JSON.stringify(episode, null, 2)}\n`, "utf8");