@ryuhq/sdk 0.0.5 → 0.0.17
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/dist/agent.cjs +4 -1
- package/dist/agent.d.cts +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{chunk-KPKMMGVC.js → chunk-MTUBUPIV.js} +4 -1
- package/dist/{chunk-GXHL5CO7.js → chunk-SKVIJH5I.js} +84 -2
- package/dist/cli.cjs +138 -10
- package/dist/cli.js +56 -9
- package/dist/{index-DAxq7Y0R.d.ts → index-B6SkaAjJ.d.ts} +4 -4
- package/dist/{index-CEbS1SlS.d.cts → index-BvAB5eMk.d.cts} +4 -4
- package/dist/index.cjs +135 -9
- package/dist/index.d.cts +30 -12
- package/dist/index.d.ts +30 -12
- package/dist/index.js +50 -8
- package/dist/manifest.cjs +85 -2
- package/dist/manifest.d.cts +93 -10
- package/dist/manifest.d.ts +93 -10
- package/dist/manifest.js +3 -1
- package/package.json +2 -2
- package/src/builder.ts +4 -4
- package/src/cli.ts +98 -13
- package/src/contracts-lockstep.test.ts +4 -4
- package/src/generated/plugin-manifest.ts +1148 -22
- package/src/manifest-schema.test.ts +182 -0
- package/src/manifest.fixtures.test.ts +447 -0
- package/src/manifest.test.ts +100 -16
- package/src/manifest.ts +137 -17
- package/src/plugin/ryu-plugin.ts +1 -1
- package/src/runnable/agent.ts +3 -3
- package/src/runnable/app.test.ts +67 -0
- package/src/runnable/app.ts +54 -4
- package/src/runnable/primitives.test.ts +1 -5
- package/src/runnable/primitives.ts +6 -5
- package/src/runnable/tool.ts +4 -4
- package/src/runnable/turn-hook.ts +30 -4
package/dist/index.cjs
CHANGED
|
@@ -194,7 +194,10 @@ function dataUrlToBytes(dataUrl) {
|
|
|
194
194
|
}
|
|
195
195
|
return { bytes, mediaType };
|
|
196
196
|
}
|
|
197
|
-
return {
|
|
197
|
+
return {
|
|
198
|
+
bytes: new TextEncoder().encode(decodeURIComponent(payload)),
|
|
199
|
+
mediaType
|
|
200
|
+
};
|
|
198
201
|
}
|
|
199
202
|
function bytesToDataUrl(bytes, mediaType) {
|
|
200
203
|
let binary = "";
|
|
@@ -903,7 +906,39 @@ var TurnHookContributionSchema = import_zod.z.object({
|
|
|
903
906
|
/** Turn boundary this fires on. Today only `"post_assistant_turn"`. */
|
|
904
907
|
on: import_zod.z.string().min(1).default("post_assistant_turn"),
|
|
905
908
|
/** The JS hook body executed in the sandbox (returns a directive). */
|
|
906
|
-
code: import_zod.z.string().min(1)
|
|
909
|
+
code: import_zod.z.string().min(1).optional(),
|
|
910
|
+
/** Path to the hook body, relative to the plugin root (`hooks/<name>.js`). */
|
|
911
|
+
code_file: import_zod.z.string().min(1).optional(),
|
|
912
|
+
/**
|
|
913
|
+
* Cheap pre-gate mirroring Core's `HookMatch` (serde name `match` on
|
|
914
|
+
* `TurnHookContribution.run_when`). MUST round-trip through this schema:
|
|
915
|
+
* `ryu pack`/`publish` persist `safeParse(...).data`, so a field missing here
|
|
916
|
+
* is silently STRIPPED before signing — a tool-gated `pre_tool_use` hook
|
|
917
|
+
* (e.g. `tools: ["bash*"]`) would lose its gate and run on EVERY tool call.
|
|
918
|
+
*/
|
|
919
|
+
match: import_zod.z.object({
|
|
920
|
+
/** Run only if the request set this composer flag true. */
|
|
921
|
+
flag: import_zod.z.string().optional(),
|
|
922
|
+
/** Run if the last user message starts with any of these prefixes. */
|
|
923
|
+
commands: import_zod.z.array(import_zod.z.string()).default([]),
|
|
924
|
+
/** Run if the plugin has stored state for this conversation. */
|
|
925
|
+
stateful: import_zod.z.boolean().default(false),
|
|
926
|
+
/** Run if `ctx.tool_name` matches any of these `*`-wildcard patterns. */
|
|
927
|
+
tools: import_zod.z.array(import_zod.z.string()).default([])
|
|
928
|
+
}).optional()
|
|
929
|
+
}).refine((h) => Boolean(h.code) !== Boolean(h.code_file), {
|
|
930
|
+
message: "a turn hook must declare exactly one of 'code' (inline body) or 'code_file' (path to hooks/<name>.js)",
|
|
931
|
+
path: ["code_file"]
|
|
932
|
+
});
|
|
933
|
+
var HookEventContributionSchema = import_zod.z.object({
|
|
934
|
+
/** Fully-qualified event id: `<plugin id>#<event name>`, e.g. `@acme/meetings#meeting.ended`. */
|
|
935
|
+
id: import_zod.z.string().min(1),
|
|
936
|
+
/** Human-readable title for the event picker. */
|
|
937
|
+
title: import_zod.z.string().min(1),
|
|
938
|
+
/** What the event means and when it fires. */
|
|
939
|
+
description: import_zod.z.string().optional(),
|
|
940
|
+
/** Example of the `ctx.event` payload. Documentation, not a validated schema. */
|
|
941
|
+
payload_example: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
907
942
|
});
|
|
908
943
|
var DEFAULT_WIDGET_MIME = "text/html+skybridge";
|
|
909
944
|
var DEFAULT_WIDGET_DISPLAY_MODE = "inline";
|
|
@@ -941,6 +976,11 @@ var ToolAppConfigSchema = import_zod.z.object({
|
|
|
941
976
|
});
|
|
942
977
|
var ContributesSchema = import_zod.z.object({
|
|
943
978
|
turn_hooks: import_zod.z.array(TurnHookContributionSchema).default([]),
|
|
979
|
+
/** App events this plugin EMITS — the provider half of the hook system, whose
|
|
980
|
+
* consumer half is `turn_hooks`. Mirrors the Rust `Contributes.hook_events`;
|
|
981
|
+
* omitting it here would have `ryu pack` strip every declared event before
|
|
982
|
+
* signing, leaving an app that emits events nothing is allowed to subscribe to. */
|
|
983
|
+
hook_events: import_zod.z.array(HookEventContributionSchema).default([]),
|
|
944
984
|
composer_controls: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
945
985
|
settings_tabs: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
946
986
|
slash_commands: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
@@ -948,7 +988,32 @@ var ContributesSchema = import_zod.z.object({
|
|
|
948
988
|
* `ui://widget/<slug>.html` template. Mirrors the Rust-side
|
|
949
989
|
* `Contributes.widgets` field, without which the CLI's zod parse would strip
|
|
950
990
|
* every widget an app authored here declares. */
|
|
951
|
-
widgets: import_zod.z.array(WidgetContributionSchema).default([])
|
|
991
|
+
widgets: import_zod.z.array(WidgetContributionSchema).default([]),
|
|
992
|
+
/** App-registered sidebar sections (header + live list) and buttons (single nav
|
|
993
|
+
* rows). Loosely typed here — the shell owns the spec vocabulary — matching how
|
|
994
|
+
* `composer_controls`/`settings_tabs` are declared. Mirrors the Rust-side
|
|
995
|
+
* `Contributes.sidebar_sections` / `Contributes.sidebar_buttons`. */
|
|
996
|
+
sidebar_sections: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
997
|
+
sidebar_buttons: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
998
|
+
/** App-registered workspace dock panels (a tab in the desktop's bottom/right
|
|
999
|
+
* dock). Loosely typed for the same reason as the surfaces above — the shell
|
|
1000
|
+
* owns the `panel` render-mode vocabulary and the `spec` payload. Mirrors the
|
|
1001
|
+
* Rust-side `Contributes.dock_panels`; without it the CLI's zod parse would
|
|
1002
|
+
* strip the dock panel an app declares here. */
|
|
1003
|
+
dock_panels: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1004
|
+
/** Language servers the plugin declares, keyed by server name — the mirror of
|
|
1005
|
+
* Claude Code's `.lsp.json` / `lspServers`, so a config written for either host
|
|
1006
|
+
* loads in the other. Mirrors the Rust-side `Contributes.lsp_servers`; without
|
|
1007
|
+
* it the CLI's zod parse would strip every language server a plugin declares,
|
|
1008
|
+
* before the manifest is signed.
|
|
1009
|
+
*
|
|
1010
|
+
* The ENTRY is deliberately a loose record and not a 13-field `z.object()`
|
|
1011
|
+
* mirroring `LspServerContribution`. Claude Code owns this field vocabulary,
|
|
1012
|
+
* not Ryu: a typed object here would strip a field from a newer Claude release
|
|
1013
|
+
* on its way through `ryu pack` — the same silent-deletion bug this field
|
|
1014
|
+
* exists to fix, one level down. Core is the layer that types it, because Core
|
|
1015
|
+
* is the layer that acts on it. */
|
|
1016
|
+
lsp_servers: import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default({})
|
|
952
1017
|
});
|
|
953
1018
|
var SetupStepSchema = import_zod.z.object({
|
|
954
1019
|
/** Card heading (e.g. the companion app name). */
|
|
@@ -1129,6 +1194,25 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1129
1194
|
license: import_zod.z.string().optional(),
|
|
1130
1195
|
/** Square logo/icon URL for the listing card + detail header. */
|
|
1131
1196
|
iconUrl: import_zod.z.string().optional(),
|
|
1197
|
+
/**
|
|
1198
|
+
* Icon-primitive id for the listing card (Ryu extension): an Iconify/icons0
|
|
1199
|
+
* `prefix:name`, a bare Hugeicons name, or a URL, resolved by the shared `Icon`
|
|
1200
|
+
* primitive. A monochrome GLYPH masked with the current text colour — distinct
|
|
1201
|
+
* from `iconUrl` (a raster logo). Falls back to `iconUrl` when omitted.
|
|
1202
|
+
*/
|
|
1203
|
+
icon: import_zod.z.string().optional(),
|
|
1204
|
+
/**
|
|
1205
|
+
* Dithered-gradient background for the card's icon square (Ryu extension),
|
|
1206
|
+
* mirroring dither-kit's `DitherGradient` props. `from`/`to` are a palette-colour
|
|
1207
|
+
* name (`green`, `blue`, `purple`, `pink`, `orange`, `red`, `grey`) or a hue
|
|
1208
|
+
* number (0–360); `direction` is where `to` ends up. Renders behind the glyph in
|
|
1209
|
+
* place of a flat `iconBackground`; the render layer validates + falls back.
|
|
1210
|
+
*/
|
|
1211
|
+
iconDither: import_zod.z.object({
|
|
1212
|
+
from: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]),
|
|
1213
|
+
to: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).optional(),
|
|
1214
|
+
direction: import_zod.z.enum(["up", "down", "left", "right"]).optional()
|
|
1215
|
+
}).optional(),
|
|
1132
1216
|
/** Ordered App-Store-style screenshot gallery URLs (Ryu extension). */
|
|
1133
1217
|
screenshots: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1134
1218
|
/** Privacy policy URL surfaced on detail (Ryu extension). */
|
|
@@ -1162,6 +1246,14 @@ function coreManifestJsonSchema() {
|
|
|
1162
1246
|
// src/runnable/app.ts
|
|
1163
1247
|
var DEFAULT_APP_WIDGET_MIME = "text/html+skybridge";
|
|
1164
1248
|
var DEFAULT_APP_DISPLAY_MODE = "inline";
|
|
1249
|
+
var WIDGET_RENDER_GRANT = "widget:render";
|
|
1250
|
+
function withWidgetRenderGrant(grants, widgets) {
|
|
1251
|
+
const out = [...grants];
|
|
1252
|
+
if (widgets.length > 0 && !out.includes(WIDGET_RENDER_GRANT)) {
|
|
1253
|
+
out.push(WIDGET_RENDER_GRANT);
|
|
1254
|
+
}
|
|
1255
|
+
return out;
|
|
1256
|
+
}
|
|
1165
1257
|
function appToolId(server, name) {
|
|
1166
1258
|
return `${server}__${name}`;
|
|
1167
1259
|
}
|
|
@@ -1203,9 +1295,21 @@ function defineApp(options) {
|
|
|
1203
1295
|
}
|
|
1204
1296
|
const contributes = {
|
|
1205
1297
|
turn_hooks: [],
|
|
1298
|
+
// This builder synthesises an app from its runnables; an app that emits
|
|
1299
|
+
// events declares them in a hand-authored `manifest.json`, same as
|
|
1300
|
+
// `lsp_servers` below.
|
|
1301
|
+
hook_events: [],
|
|
1206
1302
|
composer_controls: [],
|
|
1207
1303
|
settings_tabs: [],
|
|
1208
1304
|
slash_commands: [],
|
|
1305
|
+
sidebar_sections: [],
|
|
1306
|
+
sidebar_buttons: [],
|
|
1307
|
+
dock_panels: [],
|
|
1308
|
+
// Empty for the same reason as every sibling family above: this builder
|
|
1309
|
+
// synthesises `widgets` from the app's own runnables and nothing else, and
|
|
1310
|
+
// takes no `contributes` passthrough. An app that wants to declare language
|
|
1311
|
+
// servers writes them in a hand-authored `manifest.json`.
|
|
1312
|
+
lsp_servers: {},
|
|
1209
1313
|
widgets
|
|
1210
1314
|
};
|
|
1211
1315
|
const raw = {
|
|
@@ -1213,7 +1317,21 @@ function defineApp(options) {
|
|
|
1213
1317
|
name: options.title,
|
|
1214
1318
|
version: options.version,
|
|
1215
1319
|
runnables,
|
|
1216
|
-
|
|
1320
|
+
// An app that synthesises widgets MUST hold `widget:render`, so this
|
|
1321
|
+
// builder declares it rather than leaving the author to discover it.
|
|
1322
|
+
//
|
|
1323
|
+
// Core gates widget promotion on declared-AND-enabled-AND-granted, and a
|
|
1324
|
+
// missing grant fails as `DeniedNoGrant` — which is an `info!` log and
|
|
1325
|
+
// nothing else. The widget silently renders as plain text, with no error
|
|
1326
|
+
// in the UI and nothing pointing at the manifest. Every app scaffolded
|
|
1327
|
+
// through `defineApp` hit that, because the only fix was a grant string
|
|
1328
|
+
// the templates never mention and the builder never added; the one
|
|
1329
|
+
// working example on disk hand-writes it.
|
|
1330
|
+
//
|
|
1331
|
+
// Added only when there is a widget to render, and unioned rather than
|
|
1332
|
+
// overwritten so an author's own `grants` list survives and re-declaring
|
|
1333
|
+
// it is not an error.
|
|
1334
|
+
permission_grants: withWidgetRenderGrant(options.grants ?? [], widgets),
|
|
1217
1335
|
activation_events: options.activationEvents ?? ["*"],
|
|
1218
1336
|
contributes,
|
|
1219
1337
|
// `targets: []` means EVERY surface, so an app that declares none is
|
|
@@ -1235,7 +1353,9 @@ function defineApp(options) {
|
|
|
1235
1353
|
const first = result.error.issues[0];
|
|
1236
1354
|
const field = first?.path.join(".") ?? "unknown";
|
|
1237
1355
|
const message = first?.message ?? "validation failed";
|
|
1238
|
-
throw new Error(
|
|
1356
|
+
throw new Error(
|
|
1357
|
+
`manifest.json validation failed at '${field}': ${message}`
|
|
1358
|
+
);
|
|
1239
1359
|
}
|
|
1240
1360
|
return result.data;
|
|
1241
1361
|
}
|
|
@@ -1431,7 +1551,7 @@ var PluginBuilder = class {
|
|
|
1431
1551
|
const field = first?.path.join(".") ?? "unknown";
|
|
1432
1552
|
const message = first?.message ?? "validation failed";
|
|
1433
1553
|
throw new Error(
|
|
1434
|
-
`
|
|
1554
|
+
`manifest.json validation failed at '${field}': ${message}`
|
|
1435
1555
|
);
|
|
1436
1556
|
}
|
|
1437
1557
|
return result.data;
|
|
@@ -1804,12 +1924,18 @@ function defineTurnHook(options) {
|
|
|
1804
1924
|
function definePlugin(options) {
|
|
1805
1925
|
const contributes = {
|
|
1806
1926
|
turn_hooks: options.turnHooks ?? [],
|
|
1927
|
+
hook_events: options.hookEvents ?? [],
|
|
1807
1928
|
composer_controls: options.composerControls ?? [],
|
|
1808
1929
|
settings_tabs: options.settingsTabs ?? [],
|
|
1809
1930
|
slash_commands: options.slashCommands ?? [],
|
|
1810
|
-
|
|
1811
|
-
//
|
|
1812
|
-
|
|
1931
|
+
lsp_servers: options.lspServers ?? {},
|
|
1932
|
+
// A turn-hook plugin contributes no app widgets, sidebar entries or dock
|
|
1933
|
+
// panels; the fields are required on the resolved `Contributes` type (zod
|
|
1934
|
+
// defaults applied), so set them explicitly.
|
|
1935
|
+
widgets: [],
|
|
1936
|
+
sidebar_sections: [],
|
|
1937
|
+
sidebar_buttons: [],
|
|
1938
|
+
dock_panels: []
|
|
1813
1939
|
};
|
|
1814
1940
|
const tools = options.tools ?? [];
|
|
1815
1941
|
const runnables = tools.map((t) => inlineToolRunnable(t));
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { R as Runnable, a as RunnableContext, T as ToolRunnable } from './index-
|
|
2
|
-
export { A as Agent, b as AgentConfig, c as AgentEvent, d as AgentTool, C as ChatDelta, e as ChatMessage, f as ChatResult, D as DurableClient, E as Endpoint, g as EnginesClient, G as GatewayClient, h as GenerateResult, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient, i as MemoryItem, j as ModelClient, k as ModelClientOptions, P as PRIMITIVE_BINDINGS, l as PrimitiveBinding, m as PrimitiveTransport, Q as QueryInput, n as QueryOptions, o as RagChunk, p as RagClient, q as RagRerankResult, r as RealtimeClient, s as RealtimeSubscription, t as RemoteToolRef, u as RyuPrimitives, S as SttClient, v as ToolOptions, w as ToolSchema, x as TtsClient, y as createAgent, z as createPrimitives, B as defineModel, F as defineTool, K as httpPrimitiveTransport, L as inlineToolRunnable, N as query, O as ryuTool } from './index-
|
|
3
|
-
import { Requires, Surface, PluginManifest, RunnableMeta, CompanionSurface, CapabilityReq, TurnHookContribution } from './manifest.cjs';
|
|
1
|
+
import { R as Runnable, a as RunnableContext, T as ToolRunnable } from './index-BvAB5eMk.cjs';
|
|
2
|
+
export { A as Agent, b as AgentConfig, c as AgentEvent, d as AgentTool, C as ChatDelta, e as ChatMessage, f as ChatResult, D as DurableClient, E as Endpoint, g as EnginesClient, G as GatewayClient, h as GenerateResult, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient, i as MemoryItem, j as ModelClient, k as ModelClientOptions, P as PRIMITIVE_BINDINGS, l as PrimitiveBinding, m as PrimitiveTransport, Q as QueryInput, n as QueryOptions, o as RagChunk, p as RagClient, q as RagRerankResult, r as RealtimeClient, s as RealtimeSubscription, t as RemoteToolRef, u as RyuPrimitives, S as SttClient, v as ToolOptions, w as ToolSchema, x as TtsClient, y as createAgent, z as createPrimitives, B as defineModel, F as defineTool, K as httpPrimitiveTransport, L as inlineToolRunnable, N as query, O as ryuTool } from './index-BvAB5eMk.cjs';
|
|
3
|
+
import { Requires, Surface, PluginManifest, RunnableMeta, CompanionSurface, CapabilityReq, HookEventContribution, TurnHookContribution } from './manifest.cjs';
|
|
4
4
|
export { AppDependency, AppDependencySchema, CapabilityReqSchema, CompanionSurfaceSchema, Contributes, PluginManifestSchema, RequiresSchema, RunnableKind, RunnableKindSchema, RunnableMetaSchema, SurfaceSchema, ToolAppConfig, ToolAppConfigSchema, WidgetContribution, WidgetContributionSchema, coreManifestJsonSchema, validateManifestStrict, validatePluginId } from './manifest.cjs';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ import 'zod';
|
|
|
9
9
|
*
|
|
10
10
|
* A "Ryu App" bundles one or more tools whose results render an interactive
|
|
11
11
|
* widget inline in chat (the ChatGPT-Apps-style surface). `defineApp` assembles a
|
|
12
|
-
* complete `
|
|
12
|
+
* complete `manifest.json` `PluginManifest` from a declarative description, deriving
|
|
13
13
|
* the render-vs-companion split exactly the way Core's in-process provider does
|
|
14
14
|
* (`apps/core/src/sidecar/mcp/apps/mod.rs` `tools()`):
|
|
15
15
|
*
|
|
@@ -107,7 +107,7 @@ interface DefineAppOptions {
|
|
|
107
107
|
/** Build a fully-qualified tool id from a server namespace and tool name. */
|
|
108
108
|
declare function appToolId(server: string, name: string): string;
|
|
109
109
|
/**
|
|
110
|
-
* Assemble a `
|
|
110
|
+
* Assemble a `manifest.json` manifest for a Ryu App. The result matches Core's
|
|
111
111
|
* `PluginManifest` serde shape (validated through `PluginManifestSchema`) and can
|
|
112
112
|
* be written to disk, packed with `ryu pack`, or published with `ryu publish`.
|
|
113
113
|
*
|
|
@@ -132,7 +132,7 @@ declare function defineApp(options: DefineAppOptions): PluginManifest;
|
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* Ryu SDK typed builders — one builder per RunnableKind plus a PluginBuilder that
|
|
135
|
-
* assembles a complete, validated `
|
|
135
|
+
* assembles a complete, validated `manifest.json` manifest.
|
|
136
136
|
*
|
|
137
137
|
* Each builder follows a fluent interface: construct, chain setter calls, then
|
|
138
138
|
* call `.build()` to get a validated result. Invalid manifests throw a
|
|
@@ -174,7 +174,7 @@ declare const tool: () => ToolBuilder;
|
|
|
174
174
|
/** Create a SkillBuilder. */
|
|
175
175
|
declare const skill: () => SkillBuilder;
|
|
176
176
|
/**
|
|
177
|
-
* Fluent builder for a complete `
|
|
177
|
+
* Fluent builder for a complete `manifest.json` Plugin manifest. Produces a
|
|
178
178
|
* validated `PluginManifest` on `.build()` or throws a descriptive `Error`
|
|
179
179
|
* naming the first invalid field.
|
|
180
180
|
*
|
|
@@ -252,7 +252,7 @@ declare class PluginBuilder {
|
|
|
252
252
|
build(): PluginManifest;
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
255
|
-
* Fluent builder for a Ryu App — a `
|
|
255
|
+
* Fluent builder for a Ryu App — a `manifest.json` whose tools render interactive
|
|
256
256
|
* widgets inline in chat. Delegates to {@link defineApp} on `.build()`, so it
|
|
257
257
|
* derives the render-vs-companion split and validates through
|
|
258
258
|
* `PluginManifestSchema` (throwing a descriptive `Error` on bad input) exactly
|
|
@@ -470,7 +470,7 @@ interface AgentRunnable<TInput = unknown, TOutput = unknown> extends Runnable<TI
|
|
|
470
470
|
/** The lowered slot card (empty edges when no slots were declared). */
|
|
471
471
|
readonly card: AgentCard;
|
|
472
472
|
/**
|
|
473
|
-
* Lower this agent (card + run identity) to a single-agent `
|
|
473
|
+
* Lower this agent (card + run identity) to a single-agent `manifest.json`
|
|
474
474
|
* `PluginManifest`: the agent `RunnableMeta` carries the persona/model
|
|
475
475
|
* config; `requires.capabilities` carries the slot edges. Throws if the
|
|
476
476
|
* assembled manifest is invalid.
|
|
@@ -493,7 +493,7 @@ interface AgentManifestOptions {
|
|
|
493
493
|
*
|
|
494
494
|
* The returned value satisfies `Runnable<TInput, TOutput>` with `kind = "agent"`
|
|
495
495
|
* and additionally exposes the lowered {@link AgentCard} + a `toManifest()`
|
|
496
|
-
* lowering, so a slot-composed agent round-trips to a valid `
|
|
496
|
+
* lowering, so a slot-composed agent round-trips to a valid `manifest.json`.
|
|
497
497
|
*
|
|
498
498
|
* @example Classic (unchanged, back-compat):
|
|
499
499
|
* ```ts
|
|
@@ -651,7 +651,9 @@ interface DefineTurnHookOptions {
|
|
|
651
651
|
* is serialized into the sandbox `code` string and invoked with `ctx`/`host` at
|
|
652
652
|
* run time.
|
|
653
653
|
*/
|
|
654
|
-
declare function defineTurnHook(options: DefineTurnHookOptions): TurnHookContribution
|
|
654
|
+
declare function defineTurnHook(options: DefineTurnHookOptions): TurnHookContribution & {
|
|
655
|
+
code: string;
|
|
656
|
+
};
|
|
655
657
|
interface DefinePluginOptions {
|
|
656
658
|
/** Activation events (default `["*"]` — driven by the enabled flag). */
|
|
657
659
|
activationEvents?: string[];
|
|
@@ -659,8 +661,24 @@ interface DefinePluginOptions {
|
|
|
659
661
|
composerControls?: Record<string, unknown>[];
|
|
660
662
|
/** Capability grants the hooks need (e.g. `["hook:side-model", "storage:kv"]`). */
|
|
661
663
|
grants?: string[];
|
|
664
|
+
/**
|
|
665
|
+
* App events this plugin EMITS — the provider half of the hook system whose
|
|
666
|
+
* consumer half is {@link DefinePluginOptions.turnHooks}. Each `id` must be
|
|
667
|
+
* namespaced to this plugin's own `id`; Core validates that at load and again
|
|
668
|
+
* on every emit.
|
|
669
|
+
*/
|
|
670
|
+
hookEvents?: HookEventContribution[];
|
|
662
671
|
/** Reverse-domain id (e.g. `"com.example.my-plugin"`). */
|
|
663
672
|
id: string;
|
|
673
|
+
/**
|
|
674
|
+
* Language servers the plugin declares, keyed by server name — the same shape
|
|
675
|
+
* as Claude Code's `lspServers` / `.lsp.json`, passed verbatim. Loose records
|
|
676
|
+
* rather than a typed entry on purpose: Claude Code owns this field
|
|
677
|
+
* vocabulary, so typing it here would strip a field from a newer Claude
|
|
678
|
+
* release on its way through `ryu pack`. Core types it, because Core acts on
|
|
679
|
+
* it.
|
|
680
|
+
*/
|
|
681
|
+
lspServers?: Record<string, Record<string, unknown>>;
|
|
664
682
|
/** Display name. */
|
|
665
683
|
name: string;
|
|
666
684
|
/**
|
|
@@ -690,7 +708,7 @@ interface DefinePluginOptions {
|
|
|
690
708
|
version: string;
|
|
691
709
|
}
|
|
692
710
|
/**
|
|
693
|
-
* Assemble a `
|
|
711
|
+
* Assemble a `manifest.json` manifest for a turn-hook plugin. The result matches
|
|
694
712
|
* Core's `PluginManifest` serde shape and can be written to disk or validated via
|
|
695
713
|
* `validateManifestStrict`.
|
|
696
714
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { R as Runnable, a as RunnableContext, T as ToolRunnable } from './index-
|
|
2
|
-
export { A as Agent, b as AgentConfig, c as AgentEvent, d as AgentTool, C as ChatDelta, e as ChatMessage, f as ChatResult, D as DurableClient, E as Endpoint, g as EnginesClient, G as GatewayClient, h as GenerateResult, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient, i as MemoryItem, j as ModelClient, k as ModelClientOptions, P as PRIMITIVE_BINDINGS, l as PrimitiveBinding, m as PrimitiveTransport, Q as QueryInput, n as QueryOptions, o as RagChunk, p as RagClient, q as RagRerankResult, r as RealtimeClient, s as RealtimeSubscription, t as RemoteToolRef, u as RyuPrimitives, S as SttClient, v as ToolOptions, w as ToolSchema, x as TtsClient, y as createAgent, z as createPrimitives, B as defineModel, F as defineTool, K as httpPrimitiveTransport, L as inlineToolRunnable, N as query, O as ryuTool } from './index-
|
|
3
|
-
import { Requires, Surface, PluginManifest, RunnableMeta, CompanionSurface, CapabilityReq, TurnHookContribution } from './manifest.js';
|
|
1
|
+
import { R as Runnable, a as RunnableContext, T as ToolRunnable } from './index-B6SkaAjJ.js';
|
|
2
|
+
export { A as Agent, b as AgentConfig, c as AgentEvent, d as AgentTool, C as ChatDelta, e as ChatMessage, f as ChatResult, D as DurableClient, E as Endpoint, g as EnginesClient, G as GatewayClient, h as GenerateResult, H as HttpPrimitiveTransportOptions, I as ImageClient, J as JsonSchemaProperty, M as MemoryClient, i as MemoryItem, j as ModelClient, k as ModelClientOptions, P as PRIMITIVE_BINDINGS, l as PrimitiveBinding, m as PrimitiveTransport, Q as QueryInput, n as QueryOptions, o as RagChunk, p as RagClient, q as RagRerankResult, r as RealtimeClient, s as RealtimeSubscription, t as RemoteToolRef, u as RyuPrimitives, S as SttClient, v as ToolOptions, w as ToolSchema, x as TtsClient, y as createAgent, z as createPrimitives, B as defineModel, F as defineTool, K as httpPrimitiveTransport, L as inlineToolRunnable, N as query, O as ryuTool } from './index-B6SkaAjJ.js';
|
|
3
|
+
import { Requires, Surface, PluginManifest, RunnableMeta, CompanionSurface, CapabilityReq, HookEventContribution, TurnHookContribution } from './manifest.js';
|
|
4
4
|
export { AppDependency, AppDependencySchema, CapabilityReqSchema, CompanionSurfaceSchema, Contributes, PluginManifestSchema, RequiresSchema, RunnableKind, RunnableKindSchema, RunnableMetaSchema, SurfaceSchema, ToolAppConfig, ToolAppConfigSchema, WidgetContribution, WidgetContributionSchema, coreManifestJsonSchema, validateManifestStrict, validatePluginId } from './manifest.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ import 'zod';
|
|
|
9
9
|
*
|
|
10
10
|
* A "Ryu App" bundles one or more tools whose results render an interactive
|
|
11
11
|
* widget inline in chat (the ChatGPT-Apps-style surface). `defineApp` assembles a
|
|
12
|
-
* complete `
|
|
12
|
+
* complete `manifest.json` `PluginManifest` from a declarative description, deriving
|
|
13
13
|
* the render-vs-companion split exactly the way Core's in-process provider does
|
|
14
14
|
* (`apps/core/src/sidecar/mcp/apps/mod.rs` `tools()`):
|
|
15
15
|
*
|
|
@@ -107,7 +107,7 @@ interface DefineAppOptions {
|
|
|
107
107
|
/** Build a fully-qualified tool id from a server namespace and tool name. */
|
|
108
108
|
declare function appToolId(server: string, name: string): string;
|
|
109
109
|
/**
|
|
110
|
-
* Assemble a `
|
|
110
|
+
* Assemble a `manifest.json` manifest for a Ryu App. The result matches Core's
|
|
111
111
|
* `PluginManifest` serde shape (validated through `PluginManifestSchema`) and can
|
|
112
112
|
* be written to disk, packed with `ryu pack`, or published with `ryu publish`.
|
|
113
113
|
*
|
|
@@ -132,7 +132,7 @@ declare function defineApp(options: DefineAppOptions): PluginManifest;
|
|
|
132
132
|
|
|
133
133
|
/**
|
|
134
134
|
* Ryu SDK typed builders — one builder per RunnableKind plus a PluginBuilder that
|
|
135
|
-
* assembles a complete, validated `
|
|
135
|
+
* assembles a complete, validated `manifest.json` manifest.
|
|
136
136
|
*
|
|
137
137
|
* Each builder follows a fluent interface: construct, chain setter calls, then
|
|
138
138
|
* call `.build()` to get a validated result. Invalid manifests throw a
|
|
@@ -174,7 +174,7 @@ declare const tool: () => ToolBuilder;
|
|
|
174
174
|
/** Create a SkillBuilder. */
|
|
175
175
|
declare const skill: () => SkillBuilder;
|
|
176
176
|
/**
|
|
177
|
-
* Fluent builder for a complete `
|
|
177
|
+
* Fluent builder for a complete `manifest.json` Plugin manifest. Produces a
|
|
178
178
|
* validated `PluginManifest` on `.build()` or throws a descriptive `Error`
|
|
179
179
|
* naming the first invalid field.
|
|
180
180
|
*
|
|
@@ -252,7 +252,7 @@ declare class PluginBuilder {
|
|
|
252
252
|
build(): PluginManifest;
|
|
253
253
|
}
|
|
254
254
|
/**
|
|
255
|
-
* Fluent builder for a Ryu App — a `
|
|
255
|
+
* Fluent builder for a Ryu App — a `manifest.json` whose tools render interactive
|
|
256
256
|
* widgets inline in chat. Delegates to {@link defineApp} on `.build()`, so it
|
|
257
257
|
* derives the render-vs-companion split and validates through
|
|
258
258
|
* `PluginManifestSchema` (throwing a descriptive `Error` on bad input) exactly
|
|
@@ -470,7 +470,7 @@ interface AgentRunnable<TInput = unknown, TOutput = unknown> extends Runnable<TI
|
|
|
470
470
|
/** The lowered slot card (empty edges when no slots were declared). */
|
|
471
471
|
readonly card: AgentCard;
|
|
472
472
|
/**
|
|
473
|
-
* Lower this agent (card + run identity) to a single-agent `
|
|
473
|
+
* Lower this agent (card + run identity) to a single-agent `manifest.json`
|
|
474
474
|
* `PluginManifest`: the agent `RunnableMeta` carries the persona/model
|
|
475
475
|
* config; `requires.capabilities` carries the slot edges. Throws if the
|
|
476
476
|
* assembled manifest is invalid.
|
|
@@ -493,7 +493,7 @@ interface AgentManifestOptions {
|
|
|
493
493
|
*
|
|
494
494
|
* The returned value satisfies `Runnable<TInput, TOutput>` with `kind = "agent"`
|
|
495
495
|
* and additionally exposes the lowered {@link AgentCard} + a `toManifest()`
|
|
496
|
-
* lowering, so a slot-composed agent round-trips to a valid `
|
|
496
|
+
* lowering, so a slot-composed agent round-trips to a valid `manifest.json`.
|
|
497
497
|
*
|
|
498
498
|
* @example Classic (unchanged, back-compat):
|
|
499
499
|
* ```ts
|
|
@@ -651,7 +651,9 @@ interface DefineTurnHookOptions {
|
|
|
651
651
|
* is serialized into the sandbox `code` string and invoked with `ctx`/`host` at
|
|
652
652
|
* run time.
|
|
653
653
|
*/
|
|
654
|
-
declare function defineTurnHook(options: DefineTurnHookOptions): TurnHookContribution
|
|
654
|
+
declare function defineTurnHook(options: DefineTurnHookOptions): TurnHookContribution & {
|
|
655
|
+
code: string;
|
|
656
|
+
};
|
|
655
657
|
interface DefinePluginOptions {
|
|
656
658
|
/** Activation events (default `["*"]` — driven by the enabled flag). */
|
|
657
659
|
activationEvents?: string[];
|
|
@@ -659,8 +661,24 @@ interface DefinePluginOptions {
|
|
|
659
661
|
composerControls?: Record<string, unknown>[];
|
|
660
662
|
/** Capability grants the hooks need (e.g. `["hook:side-model", "storage:kv"]`). */
|
|
661
663
|
grants?: string[];
|
|
664
|
+
/**
|
|
665
|
+
* App events this plugin EMITS — the provider half of the hook system whose
|
|
666
|
+
* consumer half is {@link DefinePluginOptions.turnHooks}. Each `id` must be
|
|
667
|
+
* namespaced to this plugin's own `id`; Core validates that at load and again
|
|
668
|
+
* on every emit.
|
|
669
|
+
*/
|
|
670
|
+
hookEvents?: HookEventContribution[];
|
|
662
671
|
/** Reverse-domain id (e.g. `"com.example.my-plugin"`). */
|
|
663
672
|
id: string;
|
|
673
|
+
/**
|
|
674
|
+
* Language servers the plugin declares, keyed by server name — the same shape
|
|
675
|
+
* as Claude Code's `lspServers` / `.lsp.json`, passed verbatim. Loose records
|
|
676
|
+
* rather than a typed entry on purpose: Claude Code owns this field
|
|
677
|
+
* vocabulary, so typing it here would strip a field from a newer Claude
|
|
678
|
+
* release on its way through `ryu pack`. Core types it, because Core acts on
|
|
679
|
+
* it.
|
|
680
|
+
*/
|
|
681
|
+
lspServers?: Record<string, Record<string, unknown>>;
|
|
664
682
|
/** Display name. */
|
|
665
683
|
name: string;
|
|
666
684
|
/**
|
|
@@ -690,7 +708,7 @@ interface DefinePluginOptions {
|
|
|
690
708
|
version: string;
|
|
691
709
|
}
|
|
692
710
|
/**
|
|
693
|
-
* Assemble a `
|
|
711
|
+
* Assemble a `manifest.json` manifest for a turn-hook plugin. The result matches
|
|
694
712
|
* Core's `PluginManifest` serde shape and can be written to disk or validated via
|
|
695
713
|
* `validateManifestStrict`.
|
|
696
714
|
*/
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
coreManifestJsonSchema,
|
|
13
13
|
validateManifestStrict,
|
|
14
14
|
validatePluginId
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-SKVIJH5I.js";
|
|
16
16
|
import {
|
|
17
17
|
Agent,
|
|
18
18
|
PRIMITIVE_BINDINGS,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
httpPrimitiveTransport,
|
|
22
22
|
query,
|
|
23
23
|
ryuTool
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-MTUBUPIV.js";
|
|
25
25
|
import {
|
|
26
26
|
DEFAULT_GATEWAY_URL,
|
|
27
27
|
ModelClient,
|
|
@@ -34,6 +34,14 @@ import {
|
|
|
34
34
|
// src/runnable/app.ts
|
|
35
35
|
var DEFAULT_APP_WIDGET_MIME = "text/html+skybridge";
|
|
36
36
|
var DEFAULT_APP_DISPLAY_MODE = "inline";
|
|
37
|
+
var WIDGET_RENDER_GRANT = "widget:render";
|
|
38
|
+
function withWidgetRenderGrant(grants, widgets) {
|
|
39
|
+
const out = [...grants];
|
|
40
|
+
if (widgets.length > 0 && !out.includes(WIDGET_RENDER_GRANT)) {
|
|
41
|
+
out.push(WIDGET_RENDER_GRANT);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
37
45
|
function appToolId(server, name) {
|
|
38
46
|
return `${server}__${name}`;
|
|
39
47
|
}
|
|
@@ -75,9 +83,21 @@ function defineApp(options) {
|
|
|
75
83
|
}
|
|
76
84
|
const contributes = {
|
|
77
85
|
turn_hooks: [],
|
|
86
|
+
// This builder synthesises an app from its runnables; an app that emits
|
|
87
|
+
// events declares them in a hand-authored `manifest.json`, same as
|
|
88
|
+
// `lsp_servers` below.
|
|
89
|
+
hook_events: [],
|
|
78
90
|
composer_controls: [],
|
|
79
91
|
settings_tabs: [],
|
|
80
92
|
slash_commands: [],
|
|
93
|
+
sidebar_sections: [],
|
|
94
|
+
sidebar_buttons: [],
|
|
95
|
+
dock_panels: [],
|
|
96
|
+
// Empty for the same reason as every sibling family above: this builder
|
|
97
|
+
// synthesises `widgets` from the app's own runnables and nothing else, and
|
|
98
|
+
// takes no `contributes` passthrough. An app that wants to declare language
|
|
99
|
+
// servers writes them in a hand-authored `manifest.json`.
|
|
100
|
+
lsp_servers: {},
|
|
81
101
|
widgets
|
|
82
102
|
};
|
|
83
103
|
const raw = {
|
|
@@ -85,7 +105,21 @@ function defineApp(options) {
|
|
|
85
105
|
name: options.title,
|
|
86
106
|
version: options.version,
|
|
87
107
|
runnables,
|
|
88
|
-
|
|
108
|
+
// An app that synthesises widgets MUST hold `widget:render`, so this
|
|
109
|
+
// builder declares it rather than leaving the author to discover it.
|
|
110
|
+
//
|
|
111
|
+
// Core gates widget promotion on declared-AND-enabled-AND-granted, and a
|
|
112
|
+
// missing grant fails as `DeniedNoGrant` — which is an `info!` log and
|
|
113
|
+
// nothing else. The widget silently renders as plain text, with no error
|
|
114
|
+
// in the UI and nothing pointing at the manifest. Every app scaffolded
|
|
115
|
+
// through `defineApp` hit that, because the only fix was a grant string
|
|
116
|
+
// the templates never mention and the builder never added; the one
|
|
117
|
+
// working example on disk hand-writes it.
|
|
118
|
+
//
|
|
119
|
+
// Added only when there is a widget to render, and unioned rather than
|
|
120
|
+
// overwritten so an author's own `grants` list survives and re-declaring
|
|
121
|
+
// it is not an error.
|
|
122
|
+
permission_grants: withWidgetRenderGrant(options.grants ?? [], widgets),
|
|
89
123
|
activation_events: options.activationEvents ?? ["*"],
|
|
90
124
|
contributes,
|
|
91
125
|
// `targets: []` means EVERY surface, so an app that declares none is
|
|
@@ -107,7 +141,9 @@ function defineApp(options) {
|
|
|
107
141
|
const first = result.error.issues[0];
|
|
108
142
|
const field = first?.path.join(".") ?? "unknown";
|
|
109
143
|
const message = first?.message ?? "validation failed";
|
|
110
|
-
throw new Error(
|
|
144
|
+
throw new Error(
|
|
145
|
+
`manifest.json validation failed at '${field}': ${message}`
|
|
146
|
+
);
|
|
111
147
|
}
|
|
112
148
|
return result.data;
|
|
113
149
|
}
|
|
@@ -303,7 +339,7 @@ var PluginBuilder = class {
|
|
|
303
339
|
const field = first?.path.join(".") ?? "unknown";
|
|
304
340
|
const message = first?.message ?? "validation failed";
|
|
305
341
|
throw new Error(
|
|
306
|
-
`
|
|
342
|
+
`manifest.json validation failed at '${field}': ${message}`
|
|
307
343
|
);
|
|
308
344
|
}
|
|
309
345
|
return result.data;
|
|
@@ -676,12 +712,18 @@ function defineTurnHook(options) {
|
|
|
676
712
|
function definePlugin(options) {
|
|
677
713
|
const contributes = {
|
|
678
714
|
turn_hooks: options.turnHooks ?? [],
|
|
715
|
+
hook_events: options.hookEvents ?? [],
|
|
679
716
|
composer_controls: options.composerControls ?? [],
|
|
680
717
|
settings_tabs: options.settingsTabs ?? [],
|
|
681
718
|
slash_commands: options.slashCommands ?? [],
|
|
682
|
-
|
|
683
|
-
//
|
|
684
|
-
|
|
719
|
+
lsp_servers: options.lspServers ?? {},
|
|
720
|
+
// A turn-hook plugin contributes no app widgets, sidebar entries or dock
|
|
721
|
+
// panels; the fields are required on the resolved `Contributes` type (zod
|
|
722
|
+
// defaults applied), so set them explicitly.
|
|
723
|
+
widgets: [],
|
|
724
|
+
sidebar_sections: [],
|
|
725
|
+
sidebar_buttons: [],
|
|
726
|
+
dock_panels: []
|
|
685
727
|
};
|
|
686
728
|
const tools = options.tools ?? [];
|
|
687
729
|
const runnables = tools.map((t) => inlineToolRunnable(t));
|