lua-cli 3.26.0 → 3.28.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/api-exports.d.ts +84 -1
- package/dist/api-exports.js +413 -33
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +2755 -1003
- package/dist/index.js.map +1 -1
- package/docs/CLI_REFERENCE.md +5 -1
- package/docs/README.md +2 -2
- package/docs/api/LuaWebhook.md +26 -0
- package/package.json +3 -3
- package/template/package.json +1 -1
package/dist/api-exports.js
CHANGED
|
@@ -16,6 +16,8 @@ var __export = (target, all) => {
|
|
|
16
16
|
|
|
17
17
|
// ../shared-types/dist/index.mjs
|
|
18
18
|
import { z } from "zod";
|
|
19
|
+
import { z as z2 } from "zod";
|
|
20
|
+
import { z as z3 } from "zod";
|
|
19
21
|
function isPersonaTextObject(value) {
|
|
20
22
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
21
23
|
const obj = value;
|
|
@@ -384,7 +386,88 @@ function normalizeLuaJobExecutionTimeoutSeconds(timeout) {
|
|
|
384
386
|
}
|
|
385
387
|
return Math.min(Math.max(timeout, LUA_JOB_MIN_TIMEOUT_SECONDS), LUA_JOB_MAX_TIMEOUT_SECONDS);
|
|
386
388
|
}
|
|
387
|
-
|
|
389
|
+
function triggerUrlEnvKey(triggerKey) {
|
|
390
|
+
const upper = triggerKey.trim().replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
|
|
391
|
+
return `${TEMPLATE_TRIGGER_URL_ENV_PREFIX}${upper}`;
|
|
392
|
+
}
|
|
393
|
+
function parsePrincipalContext(value) {
|
|
394
|
+
const parsed = PrincipalContextSchema.safeParse(value);
|
|
395
|
+
return parsed.success ? parsed.data : void 0;
|
|
396
|
+
}
|
|
397
|
+
function isTypedApiKeyPrincipal(context) {
|
|
398
|
+
return context?.subject.subjectType === "apiKey" && context.credential.type === "apiKey" && !context.compatibility;
|
|
399
|
+
}
|
|
400
|
+
function typedApiKeyPrincipalId(context) {
|
|
401
|
+
if (!context || !isTypedApiKeyPrincipal(context) || !context.subject.subjectId || context.credential.id !== context.subject.subjectId || context.actor?.actorType !== "apiKey" || context.actor.actorId !== context.subject.subjectId || context.owner?.type !== "user" || !context.owner.id) {
|
|
402
|
+
return void 0;
|
|
403
|
+
}
|
|
404
|
+
return context.subject.subjectId;
|
|
405
|
+
}
|
|
406
|
+
function parseLuaClientHeader(value) {
|
|
407
|
+
if (typeof value !== "string" || value.length > 64) return void 0;
|
|
408
|
+
const match = CLIENT_HEADER_PATTERN.exec(value.trim());
|
|
409
|
+
if (!match) return void 0;
|
|
410
|
+
const app = LUA_CLIENT_APPS.find((candidate) => candidate === match[1]);
|
|
411
|
+
if (!app) return void 0;
|
|
412
|
+
const wireVersion = match[2];
|
|
413
|
+
if (wireVersion === "unversioned") return {
|
|
414
|
+
app,
|
|
415
|
+
version: "unknown",
|
|
416
|
+
attribution: "unknown"
|
|
417
|
+
};
|
|
418
|
+
const semver = SEMVER_PATTERN.exec(wireVersion);
|
|
419
|
+
if (semver) return {
|
|
420
|
+
app,
|
|
421
|
+
version: semver[1],
|
|
422
|
+
attribution: "known"
|
|
423
|
+
};
|
|
424
|
+
if (app === "web" && WEB_RELEASE_PATTERN.test(wireVersion)) {
|
|
425
|
+
return {
|
|
426
|
+
app,
|
|
427
|
+
version: wireVersion.toLowerCase(),
|
|
428
|
+
attribution: "known"
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
return void 0;
|
|
432
|
+
}
|
|
433
|
+
function serializeLuaClientHeader(client) {
|
|
434
|
+
if (!client) return void 0;
|
|
435
|
+
return `${client.app}/${client.version === "unknown" ? "unversioned" : client.version}`;
|
|
436
|
+
}
|
|
437
|
+
function formatLuaClientHeader(app, version) {
|
|
438
|
+
if (typeof version !== "string") return `${app}/unversioned`;
|
|
439
|
+
const normalized = version.trim();
|
|
440
|
+
if (SEMVER_PATTERN.test(normalized)) return `${app}/${normalized}`;
|
|
441
|
+
if (app === "web" && WEB_RELEASE_PATTERN.test(normalized)) return `${app}/${normalized.toLowerCase()}`;
|
|
442
|
+
return `${app}/unversioned`;
|
|
443
|
+
}
|
|
444
|
+
function luaClientMetricLabels(client) {
|
|
445
|
+
const canonical = parseLuaClientHeader(serializeLuaClientHeader(client));
|
|
446
|
+
return {
|
|
447
|
+
client_family: canonical?.app ?? "unknown",
|
|
448
|
+
client_version: canonical?.version ?? "unknown",
|
|
449
|
+
client_attribution: canonical?.attribution ?? "unknown"
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
function parseEffectiveAuthorization(value) {
|
|
453
|
+
const parsed = EffectiveAuthorizationSchema.safeParse(value);
|
|
454
|
+
return parsed.success ? parsed.data : void 0;
|
|
455
|
+
}
|
|
456
|
+
function parseResourcePage(value) {
|
|
457
|
+
const parsed = ResourcePageSchema.safeParse(value);
|
|
458
|
+
return parsed.success ? parsed.data : void 0;
|
|
459
|
+
}
|
|
460
|
+
function capabilitiesFor(profiles, profileId) {
|
|
461
|
+
if (!profileId) return [];
|
|
462
|
+
return profiles[profileId] ?? [];
|
|
463
|
+
}
|
|
464
|
+
function isKnownProfile(profiles, profileId) {
|
|
465
|
+
return profileId !== void 0 && Object.prototype.hasOwnProperty.call(profiles, profileId);
|
|
466
|
+
}
|
|
467
|
+
function hasCapability(profiles, profileId, required) {
|
|
468
|
+
return capabilitiesFor(profiles, profileId).includes(required);
|
|
469
|
+
}
|
|
470
|
+
var __defProp2, __name2, CHANNEL_SEND_CHANNELS, REVIEWABLE_ACTION_EXECUTE_TOOL_ALLOWLIST, REVIEWABLE_MCP_SEND_TOOL_SUFFIX, MCP_TOOL_READ_VERB_RE, MCP_DRAFT_CREATE_VERBS, NON_INTERACTIVE_CHANNELS, RICH_PARTS_MESSAGE_ID_PREFIX, SCREENSHOT_MESSAGE_ID_PREFIX, BROWSER_COMMANDS, BROWSER_COMMAND_NAMES, DESKTOP_FILE_COMMANDS, DESKTOP_FILE_COMMAND_SET, REASONING_EFFORT_VALUES, IMPLICIT_MODEL_SELECTION_SOURCES, AGENT_NAME_TOKEN, DEFAULT_PERSONA_GUIDE, PERSONAL_SPACE_STARTING_PERSONA, VoiceNameSchema, PluginProviderSchema, RealtimeProviderSchema, PluginClassSchema, ModelDescriptorSchema, InferenceModelSchema, PluginModelSchema, RealtimeModelSchema, LuaVoiceModelSchema, TurnDetectionSchema, InterruptionSchema, BuiltinAudioClipSchema, AudioConfigSchema, BackgroundAudioEntrySchema, BackgroundAudioSchema, LuaVoiceConfigInnerSchema, LuaVoiceConfigSchema, LuaVoiceRefSchema, LUA_JOB_DEFAULT_TIMEOUT_SECONDS, LUA_JOB_MIN_TIMEOUT_SECONDS, LUA_JOB_MAX_TIMEOUT_SECONDS, TEMPLATE_TRIGGER_URL_ENV_PREFIX, SUBJECT_TYPES, SubjectTypeSchema, CREDENTIAL_TYPES, CredentialTypeSchema, PrincipalContextSchema, LUA_CLIENT_HEADER, LUA_CLIENT_APPS, SEMVER_PATTERN, WEB_RELEASE_PATTERN, CLIENT_HEADER_PATTERN, AUTHZ_PROJECTION_VERSION, ProjectedScopeSchema, DisplayRoleSchema, AuthorizationPrincipalSchema, CredentialContextSchema, ProjectionAnomalySchema, ProjectedOrgSchema, ProjectedResourceSchema, CapabilityProfilesSchema, RoleCatalogSchema, EffectiveAuthorizationSchema, ResourcePageSchema;
|
|
388
471
|
var init_dist = __esm({
|
|
389
472
|
"../shared-types/dist/index.mjs"() {
|
|
390
473
|
"use strict";
|
|
@@ -1049,6 +1132,201 @@ This text is who you are for this person. As you learn them, their name, their w
|
|
|
1049
1132
|
__name2(resolveLuaJobTimeoutSeconds, "resolveLuaJobTimeoutSeconds");
|
|
1050
1133
|
__name(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
|
|
1051
1134
|
__name2(normalizeLuaJobExecutionTimeoutSeconds, "normalizeLuaJobExecutionTimeoutSeconds");
|
|
1135
|
+
TEMPLATE_TRIGGER_URL_ENV_PREFIX = "LUA_TRIGGER_URL__";
|
|
1136
|
+
__name(triggerUrlEnvKey, "triggerUrlEnvKey");
|
|
1137
|
+
__name2(triggerUrlEnvKey, "triggerUrlEnvKey");
|
|
1138
|
+
SUBJECT_TYPES = [
|
|
1139
|
+
"user",
|
|
1140
|
+
"apiKey",
|
|
1141
|
+
"service",
|
|
1142
|
+
"endUser",
|
|
1143
|
+
"staff"
|
|
1144
|
+
];
|
|
1145
|
+
SubjectTypeSchema = z2.enum(SUBJECT_TYPES);
|
|
1146
|
+
CREDENTIAL_TYPES = [
|
|
1147
|
+
"firstPartySession",
|
|
1148
|
+
"apiKey",
|
|
1149
|
+
"deviceCredential",
|
|
1150
|
+
"endUserSession",
|
|
1151
|
+
"staffAssertion",
|
|
1152
|
+
"serviceCredential",
|
|
1153
|
+
"legacyInternalToken"
|
|
1154
|
+
];
|
|
1155
|
+
CredentialTypeSchema = z2.enum(CREDENTIAL_TYPES);
|
|
1156
|
+
PrincipalContextSchema = z2.object({
|
|
1157
|
+
version: z2.literal(1),
|
|
1158
|
+
subject: z2.object({
|
|
1159
|
+
subjectType: SubjectTypeSchema,
|
|
1160
|
+
subjectId: z2.string().min(1).max(256)
|
|
1161
|
+
}).strict(),
|
|
1162
|
+
actor: z2.object({
|
|
1163
|
+
actorType: SubjectTypeSchema,
|
|
1164
|
+
actorId: z2.string().min(1).max(256)
|
|
1165
|
+
}).strict().optional(),
|
|
1166
|
+
credential: z2.object({
|
|
1167
|
+
type: CredentialTypeSchema,
|
|
1168
|
+
id: z2.string().min(1).max(256).optional(),
|
|
1169
|
+
issuedAt: z2.number().int().nonnegative().optional(),
|
|
1170
|
+
expiresAt: z2.number().int().nonnegative().optional()
|
|
1171
|
+
}).strict(),
|
|
1172
|
+
owner: z2.object({
|
|
1173
|
+
type: z2.enum([
|
|
1174
|
+
"user",
|
|
1175
|
+
"org",
|
|
1176
|
+
"service"
|
|
1177
|
+
]),
|
|
1178
|
+
id: z2.string().min(1).max(256)
|
|
1179
|
+
}).strict().optional(),
|
|
1180
|
+
compatibility: z2.object({
|
|
1181
|
+
mode: z2.literal("legacy-owner-delegation")
|
|
1182
|
+
}).strict().optional()
|
|
1183
|
+
}).strict();
|
|
1184
|
+
__name(parsePrincipalContext, "parsePrincipalContext");
|
|
1185
|
+
__name2(parsePrincipalContext, "parsePrincipalContext");
|
|
1186
|
+
__name(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
|
|
1187
|
+
__name2(isTypedApiKeyPrincipal, "isTypedApiKeyPrincipal");
|
|
1188
|
+
__name(typedApiKeyPrincipalId, "typedApiKeyPrincipalId");
|
|
1189
|
+
__name2(typedApiKeyPrincipalId, "typedApiKeyPrincipalId");
|
|
1190
|
+
LUA_CLIENT_HEADER = "X-Lua-Client";
|
|
1191
|
+
LUA_CLIENT_APPS = [
|
|
1192
|
+
"desktop",
|
|
1193
|
+
"web",
|
|
1194
|
+
"cli",
|
|
1195
|
+
"mobile",
|
|
1196
|
+
"claude-plugin",
|
|
1197
|
+
"codex-plugin",
|
|
1198
|
+
"cursor-plugin",
|
|
1199
|
+
"platform-mcp"
|
|
1200
|
+
];
|
|
1201
|
+
SEMVER_PATTERN = /^(\d{1,3}\.\d{1,3}\.\d{1,3})(?:-[0-9A-Za-z.-]{1,16})?(?:\+[0-9A-Za-z.-]{1,16})?$/;
|
|
1202
|
+
WEB_RELEASE_PATTERN = /^[0-9a-f]{12}$/i;
|
|
1203
|
+
CLIENT_HEADER_PATTERN = /^([^/]+)\/(.+)$/;
|
|
1204
|
+
__name(parseLuaClientHeader, "parseLuaClientHeader");
|
|
1205
|
+
__name2(parseLuaClientHeader, "parseLuaClientHeader");
|
|
1206
|
+
__name(serializeLuaClientHeader, "serializeLuaClientHeader");
|
|
1207
|
+
__name2(serializeLuaClientHeader, "serializeLuaClientHeader");
|
|
1208
|
+
__name(formatLuaClientHeader, "formatLuaClientHeader");
|
|
1209
|
+
__name2(formatLuaClientHeader, "formatLuaClientHeader");
|
|
1210
|
+
__name(luaClientMetricLabels, "luaClientMetricLabels");
|
|
1211
|
+
__name2(luaClientMetricLabels, "luaClientMetricLabels");
|
|
1212
|
+
AUTHZ_PROJECTION_VERSION = 1;
|
|
1213
|
+
ProjectedScopeSchema = z3.string().min(1).max(128);
|
|
1214
|
+
DisplayRoleSchema = z3.object({
|
|
1215
|
+
role: z3.string().min(1).max(128),
|
|
1216
|
+
boundTo: z3.enum([
|
|
1217
|
+
"org",
|
|
1218
|
+
"agent",
|
|
1219
|
+
"platform"
|
|
1220
|
+
]),
|
|
1221
|
+
resourceId: z3.string().min(1).max(256)
|
|
1222
|
+
}).passthrough();
|
|
1223
|
+
AuthorizationPrincipalSchema = z3.object({
|
|
1224
|
+
subjectType: SubjectTypeSchema,
|
|
1225
|
+
subjectId: z3.string().min(1).max(256)
|
|
1226
|
+
}).passthrough();
|
|
1227
|
+
CredentialContextSchema = z3.object({
|
|
1228
|
+
type: CredentialTypeSchema,
|
|
1229
|
+
id: z3.string().min(1).max(256).optional(),
|
|
1230
|
+
owner: z3.object({
|
|
1231
|
+
type: z3.enum([
|
|
1232
|
+
"user",
|
|
1233
|
+
"org",
|
|
1234
|
+
"service"
|
|
1235
|
+
]),
|
|
1236
|
+
id: z3.string().min(1).max(256)
|
|
1237
|
+
}).passthrough().optional(),
|
|
1238
|
+
compatibility: z3.object({
|
|
1239
|
+
mode: z3.literal("legacy-owner-delegation")
|
|
1240
|
+
}).passthrough().optional()
|
|
1241
|
+
}).passthrough();
|
|
1242
|
+
ProjectionAnomalySchema = z3.enum([
|
|
1243
|
+
"grant-without-membership",
|
|
1244
|
+
"live-grant-on-inactive-membership"
|
|
1245
|
+
]);
|
|
1246
|
+
ProjectedOrgSchema = z3.object({
|
|
1247
|
+
orgId: z3.string().min(1).max(256),
|
|
1248
|
+
name: z3.string().optional(),
|
|
1249
|
+
archived: z3.boolean(),
|
|
1250
|
+
/** Key into `capabilityProfiles`. */
|
|
1251
|
+
capabilityProfile: z3.string().min(1).max(64),
|
|
1252
|
+
displayRoles: z3.array(DisplayRoleSchema),
|
|
1253
|
+
/** Product data — notifications, ordering, labels. NEVER an authorization input. */
|
|
1254
|
+
membership: z3.object({
|
|
1255
|
+
rostered: z3.boolean(),
|
|
1256
|
+
active: z3.boolean()
|
|
1257
|
+
}).passthrough(),
|
|
1258
|
+
discoveredVia: z3.enum([
|
|
1259
|
+
"org-grant",
|
|
1260
|
+
"agent-grant-only"
|
|
1261
|
+
]).describe("For user and staff principals, grant provenance: org-grant means a stored org grant produced the row. For owner-ceiling API keys, effective provenance: org-grant means the credential-owner intersection has org-level capability; agent-grant-only means the intersection reaches only an exact agent inside the org."),
|
|
1262
|
+
anomalies: z3.array(ProjectionAnomalySchema).optional()
|
|
1263
|
+
}).passthrough();
|
|
1264
|
+
ProjectedResourceSchema = z3.object({
|
|
1265
|
+
resourceType: z3.literal("agent"),
|
|
1266
|
+
resourceId: z3.string().min(1).max(256),
|
|
1267
|
+
kind: z3.enum([
|
|
1268
|
+
"agent",
|
|
1269
|
+
"space"
|
|
1270
|
+
]),
|
|
1271
|
+
/** `null` for an org-less platform agent. */
|
|
1272
|
+
orgId: z3.string().min(1).max(256).nullable(),
|
|
1273
|
+
name: z3.string().optional(),
|
|
1274
|
+
visibility: z3.enum([
|
|
1275
|
+
"private",
|
|
1276
|
+
"public",
|
|
1277
|
+
"platform"
|
|
1278
|
+
]),
|
|
1279
|
+
capabilityProfile: z3.string().min(1).max(64),
|
|
1280
|
+
displayRoles: z3.array(DisplayRoleSchema),
|
|
1281
|
+
discoveredVia: z3.enum([
|
|
1282
|
+
"org-cascade",
|
|
1283
|
+
"agent-grant",
|
|
1284
|
+
"owner-override",
|
|
1285
|
+
"platform-allowlist"
|
|
1286
|
+
]),
|
|
1287
|
+
/** Product data only. A roster row confers nothing. */
|
|
1288
|
+
rostered: z3.boolean()
|
|
1289
|
+
}).passthrough();
|
|
1290
|
+
CapabilityProfilesSchema = z3.record(z3.string().min(1).max(64), z3.array(ProjectedScopeSchema));
|
|
1291
|
+
RoleCatalogSchema = z3.record(z3.string().min(1).max(128), z3.object({
|
|
1292
|
+
label: z3.string()
|
|
1293
|
+
}).passthrough());
|
|
1294
|
+
EffectiveAuthorizationSchema = z3.object({
|
|
1295
|
+
version: z3.literal(AUTHZ_PROJECTION_VERSION),
|
|
1296
|
+
generatedAt: z3.string().min(1),
|
|
1297
|
+
authorizationPrincipal: AuthorizationPrincipalSchema,
|
|
1298
|
+
credentialContext: CredentialContextSchema.optional(),
|
|
1299
|
+
orgs: z3.array(ProjectedOrgSchema),
|
|
1300
|
+
/**
|
|
1301
|
+
* Present only when the caller holds platform grants. This is what replaces a
|
|
1302
|
+
* client-side staff check: staff-ness is a scope on a resource, not an email
|
|
1303
|
+
* suffix and not a boolean that would read `false` on an ordinary session.
|
|
1304
|
+
*/
|
|
1305
|
+
platform: z3.object({
|
|
1306
|
+
capabilityProfile: z3.string().min(1).max(64)
|
|
1307
|
+
}).passthrough().optional(),
|
|
1308
|
+
capabilityProfiles: CapabilityProfilesSchema,
|
|
1309
|
+
roleCatalog: RoleCatalogSchema.optional()
|
|
1310
|
+
}).passthrough();
|
|
1311
|
+
ResourcePageSchema = z3.object({
|
|
1312
|
+
version: z3.literal(AUTHZ_PROJECTION_VERSION),
|
|
1313
|
+
generatedAt: z3.string().min(1),
|
|
1314
|
+
orgId: z3.string().min(1).max(256),
|
|
1315
|
+
resources: z3.array(ProjectedResourceSchema),
|
|
1316
|
+
capabilityProfiles: CapabilityProfilesSchema,
|
|
1317
|
+
/** `null` = last page. Opaque; do not construct one. */
|
|
1318
|
+
nextCursor: z3.string().nullable().describe("Opaque continuation. A non-null value may accompany a short or empty resource page when the server reaches its per-request scan cap; clients must continue until null.")
|
|
1319
|
+
}).passthrough();
|
|
1320
|
+
__name(parseEffectiveAuthorization, "parseEffectiveAuthorization");
|
|
1321
|
+
__name2(parseEffectiveAuthorization, "parseEffectiveAuthorization");
|
|
1322
|
+
__name(parseResourcePage, "parseResourcePage");
|
|
1323
|
+
__name2(parseResourcePage, "parseResourcePage");
|
|
1324
|
+
__name(capabilitiesFor, "capabilitiesFor");
|
|
1325
|
+
__name2(capabilitiesFor, "capabilitiesFor");
|
|
1326
|
+
__name(isKnownProfile, "isKnownProfile");
|
|
1327
|
+
__name2(isKnownProfile, "isKnownProfile");
|
|
1328
|
+
__name(hasCapability, "hasCapability");
|
|
1329
|
+
__name2(hasCapability, "hasCapability");
|
|
1052
1330
|
}
|
|
1053
1331
|
});
|
|
1054
1332
|
|
|
@@ -1070,7 +1348,7 @@ var init_baskets = __esm({
|
|
|
1070
1348
|
// src/config/constants.ts
|
|
1071
1349
|
import { join } from "path";
|
|
1072
1350
|
import { homedir } from "os";
|
|
1073
|
-
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, CLI_CACHE_FILE, BASE_URLS, CREDENTIALS_FILE, SANDBOX_STORAGE_FILE, AUTH_STORAGE_FILE;
|
|
1351
|
+
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, CLI_CACHE_FILE, BASE_URLS, CREDENTIALS_FILE, FIREBASE_WEB_API_KEY, SANDBOX_STORAGE_FILE, AUTH_STORAGE_FILE;
|
|
1074
1352
|
var init_constants = __esm({
|
|
1075
1353
|
"src/config/constants.ts"() {
|
|
1076
1354
|
"use strict";
|
|
@@ -1086,6 +1364,7 @@ var init_constants = __esm({
|
|
|
1086
1364
|
CDN: "https://cdn.heylua.ai"
|
|
1087
1365
|
};
|
|
1088
1366
|
CREDENTIALS_FILE = join(CLI_CONFIG_DIR, "credentials");
|
|
1367
|
+
FIREBASE_WEB_API_KEY = process.env.LUA_FIREBASE_WEB_API_KEY || "AIzaSyAGI0AxOz6UmtJgwFIA_UNTuYUEgQRRGhw";
|
|
1089
1368
|
SANDBOX_STORAGE_FILE = join(CLI_CONFIG_DIR, "sandbox.json");
|
|
1090
1369
|
AUTH_STORAGE_FILE = join(CLI_CONFIG_DIR, "auth.json");
|
|
1091
1370
|
}
|
|
@@ -1134,13 +1413,105 @@ var init_auth_error = __esm({
|
|
|
1134
1413
|
}
|
|
1135
1414
|
});
|
|
1136
1415
|
|
|
1416
|
+
// src/utils/package-root.ts
|
|
1417
|
+
import { readFileSync, existsSync } from "fs";
|
|
1418
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
1419
|
+
import { dirname, join as join2 } from "path";
|
|
1420
|
+
function locate() {
|
|
1421
|
+
if (cachedRoot && cachedPkg) return {
|
|
1422
|
+
root: cachedRoot,
|
|
1423
|
+
pkg: cachedPkg
|
|
1424
|
+
};
|
|
1425
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
1426
|
+
while (true) {
|
|
1427
|
+
const candidate = join2(dir, "package.json");
|
|
1428
|
+
if (existsSync(candidate)) {
|
|
1429
|
+
try {
|
|
1430
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf8"));
|
|
1431
|
+
if (parsed?.name === "lua-cli") {
|
|
1432
|
+
cachedRoot = dir;
|
|
1433
|
+
cachedPkg = parsed;
|
|
1434
|
+
return {
|
|
1435
|
+
root: dir,
|
|
1436
|
+
pkg: parsed
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
} catch {
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
const parent = dirname(dir);
|
|
1443
|
+
if (parent === dir) break;
|
|
1444
|
+
dir = parent;
|
|
1445
|
+
}
|
|
1446
|
+
throw new Error("Could not locate lua-cli package root from " + fileURLToPath(import.meta.url));
|
|
1447
|
+
}
|
|
1448
|
+
function getCliVersion() {
|
|
1449
|
+
try {
|
|
1450
|
+
return locate().pkg.version;
|
|
1451
|
+
} catch {
|
|
1452
|
+
return "0.0.0";
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
var cachedRoot, cachedPkg;
|
|
1456
|
+
var init_package_root = __esm({
|
|
1457
|
+
"src/utils/package-root.ts"() {
|
|
1458
|
+
"use strict";
|
|
1459
|
+
cachedRoot = null;
|
|
1460
|
+
cachedPkg = null;
|
|
1461
|
+
__name(locate, "locate");
|
|
1462
|
+
__name(getCliVersion, "getCliVersion");
|
|
1463
|
+
}
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
// src/utils/lua-fetch.ts
|
|
1467
|
+
function luaClientHeaderValue() {
|
|
1468
|
+
return formatLuaClientHeader("cli", getCliVersion());
|
|
1469
|
+
}
|
|
1470
|
+
function headerRecord(headers) {
|
|
1471
|
+
if (!headers) return {};
|
|
1472
|
+
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
|
|
1473
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
1474
|
+
const record = {};
|
|
1475
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1476
|
+
if (typeof value === "string") record[name] = value;
|
|
1477
|
+
}
|
|
1478
|
+
return record;
|
|
1479
|
+
}
|
|
1480
|
+
function luaFetch(input, init = {}) {
|
|
1481
|
+
const headers = headerRecord(init.headers);
|
|
1482
|
+
for (const name of Object.keys(headers)) {
|
|
1483
|
+
if (name.toLowerCase() === LUA_CLIENT_HEADER.toLowerCase()) delete headers[name];
|
|
1484
|
+
}
|
|
1485
|
+
headers[LUA_CLIENT_HEADER] = luaClientHeaderValue();
|
|
1486
|
+
return fetch(input, {
|
|
1487
|
+
...init,
|
|
1488
|
+
headers
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
var init_lua_fetch = __esm({
|
|
1492
|
+
"src/utils/lua-fetch.ts"() {
|
|
1493
|
+
"use strict";
|
|
1494
|
+
init_dist();
|
|
1495
|
+
init_package_root();
|
|
1496
|
+
__name(luaClientHeaderValue, "luaClientHeaderValue");
|
|
1497
|
+
__name(headerRecord, "headerRecord");
|
|
1498
|
+
__name(luaFetch, "luaFetch");
|
|
1499
|
+
}
|
|
1500
|
+
});
|
|
1501
|
+
|
|
1137
1502
|
// src/api/http.client.ts
|
|
1138
1503
|
import { randomUUID } from "crypto";
|
|
1504
|
+
function parseRetryAfter(raw) {
|
|
1505
|
+
if (!raw) return void 0;
|
|
1506
|
+
const seconds = Number.parseInt(raw, 10);
|
|
1507
|
+
return Number.isFinite(seconds) && seconds > 0 ? seconds : void 0;
|
|
1508
|
+
}
|
|
1139
1509
|
var HttpClient;
|
|
1140
1510
|
var init_http_client = __esm({
|
|
1141
1511
|
"src/api/http.client.ts"() {
|
|
1142
1512
|
"use strict";
|
|
1143
1513
|
init_auth_error();
|
|
1514
|
+
init_lua_fetch();
|
|
1144
1515
|
HttpClient = class {
|
|
1145
1516
|
static {
|
|
1146
1517
|
__name(this, "HttpClient");
|
|
@@ -1164,7 +1535,7 @@ var init_http_client = __esm({
|
|
|
1164
1535
|
const controller = new AbortController();
|
|
1165
1536
|
const timeoutId = setTimeout(() => controller.abort(), 3e4);
|
|
1166
1537
|
try {
|
|
1167
|
-
const response = await
|
|
1538
|
+
const response = await luaFetch(url, {
|
|
1168
1539
|
...options,
|
|
1169
1540
|
signal: controller.signal,
|
|
1170
1541
|
headers: {
|
|
@@ -1203,6 +1574,7 @@ Check that your API key has access to this agent/organization.`);
|
|
|
1203
1574
|
message: errorData.message || `HTTP ${response.status}: ${response.statusText}`,
|
|
1204
1575
|
statusCode: response.status,
|
|
1205
1576
|
error: errorData.error,
|
|
1577
|
+
retryAfterSeconds: parseRetryAfter(response.headers.get("retry-after")),
|
|
1206
1578
|
...errorData
|
|
1207
1579
|
}
|
|
1208
1580
|
};
|
|
@@ -1301,7 +1673,8 @@ Check that your API key has access to this agent/organization.`);
|
|
|
1301
1673
|
throw error;
|
|
1302
1674
|
}
|
|
1303
1675
|
if (attempt < maxRetries) {
|
|
1304
|
-
const
|
|
1676
|
+
const serverDelay = Number(lastResult?.error?.retryAfterSeconds ?? 0) * 1e3;
|
|
1677
|
+
const backoff = Math.max(this.calculateBackoff(attempt), serverDelay);
|
|
1305
1678
|
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
1306
1679
|
}
|
|
1307
1680
|
}
|
|
@@ -1336,6 +1709,19 @@ Check that your API key has access to this agent/organization.`);
|
|
|
1336
1709
|
});
|
|
1337
1710
|
}
|
|
1338
1711
|
/**
|
|
1712
|
+
* Performs one HTTP POST attempt.
|
|
1713
|
+
*
|
|
1714
|
+
* Use this only when a successful response contains a one-time secret that
|
|
1715
|
+
* cannot be recovered after an ambiguous network or server failure.
|
|
1716
|
+
*/
|
|
1717
|
+
async httpPostOnce(url, data, headers) {
|
|
1718
|
+
return this.retryableRequest(this.baseUrl + url, {
|
|
1719
|
+
method: "POST",
|
|
1720
|
+
body: data ? JSON.stringify(data) : void 0,
|
|
1721
|
+
headers
|
|
1722
|
+
}, 0);
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1339
1725
|
* Performs an HTTP PUT request
|
|
1340
1726
|
* @param url - The relative URL path to request (will be appended to baseUrl)
|
|
1341
1727
|
* @param data - Optional request body data (will be JSON stringified)
|
|
@@ -1379,6 +1765,7 @@ Check that your API key has access to this agent/organization.`);
|
|
|
1379
1765
|
});
|
|
1380
1766
|
}
|
|
1381
1767
|
};
|
|
1768
|
+
__name(parseRetryAfter, "parseRetryAfter");
|
|
1382
1769
|
}
|
|
1383
1770
|
});
|
|
1384
1771
|
|
|
@@ -1392,13 +1779,13 @@ var init_auth_api_service = __esm({
|
|
|
1392
1779
|
|
|
1393
1780
|
// src/services/auth.ts
|
|
1394
1781
|
import "dotenv/config";
|
|
1395
|
-
import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "fs";
|
|
1782
|
+
import { readFileSync as readFileSync2, writeFileSync, mkdirSync, unlinkSync } from "fs";
|
|
1396
1783
|
function getToken() {
|
|
1397
1784
|
if (process.env.LUA_API_KEY) {
|
|
1398
1785
|
return process.env.LUA_API_KEY;
|
|
1399
1786
|
}
|
|
1400
1787
|
try {
|
|
1401
|
-
const token =
|
|
1788
|
+
const token = readFileSync2(CREDENTIALS_FILE, "utf8").trim();
|
|
1402
1789
|
if (token) return token;
|
|
1403
1790
|
} catch {
|
|
1404
1791
|
}
|
|
@@ -2490,13 +2877,6 @@ var init_version_check = __esm({
|
|
|
2490
2877
|
}
|
|
2491
2878
|
});
|
|
2492
2879
|
|
|
2493
|
-
// src/utils/package-root.ts
|
|
2494
|
-
var init_package_root = __esm({
|
|
2495
|
-
"src/utils/package-root.ts"() {
|
|
2496
|
-
"use strict";
|
|
2497
|
-
}
|
|
2498
|
-
});
|
|
2499
|
-
|
|
2500
2880
|
// src/services/analytics.ts
|
|
2501
2881
|
import { PostHog } from "posthog-node";
|
|
2502
2882
|
var init_analytics = __esm({
|
|
@@ -4244,8 +4624,7 @@ var init_user_data_api_service = __esm({
|
|
|
4244
4624
|
* @throws Error if the message sending fails or the request is unsuccessful
|
|
4245
4625
|
*/
|
|
4246
4626
|
async sendMessage(messages) {
|
|
4247
|
-
const
|
|
4248
|
-
const response = await this.httpPost(`/admin/agents/${this.agentId}/conversations/${user.uid}`, {
|
|
4627
|
+
const response = await this.httpPost(`/admin/agents/${this.agentId}/conversations/me`, {
|
|
4249
4628
|
messages
|
|
4250
4629
|
}, {
|
|
4251
4630
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -4256,20 +4635,6 @@ var init_user_data_api_service = __esm({
|
|
|
4256
4635
|
return response.data;
|
|
4257
4636
|
}
|
|
4258
4637
|
/**
|
|
4259
|
-
* Gets the admin user for the specific agent
|
|
4260
|
-
* @returns Promise resolving to the admin user data
|
|
4261
|
-
* @throws Error if the admin user cannot be retrieved or the request is unsuccessful
|
|
4262
|
-
*/
|
|
4263
|
-
async getAdminUser() {
|
|
4264
|
-
const response = await this.httpGet(`/admin`, {
|
|
4265
|
-
Authorization: `Bearer ${this.apiKey}`
|
|
4266
|
-
});
|
|
4267
|
-
if (!response.success) {
|
|
4268
|
-
throw new Error(response.error?.message || "Failed to get admin user");
|
|
4269
|
-
}
|
|
4270
|
-
return response.data;
|
|
4271
|
-
}
|
|
4272
|
-
/**
|
|
4273
4638
|
* Gets the chat history for the current user and agent
|
|
4274
4639
|
* @returns Promise resolving to an array of chat messages
|
|
4275
4640
|
* @throws Error if the chat history cannot be retrieved or the request is unsuccessful
|
|
@@ -5486,6 +5851,7 @@ var CdnApi;
|
|
|
5486
5851
|
var init_cdn_api_service = __esm({
|
|
5487
5852
|
"src/api/cdn.api.service.ts"() {
|
|
5488
5853
|
"use strict";
|
|
5854
|
+
init_lua_fetch();
|
|
5489
5855
|
CdnApi = class {
|
|
5490
5856
|
static {
|
|
5491
5857
|
__name(this, "CdnApi");
|
|
@@ -5504,7 +5870,7 @@ var init_cdn_api_service = __esm({
|
|
|
5504
5870
|
async upload(file) {
|
|
5505
5871
|
const formData = new FormData();
|
|
5506
5872
|
formData.append("file", file, file.name);
|
|
5507
|
-
const response = await
|
|
5873
|
+
const response = await luaFetch(`${this.baseUrl}/upload`, {
|
|
5508
5874
|
method: "POST",
|
|
5509
5875
|
headers: {
|
|
5510
5876
|
Authorization: `Bearer ${this.apiKey}`
|
|
@@ -5522,7 +5888,7 @@ var init_cdn_api_service = __esm({
|
|
|
5522
5888
|
* Fetches a file from the CDN by its ID
|
|
5523
5889
|
*/
|
|
5524
5890
|
async get(fileId) {
|
|
5525
|
-
const response = await
|
|
5891
|
+
const response = await luaFetch(`${this.baseUrl}/${fileId}`);
|
|
5526
5892
|
if (!response.ok) {
|
|
5527
5893
|
throw new Error(`File not found: ${response.status}`);
|
|
5528
5894
|
}
|
|
@@ -6484,6 +6850,7 @@ var LuaWebhook = class {
|
|
|
6484
6850
|
querySchema;
|
|
6485
6851
|
headerSchema;
|
|
6486
6852
|
bodySchema;
|
|
6853
|
+
secret;
|
|
6487
6854
|
executeFunction;
|
|
6488
6855
|
/**
|
|
6489
6856
|
* Creates a new LuaWebhook instance.
|
|
@@ -6505,9 +6872,17 @@ var LuaWebhook = class {
|
|
|
6505
6872
|
this.querySchema = config.querySchema;
|
|
6506
6873
|
this.headerSchema = config.headerSchema;
|
|
6507
6874
|
this.bodySchema = config.bodySchema;
|
|
6875
|
+
this.secret = config.secret;
|
|
6508
6876
|
this.executeFunction = config.execute;
|
|
6509
6877
|
}
|
|
6510
6878
|
/**
|
|
6879
|
+
* Gets the webhook's signing key, if one is configured.
|
|
6880
|
+
* Never print this — it is the shared secret callers sign with.
|
|
6881
|
+
*/
|
|
6882
|
+
getSecret() {
|
|
6883
|
+
return this.secret;
|
|
6884
|
+
}
|
|
6885
|
+
/**
|
|
6511
6886
|
* Gets the webhook name.
|
|
6512
6887
|
*/
|
|
6513
6888
|
getName() {
|
|
@@ -6584,12 +6959,16 @@ var LuaTrigger = class {
|
|
|
6584
6959
|
verify;
|
|
6585
6960
|
filter;
|
|
6586
6961
|
transform;
|
|
6962
|
+
tool;
|
|
6587
6963
|
constructor(config) {
|
|
6588
6964
|
if (!config.name || !config.name.trim()) {
|
|
6589
6965
|
throw new Error("LuaTrigger requires a non-empty `name` (used as the server-side identifier).");
|
|
6590
6966
|
}
|
|
6591
|
-
if (!config.verify && !config.filter && !config.transform) {
|
|
6592
|
-
throw new Error("LuaTrigger requires at least one of verify, filter, or
|
|
6967
|
+
if (!config.verify && !config.filter && !config.transform && !config.tool) {
|
|
6968
|
+
throw new Error("LuaTrigger requires at least one of verify, filter, transform, or tool.");
|
|
6969
|
+
}
|
|
6970
|
+
if (config.tool && (!config.tool.name || !config.tool.name.trim())) {
|
|
6971
|
+
throw new Error("LuaTrigger `tool` requires a non-empty `name` (the bare authored tool name).");
|
|
6593
6972
|
}
|
|
6594
6973
|
this.name = config.name;
|
|
6595
6974
|
this.description = config.description;
|
|
@@ -6598,6 +6977,7 @@ var LuaTrigger = class {
|
|
|
6598
6977
|
this.verify = config.verify;
|
|
6599
6978
|
this.filter = config.filter;
|
|
6600
6979
|
this.transform = config.transform;
|
|
6980
|
+
this.tool = config.tool;
|
|
6601
6981
|
}
|
|
6602
6982
|
getName() {
|
|
6603
6983
|
return this.name;
|