@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,982 @@
1
+ /**
2
+ * Core types for the Paperclip plugin worker-side SDK.
3
+ *
4
+ * These types define the stable public API surface that plugin workers import
5
+ * from `@paperclipai/plugin-sdk`. The host provides a concrete implementation
6
+ * of `PluginContext` to the plugin at initialisation time.
7
+ *
8
+ * @see PLUGIN_SPEC.md §14 — SDK Surface
9
+ * @see PLUGIN_SPEC.md §29.2 — SDK Versioning
10
+ */
11
+ import type { PaperclipPluginManifestV1, PluginStateScopeKind, PluginEventType, PluginToolDeclaration, PluginLauncherDeclaration, Company, Project, Issue, IssueComment, IssueDocument, IssueDocumentSummary, Agent, Goal } from "@paperclipai/shared";
12
+ export type { PaperclipPluginManifestV1, PluginJobDeclaration, PluginWebhookDeclaration, PluginToolDeclaration, PluginUiSlotDeclaration, PluginUiDeclaration, PluginLauncherActionDeclaration, PluginLauncherRenderDeclaration, PluginLauncherDeclaration, PluginMinimumHostVersion, PluginRecord, PluginConfig, JsonSchema, PluginStatus, PluginCategory, PluginCapability, PluginUiSlotType, PluginUiSlotEntityType, PluginLauncherPlacementZone, PluginLauncherAction, PluginLauncherBounds, PluginLauncherRenderEnvironment, PluginStateScopeKind, PluginJobStatus, PluginJobRunStatus, PluginJobRunTrigger, PluginWebhookDeliveryStatus, PluginEventType, PluginBridgeErrorCode, Company, Project, Issue, IssueComment, IssueDocument, IssueDocumentSummary, Agent, Goal, } from "@paperclipai/shared";
13
+ /**
14
+ * A scope key identifies the exact location where plugin state is stored.
15
+ * Scope is partitioned by `scopeKind` and optional `scopeId`.
16
+ *
17
+ * Examples:
18
+ * - `{ scopeKind: "instance" }` — single global value for the whole instance
19
+ * - `{ scopeKind: "project", scopeId: "proj-uuid" }` — per-project state
20
+ * - `{ scopeKind: "issue", scopeId: "iss-uuid" }` — per-issue state
21
+ *
22
+ * @see PLUGIN_SPEC.md §21.3 `plugin_state`
23
+ */
24
+ export interface ScopeKey {
25
+ /** What kind of Paperclip object this state is scoped to. */
26
+ scopeKind: PluginStateScopeKind;
27
+ /** UUID or text identifier for the scoped object. Omit for `instance` scope. */
28
+ scopeId?: string;
29
+ /** Optional sub-namespace within the scope to avoid key collisions. Defaults to `"default"`. */
30
+ namespace?: string;
31
+ /** The state key within the namespace. */
32
+ stateKey: string;
33
+ }
34
+ /**
35
+ * Optional filter applied when subscribing to an event. The host evaluates
36
+ * the filter server-side so filtered-out events never cross the process boundary.
37
+ *
38
+ * All filter fields are optional. If omitted the plugin receives every event
39
+ * of the subscribed type.
40
+ *
41
+ * @see PLUGIN_SPEC.md §16.1 — Event Filtering
42
+ */
43
+ export interface EventFilter {
44
+ /** Only receive events for this project. */
45
+ projectId?: string;
46
+ /** Only receive events for this company. */
47
+ companyId?: string;
48
+ /** Only receive events for this agent. */
49
+ agentId?: string;
50
+ /** Additional arbitrary filter fields. */
51
+ [key: string]: unknown;
52
+ }
53
+ /**
54
+ * Envelope wrapping every domain event delivered to a plugin worker.
55
+ *
56
+ * @see PLUGIN_SPEC.md §16 — Event System
57
+ */
58
+ export interface PluginEvent<TPayload = unknown> {
59
+ /** Unique event identifier (UUID). */
60
+ eventId: string;
61
+ /** The event type (e.g. `"issue.created"`). */
62
+ eventType: PluginEventType | `plugin.${string}`;
63
+ /** ISO 8601 timestamp when the event occurred. */
64
+ occurredAt: string;
65
+ /** ID of the actor that caused the event, if applicable. */
66
+ actorId?: string;
67
+ /** Type of actor: `"user"`, `"agent"`, `"system"`, or `"plugin"`. */
68
+ actorType?: "user" | "agent" | "system" | "plugin";
69
+ /** Primary entity involved in the event. */
70
+ entityId?: string;
71
+ /** Type of the primary entity. */
72
+ entityType?: string;
73
+ /** UUID of the company this event belongs to. */
74
+ companyId: string;
75
+ /** Typed event payload. */
76
+ payload: TPayload;
77
+ }
78
+ /**
79
+ * Context passed to a plugin job handler when the host triggers a scheduled run.
80
+ *
81
+ * @see PLUGIN_SPEC.md §13.6 — `runJob`
82
+ */
83
+ export interface PluginJobContext {
84
+ /** Stable job key matching the declaration in the manifest. */
85
+ jobKey: string;
86
+ /** UUID for this specific job run instance. */
87
+ runId: string;
88
+ /** What triggered this run. */
89
+ trigger: "schedule" | "manual" | "retry";
90
+ /** ISO 8601 timestamp when the run was scheduled to start. */
91
+ scheduledAt: string;
92
+ }
93
+ /**
94
+ * Run context passed to a plugin tool handler when an agent invokes the tool.
95
+ *
96
+ * @see PLUGIN_SPEC.md §13.10 — `executeTool`
97
+ */
98
+ export interface ToolRunContext {
99
+ /** UUID of the agent invoking the tool. */
100
+ agentId: string;
101
+ /** UUID of the current agent run. */
102
+ runId: string;
103
+ /** UUID of the company the run belongs to. */
104
+ companyId: string;
105
+ /** UUID of the project the run belongs to. */
106
+ projectId: string;
107
+ }
108
+ /**
109
+ * Result returned from a plugin tool handler.
110
+ *
111
+ * @see PLUGIN_SPEC.md §13.10 — `executeTool`
112
+ */
113
+ export interface ToolResult {
114
+ /** String content returned to the agent. Required for success responses. */
115
+ content?: string;
116
+ /** Structured data returned alongside or instead of string content. */
117
+ data?: unknown;
118
+ /** If present, indicates the tool call failed. */
119
+ error?: string;
120
+ }
121
+ /**
122
+ * Input for creating or updating a plugin-owned entity.
123
+ *
124
+ * @see PLUGIN_SPEC.md §21.3 `plugin_entities`
125
+ */
126
+ export interface PluginEntityUpsert {
127
+ /** Plugin-defined entity type (e.g. `"linear-issue"`, `"github-pr"`). */
128
+ entityType: string;
129
+ /** Scope where this entity lives. */
130
+ scopeKind: PluginStateScopeKind;
131
+ /** Optional scope ID. */
132
+ scopeId?: string;
133
+ /** External identifier in the remote system (e.g. Linear issue ID). */
134
+ externalId?: string;
135
+ /** Human-readable title for display in the Paperclip UI. */
136
+ title?: string;
137
+ /** Optional status string. */
138
+ status?: string;
139
+ /** Full entity data blob. Must be JSON-serializable. */
140
+ data: Record<string, unknown>;
141
+ }
142
+ /**
143
+ * A plugin-owned entity record as returned by `ctx.entities.list()`.
144
+ *
145
+ * @see PLUGIN_SPEC.md §21.3 `plugin_entities`
146
+ */
147
+ export interface PluginEntityRecord {
148
+ /** UUID primary key. */
149
+ id: string;
150
+ /** Plugin-defined entity type. */
151
+ entityType: string;
152
+ /** Scope kind. */
153
+ scopeKind: PluginStateScopeKind;
154
+ /** Scope ID, if any. */
155
+ scopeId: string | null;
156
+ /** External identifier, if any. */
157
+ externalId: string | null;
158
+ /** Human-readable title. */
159
+ title: string | null;
160
+ /** Status string. */
161
+ status: string | null;
162
+ /** Full entity data. */
163
+ data: Record<string, unknown>;
164
+ /** ISO 8601 creation timestamp. */
165
+ createdAt: string;
166
+ /** ISO 8601 last-updated timestamp. */
167
+ updatedAt: string;
168
+ }
169
+ /**
170
+ * Query parameters for `ctx.entities.list()`.
171
+ */
172
+ export interface PluginEntityQuery {
173
+ /** Filter by entity type. */
174
+ entityType?: string;
175
+ /** Filter by scope kind. */
176
+ scopeKind?: PluginStateScopeKind;
177
+ /** Filter by scope ID. */
178
+ scopeId?: string;
179
+ /** Filter by external ID. */
180
+ externalId?: string;
181
+ /** Maximum number of results to return. */
182
+ limit?: number;
183
+ /** Number of results to skip (for pagination). */
184
+ offset?: number;
185
+ }
186
+ /**
187
+ * Workspace metadata provided by the host. Plugins use this to resolve local
188
+ * filesystem paths for file browsing, git, terminal, and process operations.
189
+ *
190
+ * @see PLUGIN_SPEC.md §7 — Project Workspaces
191
+ * @see PLUGIN_SPEC.md §20 — Local Tooling
192
+ */
193
+ export interface PluginWorkspace {
194
+ /** UUID primary key. */
195
+ id: string;
196
+ /** UUID of the parent project. */
197
+ projectId: string;
198
+ /** Display name for this workspace. */
199
+ name: string;
200
+ /** Absolute filesystem path to the workspace directory. */
201
+ path: string;
202
+ /** Whether this is the project's primary workspace. */
203
+ isPrimary: boolean;
204
+ /** ISO 8601 creation timestamp. */
205
+ createdAt: string;
206
+ /** ISO 8601 last-updated timestamp. */
207
+ updatedAt: string;
208
+ }
209
+ /**
210
+ * `ctx.config` — read resolved operator configuration for this plugin.
211
+ *
212
+ * Plugin workers receive the resolved config at initialisation. Use `get()`
213
+ * to access the current configuration at any time. The host calls
214
+ * `configChanged` on the worker when the operator updates config at runtime.
215
+ *
216
+ * @see PLUGIN_SPEC.md §13.3 — `validateConfig`
217
+ * @see PLUGIN_SPEC.md §13.4 — `configChanged`
218
+ */
219
+ export interface PluginConfigClient {
220
+ /**
221
+ * Returns the resolved operator configuration for this plugin instance.
222
+ * Values are validated against the plugin's `instanceConfigSchema` by the
223
+ * host before being passed to the worker.
224
+ */
225
+ get(): Promise<Record<string, unknown>>;
226
+ }
227
+ /**
228
+ * `ctx.events` — subscribe to and emit Paperclip domain events.
229
+ *
230
+ * Requires `events.subscribe` capability for `on()`.
231
+ * Requires `events.emit` capability for `emit()`.
232
+ *
233
+ * @see PLUGIN_SPEC.md §16 — Event System
234
+ */
235
+ export interface PluginEventsClient {
236
+ /**
237
+ * Subscribe to a core Paperclip domain event or a plugin-namespaced event.
238
+ *
239
+ * @param name - Event type, e.g. `"issue.created"` or `"plugin.@acme/linear.sync-done"`
240
+ * @param fn - Async event handler
241
+ */
242
+ on(name: PluginEventType | `plugin.${string}`, fn: (event: PluginEvent) => Promise<void>): () => void;
243
+ /**
244
+ * Subscribe to an event with an optional server-side filter.
245
+ *
246
+ * @param name - Event type
247
+ * @param filter - Server-side filter evaluated before dispatching to the worker
248
+ * @param fn - Async event handler
249
+ * @returns An unsubscribe function that removes the handler
250
+ */
251
+ on(name: PluginEventType | `plugin.${string}`, filter: EventFilter, fn: (event: PluginEvent) => Promise<void>): () => void;
252
+ /**
253
+ * Emit a plugin-namespaced event. Other plugins with `events.subscribe` can
254
+ * subscribe to it using `"plugin.<pluginId>.<eventName>"`.
255
+ *
256
+ * Requires the `events.emit` capability.
257
+ *
258
+ * Plugin-emitted events are automatically namespaced: if the plugin ID is
259
+ * `"acme.linear"` and the event name is `"sync-done"`, the full event type
260
+ * becomes `"plugin.acme.linear.sync-done"`.
261
+ *
262
+ * @see PLUGIN_SPEC.md §16.2 — Plugin-to-Plugin Events
263
+ *
264
+ * @param name - Bare event name (e.g. `"sync-done"`)
265
+ * @param companyId - UUID of the company this event belongs to
266
+ * @param payload - JSON-serializable event payload
267
+ */
268
+ emit(name: string, companyId: string, payload: unknown): Promise<void>;
269
+ }
270
+ /**
271
+ * `ctx.jobs` — register handlers for scheduled jobs declared in the manifest.
272
+ *
273
+ * Requires `jobs.schedule` capability.
274
+ *
275
+ * @see PLUGIN_SPEC.md §17 — Scheduled Jobs
276
+ */
277
+ export interface PluginJobsClient {
278
+ /**
279
+ * Register a handler for a scheduled job.
280
+ *
281
+ * The `key` must match a `jobKey` declared in the plugin manifest.
282
+ * The host calls this handler according to the job's declared `schedule`.
283
+ *
284
+ * @param key - Job key matching the manifest declaration
285
+ * @param fn - Async job handler
286
+ */
287
+ register(key: string, fn: (job: PluginJobContext) => Promise<void>): void;
288
+ }
289
+ /**
290
+ * A runtime launcher registration uses the same declaration shape as a
291
+ * manifest launcher entry.
292
+ */
293
+ export type PluginLauncherRegistration = PluginLauncherDeclaration;
294
+ /**
295
+ * `ctx.launchers` — register launcher declarations at runtime.
296
+ */
297
+ export interface PluginLaunchersClient {
298
+ /**
299
+ * Register launcher metadata for host discovery.
300
+ *
301
+ * If a launcher with the same id is registered more than once, the latest
302
+ * declaration replaces the previous one.
303
+ */
304
+ register(launcher: PluginLauncherRegistration): void;
305
+ }
306
+ /**
307
+ * `ctx.http` — make outbound HTTP requests.
308
+ *
309
+ * Requires `http.outbound` capability.
310
+ *
311
+ * @see PLUGIN_SPEC.md §15.1 — Capabilities: Runtime/Integration
312
+ */
313
+ export interface PluginHttpClient {
314
+ /**
315
+ * Perform an outbound HTTP request.
316
+ *
317
+ * The host enforces `http.outbound` capability before allowing the call.
318
+ * Plugins may also use standard Node `fetch` or other libraries directly —
319
+ * this client exists for host-managed tracing and audit logging.
320
+ *
321
+ * @param url - Target URL
322
+ * @param init - Standard `RequestInit` options
323
+ * @returns The response
324
+ */
325
+ fetch(url: string, init?: RequestInit): Promise<Response>;
326
+ }
327
+ /**
328
+ * `ctx.secrets` — resolve secret references.
329
+ *
330
+ * Requires `secrets.read-ref` capability.
331
+ *
332
+ * Plugins store secret *references* in their config (e.g. a secret name).
333
+ * This client resolves the reference through the Paperclip secret provider
334
+ * system and returns the resolved value at execution time.
335
+ *
336
+ * @see PLUGIN_SPEC.md §22 — Secrets
337
+ */
338
+ export interface PluginSecretsClient {
339
+ /**
340
+ * Resolve a secret reference to its current value.
341
+ *
342
+ * The reference is a string identifier pointing to a secret configured
343
+ * in the Paperclip secret provider (e.g. `"MY_API_KEY"`).
344
+ *
345
+ * Secret values are resolved at call time and must never be cached or
346
+ * written to logs, config, or other persistent storage.
347
+ *
348
+ * @param secretRef - The secret reference string from plugin config
349
+ * @returns The resolved secret value
350
+ */
351
+ resolve(secretRef: string): Promise<string>;
352
+ }
353
+ /**
354
+ * Input for writing a plugin activity log entry.
355
+ *
356
+ * @see PLUGIN_SPEC.md §21.4 — Activity Log Changes
357
+ */
358
+ export interface PluginActivityLogEntry {
359
+ /** UUID of the company this activity belongs to. Required for auditing. */
360
+ companyId: string;
361
+ /** Human-readable description of the activity. */
362
+ message: string;
363
+ /** Optional entity type this activity relates to. */
364
+ entityType?: string;
365
+ /** Optional entity ID this activity relates to. */
366
+ entityId?: string;
367
+ /** Optional additional metadata. */
368
+ metadata?: Record<string, unknown>;
369
+ }
370
+ /**
371
+ * `ctx.activity` — write plugin-originated activity log entries.
372
+ *
373
+ * Requires `activity.log.write` capability.
374
+ *
375
+ * @see PLUGIN_SPEC.md §21.4 — Activity Log Changes
376
+ */
377
+ export interface PluginActivityClient {
378
+ /**
379
+ * Write an activity log entry attributed to this plugin.
380
+ *
381
+ * The host writes the entry with `actor_type = plugin` and
382
+ * `actor_id = <pluginId>`.
383
+ *
384
+ * @param entry - The activity log entry to write
385
+ */
386
+ log(entry: PluginActivityLogEntry): Promise<void>;
387
+ }
388
+ /**
389
+ * `ctx.state` — read and write plugin-scoped key-value state.
390
+ *
391
+ * Each plugin gets an isolated namespace: state written by plugin A can never
392
+ * be read or overwritten by plugin B. Within a plugin, state is partitioned by
393
+ * a five-part composite key: `(pluginId, scopeKind, scopeId, namespace, stateKey)`.
394
+ *
395
+ * **Scope kinds**
396
+ *
397
+ * | `scopeKind` | `scopeId` | Typical use |
398
+ * |-------------|-----------|-------------|
399
+ * | `"instance"` | omit | Global flags, last full-sync timestamps |
400
+ * | `"company"` | company UUID | Per-company sync cursors |
401
+ * | `"project"` | project UUID | Per-project settings, branch tracking |
402
+ * | `"project_workspace"` | workspace UUID | Per-workspace state |
403
+ * | `"agent"` | agent UUID | Per-agent memory |
404
+ * | `"issue"` | issue UUID | Idempotency keys, linked external IDs |
405
+ * | `"goal"` | goal UUID | Per-goal progress |
406
+ * | `"run"` | run UUID | Per-run checkpoints |
407
+ *
408
+ * **Namespaces**
409
+ *
410
+ * The optional `namespace` field (default: `"default"`) lets you group related
411
+ * keys within a scope without risking collisions between different logical
412
+ * subsystems inside the same plugin.
413
+ *
414
+ * **Security**
415
+ *
416
+ * Never store resolved secret values. Store only secret references and resolve
417
+ * them at call time via `ctx.secrets.resolve()`.
418
+ *
419
+ * @example
420
+ * ```ts
421
+ * // Instance-global flag
422
+ * await ctx.state.set({ scopeKind: "instance", stateKey: "schema-version" }, 2);
423
+ *
424
+ * // Idempotency key per issue
425
+ * const synced = await ctx.state.get({ scopeKind: "issue", scopeId: issueId, stateKey: "synced-to-linear" });
426
+ * if (!synced) {
427
+ * await syncToLinear(issueId);
428
+ * await ctx.state.set({ scopeKind: "issue", scopeId: issueId, stateKey: "synced-to-linear" }, true);
429
+ * }
430
+ *
431
+ * // Per-project, namespaced for two integrations
432
+ * await ctx.state.set({ scopeKind: "project", scopeId: projectId, namespace: "linear", stateKey: "cursor" }, cursor);
433
+ * await ctx.state.set({ scopeKind: "project", scopeId: projectId, namespace: "github", stateKey: "last-event" }, eventId);
434
+ * ```
435
+ *
436
+ * `plugin.state.read` capability required for `get()`.
437
+ * `plugin.state.write` capability required for `set()` and `delete()`.
438
+ *
439
+ * @see PLUGIN_SPEC.md §21.3 `plugin_state`
440
+ */
441
+ export interface PluginStateClient {
442
+ /**
443
+ * Read a state value.
444
+ *
445
+ * Returns the stored JSON value as-is, or `null` if no entry has been set
446
+ * for this scope+key combination. Falsy values (`false`, `0`, `""`) are
447
+ * returned correctly and are not confused with "not set".
448
+ *
449
+ * @param input - Scope key identifying the entry to read
450
+ * @returns The stored JSON value, or `null` if no value has been set
451
+ */
452
+ get(input: ScopeKey): Promise<unknown>;
453
+ /**
454
+ * Write a state value. Creates the row if it does not exist; replaces it
455
+ * atomically (upsert) if it does. Safe to call concurrently.
456
+ *
457
+ * Any JSON-serializable value is accepted: objects, arrays, strings,
458
+ * numbers, booleans, and `null`.
459
+ *
460
+ * @param input - Scope key identifying the entry to write
461
+ * @param value - JSON-serializable value to store
462
+ */
463
+ set(input: ScopeKey, value: unknown): Promise<void>;
464
+ /**
465
+ * Delete a state value. No-ops silently if the entry does not exist
466
+ * (idempotent by design — safe to call without prior `get()`).
467
+ *
468
+ * @param input - Scope key identifying the entry to delete
469
+ */
470
+ delete(input: ScopeKey): Promise<void>;
471
+ }
472
+ /**
473
+ * `ctx.entities` — create and query plugin-owned entity records.
474
+ *
475
+ * @see PLUGIN_SPEC.md §21.3 `plugin_entities`
476
+ */
477
+ export interface PluginEntitiesClient {
478
+ /**
479
+ * Create or update a plugin entity record (upsert by `externalId` within
480
+ * the given scope, or by `id` if provided).
481
+ *
482
+ * @param input - Entity data to upsert
483
+ */
484
+ upsert(input: PluginEntityUpsert): Promise<PluginEntityRecord>;
485
+ /**
486
+ * Query plugin entity records.
487
+ *
488
+ * @param query - Filter criteria
489
+ * @returns Matching entity records
490
+ */
491
+ list(query: PluginEntityQuery): Promise<PluginEntityRecord[]>;
492
+ }
493
+ /**
494
+ * `ctx.projects` — read project and workspace metadata.
495
+ *
496
+ * Requires `projects.read` capability.
497
+ * Requires `project.workspaces.read` capability for workspace operations.
498
+ *
499
+ * @see PLUGIN_SPEC.md §7 — Project Workspaces
500
+ */
501
+ export interface PluginProjectsClient {
502
+ /**
503
+ * List projects visible to the plugin.
504
+ *
505
+ * Requires the `projects.read` capability.
506
+ */
507
+ list(input: {
508
+ companyId: string;
509
+ limit?: number;
510
+ offset?: number;
511
+ }): Promise<Project[]>;
512
+ /**
513
+ * Get a single project by ID.
514
+ *
515
+ * Requires the `projects.read` capability.
516
+ */
517
+ get(projectId: string, companyId: string): Promise<Project | null>;
518
+ /**
519
+ * List all workspaces attached to a project.
520
+ *
521
+ * @param projectId - UUID of the project
522
+ * @param companyId - UUID of the company that owns the project
523
+ * @returns All workspaces for the project, ordered with primary first
524
+ */
525
+ listWorkspaces(projectId: string, companyId: string): Promise<PluginWorkspace[]>;
526
+ /**
527
+ * Get the primary workspace for a project.
528
+ *
529
+ * @param projectId - UUID of the project
530
+ * @param companyId - UUID of the company that owns the project
531
+ * @returns The primary workspace, or `null` if no workspace is configured
532
+ */
533
+ getPrimaryWorkspace(projectId: string, companyId: string): Promise<PluginWorkspace | null>;
534
+ /**
535
+ * Resolve the primary workspace for an issue by looking up the issue's
536
+ * project and returning its primary workspace.
537
+ *
538
+ * This is a convenience method that combines `issues.get()` and
539
+ * `getPrimaryWorkspace()` in a single RPC call.
540
+ *
541
+ * @param issueId - UUID of the issue
542
+ * @param companyId - UUID of the company that owns the issue
543
+ * @returns The primary workspace for the issue's project, or `null` if
544
+ * the issue has no project or the project has no workspace
545
+ *
546
+ * @see PLUGIN_SPEC.md §20 — Local Tooling
547
+ */
548
+ getWorkspaceForIssue(issueId: string, companyId: string): Promise<PluginWorkspace | null>;
549
+ }
550
+ /**
551
+ * `ctx.data` — register `getData` handlers that back `usePluginData()` in the
552
+ * plugin's frontend components.
553
+ *
554
+ * The plugin's UI calls `usePluginData(key, params)` which routes through the
555
+ * host bridge to the worker's registered handler.
556
+ *
557
+ * @see PLUGIN_SPEC.md §13.8 — `getData`
558
+ */
559
+ export interface PluginDataClient {
560
+ /**
561
+ * Register a handler for a plugin-defined data key.
562
+ *
563
+ * @param key - Stable string identifier for this data type (e.g. `"sync-health"`)
564
+ * @param handler - Async function that receives request params and returns JSON-serializable data
565
+ */
566
+ register(key: string, handler: (params: Record<string, unknown>) => Promise<unknown>): void;
567
+ }
568
+ /**
569
+ * `ctx.actions` — register `performAction` handlers that back
570
+ * `usePluginAction()` in the plugin's frontend components.
571
+ *
572
+ * @see PLUGIN_SPEC.md §13.9 — `performAction`
573
+ */
574
+ export interface PluginActionsClient {
575
+ /**
576
+ * Register a handler for a plugin-defined action key.
577
+ *
578
+ * @param key - Stable string identifier for this action (e.g. `"resync"`)
579
+ * @param handler - Async function that receives action params and returns a result
580
+ */
581
+ register(key: string, handler: (params: Record<string, unknown>) => Promise<unknown>): void;
582
+ }
583
+ /**
584
+ * `ctx.tools` — register handlers for agent tools declared in the manifest.
585
+ *
586
+ * Requires `agent.tools.register` capability.
587
+ *
588
+ * Tool names are automatically namespaced by plugin ID at runtime.
589
+ *
590
+ * @see PLUGIN_SPEC.md §11 — Agent Tools
591
+ */
592
+ export interface PluginToolsClient {
593
+ /**
594
+ * Register a handler for a plugin-contributed agent tool.
595
+ *
596
+ * @param name - Tool name matching the manifest declaration (without namespace prefix)
597
+ * @param declaration - Tool metadata (displayName, description, parametersSchema)
598
+ * @param fn - Async handler that executes the tool
599
+ */
600
+ register(name: string, declaration: Pick<PluginToolDeclaration, "displayName" | "description" | "parametersSchema">, fn: (params: unknown, runCtx: ToolRunContext) => Promise<ToolResult>): void;
601
+ }
602
+ /**
603
+ * `ctx.logger` — structured logging from the plugin worker.
604
+ *
605
+ * Log output is captured by the host, stored, and surfaced in the plugin
606
+ * health dashboard.
607
+ *
608
+ * @see PLUGIN_SPEC.md §26.1 — Logging
609
+ */
610
+ export interface PluginLogger {
611
+ /** Log an informational message. */
612
+ info(message: string, meta?: Record<string, unknown>): void;
613
+ /** Log a warning. */
614
+ warn(message: string, meta?: Record<string, unknown>): void;
615
+ /** Log an error. */
616
+ error(message: string, meta?: Record<string, unknown>): void;
617
+ /** Log a debug message (may be suppressed in production). */
618
+ debug(message: string, meta?: Record<string, unknown>): void;
619
+ }
620
+ /**
621
+ * `ctx.metrics` — write plugin-contributed metrics.
622
+ *
623
+ * Requires `metrics.write` capability.
624
+ *
625
+ * @see PLUGIN_SPEC.md §15.1 — Capabilities: Data Write
626
+ */
627
+ export interface PluginMetricsClient {
628
+ /**
629
+ * Write a numeric metric data point.
630
+ *
631
+ * @param name - Metric name (plugin-namespaced by the host)
632
+ * @param value - Numeric value
633
+ * @param tags - Optional key-value tags for filtering
634
+ */
635
+ write(name: string, value: number, tags?: Record<string, string>): Promise<void>;
636
+ }
637
+ /**
638
+ * `ctx.companies` — read company metadata.
639
+ *
640
+ * Requires `companies.read` capability.
641
+ */
642
+ export interface PluginCompaniesClient {
643
+ /**
644
+ * List companies visible to this plugin.
645
+ */
646
+ list(input?: {
647
+ limit?: number;
648
+ offset?: number;
649
+ }): Promise<Company[]>;
650
+ /**
651
+ * Get one company by ID.
652
+ */
653
+ get(companyId: string): Promise<Company | null>;
654
+ }
655
+ /**
656
+ * `ctx.issues.documents` — read and write issue documents.
657
+ *
658
+ * Requires:
659
+ * - `issue.documents.read` for `list` and `get`
660
+ * - `issue.documents.write` for `upsert` and `delete`
661
+ *
662
+ * @see PLUGIN_SPEC.md §14 — SDK Surface
663
+ */
664
+ export interface PluginIssueDocumentsClient {
665
+ /**
666
+ * List all documents attached to an issue.
667
+ *
668
+ * Returns summary metadata (id, key, title, format, timestamps) without
669
+ * the full document body. Use `get()` to fetch a specific document's body.
670
+ *
671
+ * Requires the `issue.documents.read` capability.
672
+ */
673
+ list(issueId: string, companyId: string): Promise<IssueDocumentSummary[]>;
674
+ /**
675
+ * Get a single document by key, including its full body content.
676
+ *
677
+ * Returns `null` if no document exists with the given key.
678
+ *
679
+ * Requires the `issue.documents.read` capability.
680
+ *
681
+ * @param issueId - UUID of the issue
682
+ * @param key - Document key (e.g. `"plan"`, `"design-spec"`)
683
+ * @param companyId - UUID of the company
684
+ */
685
+ get(issueId: string, key: string, companyId: string): Promise<IssueDocument | null>;
686
+ /**
687
+ * Create or update a document on an issue.
688
+ *
689
+ * If a document with the given key already exists, it is updated and a new
690
+ * revision is created. If it does not exist, it is created.
691
+ *
692
+ * Requires the `issue.documents.write` capability.
693
+ *
694
+ * @param input - Document data including issueId, key, body, and optional title/format/changeSummary
695
+ */
696
+ upsert(input: {
697
+ issueId: string;
698
+ key: string;
699
+ body: string;
700
+ companyId: string;
701
+ title?: string;
702
+ format?: string;
703
+ changeSummary?: string;
704
+ }): Promise<IssueDocument>;
705
+ /**
706
+ * Delete a document and all its revisions.
707
+ *
708
+ * No-ops silently if the document does not exist (idempotent).
709
+ *
710
+ * Requires the `issue.documents.write` capability.
711
+ *
712
+ * @param issueId - UUID of the issue
713
+ * @param key - Document key to delete
714
+ * @param companyId - UUID of the company
715
+ */
716
+ delete(issueId: string, key: string, companyId: string): Promise<void>;
717
+ }
718
+ /**
719
+ * `ctx.issues` — read and mutate issues plus comments.
720
+ *
721
+ * Requires:
722
+ * - `issues.read` for read operations
723
+ * - `issues.create` for create
724
+ * - `issues.update` for update
725
+ * - `issue.comments.read` for `listComments`
726
+ * - `issue.comments.create` for `createComment`
727
+ * - `issue.documents.read` for `documents.list` and `documents.get`
728
+ * - `issue.documents.write` for `documents.upsert` and `documents.delete`
729
+ */
730
+ export interface PluginIssuesClient {
731
+ list(input: {
732
+ companyId: string;
733
+ projectId?: string;
734
+ assigneeAgentId?: string;
735
+ status?: Issue["status"];
736
+ limit?: number;
737
+ offset?: number;
738
+ }): Promise<Issue[]>;
739
+ get(issueId: string, companyId: string): Promise<Issue | null>;
740
+ create(input: {
741
+ companyId: string;
742
+ projectId?: string;
743
+ goalId?: string;
744
+ parentId?: string;
745
+ title: string;
746
+ description?: string;
747
+ priority?: Issue["priority"];
748
+ assigneeAgentId?: string;
749
+ }): Promise<Issue>;
750
+ update(issueId: string, patch: Partial<Pick<Issue, "title" | "description" | "status" | "priority" | "assigneeAgentId">>, companyId: string): Promise<Issue>;
751
+ listComments(issueId: string, companyId: string): Promise<IssueComment[]>;
752
+ createComment(issueId: string, body: string, companyId: string): Promise<IssueComment>;
753
+ /** Read and write issue documents. Requires `issue.documents.read` / `issue.documents.write`. */
754
+ documents: PluginIssueDocumentsClient;
755
+ }
756
+ /**
757
+ * `ctx.agents` — read and manage agents.
758
+ *
759
+ * Requires `agents.read` for reads; `agents.pause` / `agents.resume` /
760
+ * `agents.invoke` for write operations.
761
+ */
762
+ export interface PluginAgentsClient {
763
+ list(input: {
764
+ companyId: string;
765
+ status?: Agent["status"];
766
+ limit?: number;
767
+ offset?: number;
768
+ }): Promise<Agent[]>;
769
+ get(agentId: string, companyId: string): Promise<Agent | null>;
770
+ /** Pause an agent. Throws if agent is terminated or not found. Requires `agents.pause`. */
771
+ pause(agentId: string, companyId: string): Promise<Agent>;
772
+ /** Resume a paused agent (sets status to idle). Throws if terminated, pending_approval, or not found. Requires `agents.resume`. */
773
+ resume(agentId: string, companyId: string): Promise<Agent>;
774
+ /** Invoke (wake up) an agent with a prompt payload. Throws if paused, terminated, pending_approval, or not found. Requires `agents.invoke`. */
775
+ invoke(agentId: string, companyId: string, opts: {
776
+ prompt: string;
777
+ reason?: string;
778
+ }): Promise<{
779
+ runId: string;
780
+ }>;
781
+ /** Create, message, and close agent chat sessions. Requires `agent.sessions.*` capabilities. */
782
+ sessions: PluginAgentSessionsClient;
783
+ }
784
+ /**
785
+ * Represents an active conversational session with an agent.
786
+ * Maps to an `AgentTaskSession` row on the host.
787
+ */
788
+ export interface AgentSession {
789
+ sessionId: string;
790
+ agentId: string;
791
+ companyId: string;
792
+ status: "active" | "closed";
793
+ createdAt: string;
794
+ }
795
+ /**
796
+ * A streaming event received during a session's `sendMessage` call.
797
+ * Delivered via JSON-RPC notifications from host to worker.
798
+ */
799
+ export interface AgentSessionEvent {
800
+ sessionId: string;
801
+ runId: string;
802
+ seq: number;
803
+ /** The kind of event: "chunk" for output data, "status" for run state changes, "done" for end-of-stream, "error" for failures. */
804
+ eventType: "chunk" | "status" | "done" | "error";
805
+ stream: "stdout" | "stderr" | "system" | null;
806
+ message: string | null;
807
+ payload: Record<string, unknown> | null;
808
+ }
809
+ /**
810
+ * Result of sending a message to a session.
811
+ */
812
+ export interface AgentSessionSendResult {
813
+ runId: string;
814
+ }
815
+ /**
816
+ * `ctx.agents.sessions` — create, message, and close agent chat sessions.
817
+ *
818
+ * Requires `agent.sessions.create` for create, `agent.sessions.list` for list,
819
+ * `agent.sessions.send` for sendMessage, `agent.sessions.close` for close.
820
+ */
821
+ export interface PluginAgentSessionsClient {
822
+ /** Create a new conversational session with an agent. Requires `agent.sessions.create`. */
823
+ create(agentId: string, companyId: string, opts?: {
824
+ taskKey?: string;
825
+ reason?: string;
826
+ }): Promise<AgentSession>;
827
+ /** List active sessions for an agent owned by this plugin. Requires `agent.sessions.list`. */
828
+ list(agentId: string, companyId: string): Promise<AgentSession[]>;
829
+ /**
830
+ * Send a message to a session and receive streaming events via the `onEvent` callback.
831
+ * Returns immediately with `{ runId }`. Events are delivered asynchronously.
832
+ * Requires `agent.sessions.send`.
833
+ */
834
+ sendMessage(sessionId: string, companyId: string, opts: {
835
+ prompt: string;
836
+ reason?: string;
837
+ onEvent?: (event: AgentSessionEvent) => void;
838
+ }): Promise<AgentSessionSendResult>;
839
+ /** Close a session, releasing resources. Requires `agent.sessions.close`. */
840
+ close(sessionId: string, companyId: string): Promise<void>;
841
+ }
842
+ /**
843
+ * `ctx.goals` — read and mutate goals.
844
+ *
845
+ * Requires:
846
+ * - `goals.read` for read operations
847
+ * - `goals.create` for create
848
+ * - `goals.update` for update
849
+ */
850
+ export interface PluginGoalsClient {
851
+ list(input: {
852
+ companyId: string;
853
+ level?: Goal["level"];
854
+ status?: Goal["status"];
855
+ limit?: number;
856
+ offset?: number;
857
+ }): Promise<Goal[]>;
858
+ get(goalId: string, companyId: string): Promise<Goal | null>;
859
+ create(input: {
860
+ companyId: string;
861
+ title: string;
862
+ description?: string;
863
+ level?: Goal["level"];
864
+ status?: Goal["status"];
865
+ parentId?: string;
866
+ ownerAgentId?: string;
867
+ }): Promise<Goal>;
868
+ update(goalId: string, patch: Partial<Pick<Goal, "title" | "description" | "level" | "status" | "parentId" | "ownerAgentId">>, companyId: string): Promise<Goal>;
869
+ }
870
+ /**
871
+ * `ctx.streams` — push real-time events from the worker to the plugin UI.
872
+ *
873
+ * The worker opens a named channel, emits events on it, and closes it when
874
+ * done. On the UI side, `usePluginStream(channel)` receives these events in
875
+ * real time via SSE.
876
+ *
877
+ * Streams are scoped to `(pluginId, channel, companyId)`. Multiple UI clients
878
+ * can subscribe to the same channel concurrently.
879
+ *
880
+ * @example
881
+ * ```ts
882
+ * // Worker: stream chat tokens to the UI
883
+ * ctx.streams.open("chat", companyId);
884
+ * for await (const token of tokenStream) {
885
+ * ctx.streams.emit("chat", { type: "token", text: token });
886
+ * }
887
+ * ctx.streams.close("chat");
888
+ * ```
889
+ *
890
+ * @see usePluginStream in `@paperclipai/plugin-sdk/ui`
891
+ */
892
+ export interface PluginStreamsClient {
893
+ /**
894
+ * Open a named stream channel. Optional — `emit()` implicitly opens if needed.
895
+ * Sends a `stream:open` event to connected UI clients.
896
+ */
897
+ open(channel: string, companyId: string): void;
898
+ /**
899
+ * Push an event to all UI clients subscribed to this channel.
900
+ *
901
+ * @param channel - Stream channel name (e.g. `"chat"`, `"logs"`)
902
+ * @param event - JSON-serializable event payload
903
+ */
904
+ emit(channel: string, event: unknown): void;
905
+ /**
906
+ * Close a stream channel. Sends a `stream:close` event to connected UI
907
+ * clients so they know no more events will arrive.
908
+ */
909
+ close(channel: string): void;
910
+ }
911
+ /**
912
+ * The full plugin context object passed to the plugin worker at initialisation.
913
+ *
914
+ * This is the central interface plugin authors use to interact with the host.
915
+ * Every client is capability-gated: calling a client method without the
916
+ * required capability declared in the manifest results in a runtime error.
917
+ *
918
+ * @example
919
+ * ```ts
920
+ * import { definePlugin } from "@paperclipai/plugin-sdk";
921
+ *
922
+ * export default definePlugin({
923
+ * async setup(ctx) {
924
+ * ctx.events.on("issue.created", async (event) => {
925
+ * ctx.logger.info("Issue created", { issueId: event.entityId });
926
+ * });
927
+ *
928
+ * ctx.data.register("sync-health", async ({ companyId }) => {
929
+ * const state = await ctx.state.get({ scopeKind: "company", scopeId: String(companyId), stateKey: "last-sync" });
930
+ * return { lastSync: state };
931
+ * });
932
+ * },
933
+ * });
934
+ * ```
935
+ *
936
+ * @see PLUGIN_SPEC.md §14 — SDK Surface
937
+ */
938
+ export interface PluginContext {
939
+ /** The plugin's manifest as validated at install time. */
940
+ manifest: PaperclipPluginManifestV1;
941
+ /** Read resolved operator configuration. */
942
+ config: PluginConfigClient;
943
+ /** Subscribe to and emit domain events. Requires `events.subscribe` / `events.emit`. */
944
+ events: PluginEventsClient;
945
+ /** Register handlers for scheduled jobs. Requires `jobs.schedule`. */
946
+ jobs: PluginJobsClient;
947
+ /** Register launcher metadata that the host can surface in plugin UI entry points. */
948
+ launchers: PluginLaunchersClient;
949
+ /** Make outbound HTTP requests. Requires `http.outbound`. */
950
+ http: PluginHttpClient;
951
+ /** Resolve secret references. Requires `secrets.read-ref`. */
952
+ secrets: PluginSecretsClient;
953
+ /** Write activity log entries. Requires `activity.log.write`. */
954
+ activity: PluginActivityClient;
955
+ /** Read and write scoped plugin state. Requires `plugin.state.read` / `plugin.state.write`. */
956
+ state: PluginStateClient;
957
+ /** Create and query plugin-owned entity records. */
958
+ entities: PluginEntitiesClient;
959
+ /** Read project and workspace metadata. Requires `projects.read` / `project.workspaces.read`. */
960
+ projects: PluginProjectsClient;
961
+ /** Read company metadata. Requires `companies.read`. */
962
+ companies: PluginCompaniesClient;
963
+ /** Read and write issues, comments, and documents. Requires issue capabilities. */
964
+ issues: PluginIssuesClient;
965
+ /** Read and manage agents. Requires `agents.read` for reads; `agents.pause` / `agents.resume` / `agents.invoke` for write ops. */
966
+ agents: PluginAgentsClient;
967
+ /** Read and mutate goals. Requires `goals.read` for reads; `goals.create` / `goals.update` for write ops. */
968
+ goals: PluginGoalsClient;
969
+ /** Register getData handlers for the plugin's UI components. */
970
+ data: PluginDataClient;
971
+ /** Register performAction handlers for the plugin's UI components. */
972
+ actions: PluginActionsClient;
973
+ /** Push real-time events from the worker to the plugin UI via SSE. */
974
+ streams: PluginStreamsClient;
975
+ /** Register agent tool handlers. Requires `agent.tools.register`. */
976
+ tools: PluginToolsClient;
977
+ /** Write plugin metrics. Requires `metrics.write`. */
978
+ metrics: PluginMetricsClient;
979
+ /** Structured logger. Output is captured and surfaced in the plugin health dashboard. */
980
+ logger: PluginLogger;
981
+ }
982
+ //# sourceMappingURL=types.d.ts.map