@ryuhq/sdk 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +19 -6
  2. package/dist/agent-plugin.cjs +46 -0
  3. package/dist/agent-plugin.d.cts +42 -32
  4. package/dist/agent-plugin.d.ts +42 -32
  5. package/dist/agent-plugin.js +1 -1
  6. package/dist/agent.cjs +9 -0
  7. package/dist/agent.d.cts +377 -1
  8. package/dist/agent.d.ts +377 -1
  9. package/dist/agent.js +4 -2
  10. package/dist/app-Bkw7LlCK.d.ts +129 -0
  11. package/dist/app-DNaGmLVf.d.cts +129 -0
  12. package/dist/builder.cjs +1095 -0
  13. package/dist/builder.d.cts +212 -0
  14. package/dist/builder.d.ts +212 -0
  15. package/dist/builder.js +28 -0
  16. package/dist/chunk-A3RGEPDG.js +250 -0
  17. package/dist/chunk-FZSFZOIN.js +200 -0
  18. package/dist/{chunk-ODFEUVPW.js → chunk-HACAGK65.js} +1 -18
  19. package/dist/{chunk-AO2KJRDD.js → chunk-IEUQ3CDG.js} +125 -2
  20. package/dist/chunk-IKEDLLFY.js +19 -0
  21. package/dist/chunk-IOLP5FFE.js +354 -0
  22. package/dist/{chunk-G6FLVEC4.js → chunk-JX6DDRXV.js} +46 -0
  23. package/dist/chunk-T5676WL2.js +240 -0
  24. package/dist/chunk-TLDPEGC7.js +21 -0
  25. package/dist/chunk-TXSHHZF2.js +0 -0
  26. package/dist/{chunk-MTUBUPIV.js → chunk-ULSVL7EC.js} +8 -227
  27. package/dist/chunk-VLIRNNAE.js +154 -0
  28. package/dist/chunk-W3KPP4WN.js +135 -0
  29. package/dist/cli.cjs +258 -14
  30. package/dist/cli.js +96 -16
  31. package/dist/client-D5U6ssPc.d.cts +84 -0
  32. package/dist/client-D5U6ssPc.d.ts +84 -0
  33. package/dist/index.cjs +519 -5
  34. package/dist/index.d.cts +16 -632
  35. package/dist/index.d.ts +16 -632
  36. package/dist/index.js +63 -695
  37. package/dist/manifest.cjs +129 -3
  38. package/dist/manifest.d.cts +105 -2
  39. package/dist/manifest.d.ts +105 -2
  40. package/dist/manifest.js +7 -1
  41. package/dist/mcp/client.cjs +180 -0
  42. package/dist/mcp/client.d.cts +49 -0
  43. package/dist/mcp/client.d.ts +49 -0
  44. package/dist/mcp/client.js +10 -0
  45. package/dist/mcp/server.cjs +370 -0
  46. package/dist/mcp/server.d.cts +126 -0
  47. package/dist/mcp/server.d.ts +126 -0
  48. package/dist/mcp/server.js +9 -0
  49. package/dist/mcp.cjs +376 -0
  50. package/dist/mcp.d.cts +2 -0
  51. package/dist/mcp.d.ts +2 -0
  52. package/dist/mcp.js +17 -0
  53. package/dist/model.cjs +141 -0
  54. package/dist/model.d.cts +33 -0
  55. package/dist/model.d.ts +33 -0
  56. package/dist/model.js +18 -0
  57. package/dist/plugin.cjs +46 -0
  58. package/dist/plugin.d.cts +215 -0
  59. package/dist/plugin.d.ts +215 -0
  60. package/dist/plugin.js +8 -0
  61. package/dist/runnable.cjs +1230 -0
  62. package/dist/runnable.d.cts +271 -0
  63. package/dist/runnable.d.ts +271 -0
  64. package/dist/runnable.js +28 -0
  65. package/dist/{index-B6SkaAjJ.d.ts → tool-DSx2bFx8.d.ts} +35 -458
  66. package/dist/{index-BvAB5eMk.d.cts → tool-u-VR0fLF.d.cts} +35 -458
  67. package/package.json +38 -2
  68. package/src/agent/loop.test.ts +4 -4
  69. package/src/agent/tools.ts +3 -3
  70. package/src/agent-plugin.test.ts +58 -0
  71. package/src/agent-plugin.ts +108 -35
  72. package/src/cli/dev.test.ts +26 -47
  73. package/src/cli/dev.ts +10 -2
  74. package/src/cli.ts +98 -15
  75. package/src/exports-lockstep.test.ts +92 -0
  76. package/src/generated/plugin-manifest.ts +243 -27
  77. package/src/index.ts +35 -0
  78. package/src/manifest-schema.test.ts +30 -1
  79. package/src/manifest.fixtures.test.ts +13 -3
  80. package/src/manifest.test.ts +96 -10
  81. package/src/manifest.ts +334 -187
  82. package/src/mcp/index.ts +18 -0
  83. package/src/model/index.ts +22 -0
  84. package/src/plugin/ryu-plugin.ts +82 -0
  85. package/src/runnable/app.test.ts +2 -0
  86. package/src/runnable/app.ts +5 -2
  87. package/src/runnable/index.ts +2 -0
  88. package/src/runnable/primitives.ts +57 -0
  89. package/src/runnable/tool.ts +1 -1
  90. package/src/runnable/turn-hook.ts +4 -1
@@ -302,7 +302,7 @@ describe("defineApp", () => {
302
302
  const widgets = manifest.contributes?.widgets ?? [];
303
303
 
304
304
  expect(widgets).toHaveLength(1);
305
- expect(widgets[0]?.tool_id).toBe("checklist__render");
305
+ expect(widgets[0]?.tool_id).toBe("checklist.render");
306
306
  expect(widgets[0]?.uri).toBe("ui://widget/checklist.html");
307
307
  expect(widgets[0]?.ui_entry).toBe("src/checklist.tsx");
308
308
  expect(widgets[0]?.mime).toBe("text/html+skybridge");
@@ -314,9 +314,9 @@ describe("defineApp", () => {
314
314
  expect(manifest.runnables).toHaveLength(2);
315
315
  expect(manifest.runnables.every((r) => r.kind === "tool")).toBe(true);
316
316
 
317
- const render = manifest.runnables.find((r) => r.id === "checklist__render");
317
+ const render = manifest.runnables.find((r) => r.id === "checklist.render");
318
318
  expect(render?.config).toMatchObject({
319
- slug: "checklist__render",
319
+ slug: "checklist.render",
320
320
  // The manifest is the only channel for a packed app: description +
321
321
  // input_schema must survive so Core can rebuild a driveable tool.
322
322
  description: "Render a checklist",
@@ -332,9 +332,9 @@ describe("defineApp", () => {
332
332
  invoked: "Ready",
333
333
  });
334
334
 
335
- const toggle = manifest.runnables.find((r) => r.id === "checklist__toggle");
335
+ const toggle = manifest.runnables.find((r) => r.id === "checklist.toggle");
336
336
  expect(toggle?.config).toMatchObject({
337
- slug: "checklist__toggle",
337
+ slug: "checklist.toggle",
338
338
  widget: false,
339
339
  widget_accessible: true,
340
340
  });
@@ -350,13 +350,13 @@ describe("defineApp", () => {
350
350
  uiEntry: "src/chart.tsx",
351
351
  tools: [{ name: "render", description: "Render a chart" }],
352
352
  });
353
- const render = manifest.runnables.find((r) => r.id === "chart__render");
353
+ const render = manifest.runnables.find((r) => r.id === "chart.render");
354
354
  expect(render?.config).toMatchObject({
355
355
  widget: true,
356
356
  widget_accessible: false,
357
357
  });
358
358
  // `server` override qualifies the tool id and the widget binding.
359
- expect(manifest.contributes?.widgets[0]?.tool_id).toBe("chart__render");
359
+ expect(manifest.contributes?.widgets[0]?.tool_id).toBe("chart.render");
360
360
  // The widget uri still derives from the slug, not the server.
361
361
  expect(manifest.contributes?.widgets[0]?.uri).toBe(
362
362
  "ui://widget/chart-studio.html"
@@ -377,12 +377,12 @@ describe("defineApp", () => {
377
377
  }
378
378
  expect(parsed.data.contributes?.widgets).toHaveLength(1);
379
379
  expect(parsed.data.contributes?.widgets[0]?.tool_id).toBe(
380
- "checklist__render"
380
+ "checklist.render"
381
381
  );
382
382
  // description + input_schema survive the strict parse (the only channel for
383
383
  // a packed app — no `generated.rs` on the Core side).
384
384
  const render = parsed.data.runnables.find(
385
- (r) => r.id === "checklist__render"
385
+ (r) => r.id === "checklist.render"
386
386
  );
387
387
  expect(render?.config?.description).toBe("Render a checklist");
388
388
  expect(render?.config?.input_schema).toBeDefined();
@@ -423,7 +423,7 @@ describe("AppBuilder", () => {
423
423
  expect(manifest.id).toBe("com.example.checklist");
424
424
  expect(manifest.runnables).toHaveLength(2);
425
425
  expect(manifest.contributes?.widgets).toHaveLength(1);
426
- expect(manifest.contributes?.widgets[0]?.tool_id).toBe("checklist__render");
426
+ expect(manifest.contributes?.widgets[0]?.tool_id).toBe("checklist.render");
427
427
  // The author's own grant, plus the `widget:render` the builder adds because
428
428
  // this app synthesises a widget — without it Core silently degrades the
429
429
  // widget to plain text.
@@ -774,3 +774,89 @@ describe("contributes.lsp_servers", () => {
774
774
  expect(parsed.data.contributes?.lsp_servers).toEqual({});
775
775
  });
776
776
  });
777
+
778
+ describe("contributes.message_actions", () => {
779
+ it("preserves renderer-specific action args through the pack-path parse", () => {
780
+ const action = {
781
+ args: {
782
+ dispatch: "reactions.toggle",
783
+ renderer: "reaction-picker",
784
+ },
785
+ capability: "reactions.toggle",
786
+ id: "reactions.picker",
787
+ kind: "menu",
788
+ label: "Add reaction",
789
+ plugin: "@ryu/reactions",
790
+ target: "user",
791
+ };
792
+ const parsed = PluginManifestSchema.safeParse({
793
+ id: "com.example.reactions",
794
+ name: "Reactions",
795
+ version: "1.0.0",
796
+ runnables: [],
797
+ contributes: { message_actions: [action] },
798
+ });
799
+
800
+ expect(parsed.success).toBe(true);
801
+ if (!parsed.success) {
802
+ return;
803
+ }
804
+ expect(parsed.data.contributes?.message_actions).toEqual([action]);
805
+ });
806
+ });
807
+
808
+ describe("mcp_servers OAuth", () => {
809
+ const manifest = {
810
+ id: "com.example.mail",
811
+ mcp_servers: {
812
+ mail: {
813
+ auth: { client_id: "public-client", type: "oauth" },
814
+ type: "streamable-http",
815
+ url: "https://mcp.example.com/mcp",
816
+ },
817
+ },
818
+ name: "Mail",
819
+ permission_grants: ["mcp:server", "identity.read"],
820
+ runnables: [],
821
+ version: "1.0.0",
822
+ };
823
+
824
+ it("preserves the public OAuth declaration through the pack-path parse", () => {
825
+ const parsed = PluginManifestSchema.parse(manifest);
826
+ expect(parsed.mcp_servers?.mail?.auth).toEqual({
827
+ client_id: "public-client",
828
+ type: "oauth",
829
+ });
830
+ });
831
+
832
+ it("rejects secret auth fields and non-loopback plaintext URLs", () => {
833
+ expect(
834
+ PluginManifestSchema.safeParse({
835
+ ...manifest,
836
+ mcp_servers: {
837
+ mail: {
838
+ ...manifest.mcp_servers.mail,
839
+ auth: { client_secret: "nope", type: "oauth" },
840
+ },
841
+ },
842
+ }).success
843
+ ).toBe(false);
844
+ expect(
845
+ PluginManifestSchema.safeParse({
846
+ ...manifest,
847
+ mcp_servers: {
848
+ mail: { auth: { type: "oauth" }, url: "http://mcp.example.com" },
849
+ },
850
+ }).success
851
+ ).toBe(false);
852
+ });
853
+
854
+ it("requires both MCP and identity grants", () => {
855
+ expect(
856
+ PluginManifestSchema.safeParse({
857
+ ...manifest,
858
+ permission_grants: ["mcp:server"],
859
+ }).success
860
+ ).toBe(false);
861
+ });
862
+ });