diff --git a/packages/cli/src/commands/conventions.integration.spec.ts b/packages/cli/src/commands/conventions.integration.spec.ts index 4e44325..ab7faa2 100644 --- a/packages/cli/src/commands/conventions.integration.spec.ts +++ b/packages/cli/src/commands/conventions.integration.spec.ts @@ -134,7 +134,7 @@ describe("architecture and practices facets integration", () => { // Facet order: process (select), architecture (select), practices (multiselect) vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture: skip + .mockResolvedValueOnce("other"); // architecture: other vi.mocked(clack.multiselect) .mockResolvedValueOnce(["conventional-commits", "tdd-london"]) // practices .mockResolvedValueOnce(["claude-code"]); // harnesses @@ -182,7 +182,7 @@ describe("architecture and practices facets integration", () => { // Facet order: process (select), architecture (select), practices (multiselect) vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture: skip + .mockResolvedValueOnce("other"); // architecture: other vi.mocked(clack.multiselect) .mockResolvedValueOnce(["adr-nygard"]) .mockResolvedValueOnce(["claude-code"]); // harnesses @@ -199,13 +199,13 @@ describe("architecture and practices facets integration", () => { expect(adr).toContain("## Consequences"); }); - it("skips both architecture and practices when none selected", async () => { + it("writes no .ade directory when architecture is other and no practices selected", async () => { const catalog = getDefaultCatalog(); // Facet order: process (select), architecture (select), practices (multiselect) vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture: skip + .mockResolvedValueOnce("other"); // architecture: other vi.mocked(clack.multiselect) .mockResolvedValueOnce([]) // practices: none .mockResolvedValueOnce(["claude-code"]); // harnesses @@ -215,9 +215,9 @@ describe("architecture and practices facets integration", () => { // No .ade directory should exist await expect(access(join(dir, ".ade"))).rejects.toThrow(); - // config.yaml should not have architecture or practices keys + // config.yaml should have architecture: "other" but no practices key const config = await readUserConfig(dir); - expect(config!.choices).not.toHaveProperty("architecture"); + expect(config!.choices).toHaveProperty("architecture", "other"); expect(config!.choices).not.toHaveProperty("practices"); }); @@ -227,7 +227,7 @@ describe("architecture and practices facets integration", () => { // Facet order: process (select), architecture (select), practices (multiselect) vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture: skip + .mockResolvedValueOnce("other"); // architecture: other vi.mocked(clack.multiselect) .mockResolvedValueOnce(["tdd-london"]) .mockResolvedValueOnce(["claude-code"]); // harnesses diff --git a/packages/cli/src/commands/install.integration.spec.ts b/packages/cli/src/commands/install.integration.spec.ts index c56d0da..c8c3579 100644 --- a/packages/cli/src/commands/install.integration.spec.ts +++ b/packages/cli/src/commands/install.integration.spec.ts @@ -46,7 +46,7 @@ describe("install integration (real temp dir)", () => { // Step 1: Run setup to create config.yaml + config.lock.yaml vi.mocked(clack.select) .mockResolvedValueOnce("codemcp-workflows") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); @@ -73,7 +73,7 @@ describe("install integration (real temp dir)", () => { // Setup first vi.mocked(clack.select) .mockResolvedValueOnce("codemcp-workflows") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); @@ -102,7 +102,7 @@ describe("install integration (real temp dir)", () => { // Setup with native-agents-md vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); diff --git a/packages/cli/src/commands/knowledge.integration.spec.ts b/packages/cli/src/commands/knowledge.integration.spec.ts index e36a9aa..1ec7b49 100644 --- a/packages/cli/src/commands/knowledge.integration.spec.ts +++ b/packages/cli/src/commands/knowledge.integration.spec.ts @@ -95,7 +95,7 @@ describe("knowledge integration", () => { vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture: skip + .mockResolvedValueOnce("other"); // architecture: other vi.mocked(clack.multiselect).mockResolvedValueOnce(["tdd-london"]); // practices: tdd-london has no docsets await runSetup(dir, catalog); diff --git a/packages/cli/src/commands/setup.integration.spec.ts b/packages/cli/src/commands/setup.integration.spec.ts index f381f14..0c9011c 100644 --- a/packages/cli/src/commands/setup.integration.spec.ts +++ b/packages/cli/src/commands/setup.integration.spec.ts @@ -45,7 +45,7 @@ describe("setup integration (real temp dir)", () => { vi.mocked(clack.select) .mockResolvedValueOnce("codemcp-workflows") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); @@ -53,7 +53,10 @@ describe("setup integration (real temp dir)", () => { // ── config.yaml ────────────────────────────────────────────────────── const config = await readUserConfig(dir); expect(config).not.toBeNull(); - expect(config!.choices).toEqual({ process: "codemcp-workflows" }); + expect(config!.choices).toEqual({ + process: "codemcp-workflows", + architecture: "other" + }); // harnesses must NOT be in config.yaml — setup no longer selects them expect(config).not.toHaveProperty("harnesses"); @@ -61,7 +64,10 @@ describe("setup integration (real temp dir)", () => { const lock = await readLockFile(dir); expect(lock).not.toBeNull(); expect(lock!.version).toBe(1); - expect(lock!.choices).toEqual({ process: "codemcp-workflows" }); + expect(lock!.choices).toEqual({ + process: "codemcp-workflows", + architecture: "other" + }); expect(lock!.generated_at).toBeTruthy(); // harnesses must NOT be in the lock file expect(lock).not.toHaveProperty("harnesses"); @@ -78,16 +84,22 @@ describe("setup integration (real temp dir)", () => { vi.mocked(clack.select) .mockResolvedValueOnce("native-agents-md") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); const config = await readUserConfig(dir); - expect(config!.choices).toEqual({ process: "native-agents-md" }); + expect(config!.choices).toEqual({ + process: "native-agents-md", + architecture: "other" + }); const lock = await readLockFile(dir); - expect(lock!.choices).toEqual({ process: "native-agents-md" }); + expect(lock!.choices).toEqual({ + process: "native-agents-md", + architecture: "other" + }); expect(lock!.logical_config.instructions.length).toBeGreaterThan(0); }); @@ -112,7 +124,7 @@ describe("setup integration (real temp dir)", () => { vi.mocked(clack.select) .mockResolvedValueOnce("codemcp-workflows") // process - .mockResolvedValueOnce("__skip__"); // architecture + .mockResolvedValueOnce("other"); // architecture vi.mocked(clack.multiselect).mockResolvedValueOnce([]); // practices: none await runSetup(dir, catalog); diff --git a/packages/cli/src/commands/setup.ts b/packages/cli/src/commands/setup.ts index 0ab1ffa..ded77cf 100644 --- a/packages/cli/src/commands/setup.ts +++ b/packages/cli/src/commands/setup.ts @@ -194,7 +194,7 @@ function promptSelect( hint: o.description })); - if (!facet.required) { + if (!facet.required && !facet.options.some((o) => o.id === "other")) { options.push({ value: "__skip__", label: "Skip", hint: "" }); } diff --git a/packages/core/src/catalog/facets/architecture.ts b/packages/core/src/catalog/facets/architecture.ts index f1647b6..2b5149f 100644 --- a/packages/core/src/catalog/facets/architecture.ts +++ b/packages/core/src/catalog/facets/architecture.ts @@ -464,6 +464,13 @@ export const architectureFacet: Facet = { } } ] + }, + { + id: "other", + label: "Other", + description: + "Custom or unlisted architecture — no conventions will be applied", + recipe: [] } ] };