@opengeni/ogtool 1.2.1-canary.37222965366001 → 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 +148 -9
- package/dist/cli.d.ts +7 -0
- package/package.json +3 -2
- package/src/cli.ts +43 -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,
|
|
@@ -14619,6 +14620,7 @@ function requireCompleteSiteToolContext(value, context) {
|
|
|
14619
14620
|
}
|
|
14620
14621
|
var CodemodeOperationState = exports_external.enum([
|
|
14621
14622
|
"queued",
|
|
14623
|
+
"waiting_for_approval",
|
|
14622
14624
|
"running",
|
|
14623
14625
|
"completed",
|
|
14624
14626
|
"failed",
|
|
@@ -14642,6 +14644,8 @@ var CodemodeOperation = exports_external.object({
|
|
|
14642
14644
|
message: "Codemode operation caller must be codemode"
|
|
14643
14645
|
}),
|
|
14644
14646
|
state: CodemodeOperationState,
|
|
14647
|
+
durableApproval: exports_external.literal(true).optional(),
|
|
14648
|
+
approvalRequestId: exports_external.string().uuid().optional(),
|
|
14645
14649
|
result: AttemptToolResult.nullable(),
|
|
14646
14650
|
errorCode: exports_external.string().min(1).max(128).nullable(),
|
|
14647
14651
|
errorMessage: exports_external.string().min(1).max(4096).nullable(),
|
|
@@ -14652,6 +14656,7 @@ var CodemodeOperation = exports_external.object({
|
|
|
14652
14656
|
updatedAt: exports_external.string().datetime({ offset: true })
|
|
14653
14657
|
}).strict();
|
|
14654
14658
|
var CodemodeCallRequest = exports_external.object({
|
|
14659
|
+
durableApproval: exports_external.literal(true).optional(),
|
|
14655
14660
|
operationId: exports_external.string().uuid(),
|
|
14656
14661
|
catalogDigest: sha256,
|
|
14657
14662
|
identity: AttemptToolIdentity,
|
|
@@ -14672,6 +14677,65 @@ var CodemodeDispatchAck = exports_external.object({
|
|
|
14672
14677
|
status: exports_external.enum(["accepted", "already_running", "terminal", "unavailable", "rejected"])
|
|
14673
14678
|
}).strict();
|
|
14674
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
|
+
|
|
14675
14739
|
// ../tool-gateway/src/catalog.ts
|
|
14676
14740
|
var import_node_crypto = require("node:crypto");
|
|
14677
14741
|
|
|
@@ -15089,6 +15153,20 @@ class CodemodeOperationError extends Error {
|
|
|
15089
15153
|
this.operation = operation;
|
|
15090
15154
|
this.code = code;
|
|
15091
15155
|
this.name = "CodemodeOperationError";
|
|
15156
|
+
Object.defineProperty(this, "operation", { value: operation, enumerable: false });
|
|
15157
|
+
}
|
|
15158
|
+
}
|
|
15159
|
+
|
|
15160
|
+
class CodemodeApprovalPendingError extends Error {
|
|
15161
|
+
operationId;
|
|
15162
|
+
approvalRequestId;
|
|
15163
|
+
code = "codemode_approval_pending";
|
|
15164
|
+
state = "waiting_for_approval";
|
|
15165
|
+
constructor(operationId, approvalRequestId) {
|
|
15166
|
+
super(`Operation ${operationId} is waiting for approval. After review, read or resume this handle; do not submit its arguments again.`);
|
|
15167
|
+
this.operationId = operationId;
|
|
15168
|
+
this.approvalRequestId = approvalRequestId;
|
|
15169
|
+
this.name = "CodemodeApprovalPendingError";
|
|
15092
15170
|
}
|
|
15093
15171
|
}
|
|
15094
15172
|
|
|
@@ -15212,6 +15290,9 @@ class CodemodeClient {
|
|
|
15212
15290
|
} else {
|
|
15213
15291
|
operation = await this.read(operationId, options.signal);
|
|
15214
15292
|
}
|
|
15293
|
+
if (operation.state === "waiting_for_approval") {
|
|
15294
|
+
throw new CodemodeApprovalPendingError(operation.operationId, operation.approvalRequestId);
|
|
15295
|
+
}
|
|
15215
15296
|
if (operation.state === "completed") {
|
|
15216
15297
|
return { result: AttemptToolResult.parse(operation.result), entry };
|
|
15217
15298
|
}
|
|
@@ -15258,11 +15339,39 @@ class CodemodeClient {
|
|
|
15258
15339
|
operationId,
|
|
15259
15340
|
catalogDigest,
|
|
15260
15341
|
identity,
|
|
15261
|
-
arguments: argumentsValue
|
|
15342
|
+
arguments: argumentsValue,
|
|
15343
|
+
durableApproval: true
|
|
15262
15344
|
})
|
|
15263
15345
|
});
|
|
15264
15346
|
return CodemodeCallSubmission.parse(await response.json()).operation;
|
|
15265
15347
|
}
|
|
15348
|
+
async status(operationId, signal) {
|
|
15349
|
+
const operation = await this.read(operationId, signal);
|
|
15350
|
+
return {
|
|
15351
|
+
operationId: operation.operationId,
|
|
15352
|
+
state: operation.state,
|
|
15353
|
+
approvalRequestId: operation.approvalRequestId,
|
|
15354
|
+
result: operation.result,
|
|
15355
|
+
errorCode: operation.errorCode,
|
|
15356
|
+
errorMessage: operation.errorMessage
|
|
15357
|
+
};
|
|
15358
|
+
}
|
|
15359
|
+
async resume(operationId, options = {}) {
|
|
15360
|
+
const deadline = Date.now() + boundedPositiveInteger(options.timeoutMs ?? this.timeoutMs, 1000, 60 * 60000);
|
|
15361
|
+
while (true) {
|
|
15362
|
+
throwIfAborted(options.signal);
|
|
15363
|
+
const operation = await this.read(operationId, options.signal);
|
|
15364
|
+
if (operation.state === "waiting_for_approval")
|
|
15365
|
+
throw new CodemodeApprovalPendingError(operation.operationId, operation.approvalRequestId);
|
|
15366
|
+
if (operation.state === "completed")
|
|
15367
|
+
return AttemptToolResult.parse(operation.result);
|
|
15368
|
+
if (["failed", "outcome_unknown", "cancelled"].includes(operation.state))
|
|
15369
|
+
throw new CodemodeOperationError(operation, operation.errorCode ?? `codemode_${operation.state}`);
|
|
15370
|
+
if (Date.now() >= deadline)
|
|
15371
|
+
throw new CodemodeTransportError(`Codemode operation ${operationId} did not settle before the client deadline`);
|
|
15372
|
+
await abortableDelay(this.pollIntervalMs, options.signal);
|
|
15373
|
+
}
|
|
15374
|
+
}
|
|
15266
15375
|
async read(operationId, signal) {
|
|
15267
15376
|
const response = await this.request(`/calls/${operationId}`, {
|
|
15268
15377
|
method: "GET",
|
|
@@ -15280,7 +15389,8 @@ class CodemodeClient {
|
|
|
15280
15389
|
...init,
|
|
15281
15390
|
headers: {
|
|
15282
15391
|
...Object.fromEntries(new Headers(init.headers).entries()),
|
|
15283
|
-
authorization: `Bearer ${token}
|
|
15392
|
+
authorization: `Bearer ${token}`,
|
|
15393
|
+
"x-opengeni-codemode-capabilities": "durable-approval-v1"
|
|
15284
15394
|
}
|
|
15285
15395
|
});
|
|
15286
15396
|
if (!response.ok && throwOnError) {
|
|
@@ -15419,7 +15529,7 @@ async function abortableDelay(delayMs, signal) {
|
|
|
15419
15529
|
// package.json
|
|
15420
15530
|
var package_default = {
|
|
15421
15531
|
name: "@opengeni/ogtool",
|
|
15422
|
-
version: "1.
|
|
15532
|
+
version: "1.4.0",
|
|
15423
15533
|
description: "Codemode CLI and typed client entrypoint for an OpenGeni execution attempt.",
|
|
15424
15534
|
license: "Apache-2.0",
|
|
15425
15535
|
repository: {
|
|
@@ -15456,7 +15566,8 @@ var package_default = {
|
|
|
15456
15566
|
prepublishOnly: "bash ../../scripts/prepublish-guard"
|
|
15457
15567
|
},
|
|
15458
15568
|
dependencies: {
|
|
15459
|
-
"@opengeni/codemode": "workspace:*"
|
|
15569
|
+
"@opengeni/codemode": "workspace:*",
|
|
15570
|
+
"@opengeni/contracts": "workspace:*"
|
|
15460
15571
|
},
|
|
15461
15572
|
devDependencies: {
|
|
15462
15573
|
tsup: "^8.5.0",
|
|
@@ -15548,12 +15659,15 @@ function usage(exitCode = 1) {
|
|
|
15548
15659
|
" ogtool list [--full | --json]",
|
|
15549
15660
|
" [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
|
|
15550
15661
|
" ogtool show <tool-path-or-model-name>",
|
|
15551
|
-
" ogtool call <tool-path-or-model-name> [json-object]",
|
|
15662
|
+
" ogtool call <tool-path-or-model-name> [json-object] [--full]",
|
|
15663
|
+
" ogtool read <operation-id>",
|
|
15664
|
+
" ogtool resume <operation-id>",
|
|
15552
15665
|
" ogtool declarations [output-file]",
|
|
15553
15666
|
" ogtool doctor",
|
|
15554
15667
|
" ogtool --version",
|
|
15555
15668
|
"",
|
|
15556
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",
|
|
15557
15671
|
"",
|
|
15558
15672
|
"requires OPENGENI_CODEMODE_URL and OPENGENI_CODEMODE_TOKEN or OPENGENI_CODEMODE_TOKEN_FILE"
|
|
15559
15673
|
].join(`
|
|
@@ -15674,6 +15788,11 @@ function showOutput(catalog, name) {
|
|
|
15674
15788
|
return `${output}
|
|
15675
15789
|
`;
|
|
15676
15790
|
}
|
|
15791
|
+
function callOutput(result, full = false) {
|
|
15792
|
+
const printed = full ? result : omitStructuredContentTextDuplicates(result);
|
|
15793
|
+
return `${JSON.stringify(printed, null, 2)}
|
|
15794
|
+
`;
|
|
15795
|
+
}
|
|
15677
15796
|
function parseToolArguments(raw) {
|
|
15678
15797
|
if (raw === undefined)
|
|
15679
15798
|
return {};
|
|
@@ -15709,6 +15828,14 @@ async function main() {
|
|
|
15709
15828
|
throw new Error("usage: ogtool show <tool-path-or-model-name>");
|
|
15710
15829
|
}
|
|
15711
15830
|
const client = configuredClient();
|
|
15831
|
+
if (command === "read" || command === "resume") {
|
|
15832
|
+
if (args.length !== 1 || !/^[0-9a-f-]{36}$/iu.test(args[0]))
|
|
15833
|
+
throw new Error("A valid operation ID is required");
|
|
15834
|
+
const result = command === "read" ? await client.status(args[0]) : await client.resume(args[0]);
|
|
15835
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
15836
|
+
`);
|
|
15837
|
+
return;
|
|
15838
|
+
}
|
|
15712
15839
|
if (command === "list") {
|
|
15713
15840
|
const catalog = await client.catalog();
|
|
15714
15841
|
if (listOptions.full) {
|
|
@@ -15724,17 +15851,17 @@ async function main() {
|
|
|
15724
15851
|
return;
|
|
15725
15852
|
}
|
|
15726
15853
|
if (command === "call") {
|
|
15727
|
-
const
|
|
15854
|
+
const full = args.includes("--full");
|
|
15855
|
+
const [name, rawArguments] = args.filter((arg) => arg !== "--full");
|
|
15728
15856
|
if (!name)
|
|
15729
15857
|
throw new Error("tool path or model name is required");
|
|
15730
|
-
const argumentsValue = parseToolArguments(
|
|
15858
|
+
const argumentsValue = parseToolArguments(rawArguments);
|
|
15731
15859
|
const catalog = await client.catalog();
|
|
15732
15860
|
const entry = resolveTool(catalog, name);
|
|
15733
15861
|
const result = await client.call(entry.identity, argumentsValue, {
|
|
15734
15862
|
operationId: import_node_crypto3.randomUUID()
|
|
15735
15863
|
});
|
|
15736
|
-
process.stdout.write(
|
|
15737
|
-
`);
|
|
15864
|
+
process.stdout.write(callOutput(result, full));
|
|
15738
15865
|
return;
|
|
15739
15866
|
}
|
|
15740
15867
|
if (command === "declarations") {
|
|
@@ -15753,6 +15880,18 @@ async function main() {
|
|
|
15753
15880
|
return usage();
|
|
15754
15881
|
}
|
|
15755
15882
|
main().catch((error51) => {
|
|
15883
|
+
if (error51 instanceof CodemodeApprovalPendingError) {
|
|
15884
|
+
process.stdout.write(`${JSON.stringify({ operationId: error51.operationId, state: error51.state, code: error51.code, approvalRequestId: error51.approvalRequestId, message: error51.message })}
|
|
15885
|
+
`);
|
|
15886
|
+
process.exitCode = 2;
|
|
15887
|
+
return;
|
|
15888
|
+
}
|
|
15889
|
+
if (error51 instanceof CodemodeOperationError) {
|
|
15890
|
+
process.stdout.write(`${JSON.stringify({ operationId: error51.operation.operationId, state: error51.operation.state, code: error51.code, message: error51.message })}
|
|
15891
|
+
`);
|
|
15892
|
+
process.exitCode = error51.operation.state === "outcome_unknown" ? 3 : 1;
|
|
15893
|
+
return;
|
|
15894
|
+
}
|
|
15756
15895
|
const code = error51 && typeof error51 === "object" && "code" in error51 ? String(error51.code) : null;
|
|
15757
15896
|
process.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
|
|
15758
15897
|
`);
|
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
|
@@ -2,10 +2,13 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import {
|
|
4
4
|
CodemodeClient,
|
|
5
|
+
CodemodeApprovalPendingError,
|
|
6
|
+
CodemodeOperationError,
|
|
5
7
|
generateCodemodeDeclarations,
|
|
6
8
|
type AttemptToolCatalog,
|
|
7
9
|
type AttemptToolCatalogEntry,
|
|
8
10
|
} from "@opengeni/codemode";
|
|
11
|
+
import { omitStructuredContentTextDuplicates, type AttemptToolResult } from "@opengeni/contracts";
|
|
9
12
|
import packageManifest from "../package.json" with { type: "json" };
|
|
10
13
|
import { compactOutput, parseListOptions } from "./catalog-discovery";
|
|
11
14
|
|
|
@@ -18,12 +21,15 @@ function usage(exitCode = 1): void {
|
|
|
18
21
|
" ogtool list [--full | --json]",
|
|
19
22
|
" [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
|
|
20
23
|
" ogtool show <tool-path-or-model-name>",
|
|
21
|
-
" ogtool call <tool-path-or-model-name> [json-object]",
|
|
24
|
+
" ogtool call <tool-path-or-model-name> [json-object] [--full]",
|
|
25
|
+
" ogtool read <operation-id>",
|
|
26
|
+
" ogtool resume <operation-id>",
|
|
22
27
|
" ogtool declarations [output-file]",
|
|
23
28
|
" ogtool doctor",
|
|
24
29
|
" ogtool --version",
|
|
25
30
|
"",
|
|
26
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",
|
|
27
33
|
"",
|
|
28
34
|
"requires OPENGENI_CODEMODE_URL and OPENGENI_CODEMODE_TOKEN or OPENGENI_CODEMODE_TOKEN_FILE",
|
|
29
35
|
].join("\n");
|
|
@@ -160,6 +166,16 @@ export function showOutput(catalog: AttemptToolCatalog, name: string): string {
|
|
|
160
166
|
return `${output}\n`;
|
|
161
167
|
}
|
|
162
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
|
+
|
|
163
179
|
export function parseToolArguments(raw: string | undefined): Record<string, unknown> {
|
|
164
180
|
if (raw === undefined) return {};
|
|
165
181
|
let value: unknown;
|
|
@@ -197,6 +213,14 @@ async function main(): Promise<void> {
|
|
|
197
213
|
}
|
|
198
214
|
|
|
199
215
|
const client = configuredClient();
|
|
216
|
+
if (command === "read" || command === "resume") {
|
|
217
|
+
if (args.length !== 1 || !/^[0-9a-f-]{36}$/iu.test(args[0]!))
|
|
218
|
+
throw new Error("A valid operation ID is required");
|
|
219
|
+
const result =
|
|
220
|
+
command === "read" ? await client.status(args[0]!) : await client.resume(args[0]!);
|
|
221
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
200
224
|
if (command === "list") {
|
|
201
225
|
const catalog = await client.catalog();
|
|
202
226
|
if (listOptions!.full) {
|
|
@@ -211,15 +235,16 @@ async function main(): Promise<void> {
|
|
|
211
235
|
return;
|
|
212
236
|
}
|
|
213
237
|
if (command === "call") {
|
|
214
|
-
const
|
|
238
|
+
const full = args.includes("--full");
|
|
239
|
+
const [name, rawArguments] = args.filter((arg) => arg !== "--full");
|
|
215
240
|
if (!name) throw new Error("tool path or model name is required");
|
|
216
|
-
const argumentsValue = parseToolArguments(
|
|
241
|
+
const argumentsValue = parseToolArguments(rawArguments);
|
|
217
242
|
const catalog = await client.catalog();
|
|
218
243
|
const entry = resolveTool(catalog, name);
|
|
219
244
|
const result = await client.call(entry.identity, argumentsValue, {
|
|
220
245
|
operationId: randomUUID(),
|
|
221
246
|
});
|
|
222
|
-
process.stdout.write(
|
|
247
|
+
process.stdout.write(callOutput(result, full));
|
|
223
248
|
return;
|
|
224
249
|
}
|
|
225
250
|
if (command === "declarations") {
|
|
@@ -240,6 +265,20 @@ async function main(): Promise<void> {
|
|
|
240
265
|
}
|
|
241
266
|
|
|
242
267
|
void main().catch((error: unknown) => {
|
|
268
|
+
if (error instanceof CodemodeApprovalPendingError) {
|
|
269
|
+
process.stdout.write(
|
|
270
|
+
`${JSON.stringify({ operationId: error.operationId, state: error.state, code: error.code, approvalRequestId: error.approvalRequestId, message: error.message })}\n`,
|
|
271
|
+
);
|
|
272
|
+
process.exitCode = 2;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (error instanceof CodemodeOperationError) {
|
|
276
|
+
process.stdout.write(
|
|
277
|
+
`${JSON.stringify({ operationId: error.operation.operationId, state: error.operation.state, code: error.code, message: error.message })}\n`,
|
|
278
|
+
);
|
|
279
|
+
process.exitCode = error.operation.state === "outcome_unknown" ? 3 : 1;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
243
282
|
const code =
|
|
244
283
|
error && typeof error === "object" && "code" in error
|
|
245
284
|
? String((error as { code: unknown }).code)
|