-
Notifications
You must be signed in to change notification settings - Fork 2k
Fix opencode session project path tracking in agentmemory capture plugin #999
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -47,11 +47,12 @@ async function observe( | |||||||
| hookType: string, | ||||||||
| data: Record<string, unknown>, | ||||||||
| ): Promise<void> { | ||||||||
| const project = sessionProjects.get(sessionId) || projectPath; | ||||||||
| await post("/observe", { | ||||||||
| hookType, | ||||||||
| sessionId, | ||||||||
| project: projectPath, | ||||||||
| cwd: projectPath, | ||||||||
| project, | ||||||||
| cwd: project, | ||||||||
| timestamp: new Date().toISOString(), | ||||||||
| data, | ||||||||
| }); | ||||||||
|
|
@@ -60,6 +61,7 @@ async function observe( | |||||||
| let activeSessionId: string | null = null; | ||||||||
| let pendingConfig: Record<string, unknown> | null = null; | ||||||||
| let projectPath: string | null = null; | ||||||||
| const sessionProjects = new Map<string, string>(); | ||||||||
| const stashedFiles = new Map<string, Set<string>>(); | ||||||||
| const seenSubtaskIds = new Map<string, Set<string>>(); | ||||||||
| const seenToolCallIds = new Map<string, Set<string>>(); | ||||||||
|
|
@@ -93,6 +95,13 @@ function pruneSessionMaps(sid: string): void { | |||||||
| stashedFiles.delete(sid); | ||||||||
| seenSubtaskIds.delete(sid); | ||||||||
| seenToolCallIds.delete(sid); | ||||||||
| sessionProjects.delete(sid); | ||||||||
| } | ||||||||
|
|
||||||||
| async function updateSessionProject(sessionId: string, cwd: unknown): Promise<void> { | ||||||||
| if (typeof cwd !== "string" || cwd.length === 0) return; | ||||||||
| if (sessionProjects.get(sessionId) === cwd) return; | ||||||||
| sessionProjects.set(sessionId, cwd); | ||||||||
| } | ||||||||
|
|
||||||||
| function safeSlice(v: unknown, max: number): string { | ||||||||
|
|
@@ -168,7 +177,8 @@ function extractErrorMessage(err: unknown): string { | |||||||
| } | ||||||||
|
|
||||||||
| export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | ||||||||
| projectPath = ctx.worktree || ctx.project?.id || process.cwd(); | ||||||||
| const currentDirectory = (ctx as any).directory || process.cwd(); | ||||||||
| projectPath = process.env.AGENTMEMORY_PROJECT || currentDirectory || ctx.project?.id || ctx.worktree || process.cwd(); | ||||||||
|
Comment on lines
+180
to
+181
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Broken fallback precedence —
🐛 Proposed fix- const currentDirectory = (ctx as any).directory || process.cwd();
- projectPath = process.env.AGENTMEMORY_PROJECT || currentDirectory || ctx.project?.id || ctx.worktree || process.cwd();
+ projectPath = process.env.AGENTMEMORY_PROJECT || (ctx as any).directory || ctx.project?.id || ctx.worktree || process.cwd();📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||
|
|
||||||||
| return { | ||||||||
| event: async ({ event }) => { | ||||||||
|
|
@@ -180,6 +190,11 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| const info = props.info as Record<string, unknown> | undefined; | ||||||||
| activeSessionId = (info?.id as string) || props.sessionID || null; | ||||||||
| if (!activeSessionId) return; | ||||||||
| const sessionProject = process.env.AGENTMEMORY_PROJECT | ||||||||
| || (typeof info?.directory === "string" && info.directory.length > 0 ? info.directory : "") | ||||||||
| || projectPath | ||||||||
| || process.cwd(); | ||||||||
| sessionProjects.set(activeSessionId, sessionProject); | ||||||||
| stashedFiles.set(activeSessionId, new Set()); | ||||||||
| seenSubtaskIds.delete(activeSessionId); | ||||||||
| seenToolCallIds.delete(activeSessionId); | ||||||||
|
|
@@ -190,11 +205,11 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| const sessionId = activeSessionId; | ||||||||
| const startResult = await postJson("/session/start", { | ||||||||
| sessionId, | ||||||||
| title: info?.title ?? null, | ||||||||
| title: info?.title ?? sessionProject, | ||||||||
| parentID: info?.parentID ?? null, | ||||||||
| version: info?.version ?? null, | ||||||||
| project: projectPath, | ||||||||
| cwd: projectPath, | ||||||||
| project: sessionProject, | ||||||||
| cwd: sessionProject, | ||||||||
|
Comment on lines
+208
to
+212
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Session title now defaults to a raw filesystem path.
🤖 Prompt for AI Agents |
||||||||
| }); | ||||||||
| // cache the context returned at session/start so the | ||||||||
| // chat.system.transform hook injects it without a second fetch. | ||||||||
|
|
@@ -239,6 +254,9 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| const info = props.info as Record<string, unknown> | undefined; | ||||||||
| const sid = (info?.id as string) || props.sessionID || activeSessionId; | ||||||||
| if (!sid) return; | ||||||||
| if (typeof info?.directory === "string" && info.directory.length > 0) { | ||||||||
| sessionProjects.set(sid, process.env.AGENTMEMORY_PROJECT || info.directory); | ||||||||
| } | ||||||||
| await observe(sid, "session_updated", { | ||||||||
| title: info?.title ?? null, | ||||||||
| parentID: info?.parentID ?? null, | ||||||||
|
|
@@ -299,6 +317,10 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| if (info.role === "assistant") { | ||||||||
| const sid = props.sessionID || (info.sessionID as string) || activeSessionId; | ||||||||
| if (!sid) return; | ||||||||
| const cwd = (info as any).path?.cwd; | ||||||||
| if (typeof cwd === "string" && cwd.length > 0) { | ||||||||
| sessionProjects.set(sid, process.env.AGENTMEMORY_PROJECT || cwd); | ||||||||
| } | ||||||||
| const tokens = info.tokens as Record<string, unknown> | undefined; | ||||||||
| const error = info.error ? extractErrorMessage(info.error) : null; | ||||||||
| await observe(sid, "assistant_message", { | ||||||||
|
|
@@ -579,6 +601,11 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| }); | ||||||||
| }, | ||||||||
|
|
||||||||
| // ── shell.env ── | ||||||||
| "shell.env": async (input) => { | ||||||||
| if (input.sessionID) await updateSessionProject(input.sessionID, input.cwd); | ||||||||
| }, | ||||||||
|
|
||||||||
| // ── tool.execute.before ── | ||||||||
| "tool.execute.before": async (input, output) => { | ||||||||
| if (!FILE_TOOLS.has(input.tool)) return; | ||||||||
|
|
@@ -612,7 +639,7 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
| if (typeof ctx !== "string" || ctx.length === 0) { | ||||||||
| const result = await postJson("/context", { | ||||||||
| sessionId: sid, | ||||||||
| project: projectPath, | ||||||||
| project: sessionProjects.get(sid) || projectPath, | ||||||||
| }); | ||||||||
| ctx = (result as any)?.context; | ||||||||
| } else { | ||||||||
|
|
@@ -650,7 +677,7 @@ export const AgentmemoryCapturePlugin: Plugin = async (ctx) => { | |||||||
|
|
||||||||
| const result = await postJson("/context", { | ||||||||
| sessionId: sid, | ||||||||
| project: projectPath, | ||||||||
| project: sessionProjects.get(sid) || projectPath, | ||||||||
| }); | ||||||||
| const ctx = (result as any)?.context; | ||||||||
| if (typeof ctx === "string" && ctx.length > 0) { | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
updateSessionProject()ignoresAGENTMEMORY_PROJECT, unlike every other update site.session.created(193-197),session.updated(257-259), and assistantmessage.updated(320-323) all preferprocess.env.AGENTMEMORY_PROJECTbefore the discovered path.updateSessionProject()— the only function invoked by the newshell.envhandler (Lines 604-608) — writescwdunconditionally, so a shell command's directory can silently clobber a user's explicitAGENTMEMORY_PROJECToverride. This reintroduces the "wrong project directory picked up" failure mode this PR is fixing.🐛 Proposed fix
async function updateSessionProject(sessionId: string, cwd: unknown): Promise<void> { if (typeof cwd !== "string" || cwd.length === 0) return; - if (sessionProjects.get(sessionId) === cwd) return; - sessionProjects.set(sessionId, cwd); + const resolved = process.env.AGENTMEMORY_PROJECT || cwd; + if (sessionProjects.get(sessionId) === resolved) return; + sessionProjects.set(sessionId, resolved); }📝 Committable suggestion
🤖 Prompt for AI Agents