Skip to content

AINATIVEM-47 AI plugin layer — CLI subcommands and Claude Code plugin#9

Merged
dmitriyeff merged 1 commit into
masterfrom
AINATIVEM-47
May 15, 2026
Merged

AINATIVEM-47 AI plugin layer — CLI subcommands and Claude Code plugin#9
dmitriyeff merged 1 commit into
masterfrom
AINATIVEM-47

Conversation

@dmitriyeff
Copy link
Copy Markdown
Contributor

@dmitriyeff dmitriyeff commented May 14, 2026

Summary

  • Remove outdated backend options (Fastify, PHP) and webhooks references from CLAUDE.md
  • Add CLI subcommands section documenting add-app-extension subcommand
  • Correct module paths and generator flow to match actual implementation
  • Update AI plugin layer section with skill table and shipping details, covering both Claude Code and Codex marketplace plugins
  • Update README plugin installation instructions for Claude Code and Codex
  • Refactor NodeProjectBuilder to accept Partial<GeneratorOptions>, removing hardcoded dummy values from subcommands
  • Remove add-oauth subcommand and pipedrive-add-oauth skill — OAuth is always included in every scaffold, making the addon redundant
  • Fix docker-compose template in add-app-extension skill to match actual generated output
  • Fix stale src/pipedrive-client/ path references in pipedrive-api skill (now src/pipedrive/)
  • Replace rg with grep in Codex marketplace readiness reference

Test plan

Automated

npm run typecheck
npm test

CLI subcommands

npm run build

# Generate a test app first
npm run generate

# Add a custom panel to the generated test app
node dist/cli.js add-app-extension --output-dir apps/test-app --app-extensions custom-panel

# Add a custom modal
node dist/cli.js add-app-extension --output-dir apps/test-app --app-extensions custom-modal

# Verify files were created
ls apps/test-app/src/app-extensions/
ls apps/test-app/frontend/app-extension-ui/

# Error case — no package.json
node dist/cli.js add-app-extension --output-dir /tmp/no-project --app-extensions custom-panel

Install and test the Claude Code plugin locally

Once the repo is public, install via GitHub:

# CLI
claude plugin marketplace add pipedrive/create-pipedrive-app
claude plugin install create-pipedrive-app@pipedrive

# Or inside Claude Code
/plugin marketplace add pipedrive/create-pipedrive-app
/plugin install create-pipedrive-app@pipedrive
/reload-plugins

Before the repo is public, install from a local path:

/plugin marketplace add /path/to/create-pipedrive-app
/plugin install create-pipedrive-app@pipedrive
/reload-plugins

Then test the skills from any project directory:

/pipedrive-new-app
/pipedrive-add-app-extension
/pipedrive-api
/pipedrive-review-marketplace-readiness
Screenshot 2026-05-15 at 11 19 09

Install and test the Codex plugin locally

codex plugin install /path/to/create-pipedrive-app/plugins/create-pipedrive-app

Copilot AI review requested due to automatic review settings May 14, 2026 13:10
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an "AI plugin layer" on top of the existing scaffolder: two new CLI subcommands (add-oauth, add-app-extension) that re-run individual generators against an existing project, plus a Claude Code plugin (plugin/) bundling five slash-command skills that drive the CLI and provide guidance. The npm files whitelist is widened so plugin/ and dist/ ship with the package.

Changes:

  • New dispatchSubcommand in cli.ts plus src/subcommands/{addOAuth,addAppExtension}.ts (and tests) that wrap NodeProjectBuilder with a package.json precondition check.
  • New Claude Code plugin manifest and five SKILL.md files under plugin/skills/.
  • package.json gains a files whitelist including dist and plugin.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
src/cli.ts Adds dispatchSubcommand argv parser and top-level try/catch around it.
src/cli.test.ts Tests for dispatchSubcommand happy paths.
src/subcommands/addOAuth.ts Wraps NodeProjectBuilder.addOAuth().build() with a package.json check.
src/subcommands/addOAuth.test.ts Tests target dir output and missing-package.json error.
src/subcommands/addAppExtension.ts Same pattern for app extensions, with optional interactive prompt fallback.
src/subcommands/addAppExtension.test.ts Verifies panel/modal generation and precondition.
plugin/.claude-plugin/plugin.json Plugin manifest (name, description, version, author).
plugin/skills/pipedrive-new-app/SKILL.md Skill that just runs npx create-pipedrive-app.
plugin/skills/pipedrive-add-oauth/SKILL.md Skill that runs add-oauth and edits app.ts / .env.example.
plugin/skills/pipedrive-add-app-extension/SKILL.md Skill that runs add-app-extension and wires routers/Vite.
plugin/skills/pipedrive-review-marketplace-readiness/SKILL.md Skill that audits a project against marketplace-checklist.md.
plugin/skills/pipedrive-api/SKILL.md Reference doc on Pipedrive API usage from generated client.
package.json Adds files: ["dist", "plugin"] so the plugin ships with npm.
Comments suppressed due to low confidence (2)

src/subcommands/addOAuth.ts:12

  • Hard-coding database: 'postgres' and projectName: '' here is brittle. It happens to work today because generateOauth ignores those fields, but if the OAuth template ever starts to depend on the chosen database (for example, to import a database-specific token repository) this subcommand will silently produce wrong code in projects scaffolded with mysql or sqlite. Consider either reading the existing project's options (e.g. from a marker file) or making the builder API explicit about which options are required for addOAuth().
	await new NodeProjectBuilder(resolved, { projectName: '', database: 'postgres', appExtensions: [] })
		.addOAuth()
		.build();

plugin/skills/pipedrive-api/SKILL.md:58

  • Step 1 also tells the user to "Read src/pipedrive-client/ to understand the existing wrapper pattern", but the generated path is src/pipedrive/client.ts. This will lead the agent to attempt to read a directory that does not exist.
1. Read `src/pipedrive-client/` to understand the existing wrapper pattern

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cli.ts
Comment on lines +60 to +66
if (subcommand === 'add-app-extension') {
const appExtIdx = argv.indexOf('--app-extensions');
const appExtensions =
appExtIdx !== -1 ? ([argv[appExtIdx + 1]] as AppExtensionType[]) : undefined;
await addAppExtension(outputDir, appExtensions);
return true;
}
Comment thread src/cli.ts
Comment on lines +61 to +64
const appExtIdx = argv.indexOf('--app-extensions');
const appExtensions =
appExtIdx !== -1 ? ([argv[appExtIdx + 1]] as AppExtensionType[]) : undefined;
await addAppExtension(outputDir, appExtensions);
Comment thread src/cli.ts
Comment on lines +52 to +66
const outputDirIdx = argv.indexOf('--output-dir');
const outputDir = outputDirIdx !== -1 ? argv[outputDirIdx + 1] : undefined;

if (subcommand === 'add-oauth') {
await addOAuth(outputDir);
return true;
}

if (subcommand === 'add-app-extension') {
const appExtIdx = argv.indexOf('--app-extensions');
const appExtensions =
appExtIdx !== -1 ? ([argv[appExtIdx + 1]] as AppExtensionType[]) : undefined;
await addAppExtension(outputDir, appExtensions);
return true;
}
Comment thread src/subcommands/addAppExtension.ts Outdated
Comment on lines +16 to +18
await new NodeProjectBuilder(resolved, { projectName: '', database: 'postgres', appExtensions: extensions })
.addAppExtensions()
.build();
Comment thread src/subcommands/addOAuth.ts Outdated
Comment on lines +5 to +13
export async function addOAuth(outputDir: string = process.cwd()): Promise<void> {
const resolved = resolve(outputDir);
if (!existsSync(join(resolved, 'package.json'))) {
throw new Error(`No package.json found in ${resolved}. Run this command from your project root.`);
}
await new NodeProjectBuilder(resolved, { projectName: '', database: 'postgres', appExtensions: [] })
.addOAuth()
.build();
}
Comment thread src/subcommands/addOAuth.test.ts Outdated
Comment on lines +1 to +10
import { afterEach, describe, expect, it } from 'vitest';
import { access, mkdir, rm, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { tmpdir } from 'node:os';

const tmpDir = join(tmpdir(), 'cpa-add-oauth-test');
const exists = (p: string) => access(p).then(() => true, () => false);

afterEach(async () => {
await rm(tmpDir, { recursive: true, force: true });
Comment on lines +6 to +11
const tmpDir = join(tmpdir(), 'cpa-add-appext-test');
const exists = (p: string) => access(p).then(() => true, () => false);

afterEach(async () => {
await rm(tmpDir, { recursive: true, force: true });
});
Comment thread src/cli.test.ts
Comment on lines +37 to +42
const dispatchTmpDir = join(tmpdir(), 'cpa-dispatch-test');
const dispatchExists = (p: string) => access(p).then(() => true, () => false);

afterEach(async () => {
await rm(dispatchTmpDir, { recursive: true, force: true });
});
Comment thread src/cli.ts
Comment on lines +50 to +69
export async function dispatchSubcommand(argv: string[]): Promise<boolean> {
const subcommand = argv[2];
const outputDirIdx = argv.indexOf('--output-dir');
const outputDir = outputDirIdx !== -1 ? argv[outputDirIdx + 1] : undefined;

if (subcommand === 'add-oauth') {
await addOAuth(outputDir);
return true;
}

if (subcommand === 'add-app-extension') {
const appExtIdx = argv.indexOf('--app-extensions');
const appExtensions =
appExtIdx !== -1 ? ([argv[appExtIdx + 1]] as AppExtensionType[]) : undefined;
await addAppExtension(outputDir, appExtensions);
return true;
}

return false;
}
if (!existsSync(join(resolved, 'package.json'))) {
throw new Error(`No package.json found in ${resolved}. Run this command from your project root.`);
}
const extensions = appExtensions ?? (await promptAppExtensions());
Comment thread .agents/plugins/marketplace.json Outdated
{
"name": "create-pipedrive-app-local",
"interface": {
"displayName": "Create Pipedrive App Local"
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.

Suggested change
"displayName": "Create Pipedrive App Local"
"displayName": "Create Pipedrive App"

maybe we can name it Create Pipedrive App , without local ?

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.

will fix it. codex still needs that for the installation

@dmitriyeff dmitriyeff merged commit 2daf8c3 into master May 15, 2026
1 check passed
@dmitriyeff dmitriyeff deleted the AINATIVEM-47 branch May 15, 2026 10:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants