feat: simplify code project creation
This commit is contained in:
@@ -211,21 +211,7 @@ export class CodingProjectService {
|
||||
);
|
||||
}
|
||||
}
|
||||
const config = await this.readCurrentConfig(projectPath);
|
||||
if (!config) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_CONFIG_INVALID',
|
||||
'Coding project configuration is unavailable',
|
||||
);
|
||||
}
|
||||
if (!config.projectId) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_IDENTITY_REQUIRED',
|
||||
'A durable coding project identity is required',
|
||||
);
|
||||
}
|
||||
const config = (await this.getConfig(project.id)).config;
|
||||
return { project, path: projectPath, projectId: config.projectId };
|
||||
}
|
||||
|
||||
@@ -335,19 +321,10 @@ export class CodingProjectService {
|
||||
|
||||
async getConfig(projectId?: string): Promise<CodingProjectConfigSnapshot> {
|
||||
const project = projectId ? await this.getProject(projectId) : await this.requireActiveProject();
|
||||
const config = await this.readCurrentConfig(project.path);
|
||||
if (!config) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_CONFIG_INVALID',
|
||||
'Coding project configuration is unavailable',
|
||||
);
|
||||
}
|
||||
return {
|
||||
project,
|
||||
config,
|
||||
knowledgeFiles: await this.listKnowledgeFiles(project.path),
|
||||
};
|
||||
const config = await this.requireCurrentConfig(project);
|
||||
return config.projectId
|
||||
? await this.projectConfigSnapshot(project, config)
|
||||
: await this.ensureProjectIdentity(project);
|
||||
}
|
||||
|
||||
async saveConfig(projectId: string, value: unknown): Promise<CodingProjectConfigSnapshot> {
|
||||
@@ -379,8 +356,8 @@ export class CodingProjectService {
|
||||
): Promise<CodingProjectConfigSnapshot> {
|
||||
const project = await this.getProject(localProjectId);
|
||||
return await this.serializeIdentityTransition(project.path, async () => {
|
||||
const current = await this.getConfig(project.id);
|
||||
if (current.config.projectId !== undefined) {
|
||||
const current = await this.requireCurrentConfig(project);
|
||||
if (current.projectId !== undefined) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_IDENTITY_IMMUTABLE',
|
||||
@@ -397,7 +374,7 @@ export class CodingProjectService {
|
||||
nextProjectId,
|
||||
);
|
||||
const next = {
|
||||
...current.config,
|
||||
...current,
|
||||
projectId: nextProjectId,
|
||||
updatedAt: this.options.now?.() ?? new Date().toISOString(),
|
||||
};
|
||||
@@ -407,11 +384,7 @@ export class CodingProjectService {
|
||||
storageFailure(error);
|
||||
}
|
||||
await this.options.onResourcesChanged?.(project);
|
||||
return {
|
||||
project: current.project,
|
||||
config: next,
|
||||
knowledgeFiles: await this.listKnowledgeFiles(current.project.path),
|
||||
};
|
||||
return await this.projectConfigSnapshot(project, next);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -428,8 +401,8 @@ export class CodingProjectService {
|
||||
}
|
||||
const project = await this.getProject(localProjectId);
|
||||
return await this.serializeIdentityTransition(project.path, async () => {
|
||||
const current = await this.getConfig(project.id);
|
||||
if (current.config.projectId === undefined) {
|
||||
const current = await this.requireCurrentConfig(project);
|
||||
if (current.projectId === undefined) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_IDENTITY_REQUIRED',
|
||||
@@ -442,11 +415,11 @@ export class CodingProjectService {
|
||||
);
|
||||
await this.options.onProjectIdentityChanging?.(
|
||||
project,
|
||||
current.config.projectId,
|
||||
current.projectId,
|
||||
nextProjectId,
|
||||
);
|
||||
const next = {
|
||||
...current.config,
|
||||
...current,
|
||||
projectId: nextProjectId,
|
||||
updatedAt: this.options.now?.() ?? new Date().toISOString(),
|
||||
};
|
||||
@@ -456,11 +429,7 @@ export class CodingProjectService {
|
||||
storageFailure(error);
|
||||
}
|
||||
await this.options.onResourcesChanged?.(project);
|
||||
return {
|
||||
project: current.project,
|
||||
config: next,
|
||||
knowledgeFiles: await this.listKnowledgeFiles(current.project.path),
|
||||
};
|
||||
return await this.projectConfigSnapshot(project, next);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -540,6 +509,61 @@ export class CodingProjectService {
|
||||
});
|
||||
}
|
||||
|
||||
private async ensureProjectIdentity(
|
||||
project: CodingProject,
|
||||
): Promise<CodingProjectConfigSnapshot> {
|
||||
return await this.serializeIdentityTransition(project.path, async () => {
|
||||
const current = await this.requireCurrentConfig(project);
|
||||
if (current.projectId) {
|
||||
return await this.projectConfigSnapshot(project, current);
|
||||
}
|
||||
const nextProjectId = resolveProjectIdentity(
|
||||
{ kind: 'create' },
|
||||
this.options.createProjectId ?? randomUUID,
|
||||
);
|
||||
await this.options.onProjectIdentityChanging?.(
|
||||
project,
|
||||
undefined,
|
||||
nextProjectId,
|
||||
);
|
||||
const next = {
|
||||
...current,
|
||||
projectId: nextProjectId,
|
||||
updatedAt: this.options.now?.() ?? new Date().toISOString(),
|
||||
};
|
||||
try {
|
||||
await (this.options.writeConfig ?? writeCodingProjectConfigV2)(project.path, next);
|
||||
} catch (error) {
|
||||
storageFailure(error);
|
||||
}
|
||||
await this.options.onResourcesChanged?.(project);
|
||||
return await this.projectConfigSnapshot(project, next);
|
||||
});
|
||||
}
|
||||
|
||||
private async requireCurrentConfig(project: CodingProject): Promise<CodingProjectConfigV2> {
|
||||
const config = await this.readCurrentConfig(project.path);
|
||||
if (!config) {
|
||||
throw new CodingProjectServiceError(
|
||||
409,
|
||||
'CODING_PROJECT_CONFIG_INVALID',
|
||||
'Coding project configuration is unavailable',
|
||||
);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
private async projectConfigSnapshot(
|
||||
project: CodingProject,
|
||||
config: CodingProjectConfigV2,
|
||||
): Promise<CodingProjectConfigSnapshot> {
|
||||
return {
|
||||
project,
|
||||
config,
|
||||
knowledgeFiles: await this.listKnowledgeFiles(project.path),
|
||||
};
|
||||
}
|
||||
|
||||
private async listKnowledgeFiles(projectPath: string): Promise<string[]> {
|
||||
try {
|
||||
const entries = await readdir(path.join(projectPath, 'knowledge'), { withFileTypes: true });
|
||||
|
||||
Reference in New Issue
Block a user