@@ -5,6 +5,7 @@ import { writeClaudeConfig } from './writers/claude';
55import { writeWindsurfConfig } from './writers/windsurf' ;
66import { writeCopilotConfig } from './writers/copilot' ;
77import { writeCodexConfig } from './writers/codex' ;
8+ import { DashboardPanel } from './panels/DashboardPanel' ;
89
910let session_id : string | null = null ;
1011let backend_url = 'http://localhost:8080' ;
@@ -15,6 +16,7 @@ let auto_linked = false;
1516let use_mcp = false ;
1617let mcp_server_path = '' ;
1718let is_enabled = true ;
19+ let user_id = '' ;
1820
1921export function activate ( context : vscode . ExtensionContext ) {
2022 const config = vscode . workspace . getConfiguration ( 'openmemory' ) ;
@@ -23,6 +25,7 @@ export function activate(context: vscode.ExtensionContext) {
2325 api_key = config . get ( 'apiKey' ) || undefined ;
2426 use_mcp = config . get ( 'useMCP' ) || false ;
2527 mcp_server_path = config . get ( 'mcpServerPath' ) || '' ;
28+ user_id = getUserId ( context , config ) ;
2629
2730 status_bar = vscode . window . createStatusBarItem ( vscode . StatusBarAlignment . Right , 100 ) ;
2831 status_bar . command = 'openmemory.statusBarClick' ;
@@ -48,19 +51,67 @@ export function activate(context: vscode.ExtensionContext) {
4851 } ) ;
4952
5053 const status_click = vscode . commands . registerCommand ( 'openmemory.statusBarClick' , ( ) => show_menu ( ) ) ;
54+
5155 const query_cmd = vscode . commands . registerCommand ( 'openmemory.queryContext' , async ( ) => {
5256 const editor = vscode . window . activeTextEditor ;
5357 if ( ! editor ) {
5458 vscode . window . showErrorMessage ( 'No active editor' ) ;
5559 return ;
5660 }
61+
62+ await vscode . window . withProgress ( {
63+ location : vscode . ProgressLocation . Notification ,
64+ title : "OpenMemory: Querying Context..." ,
65+ cancellable : false
66+ } , async ( ) => {
67+ try {
68+ const query = editor . document . getText ( editor . selection ) || editor . document . getText ( ) ;
69+ const memories = await query_context ( query , editor . document . uri . fsPath ) ;
70+ const doc = await vscode . workspace . openTextDocument ( { content : format_memories ( memories ) , language : 'markdown' } ) ;
71+ await vscode . window . showTextDocument ( doc ) ;
72+ } catch ( error ) {
73+ vscode . window . showErrorMessage ( `Query failed: ${ error } ` ) ;
74+ }
75+ } ) ;
76+ } ) ;
77+
78+ const add_cmd = vscode . commands . registerCommand ( 'openmemory.addToMemory' , async ( ) => {
79+ const editor = vscode . window . activeTextEditor ;
80+ if ( ! editor ) {
81+ vscode . window . showErrorMessage ( 'No active editor' ) ;
82+ return ;
83+ }
84+ const selection = editor . document . getText ( editor . selection ) ;
85+ if ( ! selection ) {
86+ vscode . window . showErrorMessage ( 'No text selected' ) ;
87+ return ;
88+ }
89+
90+ await vscode . window . withProgress ( {
91+ location : vscode . ProgressLocation . Notification ,
92+ title : "OpenMemory: Saving Selection..." ,
93+ cancellable : false
94+ } , async ( ) => {
95+ try {
96+ await add_memory ( selection , editor . document . uri . fsPath ) ;
97+ vscode . window . showInformationMessage ( 'Selection added to OpenMemory' ) ;
98+ } catch ( error ) {
99+ vscode . window . showErrorMessage ( `Failed to add memory: ${ error } ` ) ;
100+ }
101+ } ) ;
102+ } ) ;
103+
104+ const note_cmd = vscode . commands . registerCommand ( 'openmemory.quickNote' , async ( ) => {
105+ const input = await vscode . window . showInputBox ( { prompt : 'Enter a quick note to remember' , placeHolder : 'e.g. Refactored the auth logic to use JWT' } ) ;
106+ if ( ! input ) return ;
107+
57108 try {
58- const query = editor . document . getText ( editor . selection ) || editor . document . getText ( ) ;
59- const memories = await query_context ( query , editor . document . uri . fsPath ) ;
60- const doc = await vscode . workspace . openTextDocument ( { content : format_memories ( memories ) , language : 'markdown' } ) ;
61- await vscode . window . showTextDocument ( doc ) ;
109+ const editor = vscode . window . activeTextEditor ;
110+ const file = editor ? editor . document . uri . fsPath : 'manual-note' ;
111+ await add_memory ( input , file ) ;
112+ vscode . window . showInformationMessage ( 'Note added to OpenMemory' ) ;
62113 } catch ( error ) {
63- vscode . window . showErrorMessage ( `Query failed : ${ error } ` ) ;
114+ vscode . window . showErrorMessage ( `Failed to add note : ${ error } ` ) ;
64115 }
65116 } ) ;
66117
@@ -86,6 +137,10 @@ export function activate(context: vscode.ExtensionContext) {
86137
87138 const setup_cmd = vscode . commands . registerCommand ( 'openmemory.setup' , ( ) => show_quick_setup ( ) ) ;
88139
140+ const dashboard_cmd = vscode . commands . registerCommand ( 'openmemory.dashboard' , ( ) => {
141+ DashboardPanel . createOrShow ( context . extensionUri ) ;
142+ } ) ;
143+
89144 const change_listener = vscode . workspace . onDidChangeTextDocument ( ( e ) => {
90145 if ( is_enabled && is_tracking && e . document . uri . scheme === 'file' ) {
91146 for ( const change of e . contentChanges ) {
@@ -114,7 +169,7 @@ export function activate(context: vscode.ExtensionContext) {
114169 }
115170 } ) ;
116171
117- context . subscriptions . push ( status_click , query_cmd , patterns_cmd , toggle_cmd , setup_cmd , change_listener , save_listener , open_listener , close_listener ) ;
172+ context . subscriptions . push ( status_click , query_cmd , add_cmd , note_cmd , patterns_cmd , dashboard_cmd , toggle_cmd , setup_cmd , change_listener , save_listener , open_listener , close_listener ) ;
118173}
119174
120175export function deactivate ( ) {
@@ -174,13 +229,17 @@ async function show_menu() {
174229
175230 const items = [ ] ;
176231 items . push ( is_tracking ? { label : '$(debug-pause) Pause Tracking' , action : 'pause' } : { label : '$(play) Resume Tracking' , action : 'resume' } ) ;
177- items . push ( { label : '$(search) Query Context' , action : 'query' } , { label : '$(graph) View Patterns' , action : 'patterns' } , { label : use_mcp ? '$(link) Switch to Direct HTTP' : '$(server-process) Switch to MCP Mode' , action : 'toggle_mcp' } , { label : '$(circle-slash) Disable Extension' , action : 'disable' } , { label : '$(gear) Setup' , action : 'setup' } , { label : '$(refresh) Reconnect' , action : 'reconnect' } ) ;
232+ items . push ( { label : '$(dashboard) Open Dashboard' , action : 'dashboard' } ) ;
233+ items . push ( { label : '$(search) Query Context' , action : 'query' } , { label : '$(add) Add Selection' , action : 'add' } , { label : '$(pencil) Quick Note' , action : 'note' } , { label : '$(graph) View Patterns' , action : 'patterns' } , { label : use_mcp ? '$(link) Switch to Direct HTTP' : '$(server-process) Switch to MCP Mode' , action : 'toggle_mcp' } , { label : '$(circle-slash) Disable Extension' , action : 'disable' } , { label : '$(gear) Setup' , action : 'setup' } , { label : '$(refresh) Reconnect' , action : 'reconnect' } ) ;
178234 const choice = await vscode . window . showQuickPick ( items , { placeHolder : 'OpenMemory Actions' } ) ;
179235 if ( ! choice ) return ;
180236 switch ( choice . action ) {
237+ case 'dashboard' : vscode . commands . executeCommand ( 'openmemory.dashboard' ) ; break ;
181238 case 'pause' : is_tracking = false ; update_status_bar ( 'paused' ) ; break ;
182239 case 'resume' : is_tracking = true ; update_status_bar ( 'active' ) ; break ;
183240 case 'query' : vscode . commands . executeCommand ( 'openmemory.queryContext' ) ; break ;
241+ case 'add' : vscode . commands . executeCommand ( 'openmemory.addToMemory' ) ; break ;
242+ case 'note' : vscode . commands . executeCommand ( 'openmemory.quickNote' ) ; break ;
184243 case 'patterns' : vscode . commands . executeCommand ( 'openmemory.viewPatterns' ) ; break ;
185244 case 'toggle_mcp' :
186245 use_mcp = ! use_mcp ;
@@ -290,6 +349,26 @@ async function show_quick_setup() {
290349 }
291350}
292351
352+ function getUserId ( context : vscode . ExtensionContext , config : vscode . WorkspaceConfiguration ) : string {
353+ // 1. Check if user has configured a custom userId
354+ const configuredUserId = config . get < string > ( 'userId' ) ;
355+ if ( configuredUserId ) return configuredUserId ;
356+
357+ // 2. Check if we have a persistent userId in global state
358+ let persistedUserId = context . globalState . get < string > ( 'openmemory.userId' ) ;
359+ if ( persistedUserId ) return persistedUserId ;
360+
361+ // 3. Generate a new unique userId based on machine ID
362+ const machineId = vscode . env . machineId ; // Unique per machine
363+ const userName = process . env . USERNAME || process . env . USER || 'user' ;
364+ persistedUserId = `${ userName } -${ machineId . substring ( 0 , 8 ) } ` ;
365+
366+ // 4. Persist it for future sessions
367+ context . globalState . update ( 'openmemory.userId' , persistedUserId ) ;
368+
369+ return persistedUserId ;
370+ }
371+
293372async function check_connection ( ) : Promise < boolean > {
294373 try {
295374 const response = await fetch ( `${ backend_url } /health` , { method : 'GET' , headers : get_headers ( ) } ) ;
@@ -307,8 +386,10 @@ function get_headers(): Record<string, string> {
307386
308387async function start_session ( ) {
309388 try {
310- const project = vscode . workspace . workspaceFolders ?. [ 0 ] ?. name || 'unknown' ;
311- const response = await fetch ( `${ backend_url } /api/ide/session/start` , { method : 'POST' , headers : get_headers ( ) , body : JSON . stringify ( { user_id : 'vscode-user' , project_name : project , ide_name : 'vscode' } ) } ) ;
389+ const config = vscode . workspace . getConfiguration ( 'openmemory' ) ;
390+ const configuredProject = config . get < string > ( 'projectName' ) ;
391+ const project = configuredProject || vscode . workspace . workspaceFolders ?. [ 0 ] ?. name || 'unknown' ;
392+ const response = await fetch ( `${ backend_url } /api/ide/session/start` , { method : 'POST' , headers : get_headers ( ) , body : JSON . stringify ( { user_id : user_id , project_name : project , ide_name : 'vscode' } ) } ) ;
312393 if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` ) ;
313394 const data = await response . json ( ) ;
314395 session_id = data . session_id ;
@@ -342,6 +423,21 @@ async function query_context(query: string, file: string) {
342423 return data . memories || [ ] ;
343424}
344425
426+ async function add_memory ( content : string , file : string ) {
427+ const response = await fetch ( `${ backend_url } /memory/add` , {
428+ method : 'POST' ,
429+ headers : get_headers ( ) ,
430+ body : JSON . stringify ( {
431+ content,
432+ user_id : user_id ,
433+ tags : [ 'manual' , 'ide-selection' ] ,
434+ metadata : { source : 'vscode' , file }
435+ } )
436+ } ) ;
437+ if ( ! response . ok ) throw new Error ( `HTTP ${ response . status } ` ) ;
438+ return await response . json ( ) ;
439+ }
440+
345441async function get_patterns ( sid : string ) {
346442 const response = await fetch ( `${ backend_url } /api/ide/patterns/${ sid } ` , { method : 'GET' , headers : get_headers ( ) } ) ;
347443 const data = await response . json ( ) ;
0 commit comments