@opengeni/ogtool 1.2.1-canary.37222965366001 → 1.3.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.
@@ -14619,6 +14619,7 @@ function requireCompleteSiteToolContext(value, context) {
14619
14619
  }
14620
14620
  var CodemodeOperationState = exports_external.enum([
14621
14621
  "queued",
14622
+ "waiting_for_approval",
14622
14623
  "running",
14623
14624
  "completed",
14624
14625
  "failed",
@@ -14642,6 +14643,8 @@ var CodemodeOperation = exports_external.object({
14642
14643
  message: "Codemode operation caller must be codemode"
14643
14644
  }),
14644
14645
  state: CodemodeOperationState,
14646
+ durableApproval: exports_external.literal(true).optional(),
14647
+ approvalRequestId: exports_external.string().uuid().optional(),
14645
14648
  result: AttemptToolResult.nullable(),
14646
14649
  errorCode: exports_external.string().min(1).max(128).nullable(),
14647
14650
  errorMessage: exports_external.string().min(1).max(4096).nullable(),
@@ -14652,6 +14655,7 @@ var CodemodeOperation = exports_external.object({
14652
14655
  updatedAt: exports_external.string().datetime({ offset: true })
14653
14656
  }).strict();
14654
14657
  var CodemodeCallRequest = exports_external.object({
14658
+ durableApproval: exports_external.literal(true).optional(),
14655
14659
  operationId: exports_external.string().uuid(),
14656
14660
  catalogDigest: sha256,
14657
14661
  identity: AttemptToolIdentity,
@@ -15089,6 +15093,20 @@ class CodemodeOperationError extends Error {
15089
15093
  this.operation = operation;
15090
15094
  this.code = code;
15091
15095
  this.name = "CodemodeOperationError";
15096
+ Object.defineProperty(this, "operation", { value: operation, enumerable: false });
15097
+ }
15098
+ }
15099
+
15100
+ class CodemodeApprovalPendingError extends Error {
15101
+ operationId;
15102
+ approvalRequestId;
15103
+ code = "codemode_approval_pending";
15104
+ state = "waiting_for_approval";
15105
+ constructor(operationId, approvalRequestId) {
15106
+ super(`Operation ${operationId} is waiting for approval. After review, read or resume this handle; do not submit its arguments again.`);
15107
+ this.operationId = operationId;
15108
+ this.approvalRequestId = approvalRequestId;
15109
+ this.name = "CodemodeApprovalPendingError";
15092
15110
  }
15093
15111
  }
15094
15112
 
@@ -15212,6 +15230,9 @@ class CodemodeClient {
15212
15230
  } else {
15213
15231
  operation = await this.read(operationId, options.signal);
15214
15232
  }
15233
+ if (operation.state === "waiting_for_approval") {
15234
+ throw new CodemodeApprovalPendingError(operation.operationId, operation.approvalRequestId);
15235
+ }
15215
15236
  if (operation.state === "completed") {
15216
15237
  return { result: AttemptToolResult.parse(operation.result), entry };
15217
15238
  }
@@ -15258,11 +15279,39 @@ class CodemodeClient {
15258
15279
  operationId,
15259
15280
  catalogDigest,
15260
15281
  identity,
15261
- arguments: argumentsValue
15282
+ arguments: argumentsValue,
15283
+ durableApproval: true
15262
15284
  })
15263
15285
  });
15264
15286
  return CodemodeCallSubmission.parse(await response.json()).operation;
15265
15287
  }
15288
+ async status(operationId, signal) {
15289
+ const operation = await this.read(operationId, signal);
15290
+ return {
15291
+ operationId: operation.operationId,
15292
+ state: operation.state,
15293
+ approvalRequestId: operation.approvalRequestId,
15294
+ result: operation.result,
15295
+ errorCode: operation.errorCode,
15296
+ errorMessage: operation.errorMessage
15297
+ };
15298
+ }
15299
+ async resume(operationId, options = {}) {
15300
+ const deadline = Date.now() + boundedPositiveInteger(options.timeoutMs ?? this.timeoutMs, 1000, 60 * 60000);
15301
+ while (true) {
15302
+ throwIfAborted(options.signal);
15303
+ const operation = await this.read(operationId, options.signal);
15304
+ if (operation.state === "waiting_for_approval")
15305
+ throw new CodemodeApprovalPendingError(operation.operationId, operation.approvalRequestId);
15306
+ if (operation.state === "completed")
15307
+ return AttemptToolResult.parse(operation.result);
15308
+ if (["failed", "outcome_unknown", "cancelled"].includes(operation.state))
15309
+ throw new CodemodeOperationError(operation, operation.errorCode ?? `codemode_${operation.state}`);
15310
+ if (Date.now() >= deadline)
15311
+ throw new CodemodeTransportError(`Codemode operation ${operationId} did not settle before the client deadline`);
15312
+ await abortableDelay(this.pollIntervalMs, options.signal);
15313
+ }
15314
+ }
15266
15315
  async read(operationId, signal) {
15267
15316
  const response = await this.request(`/calls/${operationId}`, {
15268
15317
  method: "GET",
@@ -15280,7 +15329,8 @@ class CodemodeClient {
15280
15329
  ...init,
15281
15330
  headers: {
15282
15331
  ...Object.fromEntries(new Headers(init.headers).entries()),
15283
- authorization: `Bearer ${token}`
15332
+ authorization: `Bearer ${token}`,
15333
+ "x-opengeni-codemode-capabilities": "durable-approval-v1"
15284
15334
  }
15285
15335
  });
15286
15336
  if (!response.ok && throwOnError) {
@@ -15419,7 +15469,7 @@ async function abortableDelay(delayMs, signal) {
15419
15469
  // package.json
15420
15470
  var package_default = {
15421
15471
  name: "@opengeni/ogtool",
15422
- version: "1.2.1-canary.37222965366001",
15472
+ version: "1.3.0",
15423
15473
  description: "Codemode CLI and typed client entrypoint for an OpenGeni execution attempt.",
15424
15474
  license: "Apache-2.0",
15425
15475
  repository: {
@@ -15549,6 +15599,8 @@ function usage(exitCode = 1) {
15549
15599
  " [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
15550
15600
  " ogtool show <tool-path-or-model-name>",
15551
15601
  " ogtool call <tool-path-or-model-name> [json-object]",
15602
+ " ogtool read <operation-id>",
15603
+ " ogtool resume <operation-id>",
15552
15604
  " ogtool declarations [output-file]",
15553
15605
  " ogtool doctor",
15554
15606
  " ogtool --version",
@@ -15709,6 +15761,14 @@ async function main() {
15709
15761
  throw new Error("usage: ogtool show <tool-path-or-model-name>");
15710
15762
  }
15711
15763
  const client = configuredClient();
15764
+ if (command === "read" || command === "resume") {
15765
+ if (args.length !== 1 || !/^[0-9a-f-]{36}$/iu.test(args[0]))
15766
+ throw new Error("A valid operation ID is required");
15767
+ const result = command === "read" ? await client.status(args[0]) : await client.resume(args[0]);
15768
+ process.stdout.write(`${JSON.stringify(result, null, 2)}
15769
+ `);
15770
+ return;
15771
+ }
15712
15772
  if (command === "list") {
15713
15773
  const catalog = await client.catalog();
15714
15774
  if (listOptions.full) {
@@ -15753,6 +15813,18 @@ async function main() {
15753
15813
  return usage();
15754
15814
  }
15755
15815
  main().catch((error51) => {
15816
+ if (error51 instanceof CodemodeApprovalPendingError) {
15817
+ process.stdout.write(`${JSON.stringify({ operationId: error51.operationId, state: error51.state, code: error51.code, approvalRequestId: error51.approvalRequestId, message: error51.message })}
15818
+ `);
15819
+ process.exitCode = 2;
15820
+ return;
15821
+ }
15822
+ if (error51 instanceof CodemodeOperationError) {
15823
+ process.stdout.write(`${JSON.stringify({ operationId: error51.operation.operationId, state: error51.operation.state, code: error51.code, message: error51.message })}
15824
+ `);
15825
+ process.exitCode = error51.operation.state === "outcome_unknown" ? 3 : 1;
15826
+ return;
15827
+ }
15756
15828
  const code = error51 && typeof error51 === "object" && "code" in error51 ? String(error51.code) : null;
15757
15829
  process.stderr.write(`${error51 instanceof Error ? error51.message : String(error51)}
15758
15830
  `);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/ogtool",
3
- "version": "1.2.1-canary.37222965366001",
3
+ "version": "1.3.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,7 @@
37
37
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
38
38
  },
39
39
  "dependencies": {
40
- "@opengeni/codemode": "1.2.1-canary.37222965366001"
40
+ "@opengeni/codemode": "1.3.0"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18"
package/src/cli.ts CHANGED
@@ -2,6 +2,8 @@ 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,
@@ -19,6 +21,8 @@ function usage(exitCode = 1): void {
19
21
  " [--query <substring>] [--limit <1..100>] [--offset <nonnegative integer>]",
20
22
  " ogtool show <tool-path-or-model-name>",
21
23
  " ogtool call <tool-path-or-model-name> [json-object]",
24
+ " ogtool read <operation-id>",
25
+ " ogtool resume <operation-id>",
22
26
  " ogtool declarations [output-file]",
23
27
  " ogtool doctor",
24
28
  " ogtool --version",
@@ -197,6 +201,14 @@ async function main(): Promise<void> {
197
201
  }
198
202
 
199
203
  const client = configuredClient();
204
+ if (command === "read" || command === "resume") {
205
+ if (args.length !== 1 || !/^[0-9a-f-]{36}$/iu.test(args[0]!))
206
+ throw new Error("A valid operation ID is required");
207
+ const result =
208
+ command === "read" ? await client.status(args[0]!) : await client.resume(args[0]!);
209
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
210
+ return;
211
+ }
200
212
  if (command === "list") {
201
213
  const catalog = await client.catalog();
202
214
  if (listOptions!.full) {
@@ -240,6 +252,20 @@ async function main(): Promise<void> {
240
252
  }
241
253
 
242
254
  void main().catch((error: unknown) => {
255
+ if (error instanceof CodemodeApprovalPendingError) {
256
+ process.stdout.write(
257
+ `${JSON.stringify({ operationId: error.operationId, state: error.state, code: error.code, approvalRequestId: error.approvalRequestId, message: error.message })}\n`,
258
+ );
259
+ process.exitCode = 2;
260
+ return;
261
+ }
262
+ if (error instanceof CodemodeOperationError) {
263
+ process.stdout.write(
264
+ `${JSON.stringify({ operationId: error.operation.operationId, state: error.operation.state, code: error.code, message: error.message })}\n`,
265
+ );
266
+ process.exitCode = error.operation.state === "outcome_unknown" ? 3 : 1;
267
+ return;
268
+ }
243
269
  const code =
244
270
  error && typeof error === "object" && "code" in error
245
271
  ? String((error as { code: unknown }).code)