runline 0.27.1 → 0.27.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/dist/core/engine.js +95 -1
- package/package.json +1 -1
package/dist/core/engine.js
CHANGED
|
@@ -459,6 +459,12 @@ function formatError(cause) {
|
|
|
459
459
|
// code gets a cwd-relative `require`, so a bare specifier would resolve
|
|
460
460
|
// against the caller's cwd instead of runline's own node_modules.
|
|
461
461
|
const ferrosearchPath = createRequire(import.meta.url).resolve("@shift-labs/ferrosearch");
|
|
462
|
+
// typebox ships ESM only; require() of an .mjs works everywhere runline
|
|
463
|
+
// runs (bun, and node since 22.12's require(esm)). Resolved host-side
|
|
464
|
+
// for the same reason as ferrosearch: eval'd worker code gets a
|
|
465
|
+
// cwd-relative require, so a bare specifier would resolve against the
|
|
466
|
+
// caller's cwd instead of runline's own node_modules.
|
|
467
|
+
const typeboxValuePath = createRequire(import.meta.url).resolve("typebox/value");
|
|
462
468
|
function buildHelpData(plugins) {
|
|
463
469
|
const data = {};
|
|
464
470
|
for (const p of plugins) {
|
|
@@ -467,6 +473,7 @@ function buildHelpData(plugins) {
|
|
|
467
473
|
access: a.access,
|
|
468
474
|
description: a.description,
|
|
469
475
|
inputs: helpInputs(a.inputSchema),
|
|
476
|
+
...(isTypedInputSchema(a.inputSchema) ? { schema: a.inputSchema } : {}),
|
|
470
477
|
}));
|
|
471
478
|
}
|
|
472
479
|
return data;
|
|
@@ -594,6 +601,9 @@ const __toJson = (v) => v === undefined ? undefined : JSON.parse(JSON.stringify(
|
|
|
594
601
|
// also means an index built by agent code is invisible to that limit.
|
|
595
602
|
const { FerroSearch } = require(${JSON.stringify(ferrosearchPath)});
|
|
596
603
|
|
|
604
|
+
// The host's own validator, for actions.check on typed schemas.
|
|
605
|
+
const { Check: __schemaCheck, Errors: __schemaErrors } = require(${JSON.stringify(typeboxValuePath)});
|
|
606
|
+
|
|
597
607
|
const __help = ${JSON.stringify(helpData)};
|
|
598
608
|
|
|
599
609
|
const __makeProxy = (path = []) => new Proxy(() => undefined, {
|
|
@@ -653,6 +663,82 @@ const __search = (() => {
|
|
|
653
663
|
return index;
|
|
654
664
|
})();
|
|
655
665
|
|
|
666
|
+
// instancePath "/members/0/externalId" → ["members", "0", "externalId"],
|
|
667
|
+
// with JSON-pointer escapes (~1 for /, ~0 for ~) undone per part.
|
|
668
|
+
const __pointerParts = (instancePath) =>
|
|
669
|
+
String(instancePath || '').split('/').filter((p) => p.length)
|
|
670
|
+
.map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
671
|
+
|
|
672
|
+
// ["members", "0", "externalId"] → "members[0].externalId"
|
|
673
|
+
const __fieldPath = (instancePath, prop) => {
|
|
674
|
+
const parts = __pointerParts(instancePath);
|
|
675
|
+
if (prop !== undefined) parts.push(String(prop));
|
|
676
|
+
let out = '';
|
|
677
|
+
for (const part of parts) {
|
|
678
|
+
if (/^\\d+$/.test(part)) out += '[' + part + ']';
|
|
679
|
+
else out += out ? '.' + part : part;
|
|
680
|
+
}
|
|
681
|
+
return out;
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
const __valueAt = (root, instancePath) => {
|
|
685
|
+
let v = root;
|
|
686
|
+
for (const part of __pointerParts(instancePath)) {
|
|
687
|
+
if (v == null) return undefined;
|
|
688
|
+
v = v[part];
|
|
689
|
+
}
|
|
690
|
+
return v;
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
const __valueType = (v) => v === null ? 'null' : Array.isArray(v) ? 'array' : typeof v;
|
|
694
|
+
|
|
695
|
+
// Deep validation for typed schemas (SHFT-1187): the same Check/Errors
|
|
696
|
+
// the host runs before execute, on the same schema, so the preflight
|
|
697
|
+
// verdict and the execution verdict cannot diverge. The familiar
|
|
698
|
+
// missing/unknown/typeErrors buckets are derived from the validator's
|
|
699
|
+
// structured errors — keyword and params, never message parsing — and
|
|
700
|
+
// the errors array carries each raw "<path> <message>" line exactly as
|
|
701
|
+
// a rejected execution would report it. Grouping type errors by instance
|
|
702
|
+
// path keeps a failed union one typeError instead of one per branch.
|
|
703
|
+
const __checkTyped = (entry, provided, signature) => {
|
|
704
|
+
if (__schemaCheck(entry.schema, provided)) {
|
|
705
|
+
return { ok: true, missing: [], unknown: [], typeErrors: [], errors: [], signature };
|
|
706
|
+
}
|
|
707
|
+
const missing = [];
|
|
708
|
+
const unknown = [];
|
|
709
|
+
const errors = [];
|
|
710
|
+
const byPath = new Map();
|
|
711
|
+
for (const err of __schemaErrors(entry.schema, provided)) {
|
|
712
|
+
errors.push((err.instancePath || '/') + ' ' + err.message);
|
|
713
|
+
const params = err.params || {};
|
|
714
|
+
if (err.keyword === 'required') {
|
|
715
|
+
for (const prop of params.requiredProperties || []) missing.push(__fieldPath(err.instancePath, prop));
|
|
716
|
+
} else if (err.keyword === 'additionalProperties') {
|
|
717
|
+
for (const prop of params.additionalProperties || []) unknown.push(__fieldPath(err.instancePath, prop));
|
|
718
|
+
} else {
|
|
719
|
+
const group = byPath.get(err.instancePath) || [];
|
|
720
|
+
group.push(err);
|
|
721
|
+
byPath.set(err.instancePath, group);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
const typeErrors = [];
|
|
725
|
+
for (const [instancePath, group] of byPath) {
|
|
726
|
+
const field = __fieldPath(instancePath) || '(input)';
|
|
727
|
+
const value = __valueAt(provided, instancePath);
|
|
728
|
+
const consts = group.filter((e) => e.keyword === 'const' && 'allowedValue' in (e.params || {}));
|
|
729
|
+
const typeErr = group.find((e) => e.keyword === 'type' && (e.params || {}).type);
|
|
730
|
+
if (consts.length) {
|
|
731
|
+
// A union of literals: the branches ARE the allowed values.
|
|
732
|
+
typeErrors.push({ field, expected: consts.map((e) => String(e.params.allowedValue)).join(' | '), actual: __fmt(value) });
|
|
733
|
+
} else if (typeErr) {
|
|
734
|
+
typeErrors.push({ field, expected: String(typeErr.params.type), actual: __valueType(value) });
|
|
735
|
+
} else {
|
|
736
|
+
typeErrors.push({ field, expected: group[0].message, actual: __fmt(value) });
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
return { ok: false, missing, unknown, typeErrors, errors, signature };
|
|
740
|
+
};
|
|
741
|
+
|
|
656
742
|
const __actionsApi = {
|
|
657
743
|
list(plugin) {
|
|
658
744
|
const paths = Object.keys(__index);
|
|
@@ -691,6 +777,13 @@ const __actionsApi = {
|
|
|
691
777
|
const near = __actionsApi.find(path, 3).map((n) => n.path);
|
|
692
778
|
return { ok: false, error: 'Unknown action: ' + path, suggestions: near };
|
|
693
779
|
}
|
|
780
|
+
const signature = __formatSignature(hit.plugin, hit.entry);
|
|
781
|
+
if (hit.entry.schema) {
|
|
782
|
+
// Mirror the host's normalizeActionInput: a check with no args is
|
|
783
|
+
// a call with an empty argument set; anything else — null, a
|
|
784
|
+
// scalar — is validated as given, exactly as execute would.
|
|
785
|
+
return __checkTyped(hit.entry, args === undefined ? {} : args, signature);
|
|
786
|
+
}
|
|
694
787
|
const inputs = hit.entry.inputs || {};
|
|
695
788
|
const provided = args && typeof args === 'object' ? args : {};
|
|
696
789
|
const missing = [];
|
|
@@ -719,7 +812,8 @@ const __actionsApi = {
|
|
|
719
812
|
missing,
|
|
720
813
|
unknown,
|
|
721
814
|
typeErrors,
|
|
722
|
-
|
|
815
|
+
errors: [],
|
|
816
|
+
signature,
|
|
723
817
|
};
|
|
724
818
|
},
|
|
725
819
|
};
|