stitchkit 0.90.3 → 0.90.4

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 (52) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/agent-runtime-coding-tools.js +3 -3
  3. package/dist/agent-runtime-harness.js +4 -4
  4. package/dist/agent-runtime-sandbox.js +3 -3
  5. package/dist/agent-runtime.js +7 -7
  6. package/dist/cli.d.ts +14 -1
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +359 -11
  9. package/dist/{index-gbqjt8jz.js → index-19ryv24q.js} +3 -3
  10. package/dist/{index-2hrfpw2c.js → index-32vjke6q.js} +2 -2
  11. package/dist/{index-f475yj00.js → index-6atvfjc1.js} +1 -1
  12. package/dist/{index-79hb1wyh.js → index-7t0wq6j5.js} +3 -3
  13. package/dist/{index-j7q0xj6d.js → index-8crm1srv.js} +1 -1
  14. package/dist/{index-kc6h6hg0.js → index-8z9we758.js} +1 -1
  15. package/dist/{index-r159gjwy.js → index-fenaekmk.js} +94 -8
  16. package/dist/{index-wb15909q.js → index-kzxpsf8y.js} +3 -3
  17. package/dist/{index-44ht2790.js → index-vcnfwrtr.js} +1 -1
  18. package/dist/{index-1923shw9.js → index-y47z614h.js} +214 -7
  19. package/dist/testing.js +1 -1
  20. package/dist/tool-invoker.js +4 -4
  21. package/dist/tools/cli-args.d.ts +22 -0
  22. package/dist/tools/cli-args.d.ts.map +1 -1
  23. package/dist/tools/cli-installer.d.ts +29 -0
  24. package/dist/tools/cli-installer.d.ts.map +1 -0
  25. package/dist/tools/cli-manifest.d.ts +83 -0
  26. package/dist/tools/cli-manifest.d.ts.map +1 -0
  27. package/dist/tools/cli-profile.d.ts +40 -0
  28. package/dist/tools/cli-profile.d.ts.map +1 -0
  29. package/dist/tools/cli-update.d.ts +64 -0
  30. package/dist/tools/cli-update.d.ts.map +1 -0
  31. package/dist/tools/cli-view.d.ts +12 -0
  32. package/dist/tools/cli-view.d.ts.map +1 -0
  33. package/dist/tools/cli.d.ts.map +1 -1
  34. package/dist/tools/connections/index.d.ts +2 -1
  35. package/dist/tools/connections/index.d.ts.map +1 -1
  36. package/dist/tools/connections/index.js +37 -10
  37. package/dist/tools/connections/mcp.d.ts +2 -1
  38. package/dist/tools/connections/mcp.d.ts.map +1 -1
  39. package/dist/tools/connections/mount.d.ts.map +1 -1
  40. package/dist/tools/connections/openapi.d.ts +2 -1
  41. package/dist/tools/connections/openapi.d.ts.map +1 -1
  42. package/dist/tools/connections/runtime.d.ts +17 -0
  43. package/dist/tools/connections/runtime.d.ts.map +1 -1
  44. package/dist/tools/connections/types.d.ts +18 -1
  45. package/dist/tools/connections/types.d.ts.map +1 -1
  46. package/dist/tools/json-schema-dialect.d.ts +17 -0
  47. package/dist/tools/json-schema-dialect.d.ts.map +1 -0
  48. package/dist/tools/presentation.d.ts +8 -1
  49. package/dist/tools/presentation.d.ts.map +1 -1
  50. package/dist/tools.js +8 -8
  51. package/llms-full.txt +203 -3
  52. package/package.json +1 -1
@@ -24,7 +24,7 @@ import {
24
24
  } from "./index-scs3f1eg.js";
25
25
  import {
26
26
  defineRuntimeTool
27
- } from "./index-kc6h6hg0.js";
27
+ } from "./index-8z9we758.js";
28
28
 
29
29
  // src/agent-runtime/coding-tool-contract.ts
30
30
  import { z } from "zod";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  projectRuntimeTool
3
- } from "./index-r159gjwy.js";
3
+ } from "./index-fenaekmk.js";
4
4
 
5
5
  // src/tools/runtime-tool.ts
6
6
  function defineRuntimeTool(definition) {
@@ -667,6 +667,40 @@ function assertUniqueToolName(name, taken, surface) {
667
667
 
668
668
  // src/tools/presentation.ts
669
669
  import { z as z2 } from "zod";
670
+
671
+ // src/tools/json-schema-dialect.ts
672
+ var DRAFT_07_MARKER = "draft-07";
673
+ var DRAFT_07_KEYWORD = "definitions";
674
+ var DEFS_KEYWORD = "$defs";
675
+ function declaresDraft07(dialect) {
676
+ return typeof dialect === "string" && dialect.includes(DRAFT_07_MARKER);
677
+ }
678
+ function rewriteDefinitionPointers(value) {
679
+ if (Array.isArray(value))
680
+ return value.map(rewriteDefinitionPointers);
681
+ if (!isRecord(value))
682
+ return value;
683
+ const rewritten = {};
684
+ for (const [key, child] of Object.entries(value)) {
685
+ rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith(`#/${DRAFT_07_KEYWORD}/`) ? `#/${DEFS_KEYWORD}/${child.slice(`#/${DRAFT_07_KEYWORD}/`.length)}` : rewriteDefinitionPointers(child);
686
+ }
687
+ return rewritten;
688
+ }
689
+ function withDefsDialect(schema) {
690
+ const definitions = schema[DRAFT_07_KEYWORD];
691
+ if (!isRecord(definitions) || DEFS_KEYWORD in schema)
692
+ return schema;
693
+ const rewritten = {};
694
+ for (const [key, value] of Object.entries(schema)) {
695
+ if (key === DRAFT_07_KEYWORD)
696
+ continue;
697
+ rewritten[key] = rewriteDefinitionPointers(value);
698
+ }
699
+ rewritten[DEFS_KEYWORD] = rewriteDefinitionPointers(definitions);
700
+ return rewritten;
701
+ }
702
+
703
+ // src/tools/presentation.ts
670
704
  function withoutDialect(schema) {
671
705
  const result = {};
672
706
  for (const [key, value] of Object.entries(schema)) {
@@ -684,25 +718,59 @@ function hasLocalReference(value) {
684
718
  return true;
685
719
  return Object.values(value).some(hasLocalReference);
686
720
  }
687
- function rewriteLocalReferences(value, namespace) {
721
+ var NAMESPACE_SEPARATOR = "__";
722
+ var DEFINITION_KEYWORDS = ["definitions", "$defs"];
723
+ function rewriteReference(reference, namespace, targets) {
724
+ if (reference === "#" || reference === "#/") {
725
+ targets.rootReferenced = true;
726
+ return `#/definitions/${namespace}`;
727
+ }
728
+ const segments = reference.slice(2).split("/");
729
+ const [keyword, name, ...rest] = segments;
730
+ if (keyword !== undefined && name !== undefined && DEFINITION_KEYWORDS.includes(keyword)) {
731
+ const renamed = `${namespace}${NAMESPACE_SEPARATOR}${name}`;
732
+ return ["#", "definitions", renamed, ...rest].join("/");
733
+ }
734
+ targets.rootReferenced = true;
735
+ return `#/definitions/${namespace}/${segments.join("/")}`;
736
+ }
737
+ function rewriteLocalReferences(value, namespace, targets) {
688
738
  if (Array.isArray(value)) {
689
- return value.map((child) => rewriteLocalReferences(child, namespace));
739
+ return value.map((child) => rewriteLocalReferences(child, namespace, targets));
690
740
  }
691
741
  if (!isRecord(value))
692
742
  return value;
693
743
  const rewritten = {};
694
744
  for (const [key, child] of Object.entries(value)) {
695
- rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith("#") ? `#/definitions/${namespace}${child.slice(1)}` : rewriteLocalReferences(child, namespace);
745
+ rewritten[key] = key === "$ref" && typeof child === "string" && child.startsWith("#") ? rewriteReference(child, namespace, targets) : rewriteLocalReferences(child, namespace, targets);
696
746
  }
697
747
  return rewritten;
698
748
  }
699
749
  function namespaceLocalReferences(schema, namespace) {
700
750
  if (!schema || !hasLocalReference(schema))
701
751
  return schema;
702
- const rewritten = rewriteLocalReferences(schema, namespace);
752
+ const targets = { rootReferenced: false };
753
+ const rewritten = rewriteLocalReferences(schema, namespace, targets);
703
754
  if (!isRecord(rewritten))
704
755
  return schema;
705
- return { ...rewritten, definitions: { [namespace]: rewritten } };
756
+ const definitions = {};
757
+ const body = {};
758
+ for (const [key, value] of Object.entries(rewritten)) {
759
+ if (DEFINITION_KEYWORDS.includes(key)) {
760
+ if (isRecord(value)) {
761
+ for (const [name, definition] of Object.entries(value)) {
762
+ definitions[`${namespace}${NAMESPACE_SEPARATOR}${name}`] = definition;
763
+ }
764
+ }
765
+ continue;
766
+ }
767
+ body[key] = value;
768
+ }
769
+ if (targets.rootReferenced)
770
+ definitions[namespace] = withoutDialect(body);
771
+ if (Object.keys(definitions).length === 0)
772
+ return body;
773
+ return { ...body, definitions };
706
774
  }
707
775
  function objectProperties(schema) {
708
776
  return schema.type === "object" && isRecord(schema.properties) ? schema.properties : null;
@@ -710,11 +778,29 @@ function objectProperties(schema) {
710
778
  function requiredKeys2(schema) {
711
779
  return Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === "string") : [];
712
780
  }
781
+ function hoistDefinitions(schema) {
782
+ const branches = Array.isArray(schema.allOf) ? schema.allOf : [];
783
+ const definitions = {};
784
+ const lifted = branches.map((branch) => {
785
+ if (!isRecord(branch) || !isRecord(branch.definitions))
786
+ return branch;
787
+ Object.assign(definitions, branch.definitions);
788
+ const rest = {};
789
+ for (const [key, value] of Object.entries(branch)) {
790
+ if (key !== "definitions")
791
+ rest[key] = value;
792
+ }
793
+ return rest;
794
+ });
795
+ if (Object.keys(definitions).length === 0)
796
+ return schema;
797
+ return { ...schema, allOf: lifted, definitions };
798
+ }
713
799
  function mergeObjectSchemas(left, right, rightOwnsUnknownKeys) {
714
800
  const leftProperties = objectProperties(left);
715
801
  const rightProperties = objectProperties(right);
716
802
  if (!leftProperties || !rightProperties)
717
- return { allOf: [left, right] };
803
+ return hoistDefinitions({ allOf: [left, right] });
718
804
  const conflicts = Object.keys(leftProperties).filter((key) => (key in rightProperties));
719
805
  if (conflicts.length > 0) {
720
806
  throw new Error(`Schema merge conflict: ${conflicts.join(", ")} appear in both params and input`);
@@ -777,7 +863,7 @@ function isObjectPresentationSchema(schema) {
777
863
  return schema.type === "object" && isRecord(schema.properties);
778
864
  }
779
865
  function presentationMetadata(schema) {
780
- return withoutDialect(schema);
866
+ return withDefsDialect(withoutDialect(schema));
781
867
  }
782
868
 
783
869
  // src/tools/internal/surface-projector.ts
@@ -1027,4 +1113,4 @@ function prepareProjectedMcpTools(tools, config = {}) {
1027
1113
  return prepared;
1028
1114
  }
1029
1115
 
1030
- export { objectShapeKeys, rebuildObject, mergeSchemas, validateMcpRoundPolicy, assertToolName, assertUniqueToolName, PORTABLE_JSON_SCHEMA_FORMATS, findNonPortableFormats, flattenToolJsonSchema, buildToolPresentationSchema, presentationMetadata, findUntypedProperties, assertToolExtensionCompatible, projectRuntimeTool, projectToolSurface, mcpProjectionCandidate, prepareProjectedMcpTools };
1116
+ export { objectShapeKeys, rebuildObject, mergeSchemas, validateMcpRoundPolicy, assertToolName, assertUniqueToolName, PORTABLE_JSON_SCHEMA_FORMATS, findNonPortableFormats, flattenToolJsonSchema, declaresDraft07, withDefsDialect, buildToolPresentationSchema, presentationMetadata, findUntypedProperties, assertToolExtensionCompatible, projectRuntimeTool, projectToolSurface, mcpProjectionCandidate, prepareProjectedMcpTools };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  contractToolMountable
3
- } from "./index-2hrfpw2c.js";
3
+ } from "./index-32vjke6q.js";
4
4
  import {
5
5
  runtimeToolMountable
6
- } from "./index-kc6h6hg0.js";
6
+ } from "./index-8z9we758.js";
7
7
  import {
8
8
  projectToolSurface
9
- } from "./index-r159gjwy.js";
9
+ } from "./index-fenaekmk.js";
10
10
 
11
11
  // src/tools/surface.ts
12
12
  function collectToolSurface({
@@ -20,7 +20,7 @@ import {
20
20
  } from "./index-kzfs85xp.js";
21
21
  import {
22
22
  objectShapeKeys
23
- } from "./index-r159gjwy.js";
23
+ } from "./index-fenaekmk.js";
24
24
  import {
25
25
  isRecord
26
26
  } from "./index-77fekveh.js";
@@ -3,15 +3,15 @@ import {
3
3
  } from "./index-sbdmyz75.js";
4
4
  import {
5
5
  collectToolSurface
6
- } from "./index-wb15909q.js";
6
+ } from "./index-kzxpsf8y.js";
7
7
  import {
8
8
  createToolRunner,
9
9
  formatToolError
10
- } from "./index-2hrfpw2c.js";
10
+ } from "./index-32vjke6q.js";
11
11
  import {
12
12
  toolErrorFromResult,
13
13
  toolResultFromError
14
- } from "./index-44ht2790.js";
14
+ } from "./index-vcnfwrtr.js";
15
15
  import {
16
16
  formatZodError,
17
17
  validateDeclaredOutput
@@ -27,7 +27,7 @@ import {
27
27
  assertUniqueToolName,
28
28
  buildToolPresentationSchema,
29
29
  objectShapeKeys
30
- } from "./index-r159gjwy.js";
30
+ } from "./index-fenaekmk.js";
31
31
  import {
32
32
  jsonSchemaFields
33
33
  } from "./index-cby4ar3v.js";
@@ -39,7 +39,8 @@ import {
39
39
  import { z } from "zod";
40
40
  var NUMERIC_VALUE = /^-(\d+\.?\d*|\.\d+)$/;
41
41
  var BOOL_OPTIONS = new Set(["json", "wait", "quiet", "dry-run", "help"]);
42
- var VALUE_OPTIONS = new Set(["wait-timeout", "output-dir"]);
42
+ var VIEW_OPTIONS = new Set(["count-by", "sum", "by", "top", "table"]);
43
+ var VALUE_OPTIONS = new Set(["wait-timeout", "output-dir", ...VIEW_OPTIONS]);
43
44
  var RESERVED_CLI_OPTIONS = new Set([...BOOL_OPTIONS, ...VALUE_OPTIONS]);
44
45
  function classifyLongOptionToken(token) {
45
46
  if (!token.startsWith("--") || token === "--")
@@ -315,6 +316,7 @@ function parseCliArgs(argv, schema, config = {}) {
315
316
  }
316
317
  const flags = new Map;
317
318
  const boolFlags = new Map;
319
+ const viewFlags = new Map;
318
320
  const positionals = [];
319
321
  const pushFlag = (name, value) => {
320
322
  const existing = flags.get(name);
@@ -400,6 +402,10 @@ function parseCliArgs(argv, schema, config = {}) {
400
402
  throw new CliArgumentError("--wait-timeout must be a positive number");
401
403
  }
402
404
  options.waitTimeout = timeout;
405
+ } else if (VIEW_OPTIONS.has(name)) {
406
+ if (viewFlags.has(name))
407
+ throw new CliArgumentError(`--${name} was given twice`);
408
+ viewFlags.set(name, value);
403
409
  } else {
404
410
  options.outputDir = value;
405
411
  }
@@ -433,6 +439,9 @@ function parseCliArgs(argv, schema, config = {}) {
433
439
  }
434
440
  pushFlag(name, value);
435
441
  }
442
+ const view = resolveCliView(viewFlags);
443
+ if (view)
444
+ options.view = view;
436
445
  const toolArgs = {};
437
446
  const fillable = config.positionals === undefined ? [...fields.entries()].filter(([, info]) => info.kind !== "boolean").map(([name]) => name) : [...config.positionals];
438
447
  const variadicTail = config.positionals !== undefined && fields.get(fillable[fillable.length - 1] ?? "")?.kind === "array" ? fillable[fillable.length - 1] : undefined;
@@ -536,6 +545,63 @@ function extractCliGlobalOptions(argv, schema) {
536
545
  }
537
546
  return { argv: rest, globals: parsed.data };
538
547
  }
548
+ function resolveCliView(flags) {
549
+ if (flags.size === 0)
550
+ return;
551
+ const countBy = flags.get("count-by");
552
+ const sum = flags.get("sum");
553
+ const table = flags.get("table");
554
+ const by = flags.get("by");
555
+ const rawTop = flags.get("top");
556
+ const named = [
557
+ ["--count-by", countBy],
558
+ ["--sum", sum],
559
+ ["--table", table]
560
+ ].filter(([, value]) => value !== undefined);
561
+ if (named.length > 1) {
562
+ throw new CliArgumentError(`${named.map(([flag]) => flag).join(" and ")} ask for different shapes — pass one`);
563
+ }
564
+ let top;
565
+ if (rawTop !== undefined) {
566
+ top = Number(rawTop);
567
+ if (!Number.isInteger(top) || top <= 0) {
568
+ throw new CliArgumentError("--top must be a positive whole number");
569
+ }
570
+ }
571
+ if (table !== undefined) {
572
+ if (by !== undefined || top !== undefined) {
573
+ throw new CliArgumentError("--table lists records; it takes neither --by nor --top");
574
+ }
575
+ const fields = table.split(",").map((field) => field.trim()).filter(Boolean);
576
+ if (fields.length === 0)
577
+ throw new CliArgumentError("--table needs at least one field");
578
+ return { kind: "table", fields };
579
+ }
580
+ if (sum !== undefined) {
581
+ if (top !== undefined && by === undefined) {
582
+ throw new CliArgumentError("--top needs --by: a single sum has nothing to rank");
583
+ }
584
+ return {
585
+ kind: "sum",
586
+ field: sum,
587
+ ...by !== undefined && { by },
588
+ ...top !== undefined && { top }
589
+ };
590
+ }
591
+ if (countBy !== undefined) {
592
+ if (by !== undefined) {
593
+ throw new CliArgumentError("--count-by already names the grouping field; drop --by");
594
+ }
595
+ return { kind: "count", field: countBy, ...top !== undefined && { top } };
596
+ }
597
+ if (by !== undefined) {
598
+ if (top === undefined) {
599
+ throw new CliArgumentError("--by groups a view; pass --count-by, --sum or --top with it");
600
+ }
601
+ return { kind: "count", field: by, top };
602
+ }
603
+ throw new CliArgumentError("--top needs --by, --count-by or --sum to rank");
604
+ }
539
605
 
540
606
  // src/tools/cli-command.ts
541
607
  function defineCliCommand(definition) {
@@ -633,6 +699,126 @@ function emitResult(result, writers, opts) {
633
699
  return codes[result.code] ?? 1;
634
700
  }
635
701
 
702
+ // src/tools/cli-view.ts
703
+ var ABSENT = "(absent)";
704
+ function selectRecords(data) {
705
+ if (Array.isArray(data))
706
+ return data;
707
+ if (isRecord(data)) {
708
+ const arrays = Object.entries(data).filter(([, value]) => Array.isArray(value));
709
+ const only = arrays[0];
710
+ if (arrays.length === 1 && only && Array.isArray(only[1]))
711
+ return only[1];
712
+ if (arrays.length > 1) {
713
+ throw new CliArgumentError(`an aggregate needs one collection, but the result carries several: ${arrays.map(([key]) => key).join(", ")} — name the shape you want with jq instead`);
714
+ }
715
+ }
716
+ throw new CliArgumentError("an aggregate needs a collection; this result is not one");
717
+ }
718
+ function readField(record, path) {
719
+ let current = record;
720
+ for (const segment of path) {
721
+ if (!isRecord(current))
722
+ return;
723
+ current = current[segment];
724
+ }
725
+ return current;
726
+ }
727
+ function fieldPath(field) {
728
+ const path = field.split(".");
729
+ if (path.some((segment) => segment.length === 0 || isUnsafeKey(segment))) {
730
+ throw new CliArgumentError(`"${field}" is not a readable field path`);
731
+ }
732
+ return path;
733
+ }
734
+ function availableFields(records) {
735
+ const keys = new Set;
736
+ for (const record of records) {
737
+ if (isRecord(record))
738
+ for (const key of Object.keys(record))
739
+ keys.add(key);
740
+ }
741
+ return [...keys].sort();
742
+ }
743
+ function assertFieldPresent(records, field) {
744
+ const path = fieldPath(field);
745
+ const present = records.some((record) => readField(record, path) !== undefined);
746
+ if (!present) {
747
+ const available = availableFields(records);
748
+ throw new CliArgumentError(`no record carries the field "${field}"${available.length > 0 ? ` — available: ${available.join(", ")}` : ""}`);
749
+ }
750
+ return path;
751
+ }
752
+ function groupKey(value) {
753
+ if (value === undefined)
754
+ return ABSENT;
755
+ if (value === null)
756
+ return "null";
757
+ if (typeof value === "object")
758
+ return JSON.stringify(value);
759
+ return String(value);
760
+ }
761
+ function ordered(totals, top) {
762
+ const entries = [...totals].sort(([leftKey, left], [rightKey, right]) => right === left ? leftKey.localeCompare(rightKey) : right - left);
763
+ const sliced = top === undefined ? entries : entries.slice(0, top);
764
+ return Object.fromEntries(sliced);
765
+ }
766
+ function numericValue(value, field) {
767
+ if (value === undefined || value === null)
768
+ return;
769
+ if (typeof value === "number" && Number.isFinite(value))
770
+ return value;
771
+ if (typeof value === "bigint")
772
+ return Number(value);
773
+ throw new CliArgumentError(`--sum ${field}: "${groupKey(value)}" is not a number`);
774
+ }
775
+ function renderTable(records, fields) {
776
+ const paths = fields.map((field) => assertFieldPresent(records, field));
777
+ const cell = (value) => {
778
+ if (value === undefined)
779
+ return "";
780
+ if (value === null)
781
+ return "null";
782
+ if (typeof value === "object")
783
+ return JSON.stringify(value);
784
+ return String(value);
785
+ };
786
+ const rows = records.map((record) => paths.map((path) => cell(readField(record, path))));
787
+ const widths = fields.map((field, column) => Math.max(field.length, ...rows.map((row) => row[column]?.length ?? 0)));
788
+ const line = (cells) => cells.map((value, column) => value.padEnd(widths[column] ?? value.length)).join(" ").trimEnd();
789
+ return `${[line(fields), line(widths.map((width) => "-".repeat(width))), ...rows.map(line)].join(`
790
+ `)}
791
+ `;
792
+ }
793
+ function renderCliView(data, view) {
794
+ const records = selectRecords(data);
795
+ if (view.kind === "table")
796
+ return { kind: "text", text: renderTable(records, view.fields) };
797
+ if (view.kind === "count") {
798
+ const path2 = assertFieldPresent(records, view.field);
799
+ const totals2 = new Map;
800
+ for (const record of records) {
801
+ const key = groupKey(readField(record, path2));
802
+ totals2.set(key, (totals2.get(key) ?? 0) + 1);
803
+ }
804
+ return { kind: "json", data: ordered(totals2, view.top) };
805
+ }
806
+ const path = assertFieldPresent(records, view.field);
807
+ if (view.by === undefined) {
808
+ let total = 0;
809
+ for (const record of records)
810
+ total += numericValue(readField(record, path), view.field) ?? 0;
811
+ return { kind: "json", data: total };
812
+ }
813
+ const byPath = assertFieldPresent(records, view.by);
814
+ const totals = new Map;
815
+ for (const record of records) {
816
+ const key = groupKey(readField(record, byPath));
817
+ totals.set(key, (totals.get(key) ?? 0) + (numericValue(readField(record, path), view.field) ?? 0));
818
+ }
819
+ return { kind: "json", data: ordered(totals, view.top) };
820
+ }
821
+
636
822
  // src/tools/wait-core.ts
637
823
  var DEFAULT_BACKOFF = [2, 3, 5, 5, 8, 10];
638
824
  var DEFAULT_TIMEOUT = 600;
@@ -1181,7 +1367,11 @@ var GLOBAL_OPTIONS = [
1181
1367
  ["--output-dir <dir>", "Download result media into a directory"],
1182
1368
  ["--quiet", "Suppress non-essential stderr output"],
1183
1369
  ["--dry-run", "Print the resolved call without executing it"],
1184
- ["--help, -h", "Show help for a command"]
1370
+ ["--help, -h", "Show help for a command"],
1371
+ ["--count-by <field>", "Count records per distinct value of a field"],
1372
+ ["--sum <field>", "Total a numeric field, optionally grouped by --by"],
1373
+ ["--top <n> --by <f>", "Keep only the n largest groups"],
1374
+ ["--table <a,b>", "Render the named fields as an aligned table"]
1185
1375
  ];
1186
1376
  async function readPipedStdin() {
1187
1377
  if (process.stdin.isTTY)
@@ -1708,6 +1898,23 @@ async function createCli(config) {
1708
1898
  if (options.outputDir && result.ok && config.download) {
1709
1899
  downloadsOk = await downloadResults(config.download(result.data), options.outputDir, stderr, options.quiet, config.allowPrivateDownloadHosts ?? false, config.maxDownloadBytes ?? DEFAULT_DOWNLOAD_MAX_BYTES, config.downloadTimeoutMs);
1710
1900
  }
1901
+ if (options.view && result.ok) {
1902
+ let viewed;
1903
+ try {
1904
+ viewed = renderCliView(result.data, options.view);
1905
+ } catch (error) {
1906
+ if (!(error instanceof CliArgumentError))
1907
+ throw error;
1908
+ stderr(`${error.message}
1909
+ `);
1910
+ return exit(2);
1911
+ }
1912
+ if (viewed.kind === "text") {
1913
+ stdout(viewed.text);
1914
+ return exit(downloadsOk ? 0 : 1);
1915
+ }
1916
+ result = { ...result, data: viewed.data };
1917
+ }
1711
1918
  const exitCode = emitResult(result, { stdout, stderr }, {
1712
1919
  json: options.json,
1713
1920
  toolName: command,
@@ -1717,4 +1924,4 @@ async function createCli(config) {
1717
1924
  return exit(downloadsOk ? exitCode : 1);
1718
1925
  }
1719
1926
 
1720
- export { WaitTimeoutError, runWaitOperation, fetchGuarded, fetchPinnedDocument, readCapped, parseCliArgs, defineCliCommand, DEFAULT_EXIT_CODES, emitResult, pollUntilDone, createCli };
1927
+ export { WaitTimeoutError, runWaitOperation, fetchGuarded, fetchPinnedDocument, readCapped, routeCliArgv, CliArgumentError, parseCliArgs, extractCliGlobalOptions, defineCliCommand, DEFAULT_EXIT_CODES, emitResult, renderCliView, pollUntilDone, createCli };
package/dist/testing.js CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  mcpProjectionCandidate,
49
49
  prepareProjectedMcpTools,
50
50
  projectToolSurface
51
- } from "./index-r159gjwy.js";
51
+ } from "./index-fenaekmk.js";
52
52
  import {
53
53
  toJsonSchema
54
54
  } from "./index-cby4ar3v.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createToolInvoker
3
- } from "./index-79hb1wyh.js";
4
- import"./index-2hrfpw2c.js";
5
- import"./index-44ht2790.js";
3
+ } from "./index-7t0wq6j5.js";
4
+ import"./index-32vjke6q.js";
5
+ import"./index-vcnfwrtr.js";
6
6
  import"./index-vsbzgd7b.js";
7
7
  import"./index-f9mb610r.js";
8
8
  import"./index-2hryh65w.js";
@@ -12,7 +12,7 @@ import"./index-scs3f1eg.js";
12
12
  import"./index-zcgf3gqf.js";
13
13
  import"./index-7zbps32p.js";
14
14
  import"./index-kzfs85xp.js";
15
- import"./index-r159gjwy.js";
15
+ import"./index-fenaekmk.js";
16
16
  import"./index-cby4ar3v.js";
17
17
  import"./index-77fekveh.js";
18
18
  export {
@@ -18,6 +18,26 @@
18
18
  * call does (ADR 0014 parity).
19
19
  */
20
20
  import { z } from 'zod';
21
+ /**
22
+ * A requested aggregate view over the result.
23
+ *
24
+ * `--by` always names the grouping field, in every form it appears in, so the
25
+ * grammar has one meaning rather than two: `--top 5 --by status` is the five
26
+ * largest groups of `status`, exactly as `--count-by status --top 5` is.
27
+ */
28
+ export type CliResultView = {
29
+ kind: 'count';
30
+ field: string;
31
+ top?: number;
32
+ } | {
33
+ kind: 'sum';
34
+ field: string;
35
+ by?: string;
36
+ top?: number;
37
+ } | {
38
+ kind: 'table';
39
+ fields: readonly string[];
40
+ };
21
41
  /** CLI-behaviour flags, parsed out of argv before the tool arguments. */
22
42
  export interface CliRunOptions {
23
43
  /** `--json` — emit compact success/error JSON records for scripts. */
@@ -34,6 +54,8 @@ export interface CliRunOptions {
34
54
  dryRun: boolean;
35
55
  /** `--help` / `-h` — print usage for the command. */
36
56
  help: boolean;
57
+ /** `--count-by` / `--sum` / `--top` / `--table` — aggregate instead of the collection. */
58
+ view?: CliResultView;
37
59
  }
38
60
  export interface ParsedCliArgs {
39
61
  /** The flat tool-argument object handed to `executeToolMethod`. */
@@ -1 +1 @@
1
- {"version":3,"file":"cli-args.d.ts","sourceRoot":"","sources":["../../src/tools/cli-args.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,IAAI,EAAE,OAAO,CAAC;IACd,iEAAiE;IACjE,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAC;IAChB,qDAAqD;IACrD,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,mEAAmE;IACnE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,+BAA+B;IAC/B,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,SAAS,GACV,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,QAAQ,GACR,MAAM,GACN,OAAO,GACP,QAAQ,GACR,OAAO,CAAC;AAEZ,UAAU,SAAS;IACjB,IAAI,EAAE,SAAS,CAAC;IAChB,uEAAuE;IACvE,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAOD,eAAO,MAAM,oBAAoB,aAA+C,CAAC;AA0BjF;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,YAAY,CAsFlF;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IAChC,IAAI,SAAsB;CACpC;AAuED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAI1F;AA8FD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,CAAC,CAAC,OAAO,GAAG,SAAS,EAC7B,MAAM,GAAE;IACN,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC5B,GACL,aAAa,CA+Nf;AAED,iFAAiF;AACjF,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,MAAM,EAAE,CAAC,CAAC,SAAS,GAAG,SAAS,GAC9B,qBAAqB,CA8CvB"}
1
+ {"version":3,"file":"cli-args.d.ts","sourceRoot":"","sources":["../../src/tools/cli-args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Generate the one-line installer, from the manifest, on the server.
3
+ *
4
+ * A `curl … | sh` runs on a machine where nothing is installed yet — including
5
+ * `jq`. An installer that fetches the manifest and parses it therefore fails on
6
+ * exactly the machines it exists for. Generating the script *from* the manifest,
7
+ * with the URL and the digest already substituted, removes the dependency: the
8
+ * script downloads one file, checks one digest and renames it into place.
9
+ */
10
+ import type { CliBuildAsset, CliBuildManifest } from './cli-manifest.js';
11
+ export interface CliInstallerConfig {
12
+ manifest: CliBuildManifest;
13
+ /** The asset this script installs — one script per target. */
14
+ asset: CliBuildAsset;
15
+ /** The name the binary takes on the PATH; defaults to the manifest name. */
16
+ binaryName?: string;
17
+ /** Default install directory; overridable by `INSTALL_DIR` at run time. */
18
+ installDir?: string;
19
+ }
20
+ /**
21
+ * Render the installer for one asset.
22
+ *
23
+ * The three properties that matter, in the script rather than in a comment:
24
+ * no JSON parsing, the digest is checked against the **decompressed** bytes, and
25
+ * the final step is a rename — an interrupted download leaves a temporary file,
26
+ * never a half-written executable on someone's PATH.
27
+ */
28
+ export declare function renderCliInstaller(config: CliInstallerConfig): string;
29
+ //# sourceMappingURL=cli-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-installer.d.ts","sourceRoot":"","sources":["../../src/tools/cli-installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEtE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,8DAA8D;IAC9D,KAAK,EAAE,aAAa,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAOD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAuErE"}