@ogment-ai/cli 0.9.1-next.2 → 0.10.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/dist/cli.js CHANGED
@@ -7998,26 +7998,26 @@ const toJsonValue = (value) => {
7998
7998
  //#region src/shared/recovery.ts
7999
7999
  const defaultRecoveryByCode = {
8000
8000
  [ERROR_CODE.authDeviceExpired]: {
8001
- command: "ogment auth login",
8002
- reason: "Device code expired; restart login to continue.",
8001
+ command: "ogment login",
8002
+ reason: "Login request expired; start login again to continue.",
8003
8003
  title: "Restart login",
8004
8004
  when: "immediate"
8005
8005
  },
8006
8006
  [ERROR_CODE.authDevicePending]: {
8007
- command: "ogment auth status",
8008
- reason: "Authorization is pending; check whether credentials are now available.",
8009
- title: "Check auth status",
8007
+ command: "ogment login",
8008
+ reason: "Authorization is pending; run login again after approving in the browser.",
8009
+ title: "Complete login",
8010
8010
  when: "immediate"
8011
8011
  },
8012
8012
  [ERROR_CODE.authInvalidCredentials]: {
8013
- command: "ogment auth logout",
8014
- reason: "Credentials are invalid; clear local state before re-authenticating.",
8015
- title: "Reset auth state",
8013
+ command: "ogment login",
8014
+ reason: "Credentials are invalid; sign in again to restore the local CLI session.",
8015
+ title: "Sign in again",
8016
8016
  when: "immediate"
8017
8017
  },
8018
8018
  [ERROR_CODE.authRequired]: {
8019
- command: "ogment auth login",
8020
- reason: "Authentication is required before catalog, search, or execute commands can run.",
8019
+ command: "ogment login",
8020
+ reason: "Authentication is required before catalog or invoke commands can run.",
8021
8021
  title: "Authenticate",
8022
8022
  when: "immediate"
8023
8023
  },
@@ -8053,14 +8053,14 @@ const defaultRecoveryByCode = {
8053
8053
  },
8054
8054
  [ERROR_CODE.toolInputSchemaViolation]: {
8055
8055
  command: "ogment catalog",
8056
- reason: "Tool contract did not validate; inspect available servers before retrying search or execute.",
8056
+ reason: "Tool contract did not validate; inspect available servers and tool metadata.",
8057
8057
  title: "Inspect catalog",
8058
8058
  when: "immediate"
8059
8059
  },
8060
8060
  [ERROR_CODE.toolNotFound]: {
8061
8061
  command: "ogment catalog",
8062
- reason: "Requested server or tool context could not be found; rediscover available servers.",
8063
- title: "Rediscover servers",
8062
+ reason: "Requested tool could not be found; rediscover servers and tools.",
8063
+ title: "Rediscover tools",
8064
8064
  when: "immediate"
8065
8065
  },
8066
8066
  [ERROR_CODE.transportRequestFailed]: {
@@ -8363,40 +8363,59 @@ const parseJsonValue = (raw, context) => {
8363
8363
  }
8364
8364
  });
8365
8365
  };
8366
- const isRecord$1 = (value) => {
8366
+ const isRecord$2 = (value) => {
8367
8367
  return typeof value === "object" && value !== null;
8368
8368
  };
8369
8369
 
8370
- //#endregion
8371
- //#region src/shared/schemas.ts
8372
- const credentialsFileSchema = object({
8373
- agentName: string().optional(),
8374
- apiKey: string().min(1).optional()
8375
- });
8376
-
8377
8370
  //#endregion
8378
8371
  //#region src/infra/credentials.ts
8379
8372
  const authStateFileSchema = object({
8373
+ currentAuthRequest: object({
8374
+ authRequestId: string().min(1),
8375
+ expiresAt: string().min(1),
8376
+ verificationUrl: string().min(1)
8377
+ }).nullable().optional(),
8378
+ installationId: uuid(),
8379
+ session: object({
8380
+ agentId: uuid(),
8381
+ agentName: string().min(1),
8382
+ apiKey: string().min(1),
8383
+ credentialId: uuid(),
8384
+ signedInAt: string().min(1)
8385
+ }).nullable().optional(),
8386
+ version: literal(3)
8387
+ }).strict();
8388
+ const authStateFileV2Schema = object({
8389
+ installationId: uuid(),
8390
+ pendingAuthRequest: object({
8391
+ authRequestId: string().min(1),
8392
+ expiresAt: string().min(1),
8393
+ verificationUrl: string().min(1)
8394
+ }).nullable().optional(),
8395
+ session: object({
8396
+ agentId: uuid(),
8397
+ agentName: string().min(1),
8398
+ apiKey: string().min(1),
8399
+ credentialId: uuid(),
8400
+ signedInAt: string().min(1)
8401
+ }).nullable().optional(),
8402
+ version: literal(2)
8403
+ }).strict();
8404
+ const legacyAuthStateFileSchema = object({
8380
8405
  activeAuth: object({
8381
8406
  agentName: string().optional(),
8382
8407
  apiKey: string().min(1),
8383
- boundAt: string().optional(),
8384
- namespaceKey: string().min(1).optional(),
8385
- scopeFingerprint: string().min(1).optional()
8408
+ boundAt: string().optional()
8386
8409
  }).nullable().optional(),
8387
8410
  installationId: uuid(),
8388
8411
  pendingRequests: array(object({
8389
8412
  authRequestId: string().min(1),
8390
- code: string().min(1),
8391
8413
  createdAt: string().min(1),
8392
8414
  expiresAt: string().min(1),
8393
- namespaceKey: string().min(1),
8394
- scopeFingerprint: string().min(1).optional(),
8395
8415
  verificationUrl: string().min(1)
8396
8416
  })).optional(),
8397
8417
  version: literal(1)
8398
8418
  }).strict();
8399
- const telemetryInstallationSchema = object({ installationId: uuid() }).strict();
8400
8419
  const LOCK_RETRY_DELAY_MS = 10;
8401
8420
  const LOCK_STALE_MS = 3e4;
8402
8421
  const LOCK_TIMEOUT_MS = 2e3;
@@ -8405,40 +8424,42 @@ const sleepBlocking = (milliseconds) => {
8405
8424
  const view = new Int32Array(buffer);
8406
8425
  Atomics.wait(view, 0, 0, milliseconds);
8407
8426
  };
8408
- const normalizeCredentials = (value) => {
8409
- const parsed = parseWithSchema(credentialsFileSchema, value, "legacy credentials file");
8410
- if (Result.isError(parsed) || parsed.value.apiKey === void 0) return null;
8411
- return {
8412
- ...parsed.value.agentName === void 0 ? {} : { agentName: parsed.value.agentName },
8413
- apiKey: parsed.value.apiKey
8414
- };
8415
- };
8416
8427
  const normalizeAuthState = (value) => {
8417
- const parsed = parseWithSchema(authStateFileSchema, value, "auth state file");
8418
- if (Result.isError(parsed)) return null;
8419
- const activeAuth = parsed.value.activeAuth === void 0 || parsed.value.activeAuth === null ? null : {
8420
- ...parsed.value.activeAuth.agentName === void 0 ? {} : { agentName: parsed.value.activeAuth.agentName },
8421
- apiKey: parsed.value.activeAuth.apiKey,
8422
- ...parsed.value.activeAuth.boundAt === void 0 ? {} : { boundAt: parsed.value.activeAuth.boundAt },
8423
- ...parsed.value.activeAuth.namespaceKey === void 0 ? {} : { namespaceKey: parsed.value.activeAuth.namespaceKey },
8424
- ...parsed.value.activeAuth.scopeFingerprint === void 0 ? {} : { scopeFingerprint: parsed.value.activeAuth.scopeFingerprint }
8425
- };
8426
- const pendingRequests = (parsed.value.pendingRequests ?? []).map((request) => {
8427
- return {
8428
- authRequestId: request.authRequestId,
8429
- code: request.code,
8430
- createdAt: request.createdAt,
8431
- expiresAt: request.expiresAt,
8432
- namespaceKey: request.namespaceKey,
8433
- ...request.scopeFingerprint === void 0 ? {} : { scopeFingerprint: request.scopeFingerprint },
8434
- verificationUrl: request.verificationUrl
8435
- };
8436
- });
8428
+ const parsedCurrentState = parseWithSchema(authStateFileSchema, value, "auth state file");
8429
+ if (Result.isOk(parsedCurrentState)) return {
8430
+ needsMigration: false,
8431
+ state: {
8432
+ currentAuthRequest: parsedCurrentState.value.currentAuthRequest ?? null,
8433
+ installationId: parsedCurrentState.value.installationId,
8434
+ session: parsedCurrentState.value.session ?? null,
8435
+ version: 3
8436
+ }
8437
+ };
8438
+ const parsedLegacyV2State = parseWithSchema(authStateFileV2Schema, value, "auth state v2 file");
8439
+ if (Result.isOk(parsedLegacyV2State)) return {
8440
+ needsMigration: true,
8441
+ state: {
8442
+ currentAuthRequest: parsedLegacyV2State.value.pendingAuthRequest ?? null,
8443
+ installationId: parsedLegacyV2State.value.installationId,
8444
+ session: parsedLegacyV2State.value.session ?? null,
8445
+ version: 3
8446
+ }
8447
+ };
8448
+ const parsedV1 = parseWithSchema(legacyAuthStateFileSchema, value, "legacy auth state file");
8449
+ if (Result.isError(parsedV1)) return null;
8450
+ const latestPendingRequest = (parsedV1.value.pendingRequests ?? []).at(-1);
8437
8451
  return {
8438
- activeAuth,
8439
- installationId: parsed.value.installationId,
8440
- pendingRequests,
8441
- version: 1
8452
+ needsMigration: true,
8453
+ state: {
8454
+ currentAuthRequest: latestPendingRequest === void 0 ? null : {
8455
+ authRequestId: latestPendingRequest.authRequestId,
8456
+ expiresAt: latestPendingRequest.expiresAt,
8457
+ verificationUrl: latestPendingRequest.verificationUrl
8458
+ },
8459
+ installationId: parsedV1.value.installationId,
8460
+ session: null,
8461
+ version: 3
8462
+ }
8442
8463
  };
8443
8464
  };
8444
8465
  const toCorruptPath = (path, nowFn) => {
@@ -8473,29 +8494,12 @@ const createFileCredentialsStore = (deps) => {
8473
8494
  const unlinkSyncFn = deps.unlinkSyncFn ?? unlinkSync;
8474
8495
  const writeFileSyncFn = deps.writeFileSyncFn ?? writeFileSync;
8475
8496
  const lockPath = `${deps.credentialsPath}.lock`;
8476
- const readJsonFile = (path) => {
8477
- if (!existsSyncFn(path)) return null;
8478
- try {
8479
- return JSON.parse(readFileSyncFn(path, "utf8"));
8480
- } catch {
8481
- return null;
8482
- }
8483
- };
8484
- const readLegacyCredentials = () => {
8485
- return normalizeCredentials(readJsonFile(deps.legacyCredentialsPath));
8486
- };
8487
- const readLegacyInstallationId = () => {
8488
- const raw = readJsonFile(deps.telemetryPath);
8489
- if (raw === null) return null;
8490
- const parsed = telemetryInstallationSchema.safeParse(raw);
8491
- return parsed.success ? parsed.data.installationId : null;
8492
- };
8493
8497
  const createEmptyState = (installationId = randomUuidFn()) => {
8494
8498
  return {
8495
- activeAuth: null,
8499
+ currentAuthRequest: null,
8496
8500
  installationId,
8497
- pendingRequests: [],
8498
- version: 1
8501
+ session: null,
8502
+ version: 3
8499
8503
  };
8500
8504
  };
8501
8505
  const withLock = (operation) => {
@@ -8588,43 +8592,33 @@ const createFileCredentialsStore = (deps) => {
8588
8592
  }
8589
8593
  throw error;
8590
8594
  }
8591
- const parsed = normalizeAuthState(parsedJson);
8592
- if (parsed === null) {
8595
+ const normalized = normalizeAuthState(parsedJson);
8596
+ if (normalized === null) {
8593
8597
  quarantineCorruptState();
8594
8598
  return null;
8595
8599
  }
8596
- return parsed;
8597
- };
8598
- const migrateStateFromLegacy = () => {
8599
- const migratedInstallationId = readLegacyInstallationId();
8600
- const migratedCredentials = readLegacyCredentials();
8601
- if (!(migratedInstallationId !== null || migratedCredentials !== null)) return null;
8602
- return {
8603
- ...createEmptyState(migratedInstallationId ?? randomUuidFn()),
8604
- ...migratedCredentials === null ? {} : { activeAuth: migratedCredentials }
8605
- };
8600
+ return normalized;
8606
8601
  };
8607
8602
  const loadState = (options) => {
8608
8603
  const currentState = loadStateFromDisk();
8609
- if (currentState !== null) return currentState;
8610
- const migratedState = migrateStateFromLegacy();
8611
- if (migratedState !== null) {
8612
- withLock(() => {
8613
- if (!existsSyncFn(deps.credentialsPath)) writeState(migratedState);
8604
+ if (currentState !== null) {
8605
+ if (currentState.needsMigration) withLock(() => {
8606
+ const latest = loadStateFromDisk();
8607
+ if (latest?.needsMigration) writeState(latest.state);
8614
8608
  });
8615
- return loadStateFromDisk() ?? migratedState;
8609
+ return currentState.state;
8616
8610
  }
8617
8611
  if (options?.persistIfMissing === true) {
8618
8612
  const emptyState = createEmptyState();
8619
8613
  withLock(() => {
8620
8614
  if (!existsSyncFn(deps.credentialsPath)) writeState(emptyState);
8621
8615
  });
8622
- return loadStateFromDisk() ?? emptyState;
8616
+ return loadStateFromDisk()?.state ?? emptyState;
8623
8617
  }
8624
8618
  return null;
8625
8619
  };
8626
8620
  return {
8627
- clearPendingRequests: (namespaceKey) => {
8621
+ clearCurrentAuthRequest: () => {
8628
8622
  return Result.try({
8629
8623
  catch: (cause) => new UnexpectedError({
8630
8624
  cause,
@@ -8632,10 +8626,9 @@ const createFileCredentialsStore = (deps) => {
8632
8626
  }),
8633
8627
  try: () => {
8634
8628
  withLock(() => {
8635
- const latest = loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState();
8636
8629
  writeState({
8637
- ...latest,
8638
- pendingRequests: namespaceKey === void 0 ? [] : latest.pendingRequests.filter((request) => request.namespaceKey !== namespaceKey)
8630
+ ...loadStateFromDisk()?.state ?? createEmptyState(),
8631
+ currentAuthRequest: null
8639
8632
  });
8640
8633
  });
8641
8634
  }
@@ -8650,27 +8643,22 @@ const createFileCredentialsStore = (deps) => {
8650
8643
  try: () => {
8651
8644
  withLock(() => {
8652
8645
  writeState({
8653
- ...loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState(),
8654
- activeAuth: null,
8655
- pendingRequests: []
8646
+ ...loadStateFromDisk()?.state ?? createEmptyState(),
8647
+ session: null
8656
8648
  });
8657
8649
  });
8658
8650
  }
8659
8651
  });
8660
8652
  },
8661
- deletePendingRequest: (authRequestId) => {
8653
+ reset: () => {
8662
8654
  return Result.try({
8663
8655
  catch: (cause) => new UnexpectedError({
8664
8656
  cause,
8665
- message: "Failed to update local auth state"
8657
+ message: "Failed to reset local auth state"
8666
8658
  }),
8667
8659
  try: () => {
8668
8660
  withLock(() => {
8669
- const latest = loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState();
8670
- writeState({
8671
- ...latest,
8672
- pendingRequests: latest.pendingRequests.filter((request) => request.authRequestId !== authRequestId)
8673
- });
8661
+ writeState(createEmptyState());
8674
8662
  });
8675
8663
  }
8676
8664
  });
@@ -8688,14 +8676,14 @@ const createFileCredentialsStore = (deps) => {
8688
8676
  }
8689
8677
  });
8690
8678
  },
8691
- listPendingRequests: () => {
8679
+ getCurrentAuthRequest: () => {
8692
8680
  return Result.try({
8693
8681
  catch: (cause) => new UnexpectedError({
8694
8682
  cause,
8695
8683
  message: "Failed to load local auth state"
8696
8684
  }),
8697
8685
  try: () => {
8698
- return loadState()?.pendingRequests ?? [];
8686
+ return loadState()?.currentAuthRequest ?? null;
8699
8687
  }
8700
8688
  });
8701
8689
  },
@@ -8706,12 +8694,7 @@ const createFileCredentialsStore = (deps) => {
8706
8694
  message: "Failed to load local auth state"
8707
8695
  }),
8708
8696
  try: () => {
8709
- const state = loadState();
8710
- if (state?.activeAuth === null || state === null) return null;
8711
- return {
8712
- ...state.activeAuth.agentName === void 0 ? {} : { agentName: state.activeAuth.agentName },
8713
- apiKey: state.activeAuth.apiKey
8714
- };
8697
+ return loadState()?.session ?? null;
8715
8698
  }
8716
8699
  });
8717
8700
  },
@@ -8724,40 +8707,15 @@ const createFileCredentialsStore = (deps) => {
8724
8707
  try: () => {
8725
8708
  withLock(() => {
8726
8709
  writeState({
8727
- ...loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState(),
8728
- activeAuth: {
8729
- ...credentials.agentName === void 0 ? {} : { agentName: credentials.agentName },
8730
- apiKey: credentials.apiKey
8731
- }
8732
- });
8733
- });
8734
- }
8735
- });
8736
- },
8737
- storeApprovedAuth: (credentials, namespaceKey) => {
8738
- return Result.try({
8739
- catch: (cause) => new UnexpectedError({
8740
- cause,
8741
- message: "Failed to update local auth state"
8742
- }),
8743
- try: () => {
8744
- withLock(() => {
8745
- const currentState = loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState();
8746
- writeState({
8747
- ...currentState,
8748
- activeAuth: {
8749
- ...credentials.agentName === void 0 ? {} : { agentName: credentials.agentName },
8750
- apiKey: credentials.apiKey,
8751
- boundAt: nowFn().toISOString(),
8752
- ...namespaceKey === void 0 ? {} : { namespaceKey }
8753
- },
8754
- pendingRequests: namespaceKey === void 0 ? [] : currentState.pendingRequests.filter((request) => request.namespaceKey !== namespaceKey)
8710
+ ...loadStateFromDisk()?.state ?? createEmptyState(),
8711
+ currentAuthRequest: null,
8712
+ session: credentials
8755
8713
  });
8756
8714
  });
8757
8715
  }
8758
8716
  });
8759
8717
  },
8760
- savePendingRequest: (request) => {
8718
+ saveCurrentAuthRequest: (request) => {
8761
8719
  return Result.try({
8762
8720
  catch: (cause) => new UnexpectedError({
8763
8721
  cause,
@@ -8765,20 +8723,13 @@ const createFileCredentialsStore = (deps) => {
8765
8723
  }),
8766
8724
  try: () => {
8767
8725
  withLock(() => {
8768
- const currentState = loadStateFromDisk() ?? migrateStateFromLegacy() ?? createEmptyState();
8769
- const pendingRequests = currentState.pendingRequests.filter((entry) => entry.authRequestId !== request.authRequestId);
8770
- pendingRequests.push({
8771
- authRequestId: request.authRequestId,
8772
- code: request.code,
8773
- createdAt: request.createdAt,
8774
- expiresAt: request.expiresAt,
8775
- namespaceKey: request.namespaceKey,
8776
- ...request.scopeFingerprint === void 0 ? {} : { scopeFingerprint: request.scopeFingerprint },
8777
- verificationUrl: request.verificationUrl
8778
- });
8779
8726
  writeState({
8780
- ...currentState,
8781
- pendingRequests
8727
+ ...loadStateFromDisk()?.state ?? createEmptyState(),
8728
+ currentAuthRequest: {
8729
+ authRequestId: request.authRequestId,
8730
+ expiresAt: request.expiresAt,
8731
+ verificationUrl: request.verificationUrl
8732
+ }
8782
8733
  });
8783
8734
  });
8784
8735
  }
@@ -8798,9 +8749,9 @@ const DEFAULT_OGMENT_BASE_URL = "https://dashboard.ogment.ai";
8798
8749
  * These are injected by Rolldown `transform.define` during release builds.
8799
8750
  * Runtime env vars (`OGMENT_CLI_SENTRY_*`) can still override them.
8800
8751
  */
8801
- const SENTRY_DSN_BUILD = void 0;
8802
- const SENTRY_ENVIRONMENT_BUILD = void 0;
8803
- const SENTRY_RELEASE_BUILD = void 0;
8752
+ const SENTRY_DSN_BUILD = "https://4219ab98670b61086758b4d0e31ae318@o4507724844957696.ingest.us.sentry.io/4510992932405248";
8753
+ const SENTRY_ENVIRONMENT_BUILD = "production";
8754
+ const SENTRY_RELEASE_BUILD = "cli-v0.10.0+git:4ebe33ce3";
8804
8755
  const packageJsonSchema = object({ version: string().min(1) });
8805
8756
  const hasCode = (value, code) => {
8806
8757
  if (typeof value !== "object" || value === null) return false;
@@ -8859,14 +8810,17 @@ const telemetryRuntimeFields = (env, configDir) => {
8859
8810
  credentialsPath: join(configDir, "auth-state.json"),
8860
8811
  envApiKey: env["OGMENT_API_KEY"],
8861
8812
  executionEnvironment: detectExecutionEnvironment(env),
8862
- legacyCredentialsPath: join(configDir, "credentials.json"),
8863
8813
  telemetryDisabled: telemetryDisabledFromEnv(env),
8864
- telemetryPath: join(configDir, "telemetry.json"),
8865
8814
  version: VERSION$2
8866
8815
  };
8867
8816
  };
8817
+ const resolveConfigDir = (env, homeDirectory) => {
8818
+ const configuredDir = env["OGMENT_CONFIG_DIR"]?.trim();
8819
+ if (configuredDir && configuredDir.length > 0) return configuredDir;
8820
+ return join(homeDirectory, ".config", "ogment");
8821
+ };
8868
8822
  const createRuntimeConfig = (env = process.env, homeDirectory = homedir()) => {
8869
- const configDir = join(homeDirectory, ".config", "ogment");
8823
+ const configDir = resolveConfigDir(env, homeDirectory);
8870
8824
  const envBaseUrl = env["OGMENT_BASE_URL"];
8871
8825
  const hasBaseUrlOverride = typeof envBaseUrl === "string";
8872
8826
  return {
@@ -8884,7 +8838,7 @@ const createRuntimeConfig = (env = process.env, homeDirectory = homedir()) => {
8884
8838
  };
8885
8839
  };
8886
8840
  const createTelemetryRuntimeConfig = (env = process.env, homeDirectory = homedir()) => {
8887
- const configDir = join(homeDirectory, ".config", "ogment");
8841
+ const configDir = resolveConfigDir(env, homeDirectory);
8888
8842
  const parsedBaseUrl = baseUrlSchema.safeParse(env["OGMENT_BASE_URL"]);
8889
8843
  return {
8890
8844
  baseUrl: parsedBaseUrl.success ? parsedBaseUrl.data : DEFAULT_OGMENT_BASE_URL,
@@ -13854,7 +13808,7 @@ const parseRemoteErrorDetails = (payload) => {
13854
13808
  }
13855
13809
  return { message: trimmed };
13856
13810
  }
13857
- if (!isRecord$1(payload)) return {};
13811
+ if (!isRecord$2(payload)) return {};
13858
13812
  const directCode = payload["code"];
13859
13813
  const directMessage = payload["message"];
13860
13814
  if (typeof directCode === "number" || typeof directMessage === "string") return {
@@ -13863,7 +13817,7 @@ const parseRemoteErrorDetails = (payload) => {
13863
13817
  ...Object.hasOwn(payload, "data") ? { data: toJsonValue(payload["data"]) } : {}
13864
13818
  };
13865
13819
  const nestedError = payload["error"];
13866
- if (!isRecord$1(nestedError)) return {};
13820
+ if (!isRecord$2(nestedError)) return {};
13867
13821
  return {
13868
13822
  ...typeof nestedError["code"] === "number" ? { mcpCode: nestedError["code"] } : {},
13869
13823
  ...typeof nestedError["message"] === "string" ? { message: nestedError["message"] } : {},
@@ -13954,6 +13908,17 @@ const presentRuntimeErrorPayload = (error, options) => {
13954
13908
  title: appErrorTitle(error)
13955
13909
  };
13956
13910
  };
13911
+ const presentCatalogFailureError = (error, options) => {
13912
+ const payload = presentRuntimeErrorPayload(error, options);
13913
+ return {
13914
+ code: payload.code,
13915
+ detail: payload.detail,
13916
+ diagnostics: payload.diagnostics,
13917
+ ...payload.related_codes === void 0 ? {} : { related_codes: payload.related_codes },
13918
+ retryable: payload.retryable,
13919
+ title: payload.title
13920
+ };
13921
+ };
13957
13922
 
13958
13923
  //#endregion
13959
13924
  //#region src/output/envelope.ts
@@ -14140,7 +14105,13 @@ const cliOrgSchema = object({
14140
14105
  role: string(),
14141
14106
  servers: array(cliServerSchema)
14142
14107
  }).strict();
14108
+ const cliActingAgentSchema = object({
14109
+ agentId: string().uuid(),
14110
+ agentName: string().min(1),
14111
+ boundInstallationId: string().uuid().nullable()
14112
+ }).strict();
14143
14113
  const cliMeDataSchema = object({
14114
+ actingAgent: cliActingAgentSchema.nullable(),
14144
14115
  email: string().nullable(),
14145
14116
  imageUrl: string().nullable(),
14146
14117
  name: string().nullable(),
@@ -14151,79 +14122,66 @@ const accountMeSchema = cliSuccessEnvelopeSchema(cliMeDataSchema);
14151
14122
 
14152
14123
  //#endregion
14153
14124
  //#region ../../packages/shared/src/cli/auth.ts
14154
- const deviceCodeStartDataSchema = object({
14155
- deviceCode: string().min(1),
14156
- expiresIn: number$1().int().positive(),
14157
- interval: number$1().int().positive(),
14158
- userCode: string().min(1),
14159
- verificationUri: string().url()
14160
- }).strict();
14161
- const deviceCodeStartSchema = cliSuccessEnvelopeSchema(deviceCodeStartDataSchema);
14162
14125
  const authStartDataSchema = object({
14163
14126
  authRequestId: string().min(1),
14127
+ disposition: _enum([
14128
+ "created",
14129
+ "reused_approved",
14130
+ "reused_pending"
14131
+ ]),
14164
14132
  expiresAt: isoTimestampSchema,
14165
- userCode: string().min(1),
14166
14133
  verificationUrl: string().url()
14167
14134
  }).strict();
14168
14135
  const authStartSchema = cliSuccessEnvelopeSchema(authStartDataSchema);
14169
- const deviceTokenPendingDataSchema = object({ status: literal("authorization_pending") }).strict();
14170
- const deviceTokenApprovedDataSchema = object({
14171
- agentName: string().min(1),
14172
- apiKey: string().min(1),
14173
- status: literal("approved")
14174
- }).strict();
14175
- const deviceTokenDataSchema = discriminatedUnion("status", [deviceTokenPendingDataSchema, deviceTokenApprovedDataSchema]);
14176
- const deviceTokenSchema = cliSuccessEnvelopeSchema(deviceTokenDataSchema);
14177
- const deviceTokenApprovedSchema = cliSuccessEnvelopeSchema(deviceTokenApprovedDataSchema);
14178
14136
  const authExchangePendingDataSchema = object({ status: literal("authorization_pending") }).strict();
14179
14137
  const authExchangeApprovedDataSchema = object({
14138
+ agentId: string().uuid(),
14180
14139
  agentName: string().min(1),
14181
14140
  apiKey: string().min(1),
14182
- scopeFingerprint: string().min(1),
14141
+ credentialId: string().uuid(),
14183
14142
  status: literal("approved")
14184
14143
  }).strict();
14185
14144
  const authExchangeExpiredDataSchema = object({ status: literal("expired") }).strict();
14186
- const authExchangeDeniedDataSchema = object({ status: literal("denied") }).strict();
14187
- const authExchangeConflictDataSchema = object({ status: literal("conflict") }).strict();
14188
14145
  const authExchangeInvalidDataSchema = object({ status: literal("invalid") }).strict();
14146
+ const authExchangeSupersededDataSchema = object({ status: literal("superseded") }).strict();
14189
14147
  const authExchangeDataSchema = discriminatedUnion("status", [
14190
14148
  authExchangePendingDataSchema,
14191
14149
  authExchangeApprovedDataSchema,
14192
14150
  authExchangeExpiredDataSchema,
14193
- authExchangeDeniedDataSchema,
14194
- authExchangeConflictDataSchema,
14195
- authExchangeInvalidDataSchema
14151
+ authExchangeInvalidDataSchema,
14152
+ authExchangeSupersededDataSchema
14196
14153
  ]);
14197
14154
  const authExchangeSchema = cliSuccessEnvelopeSchema(authExchangeDataSchema);
14198
14155
  const authExchangeApprovedSchema = cliSuccessEnvelopeSchema(authExchangeApprovedDataSchema);
14199
- const revokeSelfDataSchema = object({ success: literal(true) }).strict();
14200
- const revokeSelfSchema = cliSuccessEnvelopeSchema(revokeSelfDataSchema);
14156
+ const authMutationSuccessDataSchema = object({ success: literal(true) }).strict();
14157
+ const authLogoutDataSchema = authMutationSuccessDataSchema;
14158
+ const authLogoutSchema = cliSuccessEnvelopeSchema(authLogoutDataSchema);
14159
+ const authResetDataSchema = authMutationSuccessDataSchema;
14160
+ const authResetSchema = cliSuccessEnvelopeSchema(authResetDataSchema);
14201
14161
 
14202
14162
  //#endregion
14203
14163
  //#region ../../packages/shared/src/cli/endpoints.ts
14204
14164
  const cliEndpoints = {
14205
14165
  accountMe: "/api/v1/cli/me",
14206
- authExchange: "/api/v1/cli/auth/exchange",
14207
14166
  authStart: "/api/v1/cli/auth/start",
14208
- cliRevokeSelf: "/api/v1/cli/revoke-self",
14209
- deviceCode: "/api/v1/cli/device-code",
14210
- deviceToken: "/api/v1/cli/device-token",
14167
+ authExchange: "/api/v1/cli/auth/exchange",
14168
+ authLogout: "/api/v1/cli/auth/logout",
14169
+ authReset: "/api/v1/cli/auth/reset",
14211
14170
  telemetry: "/api/v1/cli/telemetry"
14212
14171
  };
14213
14172
 
14214
14173
  //#endregion
14215
14174
  //#region ../../packages/shared/src/cli/telemetry.ts
14216
14175
  const cliCommandKindSchema = _enum([
14217
- "auth_login",
14218
- "auth_logout",
14219
- "auth_status",
14220
- "catalog_detail",
14176
+ "login",
14177
+ "logout",
14178
+ "reset",
14221
14179
  "catalog_summary",
14222
- "catalog_tool_detail",
14223
- "execute",
14180
+ "catalog_tool",
14181
+ "catalog_tools",
14182
+ "invoke",
14224
14183
  "parse_error",
14225
14184
  "root",
14226
- "search",
14227
14185
  "runtime_error",
14228
14186
  "status"
14229
14187
  ]);
@@ -14368,38 +14326,19 @@ const exitCodeForError = (error) => {
14368
14326
 
14369
14327
  //#endregion
14370
14328
  //#region src/commands/auth.ts
14371
- const runAuthLoginCommand = async (context, options) => {
14372
- const loginOptions = (() => {
14373
- if (options.mode === "apiKey") return {
14374
- apiKey: options.apiKey,
14375
- mode: "apiKey"
14376
- };
14377
- return {
14378
- mode: "device",
14379
- ...options.onPending === void 0 ? {} : { onPending: options.onPending }
14380
- };
14381
- })();
14329
+ const runLoginCommand = async (context, options) => {
14330
+ const loginOptions = options.onPending === void 0 ? {} : { onPending: options.onPending };
14382
14331
  return context.services.auth.login(loginOptions);
14383
14332
  };
14384
- const runAuthStatusCommand = async (context) => {
14385
- return context.services.auth.status(context.apiKeyOverride);
14386
- };
14387
- const runAuthLogoutCommand = async (context) => {
14333
+ const runLogoutCommand = async (context) => {
14388
14334
  return context.services.auth.logout();
14389
14335
  };
14336
+ const runResetCommand = async (context) => {
14337
+ return context.services.auth.reset();
14338
+ };
14390
14339
 
14391
14340
  //#endregion
14392
14341
  //#region src/commands/server-context.ts
14393
- const commandNameForSelectorKind = (selectorKind) => {
14394
- return selectorKind;
14395
- };
14396
- const selectorRecoveryCommand = (selectorKind, selector, orgSlug, toolName) => {
14397
- switch (selectorKind) {
14398
- case "catalog": return toolName === void 0 ? `ogment catalog ${orgSlug}/${selector}` : `ogment catalog ${orgSlug}/${selector} ${toolName}`;
14399
- case "search": return `ogment search --org ${orgSlug} ${selector} --code 'return input'`;
14400
- case "execute": return `ogment execute --org ${orgSlug} ${selector} --code 'return input' --input '{}'`;
14401
- }
14402
- };
14403
14342
  const formatCandidateSelectors = (profile, path) => {
14404
14343
  return profile.orgs.flatMap((org) => {
14405
14344
  return org.servers.filter((server) => server.path === path).map((server) => `${org.orgSlug}/${server.path}`);
@@ -14466,9 +14405,8 @@ const findServerByPath = (profile, selector, options) => {
14466
14405
  const [firstCandidate] = sortedCandidates;
14467
14406
  if (firstCandidate !== void 0) {
14468
14407
  const firstCandidateParsed = parseQualifiedSelector(firstCandidate);
14469
- const commandName = commandNameForSelectorKind(options.selectorKind);
14470
- const message = `Server "${selector}" is ambiguous across organizations (${sortedCandidates.join(", ")}). Re-run \`ogment ${commandName}\` with --org <org-slug> or use a qualified selector like "${firstCandidate}".`;
14471
- const recoveryCommand = firstCandidateParsed === null ? `ogment ${commandName} --help` : selectorRecoveryCommand(options.selectorKind, selector, firstCandidateParsed.orgSlug, options.toolName);
14408
+ const message = options.selectorKind === "invoke" ? `Server "${selector}" is ambiguous across organizations (${sortedCandidates.join(", ")}). Re-run with --org <org-slug>.` : `Server "${selector}" is ambiguous across organizations (${sortedCandidates.join(", ")}). Use a qualified selector like "${firstCandidate}".`;
14409
+ const recoveryCommand = options.selectorKind === "invoke" ? options.toolName === void 0 ? "ogment invoke --help" : firstCandidateParsed === null ? "ogment invoke --help" : `ogment invoke --org ${firstCandidateParsed.orgSlug} ${selector} ${options.toolName}` : `ogment catalog ${firstCandidate}`;
14472
14410
  return Result.err(new ValidationError({
14473
14411
  message,
14474
14412
  recovery: { command: recoveryCommand }
@@ -14488,75 +14426,96 @@ const findServerByPath = (profile, selector, options) => {
14488
14426
 
14489
14427
  //#endregion
14490
14428
  //#region src/commands/catalog.ts
14491
- const toServerSummary = (target) => {
14429
+ const toServerSummary = (target, toolCount) => {
14492
14430
  return {
14493
14431
  capabilities: [],
14494
14432
  description: target.server.description,
14495
14433
  name: target.server.name,
14496
14434
  orgSlug: target.orgSlug,
14497
14435
  serverId: target.server.path,
14436
+ toolCount,
14498
14437
  version: null
14499
14438
  };
14500
14439
  };
14501
- const toToolSummary = (tool) => {
14502
- return {
14503
- description: tool.description ?? null,
14504
- name: tool.name
14505
- };
14440
+ const toToolSummaries = (tools) => {
14441
+ return tools.map((tool) => {
14442
+ return {
14443
+ description: tool.description ?? null,
14444
+ name: tool.name
14445
+ };
14446
+ });
14447
+ };
14448
+ const listServerTools = async (context, apiKey, server) => {
14449
+ return context.services.mcp.listTools({
14450
+ orgSlug: server.orgSlug,
14451
+ serverPath: server.server.path
14452
+ }, apiKey);
14506
14453
  };
14507
- const toToolDetail = (tool) => {
14454
+ const TOOL_COUNT_CONCURRENCY = 4;
14455
+ const toCatalogServerFailure = (server, error, includeDebug) => {
14508
14456
  return {
14509
- description: tool.description ?? null,
14510
- inputSchema: toJsonValue(tool.inputSchema),
14511
- name: tool.name,
14512
- outputSchema: tool.outputSchema === void 0 ? null : toJsonValue(tool.outputSchema)
14457
+ error: presentCatalogFailureError(error, { includeDebug }),
14458
+ orgSlug: server.orgSlug,
14459
+ serverId: server.server.path
14513
14460
  };
14514
14461
  };
14515
- const detailCommandForServer = (serverId, orgSlug) => {
14516
- return `ogment catalog ${orgSlug === void 0 ? serverId : `${orgSlug}/${serverId}`}`;
14517
- };
14518
- const resolveCatalogServerTarget = async (context, options) => {
14519
- const stateResult = await resolveServerState(context);
14520
- if (Result.isError(stateResult)) return stateResult;
14521
- const serverResult = findServerByPath(stateResult.value.profile, options.serverId, {
14522
- ...options.orgSlug === void 0 ? {} : { orgSlug: options.orgSlug },
14523
- selectorKind: "catalog",
14524
- ..."toolName" in options ? { toolName: options.toolName } : {}
14525
- });
14526
- if (Result.isError(serverResult)) return serverResult;
14527
- return Result.ok({
14528
- apiKey: stateResult.value.apiKey,
14529
- target: {
14530
- orgSlug: serverResult.value.orgSlug,
14531
- server: {
14532
- description: serverResult.value.server.description,
14533
- name: serverResult.value.server.name,
14534
- path: serverResult.value.server.path
14535
- }
14536
- }
14537
- });
14538
- };
14539
- const listCodeModeTools = async (context, apiKey, target) => {
14540
- return context.services.codemode.listTools({
14541
- orgSlug: target.orgSlug,
14542
- serverPath: target.server.path
14543
- }, apiKey);
14462
+ const mapWithConcurrency = async (items, concurrency, mapItem) => {
14463
+ if (items.length === 0) return [];
14464
+ const results = [];
14465
+ results.length = items.length;
14466
+ let nextIndex = 0;
14467
+ const worker = async () => {
14468
+ while (true) {
14469
+ const currentIndex = nextIndex;
14470
+ nextIndex += 1;
14471
+ if (currentIndex >= items.length) return;
14472
+ const item = items[currentIndex];
14473
+ if (item === void 0) return;
14474
+ results[currentIndex] = await mapItem(item, currentIndex);
14475
+ }
14476
+ };
14477
+ const workerCount = Math.min(concurrency, items.length);
14478
+ await Promise.all(Array.from({ length: workerCount }, async () => worker()));
14479
+ return results;
14544
14480
  };
14545
14481
  const runCatalogCommand = async (context, options) => {
14546
14482
  const stateResult = await resolveServerState(context);
14547
14483
  if (Result.isError(stateResult)) return stateResult;
14548
- const targetOrgs = options.orgSlug === void 0 ? stateResult.value.profile.orgs : stateResult.value.profile.orgs.filter((org) => org.orgSlug === options.orgSlug);
14549
- if (options.orgSlug !== void 0 && targetOrgs.length === 0) return Result.err(new ValidationError({
14550
- code: ERROR_CODE.validationInvalidInput,
14551
- message: `Organization "${options.orgSlug}" not found`,
14552
- recovery: { command: "ogment catalog" }
14553
- }));
14554
- const summaries = targetOrgs.flatMap((org) => {
14555
- return org.servers.map((server) => toServerSummary({
14484
+ let targetServers = stateResult.value.profile.orgs.flatMap((org) => {
14485
+ return org.servers.map((server) => ({
14556
14486
  orgSlug: org.orgSlug,
14557
14487
  server
14558
14488
  }));
14559
14489
  });
14490
+ if (options.serverId !== void 0) {
14491
+ const serverResult = findServerByPath(stateResult.value.profile, options.serverId, { selectorKind: "catalog" });
14492
+ if (Result.isError(serverResult)) return serverResult;
14493
+ targetServers = [{
14494
+ orgSlug: serverResult.value.orgSlug,
14495
+ server: serverResult.value.server
14496
+ }];
14497
+ }
14498
+ const serverSummaries = await mapWithConcurrency(targetServers, TOOL_COUNT_CONCURRENCY, async (server) => {
14499
+ return {
14500
+ server,
14501
+ toolsResult: await listServerTools(context, stateResult.value.apiKey, server)
14502
+ };
14503
+ });
14504
+ const summaries = [];
14505
+ const failures = [];
14506
+ for (const serverSummary of serverSummaries) {
14507
+ if (Result.isError(serverSummary.toolsResult)) {
14508
+ if (options.serverId !== void 0) return serverSummary.toolsResult;
14509
+ failures.push(toCatalogServerFailure(serverSummary.server, serverSummary.toolsResult.error, options.includeDebug === true));
14510
+ continue;
14511
+ }
14512
+ summaries.push(toServerSummary(serverSummary.server, serverSummary.toolsResult.value.length));
14513
+ }
14514
+ if (options.serverId !== void 0) return Result.ok({
14515
+ failures: [],
14516
+ nextCursor: null,
14517
+ servers: summaries
14518
+ });
14560
14519
  const limit = Math.max(1, options.limit ?? 20);
14561
14520
  let startIndex = 0;
14562
14521
  if (options.cursor !== void 0) {
@@ -14571,52 +14530,81 @@ const runCatalogCommand = async (context, options) => {
14571
14530
  const servers = summaries.slice(startIndex, startIndex + limit);
14572
14531
  const nextCursor = startIndex + limit < summaries.length ? servers.at(-1)?.serverId ?? null : null;
14573
14532
  return Result.ok({
14574
- failures: [],
14533
+ failures,
14575
14534
  nextCursor,
14576
14535
  servers
14577
14536
  });
14578
14537
  };
14579
- const runCatalogServerDetailCommand = async (context, options) => {
14580
- const targetResult = await resolveCatalogServerTarget(context, options);
14581
- if (Result.isError(targetResult)) return targetResult;
14582
- const toolsResult = await listCodeModeTools(context, targetResult.value.apiKey, targetResult.value.target);
14538
+ const runCatalogToolsCommand = async (context, options) => {
14539
+ const stateResult = await resolveServerState(context);
14540
+ if (Result.isError(stateResult)) return stateResult;
14541
+ const serverResult = findServerByPath(stateResult.value.profile, options.serverId, { selectorKind: "catalog" });
14542
+ if (Result.isError(serverResult)) return serverResult;
14543
+ const targetServer = {
14544
+ orgSlug: serverResult.value.orgSlug,
14545
+ server: serverResult.value.server
14546
+ };
14547
+ const toolsResult = await listServerTools(context, stateResult.value.apiKey, targetServer);
14583
14548
  if (Result.isError(toolsResult)) return toolsResult;
14584
14549
  return Result.ok({
14585
- server: toServerSummary(targetResult.value.target),
14586
- tools: toolsResult.value.map((tool) => toToolSummary(tool))
14550
+ server: toServerSummary(targetServer, toolsResult.value.length),
14551
+ tools: toToolSummaries(toolsResult.value)
14587
14552
  });
14588
14553
  };
14589
- const runCatalogToolDetailCommand = async (context, options) => {
14590
- const targetResult = await resolveCatalogServerTarget(context, options);
14591
- if (Result.isError(targetResult)) return targetResult;
14592
- const toolsResult = await listCodeModeTools(context, targetResult.value.apiKey, targetResult.value.target);
14554
+ const runCatalogToolDetailsCommand = async (context, options) => {
14555
+ const stateResult = await resolveServerState(context);
14556
+ if (Result.isError(stateResult)) return stateResult;
14557
+ const serverResult = findServerByPath(stateResult.value.profile, options.serverId, { selectorKind: "catalog" });
14558
+ if (Result.isError(serverResult)) return serverResult;
14559
+ const targetServer = {
14560
+ orgSlug: serverResult.value.orgSlug,
14561
+ server: serverResult.value.server
14562
+ };
14563
+ const toolsResult = await listServerTools(context, stateResult.value.apiKey, targetServer);
14593
14564
  if (Result.isError(toolsResult)) return toolsResult;
14594
- const tool = toolsResult.value.find((candidate) => {
14595
- return candidate.name === options.toolName;
14596
- });
14565
+ const tool = toolsResult.value.find((item) => item.name === options.toolName);
14597
14566
  if (tool === void 0) return Result.err(new NotFoundError({
14598
- message: `Codemode tool "${options.toolName}" not found on server "${options.serverId}"`,
14599
- recovery: { command: detailCommandForServer(targetResult.value.target.server.path, targetResult.value.target.orgSlug) },
14600
- resource: `${options.serverId}/${options.toolName}`
14567
+ message: `Tool "${options.toolName}" not found`,
14568
+ resource: options.toolName
14601
14569
  }));
14602
14570
  return Result.ok({
14603
- server: toServerSummary(targetResult.value.target),
14604
- tool: toToolDetail(tool)
14571
+ description: tool.description ?? null,
14572
+ inputSchema: tool.inputSchema,
14573
+ name: tool.name,
14574
+ outputSchema: tool.outputSchema ?? null,
14575
+ server: toServerSummary(targetServer, toolsResult.value.length)
14605
14576
  });
14606
14577
  };
14607
14578
 
14608
14579
  //#endregion
14609
- //#region src/commands/codemode.ts
14610
- const mapSourceFileReadError = (inputFile, optionName, cause) => {
14580
+ //#region src/commands/invoke.ts
14581
+ const mapInputFileReadError = (inputFile, cause) => {
14611
14582
  const code = cause instanceof Error && "code" in cause && typeof cause.code === "string" ? cause.code : void 0;
14612
- if (code === "ENOENT") return new ValidationError({ message: `${optionName} file not found: ${inputFile}` });
14613
- if (code === "EACCES" || code === "EPERM") return new ValidationError({ message: `${optionName} file is not readable: ${inputFile}` });
14614
- if (code === "EISDIR") return new ValidationError({ message: `${optionName} path must be a file: ${inputFile}` });
14583
+ if (code === "ENOENT") return new ValidationError({ message: `Input file not found: ${inputFile}` });
14584
+ if (code === "EACCES" || code === "EPERM") return new ValidationError({ message: `Input file is not readable: ${inputFile}` });
14585
+ if (code === "EISDIR") return new ValidationError({ message: `Input path must be a file: ${inputFile}` });
14615
14586
  return new UnexpectedError({
14616
14587
  cause,
14617
- message: `Failed to read ${optionName} file: ${inputFile}`
14588
+ message: `Failed to read input file: ${inputFile}`
14618
14589
  });
14619
14590
  };
14591
+ const parseInputObject = (raw, context) => {
14592
+ const parsed = parseJsonValue(raw, context);
14593
+ if (Result.isError(parsed)) return parsed;
14594
+ const parsedValue = parsed.value;
14595
+ if (!isJsonObject(parsedValue)) return Result.err(new ValidationError({ message: "Invoke input must be a JSON object" }));
14596
+ return Result.ok(parsedValue);
14597
+ };
14598
+ const toToolCallStructuredContent = (result) => {
14599
+ if (result.structuredContent !== void 0) return toJsonValue(result.structuredContent);
14600
+ const firstContent = (Array.isArray(result.content) ? result.content : [])[0];
14601
+ if (firstContent !== void 0 && firstContent.type === "text" && typeof firstContent.text === "string") {
14602
+ const parsedText = parseJsonValue(firstContent.text, "MCP text content");
14603
+ if (Result.isError(parsedText)) return firstContent.text;
14604
+ return parsedText.value;
14605
+ }
14606
+ return toJsonValue(result);
14607
+ };
14620
14608
  const readStdin = async () => {
14621
14609
  return Result.tryPromise({
14622
14610
  catch: (cause) => new UnexpectedError({
@@ -14640,111 +14628,73 @@ const readStdin = async () => {
14640
14628
  }
14641
14629
  });
14642
14630
  };
14643
- const readSourceValue = async (value, optionName, deps) => {
14644
- if (value === "-") return (deps.readStdin ?? readStdin)();
14645
- if (value.startsWith("@")) {
14646
- const inputFile = value.slice(1);
14631
+ const parseInvokeArgs = async (options, deps) => {
14632
+ if (options.input === void 0) return Result.ok({});
14633
+ if (options.input === "-") {
14634
+ const stdinResult = await (deps.readStdin ?? readStdin)();
14635
+ if (Result.isError(stdinResult)) return stdinResult;
14636
+ return parseInputObject(stdinResult.value, "--input (-)");
14637
+ }
14638
+ if (options.input.startsWith("@")) {
14639
+ const inputFile = options.input.slice(1);
14647
14640
  if (inputFile.length === 0) return Result.err(new ValidationError({
14648
- details: value,
14649
- message: `Invalid ${optionName} value. Use @<path>, -, or an inline value.`
14641
+ details: options.input,
14642
+ message: "Invalid --input value. Use @<path>, -, or an inline JSON object."
14650
14643
  }));
14651
- return Result.tryPromise({
14652
- catch: (cause) => mapSourceFileReadError(inputFile, optionName, cause),
14644
+ const fileReadResult = await Result.tryPromise({
14645
+ catch: (cause) => mapInputFileReadError(inputFile, cause),
14653
14646
  try: async () => readFile$1(inputFile, "utf8")
14654
14647
  });
14648
+ if (Result.isError(fileReadResult)) return fileReadResult;
14649
+ return parseInputObject(fileReadResult.value, "--input (@file)");
14655
14650
  }
14656
- return Result.ok(value);
14657
- };
14658
- const parseInputObject = (raw, context) => {
14659
- const parsed = parseJsonValue(raw, context);
14660
- if (Result.isError(parsed)) return parsed;
14661
- if (!isJsonObject(parsed.value)) return Result.err(new ValidationError({ message: "Execute input must be a JSON object" }));
14662
- return Result.ok(parsed.value);
14663
- };
14664
- const parseExecuteInput = async (input, deps) => {
14665
- if (input === void 0) return Result.ok(void 0);
14666
- const sourceResult = await readSourceValue(input, "--input", deps);
14667
- if (Result.isError(sourceResult)) return sourceResult;
14668
- const sourceContext = input === "-" ? "--input (-)" : input.startsWith("@") ? "--input (@file)" : "--input";
14669
- return parseInputObject(sourceResult.value, sourceContext);
14670
- };
14671
- const toToolCallStructuredContent = (result) => {
14672
- if (result.structuredContent !== void 0) return toJsonValue(result.structuredContent);
14673
- const firstContent = (Array.isArray(result.content) ? result.content : [])[0];
14674
- if (firstContent !== void 0 && firstContent.type === "text" && typeof firstContent.text === "string") {
14675
- const parsedText = parseJsonValue(firstContent.text, "MCP text content");
14676
- if (Result.isError(parsedText)) return firstContent.text;
14677
- return parsedText.value;
14678
- }
14679
- return toJsonValue(result);
14651
+ return parseInputObject(options.input, "--input");
14680
14652
  };
14681
- const resolveServerTarget = async (context, options, selectorKind) => {
14653
+ const runInvokeCommand = async (context, options, deps = {}) => {
14654
+ const argsResult = await parseInvokeArgs(options, deps);
14655
+ if (Result.isError(argsResult)) return argsResult;
14682
14656
  const stateResult = await resolveServerState(context);
14683
14657
  if (Result.isError(stateResult)) return stateResult;
14684
14658
  const serverResult = findServerByPath(stateResult.value.profile, options.serverId, {
14685
14659
  ...options.orgSlug === void 0 ? {} : { orgSlug: options.orgSlug },
14686
- selectorKind
14660
+ selectorKind: "invoke",
14661
+ toolName: options.toolName
14687
14662
  });
14688
14663
  if (Result.isError(serverResult)) return serverResult;
14689
- return Result.ok({
14690
- apiKey: stateResult.value.apiKey,
14664
+ const mcpTarget = {
14691
14665
  orgSlug: serverResult.value.orgSlug,
14692
14666
  serverPath: serverResult.value.server.path
14693
- });
14694
- };
14695
- const codemodeErrorFromToolResult = (result) => {
14696
- if (!result.isError) return null;
14697
- const structuredContent = toToolCallStructuredContent(result);
14698
- const details = parseRemoteErrorDetails(structuredContent);
14699
- return new RemoteRequestError({
14700
- ...details.mcpCode === void 0 ? {} : { mcpCode: details.mcpCode },
14701
- ...details.data === void 0 ? {} : { mcpData: details.data },
14702
- message: details.message ?? "Codemode tool call returned an error result",
14703
- operation: "tools/call",
14704
- raw: structuredContent,
14705
- retryable: false,
14706
- source: "mcp_jsonrpc"
14707
- });
14708
- };
14709
- const runSearchCommand = async (context, options, deps = {}) => {
14710
- const codeResult = await readSourceValue(options.code, "--code", deps);
14711
- if (Result.isError(codeResult)) return codeResult;
14712
- const targetResult = await resolveServerTarget(context, options, "search");
14713
- if (Result.isError(targetResult)) return targetResult;
14714
- const callResult = await context.services.codemode.callTool({
14715
- orgSlug: targetResult.value.orgSlug,
14716
- serverPath: targetResult.value.serverPath
14717
- }, targetResult.value.apiKey, "search", { code: codeResult.value });
14718
- if (Result.isError(callResult)) return callResult;
14719
- const toolError = codemodeErrorFromToolResult(callResult.value);
14720
- if (toolError !== null) return Result.err(toolError);
14721
- return Result.ok({
14722
- result: toToolCallStructuredContent(callResult.value),
14723
- serverId: options.serverId
14724
- });
14725
- };
14726
- const runExecuteCommand = async (context, options, deps = {}) => {
14727
- const [codeResult, inputResult, targetResult] = await Promise.all([
14728
- readSourceValue(options.code, "--code", deps),
14729
- parseExecuteInput(options.input, deps),
14730
- resolveServerTarget(context, options, "execute")
14731
- ]);
14732
- if (Result.isError(codeResult)) return codeResult;
14733
- if (Result.isError(inputResult)) return inputResult;
14734
- if (Result.isError(targetResult)) return targetResult;
14735
- const callResult = await context.services.codemode.callTool({
14736
- orgSlug: targetResult.value.orgSlug,
14737
- serverPath: targetResult.value.serverPath
14738
- }, targetResult.value.apiKey, "execute", {
14739
- code: codeResult.value,
14740
- ...inputResult.value === void 0 ? {} : { input: inputResult.value }
14741
- });
14742
- if (Result.isError(callResult)) return callResult;
14743
- const toolError = codemodeErrorFromToolResult(callResult.value);
14744
- if (toolError !== null) return Result.err(toolError);
14667
+ };
14668
+ const callResult = await context.services.mcp.callTool(mcpTarget, stateResult.value.apiKey, options.toolName, argsResult.value);
14669
+ if (Result.isError(callResult)) {
14670
+ if (callResult.error._tag === "RemoteRequestError") {
14671
+ const toolsResult = await context.services.mcp.listTools(mcpTarget, stateResult.value.apiKey);
14672
+ if (Result.isOk(toolsResult)) {
14673
+ if (!toolsResult.value.some((tool) => tool.name === options.toolName)) return Result.err(new NotFoundError({
14674
+ message: `Tool "${options.toolName}" not found`,
14675
+ resource: options.toolName
14676
+ }));
14677
+ }
14678
+ }
14679
+ return callResult;
14680
+ }
14681
+ const structuredContent = toToolCallStructuredContent(callResult.value);
14682
+ if (callResult.value.isError) {
14683
+ const details = parseRemoteErrorDetails(structuredContent);
14684
+ return Result.err(new RemoteRequestError({
14685
+ ...details.mcpCode === void 0 ? {} : { mcpCode: details.mcpCode },
14686
+ ...details.data === void 0 ? {} : { mcpData: details.data },
14687
+ message: details.message ?? "MCP tool call returned an error result",
14688
+ operation: "tools/call",
14689
+ raw: structuredContent,
14690
+ retryable: false,
14691
+ source: "mcp_jsonrpc"
14692
+ }));
14693
+ }
14745
14694
  return Result.ok({
14746
- result: toToolCallStructuredContent(callResult.value),
14747
- serverId: options.serverId
14695
+ result: structuredContent,
14696
+ serverId: options.serverId,
14697
+ toolName: options.toolName
14748
14698
  });
14749
14699
  };
14750
14700
 
@@ -14755,117 +14705,144 @@ const runStatusCommand = async (options, deps) => {
14755
14705
  };
14756
14706
 
14757
14707
  //#endregion
14758
- //#region src/cli/commands.ts
14759
- const withOrg = (orgSlug) => {
14760
- return orgSlug === void 0 ? [] : [`--org ${orgSlug}`];
14708
+ //#region src/shared/schema-example.ts
14709
+ const MAX_EXAMPLE_DEPTH = 6;
14710
+ const EXAMPLE_PLACEHOLDER = " ... ";
14711
+ const isRecord$1 = (value) => {
14712
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14713
+ };
14714
+ const asStringArray = (value) => {
14715
+ if (!Array.isArray(value)) return [];
14716
+ return value.filter((item) => typeof item === "string");
14717
+ };
14718
+ const firstKnown = (value) => {
14719
+ if (Array.isArray(value) && value.length > 0) return value[0];
14720
+ };
14721
+ const deriveType = (schema) => {
14722
+ const typeValue = schema["type"];
14723
+ if (typeof typeValue === "string") return typeValue;
14724
+ if (Array.isArray(typeValue)) return typeValue.find((entry) => typeof entry === "string");
14725
+ if (isRecord$1(schema["properties"])) return "object";
14726
+ if (schema["items"] !== void 0) return "array";
14727
+ };
14728
+ const baseScalarExample = (_typeName) => {
14729
+ switch (_typeName) {
14730
+ case "string": return EXAMPLE_PLACEHOLDER;
14731
+ case "integer": return EXAMPLE_PLACEHOLDER;
14732
+ case "number": return EXAMPLE_PLACEHOLDER;
14733
+ case "boolean": return EXAMPLE_PLACEHOLDER;
14734
+ case "null": return EXAMPLE_PLACEHOLDER;
14735
+ default: return EXAMPLE_PLACEHOLDER;
14736
+ }
14761
14737
  };
14738
+ const buildExample = (value, depth) => {
14739
+ if (!isRecord$1(value)) return {};
14740
+ if (depth > MAX_EXAMPLE_DEPTH) return {};
14741
+ const oneOfCandidate = firstKnown(value["oneOf"]);
14742
+ if (oneOfCandidate !== void 0) return buildExample(oneOfCandidate, depth + 1);
14743
+ const anyOfCandidate = firstKnown(value["anyOf"]);
14744
+ if (anyOfCandidate !== void 0) return buildExample(anyOfCandidate, depth + 1);
14745
+ const allOfCandidate = firstKnown(value["allOf"]);
14746
+ if (allOfCandidate !== void 0) return buildExample(allOfCandidate, depth + 1);
14747
+ const typeName = deriveType(value);
14748
+ if (typeName === "object") {
14749
+ const result = {};
14750
+ const properties = isRecord$1(value["properties"]) ? value["properties"] : {};
14751
+ const required = asStringArray(value["required"]);
14752
+ for (const propertyName of required) {
14753
+ const propertySchema = properties[propertyName];
14754
+ if (propertySchema !== void 0) result[propertyName] = buildExample(propertySchema, depth + 1);
14755
+ }
14756
+ if (required.length === 0 && isRecord$1(value["additionalProperties"])) result["example"] = buildExample(value["additionalProperties"], depth + 1);
14757
+ return result;
14758
+ }
14759
+ if (typeName === "array") {
14760
+ if (value["items"] === void 0) return [EXAMPLE_PLACEHOLDER];
14761
+ return [buildExample(value["items"], depth + 1)];
14762
+ }
14763
+ if (typeName === void 0) return depth === 0 ? {} : EXAMPLE_PLACEHOLDER;
14764
+ return baseScalarExample(typeName);
14765
+ };
14766
+ const buildJsonSchemaExample = (schema) => {
14767
+ return buildExample(schema, 0);
14768
+ };
14769
+
14770
+ //#endregion
14771
+ //#region src/cli/commands.ts
14762
14772
  const cliCommands = {
14763
- auth: {
14764
- help: () => "ogment auth --help",
14765
- login: () => "ogment auth login",
14766
- loginWithApiKeyRedacted: () => "ogment auth login --api-key <redacted>",
14767
- logout: () => "ogment auth logout",
14768
- status: () => "ogment auth status"
14769
- },
14770
14773
  catalog: {
14771
- command: (serverId, toolName, orgSlug) => [
14772
- "ogment catalog",
14773
- ...withOrg(orgSlug),
14774
- ...serverId === void 0 ? [] : [serverId],
14775
- ...toolName === void 0 ? [] : [toolName]
14776
- ].join(" "),
14777
- detail: (serverId, orgSlug) => [
14778
- "ogment catalog",
14779
- ...withOrg(orgSlug),
14780
- serverId
14781
- ].join(" "),
14774
+ command: () => "ogment catalog",
14775
+ server: (serverId) => `ogment catalog ${serverId}`,
14782
14776
  summary: (options) => {
14783
14777
  return [
14784
14778
  "ogment catalog",
14785
- ...withOrg(options.orgSlug),
14786
14779
  ...options.cursor === void 0 ? [] : [`--cursor ${options.cursor}`],
14787
14780
  ...options.limit === void 0 ? [] : [`--limit ${options.limit}`]
14788
14781
  ].join(" ");
14789
14782
  },
14790
- toolDetail: (serverId, toolName, orgSlug) => [
14791
- "ogment catalog",
14792
- ...withOrg(orgSlug),
14783
+ tool: (serverId, toolName, options) => {
14784
+ return [
14785
+ "ogment catalog",
14786
+ serverId,
14787
+ toolName,
14788
+ ...options.example ? ["--example"] : []
14789
+ ].join(" ");
14790
+ }
14791
+ },
14792
+ helpForScope: (scope) => {
14793
+ if (scope === null) return "ogment --help";
14794
+ return `ogment ${scope} --help`;
14795
+ },
14796
+ login: { command: () => "ogment login" },
14797
+ logout: { command: () => "ogment logout" },
14798
+ invoke: {
14799
+ command: (serverId, toolName, orgSlug) => [
14800
+ "ogment invoke",
14801
+ ...orgSlug === void 0 ? [] : [`--org ${orgSlug}`],
14793
14802
  serverId,
14794
14803
  toolName
14795
- ].join(" ")
14796
- },
14797
- execute: {
14798
- command: (serverId, orgSlug) => [
14799
- "ogment execute",
14800
- ...withOrg(orgSlug),
14801
- serverId
14802
14804
  ].join(" "),
14803
- help: () => "ogment execute --help",
14804
- inlineCode: (serverId, orgSlug) => [
14805
- "ogment execute",
14806
- ...withOrg(orgSlug),
14805
+ inlineJson: (serverId, toolName, orgSlug) => [
14806
+ "ogment invoke",
14807
+ ...orgSlug === void 0 ? [] : [`--org ${orgSlug}`],
14807
14808
  serverId,
14808
- "--code <javascript>"
14809
+ toolName,
14810
+ "--input <json>"
14809
14811
  ].join(" "),
14810
- stdinCode: (serverId, orgSlug) => [
14811
- "ogment execute",
14812
- ...withOrg(orgSlug),
14812
+ stdin: (serverId, toolName, orgSlug) => [
14813
+ "ogment invoke",
14814
+ ...orgSlug === void 0 ? [] : [`--org ${orgSlug}`],
14813
14815
  serverId,
14814
- "--code -"
14816
+ toolName,
14817
+ "--input -"
14815
14818
  ].join(" "),
14816
- withCodeAndInputValue: (serverId, code, input, orgSlug) => [
14817
- "ogment execute",
14818
- ...withOrg(orgSlug),
14819
- serverId,
14820
- `--code ${code}`,
14821
- ...input === void 0 ? [] : [`--input ${input}`]
14822
- ].join(" ")
14823
- },
14824
- helpForScope: (scope) => {
14825
- if (scope === null) return "ogment --help";
14826
- return `ogment ${scope} --help`;
14819
+ withInputValue: (serverId, toolName, value, orgSlug) => {
14820
+ return [
14821
+ "ogment invoke",
14822
+ ...orgSlug === void 0 ? [] : [`--org ${orgSlug}`],
14823
+ serverId,
14824
+ toolName,
14825
+ `--input ${value}`
14826
+ ].join(" ");
14827
+ }
14827
14828
  },
14828
14829
  root: {
14829
14830
  command: () => "ogment",
14830
14831
  commandsSurface: () => {
14831
14832
  return [
14832
- "auth login",
14833
- "auth status",
14834
- "auth logout",
14833
+ "login",
14834
+ "logout",
14835
+ "reset",
14835
14836
  "catalog",
14836
- "search <server-id>",
14837
- "execute <server-id>",
14837
+ "catalog <server-id>",
14838
+ "catalog <server-id> <tool-name>",
14839
+ "invoke <server-id> <tool-name>",
14838
14840
  "status"
14839
14841
  ];
14840
14842
  },
14841
14843
  help: () => "ogment --help"
14842
14844
  },
14843
- search: {
14844
- command: (serverId, orgSlug) => [
14845
- "ogment search",
14846
- ...withOrg(orgSlug),
14847
- serverId
14848
- ].join(" "),
14849
- help: () => "ogment search --help",
14850
- inspectAllTools: (serverId, orgSlug) => [
14851
- "ogment search",
14852
- ...withOrg(orgSlug),
14853
- serverId,
14854
- "--code 'return input'"
14855
- ].join(" "),
14856
- stdinCode: (serverId, orgSlug) => [
14857
- "ogment search",
14858
- ...withOrg(orgSlug),
14859
- serverId,
14860
- "--code -"
14861
- ].join(" "),
14862
- withCodeValue: (serverId, code, orgSlug) => [
14863
- "ogment search",
14864
- ...withOrg(orgSlug),
14865
- serverId,
14866
- `--code ${code}`
14867
- ].join(" ")
14868
- },
14845
+ reset: { command: () => "ogment reset" },
14869
14846
  status: { command: () => "ogment status" }
14870
14847
  };
14871
14848
 
@@ -14904,281 +14881,283 @@ const ensureSuccess = (result, runtime, context) => {
14904
14881
  }
14905
14882
  return result.unwrap();
14906
14883
  };
14907
- const nextActionsForLogin = (payload, mode) => {
14908
- return [nextAction("check_auth_status", "Check auth status", cliCommands.auth.status(), `Verify persisted credentials after ${mode} login for ${payload.agentName}.`, "immediate"), nextAction("discover_servers", "Discover servers", cliCommands.catalog.command(), `Logged in as ${payload.agentName} via ${mode}; discover available servers.`, "after_auth")];
14884
+ const nextActionsForLogin = (payload) => {
14885
+ return [nextAction("inspect_status", "Inspect status", cliCommands.status.command(), `Verify the connected CLI state for ${payload.agentName}.`, "immediate"), nextAction("discover_servers", "Discover servers", cliCommands.catalog.command(), `Logged in as ${payload.agentName}; discover available servers.`, "after_auth")];
14909
14886
  };
14910
- const nextActionsForPendingLogin = (userCode, verificationUri) => {
14911
- return [nextAction("check_login_status", "Check login status", cliCommands.auth.status(), `Approve ${userCode} at ${verificationUri}, then verify local auth state.`, "immediate"), nextAction("restart_device_login", "Restart login", cliCommands.auth.login(), `Restart login if code ${userCode} expires before approval.`, "if_expired")];
14912
- };
14913
- const nextActionsForAuthStatus = (payload) => {
14914
- if (!payload.loggedIn) return [nextAction("login", "Authenticate", cliCommands.auth.login(), "No API key is configured locally; login is required.", "immediate")];
14915
- return [nextAction("discover_servers", "Discover servers", cliCommands.catalog.command(), `Authenticated via ${payload.apiKeySource}; discover servers next.`, "after_auth")];
14887
+ const nextActionsForPendingLogin = (authRequestId, verificationUrl) => {
14888
+ return [nextAction("complete_login", "Complete login", cliCommands.login.command(), `Approve request ${authRequestId} at ${verificationUrl}, then run login again to finish local sign-in.`, "immediate"), nextAction("inspect_status", "Inspect status", cliCommands.status.command(), "Inspect the current CLI state and diagnostics.", "if_expired")];
14916
14889
  };
14917
14890
  const nextActionsForCatalogSummary = (payload, context) => {
14918
14891
  const actions = [];
14919
- const targetServer = payload.servers[0];
14920
- if (targetServer !== void 0) actions.push(nextAction("inspect_server", "Inspect server", cliCommands.catalog.detail(targetServer.serverId, targetServer.orgSlug), `Inspect Codemode tools exposed on ${targetServer.serverId}.`, "if_servers_available"));
14892
+ const targetServer = payload.servers.find((server) => server.toolCount > 0);
14893
+ if (targetServer !== void 0) actions.push(nextAction("inspect_tools", "Inspect tools", cliCommands.catalog.server(targetServer.serverId), `${targetServer.serverId} has ${targetServer.toolCount} available tools.`, "if_tool_count_gt_0"));
14921
14894
  if (context.nextCursor !== null) actions.push(nextAction("next_catalog_page", "Load next page", cliCommands.catalog.summary({
14922
14895
  cursor: context.nextCursor,
14923
- ...context.limit === null ? {} : { limit: context.limit },
14924
- ...context.orgSlug === null ? {} : { orgSlug: context.orgSlug }
14896
+ ...context.limit === null ? {} : { limit: context.limit }
14925
14897
  }), `More servers are available after cursor ${context.nextCursor}.`, "if_more_servers"));
14926
14898
  return actions;
14927
14899
  };
14928
- const nextActionsForCatalogServerDetail = (payload) => {
14929
- const searchTool = payload.tools.find((tool) => tool.name === "search");
14930
- if (searchTool !== void 0) return [nextAction("inspect_tool", "Inspect tool details", cliCommands.catalog.toolDetail(payload.server.serverId, searchTool.name, payload.server.orgSlug), `Inspect schema for ${payload.server.serverId}/${searchTool.name} before invoking.`, "if_tools_available")];
14931
- return [];
14900
+ const nextActionsForCatalogTools = (payload) => {
14901
+ const firstTool = payload.tools[0];
14902
+ if (firstTool === void 0) return [];
14903
+ return [nextAction("inspect_tool", "Inspect tool details", cliCommands.catalog.tool(payload.server.serverId, firstTool.name, { example: false }), `Inspect schema for ${payload.server.serverId}/${firstTool.name} before invoking.`, "if_tools_available")];
14932
14904
  };
14933
- const nextActionsForCatalogToolDetail = (payload) => {
14934
- if (payload.tool.name === "search") return [nextAction("run_search", "Run search", cliCommands.search.inspectAllTools(payload.server.serverId, payload.server.orgSlug), `Use Codemode search on ${payload.server.serverId} after reviewing the tool contract.`, "after_tool_inspection")];
14935
- return [nextAction("run_execute", "Run execute", cliCommands.execute.inlineCode(payload.server.serverId, payload.server.orgSlug), `Use Codemode execute on ${payload.server.serverId} after reviewing the tool contract.`, "after_tool_inspection")];
14905
+ const toInlineJsonTemplateArgument = (value) => {
14906
+ const placeholderLiteral = JSON.stringify(EXAMPLE_PLACEHOLDER);
14907
+ return `'${JSON.stringify(value).replaceAll(placeholderLiteral, " ... ").replaceAll("'", String.raw`'\''`)}'`;
14936
14908
  };
14937
- const nextActionsForSearch = (payload) => {
14938
- return [nextAction("execute_help", "Inspect execute usage", cliCommands.execute.help(), `Run Codemode execute against ${payload.serverId} after choosing a workflow.`, "after_search")];
14909
+ const nextActionsForCatalogToolDetails = (payload, exampleInput) => {
14910
+ const inputArgument = toInlineJsonTemplateArgument(exampleInput);
14911
+ return [nextAction("invoke_tool", "Invoke this tool", cliCommands.invoke.withInputValue(payload.server.serverId, payload.name, inputArgument), `Replace every ... placeholder with real JSON values, then invoke ${payload.server.serverId} ${payload.name}.`, "after_tool_inspection")];
14939
14912
  };
14940
- const nextActionsForExecute = (payload) => {
14941
- return [nextAction("search_tools", "Search tools again", cliCommands.search.inspectAllTools(payload.serverId), `Reinspect tool definitions on ${payload.serverId} before the next execution.`, "after_execute")];
14913
+ const nextActionsForInvoke = (payload) => {
14914
+ return [nextAction("inspect_tool", "Inspect tool schema", cliCommands.catalog.tool(payload.serverId, payload.toolName, { example: false }), `Review ${payload.serverId}/${payload.toolName} schema for the next invocation.`, "after_invoke")];
14942
14915
  };
14943
14916
  const nextActionsForStatus = (payload) => {
14944
- if (!payload.auth.apiKeyPresent) return [nextAction("login", "Authenticate", cliCommands.auth.login(), "Status detected no API key; authenticate first.", "immediate")];
14917
+ if (!payload.auth.apiKeyPresent) return [nextAction("login", "Authenticate", cliCommands.login.command(), "Status detected no API key; authenticate first.", "immediate")];
14945
14918
  return [nextAction("discover_servers", "Discover servers", cliCommands.catalog.command(), `Connectivity is ${payload.summary.status}; discover available servers.`, "after_status")];
14946
14919
  };
14947
- const codeSourceFromValue = (value) => {
14948
- if (value === "-") return "stdin";
14949
- if (value.startsWith("@")) return "file";
14950
- return "inline";
14951
- };
14952
- const inputSourceFromValue = (value) => {
14953
- if (value === void 0) return "none";
14954
- if (value === "-") return "stdin";
14955
- if (value.startsWith("@")) return "file";
14956
- return "inline_json";
14957
- };
14958
14920
  const runLoginFlow = async (runtime, options) => {
14959
- const { commandOptions, invokedCommand, mode } = options.mode === "apiKey" ? {
14960
- commandOptions: options,
14961
- invokedCommand: cliCommands.auth.loginWithApiKeyRedacted(),
14962
- mode: "apiKey"
14963
- } : {
14964
- commandOptions: { mode: "device" },
14965
- invokedCommand: cliCommands.auth.login(),
14966
- mode: "device"
14967
- };
14968
- const data = ensureSuccess(await runAuthLoginCommand(runtime.context, commandOptions), runtime, {
14969
- command: invokedCommand,
14970
- entity: { mode }
14971
- });
14921
+ const invokedCommand = cliCommands.login.command();
14922
+ const data = ensureSuccess(await runLoginCommand(runtime.context, options), runtime, { command: invokedCommand });
14972
14923
  if (!data.loggedIn) {
14973
14924
  const pendingOutput = {
14974
- event: "auth_login.pending",
14925
+ event: "login.pending",
14975
14926
  loggedIn: false,
14976
14927
  verification: data.verification
14977
14928
  };
14978
14929
  runtime.output.success(pendingOutput, {
14979
14930
  command: invokedCommand,
14980
14931
  entity: {
14981
- event: "auth_login.pending",
14982
- mode,
14932
+ event: "login.pending",
14983
14933
  verification: {
14984
- userCode: data.verification.userCode,
14985
- verificationUri: data.verification.verificationUri
14934
+ authRequestId: data.verification.authRequestId,
14935
+ verificationUrl: data.verification.verificationUrl
14986
14936
  }
14987
14937
  },
14988
- nextActions: nextActionsForPendingLogin(data.verification.userCode, data.verification.verificationUri)
14938
+ nextActions: nextActionsForPendingLogin(data.verification.authRequestId, data.verification.verificationUrl)
14989
14939
  });
14990
14940
  return;
14991
14941
  }
14992
14942
  const outputData = {
14993
14943
  ...data,
14994
- event: "auth_login.completed"
14944
+ event: "login.completed"
14995
14945
  };
14996
14946
  runtime.output.success(outputData, {
14997
14947
  command: invokedCommand,
14998
14948
  entity: {
14999
14949
  agentName: data.agentName,
15000
- event: "auth_login.completed",
14950
+ event: "login.completed",
15001
14951
  loggedIn: data.loggedIn,
15002
- mode,
15003
14952
  outcome: data.outcome
15004
14953
  },
15005
- nextActions: nextActionsForLogin(data, mode)
14954
+ nextActions: nextActionsForLogin(data)
15006
14955
  });
15007
14956
  };
15008
- const executeAuthLoginInvocation = async (runtime, invocation) => {
15009
- if (invocation.apiKey !== void 0) {
15010
- await runLoginFlow(runtime, {
15011
- apiKey: invocation.apiKey,
15012
- mode: "apiKey"
15013
- });
15014
- return;
15015
- }
15016
- await runLoginFlow(runtime, { mode: "device" });
14957
+ const executeLoginInvocation = async (runtime, _invocation) => {
14958
+ await runLoginFlow(runtime, {});
15017
14959
  };
15018
- const executeAuthStatusInvocation = async (runtime) => {
15019
- const command = cliCommands.auth.status();
15020
- const data = ensureSuccess(await runAuthStatusCommand(runtime.context), runtime, { command });
15021
- runtime.output.success(data, {
14960
+ const executeLogoutInvocation = async (runtime) => {
14961
+ const command = cliCommands.logout.command();
14962
+ const data = ensureSuccess(await runLogoutCommand(runtime.context), runtime, { command });
14963
+ const outputData = {
14964
+ ...data,
14965
+ event: "logout.completed"
14966
+ };
14967
+ runtime.output.success(outputData, {
15022
14968
  command,
15023
14969
  entity: {
15024
- apiKeySource: data.apiKeySource,
15025
- loggedIn: data.loggedIn
14970
+ event: "logout.completed",
14971
+ localStateCleared: data.localStateCleared,
14972
+ remoteSignedOut: data.remoteSignedOut
15026
14973
  },
15027
- nextActions: nextActionsForAuthStatus(data)
14974
+ nextActions: [nextAction("login", "Authenticate again", cliCommands.login.command(), "Sign-out completed; run login when you want to reconnect this installation.", "after_logout")]
15028
14975
  });
15029
14976
  };
15030
- const executeAuthLogoutInvocation = async (runtime) => {
15031
- const command = cliCommands.auth.logout();
15032
- const data = ensureSuccess(await runAuthLogoutCommand(runtime.context), runtime, { command });
15033
- runtime.output.success(data, {
14977
+ const executeResetInvocation = async (runtime) => {
14978
+ const command = cliCommands.reset.command();
14979
+ const data = ensureSuccess(await runResetCommand(runtime.context), runtime, { command });
14980
+ const outputData = {
14981
+ ...data,
14982
+ event: "reset.completed"
14983
+ };
14984
+ runtime.output.success(outputData, {
15034
14985
  command,
15035
14986
  entity: {
15036
- localCredentialsDeleted: data.localCredentialsDeleted,
15037
- revoked: data.revoked
14987
+ event: "reset.completed",
14988
+ installationReset: data.installationReset,
14989
+ localStateCleared: data.localStateCleared,
14990
+ remoteReset: data.remoteReset
15038
14991
  },
15039
- nextActions: [nextAction("login", "Authenticate again", cliCommands.auth.login(), "Logout completed; authenticate again before further Codemode commands.", "after_logout")]
14992
+ nextActions: [nextAction("login", "Authenticate this fresh install", cliCommands.login.command(), "Reset completed; run login to create or reconnect this installation.", "after_reset"), nextAction("inspect_status", "Inspect status", cliCommands.status.command(), "Inspect the fresh-install CLI state and diagnostics.", "after_reset")]
15040
14993
  });
15041
14994
  };
15042
14995
  const executeCatalogInvocation = async (runtime, invocation) => {
15043
- if (invocation.toolName !== void 0 && invocation.serverId !== void 0) {
15044
- const command = cliCommands.catalog.toolDetail(invocation.serverId, invocation.toolName, invocation.orgSlug);
15045
- const data = ensureSuccess(await runCatalogToolDetailCommand(runtime.context, {
15046
- includeDebug: runtime.output.debug,
15047
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
14996
+ const formatPaginationDetails = () => {
14997
+ return `${invocation.cursor === void 0 ? "" : `--cursor ${invocation.cursor} `}${invocation.limit === void 0 ? "" : `--limit ${invocation.limit}`}`.trim();
14998
+ };
14999
+ const toCatalogExecutionPlan = () => {
15000
+ if (invocation.serverId === void 0) {
15001
+ if (invocation.example) return Result.err(new ValidationError({
15002
+ details: "--example without <server-id> <tool-name>",
15003
+ message: "Invalid catalog options. --example requires <server-id> <tool-name>.",
15004
+ recovery: { command: cliCommands.catalog.command() }
15005
+ }));
15006
+ return Result.ok({
15007
+ cursor: invocation.cursor,
15008
+ kind: "summary",
15009
+ limit: invocation.limit
15010
+ });
15011
+ }
15012
+ if (invocation.toolName === void 0) {
15013
+ if (invocation.cursor !== void 0 || invocation.limit !== void 0) return Result.err(new ValidationError({
15014
+ details: formatPaginationDetails(),
15015
+ message: "Invalid catalog options. --cursor and --limit are only valid for `ogment catalog`.",
15016
+ recovery: { command: cliCommands.catalog.command() }
15017
+ }));
15018
+ if (invocation.example) return Result.err(new ValidationError({
15019
+ details: `--example without tool name for ${invocation.serverId}`,
15020
+ message: "Invalid catalog options. --example requires <tool-name>.",
15021
+ recovery: { command: cliCommands.catalog.server(invocation.serverId) }
15022
+ }));
15023
+ return Result.ok({
15024
+ kind: "tools",
15025
+ serverId: invocation.serverId
15026
+ });
15027
+ }
15028
+ if (invocation.cursor !== void 0 || invocation.limit !== void 0) return Result.err(new ValidationError({
15029
+ details: formatPaginationDetails(),
15030
+ message: "Invalid catalog options. --cursor and --limit are only valid for `ogment catalog`.",
15031
+ recovery: { command: cliCommands.catalog.tool(invocation.serverId, invocation.toolName, { example: invocation.example }) }
15032
+ }));
15033
+ return Result.ok({
15034
+ example: invocation.example,
15035
+ kind: "tool",
15048
15036
  serverId: invocation.serverId,
15049
15037
  toolName: invocation.toolName
15050
- }), runtime, {
15051
- command,
15052
- entity: {
15053
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15054
- serverId: invocation.serverId,
15055
- toolName: invocation.toolName
15056
- }
15057
- });
15058
- runtime.output.success(data, {
15059
- command,
15060
- entity: {
15061
- orgSlug: data.server.orgSlug,
15062
- serverId: data.server.serverId,
15063
- toolName: data.tool.name
15064
- },
15065
- nextActions: nextActionsForCatalogToolDetail(data)
15066
- });
15067
- return;
15068
- }
15069
- if (invocation.serverId !== void 0) {
15070
- const command = cliCommands.catalog.detail(invocation.serverId, invocation.orgSlug);
15071
- const data = ensureSuccess(await runCatalogServerDetailCommand(runtime.context, {
15072
- includeDebug: runtime.output.debug,
15073
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15074
- serverId: invocation.serverId
15075
- }), runtime, {
15076
- command,
15077
- entity: {
15078
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15079
- serverId: invocation.serverId
15080
- }
15081
- });
15082
- runtime.output.success(data, {
15083
- command,
15084
- entity: {
15085
- orgSlug: data.server.orgSlug,
15086
- serverId: data.server.serverId
15087
- },
15088
- nextActions: nextActionsForCatalogServerDetail(data)
15089
15038
  });
15090
- return;
15091
- }
15092
- const command = cliCommands.catalog.summary({
15093
- ...invocation.cursor === void 0 ? {} : { cursor: invocation.cursor },
15094
- ...invocation.limit === void 0 ? {} : { limit: invocation.limit },
15095
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug }
15096
- });
15097
- const data = ensureSuccess(await runCatalogCommand(runtime.context, {
15098
- ...invocation.cursor === void 0 ? {} : { cursor: invocation.cursor },
15099
- ...invocation.limit === void 0 ? {} : { limit: invocation.limit },
15100
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug }
15101
- }), runtime, {
15102
- command,
15103
- entity: {
15104
- cursor: invocation.cursor ?? null,
15105
- limit: invocation.limit ?? null,
15106
- orgSlug: invocation.orgSlug ?? null
15107
- }
15108
- });
15109
- const outputData = {
15110
- failures: data.failures,
15111
- servers: data.servers
15112
15039
  };
15113
- runtime.output.success(outputData, {
15114
- command,
15115
- entity: {
15116
- cursor: invocation.cursor ?? null,
15117
- failedServerCount: data.failures.length,
15118
- limit: invocation.limit ?? null,
15119
- orgSlug: invocation.orgSlug ?? null,
15120
- serverCount: data.servers.length
15121
- },
15122
- nextActions: nextActionsForCatalogSummary(outputData, {
15123
- limit: invocation.limit ?? null,
15124
- nextCursor: data.nextCursor,
15125
- orgSlug: invocation.orgSlug ?? null
15126
- }),
15127
- pagination: { nextCursor: data.nextCursor }
15128
- });
15129
- };
15130
- const executeSearchInvocation = async (runtime, invocation) => {
15131
- const codeSource = codeSourceFromValue(invocation.code);
15132
- const command = codeSource === "stdin" ? cliCommands.search.stdinCode(invocation.serverId, invocation.orgSlug) : cliCommands.search.withCodeValue(invocation.serverId, invocation.code, invocation.orgSlug);
15133
- const data = ensureSuccess(await runSearchCommand(runtime.context, {
15134
- code: invocation.code,
15135
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15136
- serverId: invocation.serverId
15137
- }), runtime, {
15138
- command,
15139
- entity: {
15140
- codeSource,
15141
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15142
- serverId: invocation.serverId
15040
+ const planResult = toCatalogExecutionPlan();
15041
+ if (Result.isError(planResult)) throw planResult.error;
15042
+ switch (planResult.value.kind) {
15043
+ case "summary": {
15044
+ const plan = planResult.value;
15045
+ const command = cliCommands.catalog.summary({
15046
+ ...plan.cursor === void 0 ? {} : { cursor: plan.cursor },
15047
+ ...plan.limit === void 0 ? {} : { limit: plan.limit }
15048
+ });
15049
+ const data = ensureSuccess(await runCatalogCommand(runtime.context, {
15050
+ ...plan.cursor === void 0 ? {} : { cursor: plan.cursor },
15051
+ includeDebug: runtime.output.debug,
15052
+ ...plan.limit === void 0 ? {} : { limit: plan.limit }
15053
+ }), runtime, {
15054
+ command,
15055
+ entity: {
15056
+ cursor: plan.cursor ?? null,
15057
+ limit: plan.limit ?? null
15058
+ }
15059
+ });
15060
+ const outputData = {
15061
+ failures: data.failures,
15062
+ servers: data.servers
15063
+ };
15064
+ runtime.output.success(outputData, {
15065
+ command,
15066
+ entity: {
15067
+ cursor: plan.cursor ?? null,
15068
+ failedServerCount: data.failures.length,
15069
+ limit: plan.limit ?? null,
15070
+ serverCount: data.servers.length
15071
+ },
15072
+ nextActions: nextActionsForCatalogSummary(outputData, {
15073
+ limit: plan.limit ?? null,
15074
+ nextCursor: data.nextCursor
15075
+ }),
15076
+ pagination: { nextCursor: data.nextCursor }
15077
+ });
15078
+ return;
15143
15079
  }
15144
- });
15145
- runtime.output.success(data, {
15146
- command,
15147
- entity: {
15148
- codeSource,
15149
- ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15150
- serverId: data.serverId
15151
- },
15152
- nextActions: nextActionsForSearch(data)
15153
- });
15080
+ case "tools": {
15081
+ const command = cliCommands.catalog.server(planResult.value.serverId);
15082
+ const data = ensureSuccess(await runCatalogToolsCommand(runtime.context, { serverId: planResult.value.serverId }), runtime, {
15083
+ command,
15084
+ entity: { serverId: planResult.value.serverId }
15085
+ });
15086
+ runtime.output.success(data, {
15087
+ command,
15088
+ entity: {
15089
+ serverId: data.server.serverId,
15090
+ toolCount: data.tools.length
15091
+ },
15092
+ nextActions: nextActionsForCatalogTools(data)
15093
+ });
15094
+ return;
15095
+ }
15096
+ case "tool": {
15097
+ const command = cliCommands.catalog.tool(planResult.value.serverId, planResult.value.toolName, { example: planResult.value.example });
15098
+ const data = ensureSuccess(await runCatalogToolDetailsCommand(runtime.context, {
15099
+ serverId: planResult.value.serverId,
15100
+ toolName: planResult.value.toolName
15101
+ }), runtime, {
15102
+ command,
15103
+ entity: {
15104
+ serverId: planResult.value.serverId,
15105
+ toolName: planResult.value.toolName
15106
+ }
15107
+ });
15108
+ const exampleInput = toJsonValue(buildJsonSchemaExample(data.inputSchema));
15109
+ const outputData = planResult.value.example ? {
15110
+ ...data,
15111
+ exampleInput
15112
+ } : data;
15113
+ runtime.output.success(outputData, {
15114
+ command,
15115
+ entity: {
15116
+ serverId: data.server.serverId,
15117
+ toolName: data.name
15118
+ },
15119
+ nextActions: nextActionsForCatalogToolDetails(data, exampleInput)
15120
+ });
15121
+ return;
15122
+ }
15123
+ }
15154
15124
  };
15155
- const executeExecuteInvocation = async (runtime, invocation) => {
15156
- const codeSource = codeSourceFromValue(invocation.code);
15157
- const inputSource = inputSourceFromValue(invocation.input);
15158
- const command = codeSource === "stdin" ? cliCommands.execute.stdinCode(invocation.serverId, invocation.orgSlug) : cliCommands.execute.withCodeAndInputValue(invocation.serverId, invocation.code, invocation.input, invocation.orgSlug);
15159
- const data = ensureSuccess(await runExecuteCommand(runtime.context, {
15160
- code: invocation.code,
15125
+ const executeInvokeInvocation = async (runtime, invocation) => {
15126
+ let inputSource = "none";
15127
+ let command = cliCommands.invoke.command(invocation.serverId, invocation.toolName, invocation.orgSlug);
15128
+ if (invocation.input !== void 0) if (invocation.input === "-") {
15129
+ inputSource = "stdin";
15130
+ command = cliCommands.invoke.stdin(invocation.serverId, invocation.toolName, invocation.orgSlug);
15131
+ } else if (invocation.input.startsWith("@")) {
15132
+ inputSource = "file";
15133
+ command = cliCommands.invoke.withInputValue(invocation.serverId, invocation.toolName, invocation.input, invocation.orgSlug);
15134
+ } else {
15135
+ inputSource = "inline_json";
15136
+ command = cliCommands.invoke.inlineJson(invocation.serverId, invocation.toolName, invocation.orgSlug);
15137
+ }
15138
+ const data = ensureSuccess(await runInvokeCommand(runtime.context, {
15161
15139
  input: invocation.input,
15162
15140
  ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15163
- serverId: invocation.serverId
15141
+ serverId: invocation.serverId,
15142
+ toolName: invocation.toolName
15164
15143
  }), runtime, {
15165
15144
  command,
15166
15145
  entity: {
15167
- codeSource,
15168
15146
  inputSource,
15169
15147
  ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15170
- serverId: invocation.serverId
15148
+ serverId: invocation.serverId,
15149
+ toolName: invocation.toolName
15171
15150
  }
15172
15151
  });
15173
15152
  runtime.output.success(data, {
15174
15153
  command,
15175
15154
  entity: {
15176
- codeSource,
15177
15155
  inputSource,
15178
15156
  ...invocation.orgSlug === void 0 ? {} : { orgSlug: invocation.orgSlug },
15179
- serverId: data.serverId
15157
+ serverId: data.serverId,
15158
+ toolName: data.toolName
15180
15159
  },
15181
- nextActions: nextActionsForExecute(data)
15160
+ nextActions: nextActionsForInvoke(data)
15182
15161
  });
15183
15162
  };
15184
15163
  const executeStatusInvocation = async (runtime) => {
@@ -15197,32 +15176,29 @@ const executeRootInvocation = (runtime) => {
15197
15176
  runtime.output.success({ commands: cliCommands.root.commandsSurface() }, {
15198
15177
  command: cliCommands.root.command(),
15199
15178
  entity: null,
15200
- nextActions: [nextAction("login", "Authenticate", cliCommands.auth.login(), "Authenticate first so catalog, search, and execute commands can run.", "immediate"), nextAction("catalog", "Discover servers", cliCommands.catalog.command(), "List accessible servers before running Codemode search or execute.", "after_auth")]
15179
+ nextActions: [nextAction("login", "Authenticate", cliCommands.login.command(), "Authenticate first so catalog and invoke commands can run.", "immediate"), nextAction("catalog", "Discover servers", cliCommands.catalog.command(), "List accessible servers and tool counts.", "after_auth")]
15201
15180
  });
15202
15181
  };
15203
15182
  const executeInvocation = async (runtime, invocation) => {
15204
15183
  switch (invocation.kind) {
15205
- case "auth_login":
15206
- await executeAuthLoginInvocation(runtime, invocation);
15184
+ case "login":
15185
+ await executeLoginInvocation(runtime, invocation);
15207
15186
  return;
15208
- case "auth_logout":
15209
- await executeAuthLogoutInvocation(runtime);
15187
+ case "logout":
15188
+ await executeLogoutInvocation(runtime);
15210
15189
  return;
15211
- case "auth_status":
15212
- await executeAuthStatusInvocation(runtime);
15190
+ case "reset":
15191
+ await executeResetInvocation(runtime);
15213
15192
  return;
15214
15193
  case "catalog":
15215
15194
  await executeCatalogInvocation(runtime, invocation);
15216
15195
  return;
15217
- case "execute":
15218
- await executeExecuteInvocation(runtime, invocation);
15196
+ case "invoke":
15197
+ await executeInvokeInvocation(runtime, invocation);
15219
15198
  return;
15220
15199
  case "root":
15221
15200
  executeRootInvocation(runtime);
15222
15201
  return;
15223
- case "search":
15224
- await executeSearchInvocation(runtime, invocation);
15225
- return;
15226
15202
  case "status":
15227
15203
  await executeStatusInvocation(runtime);
15228
15204
  return;
@@ -15285,19 +15261,19 @@ const nextActionForParseError = (scope, helpCommand) => {
15285
15261
  };
15286
15262
  };
15287
15263
  const parseActionsForScope = (scope, helpAction) => {
15288
- if (scope === "auth") return [
15264
+ if (scope === "login" || scope === "logout" || scope === "reset") return [
15289
15265
  {
15290
- command: cliCommands.auth.login(),
15291
- id: "auth_login",
15292
- reason: "Authenticate with device flow.",
15293
- title: "Auth login",
15266
+ command: cliCommands.login.command(),
15267
+ id: "login",
15268
+ reason: "Authenticate this CLI installation.",
15269
+ title: "Login",
15294
15270
  when: "immediate"
15295
15271
  },
15296
15272
  {
15297
- command: cliCommands.auth.status(),
15298
- id: "auth_status",
15299
- reason: "Check current local authentication state.",
15300
- title: "Auth status",
15273
+ command: cliCommands.status.command(),
15274
+ id: "status",
15275
+ reason: "Inspect the current CLI state and diagnostics.",
15276
+ title: "Status",
15301
15277
  when: "immediate"
15302
15278
  },
15303
15279
  helpAction
@@ -15305,22 +15281,15 @@ const parseActionsForScope = (scope, helpAction) => {
15305
15281
  if (scope === "catalog") return [{
15306
15282
  command: cliCommands.catalog.command(),
15307
15283
  id: "catalog_summary",
15308
- reason: "List available servers before selecting a Codemode target.",
15284
+ reason: "List available servers and follow progressive discovery.",
15309
15285
  title: "Catalog servers",
15310
15286
  when: "immediate"
15311
15287
  }, helpAction];
15312
- if (scope === "search") return [{
15288
+ if (scope === "invoke") return [{
15313
15289
  command: cliCommands.catalog.command(),
15314
- id: "search_prepare",
15315
- reason: "Discover servers before running Codemode search.",
15316
- title: "Discover servers",
15317
- when: "immediate"
15318
- }, helpAction];
15319
- if (scope === "execute") return [{
15320
- command: cliCommands.catalog.command(),
15321
- id: "execute_prepare",
15322
- reason: "Discover servers before running Codemode execute.",
15323
- title: "Discover servers",
15290
+ id: "invoke_prepare",
15291
+ reason: "Discover servers and tools before invoking a target command.",
15292
+ title: "Discover tools",
15324
15293
  when: "immediate"
15325
15294
  }, helpAction];
15326
15295
  if (scope === null) return [helpAction];
@@ -60760,8 +60729,8 @@ const createAccountService = (deps) => {
60760
60729
  mapStatusError: (response, body) => {
60761
60730
  if (response.status === 401) return new AuthError({
60762
60731
  code: ERROR_CODE.authInvalidCredentials,
60763
- message: "Authentication failed. Run `ogment auth login` again.",
60764
- recovery: { command: "ogment auth login" }
60732
+ message: "Authentication failed. Run `ogment login` again.",
60733
+ recovery: { command: "ogment login" }
60765
60734
  });
60766
60735
  return new RemoteRequestError({
60767
60736
  body,
@@ -60782,7 +60751,6 @@ const createAccountService = (deps) => {
60782
60751
 
60783
60752
  //#endregion
60784
60753
  //#region src/services/auth.ts
60785
- const DEFAULT_NAMESPACE_KEY = "default";
60786
60754
  const toEndpointUrl = (baseUrl, endpoint) => {
60787
60755
  return `${baseUrl}${endpoint}`;
60788
60756
  };
@@ -60792,85 +60760,138 @@ const authStartUrl = (baseUrl) => {
60792
60760
  const authExchangeUrl = (baseUrl) => {
60793
60761
  return toEndpointUrl(baseUrl, cliEndpoints.authExchange);
60794
60762
  };
60795
- const isExpiredPendingRequest = (request, nowMs) => {
60763
+ const authLogoutUrl = (baseUrl) => {
60764
+ return toEndpointUrl(baseUrl, cliEndpoints.authLogout);
60765
+ };
60766
+ const authResetUrl = (baseUrl) => {
60767
+ return toEndpointUrl(baseUrl, cliEndpoints.authReset);
60768
+ };
60769
+ const accountMeUrl = (baseUrl) => {
60770
+ return toEndpointUrl(baseUrl, cliEndpoints.accountMe);
60771
+ };
60772
+ const toLoginPendingInfo = (request) => {
60773
+ if (request === null) return null;
60774
+ return {
60775
+ authRequestId: request.authRequestId,
60776
+ verificationUrl: request.verificationUrl
60777
+ };
60778
+ };
60779
+ const isExpiredCurrentAuthRequest = (request, nowMs) => {
60796
60780
  const parsedExpiresAt = Date.parse(request.expiresAt);
60797
60781
  return !Number.isNaN(parsedExpiresAt) && parsedExpiresAt <= nowMs;
60798
60782
  };
60799
60783
  const createAuthService = (deps) => {
60800
60784
  const now = deps.now ?? Date.now;
60801
- const storeApprovedAuth = (approvedAuth, namespaceKey = DEFAULT_NAMESPACE_KEY) => {
60802
- return deps.credentialsStore.storeApprovedAuth({
60803
- agentName: approvedAuth.agentName,
60804
- apiKey: approvedAuth.apiKey
60805
- }, namespaceKey);
60806
- };
60807
- const saveApiKeyAuth = (approvedAuth) => {
60785
+ const storeApprovedAuth = (approvedAuth) => {
60808
60786
  return deps.credentialsStore.save({
60787
+ agentId: approvedAuth.agentId,
60809
60788
  agentName: approvedAuth.agentName,
60810
- apiKey: approvedAuth.apiKey
60789
+ apiKey: approvedAuth.apiKey,
60790
+ credentialId: approvedAuth.credentialId,
60791
+ signedInAt: new Date(now()).toISOString()
60811
60792
  });
60812
60793
  };
60813
- const tryExchangePendingRequests = async () => {
60814
- const installationIdResult = deps.credentialsStore.getInstallationId();
60815
- if (Result.isError(installationIdResult)) return installationIdResult;
60816
- const pendingRequestsResult = deps.credentialsStore.listPendingRequests();
60817
- if (Result.isError(pendingRequestsResult)) return pendingRequestsResult;
60818
- const pendingRequests = [...pendingRequestsResult.value].toSorted((a, b) => {
60819
- return a.createdAt.localeCompare(b.createdAt);
60794
+ const loadLocalAuthSnapshot = () => {
60795
+ const installationId = deps.credentialsStore.getInstallationId();
60796
+ if (Result.isError(installationId)) return installationId;
60797
+ const session = deps.credentialsStore.load();
60798
+ if (Result.isError(session)) return session;
60799
+ const currentAuthRequest = deps.credentialsStore.getCurrentAuthRequest();
60800
+ if (Result.isError(currentAuthRequest)) return currentAuthRequest;
60801
+ return Result.ok({
60802
+ currentAuthRequest: currentAuthRequest.value,
60803
+ installationId: installationId.value,
60804
+ session: session.value
60820
60805
  });
60821
- for (const pendingRequest of pendingRequests) {
60822
- if (isExpiredPendingRequest(pendingRequest, now())) {
60823
- const deleteResult = deps.credentialsStore.deletePendingRequest(pendingRequest.authRequestId);
60824
- if (Result.isError(deleteResult)) return deleteResult;
60825
- continue;
60826
- }
60827
- const exchangePayload = await requestJson(deps.httpClient, authExchangeUrl(deps.baseUrl), authExchangeSchema, {
60828
- body: JSON.stringify({
60829
- authRequestId: pendingRequest.authRequestId,
60830
- installationId: installationIdResult.value,
60831
- namespaceKey: pendingRequest.namespaceKey
60832
- }),
60833
- headers: { "Content-Type": "application/json" },
60834
- method: "POST"
60835
- }, {
60836
- context: "auth exchange response",
60837
- mapStatusError: (response, body) => new RemoteRequestError({
60806
+ };
60807
+ const clearCurrentAuthRequest = () => {
60808
+ return deps.credentialsStore.clearCurrentAuthRequest();
60809
+ };
60810
+ const toStoredAuthorizationHeader = (session) => {
60811
+ return session === null ? null : `Bearer ${session.apiKey}`;
60812
+ };
60813
+ const validateStoredCredentials = async (apiKey) => {
60814
+ const response = await requestJson(deps.httpClient, accountMeUrl(deps.baseUrl), accountMeSchema, { headers: { Authorization: `Bearer ${apiKey}` } }, {
60815
+ context: "account response",
60816
+ mapStatusError: (httpResponse, body) => {
60817
+ if (httpResponse.status === 401) return new AuthError({
60818
+ code: ERROR_CODE.authInvalidCredentials,
60819
+ message: "Stored CLI session is invalid. Run `ogment login` to sign in again.",
60820
+ recovery: { command: "ogment login" }
60821
+ });
60822
+ return new RemoteRequestError({
60838
60823
  body,
60839
- httpStatus: response.status,
60840
- message: "Failed to exchange pending CLI auth",
60841
- operation: "auth/exchange",
60824
+ httpStatus: httpResponse.status,
60825
+ message: "Failed to validate current CLI session",
60826
+ operation: "account/fetch",
60842
60827
  raw: body,
60843
60828
  source: "http"
60844
- }),
60845
- operation: "auth/exchange"
60846
- });
60847
- if (Result.isError(exchangePayload)) return exchangePayload;
60848
- const exchangeData = exchangePayload.value.data;
60849
- if (exchangeData.status === "authorization_pending") continue;
60850
- if (exchangeData.status === "approved") {
60851
- const storeResult = storeApprovedAuth({
60852
- agentName: exchangeData.agentName,
60853
- apiKey: exchangeData.apiKey
60854
- }, pendingRequest.namespaceKey);
60855
- if (Result.isError(storeResult)) return storeResult;
60856
- return Result.ok({
60857
- agentName: exchangeData.agentName,
60858
- apiKey: exchangeData.apiKey
60859
60829
  });
60860
- }
60861
- const deleteResult = deps.credentialsStore.deletePendingRequest(pendingRequest.authRequestId);
60862
- if (Result.isError(deleteResult)) return deleteResult;
60830
+ },
60831
+ operation: "account/fetch"
60832
+ });
60833
+ if (Result.isError(response)) {
60834
+ if (response.error instanceof AuthError && response.error.code === ERROR_CODE.authInvalidCredentials) return Result.ok(false);
60835
+ return response;
60863
60836
  }
60864
- return Result.ok(null);
60837
+ return Result.ok(true);
60865
60838
  };
60866
- const loginWithDevice = async (options) => {
60867
- const installationIdResult = deps.credentialsStore.getInstallationId();
60868
- if (Result.isError(installationIdResult)) return installationIdResult;
60839
+ const exchangeCurrentAuthRequest = async (snapshot) => {
60840
+ const currentAuthRequest = snapshot.currentAuthRequest;
60841
+ if (currentAuthRequest === null) return Result.ok({ kind: "none" });
60842
+ if (isExpiredCurrentAuthRequest(currentAuthRequest, now())) {
60843
+ const clearResult = clearCurrentAuthRequest();
60844
+ if (Result.isError(clearResult)) return clearResult;
60845
+ return Result.ok({ kind: "none" });
60846
+ }
60847
+ const exchangePayload = await requestJson(deps.httpClient, authExchangeUrl(deps.baseUrl), authExchangeSchema, {
60848
+ body: JSON.stringify({
60849
+ authRequestId: currentAuthRequest.authRequestId,
60850
+ installationId: snapshot.installationId
60851
+ }),
60852
+ headers: { "Content-Type": "application/json" },
60853
+ method: "POST"
60854
+ }, {
60855
+ context: "auth exchange response",
60856
+ mapStatusError: (response, body) => new RemoteRequestError({
60857
+ body,
60858
+ httpStatus: response.status,
60859
+ message: "Failed to exchange current CLI auth request",
60860
+ operation: "auth/exchange",
60861
+ raw: body,
60862
+ source: "http"
60863
+ }),
60864
+ operation: "auth/exchange"
60865
+ });
60866
+ if (Result.isError(exchangePayload)) return exchangePayload;
60867
+ const exchangeData = exchangePayload.value.data;
60868
+ if (exchangeData.status === "authorization_pending") return Result.ok({
60869
+ kind: "pending",
60870
+ request: currentAuthRequest
60871
+ });
60872
+ if (exchangeData.status === "approved") {
60873
+ const approvedAuth = {
60874
+ agentId: exchangeData.agentId,
60875
+ agentName: exchangeData.agentName,
60876
+ apiKey: exchangeData.apiKey,
60877
+ credentialId: exchangeData.credentialId
60878
+ };
60879
+ const storeResult = storeApprovedAuth(approvedAuth);
60880
+ if (Result.isError(storeResult)) return storeResult;
60881
+ return Result.ok({
60882
+ auth: approvedAuth,
60883
+ kind: "approved"
60884
+ });
60885
+ }
60886
+ const clearResult = clearCurrentAuthRequest();
60887
+ if (Result.isError(clearResult)) return clearResult;
60888
+ return Result.ok({ kind: "none" });
60889
+ };
60890
+ const startOrRecoverLogin = async (installationId, options) => {
60869
60891
  const startPayload = await requestJson(deps.httpClient, authStartUrl(deps.baseUrl), authStartSchema, {
60870
60892
  body: JSON.stringify({
60871
60893
  ...deps.executionEnvironment === void 0 ? {} : { executionEnvironment: deps.executionEnvironment },
60872
- installationId: installationIdResult.value,
60873
- namespaceKey: DEFAULT_NAMESPACE_KEY
60894
+ installationId
60874
60895
  }),
60875
60896
  headers: { "Content-Type": "application/json" },
60876
60897
  method: "POST"
@@ -60887,76 +60908,140 @@ const createAuthService = (deps) => {
60887
60908
  operation: "auth/start"
60888
60909
  });
60889
60910
  if (Result.isError(startPayload)) return startPayload;
60890
- const savePendingRequestResult = deps.credentialsStore.savePendingRequest({
60911
+ const currentAuthRequest = {
60891
60912
  authRequestId: startPayload.value.data.authRequestId,
60892
- code: startPayload.value.data.userCode,
60893
- createdAt: new Date(now()).toISOString(),
60894
60913
  expiresAt: startPayload.value.data.expiresAt,
60895
- namespaceKey: DEFAULT_NAMESPACE_KEY,
60896
60914
  verificationUrl: startPayload.value.data.verificationUrl
60897
- });
60898
- if (Result.isError(savePendingRequestResult)) return savePendingRequestResult;
60899
- const verification = {
60900
- userCode: startPayload.value.data.userCode,
60901
- verificationUri: startPayload.value.data.verificationUrl
60902
60915
  };
60903
- options.onPending?.(verification);
60916
+ const saveCurrentAuthRequestResult = deps.credentialsStore.saveCurrentAuthRequest(currentAuthRequest);
60917
+ if (Result.isError(saveCurrentAuthRequestResult)) return saveCurrentAuthRequestResult;
60918
+ if (startPayload.value.data.disposition === "reused_approved") {
60919
+ const exchangedCurrentAuthRequest = await exchangeCurrentAuthRequest({
60920
+ currentAuthRequest,
60921
+ installationId,
60922
+ session: null
60923
+ });
60924
+ if (Result.isError(exchangedCurrentAuthRequest)) return exchangedCurrentAuthRequest;
60925
+ if (exchangedCurrentAuthRequest.value.kind === "approved") return Result.ok({
60926
+ agentName: exchangedCurrentAuthRequest.value.auth.agentName,
60927
+ loggedIn: true,
60928
+ outcome: "authenticated"
60929
+ });
60930
+ }
60931
+ const verification = toLoginPendingInfo(currentAuthRequest);
60932
+ if (verification !== null) options.onPending?.(verification);
60904
60933
  return Result.ok({
60905
60934
  agentName: null,
60906
60935
  loggedIn: false,
60907
60936
  outcome: "pending_approval",
60908
- verification
60937
+ verification: verification ?? {
60938
+ authRequestId: currentAuthRequest.authRequestId,
60939
+ verificationUrl: currentAuthRequest.verificationUrl
60940
+ }
60909
60941
  });
60910
60942
  };
60911
60943
  return {
60912
60944
  login: async (options) => {
60913
- if (options.mode === "apiKey" && options.apiKey.length > 0) {
60914
- const saveResult = saveApiKeyAuth({
60915
- agentName: "CLI Agent",
60916
- apiKey: options.apiKey
60917
- });
60918
- if (Result.isError(saveResult)) return saveResult;
60919
- return Result.ok({
60920
- agentName: "CLI Agent",
60945
+ const snapshot = loadLocalAuthSnapshot();
60946
+ if (Result.isError(snapshot)) return snapshot;
60947
+ if (snapshot.value.session !== null) {
60948
+ const validationResult = await validateStoredCredentials(snapshot.value.session.apiKey);
60949
+ if (Result.isError(validationResult)) return validationResult;
60950
+ if (validationResult.value) return Result.ok({
60951
+ agentName: snapshot.value.session.agentName ?? "CLI Agent",
60921
60952
  loggedIn: true,
60922
- outcome: "authenticated"
60953
+ outcome: "already_authenticated"
60923
60954
  });
60955
+ const deleteResult = deps.credentialsStore.delete();
60956
+ if (Result.isError(deleteResult)) return deleteResult;
60924
60957
  }
60925
- if (options.mode === "apiKey") return Result.err(new ValidationError({
60926
- code: ERROR_CODE.validationInvalidInput,
60927
- message: "Missing API key value. Provide a non-empty API key.",
60928
- recovery: { command: "ogment auth login --api-key <key>" }
60929
- }));
60930
- const stored = deps.credentialsStore.load();
60931
- if (Result.isError(stored)) return stored;
60932
- if (stored.value !== null) return Result.ok({
60933
- agentName: stored.value.agentName ?? "CLI Agent",
60934
- loggedIn: true,
60935
- outcome: "already_authenticated"
60936
- });
60937
- const exchangedPendingAuth = await tryExchangePendingRequests();
60938
- if (Result.isError(exchangedPendingAuth)) return exchangedPendingAuth;
60939
- if (exchangedPendingAuth.value !== null) return Result.ok({
60940
- agentName: exchangedPendingAuth.value.agentName,
60958
+ const exchangedCurrentAuthRequest = await exchangeCurrentAuthRequest(snapshot.value);
60959
+ if (Result.isError(exchangedCurrentAuthRequest)) return exchangedCurrentAuthRequest;
60960
+ if (exchangedCurrentAuthRequest.value.kind === "approved") return Result.ok({
60961
+ agentName: exchangedCurrentAuthRequest.value.auth.agentName,
60941
60962
  loggedIn: true,
60942
60963
  outcome: "authenticated"
60943
60964
  });
60944
- return loginWithDevice(options);
60965
+ if (exchangedCurrentAuthRequest.value.kind === "pending") {
60966
+ const verification = toLoginPendingInfo(exchangedCurrentAuthRequest.value.request);
60967
+ if (verification !== null) options.onPending?.(verification);
60968
+ return Result.ok({
60969
+ agentName: null,
60970
+ loggedIn: false,
60971
+ outcome: "pending_approval",
60972
+ verification: verification ?? {
60973
+ authRequestId: exchangedCurrentAuthRequest.value.request.authRequestId,
60974
+ verificationUrl: exchangedCurrentAuthRequest.value.request.verificationUrl
60975
+ }
60976
+ });
60977
+ }
60978
+ return startOrRecoverLogin(snapshot.value.installationId, options);
60945
60979
  },
60946
60980
  logout: async () => {
60947
- const stored = deps.credentialsStore.load();
60948
- if (Result.isError(stored)) return stored;
60949
- const pendingRequestsResult = deps.credentialsStore.listPendingRequests();
60950
- if (Result.isError(pendingRequestsResult)) return pendingRequestsResult;
60951
- if (!(stored.value !== null || pendingRequestsResult.value.length > 0)) return Result.ok({
60952
- localCredentialsDeleted: false,
60953
- revoked: false
60981
+ const snapshot = loadLocalAuthSnapshot();
60982
+ if (Result.isError(snapshot)) return snapshot;
60983
+ if (snapshot.value.session === null) return Result.ok({
60984
+ localStateCleared: false,
60985
+ remoteSignedOut: false
60954
60986
  });
60987
+ const storedAuthorizationHeader = toStoredAuthorizationHeader(snapshot.value.session);
60988
+ let remoteSignedOut = false;
60989
+ if (storedAuthorizationHeader !== null) {
60990
+ const logoutPayload = await requestJson(deps.httpClient, authLogoutUrl(deps.baseUrl), authLogoutSchema, {
60991
+ headers: { Authorization: storedAuthorizationHeader },
60992
+ method: "POST"
60993
+ }, {
60994
+ context: "auth logout response",
60995
+ mapStatusError: (response, body) => new RemoteRequestError({
60996
+ body,
60997
+ httpStatus: response.status,
60998
+ message: "Failed to sign out current CLI session",
60999
+ operation: "auth/logout",
61000
+ raw: body,
61001
+ source: "http"
61002
+ }),
61003
+ operation: "auth/logout"
61004
+ });
61005
+ if (Result.isOk(logoutPayload)) remoteSignedOut = true;
61006
+ }
60955
61007
  const deleteResult = deps.credentialsStore.delete();
60956
61008
  if (Result.isError(deleteResult)) return deleteResult;
60957
61009
  return Result.ok({
60958
- localCredentialsDeleted: true,
60959
- revoked: false
61010
+ localStateCleared: true,
61011
+ remoteSignedOut
61012
+ });
61013
+ },
61014
+ reset: async () => {
61015
+ const snapshot = loadLocalAuthSnapshot();
61016
+ if (Result.isError(snapshot)) return snapshot;
61017
+ const storedAuthorizationHeader = toStoredAuthorizationHeader(snapshot.value.session);
61018
+ const remoteResetResult = await requestJson(deps.httpClient, authResetUrl(deps.baseUrl), authResetSchema, {
61019
+ body: JSON.stringify({ installationId: snapshot.value.installationId }),
61020
+ headers: {
61021
+ "Content-Type": "application/json",
61022
+ ...storedAuthorizationHeader === null ? {} : { Authorization: storedAuthorizationHeader }
61023
+ },
61024
+ method: "POST"
61025
+ }, {
61026
+ context: "auth reset response",
61027
+ mapStatusError: (response, body) => new RemoteRequestError({
61028
+ body,
61029
+ httpStatus: response.status,
61030
+ message: "Failed to reset current CLI installation",
61031
+ operation: "auth/reset",
61032
+ raw: body,
61033
+ source: "http"
61034
+ }),
61035
+ operation: "auth/reset"
61036
+ });
61037
+ const remoteReset = Result.isOk(remoteResetResult);
61038
+ const localStateCleared = snapshot.value.session !== null || snapshot.value.currentAuthRequest !== null;
61039
+ const resetLocalStateResult = deps.credentialsStore.reset();
61040
+ if (Result.isError(resetLocalStateResult)) return resetLocalStateResult;
61041
+ return Result.ok({
61042
+ installationReset: true,
61043
+ localStateCleared,
61044
+ remoteReset
60960
61045
  });
60961
61046
  },
60962
61047
  resolveApiKey: async (overrideApiKey) => {
@@ -60967,42 +61052,16 @@ const createAuthService = (deps) => {
60967
61052
  });
60968
61053
  if (resolution.apiKey !== null) return Result.ok(resolution.apiKey);
60969
61054
  if (resolution.source === "credentialsError" && resolution.loadError) return Result.err(resolution.loadError);
60970
- const exchangedPendingAuth = await tryExchangePendingRequests();
60971
- if (Result.isError(exchangedPendingAuth)) return exchangedPendingAuth;
60972
- if (exchangedPendingAuth.value !== null) return Result.ok(exchangedPendingAuth.value.apiKey);
61055
+ const snapshot = loadLocalAuthSnapshot();
61056
+ if (Result.isError(snapshot)) return snapshot;
61057
+ const exchangedCurrentAuthRequest = await exchangeCurrentAuthRequest(snapshot.value);
61058
+ if (Result.isError(exchangedCurrentAuthRequest)) return exchangedCurrentAuthRequest;
61059
+ if (exchangedCurrentAuthRequest.value.kind === "approved") return Result.ok(exchangedCurrentAuthRequest.value.auth.apiKey);
60973
61060
  return Result.err(new AuthError({
60974
61061
  code: ERROR_CODE.authRequired,
60975
- message: "Not logged in. Run `ogment auth login` or set OGMENT_API_KEY.",
60976
- recovery: { command: "ogment auth login" }
61062
+ message: "Not logged in. Run `ogment login` or set OGMENT_API_KEY.",
61063
+ recovery: { command: "ogment login" }
60977
61064
  }));
60978
- },
60979
- status: async (overrideApiKey) => {
60980
- const resolution = resolveApiKey({
60981
- apiKeyOverride: overrideApiKey,
60982
- credentialsStore: deps.credentialsStore,
60983
- envApiKey: deps.envApiKey
60984
- });
60985
- if (resolution.source === "credentialsError" && resolution.loadError) return Result.err(resolution.loadError);
60986
- if (resolution.apiKey !== null) {
60987
- const apiKeySource = resolution.source === "credentialsFile" ? "credentialsFile" : resolution.source === "apiKeyOption" ? "apiKeyOption" : "env";
60988
- return Result.ok({
60989
- agentName: resolution.agentName,
60990
- apiKeySource,
60991
- loggedIn: true
60992
- });
60993
- }
60994
- const exchangedPendingAuth = await tryExchangePendingRequests();
60995
- if (Result.isError(exchangedPendingAuth)) return exchangedPendingAuth;
60996
- if (exchangedPendingAuth.value !== null) return Result.ok({
60997
- agentName: exchangedPendingAuth.value.agentName,
60998
- apiKeySource: "credentialsFile",
60999
- loggedIn: true
61000
- });
61001
- return Result.ok({
61002
- agentName: null,
61003
- apiKeySource: "none",
61004
- loggedIn: false
61005
- });
61006
61065
  }
61007
61066
  };
61008
61067
  };
@@ -61015,9 +61074,9 @@ const maskApiKey = (apiKey) => {
61015
61074
  };
61016
61075
  const nextActionByIssueCode = (includeDebug) => {
61017
61076
  return {
61018
- auth_failed: "Run `ogment auth login` to refresh credentials.",
61077
+ auth_failed: "Run `ogment login` to refresh credentials.",
61019
61078
  credentials_load_failed: "Check file permissions and contents of `~/.config/ogment/auth-state.json`.",
61020
- no_api_key: "Run `ogment auth login` or set `OGMENT_API_KEY`.",
61079
+ no_api_key: "Run `ogment login` or set `OGMENT_API_KEY`.",
61021
61080
  unreachable: includeDebug ? "Verify `OGMENT_BASE_URL` and network connectivity." : "Verify network connectivity."
61022
61081
  };
61023
61082
  };
@@ -61056,6 +61115,8 @@ const createInfoService = (deps) => {
61056
61115
  credentialsStore: deps.credentialsStore,
61057
61116
  envApiKey: deps.envApiKey
61058
61117
  });
61118
+ const installationIdResult = deps.credentialsStore.getInstallationId();
61119
+ const installationId = Result.isOk(installationIdResult) ? installationIdResult.value : null;
61059
61120
  const selectedApiKey = apiKeyResolution.apiKey;
61060
61121
  const credentialsFileExists = existsSyncFn(deps.credentialsPath);
61061
61122
  const endpoint = `${deps.baseUrl}${cliEndpoints.accountMe}`;
@@ -61080,6 +61141,7 @@ const createInfoService = (deps) => {
61080
61141
  };
61081
61142
  const collectAccount = async () => {
61082
61143
  if (selectedApiKey === null) return {
61144
+ actingAgent: null,
61083
61145
  ...emptyAccountErrorDetails(),
61084
61146
  errorType: null,
61085
61147
  latencyMs: null,
@@ -61097,6 +61159,12 @@ const createInfoService = (deps) => {
61097
61159
  return organization.servers.map((server) => server.path);
61098
61160
  });
61099
61161
  return {
61162
+ actingAgent: accountResult.value.actingAgent === null ? null : {
61163
+ agentId: accountResult.value.actingAgent.agentId,
61164
+ agentName: accountResult.value.actingAgent.agentName,
61165
+ boundInstallationId: accountResult.value.actingAgent.boundInstallationId,
61166
+ boundToCurrentInstallation: installationId === null || accountResult.value.actingAgent.boundInstallationId === null ? null : accountResult.value.actingAgent.boundInstallationId === installationId
61167
+ },
61100
61168
  ...emptyAccountErrorDetails(),
61101
61169
  errorType: null,
61102
61170
  latencyMs: accountElapsedMs,
@@ -61123,6 +61191,7 @@ const createInfoService = (deps) => {
61123
61191
  break;
61124
61192
  }
61125
61193
  return {
61194
+ actingAgent: null,
61126
61195
  ..."code" in accountResult.error ? { errorCode: String(accountResult.error.code) } : { errorCode: null },
61127
61196
  ..."httpStatus" in accountResult.error ? { errorHttpStatus: typeof accountResult.error.httpStatus === "number" ? accountResult.error.httpStatus : null } : { errorHttpStatus: null },
61128
61197
  ..."mcpCode" in accountResult.error ? { errorMcpCode: typeof accountResult.error.mcpCode === "number" ? accountResult.error.mcpCode : null } : { errorMcpCode: null },
@@ -61168,13 +61237,18 @@ const createInfoService = (deps) => {
61168
61237
  code: "unexpected_diagnostic_error",
61169
61238
  message: `Unexpected diagnostic error: ${account.message ?? "unknown error"}`
61170
61239
  });
61240
+ if (Result.isError(installationIdResult)) issues.push({
61241
+ code: "credentials_load_failed",
61242
+ message: `Failed to load installation identity: ${installationIdResult.error.message}`
61243
+ });
61171
61244
  return {
61172
61245
  auth: {
61173
61246
  apiKeyPresent: selectedApiKey !== null,
61174
61247
  apiKeyPreview: selectedApiKey === null ? null : maskApiKey(selectedApiKey),
61175
61248
  apiKeySource: apiKeyResolution.source,
61176
61249
  credentialsFileExists,
61177
- credentialsFileLoadError: apiKeyResolution.loadError?.message ?? null
61250
+ credentialsFileLoadError: apiKeyResolution.loadError?.message ?? null,
61251
+ installationId
61178
61252
  },
61179
61253
  config: {
61180
61254
  baseUrl: deps.baseUrl,
@@ -61191,10 +61265,13 @@ const createInfoService = (deps) => {
61191
61265
  ],
61192
61266
  quickCommands: [
61193
61267
  "ogment status",
61194
- "ogment auth login",
61268
+ "ogment login",
61269
+ "ogment logout",
61270
+ "ogment reset",
61195
61271
  "ogment catalog",
61196
- "ogment search <server-id> --code 'return input'",
61197
- "ogment execute <server-id> --code 'return input' --input '{}'"
61272
+ "ogment catalog <server-id>",
61273
+ "ogment catalog <server-id> <tool-name>",
61274
+ "ogment invoke <server-id> <tool-name> --input '{}'"
61198
61275
  ]
61199
61276
  },
61200
61277
  generatedAt: new Date(now()).toISOString(),
@@ -71903,25 +71980,6 @@ const createRemoteRequestErrorFromMcpCause = (options) => {
71903
71980
  const MCP_CONNECT_TIMEOUT_MS = 1e4;
71904
71981
  const MCP_DISCOVERY_TIMEOUT_MS = 1e4;
71905
71982
  const MCP_INVOKE_TIMEOUT_MS = 45e3;
71906
- const DEFAULT_PATH_PREFIX = "/api/v1/mcp";
71907
- const normalizePathPrefix = (value) => {
71908
- const candidate = value?.trim() || DEFAULT_PATH_PREFIX;
71909
- if (candidate.startsWith("/")) return candidate;
71910
- return `/${candidate}`;
71911
- };
71912
- const isLocalhost = (hostname) => {
71913
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.startsWith("192.168.") || hostname.endsWith(".local");
71914
- };
71915
- const buildMcpEndpointUrl = (baseUrl, pathPrefix, target) => {
71916
- const base = new URL(baseUrl);
71917
- if (isLocalhost(base.hostname)) return new URL(`${pathPrefix}/${target.orgSlug}/${target.serverPath}`, `${base.origin}/`);
71918
- if (base.hostname.startsWith("dashboard.")) {
71919
- const rootDomain = base.hostname.slice(10);
71920
- const toolPath = pathPrefix === "/code" ? `/code/${target.serverPath}` : `/${target.serverPath}`;
71921
- return new URL(`${base.protocol}//${target.orgSlug}.mcp.${rootDomain}${toolPath}`);
71922
- }
71923
- return new URL(`${pathPrefix}/${target.orgSlug}/${target.serverPath}`, `${base.origin}/`);
71924
- };
71925
71983
  const defaultCreateClient = (version) => {
71926
71984
  return new Client({
71927
71985
  name: APP_NAME,
@@ -71934,9 +71992,9 @@ const defaultCreateTransport = (url, apiKey) => {
71934
71992
  const createMcpService = (deps) => {
71935
71993
  const createClient = deps.createClient ?? (() => defaultCreateClient(deps.version));
71936
71994
  const createTransport = deps.createTransport ?? defaultCreateTransport;
71937
- const pathPrefix = normalizePathPrefix(deps.pathPrefix);
71938
71995
  const withClient = async (target, apiKey, handler) => {
71939
- const transport = createTransport(buildMcpEndpointUrl(deps.baseUrl, pathPrefix, target), apiKey);
71996
+ const endpoint = `${deps.baseUrl}/api/v1/mcp/${target.orgSlug}/${target.serverPath}`;
71997
+ const transport = createTransport(new URL(endpoint), apiKey);
71940
71998
  const client = createClient();
71941
71999
  const connectResult = await Result.tryPromise({
71942
72000
  catch: (cause) => createRemoteRequestErrorFromMcpCause({
@@ -72001,9 +72059,7 @@ const createRuntime = () => {
72001
72059
  const output = new OutputManager();
72002
72060
  const authStateStore = createFileCredentialsStore({
72003
72061
  configDir: runtimeConfig.configDir,
72004
- credentialsPath: runtimeConfig.credentialsPath,
72005
- legacyCredentialsPath: runtimeConfig.legacyCredentialsPath,
72006
- telemetryPath: runtimeConfig.telemetryPath
72062
+ credentialsPath: runtimeConfig.credentialsPath
72007
72063
  });
72008
72064
  const httpClient = createHttpClient();
72009
72065
  const services = {
@@ -72018,11 +72074,6 @@ const createRuntime = () => {
72018
72074
  executionEnvironment,
72019
72075
  httpClient
72020
72076
  }),
72021
- codemode: createMcpService({
72022
- baseUrl: runtimeConfig.baseUrl,
72023
- pathPrefix: "/code",
72024
- version: runtimeConfig.version
72025
- }),
72026
72077
  mcp: createMcpService({
72027
72078
  baseUrl: runtimeConfig.baseUrl,
72028
72079
  version: runtimeConfig.version
@@ -72128,12 +72179,9 @@ const createProgram = (runtime, parseState) => {
72128
72179
  return [
72129
72180
  "",
72130
72181
  "Examples:",
72131
- " $ ogment auth login",
72132
- " $ ogment catalog",
72133
- " $ ogment catalog billing",
72134
- " $ ogment catalog billing execute",
72135
- " $ ogment search billing --code 'return input'",
72136
- " $ ogment execute billing --code 'return input' --input '{}'",
72182
+ " $ ogment login",
72183
+ " $ ogment catalog billing create_invoice --example",
72184
+ " $ ogment invoke billing create_invoice --input '{\"amount\":100}'",
72137
72185
  "",
72138
72186
  "Run `ogment help <command>` for command-specific usage."
72139
72187
  ].join("\n");
@@ -72143,57 +72191,35 @@ const createProgram = (runtime, parseState) => {
72143
72191
  runtime.output.configure(mapGlobalOutputOptions(options));
72144
72192
  runtime.context.apiKeyOverride = options.apiKey;
72145
72193
  });
72146
- const authCommand = program.command("auth").summary("Authenticate, inspect auth state, and logout").description("Authentication workflows").helpGroup("Authentication Commands:").helpCommand("help [command]", "Display help for auth commands").addHelpText("after", ({ error }) => {
72147
- if (error) return "";
72148
- return [
72149
- "",
72150
- "Examples:",
72151
- " $ ogment auth login",
72152
- " $ ogment auth status"
72153
- ].join("\n");
72194
+ program.command("login").summary("Authenticate this CLI installation").description("Start or complete browser-based login for this installation").helpGroup("Authentication Commands:").action(() => {
72195
+ setInvocation({ kind: "login" });
72154
72196
  });
72155
- authCommand.command("login").summary("Login with device flow (default)").description("Authenticate with Ogment using device flow (recommended)").action((_, command) => {
72156
- const { apiKey } = asGlobalOptions(command);
72157
- setInvocation({
72158
- apiKey,
72159
- kind: "auth_login"
72160
- });
72197
+ program.command("logout").summary("Sign this CLI installation out").description("Sign out the current local CLI session").helpGroup("Authentication Commands:").action(() => {
72198
+ setInvocation({ kind: "logout" });
72161
72199
  });
72162
- authCommand.command("status").summary("Show current auth state").description("Show local authentication status").action(() => {
72163
- setInvocation({ kind: "auth_status" });
72200
+ program.command("reset").summary("Reset this CLI installation").description("Wipe local state and create a fresh CLI installation identity").helpGroup("Authentication Commands:").action(() => {
72201
+ setInvocation({ kind: "reset" });
72164
72202
  });
72165
- authCommand.command("logout").summary("Delete local credentials and revoke token").description("Revoke token and delete local credentials").action(() => {
72166
- setInvocation({ kind: "auth_logout" });
72167
- });
72168
- program.command("catalog").summary("Discover servers or inspect Codemode tools").description("Discover servers or inspect Codemode tools on a server").helpGroup("Discovery Commands:").argument("[serverId]", "Server id").argument("[toolName]", "Codemode tool name").addOption(new Option("--org <orgSlug>", "Organization slug").hideHelp()).addOption(new Option("--cursor <cursor>", "Pagination cursor for server discovery")).addOption(new Option("--limit <limit>", "Maximum servers to return").argParser(parseCatalogLimitOption)).action((serverId, toolName, options) => {
72169
- if (serverId !== void 0 && (options.cursor !== void 0 || options.limit !== void 0)) throw new InvalidArgumentError("--cursor and --limit are only supported for `ogment catalog`.");
72203
+ program.command("catalog [serverId] [toolName]").summary("Discover servers and inspect tools").description("Discover servers and tools with progressive disclosure").helpGroup("Discovery Commands:").addOption(new Option("--cursor <cursor>", "Pagination cursor (catalog summary only)").conflicts("example")).addOption(new Option("--limit <limit>", "Maximum servers to return (catalog summary only)").argParser(parseCatalogLimitOption).conflicts("example")).addOption(new Option("--example", "Include a generated example input payload (tool details only)").conflicts(["cursor", "limit"])).action((serverId, toolName, options) => {
72170
72204
  setInvocation({
72205
+ example: options.example === true,
72171
72206
  kind: "catalog",
72172
72207
  ...options.cursor === void 0 ? {} : { cursor: options.cursor },
72173
72208
  ...options.limit === void 0 ? {} : { limit: options.limit },
72174
- ...options.org === void 0 ? {} : { orgSlug: options.org },
72175
72209
  ...serverId === void 0 ? {} : { serverId },
72176
72210
  ...toolName === void 0 ? {} : { toolName }
72177
72211
  });
72178
72212
  });
72179
- program.command("search").summary("Search tools on a server via Codemode").description("Run Codemode search JavaScript against a server tool catalog").helpGroup("Execution Commands:").argument("<serverId>", "Server id").addOption(new Option("--org <orgSlug>", "Organization slug").hideHelp()).requiredOption("--code <value>", "JavaScript source: inline code, @path, or - for stdin").action((serverId, options) => {
72213
+ program.command("invoke").summary("Invoke a tool by <server-id> <tool-name>").description("Invoke a tool using <server-id> <tool-name>").helpGroup("Execution Commands:").argument("<serverId>", "Server id").argument("<toolName>", "Tool name").addOption(new Option("--org <orgSlug>", "Organization slug").hideHelp()).option("--input <value>", "Input payload: inline JSON object, @path, or - for stdin").action((serverId, toolName, options) => {
72180
72214
  setInvocation({
72181
- code: options.code,
72182
- kind: "search",
72183
- ...options.org === void 0 ? {} : { orgSlug: options.org },
72184
- serverId
72185
- });
72186
- });
72187
- program.command("execute").summary("Execute Codemode JavaScript on a server").description("Run Codemode execute JavaScript with optional JSON input").helpGroup("Execution Commands:").argument("<serverId>", "Server id").addOption(new Option("--org <orgSlug>", "Organization slug").hideHelp()).requiredOption("--code <value>", "JavaScript source: inline code, @path, or - for stdin").option("--input <value>", "Input payload: inline JSON object, @path, or - for stdin").action((serverId, options) => {
72188
- setInvocation({
72189
- code: options.code,
72190
- kind: "execute",
72191
72215
  input: options.input,
72216
+ kind: "invoke",
72192
72217
  ...options.org === void 0 ? {} : { orgSlug: options.org },
72193
- serverId
72218
+ serverId,
72219
+ toolName
72194
72220
  });
72195
72221
  });
72196
- program.command("status").summary("Show runtime diagnostics").description("Show runtime configuration and connectivity diagnostics").helpGroup("Diagnostics Commands:").action(() => {
72222
+ program.command("status").summary("Show runtime diagnostics and auth state").description("Show runtime configuration, connectivity, and auth diagnostics").helpGroup("Diagnostics Commands:").action(() => {
72197
72223
  setInvocation({ kind: "status" });
72198
72224
  });
72199
72225
  program.action(() => {
@@ -72220,10 +72246,12 @@ const RUNTIME_ERROR_COMMAND_PATH = "ogment <runtime_error>";
72220
72246
  const PARSE_ERROR_COMMAND_PATH = "ogment <parse_error>";
72221
72247
  const CLI_PACKAGE_NAME = "@ogment-ai/cli";
72222
72248
  const PARSE_ERROR_SCOPE_COMMAND_PATHS = {
72223
- auth: "ogment auth <parse_error>",
72249
+ login: "ogment login <parse_error>",
72250
+ logout: "ogment logout <parse_error>",
72251
+ reset: "ogment reset <parse_error>",
72224
72252
  catalog: "ogment catalog <parse_error>",
72225
- execute: "ogment execute <parse_error>",
72226
- search: "ogment search <parse_error>"
72253
+ invoke: "ogment invoke <parse_error>",
72254
+ status: "ogment status <parse_error>"
72227
72255
  };
72228
72256
  const isParseErrorTelemetryScope = (value) => {
72229
72257
  return value in PARSE_ERROR_SCOPE_COMMAND_PATHS;
@@ -72234,63 +72262,56 @@ const parseErrorCommandPath = (scope) => {
72234
72262
  if (rootScope === void 0 || !isParseErrorTelemetryScope(rootScope)) return PARSE_ERROR_COMMAND_PATH;
72235
72263
  return PARSE_ERROR_SCOPE_COMMAND_PATHS[rootScope];
72236
72264
  };
72237
- const telemetryInputModeFromExecute = (input) => {
72265
+ const telemetryInputModeFromInvoke = (input) => {
72238
72266
  if (input === void 0) return "none";
72239
72267
  if (input === "-") return "stdin";
72240
72268
  if (input.startsWith("@")) return "file";
72241
72269
  return "inline_json";
72242
72270
  };
72243
72271
  const telemetryContextResolvers = {
72244
- auth_login: (_) => {
72272
+ login: (_) => {
72245
72273
  return {
72246
- commandKind: "auth_login",
72247
- commandPath: "ogment auth login",
72274
+ commandKind: "login",
72275
+ commandPath: "ogment login",
72248
72276
  inputMode: null
72249
72277
  };
72250
72278
  },
72251
- auth_logout: (_) => {
72279
+ logout: (_) => {
72252
72280
  return {
72253
- commandKind: "auth_logout",
72254
- commandPath: "ogment auth logout",
72281
+ commandKind: "logout",
72282
+ commandPath: "ogment logout",
72255
72283
  inputMode: null
72256
72284
  };
72257
72285
  },
72258
- auth_status: (_) => {
72286
+ reset: (_) => {
72259
72287
  return {
72260
- commandKind: "auth_status",
72261
- commandPath: "ogment auth status",
72288
+ commandKind: "reset",
72289
+ commandPath: "ogment reset",
72262
72290
  inputMode: null
72263
72291
  };
72264
72292
  },
72265
72293
  catalog: (invocation) => {
72266
- if (invocation.toolName !== void 0 && invocation.serverId !== void 0) return {
72267
- commandKind: "catalog_tool_detail",
72268
- commandPath: "ogment catalog <server-id> <tool-name>",
72294
+ if (invocation.serverId === void 0) return {
72295
+ commandKind: "catalog_summary",
72296
+ commandPath: "ogment catalog",
72269
72297
  inputMode: null
72270
72298
  };
72271
- if (invocation.serverId !== void 0) return {
72272
- commandKind: "catalog_detail",
72299
+ if (invocation.toolName === void 0) return {
72300
+ commandKind: "catalog_tools",
72273
72301
  commandPath: "ogment catalog <server-id>",
72274
72302
  inputMode: null
72275
72303
  };
72276
72304
  return {
72277
- commandKind: "catalog_summary",
72278
- commandPath: "ogment catalog",
72305
+ commandKind: "catalog_tool",
72306
+ commandPath: "ogment catalog <server-id> <tool-name>",
72279
72307
  inputMode: null
72280
72308
  };
72281
72309
  },
72282
- execute: (invocation) => {
72310
+ invoke: (invocation) => {
72283
72311
  return {
72284
- commandKind: "execute",
72285
- commandPath: "ogment execute <server-id>",
72286
- inputMode: telemetryInputModeFromExecute(invocation.input)
72287
- };
72288
- },
72289
- search: (_) => {
72290
- return {
72291
- commandKind: "search",
72292
- commandPath: "ogment search <server-id>",
72293
- inputMode: null
72312
+ commandKind: "invoke",
72313
+ commandPath: "ogment invoke <server-id> <tool-name>",
72314
+ inputMode: telemetryInputModeFromInvoke(invocation.input)
72294
72315
  };
72295
72316
  },
72296
72317
  root: (_) => {
@@ -72310,13 +72331,12 @@ const telemetryContextResolvers = {
72310
72331
  };
72311
72332
  const telemetryContextFromInvocation = (invocation) => {
72312
72333
  switch (invocation.kind) {
72313
- case "auth_login": return telemetryContextResolvers.auth_login(invocation);
72314
- case "auth_logout": return telemetryContextResolvers.auth_logout(invocation);
72315
- case "auth_status": return telemetryContextResolvers.auth_status(invocation);
72334
+ case "login": return telemetryContextResolvers.login(invocation);
72335
+ case "logout": return telemetryContextResolvers.logout(invocation);
72336
+ case "reset": return telemetryContextResolvers.reset(invocation);
72316
72337
  case "catalog": return telemetryContextResolvers.catalog(invocation);
72317
- case "execute": return telemetryContextResolvers.execute(invocation);
72338
+ case "invoke": return telemetryContextResolvers.invoke(invocation);
72318
72339
  case "root": return telemetryContextResolvers.root(invocation);
72319
- case "search": return telemetryContextResolvers.search(invocation);
72320
72340
  case "status": return telemetryContextResolvers.status(invocation);
72321
72341
  }
72322
72342
  };
@@ -72350,9 +72370,7 @@ const emitRuntimeErrorTelemetry = async (output, input) => {
72350
72370
  const telemetry = createTelemetryService({
72351
72371
  authStateStore: createFileCredentialsStore({
72352
72372
  configDir: telemetryConfig.configDir,
72353
- credentialsPath: telemetryConfig.credentialsPath,
72354
- legacyCredentialsPath: telemetryConfig.legacyCredentialsPath,
72355
- telemetryPath: telemetryConfig.telemetryPath
72373
+ credentialsPath: telemetryConfig.credentialsPath
72356
72374
  }),
72357
72375
  baseUrl: telemetryConfig.baseUrl,
72358
72376
  cliVersion: telemetryConfig.version,
@@ -72391,19 +72409,21 @@ const commandContextFromInvocation = (invocation, apiKeyOverride) => {
72391
72409
  const withBase = (commandName, invocationKind, subcommand = void 0) => {
72392
72410
  return {
72393
72411
  commandName,
72394
- hasApiKeyOverride: invocation.kind === "auth_login" ? hasApiKeyOverride(invocation.apiKey) : hasApiKeyOverride(apiKeyOverride),
72412
+ hasApiKeyOverride: hasApiKeyOverride(apiKeyOverride),
72395
72413
  invocationKind,
72396
72414
  subcommand
72397
72415
  };
72398
72416
  };
72399
72417
  switch (invocation.kind) {
72400
- case "auth_login": return withBase("auth", "auth_login", "login");
72401
- case "auth_logout": return withBase("auth", "auth_logout", "logout");
72402
- case "auth_status": return withBase("auth", "auth_status", "status");
72403
- case "catalog": return withBase("catalog", "catalog", "summary");
72404
- case "execute": return withBase("execute", "execute");
72418
+ case "login": return withBase("login", "login");
72419
+ case "logout": return withBase("logout", "logout");
72420
+ case "reset": return withBase("reset", "reset");
72421
+ case "catalog":
72422
+ if (invocation.toolName !== void 0) return withBase("catalog", "catalog", "tool");
72423
+ if (invocation.serverId !== void 0) return withBase("catalog", "catalog", "server");
72424
+ return withBase("catalog", "catalog", "summary");
72425
+ case "invoke": return withBase("invoke", "invoke");
72405
72426
  case "root": return withBase("ogment", "root");
72406
- case "search": return withBase("search", "search");
72407
72427
  case "status": return withBase("status", "status");
72408
72428
  default: return assertNever(invocation);
72409
72429
  }
@@ -72555,4 +72575,4 @@ if (shouldExecuteCli(import.meta.url, process.argv[1])) await executeCli();
72555
72575
 
72556
72576
  //#endregion
72557
72577
  export { executeCli, runCli, shouldExecuteCli };
72558
- //# debugId=7f3c7b5c-dc65-451e-8bd3-f0541a4f4fdf
72578
+ //# debugId=af3eaa67-a183-47bc-ab25-5c28a25c0929