@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 +1 -1
- package/src/cli.js +16 -1
- package/src/episodic.js +50 -0
package/package.json
CHANGED
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");
|