From 537693fe1c0dd9f273672229d7af80a2f97151a8 Mon Sep 17 00:00:00 2001 From: Justin Levine <20596508+jal-co@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:42:20 -0500 Subject: [PATCH 1/4] feat(cli): add init, uninstall, dev watch, and npm install source Adds four CLI features from improvement plans 002/005/006/013: - ap-sdk init scaffolds a working plugin.ts + .gitignore with dry-run and overwrite protection - ap-sdk install records an install manifest; ap-sdk uninstall reverses only recorded files/entries and leaves foreign config intact - ap-sdk dev watches the plugin dir, rebuilds on change, survives broken plugins, and optionally reinstalls with --install - npm:[@version] as a remote source for install/check, with the same compatibility gate as GitHub sources Docs: quickstart now leads with npx ap-sdk init; installing-plugins gains a From npm section. --- .tegami/2026-07-01-dev-watch.md | 10 + .tegami/2026-07-01-init-command.md | 10 + .tegami/2026-07-01-npm-source.md | 12 + .tegami/2026-07-01-uninstall.md | 11 + apps/docs/content/docs/installing-plugins.mdx | 47 ++++ apps/docs/content/docs/quickstart.mdx | 14 +- packages/agent-plugin-sdk/src/cli.ts | 207 ++++++++++++++---- packages/agent-plugin-sdk/src/dev.ts | 200 +++++++++++++++++ packages/agent-plugin-sdk/src/index.ts | 2 + packages/agent-plugin-sdk/src/install.ts | 70 +++++- packages/agent-plugin-sdk/src/npm.ts | 178 +++++++++++++++ .../agent-plugin-sdk/src/scaffold-plugin.ts | 52 +++++ packages/agent-plugin-sdk/src/uninstall.ts | 195 +++++++++++++++++ packages/agent-plugin-sdk/test/dev.test.ts | 113 ++++++++++ packages/agent-plugin-sdk/test/init.test.ts | 47 ++++ packages/agent-plugin-sdk/test/npm.test.ts | 105 +++++++++ .../agent-plugin-sdk/test/uninstall.test.ts | 153 +++++++++++++ 17 files changed, 1379 insertions(+), 47 deletions(-) create mode 100644 .tegami/2026-07-01-dev-watch.md create mode 100644 .tegami/2026-07-01-init-command.md create mode 100644 .tegami/2026-07-01-npm-source.md create mode 100644 .tegami/2026-07-01-uninstall.md create mode 100644 packages/agent-plugin-sdk/src/dev.ts create mode 100644 packages/agent-plugin-sdk/src/npm.ts create mode 100644 packages/agent-plugin-sdk/src/scaffold-plugin.ts create mode 100644 packages/agent-plugin-sdk/src/uninstall.ts create mode 100644 packages/agent-plugin-sdk/test/dev.test.ts create mode 100644 packages/agent-plugin-sdk/test/init.test.ts create mode 100644 packages/agent-plugin-sdk/test/npm.test.ts create mode 100644 packages/agent-plugin-sdk/test/uninstall.test.ts diff --git a/.tegami/2026-07-01-dev-watch.md b/.tegami/2026-07-01-dev-watch.md new file mode 100644 index 0000000..8f0027c --- /dev/null +++ b/.tegami/2026-07-01-dev-watch.md @@ -0,0 +1,10 @@ +--- +packages: + "@jalco/ap-sdk": minor +--- + +## Add `ap-sdk dev` + +Watch mode for plugin authors: `ap-sdk dev` rebuilds on every change to the +plugin and its referenced files, and `--install` drops the result straight +into your local harness dirs. Errors keep the watcher alive. diff --git a/.tegami/2026-07-01-init-command.md b/.tegami/2026-07-01-init-command.md new file mode 100644 index 0000000..6f5c9b0 --- /dev/null +++ b/.tegami/2026-07-01-init-command.md @@ -0,0 +1,10 @@ +--- +packages: + "@jalco/ap-sdk": minor +--- + +## Add `ap-sdk init` + +Scaffold a new plugin project with one command. `ap-sdk init my-plugin` writes +a working `plugin.ts` (a skill, a command, and instructions) that passes +`ap-sdk check` as-is, plus a `.gitignore` entry for `.aps-out/`. diff --git a/.tegami/2026-07-01-npm-source.md b/.tegami/2026-07-01-npm-source.md new file mode 100644 index 0000000..ce54304 --- /dev/null +++ b/.tegami/2026-07-01-npm-source.md @@ -0,0 +1,12 @@ +--- +packages: + "@jalco/ap-sdk": minor +--- + +## Install plugins from npm + +`ap-sdk install npm:` (and `check`/`build` with the same spec) +fetches a published package from the npm registry, verifies it's a +compatible plugin, and installs it — with `npm:@` for +pinning. Packages can point at a non-root plugin file via an +`ap-sdk.plugin` field in package.json. diff --git a/.tegami/2026-07-01-uninstall.md b/.tegami/2026-07-01-uninstall.md new file mode 100644 index 0000000..cbd6023 --- /dev/null +++ b/.tegami/2026-07-01-uninstall.md @@ -0,0 +1,11 @@ +--- +packages: + "@jalco/ap-sdk": minor +--- + +## Add `ap-sdk uninstall` + +`install` now records what it wrote to an install manifest +(`.ap-sdk/install-manifest.json`), and `ap-sdk uninstall ` cleanly +reverses it — deleting the plugin's files and removing only its entries from +merged configs (instruction blocks, MCP servers, hooks). diff --git a/apps/docs/content/docs/installing-plugins.mdx b/apps/docs/content/docs/installing-plugins.mdx index 3f1f405..0180451 100644 --- a/apps/docs/content/docs/installing-plugins.mdx +++ b/apps/docs/content/docs/installing-plugins.mdx @@ -12,6 +12,8 @@ the skills, commands, and tools immediately. npx ap-sdk install ``` +Looking for plugins? Browse the [plugin directory](/docs/plugins). + Install reuses the exact same output as `build`, so installed files are byte-for-byte identical — it just relocates each feature into the harness's live config dir instead of an output folder. @@ -105,6 +107,51 @@ Use `--path ` when the plugin lives in a subdirectory, and set `@jalco/ap-sdk` import is resolved to the SDK running the install, so simple plugins need no dependency install of their own. +## From npm + +Use the `npm:` source form to fetch a published package, run the same +compatibility check, and install only if it default-exports a valid ap-sdk +plugin: + +```bash compact +npx ap-sdk install npm:@acme/git-helper +npx ap-sdk install npm:@acme/git-helper@1.2.3 -t claude +npx ap-sdk check npm:@acme/git-helper@next +``` + +Version pinning uses the suffix after the package name (`npm:name@1.2.3` or a +dist-tag like `npm:name@next`). Scoped names keep their scope: +`npm:@scope/name@1.2.3`. + +Packages can point at a non-root plugin file with package metadata: + +```json title="package.json" +{ + "ap-sdk": { "plugin": "./dist/plugin.js" } +} +``` + +If that field is absent, the CLI looks for the usual `plugin.ts`, `plugin.js`, +or `ap-sdk.config.ts`; use `--path ` for packages that contain the plugin +inside a subdirectory. + +## Uninstalling + +Every non-dry-run install records exactly what was written in +`.ap-sdk/install-manifest.json` for project installs, or +`~/.ap-sdk/install-manifest.json` for global installs. Remove a recorded plugin +with: + +```bash compact +npx ap-sdk uninstall git-helper +npx ap-sdk uninstall git-helper --dry-run +npx ap-sdk uninstall git-helper --global +``` + +Uninstall deletes only recorded files and removes only the plugin's entries from +shared configs (instruction blocks, MCP servers, hooks). Installs made before +this manifest existed have no record, so they cannot be auto-removed. + ## Programmatic install Everything the CLI does is available as a function, so you can install from your diff --git a/apps/docs/content/docs/quickstart.mdx b/apps/docs/content/docs/quickstart.mdx index 96c5ad9..4c46d39 100644 --- a/apps/docs/content/docs/quickstart.mdx +++ b/apps/docs/content/docs/quickstart.mdx @@ -5,7 +5,13 @@ description: Define a plugin and compile it to every harness in a few minutes. ## 1. Define a plugin -Create `plugin.ts` and default-export the result of `definePlugin`: +Start with a working scaffold: + +```bash +npx ap-sdk init my-plugin +``` + +That writes a `plugin.ts` you can edit. Or create `plugin.ts` yourself and default-export the result of `definePlugin`: ```ts title="plugin.ts" import { @@ -76,6 +82,12 @@ npx ap-sdk build -t claude,gemini,cursor npx ap-sdk install -t claude ``` +For an edit/build/install loop while authoring, run watch mode: + +```bash +npx ap-sdk dev --install -t claude +``` + Add `--global` to install into your home-directory harness dirs, or `--dry-run` to preview without writing. See [Installing a plugin](/docs/installing-plugins) for the full install model. diff --git a/packages/agent-plugin-sdk/src/cli.ts b/packages/agent-plugin-sdk/src/cli.ts index 4e1381b..9f45d46 100644 --- a/packages/agent-plugin-sdk/src/cli.ts +++ b/packages/agent-plugin-sdk/src/cli.ts @@ -1,16 +1,18 @@ #!/usr/bin/env node import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; -import { dirname, isAbsolute, join, resolve } from "node:path"; +import { dirname, isAbsolute, resolve } from "node:path"; import { pathToFileURL } from "node:url"; import type { HarnessId, Plugin } from "./types.js"; import { allHarnessIds } from "./harnesses/index.js"; import { build } from "./build.js"; import { installSkills } from "./install.js"; +import { uninstallPlugin } from "./uninstall.js"; +import { startDev, writeBuildOutputs } from "./dev.js"; import { loadPluginTools } from "./load-tools.js"; import { listTools, callTool, contentToText } from "./runtime/tool.js"; import { formatWarning } from "./warnings.js"; -import { writeTree } from "./util/fs.js"; import { fetchGithubPlugin, isGithubSpec } from "./github.js"; +import { fetchNpmPlugin, isNpmSpec } from "./npm.js"; import { portPlugin } from "./port.js"; import { DEFAULT_PLUGIN_FILES, locatePlugin } from "./plugin-files.js"; import { PluginValidationError, validatePlugin } from "./validate.js"; @@ -19,47 +21,56 @@ import { deriveDisplayName, validateHarnessId, } from "./scaffold.js"; +import { gitignoreSnippet, pluginTemplate, validatePluginId } from "./scaffold-plugin.js"; const HELP = `ap-sdk — write a plugin once, ship it to every agent harness Usage: - ap-sdk build [plugin] [options] Compile to native artifacts under an output dir - ap-sdk install [plugin] [options] Install skills into local harness dirs - ap-sdk check [plugin] Validate a plugin definition - ap-sdk tools [plugin] [options] List the plugin's tools, or invoke one locally - ap-sdk add-harness [options] Scaffold a new target harness module - ap-sdk port [dir] [options] Generate a portable plugin.ts from an existing plugin + ap-sdk init [id] [options] Scaffold a new plugin.ts in the current directory + ap-sdk build [plugin] [options] Compile to native artifacts under an output dir + ap-sdk install [plugin] [options] Install skills into local harness dirs + ap-sdk uninstall [options] Remove a previously installed plugin + ap-sdk dev [plugin] [options] Watch the plugin and rebuild on change + ap-sdk check [plugin] Validate a plugin definition + ap-sdk tools [plugin] [options] List the plugin's tools, or invoke one locally + ap-sdk add-harness [options] Scaffold a new target harness module + ap-sdk port [dir] [options] Generate a portable plugin.ts from an existing plugin Arguments: plugin A local plugin module (default: ./plugin.ts, ./plugin.js, - ./ap-sdk.config.ts) or a GitHub source — owner/repo, - github:owner/repo, or a github.com URL. Must default-export a - definePlugin(...) result. Remote sources are fetched and checked for - compatibility before anything is installed. - id (add-harness) kebab-case id for the new harness, e.g. gemini, cursor. + ./ap-sdk.config.ts), a GitHub source — owner/repo, + github:owner/repo, or a github.com URL — or npm:[@version]. + Must default-export a definePlugin(...) result. Remote sources are + fetched and checked for compatibility before anything is installed. + id init: kebab-case plugin id; add-harness: kebab-case harness id. Options: --target, -t Comma-separated harnesses: ${allHarnessIds().join(", ")} (default: all) --out, -o build: output dir (default: ./.aps-out) add-harness: dir to write the harness file (default: .) --name