opencode-branch-memory-manager 0.1.6 → 0.1.9
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.
|
@@ -5,3 +5,27 @@ export { ContextInjector } from "./injector.js";
|
|
|
5
5
|
export { BranchMonitor } from "./monitor.js";
|
|
6
6
|
export { ConfigManager } from "./config.js";
|
|
7
7
|
export type { BranchContext, PluginConfig, Message, Todo } from "./types.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Show a toast notification in the OpenCode UI
|
|
11
|
+
* Falls back to console.log if toast API is unavailable
|
|
12
|
+
*/
|
|
13
|
+
export function showToast(
|
|
14
|
+
client: any,
|
|
15
|
+
message: string,
|
|
16
|
+
variant: "info" | "success" | "warning" | "error" = "info",
|
|
17
|
+
title?: string,
|
|
18
|
+
duration?: number
|
|
19
|
+
): void {
|
|
20
|
+
try {
|
|
21
|
+
client?.global?.tui?.showToast?.({
|
|
22
|
+
title: title || "Branch Memory",
|
|
23
|
+
message,
|
|
24
|
+
variant,
|
|
25
|
+
duration: duration || (variant === "error" ? undefined : 3000)
|
|
26
|
+
});
|
|
27
|
+
} catch (error) {
|
|
28
|
+
// Fallback to console if toast unavailable
|
|
29
|
+
console.log(`[${variant.toUpperCase()}] ${title || "Branch Memory"}: ${message}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -2176,19 +2176,34 @@ class ConfigManager {
|
|
|
2176
2176
|
return result;
|
|
2177
2177
|
}
|
|
2178
2178
|
}
|
|
2179
|
+
|
|
2180
|
+
// .opencode/branch-memory/index.ts
|
|
2181
|
+
function showToast(client, message, variant = "info", title, duration) {
|
|
2182
|
+
try {
|
|
2183
|
+
client?.global?.tui?.showToast?.({
|
|
2184
|
+
title: title || "Branch Memory",
|
|
2185
|
+
message,
|
|
2186
|
+
variant,
|
|
2187
|
+
duration: duration || (variant === "error" ? undefined : 3000)
|
|
2188
|
+
});
|
|
2189
|
+
} catch (error) {
|
|
2190
|
+
console.log(`[${variant.toUpperCase()}] ${title || "Branch Memory"}: ${message}`);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2179
2194
|
// .opencode/plugin/branch-memory-plugin.ts
|
|
2180
2195
|
var BranchMemoryPlugin = async ({ project, client, $, directory, worktree }) => {
|
|
2181
|
-
console.log("\uD83E\uDDE0 Branch Memory Plugin initializing...");
|
|
2182
2196
|
const configManager = new ConfigManager(directory);
|
|
2183
2197
|
const isGitRepo = await GitOperations.isGitRepo();
|
|
2184
2198
|
if (!isGitRepo) {
|
|
2185
|
-
|
|
2199
|
+
showToast(client, "Not in a git repository. Branch memory features disabled.", "warning");
|
|
2186
2200
|
return {};
|
|
2187
2201
|
}
|
|
2188
2202
|
const config = await configManager.load();
|
|
2189
2203
|
const storage = new ContextStorage(configManager.getStorageDir(), config);
|
|
2190
2204
|
const collector = new ContextCollector(config, client);
|
|
2191
2205
|
let lastAutoSave = 0;
|
|
2206
|
+
let saveCount = 0;
|
|
2192
2207
|
const autoSave = async (reason) => {
|
|
2193
2208
|
const currentConfig = await configManager.load();
|
|
2194
2209
|
if (currentConfig.autoSave.enabled) {
|
|
@@ -2200,46 +2215,40 @@ var BranchMemoryPlugin = async ({ project, client, $, directory, worktree }) =>
|
|
|
2200
2215
|
const context = await collector.collectContext(currentConfig.context.defaultInclude.includes("messages"), currentConfig.context.defaultInclude.includes("todos"), currentConfig.context.defaultInclude.includes("files"), reason);
|
|
2201
2216
|
await storage.saveContext(currentBranch, context);
|
|
2202
2217
|
lastAutoSave = now;
|
|
2203
|
-
|
|
2218
|
+
saveCount++;
|
|
2219
|
+
if (saveCount === 1 || saveCount % 10 === 0) {
|
|
2220
|
+
showToast(client, `Context saved for ${currentBranch}`, "success", undefined, 2000);
|
|
2221
|
+
}
|
|
2204
2222
|
}
|
|
2205
2223
|
} catch (error) {
|
|
2206
|
-
|
|
2224
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2225
|
+
showToast(client, `Failed to save context: ${errorMessage}`, "error");
|
|
2207
2226
|
}
|
|
2208
2227
|
}
|
|
2209
2228
|
}
|
|
2210
2229
|
};
|
|
2211
2230
|
const branchMonitor = new BranchMonitor(async (oldBranch, newBranch) => {
|
|
2212
|
-
console.log(`\uD83D\uDD04 Branch changed: ${oldBranch || "(none)"} → ${newBranch}`);
|
|
2213
2231
|
const currentConfig = await configManager.load();
|
|
2214
2232
|
if (oldBranch && currentConfig.autoSave.onBranchChange) {
|
|
2215
2233
|
const context = await collector.collectContext(currentConfig.context.defaultInclude.includes("messages"), currentConfig.context.defaultInclude.includes("todos"), currentConfig.context.defaultInclude.includes("files"), "branch change");
|
|
2216
2234
|
await storage.saveContext(oldBranch, context);
|
|
2217
|
-
console.log(`\uD83D\uDCBE Saved context for old branch '${oldBranch}'`);
|
|
2218
2235
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
} else {
|
|
2225
|
-
console.log(`ℹ️ No saved context for branch '${newBranch}'`);
|
|
2226
|
-
}
|
|
2227
|
-
} else if (currentConfig.contextLoading === "ask") {
|
|
2228
|
-
console.log(`ℹ️ Context available for branch '${newBranch}'`);
|
|
2229
|
-
console.log(` Use @branch-memory_load to restore it`);
|
|
2236
|
+
const branchContext = await storage.loadContext(newBranch);
|
|
2237
|
+
if (branchContext) {
|
|
2238
|
+
showToast(client, `Switched to ${newBranch}. Context available - use @branch-memory_load to restore.`, "info", "Branch Changed", 5000);
|
|
2239
|
+
} else {
|
|
2240
|
+
showToast(client, `Switched to ${newBranch}. No saved context for this branch.`, "info", "Branch Changed", 3000);
|
|
2230
2241
|
}
|
|
2231
2242
|
}, config);
|
|
2232
2243
|
await branchMonitor.start();
|
|
2233
2244
|
return {
|
|
2234
2245
|
"session.created": async (input, output) => {
|
|
2235
|
-
console.log("\uD83D\uDE80 Session created - checking for saved context...");
|
|
2236
2246
|
const currentConfig = await configManager.load();
|
|
2237
2247
|
const branch = await GitOperations.getCurrentBranch();
|
|
2238
2248
|
if (branch && currentConfig.contextLoading === "auto") {
|
|
2239
2249
|
const branchContext = await storage.loadContext(branch);
|
|
2240
2250
|
if (branchContext) {
|
|
2241
|
-
|
|
2242
|
-
console.log(" Use @branch-memory_load to restore it");
|
|
2251
|
+
showToast(client, `Context available for ${branch}. Use @branch-memory_load to restore.`, "info", undefined, 4000);
|
|
2243
2252
|
}
|
|
2244
2253
|
}
|
|
2245
2254
|
},
|
|
@@ -2256,12 +2265,11 @@ var BranchMemoryPlugin = async ({ project, client, $, directory, worktree }) =>
|
|
|
2256
2265
|
}
|
|
2257
2266
|
},
|
|
2258
2267
|
unload: () => {
|
|
2259
|
-
console.log("\uD83E\uDDE0 Branch Memory Plugin shutting down...");
|
|
2260
2268
|
branchMonitor.stop();
|
|
2261
2269
|
autoSave("plugin unload").catch((error) => {
|
|
2262
|
-
|
|
2270
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2271
|
+
showToast(client, `Final save failed: ${errorMessage}`, "error");
|
|
2263
2272
|
});
|
|
2264
|
-
console.log("✅ Plugin stopped");
|
|
2265
2273
|
}
|
|
2266
2274
|
};
|
|
2267
2275
|
};
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"name": "branch-memory-manager",
|
|
14
14
|
"source": ".",
|
|
15
15
|
"description": "Automatically manages branch-specific context with auto-save and auto-load. Never lose your development context when switching git branches.",
|
|
16
|
-
"version": "0.1.
|
|
16
|
+
"version": "0.1.7",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Davidcreador"
|
|
19
19
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Plugin } from '@opencode-ai/plugin'
|
|
2
|
-
import { ContextStorage, GitOperations, ContextCollector, ConfigManager, BranchMonitor } from '../branch-memory/index.js'
|
|
2
|
+
import { ContextStorage, GitOperations, ContextCollector, ConfigManager, BranchMonitor, showToast } from '../branch-memory/index.js'
|
|
3
3
|
|
|
4
4
|
export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
|
|
5
|
-
|
|
5
|
+
// Silent initialization - no need to notify user
|
|
6
6
|
|
|
7
7
|
// Load configuration
|
|
8
8
|
const configManager = new ConfigManager(directory)
|
|
@@ -10,7 +10,11 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
10
10
|
// Check if we're in a git repository
|
|
11
11
|
const isGitRepo = await GitOperations.isGitRepo()
|
|
12
12
|
if (!isGitRepo) {
|
|
13
|
-
|
|
13
|
+
showToast(
|
|
14
|
+
client,
|
|
15
|
+
'Not in a git repository. Branch memory features disabled.',
|
|
16
|
+
'warning'
|
|
17
|
+
)
|
|
14
18
|
return {}
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -18,8 +22,9 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
18
22
|
const storage = new ContextStorage(configManager.getStorageDir(), config)
|
|
19
23
|
const collector = new ContextCollector(config, client)
|
|
20
24
|
|
|
21
|
-
// Track last auto-save time
|
|
25
|
+
// Track last auto-save time and count
|
|
22
26
|
let lastAutoSave = 0
|
|
27
|
+
let saveCount = 0
|
|
23
28
|
|
|
24
29
|
// Auto-save function with throttling
|
|
25
30
|
const autoSave = async (reason: string) => {
|
|
@@ -41,10 +46,16 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
41
46
|
|
|
42
47
|
await storage.saveContext(currentBranch, context)
|
|
43
48
|
lastAutoSave = now
|
|
44
|
-
|
|
49
|
+
saveCount++
|
|
50
|
+
|
|
51
|
+
// Only show toast on first save or every 10th save to reduce noise
|
|
52
|
+
if (saveCount === 1 || saveCount % 10 === 0) {
|
|
53
|
+
showToast(client, `Context saved for ${currentBranch}`, 'success', undefined, 2000)
|
|
54
|
+
}
|
|
45
55
|
}
|
|
46
56
|
} catch (error) {
|
|
47
|
-
|
|
57
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
58
|
+
showToast(client, `Failed to save context: ${errorMessage}`, 'error')
|
|
48
59
|
}
|
|
49
60
|
}
|
|
50
61
|
}
|
|
@@ -53,8 +64,6 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
53
64
|
// Initialize branch monitor with callback
|
|
54
65
|
const branchMonitor = new BranchMonitor(
|
|
55
66
|
async (oldBranch, newBranch) => {
|
|
56
|
-
console.log(`🔄 Branch changed: ${oldBranch || '(none)'} → ${newBranch}`)
|
|
57
|
-
|
|
58
67
|
const currentConfig = await configManager.load()
|
|
59
68
|
|
|
60
69
|
// Auto-save old branch context
|
|
@@ -66,21 +75,26 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
66
75
|
'branch change'
|
|
67
76
|
)
|
|
68
77
|
await storage.saveContext(oldBranch, context)
|
|
69
|
-
console.log(`💾 Saved context for old branch '${oldBranch}'`)
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
// Check for context and show consolidated message
|
|
81
|
+
const branchContext = await storage.loadContext(newBranch)
|
|
82
|
+
if (branchContext) {
|
|
83
|
+
showToast(
|
|
84
|
+
client,
|
|
85
|
+
`Switched to ${newBranch}. Context available - use @branch-memory_load to restore.`,
|
|
86
|
+
'info',
|
|
87
|
+
'Branch Changed',
|
|
88
|
+
5000
|
|
89
|
+
)
|
|
90
|
+
} else {
|
|
91
|
+
showToast(
|
|
92
|
+
client,
|
|
93
|
+
`Switched to ${newBranch}. No saved context for this branch.`,
|
|
94
|
+
'info',
|
|
95
|
+
'Branch Changed',
|
|
96
|
+
3000
|
|
97
|
+
)
|
|
84
98
|
}
|
|
85
99
|
},
|
|
86
100
|
config
|
|
@@ -92,15 +106,20 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
92
106
|
return {
|
|
93
107
|
// Hook: Auto-load context when session is created
|
|
94
108
|
'session.created': async (input: any, output: any) => {
|
|
95
|
-
|
|
109
|
+
// Only show toast if context exists for current branch
|
|
96
110
|
const currentConfig = await configManager.load()
|
|
97
111
|
const branch = await GitOperations.getCurrentBranch()
|
|
98
112
|
|
|
99
113
|
if (branch && currentConfig.contextLoading === 'auto') {
|
|
100
114
|
const branchContext = await storage.loadContext(branch)
|
|
101
115
|
if (branchContext) {
|
|
102
|
-
|
|
103
|
-
|
|
116
|
+
showToast(
|
|
117
|
+
client,
|
|
118
|
+
`Context available for ${branch}. Use @branch-memory_load to restore.`,
|
|
119
|
+
'info',
|
|
120
|
+
undefined,
|
|
121
|
+
4000
|
|
122
|
+
)
|
|
104
123
|
}
|
|
105
124
|
}
|
|
106
125
|
},
|
|
@@ -124,17 +143,17 @@ export const BranchMemoryPlugin: Plugin = async ({ project, client, $, directory
|
|
|
124
143
|
|
|
125
144
|
// Hook: Cleanup on plugin unload
|
|
126
145
|
unload: () => {
|
|
127
|
-
|
|
146
|
+
// Silent cleanup - no need to notify user
|
|
128
147
|
|
|
129
148
|
// Stop branch monitoring
|
|
130
149
|
branchMonitor.stop()
|
|
131
150
|
|
|
132
151
|
// Save one last time before shutdown
|
|
133
152
|
autoSave('plugin unload').catch((error) => {
|
|
134
|
-
|
|
153
|
+
// Only show error if final save fails
|
|
154
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
155
|
+
showToast(client, `Final save failed: ${errorMessage}`, 'error')
|
|
135
156
|
})
|
|
136
|
-
|
|
137
|
-
console.log('✅ Plugin stopped')
|
|
138
157
|
},
|
|
139
158
|
}
|
|
140
159
|
}
|