@tarileo/avileo-catalog-cli 0.3.0 → 0.3.2

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/index.js CHANGED
@@ -14729,18 +14729,19 @@ var AGENT_CAPABILITY_ACTIONS = [
14729
14729
  "assets:read",
14730
14730
  "assets:write",
14731
14731
  "inventory:read",
14732
- "inventory:write"
14732
+ "inventory:write",
14733
+ "payments:read",
14734
+ "payments:write"
14733
14735
  ];
14734
14736
  var AgentCapabilityActionSchema = external_exports.enum(AGENT_CAPABILITY_ACTIONS);
14735
14737
  var AGENT_KEY_MODES = ["read", "mutate"];
14736
14738
  var AgentKeyModeSchema = external_exports.enum(AGENT_KEY_MODES);
14737
- var AGENT_CATALOG_KEY_PRESET_ACTIONS = [
14739
+ var AGENT_KEY_READ_ACTIONS = [
14738
14740
  "business:read",
14739
14741
  "catalog:read",
14740
- "catalog:write",
14741
14742
  "assets:read",
14742
- "assets:write",
14743
- "inventory:read"
14743
+ "inventory:read",
14744
+ "payments:read"
14744
14745
  ];
14745
14746
  var AgentGrantedActionsSchema = external_exports.array(AgentCapabilityActionSchema).min(1).max(AGENT_CAPABILITY_ACTIONS.length).refine((actions) => new Set(actions).size === actions.length, {
14746
14747
  message: "Las capacidades no pueden repetirse"
@@ -15221,9 +15222,91 @@ var AgentOperationApplyEnvelopeSchema = external_exports.object({
15221
15222
  success: external_exports.literal(true),
15222
15223
  data: external_exports.record(external_exports.string(), external_exports.unknown())
15223
15224
  }).strict();
15225
+ var AGENT_PAYMENT_LINK_STATUSES = [
15226
+ "awaiting_payment",
15227
+ "verifying",
15228
+ "under_review",
15229
+ "confirmed",
15230
+ "rejected",
15231
+ "expired",
15232
+ "cancelled"
15233
+ ];
15234
+ var AgentPaymentLinkStatusSchema = external_exports.enum(AGENT_PAYMENT_LINK_STATUSES);
15235
+ var AGENT_PAYMENT_LINK_EXPECTED_METHODS = [
15236
+ "yape",
15237
+ "plin",
15238
+ "transferencia",
15239
+ "any"
15240
+ ];
15241
+ var AgentPaymentLinkExpectedMethodSchema = external_exports.enum(AGENT_PAYMENT_LINK_EXPECTED_METHODS);
15242
+ var AGENT_PAYMENT_LINK_CONFIRMED_BY = ["ai", "gateway", "manual", "platform"];
15243
+ var AgentPaymentLinkConfirmedBySchema = external_exports.enum(AGENT_PAYMENT_LINK_CONFIRMED_BY);
15244
+ var AgentPaymentLinkExtractionDtoSchema = external_exports.object({
15245
+ provider: external_exports.enum(["yape", "plin", "bbva_transfer", "unknown"]),
15246
+ /** Detected amount in soles (major units), or null when illegible. */
15247
+ detectedAmount: external_exports.number().nonnegative().multipleOf(0.01).nullable(),
15248
+ currency: external_exports.string().length(3).nullable(),
15249
+ operationNumber: external_exports.string().nullable(),
15250
+ paidAt: timestampSchema.nullable(),
15251
+ payerName: external_exports.string().nullable(),
15252
+ recipientName: external_exports.string().nullable(),
15253
+ confidence: external_exports.enum(["high", "medium", "low"]),
15254
+ signals: external_exports.array(external_exports.string())
15255
+ }).strict();
15256
+ var AgentCreatePaymentLinkInputSchema = external_exports.object({
15257
+ /** Amount in soles (major units); the backend stores amountMinor. */
15258
+ amount: external_exports.number().positive().multipleOf(0.01).max(1e6),
15259
+ currency: external_exports.string().trim().length(3).optional(),
15260
+ concept: nonEmptyTextSchema.max(200).optional(),
15261
+ expectedMethod: AgentPaymentLinkExpectedMethodSchema.optional(),
15262
+ expiresInHours: external_exports.number().int().min(1).max(720).optional(),
15263
+ customerPhone: nonEmptyTextSchema.max(20).optional(),
15264
+ idempotencyKey: nonEmptyTextSchema.max(80).optional()
15265
+ }).strict();
15266
+ var AgentPaymentLinkBaseDtoSchema = external_exports.object({
15267
+ id: uuidSchema,
15268
+ /** Requested amount in soles (major units). */
15269
+ amount: external_exports.number().positive().multipleOf(0.01),
15270
+ currency: external_exports.string().length(3),
15271
+ concept: external_exports.string().nullable(),
15272
+ expectedMethod: AgentPaymentLinkExpectedMethodSchema,
15273
+ status: AgentPaymentLinkStatusSchema,
15274
+ confirmedBy: AgentPaymentLinkConfirmedBySchema.nullable(),
15275
+ extraction: AgentPaymentLinkExtractionDtoSchema.nullable(),
15276
+ expiresAt: timestampSchema,
15277
+ createdAt: timestampSchema,
15278
+ confirmedAt: timestampSchema.nullable().optional()
15279
+ }).strict();
15280
+ var AgentPaymentLinkDtoSchema = AgentPaymentLinkBaseDtoSchema.extend({
15281
+ /** Persisted links can never recover the plaintext token URL. */
15282
+ url: external_exports.null()
15283
+ }).strict();
15284
+ var AgentCreatedPaymentLinkDtoSchema = external_exports.discriminatedUnion("replayed", [
15285
+ AgentPaymentLinkBaseDtoSchema.extend({
15286
+ url: external_exports.string().url(),
15287
+ replayed: external_exports.literal(false)
15288
+ }).strict(),
15289
+ AgentPaymentLinkBaseDtoSchema.extend({
15290
+ url: external_exports.null(),
15291
+ replayed: external_exports.literal(true)
15292
+ }).strict()
15293
+ ]);
15294
+ var isoDateOrTimestampSchema = external_exports.union([
15295
+ external_exports.string().date(),
15296
+ external_exports.string().datetime({ offset: true })
15297
+ ]);
15298
+ var AgentPaymentLinkFilterInputSchema = AgentPaginationInputSchema.extend({
15299
+ status: AgentPaymentLinkStatusSchema.optional(),
15300
+ from: isoDateOrTimestampSchema.optional(),
15301
+ to: isoDateOrTimestampSchema.optional()
15302
+ }).strict();
15303
+ var AgentPaymentLinkPageSchema = external_exports.object({
15304
+ items: external_exports.array(AgentPaymentLinkDtoSchema),
15305
+ total: external_exports.number().int().nonnegative()
15306
+ }).strict();
15224
15307
  var AGENT_DEVICE_AUTH_STATUSES = ["pending", "approved", "denied", "expired"];
15225
15308
  var AGENT_DEVICE_AUTH_DEFAULT_PERMISSIONS = [
15226
- ...AGENT_CATALOG_KEY_PRESET_ACTIONS
15309
+ ...AGENT_KEY_READ_ACTIONS
15227
15310
  ];
15228
15311
  function parsePollResponse(value) {
15229
15312
  if (!AGENT_DEVICE_AUTH_STATUSES.includes(value.status)) {
@@ -15540,6 +15623,32 @@ var AgentOperationsResource = class {
15540
15623
  });
15541
15624
  }
15542
15625
  };
15626
+ var AgentPaymentLinksResource = class {
15627
+ constructor(http) {
15628
+ this.http = http;
15629
+ }
15630
+ http;
15631
+ /**
15632
+ * Creates a payment link. `amount` is in soles (major units); the backend
15633
+ * converts it to minor units — never convert it here. The URL is only
15634
+ * non-null for the initial create response.
15635
+ */
15636
+ create(input) {
15637
+ return this.http.request("/api/v1/agent/payment-links", {
15638
+ method: "POST",
15639
+ body: input,
15640
+ mutation: true
15641
+ }).then((response) => AgentCreatedPaymentLinkDtoSchema.parse(response));
15642
+ }
15643
+ /** Fetches a persisted link; `url` is always `null`. */
15644
+ get(paymentLinkId) {
15645
+ return this.http.request(`/api/v1/agent/payment-links/${encodeURIComponent(paymentLinkId)}`).then((response) => AgentPaymentLinkDtoSchema.parse(response));
15646
+ }
15647
+ /** Lists persisted links; every item has `url: null`. */
15648
+ list(filter = {}) {
15649
+ return this.http.request(`/api/v1/agent/payment-links${queryString(filter)}`).then((response) => AgentPaymentLinkPageSchema.parse(response));
15650
+ }
15651
+ };
15543
15652
  function createAvileoAgent(config2) {
15544
15653
  const http = new AgentHttpClient(config2);
15545
15654
  return {
@@ -15551,7 +15660,8 @@ function createAvileoAgent(config2) {
15551
15660
  tags: new AgentTagsResource(http),
15552
15661
  assets: new AgentAssetsResource(http),
15553
15662
  inventory: new AgentInventoryResource(http),
15554
- imports: new AgentImportsResource(http)
15663
+ imports: new AgentImportsResource(http),
15664
+ paymentLinks: new AgentPaymentLinksResource(http)
15555
15665
  };
15556
15666
  }
15557
15667
 
@@ -15560,6 +15670,53 @@ import { chmodSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSy
15560
15670
  import { randomUUID } from "crypto";
15561
15671
  import { homedir } from "os";
15562
15672
  import { dirname, join } from "path";
15673
+ import { isIP } from "net";
15674
+ var LOCAL_IPV4_HOST_PATTERN = /^(?:127\.|10\.|192\.168\.|169\.254\.|172\.(?:1[6-9]|2\d|3[01])\.|100\.(?:6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.)/;
15675
+ function isLocalHostname(hostname3) {
15676
+ const host = hostname3.replace(/^\[|\]$/g, "").toLowerCase();
15677
+ if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) return true;
15678
+ if (host === "::1" || host === "::" || /^f[cd][0-9a-f]{2}:/.test(host)) return true;
15679
+ if (host.includes(":")) return false;
15680
+ if (!host.includes(".")) return true;
15681
+ return isIP(host) === 4 && LOCAL_IPV4_HOST_PATTERN.test(host);
15682
+ }
15683
+ function normalizeApiBaseUrl(rawUrl) {
15684
+ const candidate = rawUrl.trim().replace(/\/+$/, "");
15685
+ if (!candidate) {
15686
+ throw new CliOriginUnsupportedError("La URL base de la API est\xE1 vac\xEDa");
15687
+ }
15688
+ let parsed;
15689
+ try {
15690
+ parsed = new URL(candidate);
15691
+ } catch {
15692
+ throw new CliOriginUnsupportedError(`La URL base de la API no es v\xE1lida: ${candidate}`);
15693
+ }
15694
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
15695
+ throw new CliOriginUnsupportedError(
15696
+ `La URL base debe usar HTTPS (o HTTP local de desarrollo); se recibi\xF3 ${parsed.protocol}//`
15697
+ );
15698
+ }
15699
+ if (parsed.protocol === "http:" && !isLocalHostname(parsed.hostname)) {
15700
+ throw new CliOriginUnsupportedError(
15701
+ "Solo se permite HTTP para hosts locales de desarrollo; usa un origen HTTPS"
15702
+ );
15703
+ }
15704
+ if (parsed.username || parsed.password) {
15705
+ throw new CliOriginUnsupportedError("La URL base no debe incluir credenciales embebidas");
15706
+ }
15707
+ if (parsed.search || parsed.hash) {
15708
+ throw new CliOriginUnsupportedError("La URL base no debe incluir query ni fragmento");
15709
+ }
15710
+ return `${parsed.protocol}//${parsed.host}${parsed.pathname.replace(/\/+$/, "")}`;
15711
+ }
15712
+ function apiOrigin(baseUrl) {
15713
+ const parsed = new URL(baseUrl);
15714
+ return `${parsed.protocol}//${parsed.host}`;
15715
+ }
15716
+ function overrideBaseUrl(env) {
15717
+ const raw = env.AVILEO_AGENT_BASE_URL?.trim();
15718
+ return raw ? normalizeApiBaseUrl(raw) : void 0;
15719
+ }
15563
15720
  var AGENT_KEY_PATTERN = /^avileo_sk_[^\s]+$/;
15564
15721
  function normalizeAgentKey(value, message) {
15565
15722
  const key = value.trim();
@@ -15590,10 +15747,15 @@ function readLocalCredential(env = process.env) {
15590
15747
  throw new CliConfigurationError("La credencial local no es una Agent Key v\xE1lida");
15591
15748
  }
15592
15749
  const apiKey = normalizeAgentKey(record2.apiKey, "La credencial local no es una Agent Key v\xE1lida");
15593
- const baseUrl = typeof record2.baseUrl === "string" && record2.baseUrl.trim() ? record2.baseUrl.trim() : void 0;
15594
- return { apiKey, ...baseUrl ? { baseUrl } : {} };
15750
+ if (typeof record2.baseUrl !== "string" || !record2.baseUrl.trim()) {
15751
+ throw new CliConfigurationError(
15752
+ "La credencial local no tiene un origen vinculado. Vuelve a autorizar con auth login --base-url <URL_DEL_PORTAL> antes de usarla."
15753
+ );
15754
+ }
15755
+ return { apiKey, baseUrl: normalizeApiBaseUrl(record2.baseUrl) };
15595
15756
  }
15596
15757
  function resolveCredential(env = process.env) {
15758
+ const override = overrideBaseUrl(env);
15597
15759
  const environmentValue = env.AVILEO_AGENT_API_KEY;
15598
15760
  if (environmentValue !== void 0) {
15599
15761
  return {
@@ -15602,31 +15764,29 @@ function resolveCredential(env = process.env) {
15602
15764
  "AVILEO_AGENT_API_KEY no es una Agent Key v\xE1lida"
15603
15765
  ),
15604
15766
  source: "environment",
15605
- ...env.AVILEO_AGENT_BASE_URL?.trim() ? { baseUrl: env.AVILEO_AGENT_BASE_URL.trim() } : {}
15767
+ baseUrl: override ?? AVILEO_AGENT_API_URL
15606
15768
  };
15607
15769
  }
15608
15770
  const local = readLocalCredential(env);
15609
15771
  if (!local) return null;
15610
- return {
15611
- ...local,
15612
- source: "local",
15613
- ...env.AVILEO_AGENT_BASE_URL?.trim() ? { baseUrl: env.AVILEO_AGENT_BASE_URL.trim() } : {}
15614
- };
15772
+ if (override && apiOrigin(local.baseUrl) !== apiOrigin(override)) {
15773
+ throw new CliOriginConflictError(
15774
+ `La credencial local est\xE1 vinculada al origen ${apiOrigin(local.baseUrl)}, pero AVILEO_AGENT_BASE_URL apunta a ${apiOrigin(override)}. La clave nunca se env\xEDa a otro origen: quita la variable de entorno o vuelve a autenticar con auth login --base-url ${apiOrigin(override)} para emitir una clave en ese origen.`
15775
+ );
15776
+ }
15777
+ return { ...local, source: "local" };
15615
15778
  }
15616
15779
  function saveLocalCredential(credential, env = process.env) {
15617
15780
  const apiKey = normalizeAgentKey(
15618
15781
  credential.apiKey,
15619
15782
  "Solo se pueden guardar Agent Keys de Avileo"
15620
15783
  );
15784
+ const baseUrl = normalizeApiBaseUrl(credential.baseUrl);
15621
15785
  const path = localCredentialPath(env);
15622
15786
  mkdirSync(dirname(path), { recursive: true, mode: 448 });
15623
15787
  const temporaryPath = `${path}.${randomUUID()}.tmp`;
15624
- writeFileSync(
15625
- temporaryPath,
15626
- `${JSON.stringify({ apiKey, ...credential.baseUrl ? { baseUrl: credential.baseUrl } : {} })}
15627
- `,
15628
- { mode: 384 }
15629
- );
15788
+ writeFileSync(temporaryPath, `${JSON.stringify({ apiKey, baseUrl })}
15789
+ `, { mode: 384 });
15630
15790
  chmodSync(temporaryPath, 384);
15631
15791
  renameSync(temporaryPath, path);
15632
15792
  chmodSync(path, 384);
@@ -15650,7 +15810,7 @@ function createClientFromEnvironment({
15650
15810
  }
15651
15811
  return clientFactory({
15652
15812
  apiKey: credential.apiKey,
15653
- ...credential.baseUrl ? { baseUrl: credential.baseUrl } : {}
15813
+ baseUrl: credential.baseUrl
15654
15814
  });
15655
15815
  }
15656
15816
  var CliConfigurationError = class extends Error {
@@ -15660,6 +15820,20 @@ var CliConfigurationError = class extends Error {
15660
15820
  this.name = "CliConfigurationError";
15661
15821
  }
15662
15822
  };
15823
+ var CliOriginUnsupportedError = class extends CliConfigurationError {
15824
+ code = "CLI_ORIGIN_UNSUPPORTED";
15825
+ constructor(message) {
15826
+ super(message);
15827
+ this.name = "CliOriginUnsupportedError";
15828
+ }
15829
+ };
15830
+ var CliOriginConflictError = class extends CliConfigurationError {
15831
+ code = "CLI_ORIGIN_CONFLICT";
15832
+ constructor(message) {
15833
+ super(message);
15834
+ this.name = "CliOriginConflictError";
15835
+ }
15836
+ };
15663
15837
 
15664
15838
  // src/output.ts
15665
15839
  var CliProtocolError = class extends Error {
@@ -15720,34 +15894,8 @@ function redact(value) {
15720
15894
  return value;
15721
15895
  }
15722
15896
 
15723
- // src/commands/business.ts
15724
- function registerBusinessCommands(root, getClient) {
15725
- const business = root.command("business").description("Consulta el negocio vinculado a la clave agente");
15726
- business.command("show").description("Muestra las capacidades seguras del negocio").action(async () => {
15727
- emitSuccess(await getClient().business.get());
15728
- });
15729
- }
15730
-
15731
- // src/commands/catalog.ts
15732
- import { createHash } from "crypto";
15733
- import { readFile, stat } from "fs/promises";
15734
- import { basename, extname } from "path";
15735
- function requireId(value, name) {
15736
- if (!value.trim()) throw new CliProtocolError("CLI_VALIDATION_ERROR", `${name} es obligatorio`);
15737
- return value;
15738
- }
15739
- async function readMutationInput(path) {
15740
- let parsed;
15741
- try {
15742
- parsed = JSON.parse(await readFile(path, "utf8"));
15743
- } catch {
15744
- throw new CliProtocolError("CLI_INPUT_ERROR", "No se pudo leer un objeto JSON desde --from");
15745
- }
15746
- if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
15747
- throw new CliProtocolError("CLI_VALIDATION_ERROR", "--from debe contener un objeto JSON");
15748
- }
15749
- return normalizeInput(parsed);
15750
- }
15897
+ // src/commands/mutation.ts
15898
+ import { readFile } from "fs/promises";
15751
15899
  function normalizeInput(value) {
15752
15900
  const forbidden = {
15753
15901
  businessId: true,
@@ -15770,12 +15918,17 @@ function normalizeInput(value) {
15770
15918
  };
15771
15919
  return visit(value);
15772
15920
  }
15773
- function withMutationOptions(command, includeFrom = true) {
15774
- if (includeFrom) command.requiredOption("--from <json-file>", "Objeto JSON estructurado");
15775
- return command.option("--apply", "Solicita aprobaci\xF3n o ejecuta una mutaci\xF3n aprobada").option("--approval-id <uuid>", "Aprobaci\xF3n emitida por Avileo");
15776
- }
15777
- function wantsApply(command) {
15778
- return Boolean(command.optsWithGlobals().apply);
15921
+ async function readMutationInput(path) {
15922
+ let parsed;
15923
+ try {
15924
+ parsed = JSON.parse(await readFile(path, "utf8"));
15925
+ } catch {
15926
+ throw new CliProtocolError("CLI_INPUT_ERROR", "No se pudo leer un objeto JSON desde --from");
15927
+ }
15928
+ if (!parsed || Array.isArray(parsed) || typeof parsed !== "object") {
15929
+ throw new CliProtocolError("CLI_VALIDATION_ERROR", "--from debe contener un objeto JSON");
15930
+ }
15931
+ return normalizeInput(parsed);
15779
15932
  }
15780
15933
  function localResult(input, current) {
15781
15934
  if (current === void 0) return { validated: "local", input };
@@ -15785,6 +15938,53 @@ function localResult(input, current) {
15785
15938
  );
15786
15939
  return { validated: "local", current, changes };
15787
15940
  }
15941
+
15942
+ // src/commands/business.ts
15943
+ function profileValues(profile) {
15944
+ const values = profile.values;
15945
+ if (!values || Array.isArray(values) || typeof values !== "object") return {};
15946
+ return values;
15947
+ }
15948
+ function registerBusinessCommands(root, getClient) {
15949
+ const business = root.command("business").description("Consulta el negocio vinculado a la clave agente");
15950
+ business.command("show").description("Muestra las capacidades seguras del negocio").action(async () => {
15951
+ emitSuccess(await getClient().business.get());
15952
+ });
15953
+ const profile = business.command("profile").description("Consulta o propone cambios al perfil del negocio");
15954
+ profile.command("show").description("Muestra campos, valores y completitud del perfil").action(async () => {
15955
+ emitSuccess(await getClient().business.profile());
15956
+ });
15957
+ profile.command("update").description("Previsualiza o propone cambios al perfil").requiredOption("--from <json-file>", "Valores de perfil en un objeto JSON").option("--apply", "Crea una propuesta para aprobaci\xF3n en Avileo").action(async (options, command) => {
15958
+ const values = await readMutationInput(options.from);
15959
+ if (!command.optsWithGlobals().apply) {
15960
+ const current = await getClient().business.profile();
15961
+ emitSuccess(localResult(values, profileValues(current)));
15962
+ return;
15963
+ }
15964
+ emitSuccess(
15965
+ await getClient().operations.propose({
15966
+ operationName: "business.profile.update",
15967
+ payload: { values }
15968
+ })
15969
+ );
15970
+ });
15971
+ }
15972
+
15973
+ // src/commands/catalog.ts
15974
+ import { createHash } from "crypto";
15975
+ import { readFile as readFile2, stat } from "fs/promises";
15976
+ import { basename, extname } from "path";
15977
+ function requireId(value, name) {
15978
+ if (!value.trim()) throw new CliProtocolError("CLI_VALIDATION_ERROR", `${name} es obligatorio`);
15979
+ return value;
15980
+ }
15981
+ function withMutationOptions(command, includeFrom = true) {
15982
+ if (includeFrom) command.requiredOption("--from <json-file>", "Objeto JSON estructurado");
15983
+ return command.option("--apply", "Solicita aprobaci\xF3n o ejecuta una mutaci\xF3n aprobada").option("--approval-id <uuid>", "Aprobaci\xF3n emitida por Avileo");
15984
+ }
15985
+ function wantsApply(command) {
15986
+ return Boolean(command.optsWithGlobals().apply);
15987
+ }
15788
15988
  function addListOptions(command) {
15789
15989
  return command.option("--search <text>").option("--category-id <id>").option("--active <true|false>", "Filtra por estado activo", parseBoolean).option("--limit <number>", "M\xE1ximo de resultados", parseInteger).option("--offset <number>", "Desplazamiento", parseInteger);
15790
15990
  }
@@ -16071,7 +16271,7 @@ function registerAssetCommands(catalog, getClient) {
16071
16271
  "Solo se permiten im\xE1genes JPEG, PNG o WebP"
16072
16272
  );
16073
16273
  }
16074
- const contents = await readFile(filePath);
16274
+ const contents = await readFile2(filePath);
16075
16275
  const file2 = new File([contents], basename(filePath), { type: mimeType });
16076
16276
  const rawApprovalId = command.optsWithGlobals().approvalId;
16077
16277
  if (typeof rawApprovalId === "string") {
@@ -16212,6 +16412,57 @@ function safeFinalResult(start, browserOpened, result) {
16212
16412
  function sleep(milliseconds) {
16213
16413
  return new Promise((resolve) => setTimeout(resolve, milliseconds));
16214
16414
  }
16415
+ function readAgentKeyFromTty(prompt = "Agent Key de Avileo: ") {
16416
+ if (!process.stdin.isTTY || !process.stderr.isTTY) {
16417
+ throw new CliProtocolError(
16418
+ "CLI_CONFIGURATION_ERROR",
16419
+ "auth configure requiere una terminal interactiva; usa AVILEO_AGENT_API_KEY en CI/CD"
16420
+ );
16421
+ }
16422
+ return new Promise((resolve, reject) => {
16423
+ let value = "";
16424
+ const input = process.stdin;
16425
+ const output = process.stderr;
16426
+ const wasRaw = input.isRaw;
16427
+ const cleanup = () => {
16428
+ input.removeListener("data", onData);
16429
+ input.pause();
16430
+ if (wasRaw !== void 0) input.setRawMode(Boolean(wasRaw));
16431
+ };
16432
+ const finish = (result) => {
16433
+ cleanup();
16434
+ output.write("\n");
16435
+ if (result instanceof Error) reject(result);
16436
+ else resolve(result);
16437
+ };
16438
+ const onData = (chunk) => {
16439
+ for (const character of String(chunk)) {
16440
+ if (character === "") {
16441
+ finish(
16442
+ new CliProtocolError(
16443
+ "CLI_CONFIGURATION_ERROR",
16444
+ "Configuraci\xF3n cancelada por el usuario"
16445
+ )
16446
+ );
16447
+ return;
16448
+ }
16449
+ if (character === "\r" || character === "\n") {
16450
+ finish(value);
16451
+ return;
16452
+ }
16453
+ if (character === "\x7F" || character === "\b") {
16454
+ value = value.slice(0, -1);
16455
+ continue;
16456
+ }
16457
+ value += character;
16458
+ }
16459
+ };
16460
+ output.write(prompt);
16461
+ input.setRawMode(true);
16462
+ input.resume();
16463
+ input.on("data", onData);
16464
+ });
16465
+ }
16215
16466
  async function openWithExecutable(command, args) {
16216
16467
  return new Promise((resolve) => {
16217
16468
  const child = spawn(command, args, { stdio: "ignore", shell: false, detached: true });
@@ -16239,9 +16490,15 @@ async function openVerificationUri(uri) {
16239
16490
  }
16240
16491
  return false;
16241
16492
  }
16493
+ function resolveSelectedBaseUrl(options) {
16494
+ const explicit = options.baseUrl?.trim();
16495
+ if (explicit) return normalizeApiBaseUrl(explicit);
16496
+ const fromEnvironment = options.env.AVILEO_AGENT_BASE_URL?.trim();
16497
+ return fromEnvironment ? normalizeApiBaseUrl(fromEnvironment) : AVILEO_AGENT_API_URL;
16498
+ }
16242
16499
  async function login(options) {
16243
- const baseUrl = options.env.AVILEO_AGENT_BASE_URL?.trim();
16244
- const deviceAuth = options.deviceAuthFactory(baseUrl ? { baseUrl } : {});
16500
+ const baseUrl = resolveSelectedBaseUrl(options);
16501
+ const deviceAuth = options.deviceAuthFactory({ baseUrl });
16245
16502
  const start = await deviceAuth.start({ name: "Avileo CLI" });
16246
16503
  const browserOpened = await options.openBrowser(start.verificationUri);
16247
16504
  process.stderr.write(
@@ -16258,7 +16515,7 @@ async function login(options) {
16258
16515
  continue;
16259
16516
  }
16260
16517
  if (result.status === "denied" || result.status === "expired") {
16261
- emitSuccess(safeFinalResult(start, browserOpened, result));
16518
+ emitSuccess({ ...safeFinalResult(start, browserOpened, result), baseUrl });
16262
16519
  return;
16263
16520
  }
16264
16521
  if (!result.agentKey || !result.keyId || !result.businessId) {
@@ -16267,18 +16524,23 @@ async function login(options) {
16267
16524
  "La autorizaci\xF3n aprobada no devolvi\xF3 una credencial v\xE1lida"
16268
16525
  );
16269
16526
  }
16270
- saveLocalCredential(
16271
- {
16272
- apiKey: result.agentKey,
16273
- ...baseUrl ? { baseUrl } : {}
16274
- },
16275
- options.env
16276
- );
16277
- emitSuccess(safeFinalResult(start, browserOpened, result));
16527
+ saveLocalCredential({ apiKey: result.agentKey, baseUrl }, options.env);
16528
+ emitSuccess({ ...safeFinalResult(start, browserOpened, result), baseUrl });
16278
16529
  return;
16279
16530
  }
16280
16531
  throw new CliProtocolError("CLI_AUTH_TIMEOUT", "La autorizaci\xF3n expir\xF3 antes de ser aprobada");
16281
16532
  }
16533
+ async function configure(options) {
16534
+ const baseUrl = resolveSelectedBaseUrl(options);
16535
+ const apiKey = await options.readSecret("Agent Key de Avileo (no se mostrar\xE1): ");
16536
+ saveLocalCredential({ apiKey, baseUrl }, options.env);
16537
+ emitSuccess({
16538
+ configured: true,
16539
+ source: "local",
16540
+ baseUrl,
16541
+ credentialPath: localCredentialPath(options.env)
16542
+ });
16543
+ }
16282
16544
  async function status(options) {
16283
16545
  const credential = resolveCredential(options.env);
16284
16546
  if (!credential) {
@@ -16290,13 +16552,13 @@ async function status(options) {
16290
16552
  try {
16291
16553
  business = await options.getClient().business.get();
16292
16554
  } catch (error51) {
16293
- const code = error51.code;
16555
+ const code = error51 && typeof error51 === "object" && "code" in error51 ? error51.code : void 0;
16294
16556
  businessLookupError = typeof code === "string" ? code : "LOOKUP_FAILED";
16295
16557
  }
16296
16558
  emitSuccess({
16297
16559
  configured: true,
16298
16560
  source: credential.source,
16299
- credentialPath: credential.source === "local" ? localCredentialPath(options.env) : void 0,
16561
+ baseUrl: credential.baseUrl ?? AVILEO_AGENT_API_URL,
16300
16562
  business,
16301
16563
  ...businessLookupError ? { businessLookupError } : {}
16302
16564
  });
@@ -16312,7 +16574,15 @@ async function logout(options) {
16312
16574
  }
16313
16575
  function registerAuthCommands(root, options) {
16314
16576
  const auth = root.command("auth").description("Conecta la CLI con Avileo sin copiar claves en el chat");
16315
- auth.command("login").description("Autoriza esta CLI mediante un link temporal").action(() => login(options));
16577
+ auth.command("configure").description("Guarda una Agent Key existente sin mostrarla en pantalla").option("--base-url <url>", "Origen de la API donde se usar\xE1 la clave").action(
16578
+ (commandOptions) => configure({ ...options, baseUrl: commandOptions.baseUrl })
16579
+ );
16580
+ auth.command("login").description("Autoriza esta CLI mediante un link temporal").option(
16581
+ "--base-url <url>",
16582
+ "Origen de la API a vincular; tiene prioridad sobre AVILEO_AGENT_BASE_URL"
16583
+ ).action(
16584
+ (commandOptions) => login({ ...options, baseUrl: commandOptions.baseUrl })
16585
+ );
16316
16586
  auth.command("status").description("Muestra el estado de la credencial sin revelar secretos").action(() => status(options));
16317
16587
  auth.command("logout").description("Elimina solamente la credencial local").action(() => logout(options));
16318
16588
  }
@@ -16338,6 +16608,7 @@ function createProgram(options = {}) {
16338
16608
  env: options.env ?? process.env,
16339
16609
  deviceAuthFactory: options.deviceAuthFactory ?? createAvileoAgentDeviceAuth,
16340
16610
  openBrowser: options.openBrowser ?? openVerificationUri,
16611
+ readSecret: options.readSecret ?? readAgentKeyFromTty,
16341
16612
  getClient,
16342
16613
  json: () => Boolean(program.opts().json)
16343
16614
  });