Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/core/project/manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ async function runCreate(
while (true) {
const next = await iterator.next();
if (next.done) {
return { events, project: next.value as Project };
return { events, project: next.value };
}
events.push(next.value);
}
Expand Down
18 changes: 11 additions & 7 deletions src/core/project/manager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class FsProjectManager implements ProjectManager {
}
}

public async *create(input: CreateProjectInput): AsyncGenerator<ProjectEvent> {
public async *create(input: CreateProjectInput): AsyncGenerator<ProjectEvent, Project> {
// Scaffold into a fresh directory, refusing to nest inside an existing project.
const enclosing = enclosingProjectRoot(process.cwd());
if (enclosing) {
Expand Down Expand Up @@ -106,12 +106,16 @@ export class FsProjectManager implements ProjectManager {
await this.run(["git", "init"], destination);
}

// Return the same shape resolve() would: a created project is a resolvable one.
return {
name: input.name,
rootPath: destination,
runtimes: TEMPLATES[input.template].spec.runtimes ?? [],
};
// A created project is a resolvable one, so read it back rather than
// duplicating the template's shape: the returned runtimes are then
// schema-validated instead of the template's loosely-typed spec sections.
const project = await this.resolve({ filePath: destination });
if (!project) {
throw new ProjectStateError(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OOS here but ProjectStateError feels pretty vague to me. What do you think of replacing it with something like ProjectValidationError for when reading a project fails?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh yes that makes sense, I will make a note and have it out as a followup!

`the project scaffolded at ${destination} could not be read back`,
);
}
return project;
}

// Runs a command with its output streamed to the file logger.
Expand Down
4 changes: 1 addition & 3 deletions src/handlers/project/create/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ export const createCreateProjectHandler = (config: CreateProjectHandlerConfig) =
skipInstall: flags["skip-install"],
skipGit: flags["skip-git"],
})) {
if (event.message) {
config.io.stderr.write(`${event.message}\n`);
}
config.io.stderr.write(`${event.message}\n`);
}

config.io.stderr.write(`Created project '${flags["name"]}' in ./${flags["name"]}\n`);
Expand Down
7 changes: 3 additions & 4 deletions src/handlers/project/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ export type CreateProjectInput = {
skipGit?: boolean;
};

/** A progress step reported while a long-running project operation runs. */
export type ProjectEvent = {
message?: string;
subprocessOutput?: string;
project?: Project;
message: string;
};

export type ResolveProjectInput = {
Expand All @@ -46,7 +45,7 @@ export type Project = {
*/
export interface ProjectManager {
/** Scaffold a new AgentCore project from the given template. */
create(input: CreateProjectInput): AsyncGenerator<ProjectEvent>;
create(input: CreateProjectInput): AsyncGenerator<ProjectEvent, Project>;

/** Locate an existing AgentCore project. Returns undefined if no project can be found. */
resolve(input: ResolveProjectInput): Promise<Project | undefined>;
Expand Down
Loading