@ryuhq/sdk 0.2.0 → 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 +51 -2
- 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.d.cts +1 -1
- package/dist/agent-plugin.d.ts +1 -1
- package/dist/agent.cjs +7 -0
- package/dist/agent.d.cts +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +2 -2
- package/dist/{app-DNaGmLVf.d.cts → app-B0Z9Ew_R.d.cts} +18 -6
- package/dist/{app-Bkw7LlCK.d.ts → app-C-BDJwfG.d.ts} +18 -6
- package/dist/builder.cjs +110 -11
- package/dist/builder.d.cts +7 -2
- package/dist/builder.d.ts +7 -2
- package/dist/builder.js +4 -3
- package/dist/chunk-4TPUZDTI.js +94 -0
- package/dist/{chunk-T5676WL2.js → chunk-BC3A7HMO.js} +1 -77
- package/dist/{chunk-IOLP5FFE.js → chunk-HLKJZAFK.js} +9 -2
- package/dist/{chunk-IEUQ3CDG.js → chunk-NZKVOSC2.js} +71 -5
- package/dist/chunk-QYFUNJOH.js +83 -0
- package/dist/{chunk-W3KPP4WN.js → chunk-SN2QBJUF.js} +20 -7
- package/dist/{chunk-ULSVL7EC.js → chunk-Z57QDDJR.js} +1 -1
- package/dist/{chunk-A3RGEPDG.js → chunk-ZTJWBRUL.js} +32 -0
- package/dist/cli.cjs +93 -8
- package/dist/cli.js +33 -8
- package/dist/index.cjs +297 -87
- package/dist/index.d.cts +10 -9
- package/dist/index.d.ts +10 -9
- package/dist/index.js +34 -19
- package/dist/manifest.cjs +76 -6
- package/dist/manifest.d.cts +157 -5
- package/dist/manifest.d.ts +157 -5
- package/dist/manifest.js +9 -1
- package/dist/mcp/server.d.cts +2 -1
- package/dist/mcp/server.d.ts +2 -1
- package/dist/runnable.cjs +279 -71
- package/dist/runnable.d.cts +6 -3
- package/dist/runnable.d.ts +6 -3
- package/dist/runnable.js +11 -5
- package/dist/{tool-DSx2bFx8.d.ts → tool-AjkdFvhE.d.ts} +54 -4
- package/dist/{tool-u-VR0fLF.d.cts → tool-CgzW92O_.d.cts} +54 -4
- package/package.json +12 -3
- package/src/agent-plugin.ts +1 -1
- package/src/builder.ts +9 -0
- package/src/cli-security.test.ts +109 -0
- package/src/cli.ts +43 -10
- package/src/contracts-lockstep.test.ts +16 -2
- package/src/exports-lockstep.test.ts +1 -0
- package/src/generated/plugin-manifest.ts +82 -5
- package/src/index.ts +18 -0
- package/src/manifest.fixtures.test.ts +9 -3
- package/src/manifest.test.ts +69 -0
- package/src/manifest.ts +137 -18
- package/src/mcp/server.ts +2 -1
- package/src/runnable/action.test.ts +128 -0
- package/src/runnable/action.ts +202 -0
- package/src/runnable/app.ts +45 -12
- package/src/runnable/index.ts +18 -3
- package/src/runnable/primitives.test.ts +34 -0
- package/src/runnable/primitives.ts +59 -0
- package/src/runnable/runnable-types.ts +3 -0
- package/src/runnable/tool.ts +35 -4
- package/src/runnable/turn-hook.ts +4 -2
- package/src/slash-command.test.ts +69 -0
package/dist/cli.cjs
CHANGED
|
@@ -692,10 +692,18 @@ var ChatWidgetTemplateSchema = import_zod.z.object({
|
|
|
692
692
|
}).superRefine((value, ctx) => {
|
|
693
693
|
const count = Number(Boolean(value.backing.tool_id)) + Number(Boolean(value.backing.view_id));
|
|
694
694
|
if (count !== 1 && value.availability === "available") {
|
|
695
|
-
ctx.addIssue({
|
|
695
|
+
ctx.addIssue({
|
|
696
|
+
code: "custom",
|
|
697
|
+
path: ["backing"],
|
|
698
|
+
message: "available templates need exactly one backing tool_id or view_id"
|
|
699
|
+
});
|
|
696
700
|
}
|
|
697
701
|
if (count > 1) {
|
|
698
|
-
ctx.addIssue({
|
|
702
|
+
ctx.addIssue({
|
|
703
|
+
code: "custom",
|
|
704
|
+
path: ["backing"],
|
|
705
|
+
message: "backing must declare at most one of tool_id or view_id"
|
|
706
|
+
});
|
|
699
707
|
}
|
|
700
708
|
});
|
|
701
709
|
var ToolAppConfigSchema = import_zod.z.object({
|
|
@@ -718,6 +726,33 @@ var ToolAppConfigSchema = import_zod.z.object({
|
|
|
718
726
|
/** Optional status label shown when the render tool finishes. */
|
|
719
727
|
invoked: import_zod.z.string().optional()
|
|
720
728
|
});
|
|
729
|
+
var SlashCommandOptionSchema = import_zod.z.object({
|
|
730
|
+
description: import_zod.z.string().optional(),
|
|
731
|
+
label: import_zod.z.string().min(1),
|
|
732
|
+
value: import_zod.z.string().min(1)
|
|
733
|
+
}).passthrough();
|
|
734
|
+
var SlashCommandCustomOptionSchema = import_zod.z.union([
|
|
735
|
+
import_zod.z.literal(true),
|
|
736
|
+
import_zod.z.object({
|
|
737
|
+
description: import_zod.z.string().optional(),
|
|
738
|
+
label: import_zod.z.string().min(1).optional()
|
|
739
|
+
}).passthrough()
|
|
740
|
+
]);
|
|
741
|
+
var SlashCommandArgumentSchema = import_zod.z.object({
|
|
742
|
+
allow_custom: import_zod.z.boolean().optional(),
|
|
743
|
+
custom: SlashCommandCustomOptionSchema.optional(),
|
|
744
|
+
description: import_zod.z.string().optional(),
|
|
745
|
+
name: import_zod.z.string().min(1),
|
|
746
|
+
options: import_zod.z.array(SlashCommandOptionSchema).optional()
|
|
747
|
+
}).passthrough();
|
|
748
|
+
var SlashCommandContributionSchema = import_zod.z.object({
|
|
749
|
+
args: import_zod.z.array(SlashCommandArgumentSchema).optional(),
|
|
750
|
+
body: import_zod.z.string().optional(),
|
|
751
|
+
command: import_zod.z.string().min(1),
|
|
752
|
+
description: import_zod.z.string().optional(),
|
|
753
|
+
id: import_zod.z.string().optional(),
|
|
754
|
+
parameters: import_zod.z.array(SlashCommandArgumentSchema).optional()
|
|
755
|
+
}).passthrough();
|
|
721
756
|
var ContributesSchema = import_zod.z.object({
|
|
722
757
|
turn_hooks: import_zod.z.array(TurnHookContributionSchema).default([]),
|
|
723
758
|
/** App events this plugin EMITS — the provider half of the hook system, whose
|
|
@@ -732,7 +767,7 @@ var ContributesSchema = import_zod.z.object({
|
|
|
732
767
|
* feature declaration before signing. */
|
|
733
768
|
chat_features: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
734
769
|
settings_tabs: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
735
|
-
slash_commands: import_zod.z.array(
|
|
770
|
+
slash_commands: import_zod.z.array(SlashCommandContributionSchema).default([]),
|
|
736
771
|
/** App widgets (Ryu Apps). Each binds a render tool id to its
|
|
737
772
|
* `ui://widget/<slug>.html` template. Mirrors the Rust-side
|
|
738
773
|
* `Contributes.widgets` field, without which the CLI's zod parse would strip
|
|
@@ -799,7 +834,10 @@ var ContributesSchema = import_zod.z.object({
|
|
|
799
834
|
output_styles: import_zod.z.array(OutputStyleContributionSchema).default([]),
|
|
800
835
|
/** Per-message actions contributed by an enabled plugin. Kept as loose records
|
|
801
836
|
* so renderer-specific `kind`/`args` payloads survive `ryu pack` unchanged. */
|
|
802
|
-
message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
|
|
837
|
+
message_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([]),
|
|
838
|
+
/** Buttons contributed to the floating text-selection toolbar. Kept as loose
|
|
839
|
+
* records so host-owned dispatch args survive `ryu pack` unchanged. */
|
|
840
|
+
selection_actions: import_zod.z.array(import_zod.z.record(import_zod.z.string(), import_zod.z.unknown())).default([])
|
|
803
841
|
});
|
|
804
842
|
var SetupStepSchema = import_zod.z.object({
|
|
805
843
|
/** Card heading (e.g. the companion app name). */
|
|
@@ -949,6 +987,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
949
987
|
/^\d+\.\d+\.\d+(?:-[\w.]+)?(?:\+[\w.]+)?$/,
|
|
950
988
|
"version must be a valid semver string (e.g. 1.0.0)"
|
|
951
989
|
),
|
|
990
|
+
/** Core-owned release maturity metadata. The Rust contract validates the
|
|
991
|
+
* richer shape; the SDK authoring parser must preserve it for pack/publish. */
|
|
992
|
+
stability: import_zod.z.unknown().optional(),
|
|
952
993
|
/**
|
|
953
994
|
* Lower-case hex `sha256(utf8_bytes(ui_code))` binding the plugin's bundled
|
|
954
995
|
* sandboxed-UI code to this manifest. `ryu pack` / `ryu publish` compute it and
|
|
@@ -966,8 +1007,26 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
966
1007
|
* Declarations only — grant enforcement is the Gateway's responsibility.
|
|
967
1008
|
*/
|
|
968
1009
|
permission_grants: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1010
|
+
/** Deny-by-default sandbox permissions. Core remains authoritative; this
|
|
1011
|
+
* schema mirrors the fields so `ryu pack` cannot strip them. */
|
|
1012
|
+
permissions: import_zod.z.object({
|
|
1013
|
+
fs: import_zod.z.object({
|
|
1014
|
+
read: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1015
|
+
write: import_zod.z.array(import_zod.z.string()).default([])
|
|
1016
|
+
}).optional(),
|
|
1017
|
+
child_process: import_zod.z.boolean().optional(),
|
|
1018
|
+
run: import_zod.z.array(import_zod.z.string()).default([]),
|
|
1019
|
+
network: import_zod.z.union([import_zod.z.boolean(), import_zod.z.array(import_zod.z.string())]).optional(),
|
|
1020
|
+
tool: import_zod.z.array(import_zod.z.string()).default([])
|
|
1021
|
+
}).optional(),
|
|
1022
|
+
/** Core-owned permission presentation levels. Preserved verbatim here and
|
|
1023
|
+
* validated by Core's authoritative manifest contract. */
|
|
1024
|
+
permission_levels: import_zod.z.unknown().optional(),
|
|
969
1025
|
/** Remote or stdio MCP servers registered by this plugin. */
|
|
970
1026
|
mcp_servers: import_zod.z.record(import_zod.z.string(), McpServerDeclSchema).optional(),
|
|
1027
|
+
/** Core-owned sidecar declarations. Their full process/HTTP schema stays in
|
|
1028
|
+
* the Rust contract; this authoring layer must never strip them. */
|
|
1029
|
+
sidecars: import_zod.z.unknown().optional(),
|
|
971
1030
|
/**
|
|
972
1031
|
* Optional Companion surface (an in-desktop overlay or sidebar panel).
|
|
973
1032
|
* Absent when the plugin has no Companion surface.
|
|
@@ -1003,6 +1062,9 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1003
1062
|
* an unsupported-target plugin stays installable and inspectable.
|
|
1004
1063
|
*/
|
|
1005
1064
|
targets: import_zod.z.array(SurfaceSchema).default([]),
|
|
1065
|
+
/** Rich per-surface declarations (`support`, UI, contributed commands, …).
|
|
1066
|
+
* Core owns and validates the nested vocabulary. */
|
|
1067
|
+
surfaces: import_zod.z.unknown().optional(),
|
|
1006
1068
|
/**
|
|
1007
1069
|
* Host version floors — the semver requirement each surface must satisfy for
|
|
1008
1070
|
* this plugin to install. Mirrors Core's `EnginesReq`
|
|
@@ -1117,7 +1179,7 @@ var PluginManifestSchema = import_zod.z.object({
|
|
|
1117
1179
|
* array of steps guiding the user through post-install configuration.
|
|
1118
1180
|
*/
|
|
1119
1181
|
setup: import_zod.z.union([SetupStepSchema, import_zod.z.array(SetupStepSchema)]).optional()
|
|
1120
|
-
}).superRefine((manifest, context) => {
|
|
1182
|
+
}).passthrough().superRefine((manifest, context) => {
|
|
1121
1183
|
const hasOAuthServer = Object.values(manifest.mcp_servers ?? {}).some(
|
|
1122
1184
|
(server) => server.auth?.type === "oauth"
|
|
1123
1185
|
);
|
|
@@ -1157,7 +1219,7 @@ function printUsage() {
|
|
|
1157
1219
|
);
|
|
1158
1220
|
}
|
|
1159
1221
|
function exitError(message) {
|
|
1160
|
-
process.stderr.
|
|
1222
|
+
(0, import_node_fs.writeSync)(process.stderr.fd, `error: ${message}
|
|
1161
1223
|
`);
|
|
1162
1224
|
process.exit(1);
|
|
1163
1225
|
}
|
|
@@ -1210,13 +1272,30 @@ function loadManifest(dir) {
|
|
|
1210
1272
|
}
|
|
1211
1273
|
var CODE_FILE_DIRS = ["hooks", "adapters"];
|
|
1212
1274
|
var CODE_FILE_PATH = /^(hooks|adapters)\/[A-Za-z0-9_][A-Za-z0-9._-]*\.m?js$/;
|
|
1275
|
+
function containedPackageFile(dir, rel, label) {
|
|
1276
|
+
let realRoot;
|
|
1277
|
+
let realTarget;
|
|
1278
|
+
try {
|
|
1279
|
+
realRoot = (0, import_node_fs.realpathSync)(dir);
|
|
1280
|
+
realTarget = (0, import_node_fs.realpathSync)((0, import_node_path.join)(dir, rel));
|
|
1281
|
+
} catch (error) {
|
|
1282
|
+
exitError(`${label}: could not resolve '${rel}': ${String(error)}`);
|
|
1283
|
+
}
|
|
1284
|
+
const fromRoot = (0, import_node_path.relative)(realRoot, realTarget);
|
|
1285
|
+
if (fromRoot === ".." || fromRoot.startsWith(`..${import_node_path.sep}`) || (0, import_node_path.isAbsolute)(fromRoot)) {
|
|
1286
|
+
exitError(
|
|
1287
|
+
`${label}: '${rel}' resolves outside the plugin package (${realTarget})`
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
return realTarget;
|
|
1291
|
+
}
|
|
1213
1292
|
function readCodeFile(dir, rel, label) {
|
|
1214
1293
|
if (!CODE_FILE_PATH.test(rel)) {
|
|
1215
1294
|
exitError(
|
|
1216
1295
|
`${label}: code_file '${rel}' must be exactly '<${CODE_FILE_DIRS.join("|")}>/<name>.js' with no traversal`
|
|
1217
1296
|
);
|
|
1218
1297
|
}
|
|
1219
|
-
const path = (
|
|
1298
|
+
const path = containedPackageFile(dir, rel, label);
|
|
1220
1299
|
let body;
|
|
1221
1300
|
try {
|
|
1222
1301
|
body = (0, import_node_fs.readFileSync)(path, "utf8");
|
|
@@ -1266,7 +1345,7 @@ function inlineOutputStyleFiles(manifest, dir) {
|
|
|
1266
1345
|
}
|
|
1267
1346
|
let body;
|
|
1268
1347
|
try {
|
|
1269
|
-
body = (0, import_node_fs.readFileSync)((
|
|
1348
|
+
body = (0, import_node_fs.readFileSync)(containedPackageFile(dir, rel, label), "utf8");
|
|
1270
1349
|
} catch (err) {
|
|
1271
1350
|
exitError(`${label}: could not read file '${rel}': ${String(err)}`);
|
|
1272
1351
|
}
|
|
@@ -1312,6 +1391,12 @@ function resolveUiFormat(manifest) {
|
|
|
1312
1391
|
return "html";
|
|
1313
1392
|
}
|
|
1314
1393
|
}
|
|
1394
|
+
for (const widget of manifest.contributes?.widgets ?? []) {
|
|
1395
|
+
const entry = widget.ui_entry;
|
|
1396
|
+
if (typeof entry === "string" && entry.trim().toLowerCase().endsWith(".html")) {
|
|
1397
|
+
return "html";
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1315
1400
|
return "js";
|
|
1316
1401
|
}
|
|
1317
1402
|
function readUiEntryHtml(dir, uiEntry) {
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import {
|
|
3
|
-
PluginManifestSchema
|
|
4
|
-
} from "./chunk-IEUQ3CDG.js";
|
|
5
2
|
import {
|
|
6
3
|
AGENT_PLUGIN_MANIFEST_FILE,
|
|
7
4
|
AGENT_PLUGIN_MCP_FILE,
|
|
8
5
|
isAgentPluginManifest,
|
|
9
6
|
toAgentPlugin
|
|
10
7
|
} from "./chunk-JX6DDRXV.js";
|
|
8
|
+
import {
|
|
9
|
+
PluginManifestSchema
|
|
10
|
+
} from "./chunk-NZKVOSC2.js";
|
|
11
11
|
import {
|
|
12
12
|
ModelClient
|
|
13
13
|
} from "./chunk-HACAGK65.js";
|
|
@@ -21,10 +21,12 @@ import {
|
|
|
21
21
|
existsSync,
|
|
22
22
|
mkdirSync,
|
|
23
23
|
readFileSync,
|
|
24
|
+
realpathSync,
|
|
24
25
|
rmSync,
|
|
25
|
-
writeFileSync
|
|
26
|
+
writeFileSync,
|
|
27
|
+
writeSync
|
|
26
28
|
} from "fs";
|
|
27
|
-
import { join, resolve } from "path";
|
|
29
|
+
import { isAbsolute, join, relative, resolve, sep } from "path";
|
|
28
30
|
|
|
29
31
|
// src/cli/dev.ts
|
|
30
32
|
import { createInterface } from "readline";
|
|
@@ -241,7 +243,7 @@ function printUsage() {
|
|
|
241
243
|
);
|
|
242
244
|
}
|
|
243
245
|
function exitError(message) {
|
|
244
|
-
process.stderr.
|
|
246
|
+
writeSync(process.stderr.fd, `error: ${message}
|
|
245
247
|
`);
|
|
246
248
|
process.exit(1);
|
|
247
249
|
}
|
|
@@ -294,13 +296,30 @@ function loadManifest(dir) {
|
|
|
294
296
|
}
|
|
295
297
|
var CODE_FILE_DIRS = ["hooks", "adapters"];
|
|
296
298
|
var CODE_FILE_PATH = /^(hooks|adapters)\/[A-Za-z0-9_][A-Za-z0-9._-]*\.m?js$/;
|
|
299
|
+
function containedPackageFile(dir, rel, label) {
|
|
300
|
+
let realRoot;
|
|
301
|
+
let realTarget;
|
|
302
|
+
try {
|
|
303
|
+
realRoot = realpathSync(dir);
|
|
304
|
+
realTarget = realpathSync(join(dir, rel));
|
|
305
|
+
} catch (error) {
|
|
306
|
+
exitError(`${label}: could not resolve '${rel}': ${String(error)}`);
|
|
307
|
+
}
|
|
308
|
+
const fromRoot = relative(realRoot, realTarget);
|
|
309
|
+
if (fromRoot === ".." || fromRoot.startsWith(`..${sep}`) || isAbsolute(fromRoot)) {
|
|
310
|
+
exitError(
|
|
311
|
+
`${label}: '${rel}' resolves outside the plugin package (${realTarget})`
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return realTarget;
|
|
315
|
+
}
|
|
297
316
|
function readCodeFile(dir, rel, label) {
|
|
298
317
|
if (!CODE_FILE_PATH.test(rel)) {
|
|
299
318
|
exitError(
|
|
300
319
|
`${label}: code_file '${rel}' must be exactly '<${CODE_FILE_DIRS.join("|")}>/<name>.js' with no traversal`
|
|
301
320
|
);
|
|
302
321
|
}
|
|
303
|
-
const path =
|
|
322
|
+
const path = containedPackageFile(dir, rel, label);
|
|
304
323
|
let body;
|
|
305
324
|
try {
|
|
306
325
|
body = readFileSync(path, "utf8");
|
|
@@ -350,7 +369,7 @@ function inlineOutputStyleFiles(manifest, dir) {
|
|
|
350
369
|
}
|
|
351
370
|
let body;
|
|
352
371
|
try {
|
|
353
|
-
body = readFileSync(
|
|
372
|
+
body = readFileSync(containedPackageFile(dir, rel, label), "utf8");
|
|
354
373
|
} catch (err) {
|
|
355
374
|
exitError(`${label}: could not read file '${rel}': ${String(err)}`);
|
|
356
375
|
}
|
|
@@ -396,6 +415,12 @@ function resolveUiFormat(manifest) {
|
|
|
396
415
|
return "html";
|
|
397
416
|
}
|
|
398
417
|
}
|
|
418
|
+
for (const widget of manifest.contributes?.widgets ?? []) {
|
|
419
|
+
const entry = widget.ui_entry;
|
|
420
|
+
if (typeof entry === "string" && entry.trim().toLowerCase().endsWith(".html")) {
|
|
421
|
+
return "html";
|
|
422
|
+
}
|
|
423
|
+
}
|
|
399
424
|
return "js";
|
|
400
425
|
}
|
|
401
426
|
function readUiEntryHtml(dir, uiEntry) {
|