@paperclipai/plugin-sdk 2026.3.17-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +888 -0
  3. package/dist/bundlers.d.ts +57 -0
  4. package/dist/bundlers.d.ts.map +1 -0
  5. package/dist/bundlers.js +105 -0
  6. package/dist/bundlers.js.map +1 -0
  7. package/dist/define-plugin.d.ts +218 -0
  8. package/dist/define-plugin.d.ts.map +1 -0
  9. package/dist/define-plugin.js +85 -0
  10. package/dist/define-plugin.js.map +1 -0
  11. package/dist/dev-cli.d.ts +3 -0
  12. package/dist/dev-cli.d.ts.map +1 -0
  13. package/dist/dev-cli.js +49 -0
  14. package/dist/dev-cli.js.map +1 -0
  15. package/dist/dev-server.d.ts +34 -0
  16. package/dist/dev-server.d.ts.map +1 -0
  17. package/dist/dev-server.js +194 -0
  18. package/dist/dev-server.js.map +1 -0
  19. package/dist/host-client-factory.d.ts +229 -0
  20. package/dist/host-client-factory.d.ts.map +1 -0
  21. package/dist/host-client-factory.js +353 -0
  22. package/dist/host-client-factory.js.map +1 -0
  23. package/dist/index.d.ts +84 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +84 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/protocol.d.ts +881 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +297 -0
  30. package/dist/protocol.js.map +1 -0
  31. package/dist/testing.d.ts +63 -0
  32. package/dist/testing.d.ts.map +1 -0
  33. package/dist/testing.js +700 -0
  34. package/dist/testing.js.map +1 -0
  35. package/dist/types.d.ts +982 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +12 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/ui/components.d.ts +257 -0
  40. package/dist/ui/components.d.ts.map +1 -0
  41. package/dist/ui/components.js +97 -0
  42. package/dist/ui/components.js.map +1 -0
  43. package/dist/ui/hooks.d.ts +120 -0
  44. package/dist/ui/hooks.d.ts.map +1 -0
  45. package/dist/ui/hooks.js +148 -0
  46. package/dist/ui/hooks.js.map +1 -0
  47. package/dist/ui/index.d.ts +50 -0
  48. package/dist/ui/index.d.ts.map +1 -0
  49. package/dist/ui/index.js +48 -0
  50. package/dist/ui/index.js.map +1 -0
  51. package/dist/ui/runtime.d.ts +3 -0
  52. package/dist/ui/runtime.d.ts.map +1 -0
  53. package/dist/ui/runtime.js +30 -0
  54. package/dist/ui/runtime.js.map +1 -0
  55. package/dist/ui/types.d.ts +308 -0
  56. package/dist/ui/types.d.ts.map +1 -0
  57. package/dist/ui/types.js +17 -0
  58. package/dist/ui/types.js.map +1 -0
  59. package/dist/worker-rpc-host.d.ts +127 -0
  60. package/dist/worker-rpc-host.d.ts.map +1 -0
  61. package/dist/worker-rpc-host.js +941 -0
  62. package/dist/worker-rpc-host.js.map +1 -0
  63. package/package.json +88 -0
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Bundling presets for Paperclip plugins.
3
+ *
4
+ * These helpers return plain config objects so plugin authors can use them
5
+ * with esbuild or rollup without re-implementing host contract defaults.
6
+ */
7
+ export interface PluginBundlerPresetInput {
8
+ pluginRoot?: string;
9
+ manifestEntry?: string;
10
+ workerEntry?: string;
11
+ uiEntry?: string;
12
+ outdir?: string;
13
+ sourcemap?: boolean;
14
+ minify?: boolean;
15
+ }
16
+ export interface EsbuildLikeOptions {
17
+ entryPoints: string[];
18
+ outdir: string;
19
+ bundle: boolean;
20
+ format: "esm";
21
+ platform: "node" | "browser";
22
+ target: string;
23
+ sourcemap?: boolean;
24
+ minify?: boolean;
25
+ external?: string[];
26
+ }
27
+ export interface RollupLikeConfig {
28
+ input: string;
29
+ output: {
30
+ dir: string;
31
+ format: "es";
32
+ sourcemap?: boolean;
33
+ entryFileNames?: string;
34
+ };
35
+ external?: string[];
36
+ plugins?: unknown[];
37
+ }
38
+ export interface PluginBundlerPresets {
39
+ esbuild: {
40
+ worker: EsbuildLikeOptions;
41
+ ui?: EsbuildLikeOptions;
42
+ manifest: EsbuildLikeOptions;
43
+ };
44
+ rollup: {
45
+ worker: RollupLikeConfig;
46
+ ui?: RollupLikeConfig;
47
+ manifest: RollupLikeConfig;
48
+ };
49
+ }
50
+ /**
51
+ * Build esbuild/rollup baseline configs for plugin worker, manifest, and UI bundles.
52
+ *
53
+ * The presets intentionally externalize host/runtime deps (`react`, SDK packages)
54
+ * to match the Paperclip plugin loader contract.
55
+ */
56
+ export declare function createPluginBundlerPresets(input?: PluginBundlerPresetInput): PluginBundlerPresets;
57
+ //# sourceMappingURL=bundlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundlers.d.ts","sourceRoot":"","sources":["../src/bundlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,wBAAwB;IACvC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,IAAI,CAAC;QACb,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE;QACP,MAAM,EAAE,kBAAkB,CAAC;QAC3B,EAAE,CAAC,EAAE,kBAAkB,CAAC;QACxB,QAAQ,EAAE,kBAAkB,CAAC;KAC9B,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,gBAAgB,CAAC;QACzB,EAAE,CAAC,EAAE,gBAAgB,CAAC;QACtB,QAAQ,EAAE,gBAAgB,CAAC;KAC5B,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,GAAE,wBAA6B,GAAG,oBAAoB,CAmGrG"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Bundling presets for Paperclip plugins.
3
+ *
4
+ * These helpers return plain config objects so plugin authors can use them
5
+ * with esbuild or rollup without re-implementing host contract defaults.
6
+ */
7
+ /**
8
+ * Build esbuild/rollup baseline configs for plugin worker, manifest, and UI bundles.
9
+ *
10
+ * The presets intentionally externalize host/runtime deps (`react`, SDK packages)
11
+ * to match the Paperclip plugin loader contract.
12
+ */
13
+ export function createPluginBundlerPresets(input = {}) {
14
+ const uiExternal = [
15
+ "@paperclipai/plugin-sdk/ui",
16
+ "@paperclipai/plugin-sdk/ui/hooks",
17
+ "react",
18
+ "react-dom",
19
+ "react/jsx-runtime",
20
+ ];
21
+ const outdir = input.outdir ?? "dist";
22
+ const workerEntry = input.workerEntry ?? "src/worker.ts";
23
+ const manifestEntry = input.manifestEntry ?? "src/manifest.ts";
24
+ const uiEntry = input.uiEntry;
25
+ const sourcemap = input.sourcemap ?? true;
26
+ const minify = input.minify ?? false;
27
+ const esbuildWorker = {
28
+ entryPoints: [workerEntry],
29
+ outdir,
30
+ bundle: true,
31
+ format: "esm",
32
+ platform: "node",
33
+ target: "node20",
34
+ sourcemap,
35
+ minify,
36
+ external: ["react", "react-dom"],
37
+ };
38
+ const esbuildManifest = {
39
+ entryPoints: [manifestEntry],
40
+ outdir,
41
+ bundle: false,
42
+ format: "esm",
43
+ platform: "node",
44
+ target: "node20",
45
+ sourcemap,
46
+ };
47
+ const esbuildUi = uiEntry
48
+ ? {
49
+ entryPoints: [uiEntry],
50
+ outdir: `${outdir}/ui`,
51
+ bundle: true,
52
+ format: "esm",
53
+ platform: "browser",
54
+ target: "es2022",
55
+ sourcemap,
56
+ minify,
57
+ external: uiExternal,
58
+ }
59
+ : undefined;
60
+ const rollupWorker = {
61
+ input: workerEntry,
62
+ output: {
63
+ dir: outdir,
64
+ format: "es",
65
+ sourcemap,
66
+ entryFileNames: "worker.js",
67
+ },
68
+ external: ["react", "react-dom"],
69
+ };
70
+ const rollupManifest = {
71
+ input: manifestEntry,
72
+ output: {
73
+ dir: outdir,
74
+ format: "es",
75
+ sourcemap,
76
+ entryFileNames: "manifest.js",
77
+ },
78
+ external: ["@paperclipai/plugin-sdk"],
79
+ };
80
+ const rollupUi = uiEntry
81
+ ? {
82
+ input: uiEntry,
83
+ output: {
84
+ dir: `${outdir}/ui`,
85
+ format: "es",
86
+ sourcemap,
87
+ entryFileNames: "index.js",
88
+ },
89
+ external: uiExternal,
90
+ }
91
+ : undefined;
92
+ return {
93
+ esbuild: {
94
+ worker: esbuildWorker,
95
+ manifest: esbuildManifest,
96
+ ...(esbuildUi ? { ui: esbuildUi } : {}),
97
+ },
98
+ rollup: {
99
+ worker: rollupWorker,
100
+ manifest: rollupManifest,
101
+ ...(rollupUi ? { ui: rollupUi } : {}),
102
+ },
103
+ };
104
+ }
105
+ //# sourceMappingURL=bundlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundlers.js","sourceRoot":"","sources":["../src/bundlers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiDH;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAkC,EAAE;IAC7E,MAAM,UAAU,GAAG;QACjB,4BAA4B;QAC5B,kCAAkC;QAClC,OAAO;QACP,WAAW;QACX,mBAAmB;KACpB,CAAC;IAEF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC;IACtC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,eAAe,CAAC;IACzD,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa,IAAI,iBAAiB,CAAC;IAC/D,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC;IAC1C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC;IAErC,MAAM,aAAa,GAAuB;QACxC,WAAW,EAAE,CAAC,WAAW,CAAC;QAC1B,MAAM;QACN,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,SAAS;QACT,MAAM;QACN,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;KACjC,CAAC;IAEF,MAAM,eAAe,GAAuB;QAC1C,WAAW,EAAE,CAAC,aAAa,CAAC;QAC5B,MAAM;QACN,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,KAAK;QACb,QAAQ,EAAE,MAAM;QAChB,MAAM,EAAE,QAAQ;QAChB,SAAS;KACV,CAAC;IAEF,MAAM,SAAS,GAAG,OAAO;QACvB,CAAC,CAAC;YACA,WAAW,EAAE,CAAC,OAAO,CAAC;YACtB,MAAM,EAAE,GAAG,MAAM,KAAK;YACtB,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,KAAc;YACtB,QAAQ,EAAE,SAAkB;YAC5B,MAAM,EAAE,QAAQ;YAChB,SAAS;YACT,MAAM;YACN,QAAQ,EAAE,UAAU;SACrB;QACD,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,YAAY,GAAqB;QACrC,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE;YACN,GAAG,EAAE,MAAM;YACX,MAAM,EAAE,IAAI;YACZ,SAAS;YACT,cAAc,EAAE,WAAW;SAC5B;QACD,QAAQ,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC;KACjC,CAAC;IAEF,MAAM,cAAc,GAAqB;QACvC,KAAK,EAAE,aAAa;QACpB,MAAM,EAAE;YACN,GAAG,EAAE,MAAM;YACX,MAAM,EAAE,IAAI;YACZ,SAAS;YACT,cAAc,EAAE,aAAa;SAC9B;QACD,QAAQ,EAAE,CAAC,yBAAyB,CAAC;KACtC,CAAC;IAEF,MAAM,QAAQ,GAAG,OAAO;QACtB,CAAC,CAAC;YACA,KAAK,EAAE,OAAO;YACd,MAAM,EAAE;gBACN,GAAG,EAAE,GAAG,MAAM,KAAK;gBACnB,MAAM,EAAE,IAAa;gBACrB,SAAS;gBACT,cAAc,EAAE,UAAU;aAC3B;YACD,QAAQ,EAAE,UAAU;SACrB;QACD,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,OAAO,EAAE;YACP,MAAM,EAAE,aAAa;YACrB,QAAQ,EAAE,eAAe;YACzB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxC;QACD,MAAM,EAAE;YACN,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,cAAc;YACxB,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * `definePlugin` — the top-level helper for authoring a Paperclip plugin.
3
+ *
4
+ * Plugin authors call `definePlugin()` and export the result as the default
5
+ * export from their worker entrypoint. The host imports the worker module,
6
+ * calls `setup()` with a `PluginContext`, and from that point the plugin
7
+ * responds to events, jobs, webhooks, and UI requests through the context.
8
+ *
9
+ * @see PLUGIN_SPEC.md §14.1 — Example SDK Shape
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // dist/worker.ts
14
+ * import { definePlugin } from "@paperclipai/plugin-sdk";
15
+ *
16
+ * export default definePlugin({
17
+ * async setup(ctx) {
18
+ * ctx.logger.info("Linear sync plugin starting");
19
+ *
20
+ * // Subscribe to events
21
+ * ctx.events.on("issue.created", async (event) => {
22
+ * const config = await ctx.config.get();
23
+ * await ctx.http.fetch(`https://api.linear.app/...`, {
24
+ * method: "POST",
25
+ * headers: { Authorization: `Bearer ${await ctx.secrets.resolve(config.apiKeyRef as string)}` },
26
+ * body: JSON.stringify({ title: event.payload.title }),
27
+ * });
28
+ * });
29
+ *
30
+ * // Register a job handler
31
+ * ctx.jobs.register("full-sync", async (job) => {
32
+ * ctx.logger.info("Running full-sync job", { runId: job.runId });
33
+ * // ... sync logic
34
+ * });
35
+ *
36
+ * // Register data for the UI
37
+ * ctx.data.register("sync-health", async ({ companyId }) => {
38
+ * const state = await ctx.state.get({
39
+ * scopeKind: "company",
40
+ * scopeId: String(companyId),
41
+ * stateKey: "last-sync",
42
+ * });
43
+ * return { lastSync: state };
44
+ * });
45
+ * },
46
+ * });
47
+ * ```
48
+ */
49
+ import type { PluginContext } from "./types.js";
50
+ /**
51
+ * Optional plugin-reported diagnostics returned from the `health()` RPC method.
52
+ *
53
+ * @see PLUGIN_SPEC.md §13.2 — `health`
54
+ */
55
+ export interface PluginHealthDiagnostics {
56
+ /** Machine-readable status: `"ok"` | `"degraded"` | `"error"`. */
57
+ status: "ok" | "degraded" | "error";
58
+ /** Human-readable description of the current health state. */
59
+ message?: string;
60
+ /** Plugin-reported key-value diagnostics (e.g. connection status, queue depth). */
61
+ details?: Record<string, unknown>;
62
+ }
63
+ /**
64
+ * Result returned from the `validateConfig()` RPC method.
65
+ *
66
+ * @see PLUGIN_SPEC.md §13.3 — `validateConfig`
67
+ */
68
+ export interface PluginConfigValidationResult {
69
+ /** Whether the config is valid. */
70
+ ok: boolean;
71
+ /** Non-fatal warnings about the config. */
72
+ warnings?: string[];
73
+ /** Validation errors (populated when `ok` is `false`). */
74
+ errors?: string[];
75
+ }
76
+ /**
77
+ * Input received by the plugin worker's `handleWebhook` handler.
78
+ *
79
+ * @see PLUGIN_SPEC.md §13.7 — `handleWebhook`
80
+ */
81
+ export interface PluginWebhookInput {
82
+ /** Endpoint key matching the manifest declaration. */
83
+ endpointKey: string;
84
+ /** Inbound request headers. */
85
+ headers: Record<string, string | string[]>;
86
+ /** Raw request body as a UTF-8 string. */
87
+ rawBody: string;
88
+ /** Parsed JSON body (if applicable and parseable). */
89
+ parsedBody?: unknown;
90
+ /** Unique request identifier for idempotency checks. */
91
+ requestId: string;
92
+ }
93
+ /**
94
+ * The plugin definition shape passed to `definePlugin()`.
95
+ *
96
+ * The only required field is `setup`, which receives the `PluginContext` and
97
+ * is where the plugin registers its handlers (events, jobs, data, actions,
98
+ * tools, etc.).
99
+ *
100
+ * All other lifecycle hooks are optional. If a hook is not implemented the
101
+ * host applies default behaviour (e.g. restarting the worker on config change
102
+ * instead of calling `onConfigChanged`).
103
+ *
104
+ * @see PLUGIN_SPEC.md §13 — Host-Worker Protocol
105
+ */
106
+ export interface PluginDefinition {
107
+ /**
108
+ * Called once when the plugin worker starts up, after `initialize` completes.
109
+ *
110
+ * This is where the plugin registers all its handlers: event subscriptions,
111
+ * job handlers, data/action handlers, and tool registrations. Registration
112
+ * must be synchronous after `setup` resolves — do not register handlers
113
+ * inside async callbacks that may resolve after `setup` returns.
114
+ *
115
+ * @param ctx - The full plugin context provided by the host
116
+ */
117
+ setup(ctx: PluginContext): Promise<void>;
118
+ /**
119
+ * Called when the host wants to know if the plugin is healthy.
120
+ *
121
+ * The host polls this on a regular interval and surfaces the result in the
122
+ * plugin health dashboard. If not implemented, the host infers health from
123
+ * worker process liveness.
124
+ *
125
+ * @see PLUGIN_SPEC.md §13.2 — `health`
126
+ */
127
+ onHealth?(): Promise<PluginHealthDiagnostics>;
128
+ /**
129
+ * Called when the operator updates the plugin's instance configuration at
130
+ * runtime, without restarting the worker.
131
+ *
132
+ * If not implemented, the host restarts the worker to apply the new config.
133
+ *
134
+ * @param newConfig - The newly resolved configuration
135
+ * @see PLUGIN_SPEC.md §13.4 — `configChanged`
136
+ */
137
+ onConfigChanged?(newConfig: Record<string, unknown>): Promise<void>;
138
+ /**
139
+ * Called when the host is about to shut down the plugin worker.
140
+ *
141
+ * The worker has at most 10 seconds (configurable via plugin config) to
142
+ * finish in-flight work and resolve this promise. After the deadline the
143
+ * host sends SIGTERM, then SIGKILL.
144
+ *
145
+ * @see PLUGIN_SPEC.md §12.5 — Graceful Shutdown Policy
146
+ */
147
+ onShutdown?(): Promise<void>;
148
+ /**
149
+ * Called to validate the current plugin configuration.
150
+ *
151
+ * The host calls this:
152
+ * - after the plugin starts (to surface config errors immediately)
153
+ * - after the operator saves a new config (to validate before persisting)
154
+ * - via the "Test Connection" button in the settings UI
155
+ *
156
+ * @param config - The configuration to validate
157
+ * @see PLUGIN_SPEC.md §13.3 — `validateConfig`
158
+ */
159
+ onValidateConfig?(config: Record<string, unknown>): Promise<PluginConfigValidationResult>;
160
+ /**
161
+ * Called to handle an inbound webhook delivery.
162
+ *
163
+ * The host routes `POST /api/plugins/:pluginId/webhooks/:endpointKey` to
164
+ * this handler. The plugin is responsible for signature verification using
165
+ * a resolved secret ref.
166
+ *
167
+ * If not implemented but webhooks are declared in the manifest, the host
168
+ * returns HTTP 501 for webhook deliveries.
169
+ *
170
+ * @param input - Webhook delivery metadata and payload
171
+ * @see PLUGIN_SPEC.md §13.7 — `handleWebhook`
172
+ */
173
+ onWebhook?(input: PluginWebhookInput): Promise<void>;
174
+ }
175
+ /**
176
+ * The sealed plugin object returned by `definePlugin()`.
177
+ *
178
+ * Plugin authors export this as the default export from their worker
179
+ * entrypoint. The host imports it and calls the lifecycle methods.
180
+ *
181
+ * @see PLUGIN_SPEC.md §14 — SDK Surface
182
+ */
183
+ export interface PaperclipPlugin {
184
+ /** The original plugin definition passed to `definePlugin()`. */
185
+ readonly definition: PluginDefinition;
186
+ }
187
+ /**
188
+ * Define a Paperclip plugin.
189
+ *
190
+ * Call this function in your worker entrypoint and export the result as the
191
+ * default export. The host will import the module and call lifecycle methods
192
+ * on the returned object.
193
+ *
194
+ * @param definition - Plugin lifecycle handlers
195
+ * @returns A sealed `PaperclipPlugin` object for the host to consume
196
+ *
197
+ * @example
198
+ * ```ts
199
+ * import { definePlugin } from "@paperclipai/plugin-sdk";
200
+ *
201
+ * export default definePlugin({
202
+ * async setup(ctx) {
203
+ * ctx.logger.info("Plugin started");
204
+ * ctx.events.on("issue.created", async (event) => {
205
+ * // handle event
206
+ * });
207
+ * },
208
+ *
209
+ * async onHealth() {
210
+ * return { status: "ok" };
211
+ * },
212
+ * });
213
+ * ```
214
+ *
215
+ * @see PLUGIN_SPEC.md §14.1 — Example SDK Shape
216
+ */
217
+ export declare function definePlugin(definition: PluginDefinition): PaperclipPlugin;
218
+ //# sourceMappingURL=define-plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-plugin.d.ts","sourceRoot":"","sources":["../src/define-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAMhD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,kEAAkE;IAClE,MAAM,EAAE,IAAI,GAAG,UAAU,GAAG,OAAO,CAAC;IACpC,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAMD;;;;GAIG;AACH,MAAM,WAAW,4BAA4B;IAC3C,mCAAmC;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAMD;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC3C,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;;;OASG;IACH,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzC;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE9C;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpE;;;;;;;;OAQG;IACH,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAC;IAE1F;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AAMD;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;CACvC;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,gBAAgB,GAAG,eAAe,CAE1E"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * `definePlugin` — the top-level helper for authoring a Paperclip plugin.
3
+ *
4
+ * Plugin authors call `definePlugin()` and export the result as the default
5
+ * export from their worker entrypoint. The host imports the worker module,
6
+ * calls `setup()` with a `PluginContext`, and from that point the plugin
7
+ * responds to events, jobs, webhooks, and UI requests through the context.
8
+ *
9
+ * @see PLUGIN_SPEC.md §14.1 — Example SDK Shape
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // dist/worker.ts
14
+ * import { definePlugin } from "@paperclipai/plugin-sdk";
15
+ *
16
+ * export default definePlugin({
17
+ * async setup(ctx) {
18
+ * ctx.logger.info("Linear sync plugin starting");
19
+ *
20
+ * // Subscribe to events
21
+ * ctx.events.on("issue.created", async (event) => {
22
+ * const config = await ctx.config.get();
23
+ * await ctx.http.fetch(`https://api.linear.app/...`, {
24
+ * method: "POST",
25
+ * headers: { Authorization: `Bearer ${await ctx.secrets.resolve(config.apiKeyRef as string)}` },
26
+ * body: JSON.stringify({ title: event.payload.title }),
27
+ * });
28
+ * });
29
+ *
30
+ * // Register a job handler
31
+ * ctx.jobs.register("full-sync", async (job) => {
32
+ * ctx.logger.info("Running full-sync job", { runId: job.runId });
33
+ * // ... sync logic
34
+ * });
35
+ *
36
+ * // Register data for the UI
37
+ * ctx.data.register("sync-health", async ({ companyId }) => {
38
+ * const state = await ctx.state.get({
39
+ * scopeKind: "company",
40
+ * scopeId: String(companyId),
41
+ * stateKey: "last-sync",
42
+ * });
43
+ * return { lastSync: state };
44
+ * });
45
+ * },
46
+ * });
47
+ * ```
48
+ */
49
+ // ---------------------------------------------------------------------------
50
+ // definePlugin — top-level factory
51
+ // ---------------------------------------------------------------------------
52
+ /**
53
+ * Define a Paperclip plugin.
54
+ *
55
+ * Call this function in your worker entrypoint and export the result as the
56
+ * default export. The host will import the module and call lifecycle methods
57
+ * on the returned object.
58
+ *
59
+ * @param definition - Plugin lifecycle handlers
60
+ * @returns A sealed `PaperclipPlugin` object for the host to consume
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * import { definePlugin } from "@paperclipai/plugin-sdk";
65
+ *
66
+ * export default definePlugin({
67
+ * async setup(ctx) {
68
+ * ctx.logger.info("Plugin started");
69
+ * ctx.events.on("issue.created", async (event) => {
70
+ * // handle event
71
+ * });
72
+ * },
73
+ *
74
+ * async onHealth() {
75
+ * return { status: "ok" };
76
+ * },
77
+ * });
78
+ * ```
79
+ *
80
+ * @see PLUGIN_SPEC.md §14.1 — Example SDK Shape
81
+ */
82
+ export function definePlugin(definition) {
83
+ return Object.freeze({ definition });
84
+ }
85
+ //# sourceMappingURL=define-plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-plugin.js","sourceRoot":"","sources":["../src/define-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AA2KH,8EAA8E;AAC9E,mCAAmC;AACnC,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,YAAY,CAAC,UAA4B;IACvD,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=dev-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-cli.d.ts","sourceRoot":"","sources":["../src/dev-cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+ import path from "node:path";
3
+ import { startPluginDevServer } from "./dev-server.js";
4
+ function parseArg(flag) {
5
+ const index = process.argv.indexOf(flag);
6
+ if (index < 0)
7
+ return undefined;
8
+ return process.argv[index + 1];
9
+ }
10
+ /**
11
+ * CLI entrypoint for the local plugin UI preview server.
12
+ *
13
+ * This is intentionally minimal and delegates all serving behavior to
14
+ * `startPluginDevServer` so tests and programmatic usage share one path.
15
+ */
16
+ async function main() {
17
+ const rootDir = parseArg("--root") ?? process.cwd();
18
+ const uiDir = parseArg("--ui-dir") ?? "dist/ui";
19
+ const host = parseArg("--host") ?? "127.0.0.1";
20
+ const rawPort = parseArg("--port") ?? "4177";
21
+ const port = Number.parseInt(rawPort, 10);
22
+ if (!Number.isFinite(port) || port <= 0 || port > 65535) {
23
+ throw new Error(`Invalid --port value: ${rawPort}`);
24
+ }
25
+ const server = await startPluginDevServer({
26
+ rootDir: path.resolve(rootDir),
27
+ uiDir,
28
+ host,
29
+ port,
30
+ });
31
+ // eslint-disable-next-line no-console
32
+ console.log(`Paperclip plugin dev server listening at ${server.url}`);
33
+ const shutdown = async () => {
34
+ await server.close();
35
+ process.exit(0);
36
+ };
37
+ process.on("SIGINT", () => {
38
+ void shutdown();
39
+ });
40
+ process.on("SIGTERM", () => {
41
+ void shutdown();
42
+ });
43
+ }
44
+ void main().catch((error) => {
45
+ // eslint-disable-next-line no-console
46
+ console.error(error instanceof Error ? error.message : String(error));
47
+ process.exit(1);
48
+ });
49
+ //# sourceMappingURL=dev-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-cli.js","sourceRoot":"","sources":["../src/dev-cli.ts"],"names":[],"mappings":";AACA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAEvD,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAChC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACpD,MAAM,KAAK,GAAG,QAAQ,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,WAAW,CAAC;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,yBAAyB,OAAO,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,oBAAoB,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;QAC9B,KAAK;QACL,IAAI;QACJ,IAAI;KACL,CAAC,CAAC;IAEH,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,4CAA4C,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC;IAEtE,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,KAAK,QAAQ,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,KAAK,QAAQ,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC1B,sCAAsC;IACtC,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ export interface PluginDevServerOptions {
2
+ /** Plugin project root. Defaults to `process.cwd()`. */
3
+ rootDir?: string;
4
+ /** Relative path from root to built UI assets. Defaults to `dist/ui`. */
5
+ uiDir?: string;
6
+ /** Bind port for local preview server. Defaults to `4177`. */
7
+ port?: number;
8
+ /** Bind host. Defaults to `127.0.0.1`. */
9
+ host?: string;
10
+ }
11
+ export interface PluginDevServer {
12
+ url: string;
13
+ close(): Promise<void>;
14
+ }
15
+ /**
16
+ * Start a local static server for plugin UI assets with SSE reload events.
17
+ *
18
+ * Endpoint summary:
19
+ * - `GET /__paperclip__/health` for diagnostics
20
+ * - `GET /__paperclip__/events` for hot-reload stream
21
+ * - Any other path serves files from the configured UI build directory
22
+ */
23
+ export declare function startPluginDevServer(options?: PluginDevServerOptions): Promise<PluginDevServer>;
24
+ /**
25
+ * Return a stable file+mtime snapshot for a built plugin UI directory.
26
+ *
27
+ * Used by the polling watcher fallback and useful for tests that need to assert
28
+ * whether a UI build has changed between runs.
29
+ */
30
+ export declare function getUiBuildSnapshot(rootDir: string, uiDir?: string): Promise<Array<{
31
+ file: string;
32
+ mtimeMs: number;
33
+ }>>;
34
+ //# sourceMappingURL=dev-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dev-server.d.ts","sourceRoot":"","sources":["../src/dev-server.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,sBAAsB;IACrC,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAkGD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,GAAE,sBAA2B,GAAG,OAAO,CAAC,eAAe,CAAC,CAiFzG;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAY,GAAG,OAAO,CAAC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAY9H"}