paperclip/packages/plugins/sdk/src/index.ts
Dotta 0096b56a1c
[codex] Add LLM Wiki plugin host support (#5597)
## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies.
> - The plugin system needs host contracts and runtime support before
large plugins can integrate cleanly.
> - The source branch mixed the LLM Wiki package with supporting
host/runtime work, managed plugin skills, root-level storage spaces, and
a bookmarks reference plugin.
> - [PAP-9173](/PAP/issues/PAP-9173) asked for the current branch to be
split by file boundary: plugin package separately from everything else.
> - [PAP-9188](/PAP/issues/PAP-9188) clarified that LLM Wiki may have
plugin-local spaces, but Paperclip core should not reorganize top-level
local storage into spaces.
> - Follow-up review clarified that the bookmarks example should not
ship in this PR either.
> - This pull request contains the
non-`packages/plugins/plugin-llm-wiki/` host/runtime work, keeps runtime
state under the selected Paperclip instance root, and no longer includes
the bookmarks example.

## What Changed

- Added/updated plugin host contracts, SDK types, worker RPC plumbing,
managed plugin skill support, and related server tests.
- Removed the bookmarks example plugin package and its
bundled-example/workspace references.
- Removed the root-level local spaces CLI/migration surface and restored
instance-root runtime defaults for config, db, logs, storage, secrets,
workspaces, projects, and adapter homes.
- Replaced shared root `space-paths` helpers with `home-paths` helpers
for core runtime storage.
- Tightened stranded recovery unique-conflict detection so concurrent
recovery scans reuse the raced recovery issue when Postgres errors are
wrapped.
- Kept `packages/plugins/plugin-llm-wiki/` out of this PR diff;
plugin-local spaces remain in the stacked plugin-only PR.

## Verification

- `pnpm exec vitest run cli/src/__tests__/data-dir.test.ts
cli/src/__tests__/home-paths.test.ts cli/src/__tests__/onboard.test.ts
packages/shared/src/home-paths.test.ts
packages/db/src/runtime-config.test.ts
server/src/__tests__/agent-instructions-service.test.ts
server/src/__tests__/claude-local-execute.test.ts
server/src/__tests__/codex-local-execute.test.ts`
- `pnpm exec vitest run packages/db/src/runtime-config.test.ts`
- `pnpm exec vitest run
server/src/__tests__/plugin-routes-authz.test.ts`
- `pnpm --filter @paperclipai/server typecheck`
- `pnpm exec vitest run
server/src/__tests__/heartbeat-process-recovery.test.ts -t "reuses the
raced stranded recovery issue"` skipped locally because embedded
Postgres did not initialize on this macOS temp host; the code path was
typechecked and is covered by Linux CI.
- Boundary check: no core references remain for `PAPERCLIP_SPACE_ID`,
`spaces migrate-default`, `@paperclipai/shared/space-paths`,
`registerSpacesCommands`, or the removed bookmarks example.
- Previous PR head `4f23e034` had green GitHub checks: `verify`, all
four serialized server shards, `e2e`, `Canary Dry Run`, `policy`, Snyk,
and `Greptile Review`. Current head `582f466d` is re-running checks
after the bookmarks deletion.

## Risks

- Plugin host changes touch shared runtime paths, so regressions would
most likely appear in adapter startup, plugin loading, or local dev path
defaults.
- Removing the bookmarks example also removes one demonstration of
plugin database namespaces plus local-folder persistence; remaining
plugin examples still cover bundled example discovery and plugin host
flows.
- The plugin package itself is intentionally deferred to the stacked
plugin-only PR, where LLM Wiki plugin-local spaces live.
- Existing installs that tested the transient root-level spaces CLI
should stop using it; this PR intentionally removes that unsupported
migration surface before merge.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI GPT-5 Codex via Codex CLI, tool use and local code execution
enabled; context window not exposed.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass, except where noted above
for host-specific embedded Postgres initialization
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

Stacked follow-up: PR #5592 contains only
`packages/plugins/plugin-llm-wiki/` and targets this branch.

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-10 07:34:12 -05:00

361 lines
9.7 KiB
TypeScript

/**
* `@paperclipai/plugin-sdk` — Paperclip plugin worker-side SDK.
*
* This is the main entrypoint for plugin worker code. For plugin UI bundles,
* import from `@paperclipai/plugin-sdk/ui` instead.
*
* @example
* ```ts
* // Plugin worker entrypoint (dist/worker.ts)
* import { definePlugin, runWorker, z } from "@paperclipai/plugin-sdk";
*
* const plugin = definePlugin({
* async setup(ctx) {
* ctx.logger.info("Plugin starting up");
*
* ctx.events.on("issue.created", async (event) => {
* ctx.logger.info("Issue created", { issueId: event.entityId });
* });
*
* ctx.jobs.register("full-sync", async (job) => {
* ctx.logger.info("Starting full sync", { runId: job.runId });
* // ... sync implementation
* });
*
* ctx.data.register("sync-health", async ({ companyId }) => {
* const state = await ctx.state.get({
* scopeKind: "company",
* scopeId: String(companyId),
* stateKey: "last-sync-at",
* });
* return { lastSync: state };
* });
* },
*
* async onHealth() {
* return { status: "ok" };
* },
* });
*
* export default plugin;
* runWorker(plugin, import.meta.url);
* ```
*
* @see PLUGIN_SPEC.md §14 — SDK Surface
* @see PLUGIN_SPEC.md §29.2 — SDK Versioning
*/
// ---------------------------------------------------------------------------
// Main factory
// ---------------------------------------------------------------------------
export { definePlugin } from "./define-plugin.js";
export { createTestHarness, createEnvironmentTestHarness, createFakeEnvironmentDriver, filterEnvironmentEvents, assertEnvironmentEventOrder, assertLeaseLifecycle, assertWorkspaceRealizationLifecycle, assertExecutionLifecycle, assertEnvironmentError } from "./testing.js";
export { createPluginBundlerPresets } from "./bundlers.js";
export { startPluginDevServer, getUiBuildSnapshot } from "./dev-server.js";
export { startWorkerRpcHost, runWorker } from "./worker-rpc-host.js";
export {
createHostClientHandlers,
getRequiredCapability,
CapabilityDeniedError,
} from "./host-client-factory.js";
// JSON-RPC protocol helpers and constants
export {
JSONRPC_VERSION,
JSONRPC_ERROR_CODES,
PLUGIN_RPC_ERROR_CODES,
HOST_TO_WORKER_REQUIRED_METHODS,
HOST_TO_WORKER_OPTIONAL_METHODS,
MESSAGE_DELIMITER,
createRequest,
createSuccessResponse,
createErrorResponse,
createNotification,
isJsonRpcRequest,
isJsonRpcNotification,
isJsonRpcResponse,
isJsonRpcSuccessResponse,
isJsonRpcErrorResponse,
serializeMessage,
parseMessage,
JsonRpcParseError,
JsonRpcCallError,
_resetIdCounter,
} from "./protocol.js";
// ---------------------------------------------------------------------------
// Type exports
// ---------------------------------------------------------------------------
// Plugin definition and lifecycle types
export type {
PluginDefinition,
PaperclipPlugin,
PluginHealthDiagnostics,
PluginConfigValidationResult,
PluginWebhookInput,
PluginApiRequestInput,
PluginApiResponse,
} from "./define-plugin.js";
export type {
TestHarness,
TestHarnessOptions,
TestHarnessLogEntry,
EnvironmentTestHarness,
EnvironmentTestHarnessOptions,
EnvironmentEventRecord,
FakeEnvironmentDriverOptions,
} from "./testing.js";
export type {
PluginBundlerPresetInput,
PluginBundlerPresets,
EsbuildLikeOptions,
RollupLikeConfig,
} from "./bundlers.js";
export type { PluginDevServer, PluginDevServerOptions } from "./dev-server.js";
export type {
WorkerRpcHostOptions,
WorkerRpcHost,
RunWorkerOptions,
} from "./worker-rpc-host.js";
export type {
HostServices,
HostClientFactoryOptions,
HostClientHandlers,
} from "./host-client-factory.js";
// JSON-RPC protocol types
export type {
JsonRpcId,
JsonRpcRequest,
JsonRpcSuccessResponse,
JsonRpcError,
JsonRpcErrorResponse,
JsonRpcResponse,
JsonRpcNotification,
JsonRpcMessage,
JsonRpcErrorCode,
PluginRpcErrorCode,
InitializeParams,
InitializeResult,
ConfigChangedParams,
ValidateConfigParams,
OnEventParams,
RunJobParams,
GetDataParams,
PerformActionParams,
ExecuteToolParams,
PluginEnvironmentDiagnostic,
PluginEnvironmentDriverBaseParams,
PluginEnvironmentValidateConfigParams,
PluginEnvironmentValidationResult,
PluginEnvironmentProbeParams,
PluginEnvironmentProbeResult,
PluginEnvironmentLease,
PluginEnvironmentAcquireLeaseParams,
PluginEnvironmentResumeLeaseParams,
PluginEnvironmentReleaseLeaseParams,
PluginEnvironmentDestroyLeaseParams,
PluginEnvironmentRealizeWorkspaceParams,
PluginEnvironmentRealizeWorkspaceResult,
PluginEnvironmentExecuteParams,
PluginEnvironmentExecuteResult,
PluginModalBoundsRequest,
PluginRenderCloseEvent,
PluginLauncherRenderContextSnapshot,
HostToWorkerMethods,
HostToWorkerMethodName,
WorkerToHostMethods,
WorkerToHostMethodName,
HostToWorkerRequest,
HostToWorkerResponse,
WorkerToHostRequest,
WorkerToHostResponse,
WorkerToHostNotifications,
WorkerToHostNotificationName,
} from "./protocol.js";
// Plugin context and all client interfaces
export type {
PluginContext,
PluginConfigClient,
PluginLocalFolderProblem,
PluginLocalFolderStatus,
PluginLocalFolderConfigureInput,
PluginLocalFolderListOptions,
PluginLocalFolderEntry,
PluginLocalFolderListing,
PluginLocalFoldersClient,
PluginEventsClient,
PluginJobsClient,
PluginLaunchersClient,
PluginHttpClient,
PluginSecretsClient,
PluginActivityClient,
PluginActivityLogEntry,
PluginStateClient,
PluginEntitiesClient,
PluginProjectsClient,
PluginSkillsClient,
PluginCompaniesClient,
PluginIssuesClient,
PluginIssueMutationActor,
PluginIssueRelationsClient,
PluginIssueRelationSummary,
PluginIssueCheckoutOwnership,
PluginIssueWakeupResult,
PluginIssueWakeupBatchResult,
PluginIssueRunSummary,
PluginIssueApprovalSummary,
PluginIssueCostSummary,
PluginBudgetIncidentSummary,
PluginIssueInvocationBlockSummary,
PluginIssueOrchestrationSummary,
PluginIssueSubtreeOptions,
PluginIssueAssigneeSummary,
PluginIssueSubtree,
PluginIssueSummariesClient,
PluginAgentsClient,
PluginAgentSessionsClient,
AgentSession,
AgentSessionEvent,
AgentSessionSendResult,
PluginGoalsClient,
PluginDataClient,
PluginActionsClient,
PluginStreamsClient,
PluginToolsClient,
PluginMetricsClient,
PluginTelemetryClient,
PluginLogger,
} from "./types.js";
// Supporting types for context clients
export type {
ScopeKey,
EventFilter,
PluginEvent,
PluginJobContext,
PluginLauncherRegistration,
ToolRunContext,
ToolResult,
PluginEntityUpsert,
PluginEntityRecord,
PluginEntityQuery,
PluginWorkspace,
Company,
Project,
Issue,
IssueComment,
IssueDocumentSummary,
Agent,
Goal,
PluginDatabaseClient,
} from "./types.js";
// Manifest and constant types re-exported from @paperclipai/shared
// Plugin authors import manifest types from here so they have a single
// dependency (@paperclipai/plugin-sdk) for all plugin authoring needs.
export type {
PaperclipPluginManifestV1,
PluginJobDeclaration,
PluginWebhookDeclaration,
PluginToolDeclaration,
PluginEnvironmentDriverDeclaration,
PluginManagedAgentDeclaration,
PluginManagedAgentResolution,
PluginManagedProjectDeclaration,
PluginManagedProjectResolution,
PluginManagedRoutineDeclaration,
PluginManagedRoutineResolution,
PluginManagedSkillDeclaration,
PluginManagedSkillFileDeclaration,
PluginManagedSkillResolution,
CompanySkill,
PluginManagedResourceKind,
PluginManagedResourceRef,
PluginUiSlotDeclaration,
PluginUiDeclaration,
PluginLauncherActionDeclaration,
PluginLauncherRenderDeclaration,
PluginLauncherDeclaration,
PluginMinimumHostVersion,
PluginDatabaseDeclaration,
PluginApiRouteCompanyResolution,
PluginApiRouteDeclaration,
PluginLocalFolderDeclaration,
PluginCompanySettings,
PluginRecord,
PluginDatabaseNamespaceRecord,
PluginMigrationRecord,
PluginConfig,
JsonSchema,
PluginStatus,
PluginCategory,
PluginCapability,
PluginUiSlotType,
PluginUiSlotEntityType,
PluginLauncherPlacementZone,
PluginLauncherAction,
PluginLauncherBounds,
PluginLauncherRenderEnvironment,
PluginStateScopeKind,
PluginJobStatus,
PluginJobRunStatus,
PluginJobRunTrigger,
PluginWebhookDeliveryStatus,
PluginDatabaseCoreReadTable,
PluginDatabaseMigrationStatus,
PluginDatabaseNamespaceMode,
PluginDatabaseNamespaceStatus,
PluginApiRouteAuthMode,
PluginApiRouteCheckoutPolicy,
PluginApiRouteMethod,
PluginEventType,
PluginBridgeErrorCode,
} from "./types.js";
// ---------------------------------------------------------------------------
// Zod re-export
// ---------------------------------------------------------------------------
/**
* Zod is re-exported for plugin authors to use when defining their
* `instanceConfigSchema` and tool `parametersSchema`.
*
* Plugin authors do not need to add a separate `zod` dependency.
*
* @see PLUGIN_SPEC.md §14.1 — Example SDK Shape
*
* @example
* ```ts
* import { z } from "@paperclipai/plugin-sdk";
*
* const configSchema = z.object({
* apiKey: z.string().describe("Your API key"),
* workspace: z.string().optional(),
* });
* ```
*/
export { z } from "zod";
// ---------------------------------------------------------------------------
// Constants re-exports (for plugin code that needs to check values at runtime)
// ---------------------------------------------------------------------------
export {
PLUGIN_API_VERSION,
PLUGIN_STATUSES,
PLUGIN_CATEGORIES,
PLUGIN_CAPABILITIES,
PLUGIN_UI_SLOT_TYPES,
PLUGIN_UI_SLOT_ENTITY_TYPES,
PLUGIN_STATE_SCOPE_KINDS,
PLUGIN_JOB_STATUSES,
PLUGIN_JOB_RUN_STATUSES,
PLUGIN_JOB_RUN_TRIGGERS,
PLUGIN_WEBHOOK_DELIVERY_STATUSES,
PLUGIN_EVENT_TYPES,
PLUGIN_BRIDGE_ERROR_CODES,
} from "@paperclipai/shared";