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.
@@ -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
- signature: __formatSignature(hit.plugin, hit.entry),
815
+ errors: [],
816
+ signature,
723
817
  };
724
818
  },
725
819
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runline",
3
- "version": "0.27.1",
3
+ "version": "0.27.2",
4
4
  "description": "Code mode for agents \u2014 turn any API or command into a callable action",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",