@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.
Files changed (105) hide show
  1. package/README.md +69 -7
  2. package/dist/action.cjs +839 -0
  3. package/dist/action.d.cts +88 -0
  4. package/dist/action.d.ts +88 -0
  5. package/dist/action.js +8 -0
  6. package/dist/agent-plugin.cjs +46 -0
  7. package/dist/agent-plugin.d.cts +43 -33
  8. package/dist/agent-plugin.d.ts +43 -33
  9. package/dist/agent-plugin.js +1 -1
  10. package/dist/agent.cjs +16 -0
  11. package/dist/agent.d.cts +377 -1
  12. package/dist/agent.d.ts +377 -1
  13. package/dist/agent.js +4 -2
  14. package/dist/app-B0Z9Ew_R.d.cts +141 -0
  15. package/dist/app-C-BDJwfG.d.ts +141 -0
  16. package/dist/builder.cjs +1194 -0
  17. package/dist/builder.d.cts +217 -0
  18. package/dist/builder.d.ts +217 -0
  19. package/dist/builder.js +29 -0
  20. package/dist/chunk-4TPUZDTI.js +94 -0
  21. package/dist/chunk-BC3A7HMO.js +164 -0
  22. package/dist/chunk-FZSFZOIN.js +200 -0
  23. package/dist/{chunk-ODFEUVPW.js → chunk-HACAGK65.js} +1 -18
  24. package/dist/chunk-HLKJZAFK.js +361 -0
  25. package/dist/chunk-IKEDLLFY.js +19 -0
  26. package/dist/{chunk-G6FLVEC4.js → chunk-JX6DDRXV.js} +46 -0
  27. package/dist/{chunk-AO2KJRDD.js → chunk-NZKVOSC2.js} +192 -3
  28. package/dist/chunk-QYFUNJOH.js +83 -0
  29. package/dist/chunk-SN2QBJUF.js +148 -0
  30. package/dist/chunk-TLDPEGC7.js +21 -0
  31. package/dist/chunk-TXSHHZF2.js +0 -0
  32. package/dist/chunk-VLIRNNAE.js +154 -0
  33. package/dist/{chunk-MTUBUPIV.js → chunk-Z57QDDJR.js} +8 -227
  34. package/dist/chunk-ZTJWBRUL.js +282 -0
  35. package/dist/cli.cjs +347 -18
  36. package/dist/cli.js +128 -23
  37. package/dist/client-D5U6ssPc.d.cts +84 -0
  38. package/dist/client-D5U6ssPc.d.ts +84 -0
  39. package/dist/index.cjs +810 -86
  40. package/dist/index.d.cts +19 -634
  41. package/dist/index.d.ts +19 -634
  42. package/dist/index.js +82 -699
  43. package/dist/manifest.cjs +200 -4
  44. package/dist/manifest.d.cts +260 -5
  45. package/dist/manifest.d.ts +260 -5
  46. package/dist/manifest.js +15 -1
  47. package/dist/mcp/client.cjs +180 -0
  48. package/dist/mcp/client.d.cts +49 -0
  49. package/dist/mcp/client.d.ts +49 -0
  50. package/dist/mcp/client.js +10 -0
  51. package/dist/mcp/server.cjs +370 -0
  52. package/dist/mcp/server.d.cts +127 -0
  53. package/dist/mcp/server.d.ts +127 -0
  54. package/dist/mcp/server.js +9 -0
  55. package/dist/mcp.cjs +376 -0
  56. package/dist/mcp.d.cts +2 -0
  57. package/dist/mcp.d.ts +2 -0
  58. package/dist/mcp.js +17 -0
  59. package/dist/model.cjs +141 -0
  60. package/dist/model.d.cts +33 -0
  61. package/dist/model.d.ts +33 -0
  62. package/dist/model.js +18 -0
  63. package/dist/plugin.cjs +46 -0
  64. package/dist/plugin.d.cts +215 -0
  65. package/dist/plugin.d.ts +215 -0
  66. package/dist/plugin.js +8 -0
  67. package/dist/runnable.cjs +1438 -0
  68. package/dist/runnable.d.cts +274 -0
  69. package/dist/runnable.d.ts +274 -0
  70. package/dist/runnable.js +34 -0
  71. package/dist/{index-B6SkaAjJ.d.ts → tool-AjkdFvhE.d.ts} +88 -461
  72. package/dist/{index-BvAB5eMk.d.cts → tool-CgzW92O_.d.cts} +88 -461
  73. package/package.json +48 -3
  74. package/src/agent/loop.test.ts +4 -4
  75. package/src/agent/tools.ts +3 -3
  76. package/src/agent-plugin.test.ts +58 -0
  77. package/src/agent-plugin.ts +109 -36
  78. package/src/builder.ts +9 -0
  79. package/src/cli/dev.test.ts +26 -47
  80. package/src/cli/dev.ts +10 -2
  81. package/src/cli-security.test.ts +109 -0
  82. package/src/cli.ts +141 -25
  83. package/src/contracts-lockstep.test.ts +16 -2
  84. package/src/exports-lockstep.test.ts +93 -0
  85. package/src/generated/plugin-manifest.ts +322 -29
  86. package/src/index.ts +53 -0
  87. package/src/manifest-schema.test.ts +30 -1
  88. package/src/manifest.fixtures.test.ts +22 -6
  89. package/src/manifest.test.ts +165 -10
  90. package/src/manifest.ts +454 -188
  91. package/src/mcp/index.ts +18 -0
  92. package/src/mcp/server.ts +2 -1
  93. package/src/model/index.ts +22 -0
  94. package/src/plugin/ryu-plugin.ts +82 -0
  95. package/src/runnable/action.test.ts +128 -0
  96. package/src/runnable/action.ts +202 -0
  97. package/src/runnable/app.test.ts +2 -0
  98. package/src/runnable/app.ts +50 -14
  99. package/src/runnable/index.ts +20 -3
  100. package/src/runnable/primitives.test.ts +34 -0
  101. package/src/runnable/primitives.ts +116 -0
  102. package/src/runnable/runnable-types.ts +3 -0
  103. package/src/runnable/tool.ts +36 -5
  104. package/src/runnable/turn-hook.ts +8 -3
  105. package/src/slash-command.test.ts +69 -0
package/dist/manifest.cjs CHANGED
@@ -22,10 +22,13 @@ var manifest_exports = {};
22
22
  __export(manifest_exports, {
23
23
  AppDependencySchema: () => AppDependencySchema,
24
24
  CapabilityReqSchema: () => CapabilityReqSchema,
25
+ ChatWidgetTemplateSchema: () => ChatWidgetTemplateSchema,
25
26
  CompanionSurfaceSchema: () => CompanionSurfaceSchema,
26
27
  ContributesSchema: () => ContributesSchema,
27
28
  EnginesReqSchema: () => EnginesReqSchema,
28
29
  HookEventContributionSchema: () => HookEventContributionSchema,
30
+ McpServerAuthSchema: () => McpServerAuthSchema,
31
+ McpServerDeclSchema: () => McpServerDeclSchema,
29
32
  OutputStyleContributionSchema: () => OutputStyleContributionSchema,
30
33
  PiExtensionContributionSchema: () => PiExtensionContributionSchema,
31
34
  PluginManifestSchema: () => PluginManifestSchema,
@@ -33,6 +36,10 @@ __export(manifest_exports, {
33
36
  RunnableKindSchema: () => RunnableKindSchema,
34
37
  RunnableMetaSchema: () => RunnableMetaSchema,
35
38
  SetupStepSchema: () => SetupStepSchema,
39
+ SlashCommandArgumentSchema: () => SlashCommandArgumentSchema,
40
+ SlashCommandContributionSchema: () => SlashCommandContributionSchema,
41
+ SlashCommandCustomOptionSchema: () => SlashCommandCustomOptionSchema,
42
+ SlashCommandOptionSchema: () => SlashCommandOptionSchema,
36
43
  SurfaceSchema: () => SurfaceSchema,
37
44
  ToolAppConfigSchema: () => ToolAppConfigSchema,
38
45
  TurnHookContributionSchema: () => TurnHookContributionSchema,
@@ -44,7 +51,7 @@ __export(manifest_exports, {
44
51
  });
45
52
  module.exports = __toCommonJS(manifest_exports);
46
53
 
47
- // ../../node_modules/.bun/tsup@8.5.1+7a7b737fa55947b7/node_modules/tsup/assets/cjs_shims.js
54
+ // ../../node_modules/.bun/tsup@8.5.1+68ce2442ac00f52e/node_modules/tsup/assets/cjs_shims.js
48
55
  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;
49
56
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
50
57
 
@@ -196,8 +203,38 @@ var WidgetContributionSchema = import_zod.z.object({
196
203
  /** Default display mode (`inline` | `fullscreen` | `pip`). */
197
204
  default_display_mode: import_zod.z.string().default(DEFAULT_WIDGET_DISPLAY_MODE)
198
205
  });
206
+ var ChatWidgetTemplateSchema = import_zod.z.object({
207
+ id: import_zod.z.string().regex(/^[a-z0-9][a-z0-9._:-]*$/),
208
+ title: import_zod.z.string().min(1),
209
+ description: import_zod.z.string().optional(),
210
+ triggers: import_zod.z.array(import_zod.z.string()).default([]),
211
+ examples: import_zod.z.array(import_zod.z.string()).default([]),
212
+ backing: import_zod.z.object({
213
+ tool_id: import_zod.z.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:/-]*$/).optional(),
214
+ view_id: import_zod.z.string().regex(/^[a-z0-9][a-z0-9._:-]*$/).optional()
215
+ }),
216
+ display_mode: import_zod.z.string().min(1),
217
+ safe_action_ids: import_zod.z.array(import_zod.z.string().regex(/^[a-z0-9][a-z0-9._-]*$/)).default([]),
218
+ availability: import_zod.z.string().default("available")
219
+ }).superRefine((value, ctx) => {
220
+ const count = Number(Boolean(value.backing.tool_id)) + Number(Boolean(value.backing.view_id));
221
+ if (count !== 1 && value.availability === "available") {
222
+ ctx.addIssue({
223
+ code: "custom",
224
+ path: ["backing"],
225
+ message: "available templates need exactly one backing tool_id or view_id"
226
+ });
227
+ }
228
+ if (count > 1) {
229
+ ctx.addIssue({
230
+ code: "custom",
231
+ path: ["backing"],
232
+ message: "backing must declare at most one of tool_id or view_id"
233
+ });
234
+ }
235
+ });
199
236
  var ToolAppConfigSchema = import_zod.z.object({
200
- /** MCP tool slug this runnable wraps — the fully-qualified `<server>__<name>` id. */
237
+ /** MCP tool slug this runnable wraps — the fully-qualified `<server>.<name>` id. */
201
238
  slug: import_zod.z.string().min(1),
202
239
  /** The tool description the model reads when choosing it. Carried here because a
203
240
  * packed app's manifest is the only channel (there is no `generated.rs`); Core's
@@ -216,6 +253,33 @@ var ToolAppConfigSchema = import_zod.z.object({
216
253
  /** Optional status label shown when the render tool finishes. */
217
254
  invoked: import_zod.z.string().optional()
218
255
  });
256
+ var SlashCommandOptionSchema = import_zod.z.object({
257
+ description: import_zod.z.string().optional(),
258
+ label: import_zod.z.string().min(1),
259
+ value: import_zod.z.string().min(1)
260
+ }).passthrough();
261
+ var SlashCommandCustomOptionSchema = import_zod.z.union([
262
+ import_zod.z.literal(true),
263
+ import_zod.z.object({
264
+ description: import_zod.z.string().optional(),
265
+ label: import_zod.z.string().min(1).optional()
266
+ }).passthrough()
267
+ ]);
268
+ var SlashCommandArgumentSchema = import_zod.z.object({
269
+ allow_custom: import_zod.z.boolean().optional(),
270
+ custom: SlashCommandCustomOptionSchema.optional(),
271
+ description: import_zod.z.string().optional(),
272
+ name: import_zod.z.string().min(1),
273
+ options: import_zod.z.array(SlashCommandOptionSchema).optional()
274
+ }).passthrough();
275
+ var SlashCommandContributionSchema = import_zod.z.object({
276
+ args: import_zod.z.array(SlashCommandArgumentSchema).optional(),
277
+ body: import_zod.z.string().optional(),
278
+ command: import_zod.z.string().min(1),
279
+ description: import_zod.z.string().optional(),
280
+ id: import_zod.z.string().optional(),
281
+ parameters: import_zod.z.array(SlashCommandArgumentSchema).optional()
282
+ }).passthrough();
219
283
  var ContributesSchema = import_zod.z.object({
220
284
  turn_hooks: import_zod.z.array(TurnHookContributionSchema).default([]),
221
285
  /** App events this plugin EMITS — the provider half of the hook system, whose
@@ -224,13 +288,20 @@ var ContributesSchema = import_zod.z.object({
224
288
  * signing, leaving an app that emits events nothing is allowed to subscribe to. */
225
289
  hook_events: import_zod.z.array(HookEventContributionSchema).default([]),
226
290
  composer_controls: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
291
+ /** Chat feature descriptors whose behavior is implemented by the host shell.
292
+ * Mirrors the Rust-side `Contributes.chat_features`; keeping this field in the
293
+ * authoring schema prevents `ryu pack` from silently deleting a plugin's chat
294
+ * feature declaration before signing. */
295
+ chat_features: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
227
296
  settings_tabs: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
228
- slash_commands: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
297
+ slash_commands: import_zod.z.array(SlashCommandContributionSchema).default([]),
229
298
  /** App widgets (Ryu Apps). Each binds a render tool id to its
230
299
  * `ui://widget/<slug>.html` template. Mirrors the Rust-side
231
300
  * `Contributes.widgets` field, without which the CLI's zod parse would strip
232
301
  * every widget an app authored here declares. */
233
302
  widgets: import_zod.z.array(WidgetContributionSchema).default([]),
303
+ /** Metadata-only chat widget templates. */
304
+ chat_widget_templates: import_zod.z.array(ChatWidgetTemplateSchema).optional(),
234
305
  /** App-registered sidebar sections (header + live list) and buttons (single nav
235
306
  * rows). Loosely typed here — the shell owns the spec vocabulary — matching how
236
307
  * `composer_controls`/`settings_tabs` are declared. Mirrors the Rust-side
@@ -243,6 +314,13 @@ var ContributesSchema = import_zod.z.object({
243
314
  * Rust-side `Contributes.dock_panels`; without it the CLI's zod parse would
244
315
  * strip the dock panel an app declares here. */
245
316
  dock_panels: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
317
+ /** App-registered live activities (the desktop "Dynamic Island" cards). Loosely
318
+ * typed for the same reason as the surfaces above — the shell owns the
319
+ * `spec` vocabulary. Mirrors the Rust-side `Contributes.live_activities`;
320
+ * without it the CLI's zod parse would strip every live activity an app
321
+ * declares here, so a packed bundle would ship a dock that silently stays
322
+ * empty. */
323
+ live_activities: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
246
324
  /** Deletable data categories the app owns — one "Delete all X" row in Settings
247
325
  * → Danger Zone. Mirrors the Rust-side `Contributes.data_categories`; without
248
326
  * it the CLI's zod parse would strip the declaration before signing, and the
@@ -280,7 +358,13 @@ var ContributesSchema = import_zod.z.object({
280
358
  * bug: the styles' `.md` files are not carried by the bundle either, so there
281
359
  * would be no residue to notice — the plugin would install clean and contribute
282
360
  * nothing. */
283
- output_styles: import_zod.z.array(OutputStyleContributionSchema).default([])
361
+ output_styles: import_zod.z.array(OutputStyleContributionSchema).default([]),
362
+ /** Per-message actions contributed by an enabled plugin. Kept as loose records
363
+ * so renderer-specific `kind`/`args` payloads survive `ryu pack` unchanged. */
364
+ message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
365
+ /** Buttons contributed to the floating text-selection toolbar. Kept as loose
366
+ * records so host-owned dispatch args survive `ryu pack` unchanged. */
367
+ selection_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
284
368
  });
285
369
  var SetupStepSchema = import_zod.z.object({
286
370
  /** Card heading (e.g. the companion app name). */
@@ -361,6 +445,61 @@ var EnginesReqSchema = import_zod.z.object({
361
445
  /** Floor for the Next.js web app. */
362
446
  web: import_zod.z.string().optional()
363
447
  });
448
+ var McpServerAuthSchema = import_zod.z.object({
449
+ client_id: import_zod.z.string().min(1).optional(),
450
+ type: import_zod.z.literal("oauth")
451
+ }).strict();
452
+ var McpServerDeclSchema = import_zod.z.object({
453
+ args: import_zod.z.array(import_zod.z.string()).default([]),
454
+ auth: McpServerAuthSchema.optional(),
455
+ command: import_zod.z.string().optional(),
456
+ command_env: import_zod.z.string().optional(),
457
+ description: import_zod.z.string().optional(),
458
+ enabled: import_zod.z.boolean().default(true),
459
+ env: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).default({}),
460
+ headers: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).default({}),
461
+ type: import_zod.z.enum(["stdio", "http", "streamable-http", "streamable_http", "sse"]).optional(),
462
+ url: import_zod.z.url().optional()
463
+ }).superRefine((server, context) => {
464
+ if (!(server.command || server.url)) {
465
+ context.addIssue({
466
+ code: "custom",
467
+ message: "an MCP server requires command or url"
468
+ });
469
+ }
470
+ if (!server.auth) {
471
+ return;
472
+ }
473
+ if (server.command || server.type === "stdio" || !server.url) {
474
+ context.addIssue({
475
+ code: "custom",
476
+ message: "OAuth is supported only for remote HTTP MCP servers"
477
+ });
478
+ return;
479
+ }
480
+ if (Object.keys(server.headers).some(
481
+ (name) => name.toLowerCase() === "authorization"
482
+ )) {
483
+ context.addIssue({
484
+ code: "custom",
485
+ message: "OAuth cannot be combined with a static Authorization header"
486
+ });
487
+ }
488
+ const url = new URL(server.url);
489
+ const loopback = url.hostname === "localhost" || url.hostname.startsWith("127.") || url.hostname === "[::1]" || url.hostname === "::1";
490
+ if (url.username || url.password || url.hash) {
491
+ context.addIssue({
492
+ code: "custom",
493
+ message: "OAuth MCP URLs cannot contain credentials or fragments"
494
+ });
495
+ }
496
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) {
497
+ context.addIssue({
498
+ code: "custom",
499
+ message: "OAuth MCP URLs must use HTTPS except on loopback"
500
+ });
501
+ }
502
+ });
364
503
  var PluginManifestSchema = import_zod.z.object({
365
504
  /** Reverse-domain unique identifier (e.g. `"com.example.my-plugin"`). */
366
505
  id: import_zod.z.string().min(1, "id is required"),
@@ -375,6 +514,9 @@ var PluginManifestSchema = import_zod.z.object({
375
514
  /^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/,
376
515
  "version must be a valid semver string (e.g. 1.0.0)"
377
516
  ),
517
+ /** Core-owned release maturity metadata. The Rust contract validates the
518
+ * richer shape; the SDK authoring parser must preserve it for pack/publish. */
519
+ stability: import_zod.z.unknown().optional(),
378
520
  /**
379
521
  * Lower-case hex `sha256(utf8_bytes(ui_code))` binding the plugin's bundled
380
522
  * sandboxed-UI code to this manifest. `ryu pack` / `ryu publish` compute it and
@@ -392,6 +534,26 @@ var PluginManifestSchema = import_zod.z.object({
392
534
  * Declarations only — grant enforcement is the Gateway's responsibility.
393
535
  */
394
536
  permission_grants: import_zod.z.array(import_zod.z.string()).default([]),
537
+ /** Deny-by-default sandbox permissions. Core remains authoritative; this
538
+ * schema mirrors the fields so `ryu pack` cannot strip them. */
539
+ permissions: import_zod.z.object({
540
+ fs: import_zod.z.object({
541
+ read: import_zod.z.array(import_zod.z.string()).default([]),
542
+ write: import_zod.z.array(import_zod.z.string()).default([])
543
+ }).optional(),
544
+ child_process: import_zod.z.boolean().optional(),
545
+ run: import_zod.z.array(import_zod.z.string()).default([]),
546
+ network: import_zod.z.union([import_zod.z.boolean(), import_zod.z.array(import_zod.z.string())]).optional(),
547
+ tool: import_zod.z.array(import_zod.z.string()).default([])
548
+ }).optional(),
549
+ /** Core-owned permission presentation levels. Preserved verbatim here and
550
+ * validated by Core's authoritative manifest contract. */
551
+ permission_levels: import_zod.z.unknown().optional(),
552
+ /** Remote or stdio MCP servers registered by this plugin. */
553
+ mcp_servers: import_zod.z.record(import_zod.z.string(), McpServerDeclSchema).optional(),
554
+ /** Core-owned sidecar declarations. Their full process/HTTP schema stays in
555
+ * the Rust contract; this authoring layer must never strip them. */
556
+ sidecars: import_zod.z.unknown().optional(),
395
557
  /**
396
558
  * Optional Companion surface (an in-desktop overlay or sidebar panel).
397
559
  * Absent when the plugin has no Companion surface.
@@ -427,6 +589,9 @@ var PluginManifestSchema = import_zod.z.object({
427
589
  * an unsupported-target plugin stays installable and inspectable.
428
590
  */
429
591
  targets: import_zod.z.array(SurfaceSchema).default([]),
592
+ /** Rich per-surface declarations (`support`, UI, contributed commands, …).
593
+ * Core owns and validates the nested vocabulary. */
594
+ surfaces: import_zod.z.unknown().optional(),
430
595
  /**
431
596
  * Host version floors — the semver requirement each surface must satisfy for
432
597
  * this plugin to install. Mirrors Core's `EnginesReq`
@@ -485,10 +650,16 @@ var PluginManifestSchema = import_zod.z.object({
485
650
  url: import_zod.z.string().optional()
486
651
  })
487
652
  ]).optional(),
653
+ /** Public source repository URL (Claude/Codex `repository`). */
654
+ repository: import_zod.z.string().url().optional(),
655
+ /** True when the provider operates outside the local Ryu runtime. */
656
+ external: import_zod.z.boolean().optional(),
488
657
  /** Project/marketing homepage — maps to the listing `website` (Claude field). */
489
658
  homepage: import_zod.z.string().optional(),
490
659
  /** Free-text search keywords (Claude field). */
491
660
  keywords: import_zod.z.array(import_zod.z.string()).optional(),
661
+ /** Stable Marketplace filter labels (Ryu extension). */
662
+ tags: import_zod.z.array(import_zod.z.string()).optional(),
492
663
  /** Taxonomy category beyond the runnable kinds (Claude field). */
493
664
  category: import_zod.z.string().optional(),
494
665
  /** SPDX-ish license identifier (Claude field). */
@@ -502,6 +673,8 @@ var PluginManifestSchema = import_zod.z.object({
502
673
  * from `iconUrl` (a raster logo). Falls back to `iconUrl` when omitted.
503
674
  */
504
675
  icon: import_zod.z.string().optional(),
676
+ /** Optional detail-page hero banner metadata forwarded to the marketplace. */
677
+ banner: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
505
678
  /**
506
679
  * Dithered-gradient background for the card's icon square (Ryu extension),
507
680
  * mirroring dither-kit's `DitherGradient` props. `from`/`to` are a palette-colour
@@ -533,6 +706,22 @@ var PluginManifestSchema = import_zod.z.object({
533
706
  * array of steps guiding the user through post-install configuration.
534
707
  */
535
708
  setup: import_zod.z.union([SetupStepSchema, import_zod.z.array(SetupStepSchema)]).optional()
709
+ }).passthrough().superRefine((manifest, context) => {
710
+ const hasOAuthServer = Object.values(manifest.mcp_servers ?? {}).some(
711
+ (server) => server.auth?.type === "oauth"
712
+ );
713
+ if (!hasOAuthServer) {
714
+ return;
715
+ }
716
+ for (const grant of ["mcp:server", "identity.read"]) {
717
+ if (!manifest.permission_grants.includes(grant)) {
718
+ context.addIssue({
719
+ code: "custom",
720
+ message: `OAuth MCP servers require the ${grant} permission grant`,
721
+ path: ["permission_grants"]
722
+ });
723
+ }
724
+ }
536
725
  });
537
726
  function validatePluginId(id) {
538
727
  loadNative().validatePluginId(id);
@@ -547,10 +736,13 @@ function coreManifestJsonSchema() {
547
736
  0 && (module.exports = {
548
737
  AppDependencySchema,
549
738
  CapabilityReqSchema,
739
+ ChatWidgetTemplateSchema,
550
740
  CompanionSurfaceSchema,
551
741
  ContributesSchema,
552
742
  EnginesReqSchema,
553
743
  HookEventContributionSchema,
744
+ McpServerAuthSchema,
745
+ McpServerDeclSchema,
554
746
  OutputStyleContributionSchema,
555
747
  PiExtensionContributionSchema,
556
748
  PluginManifestSchema,
@@ -558,6 +750,10 @@ function coreManifestJsonSchema() {
558
750
  RunnableKindSchema,
559
751
  RunnableMetaSchema,
560
752
  SetupStepSchema,
753
+ SlashCommandArgumentSchema,
754
+ SlashCommandContributionSchema,
755
+ SlashCommandCustomOptionSchema,
756
+ SlashCommandOptionSchema,
561
757
  SurfaceSchema,
562
758
  ToolAppConfigSchema,
563
759
  TurnHookContributionSchema,