diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index cb8ddcd..cd83212 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -55,9 +55,10 @@ jobs: working-directory: packages/util run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/util" - - name: Publish @aictrl/plugin - working-directory: packages/plugin - run: ${{ github.workspace }}/.github/scripts/publish-if-new.sh "@aictrl/plugin" + # Note: @aictrl/plugin (workspace at packages/plugin) is the first-party + # plugin-author SDK used internally by the CLI and .opencode/tool/. It is + # marked "private": true and is NOT published to npm. Plugin types ship + # embedded in the compiled CLI binary at runtime. - name: Publish @aictrl/sdk working-directory: packages/sdk diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 49ce9df..ad79177 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,7 @@ Replace `` with your platform (e.g., `darwin-arm64`, `linux-x64`). - `packages/aictrl/src/cli/cmd/tui/`: The TUI code, written in SolidJS with [opentui](https://github.com/sst/opentui) - `packages/app`: The shared web UI components, written in SolidJS - `packages/desktop`: The native desktop app, built with Tauri (wraps `packages/app`) - - `packages/plugin`: Source for `@aictrl/plugin` + - `packages/plugin`: Source for `@aictrl/plugin` — first-party plugin-author SDK (types + `tool()` factory). Workspace-only, marked `"private": true`, not published to npm; types are embedded in the compiled CLI binary at runtime. ### Understanding bun dev vs aictrl diff --git a/bun.lock b/bun.lock index bd60b1c..1123e09 100644 --- a/bun.lock +++ b/bun.lock @@ -25,7 +25,7 @@ }, "packages/cli": { "name": "@aictrl/cli", - "version": "0.3.2", + "version": "0.3.3", "bin": { "aictrl": "./bin/aictrl", }, @@ -178,7 +178,7 @@ }, "packages/plugin": { "name": "@aictrl/plugin", - "version": "1.2.16", + "version": "0.1.0", "dependencies": { "@aictrl/sdk": "workspace:*", "zod": "catalog:", diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 1691d30..3b0297d 100644 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -22,13 +22,11 @@ import { import { Instance } from "../project/instance" import { LSPServer } from "../lsp/server" import { BunProc } from "@/bun" -import { Installation } from "@/installation" import { ConfigMarkdown } from "./markdown" import { constants, existsSync } from "fs" import { Bus } from "@/bus" import { GlobalBus } from "@/bus/global" import { Glob } from "../util/glob" -import { PackageRegistry } from "@/bun/registry" import { proxied } from "@/util/proxied" import { iife } from "@/util/iife" import { Control } from "@/control" @@ -247,24 +245,31 @@ export namespace Config { export async function installDependencies(dir: string) { const pkg = path.join(dir, "package.json") - const targetVersion = Installation.isLocal() ? "*" : Installation.VERSION - - const json = await Filesystem.readJson<{ dependencies?: Record }>(pkg).catch(() => ({ - dependencies: {}, - })) - json.dependencies = { - ...json.dependencies, - "@aictrl/plugin": targetVersion, + + // Migration: scrub legacy @aictrl/plugin* entries from user + // package.json. Older CLIs auto-added these; the npm names aren't + // ours to manage (@aictrl/plugin is an unrelated telemetry package, + // and @aictrl/plugin is internal / private). Plugin types are + // supplied by the CLI runtime, not npm. + const json = await Filesystem.readJson<{ dependencies?: Record }>(pkg).catch(() => null) + if (json?.dependencies) { + const deps = { ...json.dependencies } + const hadLegacy = "@aictrl/plugin" in deps || "@aictrl/plugin" in deps + delete deps["@aictrl/plugin"] + delete deps["@aictrl/plugin"] + if (hadLegacy) { + json.dependencies = deps + await Filesystem.writeJson(pkg, json) + } } - await Filesystem.writeJson(pkg, json) const gitignore = path.join(dir, ".gitignore") const hasGitIgnore = await Filesystem.exists(gitignore) if (!hasGitIgnore) await Filesystem.write(gitignore, ["node_modules", "package.json", "bun.lock", ".gitignore"].join("\n")) - // Install any additional dependencies defined in the package.json - // This allows local plugins and custom tools to use external packages + // Install any dependencies declared by local plugins and custom tools + // (e.g. a .aictrl/package.json that lists 'cowsay'). await BunProc.run( [ "install", @@ -304,21 +309,14 @@ export namespace Config { const parsed = await Filesystem.readJson<{ dependencies?: Record }>(pkg).catch(() => null) const dependencies = parsed?.dependencies ?? {} - const depVersion = dependencies["@aictrl/plugin"] - if (!depVersion) return true - - const targetVersion = Installation.isLocal() ? "latest" : Installation.VERSION - if (targetVersion === "latest") { - const isOutdated = await PackageRegistry.isOutdated("@aictrl/plugin", depVersion, dir) - if (!isOutdated) return false - log.info("Cached version is outdated, proceeding with install", { - pkg: "@aictrl/plugin", - cachedVersion: depVersion, - }) - return true - } - if (depVersion === targetVersion) return false - return true + + // Migration: any legacy @aictrl/plugin* entry forces a reinstall + // so installDependencies can scrub it out in the same pass. + if (dependencies["@aictrl/plugin"] || dependencies["@aictrl/plugin"]) return true + + // No aictrl-managed deps; install only if user declared other deps + // but node_modules is absent (already checked above) — otherwise skip. + return false } function rel(item: string, patterns: string[]) { diff --git a/packages/cli/test/config/config.test.ts b/packages/cli/test/config/config.test.ts index d198f21..6df5b99 100644 --- a/packages/cli/test/config/config.test.ts +++ b/packages/cli/test/config/config.test.ts @@ -1559,6 +1559,36 @@ describe("getPluginName", () => { }) }) +describe("installDependencies migration", () => { + test("scrubs legacy @aictrl/plugin* keys from user package.json", async () => { + await using tmp = await tmpdir({ + init: async (dir) => { + await Filesystem.write( + path.join(dir, "package.json"), + JSON.stringify({ + name: "existing", + dependencies: { + "@aictrl/plugin": "1.2.16", + cowsay: "^1.6.0", + }, + }), + ) + }, + }) + await Instance.provide({ + directory: tmp.path, + fn: async () => { + await Config.installDependencies(tmp.path).catch(() => {}) + const parsed = await Filesystem.readJson<{ dependencies: Record }>( + path.join(tmp.path, "package.json"), + ) + expect(parsed.dependencies["@aictrl/plugin"]).toBeUndefined() + expect(parsed.dependencies["cowsay"]).toBe("^1.6.0") + }, + }) + }) +}) + describe("deduplicatePlugins", () => { test("removes duplicates keeping higher priority (later entries)", () => { const plugins = ["global-plugin@1.0.0", "shared-plugin@1.0.0", "local-plugin@2.0.0", "shared-plugin@2.0.0"] diff --git a/packages/plugin/package.json b/packages/plugin/package.json index 3eaaf06..b525686 100644 --- a/packages/plugin/package.json +++ b/packages/plugin/package.json @@ -1,7 +1,8 @@ { "$schema": "https://json.schemastore.org/package.json", "name": "@aictrl/plugin", - "version": "1.2.16", + "version": "0.1.0", + "private": true, "type": "module", "license": "MIT", "repository": {