From 393275332ffcab8b8769bf0453787b86e92bf18b Mon Sep 17 00:00:00 2001 From: Tejas Kashinath Date: Fri, 17 Jul 2026 17:20:14 -0400 Subject: [PATCH 1/3] feat(project): scaffold `agentcore project create` with --template flag Nest project-centric commands under a new `project` router (per the CLI project-commands re-org). Adds the `create` leaf as a stub that throws "not implemented" and a `--template` enum flag seeded with a placeholder value. Behavior, flags, and the template set land in follow-ups. --- src/handlers/index.tsx | 2 ++ src/handlers/project/create/index.ts | 20 +++++++++++++++++++ src/handlers/project/index.ts | 10 ++++++++++ src/handlers/project/project.test.ts | 30 ++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) create mode 100644 src/handlers/project/create/index.ts create mode 100644 src/handlers/project/index.ts create mode 100644 src/handlers/project/project.test.ts diff --git a/src/handlers/index.tsx b/src/handlers/index.tsx index 1fd52e1b3..5820179cb 100644 --- a/src/handlers/index.tsx +++ b/src/handlers/index.tsx @@ -2,6 +2,7 @@ import { Router } from "../router"; import { createHarnessHandler } from "./harness/index.tsx"; import { DebugKey, EndpointKey, JsonKey, RegionKey } from "./keys.tsx"; import { createConfigHandler } from "./config/"; +import { createProjectHandler } from "./project/index.ts"; import { renderTui } from "../tui"; import { withRegion, withJsonRenderer, withLogging } from "../middleware"; import type { AppIO, Core } from "./types.tsx"; @@ -33,6 +34,7 @@ export function createRootHandler(core: Core, config: RootHandlerConfig): Router // Install sub handlers root.handler(createHarnessHandler(core, io)); root.handler(createConfigHandler(io)); + root.handler(createProjectHandler()); // Invoking with no subcommand launches the interactive TUI. root.default(renderTui(core, io)); diff --git a/src/handlers/project/create/index.ts b/src/handlers/project/create/index.ts new file mode 100644 index 000000000..63e8c375c --- /dev/null +++ b/src/handlers/project/create/index.ts @@ -0,0 +1,20 @@ +import z from "zod"; +import { createHandler, flag } from "../../../router"; + +export const PROJECT_TEMPLATES = ["placeholder"] as const; + +export const createCreateProjectHandler = () => + createHandler({ + name: "create", + description: "create a new AgentCore project", + flags: [ + flag( + "template", + "project template to scaffold from", + z.enum(PROJECT_TEMPLATES).default("placeholder"), + ), + ], + handle: async () => { + throw new Error("`agentcore project create` is not implemented yet"); + }, + }); diff --git a/src/handlers/project/index.ts b/src/handlers/project/index.ts new file mode 100644 index 000000000..fdeb5b343 --- /dev/null +++ b/src/handlers/project/index.ts @@ -0,0 +1,10 @@ +import { Router } from "../../router"; +import { createCreateProjectHandler } from "./create"; + +export function createProjectHandler(): Router { + const project = new Router("project", "manage an AgentCore project"); + + project.handler(createCreateProjectHandler()); + + return project; +} diff --git a/src/handlers/project/project.test.ts b/src/handlers/project/project.test.ts new file mode 100644 index 000000000..ec010bf7f --- /dev/null +++ b/src/handlers/project/project.test.ts @@ -0,0 +1,30 @@ +import { test, expect, describe } from "bun:test"; +import { createRootHandler } from "../index"; +import { createSilentLogger, TestCoreClient, testIO } from "../../testing"; + +// End-to-end tests for the `project` command, driven through the real root +// handler and top-level route(). A TestCoreClient stands in for Core (the +// scaffold doesn't touch it, but createRootHandler requires one). + +async function run(args: string[]): Promise { + const io = testIO(); + const root = createRootHandler(new TestCoreClient(), { + io: io.io, + logger: createSilentLogger(), + }); + await root.route(["node", "agentcore", "project", ...args]); +} + +describe("project create", () => { + test("throws because it is not implemented yet", async () => { + await expect(run(["create"])).rejects.toThrow(/not implemented/); + }); + + test("accepts a known --template value", async () => { + await expect(run(["create", "--template", "placeholder"])).rejects.toThrow(/not implemented/); + }); + + test("rejects an unknown --template value", async () => { + await expect(run(["create", "--template", "nonsense"])).rejects.toThrow(); + }); +}); From d05bb33e2a1c50a2dc110dace8f7aaf5bfd21f45 Mon Sep 17 00:00:00 2001 From: Tejas Kashinath Date: Fri, 17 Jul 2026 17:24:01 -0400 Subject: [PATCH 2/3] test(project): update root command-tree assertion for new project subcommand --- src/handlers/root.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handlers/root.test.tsx b/src/handlers/root.test.tsx index 16b185a12..221c1daad 100644 --- a/src/handlers/root.test.tsx +++ b/src/handlers/root.test.tsx @@ -9,6 +9,6 @@ describe("createRootHandler", () => { logger: createSilentLogger(), }); expect(root.name()).toBe("agentcore"); - expect(root.children().map((c) => c.name())).toEqual(["harness", "config"]); + expect(root.children().map((c) => c.name())).toEqual(["harness", "config", "project"]); }); }); From 2b055fe76fd708bcc93e8bc2abcf062b009b64b3 Mon Sep 17 00:00:00 2001 From: Tejas Kashinath <42380254+tejaskash@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:24:39 -0400 Subject: [PATCH 3/3] Clean up comments in project.test.ts Removed comments explaining the purpose of the tests. --- src/handlers/project/project.test.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/handlers/project/project.test.ts b/src/handlers/project/project.test.ts index ec010bf7f..6c2922920 100644 --- a/src/handlers/project/project.test.ts +++ b/src/handlers/project/project.test.ts @@ -2,10 +2,6 @@ import { test, expect, describe } from "bun:test"; import { createRootHandler } from "../index"; import { createSilentLogger, TestCoreClient, testIO } from "../../testing"; -// End-to-end tests for the `project` command, driven through the real root -// handler and top-level route(). A TestCoreClient stands in for Core (the -// scaffold doesn't touch it, but createRootHandler requires one). - async function run(args: string[]): Promise { const io = testIO(); const root = createRootHandler(new TestCoreClient(), {