@opengeni/ogtool 1.3.0 → 1.4.0
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 +1 -1
- package/dist/bin/ogtool.cjs +74 -7
- package/dist/cli.d.ts +7 -0
- package/package.json +3 -2
- package/src/cli.ts +17 -4
package/README.md
CHANGED
|
@@ -44,7 +44,7 @@ Commands:
|
|
|
44
44
|
- `ogtool list [--json] [--query <substring>] [--limit <1..100>] [--offset <integer>]`
|
|
45
45
|
- `ogtool list --full` — the previous full catalog JSON, including identity and schemas
|
|
46
46
|
- `ogtool show <tool-path-or-model-name>` — one tool's details and schemas as JSON
|
|
47
|
-
- `ogtool call <tool-path-or-model-name> [json-object]`
|
|
47
|
+
- `ogtool call <tool-path-or-model-name> [json-object] [--full]` — the tool result as JSON. A text block that only repeats `structuredContent` as JSON is omitted, so the payload prints once; prose, differing text, annotated text, and non-text blocks stay. `--full` prints the exact result.
|
|
48
48
|
- `ogtool declarations [output-file]`
|
|
49
49
|
- `ogtool doctor`
|
|
50
50
|
- `ogtool --version`
|
package/dist/bin/ogtool.cjs
CHANGED
|
@@ -40,6 +40,7 @@ var __export = (target, all) => {
|
|
|
40
40
|
// src/cli.ts
|
|
41
41
|
var exports_cli = {};
|
|
42
42
|
__export(exports_cli, {
|
|
43
|
+
callOutput: () => callOutput,
|
|
43
44
|
listProjection: () => listProjection,
|
|
44
45
|
parseToolArguments: () => parseToolArguments,
|
|
45
46
|
resolveTool: () => resolveTool,
|
|
@@ -14676,6 +14677,65 @@ var CodemodeDispatchAck = exports_external.object({
|
|
|
14676
14677
|
status: exports_external.enum(["accepted", "already_running", "terminal", "unavailable", "rejected"])
|
|
14677
14678
|
}).strict();
|
|
14678
14679
|
|
|
14680
|
+
// ../contracts/src/mcp-structured-content.ts
|
|
14681
|
+
function omitStructuredContentTextDuplicates(result) {
|
|
14682
|
+
const structured = result.structuredContent;
|
|
14683
|
+
if (structured === undefined || structured === null)
|
|
14684
|
+
return result;
|
|
14685
|
+
const content = result.content.filter((entry) => !isPlainTextBlock(entry) || !textDuplicatesStructuredContent(entry.text, structured));
|
|
14686
|
+
if (content.length === result.content.length)
|
|
14687
|
+
return result;
|
|
14688
|
+
return { ...result, content };
|
|
14689
|
+
}
|
|
14690
|
+
function isPlainTextBlock(entry) {
|
|
14691
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry))
|
|
14692
|
+
return false;
|
|
14693
|
+
const record2 = entry;
|
|
14694
|
+
if (record2.type !== "text" || typeof record2.text !== "string")
|
|
14695
|
+
return false;
|
|
14696
|
+
return Object.keys(record2).every((key) => key === "type" || key === "text");
|
|
14697
|
+
}
|
|
14698
|
+
function textDuplicatesStructuredContent(text, structured) {
|
|
14699
|
+
const trimmed = text.replace(/^[ \t\n\r]+/u, "");
|
|
14700
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("["))
|
|
14701
|
+
return false;
|
|
14702
|
+
let parsed;
|
|
14703
|
+
try {
|
|
14704
|
+
parsed = JSON.parse(text);
|
|
14705
|
+
} catch {
|
|
14706
|
+
return false;
|
|
14707
|
+
}
|
|
14708
|
+
return !containsUnsafeInteger(parsed) && jsonValuesEqual(parsed, structured);
|
|
14709
|
+
}
|
|
14710
|
+
function containsUnsafeInteger(value) {
|
|
14711
|
+
if (typeof value === "number")
|
|
14712
|
+
return Number.isInteger(value) && !Number.isSafeInteger(value);
|
|
14713
|
+
if (Array.isArray(value))
|
|
14714
|
+
return value.some(containsUnsafeInteger);
|
|
14715
|
+
if (value && typeof value === "object")
|
|
14716
|
+
return Object.values(value).some(containsUnsafeInteger);
|
|
14717
|
+
return false;
|
|
14718
|
+
}
|
|
14719
|
+
function jsonValuesEqual(left, right) {
|
|
14720
|
+
if (left === right)
|
|
14721
|
+
return true;
|
|
14722
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) {
|
|
14723
|
+
return false;
|
|
14724
|
+
}
|
|
14725
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
14726
|
+
if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length) {
|
|
14727
|
+
return false;
|
|
14728
|
+
}
|
|
14729
|
+
return left.every((entry, index) => jsonValuesEqual(entry, right[index]));
|
|
14730
|
+
}
|
|
14731
|
+
const leftRecord = left;
|
|
14732
|
+
const rightRecord = right;
|
|
14733
|
+
const leftKeys = Object.keys(leftRecord);
|
|
14734
|
+
if (leftKeys.length !== Object.keys(rightRecord).length)
|
|
14735
|
+
return false;
|
|
14736
|
+
return leftKeys.every((key) => Object.hasOwn(rightRecord, key) && jsonValuesEqual(leftRecord[key], rightRecord[key]));
|
|
14737
|
+
}
|
|
14738
|
+
|
|
14679
14739
|
// ../tool-gateway/src/catalog.ts
|
|
14680
14740
|
var import_node_crypto = require("node:crypto");
|
|
14681
14741
|
|
|
@@ -15469,7 +15529,7 @@ async function abortableDelay(delayMs, signal) {
|
|
|
15469
15529
|
// package.json
|
|
15470
15530
|
var package_default = {
|
|
15471
15531
|
name: "@opengeni/ogtool",
|
|
15472
|
-
version: "1.
|
|
15532
|
+
version: "1.4.0",
|
|
15473
15533
|
description: "Codemode CLI and typed client entrypoint for an OpenGeni execution attempt.",
|
|
15474
15534
|
license: "Apache-2.0",
|
|
15475
15535
|
repository: {
|
|
@@ -15506,7 +15566,8 @@ var package_default = {
|
|
|
15506
15566
|
prepublishOnly: "bash ../../scripts/prepublish-guard"
|
|
15507
15567
|
},
|
|
15508
15568
|
dependencies: {
|
|
15509
|
-
"@opengeni/codemode": "workspace:*"
|
|
15569
|
+
"@opengeni/codemode": "workspace:*",
|
|
15570
|
+
"@opengeni/contracts": "workspace:*"
|
|
15510
15571
|
},
|
|
15511
15572
|
devDependencies: {
|
|
15512
15573
|
tsup: "^8.5.0",
|
|
@@ -15598,7 +15659,7 @@ function usage(exitCode = 1) {
|
|
|
15598
15659
|
" ogtool list [--full | --json]",
|
|
15599
15660
|
" [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
|
|
15600
15661
|
" ogtool show <tool-path-or-model-name>",
|
|
15601
|
-
" ogtool call <tool-path-or-model-name> [json-object]",
|
|
15662
|
+
" ogtool call <tool-path-or-model-name> [json-object] [--full]",
|
|
15602
15663
|
" ogtool read <operation-id>",
|
|
15603
15664
|
" ogtool resume <operation-id>",
|
|
15604
15665
|
" ogtool declarations [output-file]",
|
|
@@ -15606,6 +15667,7 @@ function usage(exitCode = 1) {
|
|
|
15606
15667
|
" ogtool --version",
|
|
15607
15668
|
"",
|
|
15608
15669
|
"list returns all authorized tools by default; --limit/--offset are opt-in slices",
|
|
15670
|
+
"call omits a text block that only repeats structuredContent; --full prints the exact result",
|
|
15609
15671
|
"",
|
|
15610
15672
|
"requires OPENGENI_CODEMODE_URL and OPENGENI_CODEMODE_TOKEN or OPENGENI_CODEMODE_TOKEN_FILE"
|
|
15611
15673
|
].join(`
|
|
@@ -15726,6 +15788,11 @@ function showOutput(catalog, name) {
|
|
|
15726
15788
|
return `${output}
|
|
15727
15789
|
`;
|
|
15728
15790
|
}
|
|
15791
|
+
function callOutput(result, full = false) {
|
|
15792
|
+
const printed = full ? result : omitStructuredContentTextDuplicates(result);
|
|
15793
|
+
return `${JSON.stringify(printed, null, 2)}
|
|
15794
|
+
`;
|
|
15795
|
+
}
|
|
15729
15796
|
function parseToolArguments(raw) {
|
|
15730
15797
|
if (raw === undefined)
|
|
15731
15798
|
return {};
|
|
@@ -15784,17 +15851,17 @@ async function main() {
|
|
|
15784
15851
|
return;
|
|
15785
15852
|
}
|
|
15786
15853
|
if (command === "call") {
|
|
15787
|
-
const
|
|
15854
|
+
const full = args.includes("--full");
|
|
15855
|
+
const [name, rawArguments] = args.filter((arg) => arg !== "--full");
|
|
15788
15856
|
if (!name)
|
|
15789
15857
|
throw new Error("tool path or model name is required");
|
|
15790
|
-
const argumentsValue = parseToolArguments(
|
|
15858
|
+
const argumentsValue = parseToolArguments(rawArguments);
|
|
15791
15859
|
const catalog = await client.catalog();
|
|
15792
15860
|
const entry = resolveTool(catalog, name);
|
|
15793
15861
|
const result = await client.call(entry.identity, argumentsValue, {
|
|
15794
15862
|
operationId: import_node_crypto3.randomUUID()
|
|
15795
15863
|
});
|
|
15796
|
-
process.stdout.write(
|
|
15797
|
-
`);
|
|
15864
|
+
process.stdout.write(callOutput(result, full));
|
|
15798
15865
|
return;
|
|
15799
15866
|
}
|
|
15800
15867
|
if (command === "declarations") {
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type AttemptToolCatalog, type AttemptToolCatalogEntry } from "@opengeni/codemode";
|
|
2
|
+
import { type AttemptToolResult } from "@opengeni/contracts";
|
|
2
3
|
export declare function resolveTool(catalog: AttemptToolCatalog, name: string): AttemptToolCatalogEntry;
|
|
3
4
|
export declare function listProjection(catalog: AttemptToolCatalog): Record<string, unknown>;
|
|
4
5
|
export declare function showOutput(catalog: AttemptToolCatalog, name: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* `call` prints the payload once by default: a text block that only repeats
|
|
8
|
+
* `structuredContent` as JSON is omitted. `--full` prints the exact result.
|
|
9
|
+
* The native client (`codemode call`) applies the same rule.
|
|
10
|
+
*/
|
|
11
|
+
export declare function callOutput(result: AttemptToolResult, full?: boolean): string;
|
|
5
12
|
export declare function parseToolArguments(raw: string | undefined): Record<string, unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/ogtool",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Codemode CLI and typed client entrypoint for an OpenGeni execution attempt.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@opengeni/codemode": "1.
|
|
40
|
+
"@opengeni/codemode": "1.4.0",
|
|
41
|
+
"@opengeni/contracts": "1.4.0"
|
|
41
42
|
},
|
|
42
43
|
"engines": {
|
|
43
44
|
"node": ">=18"
|
package/src/cli.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type AttemptToolCatalog,
|
|
9
9
|
type AttemptToolCatalogEntry,
|
|
10
10
|
} from "@opengeni/codemode";
|
|
11
|
+
import { omitStructuredContentTextDuplicates, type AttemptToolResult } from "@opengeni/contracts";
|
|
11
12
|
import packageManifest from "../package.json" with { type: "json" };
|
|
12
13
|
import { compactOutput, parseListOptions } from "./catalog-discovery";
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ function usage(exitCode = 1): void {
|
|
|
20
21
|
" ogtool list [--full | --json]",
|
|
21
22
|
" [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
|
|
22
23
|
" ogtool show <tool-path-or-model-name>",
|
|
23
|
-
" ogtool call <tool-path-or-model-name> [json-object]",
|
|
24
|
+
" ogtool call <tool-path-or-model-name> [json-object] [--full]",
|
|
24
25
|
" ogtool read <operation-id>",
|
|
25
26
|
" ogtool resume <operation-id>",
|
|
26
27
|
" ogtool declarations [output-file]",
|
|
@@ -28,6 +29,7 @@ function usage(exitCode = 1): void {
|
|
|
28
29
|
" ogtool --version",
|
|
29
30
|
"",
|
|
30
31
|
"list returns all authorized tools by default; --limit/--offset are opt-in slices",
|
|
32
|
+
"call omits a text block that only repeats structuredContent; --full prints the exact result",
|
|
31
33
|
"",
|
|
32
34
|
"requires OPENGENI_CODEMODE_URL and OPENGENI_CODEMODE_TOKEN or OPENGENI_CODEMODE_TOKEN_FILE",
|
|
33
35
|
].join("\n");
|
|
@@ -164,6 +166,16 @@ export function showOutput(catalog: AttemptToolCatalog, name: string): string {
|
|
|
164
166
|
return `${output}\n`;
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
/**
|
|
170
|
+
* `call` prints the payload once by default: a text block that only repeats
|
|
171
|
+
* `structuredContent` as JSON is omitted. `--full` prints the exact result.
|
|
172
|
+
* The native client (`codemode call`) applies the same rule.
|
|
173
|
+
*/
|
|
174
|
+
export function callOutput(result: AttemptToolResult, full = false): string {
|
|
175
|
+
const printed = full ? result : omitStructuredContentTextDuplicates(result);
|
|
176
|
+
return `${JSON.stringify(printed, null, 2)}\n`;
|
|
177
|
+
}
|
|
178
|
+
|
|
167
179
|
export function parseToolArguments(raw: string | undefined): Record<string, unknown> {
|
|
168
180
|
if (raw === undefined) return {};
|
|
169
181
|
let value: unknown;
|
|
@@ -223,15 +235,16 @@ async function main(): Promise<void> {
|
|
|
223
235
|
return;
|
|
224
236
|
}
|
|
225
237
|
if (command === "call") {
|
|
226
|
-
const
|
|
238
|
+
const full = args.includes("--full");
|
|
239
|
+
const [name, rawArguments] = args.filter((arg) => arg !== "--full");
|
|
227
240
|
if (!name) throw new Error("tool path or model name is required");
|
|
228
|
-
const argumentsValue = parseToolArguments(
|
|
241
|
+
const argumentsValue = parseToolArguments(rawArguments);
|
|
229
242
|
const catalog = await client.catalog();
|
|
230
243
|
const entry = resolveTool(catalog, name);
|
|
231
244
|
const result = await client.call(entry.identity, argumentsValue, {
|
|
232
245
|
operationId: randomUUID(),
|
|
233
246
|
});
|
|
234
|
-
process.stdout.write(
|
|
247
|
+
process.stdout.write(callOutput(result, full));
|
|
235
248
|
return;
|
|
236
249
|
}
|
|
237
250
|
if (command === "declarations") {
|