lua-cli 3.23.1 → 3.24.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 +95 -11
- package/dist/api-exports.js +85 -11
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +115 -25
- package/dist/index.js.map +1 -1
- package/docs/README.md +2 -2
- package/package.json +3 -3
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12890,17 +12890,42 @@ var init_custom_data_api_service = __esm({
|
|
|
12890
12890
|
this.agentId = agentId;
|
|
12891
12891
|
}
|
|
12892
12892
|
/**
|
|
12893
|
+
* Lists the agent's data collections with entry counts, timestamps, and —
|
|
12894
|
+
* when declared — managed index status (fields, pending/building/ready/
|
|
12895
|
+
* failed/rejected, error reason). The place to diagnose index declarations.
|
|
12896
|
+
* @returns Promise resolving to the collections listing
|
|
12897
|
+
*/
|
|
12898
|
+
async collections() {
|
|
12899
|
+
const response = await this.httpGet(`/developer/agents/${this.agentId}/custom-data`, {
|
|
12900
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
12901
|
+
});
|
|
12902
|
+
if (response.success && response.data) {
|
|
12903
|
+
return response.data;
|
|
12904
|
+
}
|
|
12905
|
+
throw new Error(response.error?.message || "Failed to list custom data collections");
|
|
12906
|
+
}
|
|
12907
|
+
/**
|
|
12893
12908
|
* Creates a new custom data entry in a specified collection
|
|
12894
12909
|
* @param collectionName - The name of the collection to create the entry in
|
|
12895
12910
|
* @param data - The data object to store in the entry
|
|
12896
|
-
* @param
|
|
12911
|
+
* @param optionsOrSearchText - Either a searchText string (legacy form) or an
|
|
12912
|
+
* options object: `searchText` for semantic search indexing, and `index` to
|
|
12913
|
+
* declare data fields this agent filters on (e.g. `['business_id']` or
|
|
12914
|
+
* compounds like `[['country', 'business_id']]`). Declared fields get
|
|
12915
|
+
* agent-scoped database indexes maintained by the platform: created when
|
|
12916
|
+
* first declared, removed automatically ~14 days after the code stops
|
|
12917
|
+
* declaring them. Declaring on every write is the intended, idempotent use.
|
|
12897
12918
|
* @returns Promise resolving to a DataEntryInstance representing the created entry
|
|
12898
12919
|
* @throws Error if the entry creation fails or the API request is unsuccessful
|
|
12899
12920
|
*/
|
|
12900
|
-
async create(collectionName, data,
|
|
12921
|
+
async create(collectionName, data, optionsOrSearchText) {
|
|
12922
|
+
const options = typeof optionsOrSearchText === "string" ? {
|
|
12923
|
+
searchText: optionsOrSearchText
|
|
12924
|
+
} : optionsOrSearchText ?? {};
|
|
12901
12925
|
const response = await this.httpPost(`/developer/agents/${this.agentId}/custom-data/${collectionName}`, {
|
|
12902
12926
|
data,
|
|
12903
|
-
searchText
|
|
12927
|
+
searchText: options.searchText,
|
|
12928
|
+
index: options.index
|
|
12904
12929
|
}, {
|
|
12905
12930
|
Authorization: `Bearer ${this.apiKey}`
|
|
12906
12931
|
});
|
|
@@ -12953,14 +12978,19 @@ var init_custom_data_api_service = __esm({
|
|
|
12953
12978
|
* @param collectionName - The name of the collection containing the entry
|
|
12954
12979
|
* @param entryId - The unique identifier of the entry to update
|
|
12955
12980
|
* @param data - The data object to update
|
|
12956
|
-
* @param
|
|
12981
|
+
* @param optionsOrSearchText - searchText string (legacy) or { searchText?, index? };
|
|
12982
|
+
* `index` refreshes this agent's index declarations (same semantics as create)
|
|
12957
12983
|
* @returns Promise resolving to an UpdateCustomDataResponse with the updated entry details
|
|
12958
12984
|
* @throws Error if the entry is not found or the update fails
|
|
12959
12985
|
*/
|
|
12960
|
-
async update(collectionName, entryId, data,
|
|
12986
|
+
async update(collectionName, entryId, data, optionsOrSearchText) {
|
|
12987
|
+
const options = typeof optionsOrSearchText === "string" ? {
|
|
12988
|
+
searchText: optionsOrSearchText
|
|
12989
|
+
} : optionsOrSearchText ?? {};
|
|
12961
12990
|
const response = await this.httpPut(`/developer/agents/${this.agentId}/custom-data/${collectionName}/${entryId}`, {
|
|
12962
12991
|
data,
|
|
12963
|
-
searchText
|
|
12992
|
+
searchText: options.searchText,
|
|
12993
|
+
index: options.index
|
|
12964
12994
|
}, {
|
|
12965
12995
|
Authorization: `Bearer ${this.apiKey}`
|
|
12966
12996
|
});
|
|
@@ -20723,6 +20753,14 @@ var DEFAULT_BLOCK_CIDRS = [
|
|
|
20723
20753
|
"fe80::/10",
|
|
20724
20754
|
"fc00::/7"
|
|
20725
20755
|
];
|
|
20756
|
+
var HOSTNAME_NON_OVERRIDABLE_CIDRS = [
|
|
20757
|
+
"127.0.0.0/8",
|
|
20758
|
+
"169.254.0.0/16",
|
|
20759
|
+
"0.0.0.0/8",
|
|
20760
|
+
"::1/128",
|
|
20761
|
+
"fe80::/10",
|
|
20762
|
+
"fd00:ec2::254/128"
|
|
20763
|
+
];
|
|
20726
20764
|
function ipv4ToInt(ip) {
|
|
20727
20765
|
const parts = ip.split(".").map(Number);
|
|
20728
20766
|
if (parts.length !== 4 || parts.some((n) => Number.isNaN(n) || n < 0 || n > 255)) {
|
|
@@ -20824,24 +20862,50 @@ function ipInCidr(ip, cidrs) {
|
|
|
20824
20862
|
}
|
|
20825
20863
|
__name(ipInCidr, "ipInCidr");
|
|
20826
20864
|
__name4(ipInCidr, "ipInCidr");
|
|
20865
|
+
function normalizeHostname(hostname) {
|
|
20866
|
+
return stripBrackets(hostname.trim()).toLowerCase().replace(/\.$/, "");
|
|
20867
|
+
}
|
|
20868
|
+
__name(normalizeHostname, "normalizeHostname");
|
|
20869
|
+
__name4(normalizeHostname, "normalizeHostname");
|
|
20870
|
+
function parseAllowedHostname(value) {
|
|
20871
|
+
const hostname = normalizeHostname(value);
|
|
20872
|
+
if (!hostname || net.isIP(hostname) || /[\s*/:\\?#]/.test(hostname)) {
|
|
20873
|
+
throw new Error(`Invalid sandbox egress hostname allowlist entry: ${JSON.stringify(value)}. Use an exact hostname without a wildcard, URL, port, or IP literal.`);
|
|
20874
|
+
}
|
|
20875
|
+
return hostname;
|
|
20876
|
+
}
|
|
20877
|
+
__name(parseAllowedHostname, "parseAllowedHostname");
|
|
20878
|
+
__name4(parseAllowedHostname, "parseAllowedHostname");
|
|
20827
20879
|
function compile2(opts) {
|
|
20828
20880
|
return {
|
|
20829
20881
|
blockCidrs: DEFAULT_BLOCK_CIDRS.map(parseCidr),
|
|
20830
20882
|
allowCidrs: (opts.extraAllowedCidrs ?? []).map(parseCidr),
|
|
20883
|
+
allowHostnames: new Set((opts.extraAllowedHostnames ?? []).map(parseAllowedHostname)),
|
|
20884
|
+
hostnameNonOverridableCidrs: HOSTNAME_NON_OVERRIDABLE_CIDRS.map(parseCidr),
|
|
20831
20885
|
mode: opts.mode,
|
|
20832
20886
|
onEvent: opts.onSecurityEvent
|
|
20833
20887
|
};
|
|
20834
20888
|
}
|
|
20835
20889
|
__name(compile2, "compile");
|
|
20836
20890
|
__name4(compile2, "compile");
|
|
20837
|
-
function
|
|
20838
|
-
|
|
20891
|
+
function isAllowedHostname(hostname, guard) {
|
|
20892
|
+
return !net.isIP(hostname) && guard.allowHostnames.has(normalizeHostname(hostname));
|
|
20893
|
+
}
|
|
20894
|
+
__name(isAllowedHostname, "isAllowedHostname");
|
|
20895
|
+
__name4(isAllowedHostname, "isAllowedHostname");
|
|
20896
|
+
function checkAddress(address, guard, allowedByHostname = false) {
|
|
20897
|
+
const v4 = ipv4MappedFromIpv6(address);
|
|
20898
|
+
if (ipInCidr(address, guard.allowCidrs) || v4 !== null && ipInCidr(v4, guard.allowCidrs)) return null;
|
|
20899
|
+
if (allowedByHostname) {
|
|
20900
|
+
if (ipInCidr(address, guard.hostnameNonOverridableCidrs) || v4 !== null && ipInCidr(v4, guard.hostnameNonOverridableCidrs)) {
|
|
20901
|
+
return `address ${address} is protected from sandbox hostname allowances`;
|
|
20902
|
+
}
|
|
20903
|
+
return null;
|
|
20904
|
+
}
|
|
20839
20905
|
if (ipInCidr(address, guard.blockCidrs)) {
|
|
20840
20906
|
return `address ${address} is in the sandbox egress block list`;
|
|
20841
20907
|
}
|
|
20842
|
-
const v4 = ipv4MappedFromIpv6(address);
|
|
20843
20908
|
if (v4) {
|
|
20844
|
-
if (ipInCidr(v4, guard.allowCidrs)) return null;
|
|
20845
20909
|
if (ipInCidr(v4, guard.blockCidrs)) {
|
|
20846
20910
|
return `address ${address} (IPv4-mapped: ${v4}) is in the sandbox egress block list`;
|
|
20847
20911
|
}
|
|
@@ -20866,8 +20930,9 @@ async function resolveAndCheck(hostname, guard) {
|
|
|
20866
20930
|
} catch {
|
|
20867
20931
|
return null;
|
|
20868
20932
|
}
|
|
20933
|
+
const allowedByHostname = isAllowedHostname(hostname, guard);
|
|
20869
20934
|
for (const { address } of addresses) {
|
|
20870
|
-
const reason = checkAddress(address, guard);
|
|
20935
|
+
const reason = checkAddress(address, guard, allowedByHostname);
|
|
20871
20936
|
if (reason) return {
|
|
20872
20937
|
reason,
|
|
20873
20938
|
address
|
|
@@ -20978,8 +21043,9 @@ function buildBlockingLookup(guard, target) {
|
|
|
20978
21043
|
}, (err, addresses) => {
|
|
20979
21044
|
if (err) return cb(err);
|
|
20980
21045
|
const list = addresses;
|
|
21046
|
+
const allowedByHostname = isAllowedHostname(hostname, guard);
|
|
20981
21047
|
for (const { address } of list) {
|
|
20982
|
-
const reason = checkAddress(address, guard);
|
|
21048
|
+
const reason = checkAddress(address, guard, allowedByHostname);
|
|
20983
21049
|
if (reason) {
|
|
20984
21050
|
emit(guard, target, reason, address);
|
|
20985
21051
|
if (guard.mode === "enforce") {
|
|
@@ -21275,6 +21341,7 @@ function createBaseSandboxContext(opts) {
|
|
|
21275
21341
|
const egressOpts = {
|
|
21276
21342
|
mode: egressMode,
|
|
21277
21343
|
extraAllowedCidrs: opts.egressExtraAllowedCidrs,
|
|
21344
|
+
extraAllowedHostnames: opts.egressExtraAllowedHostnames,
|
|
21278
21345
|
onSecurityEvent: onSecurityEvent ? (evt) => onSecurityEvent(evt) : void 0
|
|
21279
21346
|
};
|
|
21280
21347
|
const wrappedModuleCache = /* @__PURE__ */ new Map();
|
|
@@ -21338,6 +21405,13 @@ function resolveExtraAllowedCidrs() {
|
|
|
21338
21405
|
}
|
|
21339
21406
|
__name(resolveExtraAllowedCidrs, "resolveExtraAllowedCidrs");
|
|
21340
21407
|
__name4(resolveExtraAllowedCidrs, "resolveExtraAllowedCidrs");
|
|
21408
|
+
function resolveExtraAllowedHostnames() {
|
|
21409
|
+
const csv = process.env.LUA_ALLOWED_EGRESS_HOSTNAMES;
|
|
21410
|
+
if (!csv) return [];
|
|
21411
|
+
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21412
|
+
}
|
|
21413
|
+
__name(resolveExtraAllowedHostnames, "resolveExtraAllowedHostnames");
|
|
21414
|
+
__name4(resolveExtraAllowedHostnames, "resolveExtraAllowedHostnames");
|
|
21341
21415
|
function wrapBundleAsCjsModule(source) {
|
|
21342
21416
|
return "(function(module, exports, require) {\n" + source + "\n})(module, module.exports, require);";
|
|
21343
21417
|
}
|
|
@@ -21571,6 +21645,12 @@ function resolveExtraAllowedCidrs2() {
|
|
|
21571
21645
|
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21572
21646
|
}
|
|
21573
21647
|
__name(resolveExtraAllowedCidrs2, "resolveExtraAllowedCidrs");
|
|
21648
|
+
function resolveExtraAllowedHostnames2() {
|
|
21649
|
+
const csv = process.env.LUA_ALLOWED_EGRESS_HOSTNAMES;
|
|
21650
|
+
if (!csv) return [];
|
|
21651
|
+
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
21652
|
+
}
|
|
21653
|
+
__name(resolveExtraAllowedHostnames2, "resolveExtraAllowedHostnames");
|
|
21574
21654
|
function defaultSecurityEventLogger(evt) {
|
|
21575
21655
|
console.warn("[sandbox]", JSON.stringify(evt));
|
|
21576
21656
|
}
|
|
@@ -21759,6 +21839,7 @@ function createSandbox(options) {
|
|
|
21759
21839
|
requireMode: resolveRequireMode(),
|
|
21760
21840
|
egressMode: resolveEgressMode(),
|
|
21761
21841
|
egressExtraAllowedCidrs: resolveExtraAllowedCidrs2(),
|
|
21842
|
+
egressExtraAllowedHostnames: resolveExtraAllowedHostnames2(),
|
|
21762
21843
|
onSecurityEvent: defaultSecurityEventLogger
|
|
21763
21844
|
});
|
|
21764
21845
|
}
|
|
@@ -26261,15 +26342,18 @@ var ChatApi = class extends HttpClient {
|
|
|
26261
26342
|
}
|
|
26262
26343
|
}
|
|
26263
26344
|
/**
|
|
26264
|
-
* Clears
|
|
26345
|
+
* Clears conversation history for an agent. Without targetIdentifier this is
|
|
26346
|
+
* self-scoped; cross-user clears require org:manage for the agent on the server.
|
|
26265
26347
|
* @param agentId - The unique identifier of the agent
|
|
26266
26348
|
* @param threadId - Optional thread ID to clear a specific conversation thread
|
|
26349
|
+
* @param targetIdentifier - Optional target user ID, email, or mobile number
|
|
26267
26350
|
* @returns Promise resolving to an ApiResponse with confirmation
|
|
26268
26351
|
* @throws Error if the agent is not found or the clear operation fails
|
|
26269
26352
|
*/
|
|
26270
|
-
async clearHistory(agentId, threadId) {
|
|
26353
|
+
async clearHistory(agentId, threadId, targetIdentifier) {
|
|
26271
26354
|
const params = new URLSearchParams();
|
|
26272
26355
|
if (threadId) params.set("threadId", threadId);
|
|
26356
|
+
if (targetIdentifier !== void 0) params.set("targetIdentifier", targetIdentifier);
|
|
26273
26357
|
const query = params.toString() ? `?${params.toString()}` : "";
|
|
26274
26358
|
const url = `/chat/history/${agentId}${query}`;
|
|
26275
26359
|
return this.httpDelete(url, {
|
|
@@ -27701,22 +27785,24 @@ init_analytics();
|
|
|
27701
27785
|
async function chatClearCommand(options, command) {
|
|
27702
27786
|
return withErrorHandling(async () => {
|
|
27703
27787
|
const resolvedOptions = options ?? {};
|
|
27704
|
-
|
|
27705
|
-
|
|
27788
|
+
const targetIdentifier = resolvedOptions.user?.trim();
|
|
27789
|
+
if (resolvedOptions.user !== void 0 && !targetIdentifier) {
|
|
27790
|
+
throw new Error("--user requires a non-empty user ID, email address, or mobile number.");
|
|
27706
27791
|
}
|
|
27707
27792
|
const { agentId, apiKey } = await initializeCommand();
|
|
27708
27793
|
const threadId = resolvedOptions.thread ?? command?.parent?.opts()?.thread;
|
|
27709
27794
|
const force = !!resolvedOptions.force;
|
|
27710
27795
|
const threadContext = threadId ? ` in thread "${threadId}"` : "";
|
|
27796
|
+
const targetContext = targetIdentifier ? ` for user "${targetIdentifier}"` : "";
|
|
27711
27797
|
if (!force) {
|
|
27712
27798
|
console.log(`
|
|
27713
|
-
\u26A0\uFE0F WARNING: This will clear
|
|
27799
|
+
\u26A0\uFE0F WARNING: This will clear conversation history${targetContext}${threadContext}!`);
|
|
27714
27800
|
console.log("\u26A0\uFE0F This action cannot be undone.\n");
|
|
27715
27801
|
const confirmAnswer = await safePrompt([
|
|
27716
27802
|
{
|
|
27717
27803
|
type: "confirm",
|
|
27718
27804
|
name: "confirm",
|
|
27719
|
-
message: `Are you sure you want to clear
|
|
27805
|
+
message: `Are you sure you want to clear conversation history${targetContext}${threadContext}?`,
|
|
27720
27806
|
default: false
|
|
27721
27807
|
}
|
|
27722
27808
|
]);
|
|
@@ -27726,16 +27812,17 @@ async function chatClearCommand(options, command) {
|
|
|
27726
27812
|
}
|
|
27727
27813
|
writeProgress("\u{1F504} Clearing conversation history...");
|
|
27728
27814
|
const chatApi = new ChatApi(BASE_URLS.CHAT, apiKey);
|
|
27729
|
-
const response = await chatApi.clearHistory(agentId, threadId);
|
|
27815
|
+
const response = await chatApi.clearHistory(agentId, threadId, targetIdentifier);
|
|
27730
27816
|
if (!response.success) {
|
|
27731
27817
|
throw new Error(response.error?.message || "Failed to clear conversation history");
|
|
27732
27818
|
}
|
|
27733
|
-
writeSuccess(`\u2705
|
|
27734
|
-
console.log(`\u{1F4A1}
|
|
27819
|
+
writeSuccess(`\u2705 Conversation history has been cleared${targetContext}${threadContext}`);
|
|
27820
|
+
console.log(`\u{1F4A1} Chat history has been completely removed${targetContext}${threadContext}.
|
|
27735
27821
|
`);
|
|
27736
27822
|
trackEvent("cli_chat_cleared", {
|
|
27737
27823
|
force_mode: force,
|
|
27738
|
-
has_thread_target: !!threadId
|
|
27824
|
+
has_thread_target: !!threadId,
|
|
27825
|
+
has_user_target: !!targetIdentifier
|
|
27739
27826
|
});
|
|
27740
27827
|
}, "chat clear");
|
|
27741
27828
|
}
|
|
@@ -46380,16 +46467,19 @@ Examples:
|
|
|
46380
46467
|
$ lua chat -b "Hello" "What is the weather?" "Tell me a joke" -d 2000 -e sandbox Batch test
|
|
46381
46468
|
$ lua chat --agent-version 3 -m "test" Preview agent version 3 in an isolated thread
|
|
46382
46469
|
`).action(chatCommand);
|
|
46383
|
-
chatCmd.command("clear").description("Clear your conversation history").option("--user <identifier>", "
|
|
46470
|
+
chatCmd.command("clear").description("Clear your own or an administered user's conversation history").option("--user <identifier>", "Clear another user by ID, email, or mobile (requires org:manage)").option("-t, --thread <id>", "Clear a specific thread's history instead of all history").option("--force", "Skip confirmation prompt").addHelpText("after", `
|
|
46384
46471
|
Examples:
|
|
46385
46472
|
$ lua chat clear Clear your history
|
|
46386
46473
|
$ lua chat clear --force Clear your history without confirmation
|
|
46474
|
+
$ lua chat clear --user user@example.com Clear another user's history (requires org:manage)
|
|
46475
|
+
$ lua chat clear --user +1234567890 --force Clear another user's history without confirmation
|
|
46387
46476
|
$ lua chat clear --thread <threadId> Clear a specific thread's history
|
|
46388
46477
|
$ lua chat clear --thread <threadId> --force Clear a specific thread's history without confirmation
|
|
46389
46478
|
|
|
46390
46479
|
Notes:
|
|
46391
|
-
-
|
|
46392
|
-
-
|
|
46480
|
+
- Without --user, this command clears only YOUR OWN conversation history
|
|
46481
|
+
- --user requires org:manage for the agent
|
|
46482
|
+
- Org-admin grants do not cascade to private agents; org owners and explicit agent grants follow shared authorization rules
|
|
46393
46483
|
`).action(chatClearCommand);
|
|
46394
46484
|
program2.command("env [environment]").description("\u2699\uFE0F Manage environment variables").option("-k, --key <name>", "Environment variable key").option("-v, --value <value>", "Environment variable value").option("-d, --delete", "Delete the specified key").option("--list", "List all environment variables").addHelpText("after", `
|
|
46395
46485
|
Arguments:
|