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.
- package/CHANGELOG.md +74 -0
- package/dist/agent-runtime-coding-tools.js +3 -3
- package/dist/agent-runtime-harness.js +4 -4
- package/dist/agent-runtime-sandbox.js +3 -3
- package/dist/agent-runtime.js +7 -7
- package/dist/cli.d.ts +14 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +359 -11
- package/dist/{index-gbqjt8jz.js → index-19ryv24q.js} +3 -3
- package/dist/{index-2hrfpw2c.js → index-32vjke6q.js} +2 -2
- package/dist/{index-f475yj00.js → index-6atvfjc1.js} +1 -1
- package/dist/{index-79hb1wyh.js → index-7t0wq6j5.js} +3 -3
- package/dist/{index-j7q0xj6d.js → index-8crm1srv.js} +1 -1
- package/dist/{index-kc6h6hg0.js → index-8z9we758.js} +1 -1
- package/dist/{index-r159gjwy.js → index-fenaekmk.js} +94 -8
- package/dist/{index-wb15909q.js → index-kzxpsf8y.js} +3 -3
- package/dist/{index-44ht2790.js → index-vcnfwrtr.js} +1 -1
- package/dist/{index-1923shw9.js → index-y47z614h.js} +214 -7
- package/dist/testing.js +1 -1
- package/dist/tool-invoker.js +4 -4
- package/dist/tools/cli-args.d.ts +22 -0
- package/dist/tools/cli-args.d.ts.map +1 -1
- package/dist/tools/cli-installer.d.ts +29 -0
- package/dist/tools/cli-installer.d.ts.map +1 -0
- package/dist/tools/cli-manifest.d.ts +83 -0
- package/dist/tools/cli-manifest.d.ts.map +1 -0
- package/dist/tools/cli-profile.d.ts +40 -0
- package/dist/tools/cli-profile.d.ts.map +1 -0
- package/dist/tools/cli-update.d.ts +64 -0
- package/dist/tools/cli-update.d.ts.map +1 -0
- package/dist/tools/cli-view.d.ts +12 -0
- package/dist/tools/cli-view.d.ts.map +1 -0
- package/dist/tools/cli.d.ts.map +1 -1
- package/dist/tools/connections/index.d.ts +2 -1
- package/dist/tools/connections/index.d.ts.map +1 -1
- package/dist/tools/connections/index.js +37 -10
- package/dist/tools/connections/mcp.d.ts +2 -1
- package/dist/tools/connections/mcp.d.ts.map +1 -1
- package/dist/tools/connections/mount.d.ts.map +1 -1
- package/dist/tools/connections/openapi.d.ts +2 -1
- package/dist/tools/connections/openapi.d.ts.map +1 -1
- package/dist/tools/connections/runtime.d.ts +17 -0
- package/dist/tools/connections/runtime.d.ts.map +1 -1
- package/dist/tools/connections/types.d.ts +18 -1
- package/dist/tools/connections/types.d.ts.map +1 -1
- package/dist/tools/json-schema-dialect.d.ts +17 -0
- package/dist/tools/json-schema-dialect.d.ts.map +1 -0
- package/dist/tools/presentation.d.ts +8 -1
- package/dist/tools/presentation.d.ts.map +1 -1
- package/dist/tools.js +8 -8
- package/llms-full.txt +203 -3
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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("#") ?
|
|
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
|
|
752
|
+
const targets = { rootReferenced: false };
|
|
753
|
+
const rewritten = rewriteLocalReferences(schema, namespace, targets);
|
|
703
754
|
if (!isRecord(rewritten))
|
|
704
755
|
return schema;
|
|
705
|
-
|
|
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-
|
|
3
|
+
} from "./index-32vjke6q.js";
|
|
4
4
|
import {
|
|
5
5
|
runtimeToolMountable
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-8z9we758.js";
|
|
7
7
|
import {
|
|
8
8
|
projectToolSurface
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-fenaekmk.js";
|
|
10
10
|
|
|
11
11
|
// src/tools/surface.ts
|
|
12
12
|
function collectToolSurface({
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
} from "./index-sbdmyz75.js";
|
|
4
4
|
import {
|
|
5
5
|
collectToolSurface
|
|
6
|
-
} from "./index-
|
|
6
|
+
} from "./index-kzxpsf8y.js";
|
|
7
7
|
import {
|
|
8
8
|
createToolRunner,
|
|
9
9
|
formatToolError
|
|
10
|
-
} from "./index-
|
|
10
|
+
} from "./index-32vjke6q.js";
|
|
11
11
|
import {
|
|
12
12
|
toolErrorFromResult,
|
|
13
13
|
toolResultFromError
|
|
14
|
-
} from "./index-
|
|
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-
|
|
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
|
|
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
package/dist/tool-invoker.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createToolInvoker
|
|
3
|
-
} from "./index-
|
|
4
|
-
import"./index-
|
|
5
|
-
import"./index-
|
|
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-
|
|
15
|
+
import"./index-fenaekmk.js";
|
|
16
16
|
import"./index-cby4ar3v.js";
|
|
17
17
|
import"./index-77fekveh.js";
|
|
18
18
|
export {
|
package/dist/tools/cli-args.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|