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
16 changes: 8 additions & 8 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,56 +12,56 @@
"source": "./plugins/aidd-context",
"description": "Knowledge production: project bootstrap, project init, generation of context artifacts (skills, agents, rules, commands, hooks), mermaid diagrams, learn, discovery",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-dev",
"source": "./plugins/aidd-dev",
"description": "Code transformation: plan, implement, assert, audit, review, test, refactor, debug, for-sure. Hosts engineering agents.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-vcs",
"source": "./plugins/aidd-vcs",
"description": "External artifacts: commit, pull-request, release-tag, issue-create",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-pm",
"source": "./plugins/aidd-pm",
"description": "Product backlog artifacts, refinement, Product Briefs, Epics, User Stories, Tasks, Spikes, Defects, requirements, and specs.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-orchestrator",
"source": "./plugins/aidd-orchestrator",
"description": "Orchestration: synchronous SDLC pipeline, async issue-to-PR automation, and product backlog.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-refine",
"source": "./plugins/aidd-refine",
"description": "Meta-cognition: refine input through brainstorming, refine output through challenge, blind-spot scanning, and fact-checking.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-ui",
"source": "./plugins/aidd-ui",
"description": "ALPHA, not ready for use. UI and UX concern: design, review, and improve frontend interfaces.",
"strict": true,
"recommended": false
"metadata": { "recommended": false }
},
{
"name": "aidd-telemetry",
"source": "./plugins/aidd-telemetry",
"description": "Measurement: journals every session so a unit of work can be tied to what it cost. The hooks record on plain node; its three skills reach the `aidd` CLI to turn it on, answer and check.",
"strict": true,
"recommended": false
"metadata": { "recommended": false }
}
]
}
9 changes: 7 additions & 2 deletions cli/assets/schemas/claude-marketplace-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@
"strict": {
"type": "boolean"
},
"recommended": {
"type": "boolean"
"metadata": {
"type": "object",
"properties": {
"recommended": {
"type": "boolean"
}
}
}
}
}
Expand Down
8 changes: 7 additions & 1 deletion cli/src/contexts/distribution/domain/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function parseEntry(raw: unknown, index: number): PluginCatalogEntry {
const entry: PluginCatalogEntry = {
name: obj.name,
source,
recommended: typeof obj.recommended === "boolean" ? obj.recommended : false,
recommended: recommendedUnderMetadata(obj.metadata),
strict: typeof obj.strict === "boolean" ? obj.strict : false,
};

Expand All @@ -46,6 +46,12 @@ function parseEntry(raw: unknown, index: number): PluginCatalogEntry {
return entry;
}

function recommendedUnderMetadata(metadata: unknown): boolean {
if (metadata === null || typeof metadata !== "object") return false;
const { recommended } = metadata as Record<string, unknown>;
return typeof recommended === "boolean" ? recommended : false;
}

export function hasRelativePluginSources(catalog: PluginCatalog): boolean {
return catalog.plugins.some(
(entry) => entry.source.kind === "local" && !isAbsolute(entry.source.path)
Expand Down
2 changes: 1 addition & 1 deletion cli/src/contexts/tools/domain/build-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export interface SourcePluginEntryRef {
readonly version?: string;
readonly description?: string;
readonly strict?: boolean;
readonly recommended?: boolean;
readonly metadata?: { readonly recommended?: boolean };
readonly [key: string]: unknown;
}

Expand Down
14 changes: 12 additions & 2 deletions cli/src/contexts/tools/domain/marketplace-catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,12 @@ import type { FileWriter } from "../../../kernel/ports/file-writer.js";
import type { PluginPresence } from "./build-contract.js";

type SrcEntry =
| { version?: string; description?: string; strict?: boolean; recommended?: boolean }
| {
version?: string;
description?: string;
strict?: boolean;
metadata?: { recommended?: boolean };
}
| undefined;

/** Marketplace-mode agent transform shared by claude and copilot: the frontmatter is kept
Expand Down Expand Up @@ -91,7 +96,12 @@ export function buildClaudeStyleCatalogEntry(
version,
};
if (typeof srcEntry?.strict === "boolean") entry.strict = srcEntry.strict;
if (typeof srcEntry?.recommended === "boolean") entry.recommended = srcEntry.recommended;
const metadata = srcEntry?.metadata;
const recommended =
metadata !== null && typeof metadata === "object"
? (metadata as { recommended?: unknown }).recommended
: undefined;
if (typeof recommended === "boolean") entry.metadata = { recommended };
return entry;
}

Expand Down
12 changes: 10 additions & 2 deletions cli/tests/contexts/distribution/domain/catalog.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ const VALID_RAW = {
name: "dev",
source: { kind: "local", path: "./plugins/dev" },
description: "Dev plugin",
recommended: true,
metadata: { recommended: true },
strict: true,
},
{
name: "pm",
source: { kind: "github", repo: "ai-driven-dev/aidd-pm" },
description: "PM plugin",
recommended: false,
metadata: { recommended: false },
strict: false,
},
],
Expand Down Expand Up @@ -94,6 +94,14 @@ describe("parsePluginCatalog", () => {
expect(catalog.plugins[0].recommended).toBe(false);
});

it("reads recommended under the entry's metadata alone, the one place Claude Code does not warn on", () => {
const raw = {
plugins: [{ name: "x", source: { kind: "local", path: "./x" }, recommended: true }],
};
const catalog = parsePluginCatalog(raw);
expect(catalog.plugins[0].recommended).toBe(false);
});

it("defaults strict to false when absent", () => {
const raw = { plugins: [{ name: "x", source: { kind: "local", path: "./x" } }] };
const catalog = parsePluginCatalog(raw);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ describe("PluginSearchUseCase", () => {
it("filters by --recommended", async () => {
const fs = new InMemoryFileAdapter();
seedMarketplace(fs, MKT1_PATH, [
{ name: "a", source: { kind: "github", repo: "x/y" }, recommended: true },
{ name: "b", source: { kind: "github", repo: "x/y" }, recommended: false },
{ name: "a", source: { kind: "github", repo: "x/y" }, metadata: { recommended: true } },
{ name: "b", source: { kind: "github", repo: "x/y" }, metadata: { recommended: false } },
]);
const registry = new InMemoryMarketplaceRegistry();
await registry.save(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,19 +241,20 @@ describe("buildClaudeStyleCatalogEntry", () => {
expect(entry.version).toBe("1.0.0");
});

it("passes through strict and recommended when present", () => {
it("passes strict through, and recommended under metadata, where Claude Code does not warn", () => {
const entry = buildClaudeStyleCatalogEntry("aidd-dev", "desc", "1.0.0", {
strict: true,
recommended: false,
metadata: { recommended: false },
});
expect(entry.strict).toBe(true);
expect(entry.recommended).toBe(false);
expect(entry.metadata).toStrictEqual({ recommended: false });
expect(entry).not.toHaveProperty("recommended");
});

it("omits strict and recommended when absent", () => {
it("omits strict and metadata when absent", () => {
const entry = buildClaudeStyleCatalogEntry("aidd-dev", "desc", "1.0.0", undefined);
expect(entry.strict).toBeUndefined();
expect(entry.recommended).toBeUndefined();
expect(entry.metadata).toBeUndefined();
});

it("only includes strict when it is boolean (not string/number)", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe("claude-marketplace-manifest.json schema", () => {
description: "Dev plugin",
version: "1.0.0",
strict: true,
recommended: true,
metadata: { recommended: true },
},
],
})
Expand Down
2 changes: 1 addition & 1 deletion cli/tests/e2e/plugin-install.e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ describe.concurrent("E2E: aidd plugin marketplace", () => {
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
description: "Sample",
recommended: true,
metadata: { recommended: true },
},
]);
await runCli(["marketplace", "add", "local", marketDir, "--yes"], projectDir, fakeHome);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"source": "./plugins/aidd-codex-fixture",
"description": "Fixture plugin for codex build target tests",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,47 @@
"source": "./plugins/aidd-context",
"description": "Knowledge production: project bootstrap, project init, context generation, mermaid diagrams, learn, discovery",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-dev",
"version": "1.0.0",
"source": "./plugins/aidd-dev",
"description": "Code transformation: SDLC orchestrator, plan, assert, audit, review, test, refactor, debug, for-sure. Hosts agents.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-vcs",
"version": "1.0.0",
"source": "./plugins/aidd-vcs",
"description": "External artifacts: commit, pull-request, release-tag, issue-create",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-pm",
"version": "1.0.0-rc.1",
"source": "./plugins/aidd-pm",
"description": "Product management (release candidate): ticket-info, user-stories-create, prd",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
},
{
"name": "aidd-async-dev",
"version": "1.0.0",
"source": "./plugins/aidd-async-dev",
"description": "Async development orchestration: turn ready issues into pull requests, then iterate on review feedback until a human takes over.",
"strict": true,
"recommended": false
"metadata": { "recommended": false }
},
{
"name": "aidd-refine",
"version": "1.0.0",
"source": "./plugins/aidd-refine",
"description": "Meta-cognition: refine input through brainstorming, refine output through challenge and condensed communication mode.",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"source": "./plugins/aidd-test",
"description": "Test plugin",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"source": "./plugins/aidd-test",
"description": "Test plugin",
"strict": true,
"recommended": true
"metadata": { "recommended": true }
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"name": "dev",
"source": { "kind": "local", "path": "./plugins/dev" },
"description": "Dev plugin",
"recommended": true,
"metadata": { "recommended": true },
"strict": true
},
{
"name": "pm",
"source": { "kind": "github", "repo": "ai-driven-dev/aidd-pm" },
"description": "PM plugin",
"recommended": false,
"metadata": { "recommended": false },
"strict": false
}
]
Expand Down
4 changes: 2 additions & 2 deletions cli/tests/golden/snapshots/framework-build/golden.json
Original file line number Diff line number Diff line change
Expand Up @@ -597,7 +597,7 @@
"plugins/aidd-async-dev/hooks/hooks.json": "78922a784ee78e9e50587e93628cd3b9d4dfbe49087adc4514e6781cea38cbb9",
"plugins/aidd-async-dev/agents/async-orchestrator.md": "8b29ba73f27414e75c89c6453c0557212790d00d6becfadba363466999f2c9de",
"plugins/aidd-async-dev/.claude-plugin/plugin.json": "04cce92dc7c10e8041807220c255005c0510abbbb0322176f2a8a254808e4466",
".claude-plugin/marketplace.json": "d660f4eb03d90f2b2384c9ff61626d6ded7ede5664816681991ddebe622e099f"
".claude-plugin/marketplace.json": "d197f330a5787647d58c7dc20253c8ef8b59c4dce115fdd7f12de45ccec7b18e"
},
"cursor": {
"plugins/aidd-vcs/skills/04-issue-create/SKILL.md": "41fb7f904c88a07eb3ab94c6137c130166fa44069ed76322fc6eb78b81a7b5a4",
Expand Down Expand Up @@ -797,7 +797,7 @@
"plugins/aidd-async-dev/hooks/hooks.json": "78922a784ee78e9e50587e93628cd3b9d4dfbe49087adc4514e6781cea38cbb9",
"plugins/aidd-async-dev/agents/async-orchestrator.md": "8b29ba73f27414e75c89c6453c0557212790d00d6becfadba363466999f2c9de",
"plugins/aidd-async-dev/.cursor-plugin/plugin.json": "8d9b5b5edc8ac5d51cdb24bc5605b30ed3149616bfbbcc69db45f35d477315d5",
".cursor-plugin/marketplace.json": "d660f4eb03d90f2b2384c9ff61626d6ded7ede5664816681991ddebe622e099f"
".cursor-plugin/marketplace.json": "d197f330a5787647d58c7dc20253c8ef8b59c4dce115fdd7f12de45ccec7b18e"
},
"claude:flat": {
".mcp.json": "1bbb467a5d737b5c65daf9fe8551c9ced50608a09f523d5d20baa9150f266f73",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ describe("PluginPickUseCase", () => {
name: "sample-plugin",
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
recommended: true,
metadata: { recommended: true },
},
]);
await registry.save(
Expand Down Expand Up @@ -170,7 +170,7 @@ describe("PluginPickUseCase", () => {
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
description: "A sample plugin used in tests",
recommended: true,
metadata: { recommended: true },
strict: true,
},
]);
Expand Down Expand Up @@ -246,7 +246,7 @@ describe("PluginPickUseCase β€” what it asks, and when it asks nothing", () => {
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
description: "A sample plugin used in tests",
recommended: true,
metadata: { recommended: true },
},
{ name: "bare-plugin", source: { kind: "local", path: PLUGIN_FIXTURE }, version: "1.0.0" },
]);
Expand Down Expand Up @@ -274,7 +274,7 @@ describe("PluginPickUseCase β€” what it hands the installer", () => {
name: "sample-plugin",
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
recommended: true,
metadata: { recommended: true },
strict: true,
},
]);
Expand Down Expand Up @@ -304,7 +304,7 @@ describe("PluginPickUseCase β€” what it hands the installer", () => {
name: "sample-plugin",
source: { kind: "local", path: PLUGIN_FIXTURE },
version: "1.0.0",
recommended: true,
metadata: { recommended: true },
},
]);
await registerMarketplace(registry, "local", MKT_DIR);
Expand Down
2 changes: 1 addition & 1 deletion docs/CREATE_PLUGIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Pick a name (lowercase, `aidd-<x>`). For the directory shape, `plugin.json`, and

## πŸ“ Register

- **Marketplace** β€” append an entry to `.claude-plugin/marketplace.json`: `name`, `source` (required, `./plugins/aidd-<x>`), `strict: true`, `recommended: false` (keeps it off the curated install path until it stabilises).
- **Marketplace** β€” append an entry to `.claude-plugin/marketplace.json`: `name`, `source` (required, `./plugins/aidd-<x>`), `strict: true`, `metadata: { "recommended": false }` (keeps it off the curated install path until it stabilises; under `metadata` because Claude Code warns on any other field of its own).
- **Release** β€” add the package to `release-please-config.json` `packages` **and** `.release-please-manifest.json`, or it never versions.

## πŸ§ͺ Try locally
Expand Down
Loading