@ericsanchezok/synergy-plugin 2.4.3 → 2.4.5

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.
package/README.md CHANGED
@@ -65,15 +65,14 @@ export default plugin
65
65
 
66
66
  Tools can return user-facing files through `attachments`. Use the generated SDK `asset.upload()` route or the public `/asset` endpoint to upload binary data, then return the resulting `asset://...` URL. Do not import Synergy internal asset modules from a plugin.
67
67
 
68
- For visual tools whose output belongs in the main answer area, set `metadata.display.presentation` to `artifact-only` and list the attachment ids to promote:
68
+ For visual tools whose output belongs in the main answer area, hide the tool card and set presentation on the returned attachment:
69
69
 
70
70
  ```ts
71
71
  return {
72
72
  output: "",
73
73
  metadata: {
74
74
  display: {
75
- presentation: "artifact-only",
76
- primaryAttachmentIds: [partId],
75
+ toolCard: "hidden",
77
76
  },
78
77
  },
79
78
  attachments: [
@@ -81,31 +80,29 @@ return {
81
80
  id: partId,
82
81
  sessionID: context.sessionID,
83
82
  messageID: context.messageID,
84
- type: "file",
83
+ type: "attachment",
85
84
  mime: "image/svg+xml",
86
85
  filename: "result.svg",
87
86
  url: uploaded.url,
87
+ presentation: { renderer: "image", size: "medium", crop: false },
88
+ model: { mode: "summary", summary: "Generated SVG result." },
88
89
  },
89
90
  ],
90
91
  }
91
92
  ```
92
93
 
93
- Running and failed tool states still render normally, so progress, approvals, and errors remain visible.
94
+ Each attachment controls its own display with `presentation.hidden`, `presentation.renderer`, `presentation.size`, and `presentation.crop`. Omit `renderer` to let Synergy choose from the MIME type.
94
95
 
95
- For image, video, or audio generation tools, declare the display protocol on the tool definition as well. This lets Synergy show its built-in media generation placeholder as soon as the tool starts, then replace it with the promoted attachment when the tool completes:
96
+ For image, video, or audio generation tools, declare the display protocol on the tool definition as well. This lets Synergy show its built-in media generation placeholder as soon as the tool starts, then replace it with the completed attachment in the original message order:
96
97
 
97
98
  ```ts
98
99
  const mediaDisplay = {
99
100
  kind: "media-generation",
100
- visibility: "media",
101
- presentation: "artifact-only",
101
+ toolCard: "hidden",
102
102
  media: {
103
103
  type: "image",
104
- actionLabel: "Create image",
105
- pendingTitle: "Generating image",
106
- pendingDescription: "Preparing the image...",
107
- promptField: "prompt",
108
104
  aspectRatio: "1:1",
105
+ size: "small",
109
106
  },
110
107
  } as const
111
108
 
@@ -116,12 +113,12 @@ tool({
116
113
  prompt: tool.schema.string(),
117
114
  },
118
115
  async execute(args, context) {
119
- // Upload the generated image, then return metadata.display with primaryAttachmentIds.
116
+ // Upload the generated image, then return it with attachment-level presentation.
120
117
  },
121
118
  })
122
119
  ```
123
120
 
124
- Use `visibility: "media"` for tools whose running and completed success states belong on the media surface. Error states still fall back to normal tool cards.
121
+ Use `toolCard: "hidden"` for tools whose running and completed states belong on a dedicated surface instead of a tool card. Optional media labels are for accessibility and host-specific status surfaces; Synergy does not show tool input parameters as transcript copy.
125
122
 
126
123
  ## Internal Tools And Delegated Tasks
127
124
 
@@ -152,7 +149,7 @@ const plan = await context.task?.run({
152
149
  "plugin__my-plugin__private_helper": true,
153
150
  },
154
151
  visibility: "hidden",
155
- timeoutMs: 30_000,
152
+ timeoutMs: 120_000,
156
153
  output: {
157
154
  mode: "structured",
158
155
  schema: {
@@ -169,6 +166,69 @@ const plan = await context.task?.run({
169
166
 
170
167
  When `output.mode` is `structured`, Cortex validates the child task result against the schema and may run repair turns before completing. Cortex still stores its normal task trajectory summary in `task.result`; the structured value is returned to the plugin call site as `plan.outputResult.data`.
171
168
 
169
+ ## Hooks
170
+
171
+ Plugins return hooks from `init()`. Hook permissions are declared in `plugin.json` and Synergy only invokes permissioned hooks.
172
+
173
+ ### Event hook
174
+
175
+ `event(input)` observes runtime bus events without mutating them. Declare event access under `permissions.hooks`:
176
+
177
+ ```jsonc
178
+ {
179
+ "permissions": {
180
+ "hooks": {
181
+ "events": "selected",
182
+ "eventNames": ["session.*", "message.updated"],
183
+ },
184
+ },
185
+ }
186
+ ```
187
+
188
+ `events` is `"none"`, `"selected"`, or `"all"`. In selected mode, `eventNames` supports exact names, `*` for all events, and prefix wildcards ending in `.*` such as `session.*`.
189
+
190
+ ```ts
191
+ event(input) {
192
+ console.log(input.event.type, input.event.properties)
193
+ }
194
+ ```
195
+
196
+ ### Config hook
197
+
198
+ `config(input, output)` observes a redacted runtime config snapshot at startup, plugin reload, and config reload. Declare `permissions.hooks.config: true`; this permission is separate from `permissions.data.config`.
199
+
200
+ ```jsonc
201
+ {
202
+ "permissions": {
203
+ "hooks": {
204
+ "config": true,
205
+ },
206
+ },
207
+ }
208
+ ```
209
+
210
+ ```ts
211
+ config(input, output) {
212
+ console.log(input.source, input.changedFields)
213
+ console.log(output.config.model)
214
+ }
215
+ ```
216
+
217
+ `input.source` is `"startup"`, `"plugin_reload"`, or `"reload"`. Secret fields in `output.config` are replaced with Synergy's redacted sentinel before dispatch.
218
+
219
+ ### System prompt transform
220
+
221
+ `experimental.chat.system.transform(input, output)` can rewrite the assembled system prompt when `permissions.hooks.promptTransform` is `true`. Synergy calls this hook in two phases: `input.phase === "budget"` before token budgeting and `input.phase === "final"` before the provider call. The input includes `sessionID`, `agent`, `model`, `messageID`, and `small` for final calls.
222
+
223
+ ```ts
224
+ "experimental.chat.system.transform"(input, output) {
225
+ if (input.phase !== "final") return
226
+ output.system.push("Additional final-call instruction.")
227
+ }
228
+ ```
229
+
230
+ If a transform empties `output.system`, Synergy restores the original system prompt.
231
+
172
232
  ## Plugin Input
173
233
 
174
234
  `init(input)` receives runtime services scoped to the active Synergy Scope:
@@ -188,7 +248,7 @@ type PluginInput = {
188
248
  }
189
249
  ```
190
250
 
191
- For isolated worker/process plugins, these services are proxied through the host bridge and checked against the plugin approval record.
251
+ For isolated worker/process plugins, these services are proxied through the host bridge and checked against the plugin approval record. Workspace file and shell bridge calls require an active plugin tool context; read plugin package assets directly from `input.pluginDir`.
192
252
 
193
253
  ## Manifest
194
254
 
@@ -200,9 +260,11 @@ Each distributable plugin has a root `plugin.json`:
200
260
  "version": "0.1.0",
201
261
  "description": "Example Synergy plugin",
202
262
  "main": "./src/index.ts",
263
+ "engines": {
264
+ "synergy": ">=2.4.3",
265
+ },
203
266
  "permissions": {
204
267
  "tools": {
205
- "invoke": true,
206
268
  "filesystem": "none",
207
269
  "network": false,
208
270
  "shell": false,
@@ -235,15 +297,50 @@ Each distributable plugin has a root `plugin.json`:
235
297
 
236
298
  `contributes.ui.entry` is a runtime-loadable JavaScript asset. Source files such as `src/ui.tsx` are only build inputs. `synergy-plugin build` uses the conventional UI source path and writes the compiled bundle to the declared entry.
237
299
 
300
+ Session workbench UI uses `contributes.ui.workbenchPanels`. A workbench panel declares which surface it belongs to and how its tabs behave:
301
+
302
+ ```jsonc
303
+ {
304
+ "contributes": {
305
+ "ui": {
306
+ "entry": "./dist/ui/index.js",
307
+ "workbenchPanels": [
308
+ {
309
+ "id": "build-log",
310
+ "label": "Build Log",
311
+ "icon": "terminal",
312
+ "exportName": "BuildLogPanel",
313
+ "surface": "bottom",
314
+ "cardinality": "multi",
315
+ "requiresSession": true,
316
+ },
317
+ ],
318
+ },
319
+ },
320
+ "permissions": {
321
+ "ui": {
322
+ "workbenchPanels": true,
323
+ },
324
+ },
325
+ }
326
+ ```
327
+
328
+ `surface` is `"side"` or `"bottom"`. `cardinality` is `"exclusive"` for one active panel on that surface, `"singleton"` for one tab per panel id, or `"multi"` for a new tab each time. `requiresSession` hides the panel until the user is in a concrete session. App panels remain separate under `contributes.ui.appPanels` and create top-level sidebar entries.
329
+
238
330
  ## UI Types
239
331
 
240
332
  UI contribution types are exported separately:
241
333
 
242
334
  ```ts
243
- import type { PluginToolRendererProps, PluginPanelProps } from "@ericsanchezok/synergy-plugin/ui"
335
+ import type {
336
+ PluginToolRendererProps,
337
+ PluginWorkbenchPanel,
338
+ PluginPanelProps,
339
+ PluginMessageSlotProps,
340
+ } from "@ericsanchezok/synergy-plugin/ui"
244
341
  ```
245
342
 
246
- Supported UI surfaces are tool renderers, part renderers, workspace panels, global panels, settings sections, chat components, themes, icons, routes, and commands. The Web client loads aggregated UI metadata with the generated SDK method `plugin.listUiContributions()`, which maps to `/plugin/ui/contributions`; plugin JS and assets are still loaded through browser-native asset URLs.
343
+ Supported UI surfaces are tool renderers, part renderers, workbench panels, app panels, settings sections, message slots, themes, icons, app routes, and commands. The Web client loads aggregated UI metadata with the generated SDK method `plugin.listUiContributions()`, which maps to `/plugin/ui/contributions`; plugin JS and assets are still loaded through browser-native asset URLs.
247
344
 
248
345
  ## Runtime Modes
249
346
 
@@ -266,7 +363,7 @@ Worker and process plugins are started through Synergy's plugin runner. The runn
266
363
  - `dist/permissions.summary.json`
267
364
  - `dist/integrity.json`
268
365
 
269
- `synergy-plugin pack` archives `dist/` into `<name>-<version>.synergy-plugin.tgz`. `synergy-plugin sign` writes `<tarball>.sig`. `synergy-plugin publish-market` prepares the official marketplace submission by uploading or checking GitHub Release assets, writing a `SII-Holos/synergy-plugins` entry with the signer public key, regenerating the registry index, running registry validation, and opening a PR when `gh` is available.
366
+ `synergy-plugin pack` archives `dist/` into `<name>-<version>.synergy-plugin.tgz`. `synergy-plugin sign` writes `<tarball>.sig`. `synergy-plugin publish-market` prepares the official marketplace submission by uploading or checking GitHub Release assets, writing a `SII-Holos/synergy-plugins` entry with the signer public key and `compatibility.synergy` from `plugin.json` `engines.synergy`, regenerating the registry index, running registry validation, and opening a PR when `gh` is available.
270
367
 
271
368
  For local marketplace UX testing, the Synergy runtime still provides `synergy plugin publish <tarball>` to publish into the local development registry.
272
369
 
@@ -0,0 +1,15 @@
1
+ export declare namespace PluginArtifact {
2
+ const manifestFile = "plugin.json";
3
+ const normalizedManifestFile = "plugin.normalized.json";
4
+ const runtimeEntry = "runtime/index.js";
5
+ const integrityFile = "integrity.json";
6
+ const permissionsSummaryFile = "permissions.summary.json";
7
+ const requiredFiles: readonly ["plugin.json", "runtime/index.js", "integrity.json", "permissions.summary.json"];
8
+ const assetRoutePrefix = "/plugin/assets";
9
+ const allowedAssetRoots: readonly ["dist", "public", "assets", "ui", "themes", "icons"];
10
+ }
11
+ export declare function normalizePluginArtifactPath(filePath: string): string;
12
+ export declare function normalizePluginArchiveEntry(entry: string): string | undefined;
13
+ export declare function pluginArtifactAssetRoot(filePath: string): string;
14
+ export declare function isAllowedPluginAssetPath(filePath: string): boolean;
15
+ export declare function pluginAssetUrl(pluginId: string, versionHash: string, filePath: string): string;
@@ -0,0 +1,52 @@
1
+ export var PluginArtifact;
2
+ (function (PluginArtifact) {
3
+ PluginArtifact.manifestFile = "plugin.json";
4
+ PluginArtifact.normalizedManifestFile = "plugin.normalized.json";
5
+ PluginArtifact.runtimeEntry = "runtime/index.js";
6
+ PluginArtifact.integrityFile = "integrity.json";
7
+ PluginArtifact.permissionsSummaryFile = "permissions.summary.json";
8
+ PluginArtifact.requiredFiles = [PluginArtifact.manifestFile, PluginArtifact.runtimeEntry, PluginArtifact.integrityFile, PluginArtifact.permissionsSummaryFile];
9
+ PluginArtifact.assetRoutePrefix = "/plugin/assets";
10
+ PluginArtifact.allowedAssetRoots = ["dist", "public", "assets", "ui", "themes", "icons"];
11
+ })(PluginArtifact || (PluginArtifact = {}));
12
+ export function normalizePluginArtifactPath(filePath) {
13
+ const normalized = filePath.replace(/\\/g, "/").replace(/^\.\//, "");
14
+ if (!normalized || normalized === ".")
15
+ throw new Error("Plugin artifact path cannot be empty");
16
+ if (normalized.startsWith("/") || /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(normalized)) {
17
+ throw new Error(`Plugin artifact path must be relative: ${filePath}`);
18
+ }
19
+ const parts = normalized.split("/").filter(Boolean);
20
+ if (parts.includes(".."))
21
+ throw new Error(`Plugin artifact path cannot escape the plugin root: ${filePath}`);
22
+ return parts.join("/");
23
+ }
24
+ export function normalizePluginArchiveEntry(entry) {
25
+ let normalized = entry.replace(/\r$/, "").replace(/\\/g, "/");
26
+ while (normalized.startsWith("./"))
27
+ normalized = normalized.slice(2);
28
+ normalized = normalized.replace(/\/+$/, "");
29
+ if (!normalized || normalized === ".")
30
+ return undefined;
31
+ return normalizePluginArtifactPath(normalized);
32
+ }
33
+ export function pluginArtifactAssetRoot(filePath) {
34
+ return normalizePluginArtifactPath(filePath).split("/")[0] ?? "";
35
+ }
36
+ export function isAllowedPluginAssetPath(filePath) {
37
+ try {
38
+ const root = pluginArtifactAssetRoot(filePath);
39
+ return PluginArtifact.allowedAssetRoots.includes(root);
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ export function pluginAssetUrl(pluginId, versionHash, filePath) {
46
+ const normalized = normalizePluginArtifactPath(filePath);
47
+ const encodedPath = normalized
48
+ .split("/")
49
+ .map((part) => encodeURIComponent(part))
50
+ .join("/");
51
+ return `${PluginArtifact.assetRoutePrefix}/${encodeURIComponent(pluginId)}/${encodeURIComponent(versionHash)}/${encodedPath}`;
52
+ }
package/dist/display.d.ts CHANGED
@@ -3,13 +3,11 @@ export interface ToolMediaDisplay {
3
3
  actionLabel?: string;
4
4
  pendingTitle?: string;
5
5
  pendingDescription?: string;
6
- promptField?: string;
7
6
  aspectRatio?: "1:1" | "4:3" | "16:9" | "auto";
7
+ size?: "small" | "medium" | "large";
8
8
  }
9
9
  export interface ToolDisplay {
10
10
  kind?: "default" | "media-generation";
11
- visibility?: "default" | "media" | "hidden-unless-error";
12
- presentation?: "default" | "artifact-only";
11
+ toolCard?: "visible" | "hidden";
13
12
  media?: ToolMediaDisplay;
14
- primaryAttachmentIds?: string[];
15
13
  }
package/dist/example.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { PluginDescriptor } from "./index";
1
+ import type { PluginDescriptor } from "./index.js";
2
2
  export declare const ExamplePlugin: PluginDescriptor;
3
3
  export default ExamplePlugin;
package/dist/example.js CHANGED
@@ -1,4 +1,4 @@
1
- import { tool } from "./tool";
1
+ import { tool } from "./tool.js";
2
2
  const MAX_NOTE_TAGS = 8;
3
3
  const AUTO_TAG = "reference-plugin";
4
4
  function normalizeTag(value) {
package/dist/hooks.js CHANGED
@@ -21,13 +21,13 @@ export const HOOKS = [
21
21
  name: "config",
22
22
  category: "core",
23
23
  mutatesOutput: false,
24
- summary: "Observe the loaded runtime config",
24
+ summary: "Observe redacted runtime config snapshots at startup and config reload",
25
25
  },
26
26
  {
27
27
  name: "event",
28
28
  category: "core",
29
29
  mutatesOutput: false,
30
- summary: "Observe runtime bus events",
30
+ summary: "Observe permitted runtime bus events by exact or wildcard event name",
31
31
  },
32
32
  {
33
33
  name: "chat.message",
@@ -153,7 +153,7 @@ export const HOOKS = [
153
153
  name: "experimental.chat.system.transform",
154
154
  category: "experimental",
155
155
  mutatesOutput: true,
156
- summary: "Rewrite the assembled system prompt",
156
+ summary: "Rewrite the assembled system prompt during budget and final phases",
157
157
  },
158
158
  {
159
159
  name: "experimental.session.compacting",
package/dist/ids.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export declare namespace PluginToolId {
2
+ function format(pluginId: string, toolId: string): string;
3
+ function parse(id: string): {
4
+ pluginId: string;
5
+ toolId: string;
6
+ } | undefined;
7
+ function is(id: string): boolean;
8
+ }
9
+ export declare namespace PluginId {
10
+ function isValid(id: string): boolean;
11
+ function normalize(id: string): string;
12
+ function mcpServerKey(pluginId: string, serverKey: string): string;
13
+ }
package/dist/ids.js ADDED
@@ -0,0 +1,33 @@
1
+ export var PluginToolId;
2
+ (function (PluginToolId) {
3
+ function format(pluginId, toolId) {
4
+ return `plugin__${pluginId}__${toolId}`;
5
+ }
6
+ PluginToolId.format = format;
7
+ function parse(id) {
8
+ const match = id.match(/^plugin__([^_]+(?:_[^_]+)*?)__([^_].*)$/);
9
+ if (!match)
10
+ return undefined;
11
+ return { pluginId: match[1], toolId: match[2] };
12
+ }
13
+ PluginToolId.parse = parse;
14
+ function is(id) {
15
+ return id.startsWith("plugin__");
16
+ }
17
+ PluginToolId.is = is;
18
+ })(PluginToolId || (PluginToolId = {}));
19
+ export var PluginId;
20
+ (function (PluginId) {
21
+ function isValid(id) {
22
+ return /^[a-z][a-z0-9_-]*$/i.test(id);
23
+ }
24
+ PluginId.isValid = isValid;
25
+ function normalize(id) {
26
+ return id.trim().toLowerCase();
27
+ }
28
+ PluginId.normalize = normalize;
29
+ function mcpServerKey(pluginId, serverKey) {
30
+ return `${pluginId}::${serverKey}`;
31
+ }
32
+ PluginId.mcpServerKey = mcpServerKey;
33
+ })(PluginId || (PluginId = {}));
package/dist/index.d.ts CHANGED
@@ -1,15 +1,19 @@
1
- import type { AgendaItem, AgendaRunLog, CortexTask, Event, createSynergyClient, MemoryCategory, MemoryRecallMode, MemorySearchResult, Model, NoteCreateInput, NoteInfo, NotePatchInput, Provider, PermissionRequest, UserMessage, Message, Part, Auth, Config } from "@ericsanchezok/synergy-sdk";
2
- import type { BunShell } from "./shell";
3
- import type { ToolDefinition, ToolResult } from "./tool";
4
- export * from "./tool";
5
- export type { ToolDisplay, ToolMediaDisplay } from "./display";
1
+ import type { AgendaItem, AgendaRunLog, CortexTask, createSynergyClient, MemoryCategory, MemoryRecallMode, MemorySearchResult, Model, NoteCreateInput, NoteInfo, NotePatchInput, Provider, PermissionRequest, UserMessage, Message, Part, Auth, Config } from "@ericsanchezok/synergy-sdk";
2
+ import type { BunShell } from "./shell.js";
3
+ import type { ToolDefinition, ToolResult } from "./tool.js";
4
+ export * from "./tool.js";
5
+ export type { ToolDisplay, ToolMediaDisplay } from "./display.js";
6
6
  export type { ToolResult };
7
- export * from "./manifest";
8
- export type { BunShell, BunShellOutput, BunShellPromise, ShellExpression, ShellFunction } from "./shell";
7
+ export * from "./manifest.js";
8
+ export * from "./policy.js";
9
+ export * from "./spec.js";
10
+ export * from "./version.js";
11
+ export * from "./artifact.js";
12
+ export type { BunShell, BunShellOutput, BunShellPromise, ShellExpression, ShellFunction } from "./shell.js";
9
13
  export interface PluginConfigAccessor {
10
14
  /** Get the plugin's full config object */
11
15
  get(): Promise<Record<string, any>>;
12
- /** Set one or more config values (deep-merged into the plugin's namespace) */
16
+ /** Replace the plugin's config namespace with these values */
13
17
  set(values: Record<string, any>): Promise<void>;
14
18
  }
15
19
  /**
@@ -310,6 +314,15 @@ export type ProviderProfileHook = {
310
314
  modelID: string;
311
315
  options?: Record<string, any>;
312
316
  }) => Promise<any>;
317
+ fetchModelCatalog?: (input: {
318
+ auth?: Auth;
319
+ fetch?: typeof fetch;
320
+ baseURL?: string;
321
+ }) => Promise<Array<{
322
+ id: string;
323
+ rank?: number;
324
+ model?: Partial<Model>;
325
+ }>>;
313
326
  fetchModels?: (input: {
314
327
  auth?: Auth;
315
328
  fetch?: typeof fetch;
@@ -354,6 +367,33 @@ export interface PluginDescriptor {
354
367
  /** Initialize the plugin and return hooks */
355
368
  init(input: PluginInput): Promise<PluginHooks>;
356
369
  }
370
+ export interface PluginEventHookInput {
371
+ event: {
372
+ type: string;
373
+ properties: unknown;
374
+ };
375
+ }
376
+ export interface PluginConfigHookInput {
377
+ source: "startup" | "reload" | "plugin_reload";
378
+ scopeID?: string;
379
+ scopeType?: string;
380
+ changedFields?: string[];
381
+ timestamp: number;
382
+ }
383
+ export interface PluginConfigHookOutput {
384
+ config: Config;
385
+ }
386
+ export interface PluginChatSystemTransformInput {
387
+ phase: "budget" | "final";
388
+ sessionID: string;
389
+ agent: string;
390
+ model: {
391
+ providerID: string;
392
+ modelID: string;
393
+ };
394
+ messageID?: string;
395
+ small?: boolean;
396
+ }
357
397
  export interface PluginHooks {
358
398
  /** Called when the plugin is being unloaded (e.g. runtime reload) */
359
399
  dispose?(): Promise<void>;
@@ -370,11 +410,9 @@ export interface PluginHooks {
370
410
  /** Provider runtime/catalog profiles */
371
411
  provider?: ProviderProfileHook | ProviderProfileHook[];
372
412
  /** Observe runtime bus events */
373
- event?(input: {
374
- event: Event;
375
- }): Promise<void>;
376
- /** Observe the loaded runtime config */
377
- config?(input: Config): Promise<void>;
413
+ event?(input: PluginEventHookInput): Promise<void>;
414
+ /** Observe a redacted runtime config snapshot */
415
+ config?(input: PluginConfigHookInput, output: PluginConfigHookOutput): Promise<void>;
378
416
  /** Rewrite incoming user messages */
379
417
  "chat.message"?(input: {
380
418
  sessionID: string;
@@ -432,7 +470,7 @@ export interface PluginHooks {
432
470
  }[];
433
471
  }): Promise<void>;
434
472
  /** Rewrite the assembled system prompt */
435
- "experimental.chat.system.transform"?(input: {}, output: {
473
+ "experimental.chat.system.transform"?(input: PluginChatSystemTransformInput, output: {
436
474
  system: string[];
437
475
  }): Promise<void>;
438
476
  /** Customize session compaction */
package/dist/index.js CHANGED
@@ -1,2 +1,6 @@
1
- export * from "./tool";
2
- export * from "./manifest";
1
+ export * from "./tool.js";
2
+ export * from "./manifest.js";
3
+ export * from "./policy.js";
4
+ export * from "./spec.js";
5
+ export * from "./version.js";
6
+ export * from "./artifact.js";