Commit 9364a62cbb95

Vincent Demeester <vincent@sbr.pm>
2026-02-02 16:18:40
pi: add session tracking and update/append support to session-history
- Track currentSessionFile and currentSessionDescription across saves - First /save-session creates new file - Subsequent /save-session in same session: - Replaces file if content >20% longer or contains '## Update' - Otherwise appends '## Update (time)' section - Reset tracking on new session_start - Notify user whether updating existing or creating new session
1 parent 9cd49ff
Changed files (1)
dots
pi
agent
dots/pi/agent/extensions/session-history.ts
@@ -22,6 +22,10 @@ export default function (pi: ExtensionAPI) {
 	const HISTORY_DIR = join(homedir(), ".config", "claude", "history");
 	const SESSIONS_DIR = join(HISTORY_DIR, "sessions");
 
+	// Track current session file across multiple saves
+	let currentSessionFile: string | null = null;
+	let currentSessionDescription: string | null = null;
+
 	/**
 	 * Detect which tool is being used
 	 */
@@ -93,7 +97,7 @@ export default function (pi: ExtensionAPI) {
 		name: "save_session_to_history",
 		label: "Save Session to History",
 		description:
-			"Saves a session summary to ~/.config/claude/history/sessions/. Works with any AI coding tool (pi, claude, copilot, cursor). Auto-detects which tool is being used.",
+			"Saves a session summary to ~/.config/claude/history/sessions/. Works with any AI coding tool (pi, claude, copilot, cursor). Auto-detects which tool is being used. If called multiple times in the same session, updates the existing file.",
 		parameters: {
 			type: "object",
 			properties: {
@@ -127,21 +131,70 @@ export default function (pi: ExtensionAPI) {
 				// Create directory
 				await mkdir(sessionDir, { recursive: true });
 
-				// Write file
-				await writeFile(filepath, content, "utf-8");
+				// Check if we're updating the current session or creating a new one
+				const isUpdate = currentSessionFile === filepath;
 
-				// Append to session log
-				await appendToSessionLog(`Session saved: ${filename}`);
+				if (isUpdate) {
+					// Read existing content
+					const existingContent = await readFile(filepath, "utf-8");
 
-				return {
-					content: [
-						{
-							type: "text",
-							text: `✓ Session saved to: ${filepath}`,
-						},
-					],
-					details: {},
-				};
+					// Check if we should append or replace
+					// If content has changed significantly, replace; otherwise append
+					if (content.length > existingContent.length * 1.2 || content.includes("## Update")) {
+						// Replace with new version
+						await writeFile(filepath, content, "utf-8");
+						await appendToSessionLog(`Session updated: ${filename}`);
+
+						return {
+							content: [
+								{
+									type: "text",
+									text: `✓ Session updated: ${filepath}`,
+								},
+							],
+							details: { updated: true },
+						};
+					} else {
+						// Append update section
+						const updateSection = `\n\n---\n\n## Update (${time})\n\n${content
+							.split("\n")
+							.filter((line) => !line.startsWith("#") && !line.startsWith("**Date:**") && !line.startsWith("**Time:**"))
+							.join("\n")}`;
+
+						await appendFile(filepath, updateSection);
+						await appendToSessionLog(`Session updated: ${filename}`);
+
+						return {
+							content: [
+								{
+									type: "text",
+									text: `✓ Session updated (appended): ${filepath}`,
+								},
+							],
+							details: { updated: true, appended: true },
+						};
+					}
+				} else {
+					// New session file
+					await writeFile(filepath, content, "utf-8");
+
+					// Track this as the current session
+					currentSessionFile = filepath;
+					currentSessionDescription = description;
+
+					// Append to session log
+					await appendToSessionLog(`Session saved: ${filename}`);
+
+					return {
+						content: [
+							{
+								type: "text",
+								text: `✓ Session saved to: ${filepath}`,
+							},
+						],
+						details: { created: true },
+					};
+				}
 			} catch (error) {
 				return {
 					content: [
@@ -156,9 +209,13 @@ export default function (pi: ExtensionAPI) {
 		},
 	});
 
-	// Log session start
+	// Log session start and reset session tracking
 	pi.on("session_start", async (_event, ctx) => {
 		try {
+			// Reset session tracking on new session
+			currentSessionFile = null;
+			currentSessionDescription = null;
+
 			await logSessionStart();
 			// Show hint
 			ctx.ui.setStatus("session", ctx.ui.theme.fg("dim", "💾 /save-session"));
@@ -177,7 +234,17 @@ export default function (pi: ExtensionAPI) {
 			ctx.ui.notify("Generating session summary...", "info");
 
 			// Insert a prompt for the AI
-			const prompt = `Please generate a session summary for this conversation following the Session Entry template from the CORE skill's history-system.md.
+			const prompt = `Please generate ${currentSessionFile ? "an updated" : "a"} session summary for this conversation following the Session Entry template from the CORE skill's history-system.md.
+
+${
+	currentSessionFile
+		? `This session has already been saved. Please review what additional work was done and either:
+1. Generate a complete updated summary (if significant new work was done)
+2. Or generate just an update section with the new accomplishments
+
+Current session: ${currentSessionDescription}`
+		: ""
+}
 
 The summary should include:
 - A descriptive title
@@ -223,7 +290,7 @@ Result of the session.
 #${tool} #relevant-tags
 \`\`\`
 
-After generating the summary, use the save_session_to_history tool to save it with an appropriate filename description.`;
+After generating the summary, use the save_session_to_history tool to save it${currentSessionFile ? " (it will automatically update the existing session file)" : " with an appropriate filename description"}.`;
 
 			// Set the editor text to trigger the AI
 			ctx.ui.setEditorText(prompt);