Skip to content

Commit 658d1ad

Browse files
author
Marvin Zhang
committed
Refactor workspace management to project management
- Removed WorkspaceContext and related hooks, replacing them with ProjectContext. - Updated useDevlogDetails hook to utilize currentProject instead of currentWorkspace. - Created ProjectManagementPage for managing projects, including project creation and status display. - Implemented ProjectsPage to render ProjectManagementPage. - Deleted WorkspaceManagementPage and associated styles, as workspace management is no longer supported. - Adjusted layout to use ProjectProvider instead of WorkspaceProvider. - Updated SSEEventBridge to work with ProjectDevlogManager instead of WorkspaceDevlogManager. - Removed unused devlog-manager and workspace-management CSS files.
1 parent f0d331a commit 658d1ad

32 files changed

+1278
-1921
lines changed

packages/ai/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ export * from './automation/index.js';
2323
export {
2424
MessageData as Message,
2525
ChatSessionData as ChatSession,
26-
WorkspaceDataContainer as WorkspaceData,
26+
ProjectDataContainer as ProjectData,
2727
} from './models/index.js';

packages/cli/src/api/devlog-api-client.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ export class DevlogApiClient {
170170
/**
171171
* Import chat data to a workspace
172172
*/
173-
async importChatData(workspaceId: string, data: ChatImportRequest): Promise<ChatImportResponse> {
173+
async importChatData(projectId: string, data: ChatImportRequest): Promise<ChatImportResponse> {
174174
try {
175-
const response = await this.client.post(`/api/workspaces/${workspaceId}/chat/import`, data);
175+
const response = await this.client.post(`/api/projects/${projectId}/chat/import`, data);
176176
return response.data;
177177
} catch (error) {
178178
throw error instanceof Error ? error : new Error('Failed to import chat data');
@@ -182,10 +182,10 @@ export class DevlogApiClient {
182182
/**
183183
* Get import progress status
184184
*/
185-
async getImportProgress(workspaceId: string, importId: string): Promise<ChatProgressResponse> {
185+
async getImportProgress(projectId: string, importId: string): Promise<ChatProgressResponse> {
186186
try {
187187
const response = await this.client.get(
188-
`/api/workspaces/${workspaceId}/chat/import?importId=${importId}`,
188+
`/api/projects/${projectId}/chat/import?importId=${importId}`,
189189
);
190190
return response.data;
191191
} catch (error) {
@@ -196,9 +196,9 @@ export class DevlogApiClient {
196196
/**
197197
* List workspaces available on the server
198198
*/
199-
async listWorkspaces(): Promise<any[]> {
199+
async listProjects(): Promise<any[]> {
200200
try {
201-
const response = await this.client.get('/api/workspaces');
201+
const response = await this.client.get('/api/projects');
202202
return response.data.workspaces || [];
203203
} catch (error) {
204204
throw error instanceof Error ? error : new Error('Failed to list workspaces');
@@ -208,20 +208,20 @@ export class DevlogApiClient {
208208
/**
209209
* Get workspace details
210210
*/
211-
async getWorkspace(workspaceId: string): Promise<any> {
211+
async getProject(projectId: string): Promise<any> {
212212
try {
213-
const response = await this.client.get(`/api/workspaces/${workspaceId}`);
213+
const response = await this.client.get(`/api/projects/${projectId}`);
214214
return response.data;
215215
} catch (error) {
216-
throw error instanceof Error ? error : new Error(`Failed to get workspace ${workspaceId}`);
216+
throw error instanceof Error ? error : new Error(`Failed to get workspace ${projectId}`);
217217
}
218218
}
219219

220220
/**
221221
* Search chat content in a workspace
222222
*/
223223
async searchChatContent(
224-
workspaceId: string,
224+
projectId: string,
225225
query: string,
226226
options: {
227227
limit?: number;
@@ -238,7 +238,7 @@ export class DevlogApiClient {
238238
});
239239

240240
const response = await this.client.get(
241-
`/api/workspaces/${workspaceId}/chat/search?${params.toString()}`,
241+
`/api/projects/${projectId}/chat/search?${params.toString()}`,
242242
);
243243
return response.data;
244244
} catch (error) {
@@ -249,9 +249,9 @@ export class DevlogApiClient {
249249
/**
250250
* Get chat statistics for a workspace
251251
*/
252-
async getChatStats(workspaceId: string): Promise<any> {
252+
async getChatStats(projectId: string): Promise<any> {
253253
try {
254-
const response = await this.client.get(`/api/workspaces/${workspaceId}/chat/stats`);
254+
const response = await this.client.get(`/api/projects/${projectId}/chat/stats`);
255255
return response.data;
256256
} catch (error) {
257257
throw error instanceof Error ? error : new Error('Failed to get chat statistics');

packages/cli/src/index.ts

Lines changed: 50 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* DevLog CLI - Main Entry Point
55
*
66
* Command-line interface for streaming chat history to devlog server
7-
* and managing devlog workspaces.
7+
* and managing devlog projects.
88
*/
99

1010
import { Command } from 'commander';
@@ -17,12 +17,12 @@ import {
1717
ChatStatistics,
1818
CopilotParser,
1919
SearchResult,
20-
WorkspaceDataContainer,
20+
ProjectDataContainer,
2121
} from '@codervisor/devlog-ai';
2222
import { DevlogApiClient, ChatImportRequest } from './api/devlog-api-client.js';
2323
import {
24-
convertWorkspaceDataToCoreFormat,
25-
extractWorkspaceInfo,
24+
convertProjectDataToCoreFormat,
25+
extractProjectInfo,
2626
validateConvertedData,
2727
} from './utils/data-mapper.js';
2828
import {
@@ -38,7 +38,7 @@ import { loadConfig, ConfigOptions } from './utils/config.js';
3838
// CLI option interfaces for better type safety
3939
interface BaseCommandOptions {
4040
server?: string;
41-
workspace?: string;
41+
project?: string;
4242
verbose: boolean;
4343
config?: string;
4444
}
@@ -60,10 +60,10 @@ const program = new Command();
6060

6161
program
6262
.name('devlog')
63-
.description('DevLog CLI - Stream chat history and manage devlog workspaces')
63+
.description('DevLog CLI - Stream chat history and manage devlog projects')
6464
.version('0.1.0')
6565
.option('-s, --server <url>', 'DevLog server URL')
66-
.option('-w, --workspace <id>', 'Workspace ID')
66+
.option('-w, --project <id>', 'Project ID')
6767
.option('-c, --config <path>', 'Configuration file path')
6868
.option('-v, --verbose', 'Show detailed progress', false);
6969

@@ -87,16 +87,16 @@ async function setupApiClient(options: BaseCommandOptions): Promise<DevlogApiCli
8787
});
8888
}
8989

90-
function getWorkspaceId(options: BaseCommandOptions, config: ConfigOptions): string {
91-
const workspaceId = options.workspace || config.workspace || process.env.DEVLOG_WORKSPACE;
92-
if (!workspaceId) {
90+
function getProjectId(options: BaseCommandOptions, config: ConfigOptions): string {
91+
const projectId = options.project || config.project || process.env.DEVLOG_PROJECT;
92+
if (!projectId) {
9393
displayError(
9494
'configuration',
95-
'Workspace ID is required. Use --workspace, DEVLOG_WORKSPACE env var, or config file.',
95+
'Project ID is required. Use --project, DEVLOG_PROJECT env var, or config file.',
9696
);
9797
process.exit(1);
9898
}
99-
return workspaceId;
99+
return projectId;
100100
}
101101

102102
// Chat import command
@@ -120,7 +120,7 @@ program
120120
try {
121121
const config = await loadConfig(options.config);
122122
const apiClient = await setupApiClient(options);
123-
const workspaceId = getWorkspaceId(options, config);
123+
const projectId = getProjectId(options, config);
124124

125125
// Test connection first
126126
spinner && (spinner.text = 'Testing server connection...');
@@ -139,30 +139,28 @@ program
139139
}
140140

141141
const parser = new CopilotParser();
142-
const workspaceData = await parser.discoverVSCodeCopilotData();
142+
const projectData = await parser.discoverVSCodeCopilotData();
143143

144-
if (workspaceData.chat_sessions.length === 0) {
144+
if (projectData.chat_sessions.length === 0) {
145145
spinner?.stop();
146146
displayError('discovery', 'No GitHub Copilot chat data found');
147147
displayWarning('Make sure VS Code is installed and you have used GitHub Copilot chat');
148148
process.exit(1);
149149
}
150150

151151
spinner?.stop();
152-
displaySuccess(`Found ${formatCount(workspaceData.chat_sessions.length)} chat sessions`);
152+
displaySuccess(`Found ${formatCount(projectData.chat_sessions.length)} chat sessions`);
153153

154154
// Show dry run information
155155
if (options.dryRun) {
156-
const stats = parser.getChatStatistics(workspaceData);
156+
const stats = parser.getChatStatistics(projectData);
157157
displayInfo('DRY RUN - No data will be imported');
158158
displayChatSummary(stats, [], options.verbose);
159159
return;
160160
}
161161

162162
// Convert AI package data to Core package format
163-
const convertedData = convertWorkspaceDataToCoreFormat(
164-
workspaceData as WorkspaceDataContainer,
165-
);
163+
const convertedData = convertProjectDataToCoreFormat(projectData as ProjectDataContainer);
166164

167165
// Validate the converted data
168166
if (!validateConvertedData(convertedData)) {
@@ -176,14 +174,14 @@ program
176174
sessions: convertedData.sessions,
177175
messages: convertedData.messages,
178176
source: options.source,
179-
workspaceInfo: extractWorkspaceInfo(workspaceData as WorkspaceDataContainer),
177+
projectInfo: extractProjectInfo(projectData as ProjectDataContainer),
180178
};
181179

182180
// Start import
183-
displayInfo(`Importing to workspace: ${workspaceId}`);
181+
displayInfo(`Importing to project: ${projectId}`);
184182
const progressSpinner = ora('Starting import...').start();
185183

186-
const importResponse = await apiClient.importChatData(workspaceId, importData);
184+
const importResponse = await apiClient.importChatData(projectId, importData);
187185

188186
progressSpinner.stop();
189187
displaySuccess(`Import started: ${importResponse.importId}`);
@@ -204,7 +202,7 @@ program
204202
await new Promise((resolve) => setTimeout(resolve, 1000));
205203

206204
const progressResponse = await apiClient.getImportProgress(
207-
workspaceId,
205+
projectId,
208206
importResponse.importId,
209207
);
210208
lastProgress = progressResponse.progress;
@@ -246,9 +244,9 @@ program
246244
try {
247245
const config = await loadConfig(options.config);
248246
const apiClient = await setupApiClient(options);
249-
const workspaceId = getWorkspaceId(options, config);
247+
const projectId = getProjectId(options, config);
250248

251-
const stats = await apiClient.getChatStats(workspaceId);
249+
const stats = await apiClient.getChatStats(projectId);
252250

253251
displayHeader('DevLog Chat Statistics');
254252

@@ -261,7 +259,7 @@ program
261259
['Total Sessions', stats.totalSessions?.toString() || '0'],
262260
['Total Messages', stats.totalMessages?.toString() || '0'],
263261
['Unique Agents', stats.uniqueAgents?.toString() || '0'],
264-
['Workspaces', stats.workspaceCount?.toString() || '0'],
262+
['Projects', stats.projectCount?.toString() || '0'],
265263
);
266264

267265
if (stats.dateRange?.earliest) {
@@ -294,9 +292,9 @@ program
294292
try {
295293
const config = await loadConfig(options.config);
296294
const apiClient = await setupApiClient(options);
297-
const workspaceId = getWorkspaceId(options, config);
295+
const projectId = getProjectId(options, config);
298296

299-
const searchResults = await apiClient.searchChatContent(workspaceId, query, {
297+
const searchResults = await apiClient.searchChatContent(projectId, query, {
300298
limit: parseInt(options.limit, 10),
301299
caseSensitive: options.caseSensitive,
302300
searchType: options.searchType,
@@ -327,80 +325,74 @@ program
327325
}),
328326
);
329327

330-
// Workspace management commands
328+
// Project management commands
331329
program
332-
.command('workspace')
333-
.description('Workspace management commands')
330+
.command('project')
331+
.description('Project management commands')
334332
.addCommand(
335333
new Command('list')
336-
.description('List available workspaces on server')
334+
.description('List available projects on server')
337335
.action(async (options: BaseCommandOptions) => {
338336
try {
339337
const apiClient = await setupApiClient(options);
340-
const workspaces = await apiClient.listWorkspaces();
338+
const projects = await apiClient.listProjects();
341339

342-
if (workspaces.length === 0) {
343-
console.log(chalk.yellow('No workspaces found'));
340+
if (projects.length === 0) {
341+
console.log(chalk.yellow('No projects found'));
344342
return;
345343
}
346344

347-
displayHeader('Available Workspaces');
345+
displayHeader('Available Projects');
348346

349347
const table = new Table({
350348
head: [chalk.cyan('ID'), chalk.cyan('Name'), chalk.cyan('Status')],
351349
colWidths: [20, 30, 15],
352350
});
353351

354-
for (const workspace of workspaces) {
352+
for (const project of projects) {
355353
table.push([
356-
workspace.id || 'N/A',
357-
workspace.name || 'Unnamed',
358-
workspace.status || 'active',
354+
project.id || 'N/A',
355+
project.name || 'Unnamed',
356+
project.status || 'active',
359357
]);
360358
}
361359

362360
console.log(table.toString());
363361
} catch (error) {
364-
displayError('listing workspaces', error);
362+
displayError('listing projects', error);
365363
process.exit(1);
366364
}
367365
}),
368366
)
369367
.addCommand(
370368
new Command('info')
371-
.description('Show workspace information')
369+
.description('Show project information')
372370
.action(async (options: BaseCommandOptions) => {
373371
try {
374372
const config = await loadConfig(options.config);
375373
const apiClient = await setupApiClient(options);
376-
const workspaceId = getWorkspaceId(options, config);
374+
const projectId = getProjectId(options, config);
377375

378-
const workspace = await apiClient.getWorkspace(workspaceId);
376+
const project = await apiClient.getProject(projectId);
379377

380-
displayHeader(`Workspace: ${workspace.name || workspaceId}`);
378+
displayHeader(`Project: ${project.name || projectId}`);
381379

382380
const table = new Table({
383381
head: [chalk.cyan('Property'), chalk.green('Value')],
384382
colWidths: [20, 50],
385383
});
386384

387385
table.push(
388-
['ID', workspace.id || 'N/A'],
389-
['Name', workspace.name || 'Unnamed'],
390-
['Status', workspace.status || 'active'],
391-
[
392-
'Created',
393-
workspace.createdAt ? new Date(workspace.createdAt).toLocaleString() : 'N/A',
394-
],
395-
[
396-
'Updated',
397-
workspace.updatedAt ? new Date(workspace.updatedAt).toLocaleString() : 'N/A',
398-
],
386+
['ID', project.id || 'N/A'],
387+
['Name', project.name || 'Unnamed'],
388+
['Status', project.status || 'active'],
389+
['Created', project.createdAt ? new Date(project.createdAt).toLocaleString() : 'N/A'],
390+
['Updated', project.updatedAt ? new Date(project.updatedAt).toLocaleString() : 'N/A'],
399391
);
400392

401393
console.log(table.toString());
402394
} catch (error) {
403-
displayError('getting workspace info', error);
395+
displayError('getting project info', error);
404396
process.exit(1);
405397
}
406398
}),

packages/mcp/src/config/mcp-config.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export interface MCPServerConfig {
77
/** Architecture mode: 'direct' uses core directly, 'api' uses HTTP client */
88
mode: 'direct' | 'api';
99
/** Default workspace ID */
10-
defaultWorkspaceId?: string;
10+
defaultProjectId?: string;
1111
/** Web API configuration (required for 'api' mode) */
1212
webApi?: {
1313
/** Base URL for the web API server */
@@ -35,11 +35,11 @@ export interface MCPServerConfig {
3535
*/
3636
export function loadMCPConfig(): MCPServerConfig {
3737
const mode = (process.env.MCP_MODE || 'direct') as 'direct' | 'api';
38-
const defaultWorkspaceId = process.env.MCP_DEFAULT_WORKSPACE || 'default';
38+
const defaultProjectId = process.env.MCP_DEFAULT_PROJECT || 'default';
3939

4040
const config: MCPServerConfig = {
4141
mode,
42-
defaultWorkspaceId,
42+
defaultProjectId,
4343
};
4444

4545
if (mode === 'api') {
@@ -101,7 +101,7 @@ export function validateMCPConfig(config: MCPServerConfig): void {
101101
export function printConfigSummary(config: MCPServerConfig): void {
102102
console.log('\n=== MCP Server Configuration ===');
103103
console.log(`Mode: ${config.mode}`);
104-
console.log(`Default Workspace: ${config.defaultWorkspaceId}`);
104+
console.log(`Default Project: ${config.defaultProjectId}`);
105105

106106
if (config.mode === 'api' && config.webApi) {
107107
console.log(`Web API URL: ${config.webApi.baseUrl}`);

0 commit comments

Comments
 (0)