@tarileo/avileo-catalog-cli 0.3.13 → 0.3.15
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 +657 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1867,18 +1867,18 @@ var validateAsync = async (schema, value, _ctx) => {
|
|
|
1867
1867
|
return result.issues.length === 0;
|
|
1868
1868
|
};
|
|
1869
1869
|
var _encode = (_Err) => {
|
|
1870
|
-
const
|
|
1870
|
+
const parse4 = _parse(_Err);
|
|
1871
1871
|
const fn = (schema, value, _ctx, _params) => {
|
|
1872
1872
|
const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
|
|
1873
|
-
return
|
|
1873
|
+
return parse4(schema, value, ctx, finalizeParams(fn, _params));
|
|
1874
1874
|
};
|
|
1875
1875
|
return fn;
|
|
1876
1876
|
};
|
|
1877
1877
|
var encode = /* @__PURE__ */ _encode($ZodRealError);
|
|
1878
1878
|
var _decode = (_Err) => {
|
|
1879
|
-
const
|
|
1879
|
+
const parse4 = _parse(_Err);
|
|
1880
1880
|
const fn = (schema, value, _ctx, _params) => {
|
|
1881
|
-
return
|
|
1881
|
+
return parse4(schema, value, _ctx, finalizeParams(fn, _params));
|
|
1882
1882
|
};
|
|
1883
1883
|
return fn;
|
|
1884
1884
|
};
|
|
@@ -3373,7 +3373,7 @@ function capSize(inst, size) {
|
|
|
3373
3373
|
if (!caps.length)
|
|
3374
3374
|
return;
|
|
3375
3375
|
const cap = Math.min(...caps.map((c) => c[0]));
|
|
3376
|
-
const
|
|
3376
|
+
const parse4 = inst._zod.parse;
|
|
3377
3377
|
inst._zod.parse = (payload, ctx) => {
|
|
3378
3378
|
const n = size(payload.value);
|
|
3379
3379
|
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
@@ -3387,7 +3387,7 @@ function capSize(inst, size) {
|
|
|
3387
3387
|
}
|
|
3388
3388
|
}
|
|
3389
3389
|
}
|
|
3390
|
-
return
|
|
3390
|
+
return parse4(payload, ctx);
|
|
3391
3391
|
};
|
|
3392
3392
|
}
|
|
3393
3393
|
var arraySize = (input2) => Array.isArray(input2) ? input2.length : -1;
|
|
@@ -5076,7 +5076,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
|
|
|
5076
5076
|
var NONE = 0;
|
|
5077
5077
|
var ASSUMED = 1;
|
|
5078
5078
|
var PROVEN = 2;
|
|
5079
|
-
function isRecursive(inst, stack,
|
|
5079
|
+
function isRecursive(inst, stack, resolve3) {
|
|
5080
5080
|
const cached2 = recursive.get(inst);
|
|
5081
5081
|
if (cached2 !== void 0)
|
|
5082
5082
|
return cached2 ? PROVEN : NONE;
|
|
@@ -5086,7 +5086,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5086
5086
|
let result = NONE;
|
|
5087
5087
|
const check2 = (child) => {
|
|
5088
5088
|
if (result !== PROVEN && child?._zod) {
|
|
5089
|
-
const answer = isRecursive(child, stack,
|
|
5089
|
+
const answer = isRecursive(child, stack, resolve3);
|
|
5090
5090
|
if (answer > result)
|
|
5091
5091
|
result = answer;
|
|
5092
5092
|
}
|
|
@@ -5097,7 +5097,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5097
5097
|
const desc = Object.getOwnPropertyDescriptor(sh, key);
|
|
5098
5098
|
if (spread && !desc.enumerable)
|
|
5099
5099
|
continue;
|
|
5100
|
-
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack,
|
|
5100
|
+
const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve3) : NONE;
|
|
5101
5101
|
if (child > answer)
|
|
5102
5102
|
answer = child;
|
|
5103
5103
|
}
|
|
@@ -5161,7 +5161,7 @@ function isRecursive(inst, stack, resolve2) {
|
|
|
5161
5161
|
break;
|
|
5162
5162
|
// `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
|
|
5163
5163
|
case "lazy": {
|
|
5164
|
-
const inner = def._cachedInner ?? (
|
|
5164
|
+
const inner = def._cachedInner ?? (resolve3 ? inst._zod.innerType : void 0);
|
|
5165
5165
|
merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
|
|
5166
5166
|
break;
|
|
5167
5167
|
}
|
|
@@ -19915,7 +19915,7 @@ var AgentHttpClient = class {
|
|
|
19915
19915
|
} catch {
|
|
19916
19916
|
abort.cancel();
|
|
19917
19917
|
if (retry && attempt < 2) {
|
|
19918
|
-
await new Promise((
|
|
19918
|
+
await new Promise((resolve3) => setTimeout(resolve3, retryDelayMs(attempt)));
|
|
19919
19919
|
continue;
|
|
19920
19920
|
}
|
|
19921
19921
|
throw new AgentNetworkError("No se pudo conectar con la API de Avileo", {
|
|
@@ -19926,7 +19926,7 @@ var AgentHttpClient = class {
|
|
|
19926
19926
|
}
|
|
19927
19927
|
abort.cancel();
|
|
19928
19928
|
if (retry && isRetryableStatus(response.status) && attempt < 2) {
|
|
19929
|
-
await new Promise((
|
|
19929
|
+
await new Promise((resolve3) => setTimeout(resolve3, retryDelayMs(attempt, response)));
|
|
19930
19930
|
continue;
|
|
19931
19931
|
}
|
|
19932
19932
|
let payload;
|
|
@@ -19962,7 +19962,8 @@ var AGENT_CAPABILITY_ACTIONS = [
|
|
|
19962
19962
|
"inventory:read",
|
|
19963
19963
|
"inventory:write",
|
|
19964
19964
|
"payments:read",
|
|
19965
|
-
"payments:write"
|
|
19965
|
+
"payments:write",
|
|
19966
|
+
"sales:read"
|
|
19966
19967
|
];
|
|
19967
19968
|
var AgentCapabilityActionSchema = external_exports.enum(AGENT_CAPABILITY_ACTIONS);
|
|
19968
19969
|
var AGENT_KEY_MODES = ["read", "mutate"];
|
|
@@ -19972,7 +19973,8 @@ var AGENT_KEY_READ_ACTIONS = [
|
|
|
19972
19973
|
"catalog:read",
|
|
19973
19974
|
"assets:read",
|
|
19974
19975
|
"inventory:read",
|
|
19975
|
-
"payments:read"
|
|
19976
|
+
"payments:read",
|
|
19977
|
+
"sales:read"
|
|
19976
19978
|
];
|
|
19977
19979
|
var AgentGrantedActionsSchema = external_exports.array(AgentCapabilityActionSchema).min(1).max(AGENT_CAPABILITY_ACTIONS.length).refine((actions) => new Set(actions).size === actions.length, {
|
|
19978
19980
|
message: "Las capacidades no pueden repetirse"
|
|
@@ -20772,6 +20774,75 @@ var AgentPaymentMethodDtoSchema = external_exports.object({
|
|
|
20772
20774
|
qrRenderUrl: external_exports.string().nullable(),
|
|
20773
20775
|
habilitado: external_exports.boolean()
|
|
20774
20776
|
}).strict();
|
|
20777
|
+
var uuidSchema2 = external_exports.string().uuid();
|
|
20778
|
+
var timestampSchema2 = external_exports.string().datetime({ offset: true });
|
|
20779
|
+
var nonEmptyTextSchema2 = external_exports.string().trim().min(1);
|
|
20780
|
+
var nonNegativeDecimalStringSchema2 = external_exports.string().regex(/^(?:0|[1-9]\d*)(?:\.\d+)?$/, "Debe ser un decimal no negativo");
|
|
20781
|
+
var AgentSalesChannelSchema = external_exports.enum(["web", "tienda"]);
|
|
20782
|
+
var agentSaleTypeSchema = external_exports.enum(["instant_sale", "pre_order"]);
|
|
20783
|
+
var AgentSalesListQuerySchema = external_exports.object({
|
|
20784
|
+
// Acepta tanto el estado legado como el nombre canónico en v1.
|
|
20785
|
+
status: nonEmptyTextSchema2.max(40).optional(),
|
|
20786
|
+
channel: AgentSalesChannelSchema.optional(),
|
|
20787
|
+
type: agentSaleTypeSchema.optional(),
|
|
20788
|
+
// Rango inclusivo por `since` y exclusivo por `until`.
|
|
20789
|
+
since: timestampSchema2.optional(),
|
|
20790
|
+
until: timestampSchema2.optional(),
|
|
20791
|
+
limit: external_exports.number().int().min(1).max(100).default(20),
|
|
20792
|
+
// Cursor opaco emitido por el backend; no interpretable por el agente.
|
|
20793
|
+
cursor: external_exports.string().min(1).max(512).optional()
|
|
20794
|
+
}).strict();
|
|
20795
|
+
var AgentCustomerMaskedSchema = external_exports.object({
|
|
20796
|
+
name: external_exports.string().nullable(),
|
|
20797
|
+
phone: external_exports.string().nullable(),
|
|
20798
|
+
address: external_exports.string().nullable()
|
|
20799
|
+
}).strict();
|
|
20800
|
+
var AgentSaleItemSchema = external_exports.object({
|
|
20801
|
+
productId: uuidSchema2.nullable(),
|
|
20802
|
+
variantId: uuidSchema2.nullable(),
|
|
20803
|
+
name: nonEmptyTextSchema2,
|
|
20804
|
+
variantName: external_exports.string().nullable(),
|
|
20805
|
+
quantity: nonNegativeDecimalStringSchema2,
|
|
20806
|
+
unitPrice: nonNegativeDecimalStringSchema2,
|
|
20807
|
+
lineTotal: nonNegativeDecimalStringSchema2
|
|
20808
|
+
}).strict();
|
|
20809
|
+
var AgentSaleSummarySchema = external_exports.object({
|
|
20810
|
+
id: uuidSchema2,
|
|
20811
|
+
code: external_exports.string().nullable(),
|
|
20812
|
+
channel: AgentSalesChannelSchema.nullable(),
|
|
20813
|
+
type: agentSaleTypeSchema,
|
|
20814
|
+
// Estado legado de la venta; `commercialStatus` es el canónico actual.
|
|
20815
|
+
legacyStatus: nonEmptyTextSchema2,
|
|
20816
|
+
commercialStatus: external_exports.string().nullable(),
|
|
20817
|
+
paymentStatus: external_exports.string().nullable(),
|
|
20818
|
+
fulfillmentStatus: external_exports.string().nullable(),
|
|
20819
|
+
createdAt: timestampSchema2,
|
|
20820
|
+
currency: external_exports.string().length(3),
|
|
20821
|
+
total: nonNegativeDecimalStringSchema2,
|
|
20822
|
+
itemCount: external_exports.number().int().nonnegative()
|
|
20823
|
+
}).strict();
|
|
20824
|
+
var AgentSaleTimelineEntrySchema = external_exports.object({
|
|
20825
|
+
at: timestampSchema2,
|
|
20826
|
+
kind: nonEmptyTextSchema2,
|
|
20827
|
+
actorKind: external_exports.string().nullable(),
|
|
20828
|
+
// Nota ya enmascarada por el servidor; nunca PII libre.
|
|
20829
|
+
note: external_exports.string().nullable()
|
|
20830
|
+
}).strict();
|
|
20831
|
+
var AgentSaleDetailSchema = AgentSaleSummarySchema.extend({
|
|
20832
|
+
subtotal: nonNegativeDecimalStringSchema2,
|
|
20833
|
+
confirmedAt: timestampSchema2.nullable(),
|
|
20834
|
+
// Método de entrega, NO el `fulfillmentSnapshot` crudo.
|
|
20835
|
+
fulfillmentMethod: external_exports.string().nullable(),
|
|
20836
|
+
deliveryDistrict: external_exports.string().nullable(),
|
|
20837
|
+
customer: AgentCustomerMaskedSchema,
|
|
20838
|
+
items: external_exports.array(AgentSaleItemSchema).max(200),
|
|
20839
|
+
timeline: external_exports.array(AgentSaleTimelineEntrySchema).max(200)
|
|
20840
|
+
}).strict();
|
|
20841
|
+
var AgentSalesPageSchema = external_exports.object({
|
|
20842
|
+
items: external_exports.array(AgentSaleSummarySchema).max(100),
|
|
20843
|
+
total: external_exports.number().int().nonnegative(),
|
|
20844
|
+
nextCursor: external_exports.string().nullable()
|
|
20845
|
+
}).strict();
|
|
20775
20846
|
var AGENT_DEVICE_AUTH_STATUSES = ["pending", "approved", "denied", "expired"];
|
|
20776
20847
|
var AGENT_DEVICE_AUTH_DEFAULT_PERMISSIONS = [
|
|
20777
20848
|
...AGENT_KEY_READ_ACTIONS
|
|
@@ -20834,6 +20905,32 @@ var AgentBusinessResource = class {
|
|
|
20834
20905
|
profile() {
|
|
20835
20906
|
return this.http.request("/api/v1/agent/business/profile");
|
|
20836
20907
|
}
|
|
20908
|
+
/** Diagnostic state of this credential; never returns key material. */
|
|
20909
|
+
credential() {
|
|
20910
|
+
return this.http.request("/api/v1/agent/credential");
|
|
20911
|
+
}
|
|
20912
|
+
};
|
|
20913
|
+
var AgentSalesResource = class {
|
|
20914
|
+
constructor(http) {
|
|
20915
|
+
this.http = http;
|
|
20916
|
+
}
|
|
20917
|
+
http;
|
|
20918
|
+
list(query = {}) {
|
|
20919
|
+
return this.http.request(
|
|
20920
|
+
`/api/v1/agent/sales${queryString({
|
|
20921
|
+
status: query.status,
|
|
20922
|
+
channel: query.channel,
|
|
20923
|
+
type: query.type,
|
|
20924
|
+
since: query.since,
|
|
20925
|
+
until: query.until,
|
|
20926
|
+
limit: query.limit,
|
|
20927
|
+
cursor: query.cursor
|
|
20928
|
+
})}`
|
|
20929
|
+
);
|
|
20930
|
+
}
|
|
20931
|
+
get(id) {
|
|
20932
|
+
return this.http.request(`/api/v1/agent/sales/${encodeURIComponent(id)}`);
|
|
20933
|
+
}
|
|
20837
20934
|
};
|
|
20838
20935
|
async function uploadTemporaryImage(http, file2, options = {}) {
|
|
20839
20936
|
const body = new FormData();
|
|
@@ -21221,6 +21318,7 @@ function createAvileoAgent(config2) {
|
|
|
21221
21318
|
const http = new AgentHttpClient(config2);
|
|
21222
21319
|
return {
|
|
21223
21320
|
business: new AgentBusinessResource(http),
|
|
21321
|
+
sales: new AgentSalesResource(http),
|
|
21224
21322
|
operations: new AgentOperationsResource(http),
|
|
21225
21323
|
products: new AgentProductsResource(http),
|
|
21226
21324
|
variants: new AgentVariantsResource(http),
|
|
@@ -21235,10 +21333,21 @@ function createAvileoAgent(config2) {
|
|
|
21235
21333
|
}
|
|
21236
21334
|
|
|
21237
21335
|
// src/config.ts
|
|
21238
|
-
import {
|
|
21336
|
+
import {
|
|
21337
|
+
chmodSync,
|
|
21338
|
+
existsSync,
|
|
21339
|
+
lstatSync,
|
|
21340
|
+
mkdirSync,
|
|
21341
|
+
readFileSync,
|
|
21342
|
+
realpathSync,
|
|
21343
|
+
renameSync,
|
|
21344
|
+
statSync,
|
|
21345
|
+
unlinkSync,
|
|
21346
|
+
writeFileSync
|
|
21347
|
+
} from "fs";
|
|
21239
21348
|
import { randomUUID } from "crypto";
|
|
21240
|
-
import { homedir } from "os";
|
|
21241
|
-
import { dirname, join } from "path";
|
|
21349
|
+
import { homedir, tmpdir } from "os";
|
|
21350
|
+
import { basename, dirname, join, parse as parse3, resolve } from "path";
|
|
21242
21351
|
import { isIP } from "net";
|
|
21243
21352
|
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])\.)/;
|
|
21244
21353
|
function isLocalHostname(hostname3) {
|
|
@@ -21301,13 +21410,12 @@ function localCredentialPath(env = process.env) {
|
|
|
21301
21410
|
"credentials.json"
|
|
21302
21411
|
);
|
|
21303
21412
|
}
|
|
21304
|
-
function
|
|
21305
|
-
|
|
21306
|
-
|
|
21307
|
-
|
|
21308
|
-
|
|
21309
|
-
|
|
21310
|
-
}
|
|
21413
|
+
function localCredentialPathSource(env) {
|
|
21414
|
+
if (env.AVILEO_AGENT_CONFIG_PATH?.trim()) return "AVILEO_AGENT_CONFIG_PATH";
|
|
21415
|
+
if (env.XDG_CONFIG_HOME?.trim()) return "XDG_CONFIG_HOME";
|
|
21416
|
+
return "default";
|
|
21417
|
+
}
|
|
21418
|
+
function parseLocalCredential(parsed) {
|
|
21311
21419
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
21312
21420
|
throw new CliConfigurationError("La credencial local no tiene un formato v\xE1lido");
|
|
21313
21421
|
}
|
|
@@ -21323,6 +21431,60 @@ function readLocalCredential(env = process.env) {
|
|
|
21323
21431
|
}
|
|
21324
21432
|
return { apiKey, baseUrl: normalizeApiBaseUrl(record2.baseUrl) };
|
|
21325
21433
|
}
|
|
21434
|
+
function readCredentialFile(env) {
|
|
21435
|
+
const path = localCredentialPath(env);
|
|
21436
|
+
const pathSource = localCredentialPathSource(env);
|
|
21437
|
+
let raw;
|
|
21438
|
+
try {
|
|
21439
|
+
raw = readFileSync(path, "utf8");
|
|
21440
|
+
} catch (error62) {
|
|
21441
|
+
const errorCode2 = error62?.code;
|
|
21442
|
+
if (errorCode2 === "ENOENT") return { status: "missing", path, pathSource };
|
|
21443
|
+
return {
|
|
21444
|
+
status: "unreadable",
|
|
21445
|
+
path,
|
|
21446
|
+
pathSource,
|
|
21447
|
+
...typeof errorCode2 === "string" ? { errorCode: errorCode2 } : {}
|
|
21448
|
+
};
|
|
21449
|
+
}
|
|
21450
|
+
let parsed;
|
|
21451
|
+
try {
|
|
21452
|
+
parsed = JSON.parse(raw);
|
|
21453
|
+
} catch {
|
|
21454
|
+
return { status: "invalid_json", path, pathSource };
|
|
21455
|
+
}
|
|
21456
|
+
try {
|
|
21457
|
+
return { status: "ok", credential: parseLocalCredential(parsed), path, pathSource };
|
|
21458
|
+
} catch (error62) {
|
|
21459
|
+
const failure2 = error62 instanceof CliConfigurationError ? error62 : new CliConfigurationError("La credencial local no tiene un formato v\xE1lido");
|
|
21460
|
+
return { status: "invalid_shape", path, pathSource, errorCode: failure2.code, error: failure2 };
|
|
21461
|
+
}
|
|
21462
|
+
}
|
|
21463
|
+
function inspectLocalCredential(env = process.env) {
|
|
21464
|
+
const result = readCredentialFile(env);
|
|
21465
|
+
if (result.status === "ok") {
|
|
21466
|
+
return {
|
|
21467
|
+
status: "ok",
|
|
21468
|
+
credential: result.credential,
|
|
21469
|
+
path: result.path,
|
|
21470
|
+
pathSource: result.pathSource,
|
|
21471
|
+
...observedCredentialModes(result.path)
|
|
21472
|
+
};
|
|
21473
|
+
}
|
|
21474
|
+
return {
|
|
21475
|
+
status: result.status,
|
|
21476
|
+
path: result.path,
|
|
21477
|
+
pathSource: result.pathSource,
|
|
21478
|
+
...result.errorCode === void 0 ? {} : { errorCode: result.errorCode },
|
|
21479
|
+
...result.status === "missing" ? {} : observedCredentialModes(result.path)
|
|
21480
|
+
};
|
|
21481
|
+
}
|
|
21482
|
+
function readLocalCredential(env = process.env) {
|
|
21483
|
+
const result = readCredentialFile(env);
|
|
21484
|
+
if (result.status === "ok") return result.credential;
|
|
21485
|
+
if (result.error) throw result.error;
|
|
21486
|
+
return null;
|
|
21487
|
+
}
|
|
21326
21488
|
function resolveCredential(env = process.env) {
|
|
21327
21489
|
const override = overrideBaseUrl(env);
|
|
21328
21490
|
if (env.AVILEO_AGENT_REQUIRE_EXPLICIT_ORIGIN === "1" && override === void 0) {
|
|
@@ -21350,6 +21512,152 @@ function resolveCredential(env = process.env) {
|
|
|
21350
21512
|
}
|
|
21351
21513
|
return { ...local, source: "local" };
|
|
21352
21514
|
}
|
|
21515
|
+
var DEFAULT_CREDENTIAL_PATH_HINT = "~/.config/avileo/credentials.json";
|
|
21516
|
+
function formatMode(mode) {
|
|
21517
|
+
const masked = mode & 4095;
|
|
21518
|
+
return masked > 511 ? masked.toString(8) : `0${masked.toString(8).padStart(3, "0")}`;
|
|
21519
|
+
}
|
|
21520
|
+
function observedCredentialModes(path) {
|
|
21521
|
+
const modes = {};
|
|
21522
|
+
const file2 = statSync(path, { throwIfNoEntry: false });
|
|
21523
|
+
if (file2) modes.fileMode = formatMode(file2.mode);
|
|
21524
|
+
const directory = statSync(dirname(path), { throwIfNoEntry: false });
|
|
21525
|
+
if (directory) modes.directoryMode = formatMode(directory.mode);
|
|
21526
|
+
return modes;
|
|
21527
|
+
}
|
|
21528
|
+
function sharedTempRoots() {
|
|
21529
|
+
const roots = [];
|
|
21530
|
+
for (const candidate of ["/tmp", "/var/tmp", tmpdir()]) {
|
|
21531
|
+
try {
|
|
21532
|
+
roots.push(realpathSync(candidate));
|
|
21533
|
+
} catch {
|
|
21534
|
+
}
|
|
21535
|
+
}
|
|
21536
|
+
return roots;
|
|
21537
|
+
}
|
|
21538
|
+
function resolveThroughExistingAncestors(targetPath) {
|
|
21539
|
+
const absolute = resolve(targetPath);
|
|
21540
|
+
const missingSegments = [];
|
|
21541
|
+
let existingAncestor = absolute;
|
|
21542
|
+
while (!existsSync(existingAncestor)) {
|
|
21543
|
+
const parent = dirname(existingAncestor);
|
|
21544
|
+
if (parent === existingAncestor) break;
|
|
21545
|
+
missingSegments.unshift(basename(existingAncestor));
|
|
21546
|
+
existingAncestor = parent;
|
|
21547
|
+
}
|
|
21548
|
+
const realAncestor = realpathSync(existingAncestor);
|
|
21549
|
+
return missingSegments.length === 0 ? realAncestor : resolve(realAncestor, ...missingSegments);
|
|
21550
|
+
}
|
|
21551
|
+
function findRepositoryAncestor(startPath) {
|
|
21552
|
+
let current = startPath;
|
|
21553
|
+
while (true) {
|
|
21554
|
+
if (statSync(join(current, ".git"), { throwIfNoEntry: false })) return current;
|
|
21555
|
+
const parent = dirname(current);
|
|
21556
|
+
if (parent === current) return null;
|
|
21557
|
+
current = parent;
|
|
21558
|
+
}
|
|
21559
|
+
}
|
|
21560
|
+
function assertOutsideRepository(resolvedPath) {
|
|
21561
|
+
const repositoryRoot = findRepositoryAncestor(resolvedPath);
|
|
21562
|
+
if (repositoryRoot === null) return;
|
|
21563
|
+
throw new CliConfigurationError(
|
|
21564
|
+
`No se puede guardar la credencial dentro de un repositorio: ${repositoryRoot} contiene .git. Usa la ruta por defecto ${DEFAULT_CREDENTIAL_PATH_HINT} o define AVILEO_AGENT_CONFIG_PATH fuera del \xE1rbol del repositorio.`
|
|
21565
|
+
);
|
|
21566
|
+
}
|
|
21567
|
+
var UNRESOLVABLE_PARENT_CODES = {
|
|
21568
|
+
EEXIST: true,
|
|
21569
|
+
ELOOP: true,
|
|
21570
|
+
ENOENT: true,
|
|
21571
|
+
ENOTDIR: true
|
|
21572
|
+
};
|
|
21573
|
+
function findBrokenSymlinkAncestor(targetPath) {
|
|
21574
|
+
const absolute = resolve(targetPath);
|
|
21575
|
+
const segments = [];
|
|
21576
|
+
let current = absolute;
|
|
21577
|
+
while (true) {
|
|
21578
|
+
const parent = dirname(current);
|
|
21579
|
+
if (parent === current) break;
|
|
21580
|
+
segments.unshift(basename(current));
|
|
21581
|
+
current = parent;
|
|
21582
|
+
}
|
|
21583
|
+
let walked = parse3(absolute).root;
|
|
21584
|
+
for (const segment of segments) {
|
|
21585
|
+
walked = join(walked, segment);
|
|
21586
|
+
const stats = lstatSync(walked, { throwIfNoEntry: false });
|
|
21587
|
+
if (!stats) return null;
|
|
21588
|
+
if (!stats.isSymbolicLink()) continue;
|
|
21589
|
+
try {
|
|
21590
|
+
realpathSync(walked);
|
|
21591
|
+
} catch {
|
|
21592
|
+
return walked;
|
|
21593
|
+
}
|
|
21594
|
+
}
|
|
21595
|
+
return null;
|
|
21596
|
+
}
|
|
21597
|
+
function describeUnresolvableParent(parentPath, error62) {
|
|
21598
|
+
const code = error62?.code;
|
|
21599
|
+
if (typeof code !== "string" || UNRESOLVABLE_PARENT_CODES[code] !== true) return null;
|
|
21600
|
+
const brokenLink = findBrokenSymlinkAncestor(parentPath);
|
|
21601
|
+
const subject = brokenLink === null ? `${parentPath} contiene un enlace simb\xF3lico` : `${brokenLink} es un enlace simb\xF3lico`;
|
|
21602
|
+
return new CliConfigurationError(
|
|
21603
|
+
`No se pudo preparar el directorio de la credencial ${parentPath}: ${subject} roto o circular. Corrige o elimina ese enlace, o usa la ruta por defecto ${DEFAULT_CREDENTIAL_PATH_HINT} o un directorio privado 0700 fuera del repositorio.`
|
|
21604
|
+
);
|
|
21605
|
+
}
|
|
21606
|
+
function decideParentDirectoryAction(input2) {
|
|
21607
|
+
const fullMode = input2.mode & 4095;
|
|
21608
|
+
if ((fullMode & 63) === 0) return "ok";
|
|
21609
|
+
if (input2.isSharedTempRoot || (fullMode & 512) !== 0) return "refuse-shared";
|
|
21610
|
+
if (input2.ownerUid === input2.processUid) return "repair";
|
|
21611
|
+
return "refuse-foreign";
|
|
21612
|
+
}
|
|
21613
|
+
function assertPrivateParentDirectory(parentPath) {
|
|
21614
|
+
const stats = statSync(parentPath);
|
|
21615
|
+
const fullMode = stats.mode & 4095;
|
|
21616
|
+
const processUid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
21617
|
+
const action = decideParentDirectoryAction({
|
|
21618
|
+
mode: fullMode,
|
|
21619
|
+
ownerUid: stats.uid,
|
|
21620
|
+
processUid,
|
|
21621
|
+
isSharedTempRoot: sharedTempRoots().includes(parentPath)
|
|
21622
|
+
});
|
|
21623
|
+
if (action === "ok") return;
|
|
21624
|
+
if (action === "refuse-shared") {
|
|
21625
|
+
throw new CliConfigurationError(
|
|
21626
|
+
`El directorio padre de la credencial es un directorio temporal compartido (modo ${formatMode(fullMode)}) pensado para archivos temporales: no guardes credenciales ah\xED ni cambies sus permisos. Usa un subdirectorio privado 0700, por ejemplo mkdtempSync(join(tmpdir(), 'avileo-')), o la ruta por defecto ${DEFAULT_CREDENTIAL_PATH_HINT}.`
|
|
21627
|
+
);
|
|
21628
|
+
}
|
|
21629
|
+
if (action === "refuse-foreign") {
|
|
21630
|
+
throw new CliConfigurationError(
|
|
21631
|
+
`El directorio de credenciales ${parentPath} tiene permisos ${formatMode(fullMode)} y pertenece a otro usuario (uid ${stats.uid}; este proceso usa uid ${processUid}), as\xED que permite acceso de grupo o de otros usuarios y no se puede reparar autom\xE1ticamente. Usa la ruta por defecto ${DEFAULT_CREDENTIAL_PATH_HINT} o un directorio privado propio 0700.`
|
|
21632
|
+
);
|
|
21633
|
+
}
|
|
21634
|
+
chmodSync(parentPath, 448);
|
|
21635
|
+
const repairedMode = statSync(parentPath).mode & 511;
|
|
21636
|
+
if (repairedMode !== 448) {
|
|
21637
|
+
throw new CliConfigurationError(
|
|
21638
|
+
`El directorio de credenciales ${parentPath} qued\xF3 con permisos ${formatMode(repairedMode)} tras repararlo; se requiere 0700.`
|
|
21639
|
+
);
|
|
21640
|
+
}
|
|
21641
|
+
}
|
|
21642
|
+
function assertSafeCredentialPath(targetPath) {
|
|
21643
|
+
const resolvedTarget = resolve(targetPath);
|
|
21644
|
+
const parentPath = dirname(resolvedTarget);
|
|
21645
|
+
try {
|
|
21646
|
+
const resolvedParent = resolveThroughExistingAncestors(parentPath);
|
|
21647
|
+
assertOutsideRepository(resolvedParent);
|
|
21648
|
+
mkdirSync(resolvedParent, { recursive: true, mode: 448 });
|
|
21649
|
+
const realParent = realpathSync(resolvedParent);
|
|
21650
|
+
assertOutsideRepository(realParent);
|
|
21651
|
+
assertPrivateParentDirectory(realParent);
|
|
21652
|
+
} catch (error62) {
|
|
21653
|
+
if (error62 instanceof CliConfigurationError) throw error62;
|
|
21654
|
+
throw describeUnresolvableParent(parentPath, error62) ?? error62;
|
|
21655
|
+
}
|
|
21656
|
+
}
|
|
21657
|
+
function errorCodeOf(error62) {
|
|
21658
|
+
const code = error62?.code;
|
|
21659
|
+
return typeof code === "string" && code.length > 0 ? code : "UNKNOWN";
|
|
21660
|
+
}
|
|
21353
21661
|
function saveLocalCredential(credential, env = process.env) {
|
|
21354
21662
|
const apiKey = normalizeAgentKey(
|
|
21355
21663
|
credential.apiKey,
|
|
@@ -21357,13 +21665,46 @@ function saveLocalCredential(credential, env = process.env) {
|
|
|
21357
21665
|
);
|
|
21358
21666
|
const baseUrl = normalizeApiBaseUrl(credential.baseUrl);
|
|
21359
21667
|
const path = localCredentialPath(env);
|
|
21360
|
-
|
|
21668
|
+
assertSafeCredentialPath(path);
|
|
21361
21669
|
const temporaryPath = `${path}.${randomUUID()}.tmp`;
|
|
21362
|
-
|
|
21670
|
+
try {
|
|
21671
|
+
writeFileSync(temporaryPath, `${JSON.stringify({ apiKey, baseUrl })}
|
|
21363
21672
|
`, { mode: 384 });
|
|
21364
|
-
|
|
21365
|
-
|
|
21366
|
-
|
|
21673
|
+
chmodSync(temporaryPath, 384);
|
|
21674
|
+
renameSync(temporaryPath, path);
|
|
21675
|
+
} catch (error62) {
|
|
21676
|
+
throw new CliConfigurationError(
|
|
21677
|
+
`No se pudo guardar la credencial local en ${path} (${errorCodeOf(error62)}).`
|
|
21678
|
+
);
|
|
21679
|
+
} finally {
|
|
21680
|
+
try {
|
|
21681
|
+
unlinkSync(temporaryPath);
|
|
21682
|
+
} catch {
|
|
21683
|
+
}
|
|
21684
|
+
}
|
|
21685
|
+
try {
|
|
21686
|
+
chmodSync(path, 384);
|
|
21687
|
+
} catch (error62) {
|
|
21688
|
+
throw new CliConfigurationError(
|
|
21689
|
+
`La credencial local en ${path} se guard\xF3 pero no se pudo ajustar a 0600 (${errorCodeOf(error62)}). Ejecuta chmod 600 ${path}.`
|
|
21690
|
+
);
|
|
21691
|
+
}
|
|
21692
|
+
const finalMode = statSync(path).mode & 511;
|
|
21693
|
+
if (finalMode !== 384) {
|
|
21694
|
+
throw new CliConfigurationError(
|
|
21695
|
+
`La credencial local en ${path} qued\xF3 con permisos ${formatMode(finalMode)}; se requiere 0600. Ejecuta chmod 600 ${path}.`
|
|
21696
|
+
);
|
|
21697
|
+
}
|
|
21698
|
+
}
|
|
21699
|
+
function inspectLocalCredentialPermissions(env = process.env) {
|
|
21700
|
+
const path = localCredentialPath(env);
|
|
21701
|
+
const { fileMode, directoryMode } = observedCredentialModes(path);
|
|
21702
|
+
if (!fileMode || !directoryMode) {
|
|
21703
|
+
throw new CliConfigurationError(
|
|
21704
|
+
`No se pudieron leer los permisos de la credencial local en ${path}`
|
|
21705
|
+
);
|
|
21706
|
+
}
|
|
21707
|
+
return { path, fileMode, directoryMode };
|
|
21367
21708
|
}
|
|
21368
21709
|
function removeLocalCredential(env = process.env) {
|
|
21369
21710
|
try {
|
|
@@ -21548,13 +21889,41 @@ function registerBusinessCommands(root, getClient) {
|
|
|
21548
21889
|
// src/commands/catalog.ts
|
|
21549
21890
|
import { createHash } from "crypto";
|
|
21550
21891
|
import { readFile as readFile2, stat } from "fs/promises";
|
|
21551
|
-
import { basename as
|
|
21892
|
+
import { basename as basename3, extname } from "path";
|
|
21893
|
+
|
|
21894
|
+
// src/commands/import-example.ts
|
|
21895
|
+
var CATALOG_IMPORT_EXAMPLE = {
|
|
21896
|
+
source: "supplier-file",
|
|
21897
|
+
products: [
|
|
21898
|
+
{
|
|
21899
|
+
externalRef: { source: "supplier-file", externalId: "SKU-001" },
|
|
21900
|
+
name: "Arroz extra 1 kg",
|
|
21901
|
+
description: "Arroz extra de grano largo, bolsa de 1 kg.",
|
|
21902
|
+
category: { name: "Abarrotes" },
|
|
21903
|
+
unit: "unidad",
|
|
21904
|
+
basePrice: "6.50",
|
|
21905
|
+
costPrice: "5.20",
|
|
21906
|
+
isActive: true,
|
|
21907
|
+
images: [{ kind: "file", path: "./arroz-extra-1kg.jpg" }],
|
|
21908
|
+
variants: [
|
|
21909
|
+
{
|
|
21910
|
+
name: "Bolsa 1 kg",
|
|
21911
|
+
sku: "SKU-001-1KG",
|
|
21912
|
+
unitQuantity: "1",
|
|
21913
|
+
price: "6.50",
|
|
21914
|
+
initialStock: "20",
|
|
21915
|
+
isActive: true
|
|
21916
|
+
}
|
|
21917
|
+
]
|
|
21918
|
+
}
|
|
21919
|
+
]
|
|
21920
|
+
};
|
|
21552
21921
|
|
|
21553
21922
|
// src/commands/import-images.ts
|
|
21554
21923
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
21555
21924
|
import { constants } from "fs";
|
|
21556
21925
|
import { open as open2 } from "fs/promises";
|
|
21557
|
-
import { basename, dirname as dirname2, resolve } from "path";
|
|
21926
|
+
import { basename as basename2, dirname as dirname2, resolve as resolve2 } from "path";
|
|
21558
21927
|
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
21559
21928
|
var MAX_TEMPORARY_IMAGES = 100;
|
|
21560
21929
|
var MAX_TEMPORARY_BYTES = 100 * 1024 * 1024;
|
|
@@ -21603,7 +21972,7 @@ async function readImage(path, remainingBytes) {
|
|
|
21603
21972
|
const bytes = buffer.subarray(0, length);
|
|
21604
21973
|
const mimeType = imageMimeType(bytes);
|
|
21605
21974
|
if (!mimeType) invalidInput("Solo se permiten im\xE1genes JPEG, PNG, WebP o GIF");
|
|
21606
|
-
return new File([bytes],
|
|
21975
|
+
return new File([bytes], basename2(path), { type: mimeType });
|
|
21607
21976
|
} catch (error62) {
|
|
21608
21977
|
if (error62 instanceof CliProtocolError) throw error62;
|
|
21609
21978
|
invalidInput("No se pudo leer una imagen local del cat\xE1logo");
|
|
@@ -21614,7 +21983,7 @@ async function readImage(path, remainingBytes) {
|
|
|
21614
21983
|
function localImageSources(inputPath) {
|
|
21615
21984
|
const paths = /* @__PURE__ */ new Map();
|
|
21616
21985
|
const placeholders = /* @__PURE__ */ new Map();
|
|
21617
|
-
const baseDirectory = dirname2(
|
|
21986
|
+
const baseDirectory = dirname2(resolve2(inputPath));
|
|
21618
21987
|
const normalizeImages = (value) => {
|
|
21619
21988
|
if (!Array.isArray(value)) return value;
|
|
21620
21989
|
return value.map((source) => {
|
|
@@ -21622,7 +21991,7 @@ function localImageSources(inputPath) {
|
|
|
21622
21991
|
if (Object.keys(source).some((key) => key !== "kind" && key !== "path") || typeof source.path !== "string" || source.path.trim().length === 0 || source.path.includes("\0")) {
|
|
21623
21992
|
invalidInput("Cada imagen local requiere \xFAnicamente kind: file y un path v\xE1lido");
|
|
21624
21993
|
}
|
|
21625
|
-
const path =
|
|
21994
|
+
const path = resolve2(baseDirectory, source.path);
|
|
21626
21995
|
let placeholder = paths.get(path);
|
|
21627
21996
|
if (!placeholder) {
|
|
21628
21997
|
placeholder = randomUUID2();
|
|
@@ -22081,7 +22450,7 @@ function registerAssetCommands(catalog, getClient) {
|
|
|
22081
22450
|
if (!wantsApply(command)) {
|
|
22082
22451
|
emitSuccess({
|
|
22083
22452
|
validated: "local",
|
|
22084
|
-
file:
|
|
22453
|
+
file: basename3(filePath),
|
|
22085
22454
|
sizeBytes: fileStat.size
|
|
22086
22455
|
});
|
|
22087
22456
|
return;
|
|
@@ -22095,7 +22464,7 @@ function registerAssetCommands(catalog, getClient) {
|
|
|
22095
22464
|
);
|
|
22096
22465
|
}
|
|
22097
22466
|
const contents = await readFile2(filePath);
|
|
22098
|
-
const file2 = new File([contents],
|
|
22467
|
+
const file2 = new File([contents], basename3(filePath), { type: mimeType });
|
|
22099
22468
|
const rawApprovalId = command.optsWithGlobals().approvalId;
|
|
22100
22469
|
if (typeof rawApprovalId === "string") {
|
|
22101
22470
|
emitSuccess(await getClient().assets.upload(file2, requireId(rawApprovalId, "approvalId")));
|
|
@@ -22187,6 +22556,7 @@ function registerImportCommands(catalog, getClient) {
|
|
|
22187
22556
|
);
|
|
22188
22557
|
}
|
|
22189
22558
|
);
|
|
22559
|
+
imports.command("example").description("Imprime el payload can\xF3nico de una importaci\xF3n").action(() => emitSuccess(CATALOG_IMPORT_EXAMPLE));
|
|
22190
22560
|
imports.command("status <importId>").action(async (importId) => {
|
|
22191
22561
|
emitSuccess(await getClient().imports.get(requireId(importId, "importId")));
|
|
22192
22562
|
});
|
|
@@ -22222,8 +22592,59 @@ function registerOperationBatchCommands(operation, getClient) {
|
|
|
22222
22592
|
});
|
|
22223
22593
|
}
|
|
22224
22594
|
|
|
22595
|
+
// src/commands/sales.ts
|
|
22596
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22597
|
+
function parseLimit(value) {
|
|
22598
|
+
const parsed = Number(value);
|
|
22599
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100) {
|
|
22600
|
+
throw new CliProtocolError("CLI_VALIDATION_ERROR", "--limit debe ser un entero entre 1 y 100", {
|
|
22601
|
+
limit: value
|
|
22602
|
+
});
|
|
22603
|
+
}
|
|
22604
|
+
return parsed;
|
|
22605
|
+
}
|
|
22606
|
+
function parseChannel(value) {
|
|
22607
|
+
if (value === "web" || value === "tienda") return value;
|
|
22608
|
+
throw new CliProtocolError("CLI_VALIDATION_ERROR", "--channel debe ser web o tienda", {
|
|
22609
|
+
channel: value
|
|
22610
|
+
});
|
|
22611
|
+
}
|
|
22612
|
+
function parseType(value) {
|
|
22613
|
+
if (value === "instant_sale" || value === "pre_order") return value;
|
|
22614
|
+
throw new CliProtocolError("CLI_VALIDATION_ERROR", "--type debe ser instant_sale o pre_order", {
|
|
22615
|
+
type: value
|
|
22616
|
+
});
|
|
22617
|
+
}
|
|
22618
|
+
function requireUuid(value, name) {
|
|
22619
|
+
const trimmed = value.trim();
|
|
22620
|
+
if (!UUID_PATTERN.test(trimmed)) {
|
|
22621
|
+
throw new CliProtocolError("CLI_VALIDATION_ERROR", `${name} debe ser un UUID v\xE1lido`);
|
|
22622
|
+
}
|
|
22623
|
+
return trimmed;
|
|
22624
|
+
}
|
|
22625
|
+
function registerSalesCommands(root, getClient) {
|
|
22626
|
+
const sales = root.command("sales").description("Consulta ventas del negocio (solo lectura, tel\xE9fono parcialmente enmascarado)");
|
|
22627
|
+
sales.command("list").description("Lista ventas con filtros opcionales").option("--status <status>", "Estado de la venta").option("--channel <channel>", "Canal de la venta (web|tienda)", parseChannel).option("--type <type>", "Tipo de venta (instant_sale|pre_order)", parseType).option("--since <iso>", "Fecha m\xEDnima (ISO 8601)").option("--until <iso>", "Fecha m\xE1xima (ISO 8601)").option("--limit <number>", "M\xE1ximo de resultados (1-100)", parseLimit).option("--cursor <cursor>", "Cursor de paginaci\xF3n").action(async (options) => {
|
|
22628
|
+
emitSuccess(
|
|
22629
|
+
await getClient().sales.list({
|
|
22630
|
+
...options.status === void 0 ? {} : { status: options.status },
|
|
22631
|
+
...options.channel === void 0 ? {} : { channel: options.channel },
|
|
22632
|
+
...options.type === void 0 ? {} : { type: options.type },
|
|
22633
|
+
...options.since === void 0 ? {} : { since: options.since },
|
|
22634
|
+
...options.until === void 0 ? {} : { until: options.until },
|
|
22635
|
+
...options.limit === void 0 ? {} : { limit: options.limit },
|
|
22636
|
+
...options.cursor === void 0 ? {} : { cursor: options.cursor }
|
|
22637
|
+
})
|
|
22638
|
+
);
|
|
22639
|
+
});
|
|
22640
|
+
sales.command("get <id>").description("Consulta el detalle de una venta").action(async (id) => {
|
|
22641
|
+
emitSuccess(await getClient().sales.get(requireUuid(id, "id")));
|
|
22642
|
+
});
|
|
22643
|
+
}
|
|
22644
|
+
|
|
22225
22645
|
// src/commands/auth.ts
|
|
22226
22646
|
import { spawn } from "child_process";
|
|
22647
|
+
import { dirname as dirname3 } from "path";
|
|
22227
22648
|
function safeStartResult(start, browserOpened) {
|
|
22228
22649
|
return {
|
|
22229
22650
|
status: "pending",
|
|
@@ -22249,7 +22670,7 @@ function safeFinalResult(start, browserOpened, result) {
|
|
|
22249
22670
|
};
|
|
22250
22671
|
}
|
|
22251
22672
|
function sleep(milliseconds) {
|
|
22252
|
-
return new Promise((
|
|
22673
|
+
return new Promise((resolve3) => setTimeout(resolve3, milliseconds));
|
|
22253
22674
|
}
|
|
22254
22675
|
function readAgentKeyFromTty(prompt = "Agent Key de Avileo: ") {
|
|
22255
22676
|
if (!process.stdin.isTTY || !process.stderr.isTTY) {
|
|
@@ -22258,7 +22679,7 @@ function readAgentKeyFromTty(prompt = "Agent Key de Avileo: ") {
|
|
|
22258
22679
|
"auth configure requiere una terminal interactiva; usa AVILEO_AGENT_API_KEY en CI/CD"
|
|
22259
22680
|
);
|
|
22260
22681
|
}
|
|
22261
|
-
return new Promise((
|
|
22682
|
+
return new Promise((resolve3, reject) => {
|
|
22262
22683
|
let value = "";
|
|
22263
22684
|
const input2 = process.stdin;
|
|
22264
22685
|
const output2 = process.stderr;
|
|
@@ -22272,7 +22693,7 @@ function readAgentKeyFromTty(prompt = "Agent Key de Avileo: ") {
|
|
|
22272
22693
|
cleanup();
|
|
22273
22694
|
output2.write("\n");
|
|
22274
22695
|
if (result instanceof Error) reject(result);
|
|
22275
|
-
else
|
|
22696
|
+
else resolve3(result);
|
|
22276
22697
|
};
|
|
22277
22698
|
const onData = (chunk) => {
|
|
22278
22699
|
for (const character of String(chunk)) {
|
|
@@ -22303,12 +22724,12 @@ function readAgentKeyFromTty(prompt = "Agent Key de Avileo: ") {
|
|
|
22303
22724
|
});
|
|
22304
22725
|
}
|
|
22305
22726
|
async function openWithExecutable(command, args) {
|
|
22306
|
-
return new Promise((
|
|
22727
|
+
return new Promise((resolve3) => {
|
|
22307
22728
|
const child = spawn(command, args, { stdio: "ignore", shell: false, detached: true });
|
|
22308
|
-
child.once("error", () =>
|
|
22729
|
+
child.once("error", () => resolve3(false));
|
|
22309
22730
|
child.once("spawn", () => {
|
|
22310
22731
|
child.unref();
|
|
22311
|
-
|
|
22732
|
+
resolve3(true);
|
|
22312
22733
|
});
|
|
22313
22734
|
});
|
|
22314
22735
|
}
|
|
@@ -22400,7 +22821,15 @@ async function login(options) {
|
|
|
22400
22821
|
);
|
|
22401
22822
|
}
|
|
22402
22823
|
saveLocalCredential({ apiKey: result.agentKey, baseUrl }, options.env);
|
|
22403
|
-
|
|
22824
|
+
const permissions = inspectLocalCredentialPermissions(options.env);
|
|
22825
|
+
emitSuccess({
|
|
22826
|
+
...safeFinalResult(start, browserOpened, result),
|
|
22827
|
+
baseUrl,
|
|
22828
|
+
credentialPath: permissions.path,
|
|
22829
|
+
credentialMode: permissions.fileMode,
|
|
22830
|
+
credentialDirMode: permissions.directoryMode,
|
|
22831
|
+
durability: "La credencial qued\xF3 guardada solo en este equipo: si se pierde el archivo tendr\xE1s que emparejar de nuevo con \xABavileo auth login\xBB."
|
|
22832
|
+
});
|
|
22404
22833
|
return;
|
|
22405
22834
|
}
|
|
22406
22835
|
throw new CliProtocolError("CLI_AUTH_TIMEOUT", "La autorizaci\xF3n expir\xF3 antes de ser aprobada");
|
|
@@ -22410,33 +22839,206 @@ async function configure(options) {
|
|
|
22410
22839
|
assertIsolatedDevelopmentPairing(options);
|
|
22411
22840
|
const apiKey = await options.readSecret("Agent Key de Avileo (no se mostrar\xE1): ");
|
|
22412
22841
|
saveLocalCredential({ apiKey, baseUrl }, options.env);
|
|
22842
|
+
const permissions = inspectLocalCredentialPermissions(options.env);
|
|
22413
22843
|
emitSuccess({
|
|
22414
22844
|
configured: true,
|
|
22415
22845
|
source: "local",
|
|
22416
22846
|
baseUrl,
|
|
22417
|
-
credentialPath: localCredentialPath(options.env)
|
|
22847
|
+
credentialPath: localCredentialPath(options.env),
|
|
22848
|
+
credentialMode: permissions.fileMode,
|
|
22849
|
+
credentialDirMode: permissions.directoryMode
|
|
22418
22850
|
});
|
|
22419
22851
|
}
|
|
22852
|
+
var PORTAL_URL_PLACEHOLDER = "<URL_DEL_PORTAL>";
|
|
22853
|
+
function inspectedState(inspection) {
|
|
22854
|
+
switch (inspection.status) {
|
|
22855
|
+
case "ok":
|
|
22856
|
+
return "absent";
|
|
22857
|
+
case "missing":
|
|
22858
|
+
return "absent";
|
|
22859
|
+
default:
|
|
22860
|
+
return inspection.status;
|
|
22861
|
+
}
|
|
22862
|
+
}
|
|
22863
|
+
function defaultCredentialPath(env) {
|
|
22864
|
+
return localCredentialPath({ XDG_CONFIG_HOME: env.XDG_CONFIG_HOME });
|
|
22865
|
+
}
|
|
22866
|
+
function permissionWarning(inspection) {
|
|
22867
|
+
const directoryPath = dirname3(inspection.path);
|
|
22868
|
+
const { fileMode, directoryMode } = inspection;
|
|
22869
|
+
const warnings = [];
|
|
22870
|
+
if (fileMode !== void 0 && (Number.parseInt(fileMode, 8) & 63) !== 0) {
|
|
22871
|
+
warnings.push(
|
|
22872
|
+
`El archivo ${inspection.path} tiene permisos ${fileMode}; ejecuta chmod 600 ${inspection.path}.`
|
|
22873
|
+
);
|
|
22874
|
+
}
|
|
22875
|
+
if (directoryMode !== void 0 && (Number.parseInt(directoryMode, 8) & 63) !== 0) {
|
|
22876
|
+
warnings.push(
|
|
22877
|
+
`El directorio ${directoryPath} tiene permisos ${directoryMode}; ejecuta chmod 700 ${directoryPath}.`
|
|
22878
|
+
);
|
|
22879
|
+
}
|
|
22880
|
+
return warnings.length > 0 ? ` ${warnings.join(" ")}` : "";
|
|
22881
|
+
}
|
|
22882
|
+
function defaultCredentialRecovery(env) {
|
|
22883
|
+
const defaultInspection = inspectLocalCredential({ XDG_CONFIG_HOME: env.XDG_CONFIG_HOME });
|
|
22884
|
+
if (defaultInspection.status !== "ok") return "";
|
|
22885
|
+
return ` Hay una credencial legible en la ruta por defecto (${defaultInspection.path}); para usarla ejecuta \`env -u AVILEO_AGENT_CONFIG_PATH avileo auth status\`.`;
|
|
22886
|
+
}
|
|
22887
|
+
function nextStepForInspection(inspection, env) {
|
|
22888
|
+
switch (inspection.status) {
|
|
22889
|
+
case "missing":
|
|
22890
|
+
if (inspection.pathSource === "AVILEO_AGENT_CONFIG_PATH") {
|
|
22891
|
+
return `AVILEO_AGENT_CONFIG_PATH apunta a ${inspection.path}, pero ese archivo no existe. Ejecuta \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\` para crearlo en esa ruta, o quita la variable AVILEO_AGENT_CONFIG_PATH para volver a la ruta por defecto (${defaultCredentialPath(env)}).` + defaultCredentialRecovery(env);
|
|
22892
|
+
}
|
|
22893
|
+
return `No hay una credencial guardada en ${inspection.path}. Ejecuta \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\` para vincular esta m\xE1quina.`;
|
|
22894
|
+
case "unreadable":
|
|
22895
|
+
return `No se pudo leer ${inspection.path}${inspection.errorCode ? ` (${inspection.errorCode})` : ""}. Revisa los permisos del archivo y vuelve a ejecutar \`avileo auth login\`.`;
|
|
22896
|
+
case "invalid_json":
|
|
22897
|
+
return `El archivo ${inspection.path} no contiene JSON v\xE1lido. Vuelve a ejecutar \`avileo auth login\` para regenerarlo.`;
|
|
22898
|
+
case "invalid_shape":
|
|
22899
|
+
return `La credencial en ${inspection.path} no es una Agent Key v\xE1lida o le falta el origen vinculado. Vuelve a ejecutar \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\`.`;
|
|
22900
|
+
case "ok":
|
|
22901
|
+
return "La credencial local est\xE1 disponible.";
|
|
22902
|
+
}
|
|
22903
|
+
}
|
|
22904
|
+
function describeResolutionFailure(error62, inspection, env) {
|
|
22905
|
+
const originIssue = error62 instanceof CliOriginConflictError || error62 instanceof CliOriginUnsupportedError;
|
|
22906
|
+
if (originIssue || env.AVILEO_AGENT_API_KEY?.trim()) {
|
|
22907
|
+
return { state: "invalid", nextStep: error62.message };
|
|
22908
|
+
}
|
|
22909
|
+
if (inspection.status !== "ok") {
|
|
22910
|
+
return {
|
|
22911
|
+
state: inspectedState(inspection),
|
|
22912
|
+
nextStep: nextStepForInspection(inspection, env)
|
|
22913
|
+
};
|
|
22914
|
+
}
|
|
22915
|
+
return { state: "invalid", nextStep: error62.message };
|
|
22916
|
+
}
|
|
22917
|
+
function lookupFailureState(error62) {
|
|
22918
|
+
if (error62 instanceof AgentNetworkError) return "unreachable";
|
|
22919
|
+
if (error62 instanceof AgentAuthenticationError || error62 instanceof AgentPermissionError) {
|
|
22920
|
+
return "invalid";
|
|
22921
|
+
}
|
|
22922
|
+
const status2 = error62?.status;
|
|
22923
|
+
if (status2 === 401 || status2 === 403) return "invalid";
|
|
22924
|
+
return "unreachable";
|
|
22925
|
+
}
|
|
22926
|
+
function errorCode(error62) {
|
|
22927
|
+
const code = error62 && typeof error62 === "object" && "code" in error62 ? error62.code : void 0;
|
|
22928
|
+
return typeof code === "string" ? code : "LOOKUP_FAILED";
|
|
22929
|
+
}
|
|
22930
|
+
function credentialDiagnostic(value) {
|
|
22931
|
+
if (!value || typeof value !== "object") return null;
|
|
22932
|
+
const record2 = value;
|
|
22933
|
+
const state = record2.state;
|
|
22934
|
+
if (state !== "active" && state !== "expired" && state !== "revoked") return null;
|
|
22935
|
+
return {
|
|
22936
|
+
state,
|
|
22937
|
+
expiresAt: typeof record2.expiresAt === "string" ? record2.expiresAt : null
|
|
22938
|
+
};
|
|
22939
|
+
}
|
|
22940
|
+
function isRejectedCredential(error62) {
|
|
22941
|
+
if (error62 instanceof AgentAuthenticationError || error62 instanceof AgentPermissionError) {
|
|
22942
|
+
return true;
|
|
22943
|
+
}
|
|
22944
|
+
const status2 = error62?.status;
|
|
22945
|
+
return status2 === 401 || status2 === 403;
|
|
22946
|
+
}
|
|
22947
|
+
function nextStepForStatus(state, baseUrl) {
|
|
22948
|
+
if (state === "expired") {
|
|
22949
|
+
return `La Agent Key expir\xF3. Renu\xE9vala volviendo a vincular esta m\xE1quina con \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\`.`;
|
|
22950
|
+
}
|
|
22951
|
+
if (state === "revoked") {
|
|
22952
|
+
return `La Agent Key fue revocada. Vuelve a vincular esta m\xE1quina con \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\`.`;
|
|
22953
|
+
}
|
|
22954
|
+
if (state === "invalid") return lookupNextStep("invalid", baseUrl);
|
|
22955
|
+
if (state === "unreachable") return lookupNextStep("unreachable", baseUrl);
|
|
22956
|
+
return lookupNextStep("active", baseUrl);
|
|
22957
|
+
}
|
|
22958
|
+
function lookupNextStep(state, baseUrl) {
|
|
22959
|
+
if (state === "active") {
|
|
22960
|
+
return `La credencial responde contra ${baseUrl}; no hay nada que hacer.`;
|
|
22961
|
+
}
|
|
22962
|
+
if (state === "invalid") {
|
|
22963
|
+
return `El origen ${baseUrl} rechaz\xF3 la credencial. Vuelve a vincular esta m\xE1quina con \`avileo auth login --base-url ${PORTAL_URL_PLACEHOLDER}\`; la clave puede haber sido revocada.`;
|
|
22964
|
+
}
|
|
22965
|
+
return `No se pudo contactar ${baseUrl}. Verifica la conectividad o AVILEO_AGENT_BASE_URL y reintenta con \`avileo auth status\`.`;
|
|
22966
|
+
}
|
|
22420
22967
|
async function status(options) {
|
|
22421
|
-
const
|
|
22968
|
+
const inspection = inspectLocalCredential(options.env);
|
|
22969
|
+
const permissionWarningSuffix = permissionWarning(inspection);
|
|
22970
|
+
let credential = null;
|
|
22971
|
+
let resolution;
|
|
22972
|
+
try {
|
|
22973
|
+
credential = resolveCredential(options.env);
|
|
22974
|
+
} catch (error62) {
|
|
22975
|
+
if (!(error62 instanceof CliConfigurationError)) throw error62;
|
|
22976
|
+
resolution = describeResolutionFailure(error62, inspection, options.env);
|
|
22977
|
+
}
|
|
22422
22978
|
if (!credential) {
|
|
22423
|
-
|
|
22979
|
+
const nextStep = resolution?.nextStep ?? nextStepForInspection(inspection, options.env);
|
|
22980
|
+
emitSuccess({
|
|
22981
|
+
configured: false,
|
|
22982
|
+
state: resolution?.state ?? inspectedState(inspection),
|
|
22983
|
+
source: null,
|
|
22984
|
+
credentialPath: inspection.path,
|
|
22985
|
+
pathSource: inspection.pathSource,
|
|
22986
|
+
credentialMode: inspection.fileMode,
|
|
22987
|
+
credentialDirMode: inspection.directoryMode,
|
|
22988
|
+
baseUrl: null,
|
|
22989
|
+
business: null,
|
|
22990
|
+
nextStep: `${nextStep}${permissionWarningSuffix}`
|
|
22991
|
+
});
|
|
22424
22992
|
return;
|
|
22425
22993
|
}
|
|
22994
|
+
const baseUrl = credential.baseUrl ?? AVILEO_AGENT_API_URL;
|
|
22995
|
+
const client = options.getClient();
|
|
22426
22996
|
let business = null;
|
|
22427
22997
|
let businessLookupError;
|
|
22998
|
+
let state = "active";
|
|
22999
|
+
let diagnostic = null;
|
|
22428
23000
|
try {
|
|
22429
|
-
|
|
23001
|
+
diagnostic = credentialDiagnostic(await client.business.credential());
|
|
22430
23002
|
} catch (error62) {
|
|
22431
|
-
|
|
22432
|
-
|
|
23003
|
+
if (isRejectedCredential(error62)) {
|
|
23004
|
+
state = "invalid";
|
|
23005
|
+
businessLookupError = errorCode(error62);
|
|
23006
|
+
}
|
|
22433
23007
|
}
|
|
23008
|
+
if (state !== "invalid") {
|
|
23009
|
+
if (diagnostic) {
|
|
23010
|
+
state = diagnostic.state;
|
|
23011
|
+
} else {
|
|
23012
|
+
try {
|
|
23013
|
+
business = await client.business.get();
|
|
23014
|
+
} catch (error62) {
|
|
23015
|
+
businessLookupError = errorCode(error62);
|
|
23016
|
+
state = lookupFailureState(error62);
|
|
23017
|
+
}
|
|
23018
|
+
}
|
|
23019
|
+
}
|
|
23020
|
+
if (diagnostic?.state === "active") {
|
|
23021
|
+
try {
|
|
23022
|
+
business = await client.business.get();
|
|
23023
|
+
} catch (error62) {
|
|
23024
|
+
businessLookupError = errorCode(error62);
|
|
23025
|
+
state = lookupFailureState(error62);
|
|
23026
|
+
}
|
|
23027
|
+
}
|
|
23028
|
+
const resolvedNextStep = diagnostic?.state === "active" && state === "invalid" ? `El origen ${baseUrl} reconoce la credencial como activa, pero deneg\xF3 el acceso al negocio. Revisa en Mis agentes los permisos y la autorizaci\xF3n del emisor para el negocio vinculado en este mismo origen. Si persiste, solicita un diagn\xF3stico del backend.` : nextStepForStatus(state, baseUrl);
|
|
22434
23029
|
emitSuccess({
|
|
22435
23030
|
configured: true,
|
|
22436
|
-
|
|
22437
|
-
|
|
23031
|
+
state,
|
|
23032
|
+
source: credential.source === "environment" ? "env" : "local",
|
|
23033
|
+
credentialPath: inspection.path,
|
|
23034
|
+
pathSource: inspection.pathSource,
|
|
23035
|
+
credentialMode: inspection.fileMode,
|
|
23036
|
+
credentialDirMode: inspection.directoryMode,
|
|
23037
|
+
baseUrl,
|
|
22438
23038
|
business,
|
|
22439
|
-
...businessLookupError ? { businessLookupError } : {}
|
|
23039
|
+
...businessLookupError ? { businessLookupError } : {},
|
|
23040
|
+
...diagnostic ? { expiresAt: diagnostic.expiresAt } : {},
|
|
23041
|
+
nextStep: `${resolvedNextStep}${permissionWarningSuffix}`
|
|
22440
23042
|
});
|
|
22441
23043
|
}
|
|
22442
23044
|
async function logout(options) {
|
|
@@ -22500,6 +23102,7 @@ function createProgram(options = {}) {
|
|
|
22500
23102
|
json: () => Boolean(program.opts().json)
|
|
22501
23103
|
});
|
|
22502
23104
|
registerBusinessCommands(program, getClient);
|
|
23105
|
+
registerSalesCommands(program, getClient);
|
|
22503
23106
|
registerCatalogCommands(program, getClient);
|
|
22504
23107
|
const operation = program.command("operation").description("Consulta y aplica operaciones aprobadas en Avileo");
|
|
22505
23108
|
registerOperationBatchCommands(operation, getClient);
|
|
@@ -22528,8 +23131,8 @@ function createProgram(options = {}) {
|
|
|
22528
23131
|
return await parseAsync3(...args);
|
|
22529
23132
|
} catch (error62) {
|
|
22530
23133
|
if (error62 instanceof CliVersionRequested) return program;
|
|
22531
|
-
const
|
|
22532
|
-
if (
|
|
23134
|
+
const errorCode2 = typeof error62 === "object" && error62 !== null && "code" in error62 ? String(error62.code) : "";
|
|
23135
|
+
if (errorCode2 === "commander.helpDisplayed" || errorCode2 === "commander.version")
|
|
22533
23136
|
return program;
|
|
22534
23137
|
emitFailure(toFailure(error62));
|
|
22535
23138
|
process.exitCode = exitCodeFor(error62);
|