@ryuhq/sdk 0.1.14 → 0.2.2
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 +69 -7
- package/dist/action.cjs +839 -0
- package/dist/action.d.cts +88 -0
- package/dist/action.d.ts +88 -0
- package/dist/action.js +8 -0
- package/dist/agent-plugin.cjs +46 -0
- package/dist/agent-plugin.d.cts +43 -33
- package/dist/agent-plugin.d.ts +43 -33
- package/dist/agent-plugin.js +1 -1
- package/dist/agent.cjs +16 -0
- package/dist/agent.d.cts +377 -1
- package/dist/agent.d.ts +377 -1
- package/dist/agent.js +4 -2
- package/dist/app-B0Z9Ew_R.d.cts +141 -0
- package/dist/app-C-BDJwfG.d.ts +141 -0
- package/dist/builder.cjs +1194 -0
- package/dist/builder.d.cts +217 -0
- package/dist/builder.d.ts +217 -0
- package/dist/builder.js +29 -0
- package/dist/chunk-4TPUZDTI.js +94 -0
- package/dist/chunk-BC3A7HMO.js +164 -0
- package/dist/chunk-FZSFZOIN.js +200 -0
- package/dist/{chunk-ODFEUVPW.js → chunk-HACAGK65.js} +1 -18
- package/dist/chunk-HLKJZAFK.js +361 -0
- package/dist/chunk-IKEDLLFY.js +19 -0
- package/dist/{chunk-G6FLVEC4.js → chunk-JX6DDRXV.js} +46 -0
- package/dist/{chunk-AO2KJRDD.js → chunk-NZKVOSC2.js} +192 -3
- package/dist/chunk-QYFUNJOH.js +83 -0
- package/dist/chunk-SN2QBJUF.js +148 -0
- package/dist/chunk-TLDPEGC7.js +21 -0
- package/dist/chunk-TXSHHZF2.js +0 -0
- package/dist/chunk-VLIRNNAE.js +154 -0
- package/dist/{chunk-MTUBUPIV.js → chunk-Z57QDDJR.js} +8 -227
- package/dist/chunk-ZTJWBRUL.js +282 -0
- package/dist/cli.cjs +347 -18
- package/dist/cli.js +128 -23
- package/dist/client-D5U6ssPc.d.cts +84 -0
- package/dist/client-D5U6ssPc.d.ts +84 -0
- package/dist/index.cjs +810 -86
- package/dist/index.d.cts +19 -634
- package/dist/index.d.ts +19 -634
- package/dist/index.js +82 -699
- package/dist/manifest.cjs +200 -4
- package/dist/manifest.d.cts +260 -5
- package/dist/manifest.d.ts +260 -5
- package/dist/manifest.js +15 -1
- package/dist/mcp/client.cjs +180 -0
- package/dist/mcp/client.d.cts +49 -0
- package/dist/mcp/client.d.ts +49 -0
- package/dist/mcp/client.js +10 -0
- package/dist/mcp/server.cjs +370 -0
- package/dist/mcp/server.d.cts +127 -0
- package/dist/mcp/server.d.ts +127 -0
- package/dist/mcp/server.js +9 -0
- package/dist/mcp.cjs +376 -0
- package/dist/mcp.d.cts +2 -0
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.js +17 -0
- package/dist/model.cjs +141 -0
- package/dist/model.d.cts +33 -0
- package/dist/model.d.ts +33 -0
- package/dist/model.js +18 -0
- package/dist/plugin.cjs +46 -0
- package/dist/plugin.d.cts +215 -0
- package/dist/plugin.d.ts +215 -0
- package/dist/plugin.js +8 -0
- package/dist/runnable.cjs +1438 -0
- package/dist/runnable.d.cts +274 -0
- package/dist/runnable.d.ts +274 -0
- package/dist/runnable.js +34 -0
- package/dist/{index-B6SkaAjJ.d.ts → tool-AjkdFvhE.d.ts} +88 -461
- package/dist/{index-BvAB5eMk.d.cts → tool-CgzW92O_.d.cts} +88 -461
- package/package.json +48 -3
- package/src/agent/loop.test.ts +4 -4
- package/src/agent/tools.ts +3 -3
- package/src/agent-plugin.test.ts +58 -0
- package/src/agent-plugin.ts +109 -36
- package/src/builder.ts +9 -0
- package/src/cli/dev.test.ts +26 -47
- package/src/cli/dev.ts +10 -2
- package/src/cli-security.test.ts +109 -0
- package/src/cli.ts +141 -25
- package/src/contracts-lockstep.test.ts +16 -2
- package/src/exports-lockstep.test.ts +93 -0
- package/src/generated/plugin-manifest.ts +322 -29
- package/src/index.ts +53 -0
- package/src/manifest-schema.test.ts +30 -1
- package/src/manifest.fixtures.test.ts +22 -6
- package/src/manifest.test.ts +165 -10
- package/src/manifest.ts +454 -188
- package/src/mcp/index.ts +18 -0
- package/src/mcp/server.ts +2 -1
- package/src/model/index.ts +22 -0
- package/src/plugin/ryu-plugin.ts +82 -0
- package/src/runnable/action.test.ts +128 -0
- package/src/runnable/action.ts +202 -0
- package/src/runnable/app.test.ts +2 -0
- package/src/runnable/app.ts +50 -14
- package/src/runnable/index.ts +20 -3
- package/src/runnable/primitives.test.ts +34 -0
- package/src/runnable/primitives.ts +116 -0
- package/src/runnable/runnable-types.ts +3 -0
- package/src/runnable/tool.ts +36 -5
- package/src/runnable/turn-hook.ts +8 -3
- package/src/slash-command.test.ts +69 -0
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,10 @@ __export(src_exports, {
|
|
|
37
37
|
CapabilityReqSchema: () => CapabilityReqSchema,
|
|
38
38
|
CompanionSurfaceSchema: () => CompanionSurfaceSchema,
|
|
39
39
|
DEFAULT_GATEWAY_URL: () => DEFAULT_GATEWAY_URL,
|
|
40
|
+
MCP_PROTOCOL_VERSION: () => MCP_PROTOCOL_VERSION,
|
|
41
|
+
McpServer: () => McpServer,
|
|
42
|
+
McpServerAuthSchema: () => McpServerAuthSchema,
|
|
43
|
+
McpServerDeclSchema: () => McpServerDeclSchema,
|
|
40
44
|
ModelClient: () => ModelClient2,
|
|
41
45
|
PRIMITIVE_BINDINGS: () => PRIMITIVE_BINDINGS,
|
|
42
46
|
PluginBuilder: () => PluginBuilder,
|
|
@@ -45,6 +49,10 @@ __export(src_exports, {
|
|
|
45
49
|
RunnableKindSchema: () => RunnableKindSchema,
|
|
46
50
|
RunnableMetaSchema: () => RunnableMetaSchema,
|
|
47
51
|
SkillBuilder: () => SkillBuilder,
|
|
52
|
+
SlashCommandArgumentSchema: () => SlashCommandArgumentSchema,
|
|
53
|
+
SlashCommandContributionSchema: () => SlashCommandContributionSchema,
|
|
54
|
+
SlashCommandCustomOptionSchema: () => SlashCommandCustomOptionSchema,
|
|
55
|
+
SlashCommandOptionSchema: () => SlashCommandOptionSchema,
|
|
48
56
|
SurfaceSchema: () => SurfaceSchema,
|
|
49
57
|
ToolAppConfigSchema: () => ToolAppConfigSchema,
|
|
50
58
|
ToolBuilder: () => ToolBuilder,
|
|
@@ -54,9 +62,11 @@ __export(src_exports, {
|
|
|
54
62
|
app: () => app,
|
|
55
63
|
appToolId: () => appToolId,
|
|
56
64
|
assertAllowedEgressUrl: () => assertAllowedEgressUrl,
|
|
65
|
+
callTool: () => callTool,
|
|
57
66
|
coreManifestJsonSchema: () => coreManifestJsonSchema,
|
|
58
67
|
createAgent: () => createAgent,
|
|
59
68
|
createPrimitives: () => createPrimitives,
|
|
69
|
+
defineAction: () => defineAction,
|
|
60
70
|
defineAgent: () => defineAgent,
|
|
61
71
|
defineApp: () => defineApp,
|
|
62
72
|
defineModel: () => defineModel,
|
|
@@ -67,19 +77,22 @@ __export(src_exports, {
|
|
|
67
77
|
defineWorkflow: () => defineWorkflow,
|
|
68
78
|
httpPrimitiveTransport: () => httpPrimitiveTransport,
|
|
69
79
|
inlineToolRunnable: () => inlineToolRunnable,
|
|
80
|
+
listTools: () => listTools,
|
|
70
81
|
query: () => query,
|
|
71
82
|
resolveGatewayToken: () => resolveGatewayToken2,
|
|
72
83
|
resolveGatewayUrl: () => resolveGatewayUrl3,
|
|
73
84
|
ryuTool: () => ryuTool,
|
|
74
85
|
skill: () => skill,
|
|
86
|
+
toDisposable: () => toDisposable,
|
|
75
87
|
tool: () => tool,
|
|
88
|
+
unwrapContent: () => unwrapContent,
|
|
76
89
|
validateManifestStrict: () => validateManifestStrict,
|
|
77
90
|
validatePluginId: () => validatePluginId,
|
|
78
91
|
workflow: () => workflow
|
|
79
92
|
});
|
|
80
93
|
module.exports = __toCommonJS(src_exports);
|
|
81
94
|
|
|
82
|
-
// ../../node_modules/.bun/tsup@8.5.1+
|
|
95
|
+
// ../../node_modules/.bun/tsup@8.5.1+68ce2442ac00f52e/node_modules/tsup/assets/cjs_shims.js
|
|
83
96
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
84
97
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
85
98
|
|
|
@@ -317,6 +330,41 @@ var PRIMITIVE_BINDINGS = {
|
|
|
317
330
|
method: "model.complete",
|
|
318
331
|
grant: "hook:side-model"
|
|
319
332
|
},
|
|
333
|
+
"background.list": {
|
|
334
|
+
transport: "bridge",
|
|
335
|
+
method: "background.list",
|
|
336
|
+
grant: "background:control"
|
|
337
|
+
},
|
|
338
|
+
"background.stop": {
|
|
339
|
+
transport: "bridge",
|
|
340
|
+
method: "background.stop",
|
|
341
|
+
grant: "background:control"
|
|
342
|
+
},
|
|
343
|
+
"storage.get": {
|
|
344
|
+
transport: "bridge",
|
|
345
|
+
method: "storage.get",
|
|
346
|
+
grant: "storage:kv"
|
|
347
|
+
},
|
|
348
|
+
"storage.set": {
|
|
349
|
+
transport: "bridge",
|
|
350
|
+
method: "storage.set",
|
|
351
|
+
grant: "storage:kv"
|
|
352
|
+
},
|
|
353
|
+
"storage.delete": {
|
|
354
|
+
transport: "bridge",
|
|
355
|
+
method: "storage.delete",
|
|
356
|
+
grant: "storage:kv"
|
|
357
|
+
},
|
|
358
|
+
"storage.keys": {
|
|
359
|
+
transport: "bridge",
|
|
360
|
+
method: "storage.keys",
|
|
361
|
+
grant: "storage:kv"
|
|
362
|
+
},
|
|
363
|
+
"storage.compareAndSet": {
|
|
364
|
+
transport: "bridge",
|
|
365
|
+
method: "storage.compareAndSet",
|
|
366
|
+
grant: "storage:kv"
|
|
367
|
+
},
|
|
320
368
|
// Host-direct media data-path (the host holds the node token; returns data: URLs).
|
|
321
369
|
"image.generate": {
|
|
322
370
|
transport: "direct",
|
|
@@ -350,6 +398,22 @@ function brokerCall(transport, cap, op, input) {
|
|
|
350
398
|
}
|
|
351
399
|
function createPrimitives(transport) {
|
|
352
400
|
return {
|
|
401
|
+
background: {
|
|
402
|
+
list: (input) => transport.bridge("background.list", {
|
|
403
|
+
producer: input?.producer,
|
|
404
|
+
running_only: input?.runningOnly
|
|
405
|
+
}),
|
|
406
|
+
stop: (input) => transport.bridge("background.stop", {
|
|
407
|
+
process_id: input.processId
|
|
408
|
+
})
|
|
409
|
+
},
|
|
410
|
+
storage: {
|
|
411
|
+
get: (input) => transport.bridge("storage.get", input),
|
|
412
|
+
set: (input) => transport.bridge("storage.set", input).then(() => void 0),
|
|
413
|
+
delete: (input) => transport.bridge("storage.delete", input).then(() => void 0),
|
|
414
|
+
keys: (input) => transport.bridge("storage.keys", input ?? {}).then((value) => Array.isArray(value) ? value : []),
|
|
415
|
+
compareAndSet: (input) => transport.bridge("storage.compareAndSet", input)
|
|
416
|
+
},
|
|
353
417
|
rag: {
|
|
354
418
|
retrieve: (input) => brokerCall(transport, "rag", "retrieve", input),
|
|
355
419
|
embed: (input) => brokerCall(transport, "rag", "embed", input),
|
|
@@ -976,8 +1040,38 @@ var WidgetContributionSchema = import_zod.z.object({
|
|
|
976
1040
|
/** Default display mode (`inline` | `fullscreen` | `pip`). */
|
|
977
1041
|
default_display_mode: import_zod.z.string().default(DEFAULT_WIDGET_DISPLAY_MODE)
|
|
978
1042
|
});
|
|
1043
|
+
var ChatWidgetTemplateSchema = import_zod.z.object({
|
|
1044
|
+
id: import_zod.z.string().regex(/^[a-z0-9][a-z0-9._:-]*$/),
|
|
1045
|
+
title: import_zod.z.string().min(1),
|
|
1046
|
+
description: import_zod.z.string().optional(),
|
|
1047
|
+
triggers: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1048
|
+
examples: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1049
|
+
backing: import_zod.z.object({
|
|
1050
|
+
tool_id: import_zod.z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/).optional(),
|
|
1051
|
+
view_id: import_zod.z.string().regex(/^[a-z0-9][a-z0-9._:-]*$/).optional()
|
|
1052
|
+
}),
|
|
1053
|
+
display_mode: import_zod.z.string().min(1),
|
|
1054
|
+
safe_action_ids: import_zod.z.array(import_zod.z.string().regex(/^[a-z0-9][a-z0-9._-]*$/)).default([]),
|
|
1055
|
+
availability: import_zod.z.string().default("available")
|
|
1056
|
+
}).superRefine((value, ctx) => {
|
|
1057
|
+
const count = Number(Boolean(value.backing.tool_id)) + Number(Boolean(value.backing.view_id));
|
|
1058
|
+
if (count !== 1 && value.availability === "available") {
|
|
1059
|
+
ctx.addIssue({
|
|
1060
|
+
code: "custom",
|
|
1061
|
+
path: ["backing"],
|
|
1062
|
+
message: "available templates need exactly one backing tool_id or view_id"
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
if (count > 1) {
|
|
1066
|
+
ctx.addIssue({
|
|
1067
|
+
code: "custom",
|
|
1068
|
+
path: ["backing"],
|
|
1069
|
+
message: "backing must declare at most one of tool_id or view_id"
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
979
1073
|
var ToolAppConfigSchema = import_zod.z.object({
|
|
980
|
-
/** MCP tool slug this runnable wraps — the fully-qualified `<server
|
|
1074
|
+
/** MCP tool slug this runnable wraps — the fully-qualified `<server>.<name>` id. */
|
|
981
1075
|
slug: import_zod.z.string().min(1),
|
|
982
1076
|
/** The tool description the model reads when choosing it. Carried here because a
|
|
983
1077
|
* packed app's manifest is the only channel (there is no `generated.rs`); Core's
|
|
@@ -996,6 +1090,33 @@ var ToolAppConfigSchema = import_zod.z.object({
|
|
|
996
1090
|
/** Optional status label shown when the render tool finishes. */
|
|
997
1091
|
invoked: import_zod.z.string().optional()
|
|
998
1092
|
});
|
|
1093
|
+
var SlashCommandOptionSchema = import_zod.z.object({
|
|
1094
|
+
description: import_zod.z.string().optional(),
|
|
1095
|
+
label: import_zod.z.string().min(1),
|
|
1096
|
+
value: import_zod.z.string().min(1)
|
|
1097
|
+
}).passthrough();
|
|
1098
|
+
var SlashCommandCustomOptionSchema = import_zod.z.union([
|
|
1099
|
+
import_zod.z.literal(true),
|
|
1100
|
+
import_zod.z.object({
|
|
1101
|
+
description: import_zod.z.string().optional(),
|
|
1102
|
+
label: import_zod.z.string().min(1).optional()
|
|
1103
|
+
}).passthrough()
|
|
1104
|
+
]);
|
|
1105
|
+
var SlashCommandArgumentSchema = import_zod.z.object({
|
|
1106
|
+
allow_custom: import_zod.z.boolean().optional(),
|
|
1107
|
+
custom: SlashCommandCustomOptionSchema.optional(),
|
|
1108
|
+
description: import_zod.z.string().optional(),
|
|
1109
|
+
name: import_zod.z.string().min(1),
|
|
1110
|
+
options: import_zod.z.array(SlashCommandOptionSchema).optional()
|
|
1111
|
+
}).passthrough();
|
|
1112
|
+
var SlashCommandContributionSchema = import_zod.z.object({
|
|
1113
|
+
args: import_zod.z.array(SlashCommandArgumentSchema).optional(),
|
|
1114
|
+
body: import_zod.z.string().optional(),
|
|
1115
|
+
command: import_zod.z.string().min(1),
|
|
1116
|
+
description: import_zod.z.string().optional(),
|
|
1117
|
+
id: import_zod.z.string().optional(),
|
|
1118
|
+
parameters: import_zod.z.array(SlashCommandArgumentSchema).optional()
|
|
1119
|
+
}).passthrough();
|
|
999
1120
|
var ContributesSchema = import_zod.z.object({
|
|
1000
1121
|
turn_hooks: import_zod.z.array(TurnHookContributionSchema).default([]),
|
|
1001
1122
|
/** App events this plugin EMITS — the provider half of the hook system, whose
|
|
@@ -1004,13 +1125,20 @@ var ContributesSchema = import_zod.z.object({
|
|
|
1004
1125
|
* signing, leaving an app that emits events nothing is allowed to subscribe to. */
|
|
1005
1126
|
hook_events: import_zod.z.array(HookEventContributionSchema).default([]),
|
|
1006
1127
|
composer_controls: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1128
|
+
/** Chat feature descriptors whose behavior is implemented by the host shell.
|
|
1129
|
+
* Mirrors the Rust-side `Contributes.chat_features`; keeping this field in the
|
|
1130
|
+
* authoring schema prevents `ryu pack` from silently deleting a plugin's chat
|
|
1131
|
+
* feature declaration before signing. */
|
|
1132
|
+
chat_features: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1007
1133
|
settings_tabs: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1008
|
-
slash_commands: import_zod.z.array(
|
|
1134
|
+
slash_commands: import_zod.z.array(SlashCommandContributionSchema).default([]),
|
|
1009
1135
|
/** App widgets (Ryu Apps). Each binds a render tool id to its
|
|
1010
1136
|
* `ui://widget/<slug>.html` template. Mirrors the Rust-side
|
|
1011
1137
|
* `Contributes.widgets` field, without which the CLI's zod parse would strip
|
|
1012
1138
|
* every widget an app authored here declares. */
|
|
1013
1139
|
widgets: import_zod.z.array(WidgetContributionSchema).default([]),
|
|
1140
|
+
/** Metadata-only chat widget templates. */
|
|
1141
|
+
chat_widget_templates: import_zod.z.array(ChatWidgetTemplateSchema).optional(),
|
|
1014
1142
|
/** App-registered sidebar sections (header + live list) and buttons (single nav
|
|
1015
1143
|
* rows). Loosely typed here — the shell owns the spec vocabulary — matching how
|
|
1016
1144
|
* `composer_controls`/`settings_tabs` are declared. Mirrors the Rust-side
|
|
@@ -1023,6 +1151,13 @@ var ContributesSchema = import_zod.z.object({
|
|
|
1023
1151
|
* Rust-side `Contributes.dock_panels`; without it the CLI's zod parse would
|
|
1024
1152
|
* strip the dock panel an app declares here. */
|
|
1025
1153
|
dock_panels: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1154
|
+
/** App-registered live activities (the desktop "Dynamic Island" cards). Loosely
|
|
1155
|
+
* typed for the same reason as the surfaces above — the shell owns the
|
|
1156
|
+
* `spec` vocabulary. Mirrors the Rust-side `Contributes.live_activities`;
|
|
1157
|
+
* without it the CLI's zod parse would strip every live activity an app
|
|
1158
|
+
* declares here, so a packed bundle would ship a dock that silently stays
|
|
1159
|
+
* empty. */
|
|
1160
|
+
live_activities: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1026
1161
|
/** Deletable data categories the app owns — one "Delete all X" row in Settings
|
|
1027
1162
|
* → Danger Zone. Mirrors the Rust-side `Contributes.data_categories`; without
|
|
1028
1163
|
* it the CLI's zod parse would strip the declaration before signing, and the
|
|
@@ -1060,7 +1195,13 @@ var ContributesSchema = import_zod.z.object({
|
|
|
1060
1195
|
* bug: the styles' `.md` files are not carried by the bundle either, so there
|
|
1061
1196
|
* would be no residue to notice — the plugin would install clean and contribute
|
|
1062
1197
|
* nothing. */
|
|
1063
|
-
output_styles: import_zod.z.array(OutputStyleContributionSchema).default([])
|
|
1198
|
+
output_styles: import_zod.z.array(OutputStyleContributionSchema).default([]),
|
|
1199
|
+
/** Per-message actions contributed by an enabled plugin. Kept as loose records
|
|
1200
|
+
* so renderer-specific `kind`/`args` payloads survive `ryu pack` unchanged. */
|
|
1201
|
+
message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
1202
|
+
/** Buttons contributed to the floating text-selection toolbar. Kept as loose
|
|
1203
|
+
* records so host-owned dispatch args survive `ryu pack` unchanged. */
|
|
1204
|
+
selection_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
|
|
1064
1205
|
});
|
|
1065
1206
|
var SetupStepSchema = import_zod.z.object({
|
|
1066
1207
|
/** Card heading (e.g. the companion app name). */
|
|
@@ -1141,6 +1282,61 @@ var EnginesReqSchema = import_zod.z.object({
|
|
|
1141
1282
|
/** Floor for the Next.js web app. */
|
|
1142
1283
|
web: import_zod.z.string().optional()
|
|
1143
1284
|
});
|
|
1285
|
+
var McpServerAuthSchema = import_zod.z.object({
|
|
1286
|
+
client_id: import_zod.z.string().min(1).optional(),
|
|
1287
|
+
type: import_zod.z.literal("oauth")
|
|
1288
|
+
}).strict();
|
|
1289
|
+
var McpServerDeclSchema = import_zod.z.object({
|
|
1290
|
+
args: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1291
|
+
auth: McpServerAuthSchema.optional(),
|
|
1292
|
+
command: import_zod.z.string().optional(),
|
|
1293
|
+
command_env: import_zod.z.string().optional(),
|
|
1294
|
+
description: import_zod.z.string().optional(),
|
|
1295
|
+
enabled: import_zod.z.boolean().default(true),
|
|
1296
|
+
env: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).default({}),
|
|
1297
|
+
headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).default({}),
|
|
1298
|
+
type: import_zod.z.enum(["stdio", "http", "streamable-http", "streamable_http", "sse"]).optional(),
|
|
1299
|
+
url: import_zod.z.url().optional()
|
|
1300
|
+
}).superRefine((server, context) => {
|
|
1301
|
+
if (!(server.command || server.url)) {
|
|
1302
|
+
context.addIssue({
|
|
1303
|
+
code: "custom",
|
|
1304
|
+
message: "an MCP server requires command or url"
|
|
1305
|
+
});
|
|
1306
|
+
}
|
|
1307
|
+
if (!server.auth) {
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
if (server.command || server.type === "stdio" || !server.url) {
|
|
1311
|
+
context.addIssue({
|
|
1312
|
+
code: "custom",
|
|
1313
|
+
message: "OAuth is supported only for remote HTTP MCP servers"
|
|
1314
|
+
});
|
|
1315
|
+
return;
|
|
1316
|
+
}
|
|
1317
|
+
if (Object.keys(server.headers).some(
|
|
1318
|
+
(name) => name.toLowerCase() === "authorization"
|
|
1319
|
+
)) {
|
|
1320
|
+
context.addIssue({
|
|
1321
|
+
code: "custom",
|
|
1322
|
+
message: "OAuth cannot be combined with a static Authorization header"
|
|
1323
|
+
});
|
|
1324
|
+
}
|
|
1325
|
+
const url = new URL(server.url);
|
|
1326
|
+
const loopback = url.hostname === "localhost" || url.hostname.startsWith("127.") || url.hostname === "[::1]" || url.hostname === "::1";
|
|
1327
|
+
if (url.username || url.password || url.hash) {
|
|
1328
|
+
context.addIssue({
|
|
1329
|
+
code: "custom",
|
|
1330
|
+
message: "OAuth MCP URLs cannot contain credentials or fragments"
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
|
|
1334
|
+
context.addIssue({
|
|
1335
|
+
code: "custom",
|
|
1336
|
+
message: "OAuth MCP URLs must use HTTPS except on loopback"
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
});
|
|
1144
1340
|
var PluginManifestSchema = import_zod.z.object({
|
|
1145
1341
|
/** Reverse-domain unique identifier (e.g. `"com.example.my-plugin"`). */
|
|
1146
1342
|
id: import_zod.z.string().min(1, "id is required"),
|
|
@@ -1155,6 +1351,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1155
1351
|
/^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/,
|
|
1156
1352
|
"version must be a valid semver string (e.g. 1.0.0)"
|
|
1157
1353
|
),
|
|
1354
|
+
/** Core-owned release maturity metadata. The Rust contract validates the
|
|
1355
|
+
* richer shape; the SDK authoring parser must preserve it for pack/publish. */
|
|
1356
|
+
stability: import_zod.z.unknown().optional(),
|
|
1158
1357
|
/**
|
|
1159
1358
|
* Lower-case hex `sha256(utf8_bytes(ui_code))` binding the plugin's bundled
|
|
1160
1359
|
* sandboxed-UI code to this manifest. `ryu pack` / `ryu publish` compute it and
|
|
@@ -1172,6 +1371,26 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1172
1371
|
* Declarations only — grant enforcement is the Gateway's responsibility.
|
|
1173
1372
|
*/
|
|
1174
1373
|
permission_grants: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1374
|
+
/** Deny-by-default sandbox permissions. Core remains authoritative; this
|
|
1375
|
+
* schema mirrors the fields so `ryu pack` cannot strip them. */
|
|
1376
|
+
permissions: import_zod.z.object({
|
|
1377
|
+
fs: import_zod.z.object({
|
|
1378
|
+
read: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1379
|
+
write: import_zod.z.array(import_zod.z.string()).default([])
|
|
1380
|
+
}).optional(),
|
|
1381
|
+
child_process: import_zod.z.boolean().optional(),
|
|
1382
|
+
run: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1383
|
+
network: import_zod.z.union([import_zod.z.boolean(), import_zod.z.array(import_zod.z.string())]).optional(),
|
|
1384
|
+
tool: import_zod.z.array(import_zod.z.string()).default([])
|
|
1385
|
+
}).optional(),
|
|
1386
|
+
/** Core-owned permission presentation levels. Preserved verbatim here and
|
|
1387
|
+
* validated by Core's authoritative manifest contract. */
|
|
1388
|
+
permission_levels: import_zod.z.unknown().optional(),
|
|
1389
|
+
/** Remote or stdio MCP servers registered by this plugin. */
|
|
1390
|
+
mcp_servers: import_zod.z.record(import_zod.z.string(), McpServerDeclSchema).optional(),
|
|
1391
|
+
/** Core-owned sidecar declarations. Their full process/HTTP schema stays in
|
|
1392
|
+
* the Rust contract; this authoring layer must never strip them. */
|
|
1393
|
+
sidecars: import_zod.z.unknown().optional(),
|
|
1175
1394
|
/**
|
|
1176
1395
|
* Optional Companion surface (an in-desktop overlay or sidebar panel).
|
|
1177
1396
|
* Absent when the plugin has no Companion surface.
|
|
@@ -1207,6 +1426,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1207
1426
|
* an unsupported-target plugin stays installable and inspectable.
|
|
1208
1427
|
*/
|
|
1209
1428
|
targets: import_zod.z.array(SurfaceSchema).default([]),
|
|
1429
|
+
/** Rich per-surface declarations (`support`, UI, contributed commands, …).
|
|
1430
|
+
* Core owns and validates the nested vocabulary. */
|
|
1431
|
+
surfaces: import_zod.z.unknown().optional(),
|
|
1210
1432
|
/**
|
|
1211
1433
|
* Host version floors — the semver requirement each surface must satisfy for
|
|
1212
1434
|
* this plugin to install. Mirrors Core's `EnginesReq`
|
|
@@ -1265,10 +1487,16 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1265
1487
|
url: import_zod.z.string().optional()
|
|
1266
1488
|
})
|
|
1267
1489
|
]).optional(),
|
|
1490
|
+
/** Public source repository URL (Claude/Codex `repository`). */
|
|
1491
|
+
repository: import_zod.z.string().url().optional(),
|
|
1492
|
+
/** True when the provider operates outside the local Ryu runtime. */
|
|
1493
|
+
external: import_zod.z.boolean().optional(),
|
|
1268
1494
|
/** Project/marketing homepage — maps to the listing `website` (Claude field). */
|
|
1269
1495
|
homepage: import_zod.z.string().optional(),
|
|
1270
1496
|
/** Free-text search keywords (Claude field). */
|
|
1271
1497
|
keywords: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1498
|
+
/** Stable Marketplace filter labels (Ryu extension). */
|
|
1499
|
+
tags: import_zod.z.array(import_zod.z.string()).optional(),
|
|
1272
1500
|
/** Taxonomy category beyond the runnable kinds (Claude field). */
|
|
1273
1501
|
category: import_zod.z.string().optional(),
|
|
1274
1502
|
/** SPDX-ish license identifier (Claude field). */
|
|
@@ -1282,6 +1510,8 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1282
1510
|
* from `iconUrl` (a raster logo). Falls back to `iconUrl` when omitted.
|
|
1283
1511
|
*/
|
|
1284
1512
|
icon: import_zod.z.string().optional(),
|
|
1513
|
+
/** Optional detail-page hero banner metadata forwarded to the marketplace. */
|
|
1514
|
+
banner: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
1285
1515
|
/**
|
|
1286
1516
|
* Dithered-gradient background for the card's icon square (Ryu extension),
|
|
1287
1517
|
* mirroring dither-kit's `DitherGradient` props. `from`/`to` are a palette-colour
|
|
@@ -1313,6 +1543,22 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1313
1543
|
* array of steps guiding the user through post-install configuration.
|
|
1314
1544
|
*/
|
|
1315
1545
|
setup: import_zod.z.union([SetupStepSchema, import_zod.z.array(SetupStepSchema)]).optional()
|
|
1546
|
+
}).passthrough().superRefine((manifest, context) => {
|
|
1547
|
+
const hasOAuthServer = Object.values(manifest.mcp_servers ?? {}).some(
|
|
1548
|
+
(server) => server.auth?.type === "oauth"
|
|
1549
|
+
);
|
|
1550
|
+
if (!hasOAuthServer) {
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
for (const grant of ["mcp:server", "identity.read"]) {
|
|
1554
|
+
if (!manifest.permission_grants.includes(grant)) {
|
|
1555
|
+
context.addIssue({
|
|
1556
|
+
code: "custom",
|
|
1557
|
+
message: `OAuth MCP servers require the ${grant} permission grant`,
|
|
1558
|
+
path: ["permission_grants"]
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1316
1562
|
});
|
|
1317
1563
|
function validatePluginId(id) {
|
|
1318
1564
|
loadNative().validatePluginId(id);
|
|
@@ -1324,6 +1570,85 @@ function coreManifestJsonSchema() {
|
|
|
1324
1570
|
return JSON.parse(loadNative().pluginManifestJsonSchema());
|
|
1325
1571
|
}
|
|
1326
1572
|
|
|
1573
|
+
// src/runnable/tool.ts
|
|
1574
|
+
function validateInput(input, schema, toolId) {
|
|
1575
|
+
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
1576
|
+
throw new Error(
|
|
1577
|
+
`[ryu-sdk] Tool "${toolId}" input must be an object, got ${JSON.stringify(input)}`
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
const record = input;
|
|
1581
|
+
for (const requiredKey of schema.required ?? []) {
|
|
1582
|
+
if (!(requiredKey in record)) {
|
|
1583
|
+
throw new Error(
|
|
1584
|
+
`[ryu-sdk] Tool "${toolId}" input missing required field "${requiredKey}"`
|
|
1585
|
+
);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1589
|
+
if (!(key in record)) {
|
|
1590
|
+
continue;
|
|
1591
|
+
}
|
|
1592
|
+
const value = record[key];
|
|
1593
|
+
if (!checkType(value, prop.type)) {
|
|
1594
|
+
throw new Error(
|
|
1595
|
+
`[ryu-sdk] Tool "${toolId}" input field "${key}" expected type "${prop.type}", got ${JSON.stringify(value)}`
|
|
1596
|
+
);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
function checkType(value, type) {
|
|
1601
|
+
switch (type) {
|
|
1602
|
+
case "string":
|
|
1603
|
+
return typeof value === "string";
|
|
1604
|
+
case "number":
|
|
1605
|
+
case "integer":
|
|
1606
|
+
return typeof value === "number";
|
|
1607
|
+
case "boolean":
|
|
1608
|
+
return typeof value === "boolean";
|
|
1609
|
+
case "array":
|
|
1610
|
+
return Array.isArray(value);
|
|
1611
|
+
case "object":
|
|
1612
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1613
|
+
default:
|
|
1614
|
+
return false;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
function defineTool(options) {
|
|
1618
|
+
const { description, id, name, schema, run } = options;
|
|
1619
|
+
const code = `return await (${run.toString()})(input, host);`;
|
|
1620
|
+
return {
|
|
1621
|
+
id,
|
|
1622
|
+
name,
|
|
1623
|
+
kind: "tool",
|
|
1624
|
+
schema,
|
|
1625
|
+
...description === void 0 ? {} : { description },
|
|
1626
|
+
code,
|
|
1627
|
+
run(input, ctx) {
|
|
1628
|
+
validateInput(input, schema, id);
|
|
1629
|
+
return run(input, ctx);
|
|
1630
|
+
}
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
function inlineToolRunnable(tool2, options) {
|
|
1634
|
+
return {
|
|
1635
|
+
id: tool2.id,
|
|
1636
|
+
name: tool2.name,
|
|
1637
|
+
kind: "tool",
|
|
1638
|
+
config: {
|
|
1639
|
+
slug: tool2.id,
|
|
1640
|
+
backend: "inline_deno",
|
|
1641
|
+
code: tool2.code,
|
|
1642
|
+
input_schema: tool2.schema,
|
|
1643
|
+
...options?.description === void 0 ? tool2.description === void 0 ? {} : { description: tool2.description } : { description: options.description },
|
|
1644
|
+
...options?.outputSchema ? { output_schema: options.outputSchema } : {},
|
|
1645
|
+
...options?.annotations ? { annotations: options.annotations } : {},
|
|
1646
|
+
...options?.action === void 0 ? {} : { action: options.action },
|
|
1647
|
+
...options?.needsApproval === void 0 ? {} : { needs_approval: options.needsApproval }
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1327
1652
|
// src/runnable/app.ts
|
|
1328
1653
|
var DEFAULT_APP_WIDGET_MIME = "text/html+skybridge";
|
|
1329
1654
|
var DEFAULT_APP_DISPLAY_MODE = "inline";
|
|
@@ -1335,8 +1660,15 @@ function withWidgetRenderGrant(grants, widgets) {
|
|
|
1335
1660
|
}
|
|
1336
1661
|
return out;
|
|
1337
1662
|
}
|
|
1663
|
+
function withToolExecuteGrant(grants, tools) {
|
|
1664
|
+
const out = [...grants];
|
|
1665
|
+
if (tools.some((tool2) => tool2.runnable !== void 0) && !out.includes("tool:execute")) {
|
|
1666
|
+
out.push("tool:execute");
|
|
1667
|
+
}
|
|
1668
|
+
return out;
|
|
1669
|
+
}
|
|
1338
1670
|
function appToolId(server, name) {
|
|
1339
|
-
return `${server}
|
|
1671
|
+
return `${server}.${name}`;
|
|
1340
1672
|
}
|
|
1341
1673
|
function defineApp(options) {
|
|
1342
1674
|
const server = options.server ?? options.slug;
|
|
@@ -1349,7 +1681,9 @@ function defineApp(options) {
|
|
|
1349
1681
|
for (const spec of options.tools) {
|
|
1350
1682
|
const isRender = spec.accessible !== true;
|
|
1351
1683
|
const id = appToolId(server, spec.name);
|
|
1684
|
+
const executable = spec.runnable ? inlineToolRunnable(spec.runnable) : void 0;
|
|
1352
1685
|
const config = {
|
|
1686
|
+
...executable?.config ?? {},
|
|
1353
1687
|
slug: id,
|
|
1354
1688
|
description: spec.description,
|
|
1355
1689
|
widget: isRender,
|
|
@@ -1376,16 +1710,18 @@ function defineApp(options) {
|
|
|
1376
1710
|
}
|
|
1377
1711
|
const contributes = {
|
|
1378
1712
|
turn_hooks: [],
|
|
1713
|
+
chat_features: [],
|
|
1379
1714
|
// This builder synthesises an app from its runnables; an app that emits
|
|
1380
1715
|
// events declares them in a hand-authored `manifest.json`, same as
|
|
1381
1716
|
// `lsp_servers` below.
|
|
1382
1717
|
hook_events: [],
|
|
1383
1718
|
composer_controls: [],
|
|
1384
1719
|
settings_tabs: [],
|
|
1385
|
-
slash_commands: [],
|
|
1720
|
+
slash_commands: options.slashCommands ?? [],
|
|
1386
1721
|
sidebar_sections: [],
|
|
1387
1722
|
sidebar_buttons: [],
|
|
1388
1723
|
dock_panels: [],
|
|
1724
|
+
live_activities: [],
|
|
1389
1725
|
// Empty for the same reason as every sibling family above: this builder
|
|
1390
1726
|
// synthesises `widgets` from the app's own runnables and nothing else, and
|
|
1391
1727
|
// takes no `contributes` passthrough. An app that wants to declare language
|
|
@@ -1398,6 +1734,8 @@ function defineApp(options) {
|
|
|
1398
1734
|
data_categories: [],
|
|
1399
1735
|
pi_extensions: [],
|
|
1400
1736
|
output_styles: [],
|
|
1737
|
+
message_actions: [],
|
|
1738
|
+
selection_actions: [],
|
|
1401
1739
|
widgets
|
|
1402
1740
|
};
|
|
1403
1741
|
const raw = {
|
|
@@ -1411,15 +1749,15 @@ function defineApp(options) {
|
|
|
1411
1749
|
// Core gates widget promotion on declared-AND-enabled-AND-granted, and a
|
|
1412
1750
|
// missing grant fails as `DeniedNoGrant` — which is an `info!` log and
|
|
1413
1751
|
// nothing else. The widget silently renders as plain text, with no error
|
|
1414
|
-
// in the UI and nothing pointing at the manifest.
|
|
1415
|
-
// through `defineApp` hit that, because the only fix was a grant string
|
|
1416
|
-
// the templates never mention and the builder never added; the one
|
|
1417
|
-
// working example on disk hand-writes it.
|
|
1752
|
+
// in the UI and nothing pointing at the manifest.
|
|
1418
1753
|
//
|
|
1419
1754
|
// Added only when there is a widget to render, and unioned rather than
|
|
1420
1755
|
// overwritten so an author's own `grants` list survives and re-declaring
|
|
1421
1756
|
// it is not an error.
|
|
1422
|
-
permission_grants:
|
|
1757
|
+
permission_grants: withToolExecuteGrant(
|
|
1758
|
+
withWidgetRenderGrant(options.grants ?? [], widgets),
|
|
1759
|
+
options.tools
|
|
1760
|
+
),
|
|
1423
1761
|
activation_events: options.activationEvents ?? ["*"],
|
|
1424
1762
|
contributes,
|
|
1425
1763
|
// `targets: []` means EVERY surface, so an app that declares none is
|
|
@@ -1660,6 +1998,7 @@ var AppBuilder = class {
|
|
|
1660
1998
|
_dependencies = [];
|
|
1661
1999
|
_requiredCapabilities = [];
|
|
1662
2000
|
_requiredGrants = [];
|
|
2001
|
+
_slashCommands = [];
|
|
1663
2002
|
_targets = [];
|
|
1664
2003
|
/** Set the reverse-domain app id (e.g. `"com.example.checklist"`). */
|
|
1665
2004
|
id(value) {
|
|
@@ -1716,6 +2055,11 @@ var AppBuilder = class {
|
|
|
1716
2055
|
this._tools.push(spec);
|
|
1717
2056
|
return this;
|
|
1718
2057
|
}
|
|
2058
|
+
/** Add a slash command and its optional sequential argument choices. */
|
|
2059
|
+
slashCommand(command) {
|
|
2060
|
+
this._slashCommands.push(command);
|
|
2061
|
+
return this;
|
|
2062
|
+
}
|
|
1719
2063
|
/**
|
|
1720
2064
|
* Declare a **plugin-to-plugin dependency** (auto-enabled, in dependency order,
|
|
1721
2065
|
* before this app). `minVersion` is a MINIMUM (`"1.2.0"` = `">=1.2.0"`).
|
|
@@ -1763,6 +2107,7 @@ var AppBuilder = class {
|
|
|
1763
2107
|
uiEntry: this._uiEntry,
|
|
1764
2108
|
tools: this._tools,
|
|
1765
2109
|
grants: this._grants,
|
|
2110
|
+
slashCommands: this._slashCommands,
|
|
1766
2111
|
...this._server ? { server: this._server } : {},
|
|
1767
2112
|
...this._displayMode ? { displayMode: this._displayMode } : {},
|
|
1768
2113
|
...this._mime ? { mime: this._mime } : {},
|
|
@@ -1781,6 +2126,442 @@ var AppBuilder = class {
|
|
|
1781
2126
|
};
|
|
1782
2127
|
var app = () => new AppBuilder();
|
|
1783
2128
|
|
|
2129
|
+
// src/mcp/client.ts
|
|
2130
|
+
var import_node_child_process = require("child_process");
|
|
2131
|
+
var import_node_readline = require("readline");
|
|
2132
|
+
var MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
2133
|
+
var RPC_TIMEOUT_MS = 6e4;
|
|
2134
|
+
var McpConnection = class _McpConnection {
|
|
2135
|
+
proc;
|
|
2136
|
+
nextId = 1;
|
|
2137
|
+
closed = false;
|
|
2138
|
+
waiters = [];
|
|
2139
|
+
constructor(proc) {
|
|
2140
|
+
this.proc = proc;
|
|
2141
|
+
}
|
|
2142
|
+
/** Spawn the server and complete the MCP `initialize` handshake. */
|
|
2143
|
+
static async connect(cmd) {
|
|
2144
|
+
const env2 = { ...process.env, ...cmd.env ?? {} };
|
|
2145
|
+
const proc = (0, import_node_child_process.spawn)(cmd.command, cmd.args ?? [], {
|
|
2146
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
2147
|
+
env: env2
|
|
2148
|
+
});
|
|
2149
|
+
if (!(proc.stdin && proc.stdout)) {
|
|
2150
|
+
proc.kill();
|
|
2151
|
+
throw new Error(`MCP server '${cmd.command}' stdin/stdout unavailable`);
|
|
2152
|
+
}
|
|
2153
|
+
if (proc.stderr) {
|
|
2154
|
+
proc.stderr.on("data", (chunk) => {
|
|
2155
|
+
process.stderr.write(`[mcp-server] ${chunk.toString()}`);
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
const conn = new _McpConnection(proc);
|
|
2159
|
+
const rl = (0, import_node_readline.createInterface)({
|
|
2160
|
+
input: proc.stdout,
|
|
2161
|
+
crlfDelay: Number.POSITIVE_INFINITY
|
|
2162
|
+
});
|
|
2163
|
+
rl.on("line", (rawLine) => {
|
|
2164
|
+
const trimmed = rawLine.trim();
|
|
2165
|
+
if (!trimmed) {
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
let parsed;
|
|
2169
|
+
try {
|
|
2170
|
+
parsed = JSON.parse(trimmed);
|
|
2171
|
+
} catch {
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
if (parsed.id === void 0 || parsed.id === null) {
|
|
2175
|
+
return;
|
|
2176
|
+
}
|
|
2177
|
+
const idx = conn.waiters.findIndex((w) => w.id === parsed.id);
|
|
2178
|
+
if (idx === -1) {
|
|
2179
|
+
return;
|
|
2180
|
+
}
|
|
2181
|
+
const [waiter] = conn.waiters.splice(idx, 1);
|
|
2182
|
+
if (!waiter) {
|
|
2183
|
+
return;
|
|
2184
|
+
}
|
|
2185
|
+
clearTimeout(waiter.timer);
|
|
2186
|
+
if (parsed.error) {
|
|
2187
|
+
waiter.reject(new Error(`MCP error: ${JSON.stringify(parsed.error)}`));
|
|
2188
|
+
} else {
|
|
2189
|
+
waiter.resolve(parsed.result ?? null);
|
|
2190
|
+
}
|
|
2191
|
+
});
|
|
2192
|
+
rl.on("close", () => {
|
|
2193
|
+
for (const waiter of conn.waiters.splice(0)) {
|
|
2194
|
+
clearTimeout(waiter.timer);
|
|
2195
|
+
waiter.reject(new Error("MCP server closed the connection"));
|
|
2196
|
+
}
|
|
2197
|
+
});
|
|
2198
|
+
await conn.request("initialize", {
|
|
2199
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
2200
|
+
capabilities: {},
|
|
2201
|
+
clientInfo: { name: "ryu-sdk", version: "0.0.1" }
|
|
2202
|
+
});
|
|
2203
|
+
conn.notify("notifications/initialized", {});
|
|
2204
|
+
return conn;
|
|
2205
|
+
}
|
|
2206
|
+
/** Send a JSON-RPC request and return the `result` field. */
|
|
2207
|
+
request(method, params) {
|
|
2208
|
+
const id = this.nextId++;
|
|
2209
|
+
const frame = JSON.stringify({
|
|
2210
|
+
jsonrpc: "2.0",
|
|
2211
|
+
id,
|
|
2212
|
+
method,
|
|
2213
|
+
params
|
|
2214
|
+
});
|
|
2215
|
+
this.write(frame);
|
|
2216
|
+
return new Promise((resolve, reject) => {
|
|
2217
|
+
const timer = setTimeout(
|
|
2218
|
+
() => reject(new Error(`MCP request '${method}' timed out`)),
|
|
2219
|
+
RPC_TIMEOUT_MS
|
|
2220
|
+
);
|
|
2221
|
+
this.waiters.push({ id, resolve, reject, timer });
|
|
2222
|
+
});
|
|
2223
|
+
}
|
|
2224
|
+
/** Send a JSON-RPC notification (no response expected). */
|
|
2225
|
+
notify(method, params) {
|
|
2226
|
+
const frame = JSON.stringify({ jsonrpc: "2.0", method, params });
|
|
2227
|
+
this.write(frame);
|
|
2228
|
+
}
|
|
2229
|
+
write(frame) {
|
|
2230
|
+
if (this.closed) {
|
|
2231
|
+
return;
|
|
2232
|
+
}
|
|
2233
|
+
this.proc.stdin?.write(`${frame}
|
|
2234
|
+
`);
|
|
2235
|
+
}
|
|
2236
|
+
/** Graceful shutdown: close stdin, then kill. */
|
|
2237
|
+
async shutdown() {
|
|
2238
|
+
this.closed = true;
|
|
2239
|
+
this.proc.stdin?.end();
|
|
2240
|
+
await new Promise((resolve) => {
|
|
2241
|
+
this.proc.once("exit", () => resolve());
|
|
2242
|
+
this.proc.kill();
|
|
2243
|
+
setTimeout(resolve, 500);
|
|
2244
|
+
});
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
async function listTools(cmd) {
|
|
2248
|
+
const conn = await McpConnection.connect(cmd);
|
|
2249
|
+
let result;
|
|
2250
|
+
try {
|
|
2251
|
+
result = await conn.request("tools/list", {});
|
|
2252
|
+
} finally {
|
|
2253
|
+
await conn.shutdown();
|
|
2254
|
+
}
|
|
2255
|
+
const tools = result?.tools ?? [];
|
|
2256
|
+
return tools.map((t) => {
|
|
2257
|
+
const tool2 = t;
|
|
2258
|
+
const name = tool2.name;
|
|
2259
|
+
if (typeof name !== "string") {
|
|
2260
|
+
return null;
|
|
2261
|
+
}
|
|
2262
|
+
return {
|
|
2263
|
+
name,
|
|
2264
|
+
description: typeof tool2.description === "string" ? tool2.description : void 0,
|
|
2265
|
+
inputSchema: tool2.inputSchema
|
|
2266
|
+
};
|
|
2267
|
+
}).filter((t) => t !== null);
|
|
2268
|
+
}
|
|
2269
|
+
async function callTool(cmd, tool2, args) {
|
|
2270
|
+
const conn = await McpConnection.connect(cmd);
|
|
2271
|
+
try {
|
|
2272
|
+
return await conn.request("tools/call", { name: tool2, arguments: args });
|
|
2273
|
+
} finally {
|
|
2274
|
+
await conn.shutdown();
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// src/mcp/server.ts
|
|
2279
|
+
var import_node_readline2 = require("readline");
|
|
2280
|
+
function respond(id, result) {
|
|
2281
|
+
return { jsonrpc: "2.0", id: id ?? null, result };
|
|
2282
|
+
}
|
|
2283
|
+
function respondError(id, code, message) {
|
|
2284
|
+
return { jsonrpc: "2.0", id: id ?? null, error: { code, message } };
|
|
2285
|
+
}
|
|
2286
|
+
function wrapContent(value) {
|
|
2287
|
+
return {
|
|
2288
|
+
content: [
|
|
2289
|
+
{
|
|
2290
|
+
type: "text",
|
|
2291
|
+
text: typeof value === "string" ? value : JSON.stringify(value)
|
|
2292
|
+
}
|
|
2293
|
+
]
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2296
|
+
function unwrapContent(raw) {
|
|
2297
|
+
const r = raw;
|
|
2298
|
+
const text = r?.content?.[0]?.text;
|
|
2299
|
+
if (text === void 0) {
|
|
2300
|
+
return raw;
|
|
2301
|
+
}
|
|
2302
|
+
try {
|
|
2303
|
+
return JSON.parse(text);
|
|
2304
|
+
} catch {
|
|
2305
|
+
return text;
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
var McpServer = class {
|
|
2309
|
+
runnables = /* @__PURE__ */ new Map();
|
|
2310
|
+
passthroughs = [];
|
|
2311
|
+
/**
|
|
2312
|
+
* Register an SDK Runnable as an MCP tool.
|
|
2313
|
+
* Returns `this` for chaining.
|
|
2314
|
+
*/
|
|
2315
|
+
register(runnable) {
|
|
2316
|
+
this.runnables.set(runnable.name, runnable);
|
|
2317
|
+
return this;
|
|
2318
|
+
}
|
|
2319
|
+
/**
|
|
2320
|
+
* Register a passthrough to an external MCP stdio server (e.g. Ghost or
|
|
2321
|
+
* Shadow). Tools from that server are fetched lazily and re-advertised.
|
|
2322
|
+
* Returns `this` for chaining.
|
|
2323
|
+
*/
|
|
2324
|
+
passthrough(registration) {
|
|
2325
|
+
this.passthroughs.push(registration);
|
|
2326
|
+
return this;
|
|
2327
|
+
}
|
|
2328
|
+
/** Fetch all tools: local Runnables + passthrough tools. */
|
|
2329
|
+
async allTools() {
|
|
2330
|
+
const local = [...this.runnables.values()].map((r) => ({
|
|
2331
|
+
name: r.name,
|
|
2332
|
+
description: r.description,
|
|
2333
|
+
inputSchema: r.inputSchema
|
|
2334
|
+
}));
|
|
2335
|
+
const remote = [];
|
|
2336
|
+
for (const pt of this.passthroughs) {
|
|
2337
|
+
try {
|
|
2338
|
+
const tools = await listTools(pt.command);
|
|
2339
|
+
remote.push(...tools);
|
|
2340
|
+
} catch (err) {
|
|
2341
|
+
process.stderr.write(
|
|
2342
|
+
`[mcp-server] passthrough '${pt.label}' list_tools failed: ${err}
|
|
2343
|
+
`
|
|
2344
|
+
);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
return [...local, ...remote];
|
|
2348
|
+
}
|
|
2349
|
+
/** Handle a `tools/call` request. */
|
|
2350
|
+
async handleCallTool(name, args) {
|
|
2351
|
+
const local = this.runnables.get(name);
|
|
2352
|
+
if (local) {
|
|
2353
|
+
const result = await local.run(args);
|
|
2354
|
+
return wrapContent(result);
|
|
2355
|
+
}
|
|
2356
|
+
for (const pt of this.passthroughs) {
|
|
2357
|
+
try {
|
|
2358
|
+
const tools = await listTools(pt.command);
|
|
2359
|
+
if (tools.some((t) => t.name === name)) {
|
|
2360
|
+
return await callTool(pt.command, name, args);
|
|
2361
|
+
}
|
|
2362
|
+
} catch {
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
2366
|
+
}
|
|
2367
|
+
/**
|
|
2368
|
+
* Handle a single parsed JSON-RPC request line. Returns the response to write
|
|
2369
|
+
* (or null for notifications that require no response).
|
|
2370
|
+
*/
|
|
2371
|
+
async handleRequest(req, initialized, write) {
|
|
2372
|
+
const { id, method, params } = req;
|
|
2373
|
+
if (method === "initialize") {
|
|
2374
|
+
initialized.value = true;
|
|
2375
|
+
write(
|
|
2376
|
+
respond(id, {
|
|
2377
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
2378
|
+
capabilities: { tools: {} },
|
|
2379
|
+
serverInfo: { name: "ryu-sdk-server", version: "0.0.1" }
|
|
2380
|
+
})
|
|
2381
|
+
);
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
if (method === "notifications/initialized") {
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
if (!initialized.value) {
|
|
2388
|
+
write(respondError(id, -32002, "Server not initialized"));
|
|
2389
|
+
return;
|
|
2390
|
+
}
|
|
2391
|
+
if (method === "tools/list") {
|
|
2392
|
+
try {
|
|
2393
|
+
const tools = await this.allTools();
|
|
2394
|
+
write(respond(id, { tools }));
|
|
2395
|
+
} catch (err) {
|
|
2396
|
+
write(respondError(id, -32603, String(err)));
|
|
2397
|
+
}
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2400
|
+
if (method === "tools/call") {
|
|
2401
|
+
await this.handleToolsCall(id, params, write);
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
write(respondError(id, -32601, `Method not found: ${method}`));
|
|
2405
|
+
}
|
|
2406
|
+
/** Handle a `tools/call` JSON-RPC request. */
|
|
2407
|
+
async handleToolsCall(id, params, write) {
|
|
2408
|
+
const p = params;
|
|
2409
|
+
const toolName = p?.name;
|
|
2410
|
+
const toolArgs = p?.arguments ?? {};
|
|
2411
|
+
if (typeof toolName !== "string") {
|
|
2412
|
+
write(respondError(id, -32602, "tools/call requires 'name'"));
|
|
2413
|
+
return;
|
|
2414
|
+
}
|
|
2415
|
+
try {
|
|
2416
|
+
const result = await this.handleCallTool(toolName, toolArgs);
|
|
2417
|
+
write(respond(id, result));
|
|
2418
|
+
} catch (err) {
|
|
2419
|
+
write(
|
|
2420
|
+
respond(id, {
|
|
2421
|
+
content: [{ type: "text", text: String(err) }],
|
|
2422
|
+
isError: true
|
|
2423
|
+
})
|
|
2424
|
+
);
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
/**
|
|
2428
|
+
* Start reading JSON-RPC requests from the given readable stream and writing
|
|
2429
|
+
* responses to the given writable stream.
|
|
2430
|
+
*
|
|
2431
|
+
* Defaults to `process.stdin` / `process.stdout`. Passing explicit streams
|
|
2432
|
+
* lets tests inject a pair of in-process pipes.
|
|
2433
|
+
*
|
|
2434
|
+
* Resolves when the input stream ends (EOF).
|
|
2435
|
+
*/
|
|
2436
|
+
serve(input = process.stdin, output = process.stdout) {
|
|
2437
|
+
const write = (obj) => {
|
|
2438
|
+
output.write(`${JSON.stringify(obj)}
|
|
2439
|
+
`);
|
|
2440
|
+
};
|
|
2441
|
+
const initialized = { value: false };
|
|
2442
|
+
return new Promise((resolve) => {
|
|
2443
|
+
const rl = (0, import_node_readline2.createInterface)({
|
|
2444
|
+
input,
|
|
2445
|
+
crlfDelay: Number.POSITIVE_INFINITY
|
|
2446
|
+
});
|
|
2447
|
+
rl.on("line", (rawLine) => {
|
|
2448
|
+
const line = rawLine.trim();
|
|
2449
|
+
if (!line) {
|
|
2450
|
+
return;
|
|
2451
|
+
}
|
|
2452
|
+
let req;
|
|
2453
|
+
try {
|
|
2454
|
+
req = JSON.parse(line);
|
|
2455
|
+
} catch {
|
|
2456
|
+
write(respondError(null, -32700, "Parse error"));
|
|
2457
|
+
return;
|
|
2458
|
+
}
|
|
2459
|
+
this.handleRequest(req, initialized, write).catch((err) => {
|
|
2460
|
+
write(respondError(req.id, -32603, String(err)));
|
|
2461
|
+
});
|
|
2462
|
+
});
|
|
2463
|
+
rl.on("close", resolve);
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2466
|
+
};
|
|
2467
|
+
|
|
2468
|
+
// src/plugin/ryu-plugin.ts
|
|
2469
|
+
function toDisposable(teardown) {
|
|
2470
|
+
let done = false;
|
|
2471
|
+
return {
|
|
2472
|
+
dispose() {
|
|
2473
|
+
if (done) {
|
|
2474
|
+
return;
|
|
2475
|
+
}
|
|
2476
|
+
done = true;
|
|
2477
|
+
teardown();
|
|
2478
|
+
}
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// src/runnable/action.ts
|
|
2483
|
+
function deriveAnnotations(effect, annotations) {
|
|
2484
|
+
const resolved = {
|
|
2485
|
+
...annotations,
|
|
2486
|
+
readOnlyHint: annotations?.readOnlyHint ?? effect === "read",
|
|
2487
|
+
destructiveHint: annotations?.destructiveHint ?? effect === "mutate"
|
|
2488
|
+
};
|
|
2489
|
+
if (effect === "read" && resolved.destructiveHint) {
|
|
2490
|
+
throw new Error(
|
|
2491
|
+
"[ryu-sdk] read actions cannot set annotations.destructiveHint=true"
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
if (effect === "mutate" && resolved.readOnlyHint) {
|
|
2495
|
+
throw new Error(
|
|
2496
|
+
"[ryu-sdk] mutate actions cannot set annotations.readOnlyHint=true"
|
|
2497
|
+
);
|
|
2498
|
+
}
|
|
2499
|
+
return resolved;
|
|
2500
|
+
}
|
|
2501
|
+
function actionManifestEntry(action) {
|
|
2502
|
+
const options = {
|
|
2503
|
+
action: true,
|
|
2504
|
+
annotations: action.annotations,
|
|
2505
|
+
description: action.description,
|
|
2506
|
+
needsApproval: action.needsApproval,
|
|
2507
|
+
...action.outputSchema ? { outputSchema: action.outputSchema } : {}
|
|
2508
|
+
};
|
|
2509
|
+
return inlineToolRunnable(action, options);
|
|
2510
|
+
}
|
|
2511
|
+
function actionToManifest(action, options) {
|
|
2512
|
+
const grants = [.../* @__PURE__ */ new Set([...options.grants ?? [], "tool:execute"])];
|
|
2513
|
+
const raw = {
|
|
2514
|
+
id: options.id,
|
|
2515
|
+
name: options.name ?? action.name,
|
|
2516
|
+
version: options.version,
|
|
2517
|
+
runnables: [actionManifestEntry(action)],
|
|
2518
|
+
permission_grants: grants,
|
|
2519
|
+
activation_events: [...options.activationEvents ?? ["*"]],
|
|
2520
|
+
targets: [...options.targets ?? []]
|
|
2521
|
+
};
|
|
2522
|
+
const result = PluginManifestSchema.safeParse(raw);
|
|
2523
|
+
if (!result.success) {
|
|
2524
|
+
const first = result.error.issues[0];
|
|
2525
|
+
const field = first?.path.join(".") ?? "unknown";
|
|
2526
|
+
const message = first?.message ?? "validation failed";
|
|
2527
|
+
throw new Error(
|
|
2528
|
+
`[ryu-sdk] action manifest validation failed at '${field}': ${message}`
|
|
2529
|
+
);
|
|
2530
|
+
}
|
|
2531
|
+
return result.data;
|
|
2532
|
+
}
|
|
2533
|
+
function defineAction(options) {
|
|
2534
|
+
const annotations = deriveAnnotations(options.effect, options.annotations);
|
|
2535
|
+
const tool2 = defineTool({
|
|
2536
|
+
description: options.description,
|
|
2537
|
+
id: options.id,
|
|
2538
|
+
name: options.name,
|
|
2539
|
+
run: options.run,
|
|
2540
|
+
schema: options.schema
|
|
2541
|
+
});
|
|
2542
|
+
const action = {
|
|
2543
|
+
...tool2,
|
|
2544
|
+
action: true,
|
|
2545
|
+
annotations,
|
|
2546
|
+
description: options.description,
|
|
2547
|
+
effect: options.effect,
|
|
2548
|
+
needsApproval: options.needsApproval ?? false,
|
|
2549
|
+
...options.outputSchema ? { outputSchema: options.outputSchema } : {},
|
|
2550
|
+
toManifest(manifestOptions) {
|
|
2551
|
+
return actionToManifest(action, manifestOptions);
|
|
2552
|
+
},
|
|
2553
|
+
toMcpTool(context) {
|
|
2554
|
+
return {
|
|
2555
|
+
name: action.id,
|
|
2556
|
+
description: action.description,
|
|
2557
|
+
inputSchema: action.schema,
|
|
2558
|
+
run: (input) => action.run(input, context)
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
};
|
|
2562
|
+
return action;
|
|
2563
|
+
}
|
|
2564
|
+
|
|
1784
2565
|
// src/runnable/agent.ts
|
|
1785
2566
|
var CAPABILITY_SLOTS = ["rag", "memory", "tts", "stt"];
|
|
1786
2567
|
function lowerChatSlot(chat) {
|
|
@@ -1925,80 +2706,6 @@ function defineSkill(options) {
|
|
|
1925
2706
|
};
|
|
1926
2707
|
}
|
|
1927
2708
|
|
|
1928
|
-
// src/runnable/tool.ts
|
|
1929
|
-
function validateInput(input, schema, toolId) {
|
|
1930
|
-
if (typeof input !== "object" || input === null || Array.isArray(input)) {
|
|
1931
|
-
throw new Error(
|
|
1932
|
-
`[ryu-sdk] Tool "${toolId}" input must be an object, got ${JSON.stringify(input)}`
|
|
1933
|
-
);
|
|
1934
|
-
}
|
|
1935
|
-
const record = input;
|
|
1936
|
-
for (const requiredKey of schema.required ?? []) {
|
|
1937
|
-
if (!(requiredKey in record)) {
|
|
1938
|
-
throw new Error(
|
|
1939
|
-
`[ryu-sdk] Tool "${toolId}" input missing required field "${requiredKey}"`
|
|
1940
|
-
);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
1944
|
-
if (!(key in record)) {
|
|
1945
|
-
continue;
|
|
1946
|
-
}
|
|
1947
|
-
const value = record[key];
|
|
1948
|
-
if (!checkType(value, prop.type)) {
|
|
1949
|
-
throw new Error(
|
|
1950
|
-
`[ryu-sdk] Tool "${toolId}" input field "${key}" expected type "${prop.type}", got ${JSON.stringify(value)}`
|
|
1951
|
-
);
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
function checkType(value, type) {
|
|
1956
|
-
switch (type) {
|
|
1957
|
-
case "string":
|
|
1958
|
-
return typeof value === "string";
|
|
1959
|
-
case "number":
|
|
1960
|
-
case "integer":
|
|
1961
|
-
return typeof value === "number";
|
|
1962
|
-
case "boolean":
|
|
1963
|
-
return typeof value === "boolean";
|
|
1964
|
-
case "array":
|
|
1965
|
-
return Array.isArray(value);
|
|
1966
|
-
case "object":
|
|
1967
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1968
|
-
default:
|
|
1969
|
-
return false;
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
function defineTool(options) {
|
|
1973
|
-
const { id, name, schema, run } = options;
|
|
1974
|
-
const code = `return await (${run.toString()})(input, host);`;
|
|
1975
|
-
return {
|
|
1976
|
-
id,
|
|
1977
|
-
name,
|
|
1978
|
-
kind: "tool",
|
|
1979
|
-
schema,
|
|
1980
|
-
code,
|
|
1981
|
-
run(input, ctx) {
|
|
1982
|
-
validateInput(input, schema, id);
|
|
1983
|
-
return run(input, ctx);
|
|
1984
|
-
}
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
function inlineToolRunnable(tool2, options) {
|
|
1988
|
-
return {
|
|
1989
|
-
id: tool2.id,
|
|
1990
|
-
name: tool2.name,
|
|
1991
|
-
kind: "tool",
|
|
1992
|
-
config: {
|
|
1993
|
-
slug: tool2.id,
|
|
1994
|
-
backend: "inline_deno",
|
|
1995
|
-
code: tool2.code,
|
|
1996
|
-
input_schema: tool2.schema,
|
|
1997
|
-
...options?.description ? { description: options.description } : {}
|
|
1998
|
-
}
|
|
1999
|
-
};
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
2709
|
// src/runnable/turn-hook.ts
|
|
2003
2710
|
function defineTurnHook(options) {
|
|
2004
2711
|
const source = options.run.toString();
|
|
@@ -2014,6 +2721,7 @@ function definePlugin(options) {
|
|
|
2014
2721
|
turn_hooks: options.turnHooks ?? [],
|
|
2015
2722
|
hook_events: options.hookEvents ?? [],
|
|
2016
2723
|
composer_controls: options.composerControls ?? [],
|
|
2724
|
+
chat_features: [],
|
|
2017
2725
|
settings_tabs: options.settingsTabs ?? [],
|
|
2018
2726
|
slash_commands: options.slashCommands ?? [],
|
|
2019
2727
|
lsp_servers: options.lspServers ?? {},
|
|
@@ -2025,9 +2733,12 @@ function definePlugin(options) {
|
|
|
2025
2733
|
sidebar_sections: [],
|
|
2026
2734
|
sidebar_buttons: [],
|
|
2027
2735
|
dock_panels: [],
|
|
2736
|
+
live_activities: [],
|
|
2028
2737
|
data_categories: [],
|
|
2029
2738
|
pi_extensions: [],
|
|
2030
|
-
output_styles: []
|
|
2739
|
+
output_styles: [],
|
|
2740
|
+
message_actions: [],
|
|
2741
|
+
selection_actions: []
|
|
2031
2742
|
};
|
|
2032
2743
|
const tools = options.tools ?? [];
|
|
2033
2744
|
const runnables = tools.map((t) => inlineToolRunnable(t));
|
|
@@ -2076,6 +2787,10 @@ function defineWorkflow(options) {
|
|
|
2076
2787
|
CapabilityReqSchema,
|
|
2077
2788
|
CompanionSurfaceSchema,
|
|
2078
2789
|
DEFAULT_GATEWAY_URL,
|
|
2790
|
+
MCP_PROTOCOL_VERSION,
|
|
2791
|
+
McpServer,
|
|
2792
|
+
McpServerAuthSchema,
|
|
2793
|
+
McpServerDeclSchema,
|
|
2079
2794
|
ModelClient,
|
|
2080
2795
|
PRIMITIVE_BINDINGS,
|
|
2081
2796
|
PluginBuilder,
|
|
@@ -2084,6 +2799,10 @@ function defineWorkflow(options) {
|
|
|
2084
2799
|
RunnableKindSchema,
|
|
2085
2800
|
RunnableMetaSchema,
|
|
2086
2801
|
SkillBuilder,
|
|
2802
|
+
SlashCommandArgumentSchema,
|
|
2803
|
+
SlashCommandContributionSchema,
|
|
2804
|
+
SlashCommandCustomOptionSchema,
|
|
2805
|
+
SlashCommandOptionSchema,
|
|
2087
2806
|
SurfaceSchema,
|
|
2088
2807
|
ToolAppConfigSchema,
|
|
2089
2808
|
ToolBuilder,
|
|
@@ -2093,9 +2812,11 @@ function defineWorkflow(options) {
|
|
|
2093
2812
|
app,
|
|
2094
2813
|
appToolId,
|
|
2095
2814
|
assertAllowedEgressUrl,
|
|
2815
|
+
callTool,
|
|
2096
2816
|
coreManifestJsonSchema,
|
|
2097
2817
|
createAgent,
|
|
2098
2818
|
createPrimitives,
|
|
2819
|
+
defineAction,
|
|
2099
2820
|
defineAgent,
|
|
2100
2821
|
defineApp,
|
|
2101
2822
|
defineModel,
|
|
@@ -2106,12 +2827,15 @@ function defineWorkflow(options) {
|
|
|
2106
2827
|
defineWorkflow,
|
|
2107
2828
|
httpPrimitiveTransport,
|
|
2108
2829
|
inlineToolRunnable,
|
|
2830
|
+
listTools,
|
|
2109
2831
|
query,
|
|
2110
2832
|
resolveGatewayToken,
|
|
2111
2833
|
resolveGatewayUrl,
|
|
2112
2834
|
ryuTool,
|
|
2113
2835
|
skill,
|
|
2836
|
+
toDisposable,
|
|
2114
2837
|
tool,
|
|
2838
|
+
unwrapContent,
|
|
2115
2839
|
validateManifestStrict,
|
|
2116
2840
|
validatePluginId,
|
|
2117
2841
|
workflow
|