lua-cli 3.16.0 → 3.17.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 +28 -0
- package/dist/api-exports.js +2 -1
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +1908 -318
- package/dist/index.js.map +1 -1
- package/docs/README.md +2 -2
- package/package.json +2 -2
- package/template/lua.skill.yaml +7 -0
- package/template/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -132,13 +132,14 @@ var init_semver = __esm({
|
|
|
132
132
|
// src/config/constants.ts
|
|
133
133
|
import { join } from "path";
|
|
134
134
|
import { homedir } from "os";
|
|
135
|
-
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, BASE_URLS, CREDENTIALS_FILE, PREFERRED_AGENT_TYPES, SANDBOX_STORAGE_FILE, POSTHOG_API_KEY, POSTHOG_HOST;
|
|
135
|
+
var CLI_CONFIG_DIR, VERSION_CHECK_FILE, TELEMETRY_FILE, CLI_CACHE_FILE, BASE_URLS, CREDENTIALS_FILE, PREFERRED_AGENT_TYPES, SANDBOX_STORAGE_FILE, POSTHOG_API_KEY, POSTHOG_HOST;
|
|
136
136
|
var init_constants = __esm({
|
|
137
137
|
"src/config/constants.ts"() {
|
|
138
138
|
"use strict";
|
|
139
139
|
CLI_CONFIG_DIR = join(homedir(), ".lua-cli");
|
|
140
140
|
VERSION_CHECK_FILE = join(CLI_CONFIG_DIR, "version-check.json");
|
|
141
141
|
TELEMETRY_FILE = join(CLI_CONFIG_DIR, "telemetry.json");
|
|
142
|
+
CLI_CACHE_FILE = join(CLI_CONFIG_DIR, "cache.json");
|
|
142
143
|
BASE_URLS = {
|
|
143
144
|
API: process.env.LUA_API_URL || "https://api.heylua.ai",
|
|
144
145
|
AUTH: process.env.LUA_AUTH_URL || "https://auth.heylua.ai",
|
|
@@ -1526,7 +1527,7 @@ var init_artifact_loader = __esm({
|
|
|
1526
1527
|
});
|
|
1527
1528
|
|
|
1528
1529
|
// src/api/backup.api.service.ts
|
|
1529
|
-
var BackupApi;
|
|
1530
|
+
var BackupApi, backup_api_service_default;
|
|
1530
1531
|
var init_backup_api_service = __esm({
|
|
1531
1532
|
"src/api/backup.api.service.ts"() {
|
|
1532
1533
|
"use strict";
|
|
@@ -1645,7 +1646,20 @@ var init_backup_api_service = __esm({
|
|
|
1645
1646
|
Authorization: `Bearer ${this.apiKey}`
|
|
1646
1647
|
});
|
|
1647
1648
|
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Get the list of backup versions for this agent.
|
|
1651
|
+
*
|
|
1652
|
+
* @param all - If true, lifts the server-side 50-version cap
|
|
1653
|
+
* @returns Promise resolving to the list of version summaries (newest first)
|
|
1654
|
+
*/
|
|
1655
|
+
async getBackupVersions(all = false) {
|
|
1656
|
+
const qs = all ? "?all=true" : "";
|
|
1657
|
+
return this.httpGet(`/developer/agents/${this.agentId}/backup/versions${qs}`, {
|
|
1658
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1648
1661
|
};
|
|
1662
|
+
backup_api_service_default = BackupApi;
|
|
1649
1663
|
}
|
|
1650
1664
|
});
|
|
1651
1665
|
|
|
@@ -1662,7 +1676,7 @@ async function ensureBundlesUploaded(apiKey, agentId, bundles) {
|
|
|
1662
1676
|
uploaded: 0
|
|
1663
1677
|
};
|
|
1664
1678
|
}
|
|
1665
|
-
const api = new
|
|
1679
|
+
const api = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
1666
1680
|
const hashes = Array.from(bundles.keys());
|
|
1667
1681
|
const urlResponse = await api.getBlobUploadUrls(hashes);
|
|
1668
1682
|
if (!urlResponse.success) {
|
|
@@ -4122,8 +4136,12 @@ var init_tool_plugin = __esm({
|
|
|
4122
4136
|
displayName = "Tool";
|
|
4123
4137
|
defineFunction = "defineTool";
|
|
4124
4138
|
legacyClassNames = [
|
|
4125
|
-
"LuaTool"
|
|
4139
|
+
"LuaTool",
|
|
4140
|
+
"LuaVoiceTool"
|
|
4126
4141
|
];
|
|
4142
|
+
crossFileRewrite = {
|
|
4143
|
+
copyAllFields: true
|
|
4144
|
+
};
|
|
4127
4145
|
supportsClassDefinition = true;
|
|
4128
4146
|
/**
|
|
4129
4147
|
* Extract metadata from a `defineTool({...})` / `new LuaTool({...})`
|
|
@@ -4298,6 +4316,9 @@ var init_job_plugin = __esm({
|
|
|
4298
4316
|
legacyClassNames = [
|
|
4299
4317
|
"LuaJob"
|
|
4300
4318
|
];
|
|
4319
|
+
crossFileRewrite = {
|
|
4320
|
+
copyAllFields: true
|
|
4321
|
+
};
|
|
4301
4322
|
supportsClassDefinition = true;
|
|
4302
4323
|
/**
|
|
4303
4324
|
* Class-definition extraction. Reads `name`/`description`/`schedule`/
|
|
@@ -4479,6 +4500,9 @@ var init_webhook_plugin = __esm({
|
|
|
4479
4500
|
legacyClassNames = [
|
|
4480
4501
|
"LuaWebhook"
|
|
4481
4502
|
];
|
|
4503
|
+
crossFileRewrite = {
|
|
4504
|
+
copyAllFields: true
|
|
4505
|
+
};
|
|
4482
4506
|
supportsClassDefinition = true;
|
|
4483
4507
|
/**
|
|
4484
4508
|
* Class-definition shape: read fields off the inheritance chain
|
|
@@ -4705,6 +4729,9 @@ var init_preprocessor_plugin = __esm({
|
|
|
4705
4729
|
"PreProcessor",
|
|
4706
4730
|
"LuaPreprocessor"
|
|
4707
4731
|
];
|
|
4732
|
+
crossFileRewrite = {
|
|
4733
|
+
copyAllFields: true
|
|
4734
|
+
};
|
|
4708
4735
|
/**
|
|
4709
4736
|
* Class-definition extraction. Reads `name`/`description`/`async`/
|
|
4710
4737
|
* `priority`/`execute` off the inheritance chain (most-derived wins).
|
|
@@ -4788,6 +4815,9 @@ var init_postprocessor_plugin = __esm({
|
|
|
4788
4815
|
"PostProcessor",
|
|
4789
4816
|
"LuaPostprocessor"
|
|
4790
4817
|
];
|
|
4818
|
+
crossFileRewrite = {
|
|
4819
|
+
copyAllFields: true
|
|
4820
|
+
};
|
|
4791
4821
|
/**
|
|
4792
4822
|
* Class-definition extraction. Reads `name`/`description`/`priority`/
|
|
4793
4823
|
* `execute` off the inheritance chain.
|
|
@@ -4863,6 +4893,9 @@ var init_mcp_server_plugin = __esm({
|
|
|
4863
4893
|
legacyClassNames = [
|
|
4864
4894
|
"LuaMCPServer"
|
|
4865
4895
|
];
|
|
4896
|
+
crossFileRewrite = {
|
|
4897
|
+
copyAllFields: true
|
|
4898
|
+
};
|
|
4866
4899
|
supportsClassDefinition = true;
|
|
4867
4900
|
/**
|
|
4868
4901
|
* Class-definition extraction. Reads `name`/`description`/`transport`/
|
|
@@ -5034,11 +5067,11 @@ var init_mcp_server_plugin = __esm({
|
|
|
5034
5067
|
// ../shared-source-sync/dist/index.mjs
|
|
5035
5068
|
import { createHash } from "crypto";
|
|
5036
5069
|
import { extname } from "path";
|
|
5037
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
5070
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync2 } from "fs";
|
|
5038
5071
|
import { join as join4, sep } from "path";
|
|
5039
5072
|
import { gunzipSync, gzipSync } from "zlib";
|
|
5040
|
-
import { existsSync as existsSync5, mkdirSync as
|
|
5041
|
-
import { dirname as
|
|
5073
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync22, statSync as statSync22, writeFileSync as writeFileSync6 } from "fs";
|
|
5074
|
+
import { dirname as dirname4, join as join22, resolve, sep as sep2 } from "path";
|
|
5042
5075
|
import { mkdirSync as mkdirSync22, readdirSync as readdirSync22, readFileSync as readFileSync32, statSync as statSync3, writeFileSync as writeFileSync22 } from "fs";
|
|
5043
5076
|
import { dirname as dirname22, join as join32, sep as sep3 } from "path";
|
|
5044
5077
|
import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "zlib";
|
|
@@ -5098,7 +5131,7 @@ function walkWorkspace(rootDir, opts = {}) {
|
|
|
5098
5131
|
if (stats.size > maxBytes) continue;
|
|
5099
5132
|
let content;
|
|
5100
5133
|
try {
|
|
5101
|
-
content =
|
|
5134
|
+
content = readFileSync7(abs);
|
|
5102
5135
|
} catch {
|
|
5103
5136
|
continue;
|
|
5104
5137
|
}
|
|
@@ -5215,10 +5248,10 @@ function restoreFromBlobs(manifest, blobs, targetDir, opts = {}) {
|
|
|
5215
5248
|
continue;
|
|
5216
5249
|
}
|
|
5217
5250
|
}
|
|
5218
|
-
|
|
5251
|
+
mkdirSync6(dirname4(targetPath), {
|
|
5219
5252
|
recursive: true
|
|
5220
5253
|
});
|
|
5221
|
-
|
|
5254
|
+
writeFileSync6(targetPath, content);
|
|
5222
5255
|
filesWritten++;
|
|
5223
5256
|
}
|
|
5224
5257
|
return {
|
|
@@ -5413,12 +5446,12 @@ var init_dist2 = __esm({
|
|
|
5413
5446
|
this.options = options;
|
|
5414
5447
|
this.fetchFn = options.fetch ?? fetch;
|
|
5415
5448
|
}
|
|
5416
|
-
url(
|
|
5449
|
+
url(path19) {
|
|
5417
5450
|
const base = this.options.baseUrl.replace(/\/$/, "");
|
|
5418
|
-
return `${base}/developer/agents/${encodeURIComponent(this.options.agentId)}${
|
|
5451
|
+
return `${base}/developer/agents/${encodeURIComponent(this.options.agentId)}${path19}`;
|
|
5419
5452
|
}
|
|
5420
|
-
async json(method,
|
|
5421
|
-
const endpoint = this.url(
|
|
5453
|
+
async json(method, path19, body) {
|
|
5454
|
+
const endpoint = this.url(path19);
|
|
5422
5455
|
const res = await this.fetchFn(endpoint, {
|
|
5423
5456
|
method,
|
|
5424
5457
|
headers: {
|
|
@@ -5437,7 +5470,7 @@ var init_dist2 = __esm({
|
|
|
5437
5470
|
} catch {
|
|
5438
5471
|
text2 = void 0;
|
|
5439
5472
|
}
|
|
5440
|
-
throw new BackupHttpError(`Backup request failed: ${method} ${
|
|
5473
|
+
throw new BackupHttpError(`Backup request failed: ${method} ${path19} \u2192 ${res.status} ${res.statusText}`, res.status, endpoint, text2);
|
|
5441
5474
|
}
|
|
5442
5475
|
const text = await res.text();
|
|
5443
5476
|
if (!text) return void 0;
|
|
@@ -5504,16 +5537,16 @@ var init_dist2 = __esm({
|
|
|
5504
5537
|
});
|
|
5505
5538
|
|
|
5506
5539
|
// src/compiler/utils/common.ts
|
|
5507
|
-
import
|
|
5540
|
+
import path4 from "path";
|
|
5508
5541
|
function hashContent(content) {
|
|
5509
5542
|
return hashContentTruncated(content);
|
|
5510
5543
|
}
|
|
5511
5544
|
function isInside(child, parent) {
|
|
5512
|
-
const resolvedChild =
|
|
5513
|
-
const resolvedParent =
|
|
5545
|
+
const resolvedChild = path4.resolve(child);
|
|
5546
|
+
const resolvedParent = path4.resolve(parent);
|
|
5514
5547
|
if (resolvedChild === resolvedParent) return true;
|
|
5515
|
-
const rel =
|
|
5516
|
-
return !!rel && !rel.startsWith("..") && !
|
|
5548
|
+
const rel = path4.relative(resolvedParent, resolvedChild);
|
|
5549
|
+
return !!rel && !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
5517
5550
|
}
|
|
5518
5551
|
function classifyProjectFile(name) {
|
|
5519
5552
|
if (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js")) {
|
|
@@ -5542,20 +5575,20 @@ var init_common = __esm({
|
|
|
5542
5575
|
});
|
|
5543
5576
|
|
|
5544
5577
|
// src/compiler/utils/path-resolver.ts
|
|
5545
|
-
import * as
|
|
5546
|
-
import * as
|
|
5578
|
+
import * as fs4 from "fs";
|
|
5579
|
+
import * as path5 from "path";
|
|
5547
5580
|
function getTsConfigPathMappings(rootDir) {
|
|
5548
|
-
const resolvedRoot =
|
|
5581
|
+
const resolvedRoot = path5.resolve(rootDir);
|
|
5549
5582
|
if (mappingsCache.has(resolvedRoot)) {
|
|
5550
5583
|
return mappingsCache.get(resolvedRoot) ?? null;
|
|
5551
5584
|
}
|
|
5552
|
-
const tsconfigPath =
|
|
5553
|
-
if (!
|
|
5585
|
+
const tsconfigPath = path5.join(resolvedRoot, "tsconfig.json");
|
|
5586
|
+
if (!fs4.existsSync(tsconfigPath)) {
|
|
5554
5587
|
mappingsCache.set(resolvedRoot, null);
|
|
5555
5588
|
return null;
|
|
5556
5589
|
}
|
|
5557
5590
|
try {
|
|
5558
|
-
const tsconfigContent =
|
|
5591
|
+
const tsconfigContent = fs4.readFileSync(tsconfigPath, "utf-8");
|
|
5559
5592
|
const tsconfig = JSON.parse(tsconfigContent);
|
|
5560
5593
|
const compilerOptions = tsconfig.compilerOptions || {};
|
|
5561
5594
|
if (compilerOptions.paths) {
|
|
@@ -5582,7 +5615,7 @@ function resolvePathAlias(specifier, rootDir) {
|
|
|
5582
5615
|
if (match) {
|
|
5583
5616
|
const captured = match[1] || "";
|
|
5584
5617
|
const targetPath = targets[0].replace("*", captured);
|
|
5585
|
-
return
|
|
5618
|
+
return path5.join(mappings.rootDir, mappings.baseUrl, targetPath);
|
|
5586
5619
|
}
|
|
5587
5620
|
}
|
|
5588
5621
|
return null;
|
|
@@ -5594,20 +5627,20 @@ function resolveModuleSpecifier(specifier, fromFile, rootDir) {
|
|
|
5594
5627
|
return tryExtensions(aliasResolved);
|
|
5595
5628
|
}
|
|
5596
5629
|
if (normalized.startsWith("./") || normalized.startsWith("../")) {
|
|
5597
|
-
const basePath =
|
|
5630
|
+
const basePath = path5.resolve(path5.dirname(fromFile), normalized);
|
|
5598
5631
|
return tryExtensions(basePath);
|
|
5599
5632
|
}
|
|
5600
5633
|
return void 0;
|
|
5601
5634
|
}
|
|
5602
5635
|
function tryExtensions(basePath) {
|
|
5603
5636
|
for (const ext of MODULE_EXTENSIONS) {
|
|
5604
|
-
const full = ext.startsWith("/") ?
|
|
5605
|
-
if (
|
|
5637
|
+
const full = ext.startsWith("/") ? path5.join(basePath, ext) : basePath + ext;
|
|
5638
|
+
if (fs4.existsSync(full)) return full;
|
|
5606
5639
|
}
|
|
5607
5640
|
return void 0;
|
|
5608
5641
|
}
|
|
5609
5642
|
function registerProjectRootDir(project, rootDir) {
|
|
5610
|
-
projectRootDirs.set(project,
|
|
5643
|
+
projectRootDirs.set(project, path5.resolve(rootDir));
|
|
5611
5644
|
}
|
|
5612
5645
|
function getProjectRootDir(project) {
|
|
5613
5646
|
return projectRootDirs.get(project);
|
|
@@ -6207,7 +6240,7 @@ var init_reference_resolver = __esm({
|
|
|
6207
6240
|
});
|
|
6208
6241
|
|
|
6209
6242
|
// src/compiler/plugins/skill.plugin.ts
|
|
6210
|
-
import
|
|
6243
|
+
import fs5 from "fs/promises";
|
|
6211
6244
|
import { Node as Node11 } from "ts-morph";
|
|
6212
6245
|
function findEnclosingVariableDeclaration(config) {
|
|
6213
6246
|
let current = config.getParent();
|
|
@@ -6256,6 +6289,22 @@ var init_skill_plugin = __esm({
|
|
|
6256
6289
|
legacyClassNames = [
|
|
6257
6290
|
"LuaSkill"
|
|
6258
6291
|
];
|
|
6292
|
+
// Whitelist drops `tools` for the same reasons agent drops skills/webhooks/jobs:
|
|
6293
|
+
// 1. Bundle size — preserving class references drags tool source files into
|
|
6294
|
+
// the parent bundle.
|
|
6295
|
+
// 2. Residual super-edge cases — `stripSuperCallsInConstructors` covers
|
|
6296
|
+
// top-level `super(...)` only; `super.method()` mid-constructor and
|
|
6297
|
+
// `field = super.x` survive a strip and explode at runtime.
|
|
6298
|
+
// MAINTENANCE: this whitelist also assumes skills are JSON-only artifacts (via
|
|
6299
|
+
// `buildArtifact`). If skills ever migrate to bundled JS, this drop will silently
|
|
6300
|
+
// lose `tools` from skill bundles — re-evaluate.
|
|
6301
|
+
crossFileRewrite = {
|
|
6302
|
+
fields: [
|
|
6303
|
+
"name",
|
|
6304
|
+
"description",
|
|
6305
|
+
"context"
|
|
6306
|
+
]
|
|
6307
|
+
};
|
|
6259
6308
|
supportsClassDefinition = true;
|
|
6260
6309
|
/**
|
|
6261
6310
|
* Class-definition extraction. Reads `name`/`description`/`context`/
|
|
@@ -6524,7 +6573,7 @@ var init_skill_plugin = __esm({
|
|
|
6524
6573
|
description: metadata.description,
|
|
6525
6574
|
metadata: this.sanitizeForPersistence(metadata.metadata)
|
|
6526
6575
|
}, null, 2);
|
|
6527
|
-
const originalSource = await
|
|
6576
|
+
const originalSource = await fs5.readFile(metadata.sourcePath, "utf-8");
|
|
6528
6577
|
return {
|
|
6529
6578
|
code,
|
|
6530
6579
|
sourceMap: "",
|
|
@@ -6647,6 +6696,22 @@ var init_agent_plugin = __esm({
|
|
|
6647
6696
|
legacyClassNames = [
|
|
6648
6697
|
"LuaAgent"
|
|
6649
6698
|
];
|
|
6699
|
+
// Whitelist (not copyAllFields). Two reasons, both real:
|
|
6700
|
+
// 1. Bundle size — `skills`/`webhooks`/`jobs`/etc. hold CLASS references;
|
|
6701
|
+
// preserving them drags every subclass source file into the agent bundle.
|
|
6702
|
+
// 2. Residual super-edge cases — `stripSuperCallsInConstructors` handles
|
|
6703
|
+
// top-level `super(...)`, but NOT `super.method()` mid-constructor or
|
|
6704
|
+
// `field = super.x` initializers, both of which still orphan after
|
|
6705
|
+
// `stripSdkExtendsClauses` runs on dragged-in files.
|
|
6706
|
+
// Agent runtime only needs name/persona/model; references are resolved by `resolveArrayRefs`.
|
|
6707
|
+
crossFileRewrite = {
|
|
6708
|
+
fields: [
|
|
6709
|
+
"name",
|
|
6710
|
+
"description",
|
|
6711
|
+
"persona",
|
|
6712
|
+
"model"
|
|
6713
|
+
]
|
|
6714
|
+
};
|
|
6650
6715
|
supportsClassDefinition = true;
|
|
6651
6716
|
/**
|
|
6652
6717
|
* Class-definition extraction. Reads the agent's own metadata
|
|
@@ -6993,6 +7058,9 @@ var init_device_plugin = __esm({
|
|
|
6993
7058
|
legacyClassNames = [
|
|
6994
7059
|
"LuaDevice"
|
|
6995
7060
|
];
|
|
7061
|
+
crossFileRewrite = {
|
|
7062
|
+
copyAllFields: true
|
|
7063
|
+
};
|
|
6996
7064
|
supportsClassDefinition = true;
|
|
6997
7065
|
/**
|
|
6998
7066
|
* Class-definition extraction. Reads `name`/`description`/`group`
|
|
@@ -7115,6 +7183,9 @@ var init_device_trigger_plugin = __esm({
|
|
|
7115
7183
|
legacyClassNames = [
|
|
7116
7184
|
"LuaDeviceTrigger"
|
|
7117
7185
|
];
|
|
7186
|
+
crossFileRewrite = {
|
|
7187
|
+
copyAllFields: true
|
|
7188
|
+
};
|
|
7118
7189
|
supportsClassDefinition = true;
|
|
7119
7190
|
/**
|
|
7120
7191
|
* Class-definition extraction. Reads `name`/`description`/has-flags
|
|
@@ -7255,13 +7326,355 @@ var init_device_trigger_plugin = __esm({
|
|
|
7255
7326
|
}
|
|
7256
7327
|
});
|
|
7257
7328
|
|
|
7329
|
+
// src/compiler/utils/primitive-rewrite.ts
|
|
7330
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
7331
|
+
import { Node as Node14, Project, ts as ts3 } from "ts-morph";
|
|
7332
|
+
function rewritePrimitiveSource(metadata, opts) {
|
|
7333
|
+
const sourceCode = readFileSync9(metadata.sourcePath, "utf-8");
|
|
7334
|
+
const localProject = new Project({
|
|
7335
|
+
useInMemoryFileSystem: true,
|
|
7336
|
+
compilerOptions: {
|
|
7337
|
+
allowJs: true,
|
|
7338
|
+
target: 99,
|
|
7339
|
+
module: 99
|
|
7340
|
+
}
|
|
7341
|
+
});
|
|
7342
|
+
const sf = localProject.createSourceFile(`__rewrite_${metadata.kind}_${metadata.name}.ts`, sourceCode);
|
|
7343
|
+
const isPrimitiveCall = /* @__PURE__ */ __name((n) => {
|
|
7344
|
+
if (Node14.isNewExpression(n)) {
|
|
7345
|
+
const callee = n.getExpression();
|
|
7346
|
+
return Node14.isIdentifier(callee) && opts.constructorNames.includes(callee.getText());
|
|
7347
|
+
}
|
|
7348
|
+
if (Node14.isCallExpression(n)) {
|
|
7349
|
+
const callee = n.getExpression();
|
|
7350
|
+
return Node14.isIdentifier(callee) && opts.defineFunctionName !== void 0 && callee.getText() === opts.defineFunctionName;
|
|
7351
|
+
}
|
|
7352
|
+
return false;
|
|
7353
|
+
}, "isPrimitiveCall");
|
|
7354
|
+
const callNode = findCallByExportName(sf, metadata, isPrimitiveCall);
|
|
7355
|
+
if (!callNode) {
|
|
7356
|
+
throw new Error(`Primitive call for export "${metadata.exportName}" (kind=${metadata.kind}) not found in ${metadata.sourcePath}`);
|
|
7357
|
+
}
|
|
7358
|
+
const arg = callNode.getArguments()[0];
|
|
7359
|
+
if (!arg || !Node14.isObjectLiteralExpression(arg)) {
|
|
7360
|
+
throw new Error(`Primitive config arg is not an object literal in ${metadata.sourcePath}`);
|
|
7361
|
+
}
|
|
7362
|
+
const synthesized = opts.buildLiteral(arg, {
|
|
7363
|
+
metadata,
|
|
7364
|
+
compilerVersion: COMPILER_VERSION
|
|
7365
|
+
});
|
|
7366
|
+
callNode.replaceWithText(synthesized);
|
|
7367
|
+
sf.forEachDescendant((n) => {
|
|
7368
|
+
if (n === callNode) return;
|
|
7369
|
+
if (isPrimitiveCall(n)) n.replaceWithText("undefined");
|
|
7370
|
+
});
|
|
7371
|
+
rewriteCrossFileCallsInSourceFile(sf, opts.crossFileSpecs, opts.sdkBaseClassNames);
|
|
7372
|
+
stripLuaCliImports(sf);
|
|
7373
|
+
ensureDefaultExport(sf, metadata);
|
|
7374
|
+
return sf.getText();
|
|
7375
|
+
}
|
|
7376
|
+
function rewriteCrossFileCallsInSourceFile(sf, specs, sdkBaseClassNames) {
|
|
7377
|
+
warnUnsupportedNamespaceImports(sf);
|
|
7378
|
+
const sdkIdentifiers = new Set(sdkBaseClassNames);
|
|
7379
|
+
for (const spec of specs) {
|
|
7380
|
+
if (spec.defineFunction) sdkIdentifiers.add(spec.defineFunction);
|
|
7381
|
+
}
|
|
7382
|
+
const aliasMap = buildSdkAliasMap(sf, sdkIdentifiers);
|
|
7383
|
+
let progressed = true;
|
|
7384
|
+
while (progressed) {
|
|
7385
|
+
progressed = false;
|
|
7386
|
+
const callNode = findFirstCrossFileSdkCall(sf, specs, aliasMap);
|
|
7387
|
+
if (!callNode) break;
|
|
7388
|
+
const spec = callNode.spec;
|
|
7389
|
+
const node = callNode.node;
|
|
7390
|
+
const arg = node.getArguments()[0];
|
|
7391
|
+
const objArg = arg && Node14.isObjectLiteralExpression(arg) ? arg : void 0;
|
|
7392
|
+
node.replaceWithText(buildBareObjectLiteral(spec, objArg));
|
|
7393
|
+
progressed = true;
|
|
7394
|
+
}
|
|
7395
|
+
stripSdkExtendsClauses(sf, sdkBaseClassNames, aliasMap);
|
|
7396
|
+
}
|
|
7397
|
+
function warnUnsupportedNamespaceImports(sf) {
|
|
7398
|
+
for (const imp of sf.getImportDeclarations()) {
|
|
7399
|
+
const spec = imp.getModuleSpecifierValue();
|
|
7400
|
+
if (spec !== "lua-cli" && spec !== "lua-cli/skill" && spec !== "lua-cli/voice") continue;
|
|
7401
|
+
const ns = imp.getNamespaceImport();
|
|
7402
|
+
if (!ns) continue;
|
|
7403
|
+
const localName = ns.getText();
|
|
7404
|
+
const pos = sf.getLineAndColumnAtPos(imp.getStart());
|
|
7405
|
+
console.warn(formatSarifWarning({
|
|
7406
|
+
ruleId: "lua/unsupported-namespace-import",
|
|
7407
|
+
filePath: sf.getFilePath(),
|
|
7408
|
+
line: pos.line,
|
|
7409
|
+
column: pos.column,
|
|
7410
|
+
message: `namespace import \`import * as ${localName} from '${spec}'\` is not supported by the cross-file rewrite. \`new ${localName}.X({...})\` calls will leak \`${localName}\` into the bundle as an undefined identifier.`,
|
|
7411
|
+
hint: `Use named imports instead: \`import { LuaTool, LuaWebhook, ... } from '${spec}'\`.`
|
|
7412
|
+
}));
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
function stripSdkExtendsClauses(sf, sdkBaseClassNames, aliasMap) {
|
|
7416
|
+
const matchesSdkClass = /* @__PURE__ */ __name((text) => {
|
|
7417
|
+
const canonical = aliasMap.get(text) ?? text;
|
|
7418
|
+
return sdkBaseClassNames.has(canonical);
|
|
7419
|
+
}, "matchesSdkClass");
|
|
7420
|
+
for (const classDecl of sf.getClasses()) {
|
|
7421
|
+
const ext = classDecl.getExtends();
|
|
7422
|
+
if (!ext) continue;
|
|
7423
|
+
const expr = ext.getExpression();
|
|
7424
|
+
if (!Node14.isIdentifier(expr)) continue;
|
|
7425
|
+
if (matchesSdkClass(expr.getText())) {
|
|
7426
|
+
classDecl.removeExtends();
|
|
7427
|
+
stripSuperCallsInConstructors(classDecl);
|
|
7428
|
+
}
|
|
7429
|
+
}
|
|
7430
|
+
sf.forEachDescendant((n) => {
|
|
7431
|
+
if (!Node14.isClassExpression(n)) return;
|
|
7432
|
+
const ext = n.getExtends();
|
|
7433
|
+
if (!ext) return;
|
|
7434
|
+
const expr = ext.getExpression();
|
|
7435
|
+
if (!Node14.isIdentifier(expr)) return;
|
|
7436
|
+
if (matchesSdkClass(expr.getText())) {
|
|
7437
|
+
n.removeExtends();
|
|
7438
|
+
stripSuperCallsInConstructors(n);
|
|
7439
|
+
}
|
|
7440
|
+
});
|
|
7441
|
+
}
|
|
7442
|
+
function stripSuperCallsInConstructors(classNode) {
|
|
7443
|
+
for (const ctor of classNode.getConstructors()) {
|
|
7444
|
+
const body = ctor.getBody();
|
|
7445
|
+
if (!body || !Node14.isBlock(body)) continue;
|
|
7446
|
+
const toRemove = [];
|
|
7447
|
+
for (const stmt of body.getStatements()) {
|
|
7448
|
+
if (!Node14.isExpressionStatement(stmt)) continue;
|
|
7449
|
+
const expr = stmt.getExpression();
|
|
7450
|
+
if (!Node14.isCallExpression(expr)) continue;
|
|
7451
|
+
if (expr.getExpression().getKind() !== ts3.SyntaxKind.SuperKeyword) continue;
|
|
7452
|
+
toRemove.push(stmt);
|
|
7453
|
+
}
|
|
7454
|
+
for (const stmt of toRemove) stmt.remove();
|
|
7455
|
+
}
|
|
7456
|
+
warnRemainingSuperReferences(classNode);
|
|
7457
|
+
}
|
|
7458
|
+
function warnRemainingSuperReferences(classNode) {
|
|
7459
|
+
const sf = classNode.getSourceFile();
|
|
7460
|
+
classNode.forEachDescendant((n) => {
|
|
7461
|
+
if (n.getKind() !== ts3.SyntaxKind.SuperKeyword) return;
|
|
7462
|
+
const parent = n.getParent();
|
|
7463
|
+
if (parent && Node14.isCallExpression(parent) && parent.getExpression() === n && Node14.isExpressionStatement(parent.getParent())) {
|
|
7464
|
+
return;
|
|
7465
|
+
}
|
|
7466
|
+
const pos = sf.getLineAndColumnAtPos(n.getStart());
|
|
7467
|
+
console.warn(formatSarifWarning({
|
|
7468
|
+
ruleId: "lua/orphan-super-reference",
|
|
7469
|
+
filePath: sf.getFilePath(),
|
|
7470
|
+
line: pos.line,
|
|
7471
|
+
column: pos.column,
|
|
7472
|
+
message: `\`super\` reference will become orphan after the SDK base class is stripped from the bundle. The compiled artifact will throw \`SyntaxError: 'super' keyword is only allowed in a derived class\` at sandbox eval.`,
|
|
7473
|
+
hint: `Move the override into a class field initializer (the canonical subclass-with-field-override pattern), or stop subclassing the SDK base and use the \`defineX({...})\` / \`new LuaX({...})\` form.`
|
|
7474
|
+
}));
|
|
7475
|
+
});
|
|
7476
|
+
}
|
|
7477
|
+
function buildSdkAliasMap(sf, sdkIdentifiers) {
|
|
7478
|
+
const map = /* @__PURE__ */ new Map();
|
|
7479
|
+
for (const imp of sf.getImportDeclarations()) {
|
|
7480
|
+
const spec = imp.getModuleSpecifierValue();
|
|
7481
|
+
if (spec !== "lua-cli" && spec !== "lua-cli/skill" && spec !== "lua-cli/voice") continue;
|
|
7482
|
+
for (const named of imp.getNamedImports()) {
|
|
7483
|
+
const exported = named.getName();
|
|
7484
|
+
const alias = named.getAliasNode()?.getText();
|
|
7485
|
+
if (!sdkIdentifiers.has(exported)) continue;
|
|
7486
|
+
const local = alias ?? exported;
|
|
7487
|
+
map.set(local, exported);
|
|
7488
|
+
}
|
|
7489
|
+
}
|
|
7490
|
+
let progressed = true;
|
|
7491
|
+
while (progressed) {
|
|
7492
|
+
progressed = false;
|
|
7493
|
+
for (const vd of sf.getVariableDeclarations()) {
|
|
7494
|
+
const init = vd.getInitializer();
|
|
7495
|
+
if (!init || !Node14.isIdentifier(init)) continue;
|
|
7496
|
+
const name = vd.getName();
|
|
7497
|
+
if (map.has(name)) continue;
|
|
7498
|
+
const initText = init.getText();
|
|
7499
|
+
const canonical = map.get(initText) ?? (sdkIdentifiers.has(initText) ? initText : void 0);
|
|
7500
|
+
if (canonical) {
|
|
7501
|
+
map.set(name, canonical);
|
|
7502
|
+
progressed = true;
|
|
7503
|
+
}
|
|
7504
|
+
}
|
|
7505
|
+
}
|
|
7506
|
+
return map;
|
|
7507
|
+
}
|
|
7508
|
+
function findFirstCrossFileSdkCall(sf, specs, aliasMap) {
|
|
7509
|
+
let found;
|
|
7510
|
+
sf.forEachDescendant((n) => {
|
|
7511
|
+
if (found) return;
|
|
7512
|
+
if (Node14.isNewExpression(n)) {
|
|
7513
|
+
const callee = n.getExpression();
|
|
7514
|
+
if (!Node14.isIdentifier(callee)) return;
|
|
7515
|
+
const canonical = aliasMap.get(callee.getText()) ?? callee.getText();
|
|
7516
|
+
const spec = specs.find((s) => s.classNames.includes(canonical));
|
|
7517
|
+
if (spec) found = {
|
|
7518
|
+
node: n,
|
|
7519
|
+
spec
|
|
7520
|
+
};
|
|
7521
|
+
} else if (Node14.isCallExpression(n)) {
|
|
7522
|
+
const callee = n.getExpression();
|
|
7523
|
+
if (!Node14.isIdentifier(callee)) return;
|
|
7524
|
+
const canonical = aliasMap.get(callee.getText()) ?? callee.getText();
|
|
7525
|
+
const spec = specs.find((s) => s.defineFunction !== void 0 && s.defineFunction === canonical);
|
|
7526
|
+
if (spec) found = {
|
|
7527
|
+
node: n,
|
|
7528
|
+
spec
|
|
7529
|
+
};
|
|
7530
|
+
}
|
|
7531
|
+
});
|
|
7532
|
+
return found;
|
|
7533
|
+
}
|
|
7534
|
+
function buildBareObjectLiteral(spec, arg) {
|
|
7535
|
+
if (!arg) return "{}";
|
|
7536
|
+
if (spec.mode === "copyAllFields") {
|
|
7537
|
+
return arg.getText();
|
|
7538
|
+
}
|
|
7539
|
+
const parts = [];
|
|
7540
|
+
for (const f of spec.fields) {
|
|
7541
|
+
const prop = arg.getProperty(f);
|
|
7542
|
+
if (prop && Node14.isPropertyAssignment(prop)) {
|
|
7543
|
+
const init = prop.getInitializer();
|
|
7544
|
+
if (init) parts.push(`${f}: ${init.getText()}`);
|
|
7545
|
+
} else if (prop && Node14.isShorthandPropertyAssignment(prop)) {
|
|
7546
|
+
parts.push(`${f}: ${prop.getName()}`);
|
|
7547
|
+
}
|
|
7548
|
+
}
|
|
7549
|
+
return `{ ${parts.join(", ")} }`;
|
|
7550
|
+
}
|
|
7551
|
+
function findCallByExportName(sf, metadata, isPrimitiveCall) {
|
|
7552
|
+
if (metadata.isDefaultExport) {
|
|
7553
|
+
for (const stmt of sf.getStatements()) {
|
|
7554
|
+
if (!Node14.isExportAssignment(stmt)) continue;
|
|
7555
|
+
const expr = stmt.getExpression();
|
|
7556
|
+
if (isPrimitiveCall(expr)) return expr;
|
|
7557
|
+
if (Node14.isIdentifier(expr)) {
|
|
7558
|
+
const varDecl2 = sf.getVariableDeclaration(expr.getText());
|
|
7559
|
+
const init2 = varDecl2?.getInitializer();
|
|
7560
|
+
if (init2 && isPrimitiveCall(init2)) return init2;
|
|
7561
|
+
}
|
|
7562
|
+
}
|
|
7563
|
+
return void 0;
|
|
7564
|
+
}
|
|
7565
|
+
const varDecl = sf.getVariableDeclaration(metadata.exportName);
|
|
7566
|
+
const init = varDecl?.getInitializer();
|
|
7567
|
+
if (init && isPrimitiveCall(init)) return init;
|
|
7568
|
+
return void 0;
|
|
7569
|
+
}
|
|
7570
|
+
function stripLuaCliImports(sf) {
|
|
7571
|
+
for (const imp of sf.getImportDeclarations()) {
|
|
7572
|
+
const spec = imp.getModuleSpecifierValue();
|
|
7573
|
+
if (spec === "lua-cli" || spec === "lua-cli/skill" || spec === "lua-cli/voice") {
|
|
7574
|
+
imp.remove();
|
|
7575
|
+
}
|
|
7576
|
+
}
|
|
7577
|
+
}
|
|
7578
|
+
function ensureDefaultExport(sf, metadata) {
|
|
7579
|
+
if (metadata.isDefaultExport) return;
|
|
7580
|
+
const existingDefault = sf.getStatements().find(Node14.isExportAssignment);
|
|
7581
|
+
if (!existingDefault) {
|
|
7582
|
+
sf.addStatements(`
|
|
7583
|
+
export default ${metadata.exportName};`);
|
|
7584
|
+
return;
|
|
7585
|
+
}
|
|
7586
|
+
const expr = existingDefault.getExpression();
|
|
7587
|
+
const alreadyCorrect = Node14.isIdentifier(expr) && expr.getText() === metadata.exportName;
|
|
7588
|
+
if (!alreadyCorrect) {
|
|
7589
|
+
existingDefault.remove();
|
|
7590
|
+
sf.addStatements(`
|
|
7591
|
+
export default ${metadata.exportName};`);
|
|
7592
|
+
}
|
|
7593
|
+
}
|
|
7594
|
+
function getPropertyText(arg, name) {
|
|
7595
|
+
const prop = arg.getProperty(name);
|
|
7596
|
+
if (prop && Node14.isPropertyAssignment(prop)) {
|
|
7597
|
+
return prop.getInitializer()?.getText();
|
|
7598
|
+
}
|
|
7599
|
+
if (prop && Node14.isShorthandPropertyAssignment(prop)) {
|
|
7600
|
+
return prop.getName();
|
|
7601
|
+
}
|
|
7602
|
+
return void 0;
|
|
7603
|
+
}
|
|
7604
|
+
function buildLuaPrimitiveMarker(metadata, kind) {
|
|
7605
|
+
return `__lua_primitive__: { version: ${JSON.stringify(COMPILER_VERSION)}, kind: '${kind}', name: ${JSON.stringify(metadata.name)}, description: ${JSON.stringify(metadata.description)}, exportName: ${JSON.stringify(metadata.exportName)} }`;
|
|
7606
|
+
}
|
|
7607
|
+
var init_primitive_rewrite = __esm({
|
|
7608
|
+
"src/compiler/utils/primitive-rewrite.ts"() {
|
|
7609
|
+
"use strict";
|
|
7610
|
+
init_types();
|
|
7611
|
+
init_reference_resolver();
|
|
7612
|
+
__name(rewritePrimitiveSource, "rewritePrimitiveSource");
|
|
7613
|
+
__name(rewriteCrossFileCallsInSourceFile, "rewriteCrossFileCallsInSourceFile");
|
|
7614
|
+
__name(warnUnsupportedNamespaceImports, "warnUnsupportedNamespaceImports");
|
|
7615
|
+
__name(stripSdkExtendsClauses, "stripSdkExtendsClauses");
|
|
7616
|
+
__name(stripSuperCallsInConstructors, "stripSuperCallsInConstructors");
|
|
7617
|
+
__name(warnRemainingSuperReferences, "warnRemainingSuperReferences");
|
|
7618
|
+
__name(buildSdkAliasMap, "buildSdkAliasMap");
|
|
7619
|
+
__name(findFirstCrossFileSdkCall, "findFirstCrossFileSdkCall");
|
|
7620
|
+
__name(buildBareObjectLiteral, "buildBareObjectLiteral");
|
|
7621
|
+
__name(findCallByExportName, "findCallByExportName");
|
|
7622
|
+
__name(stripLuaCliImports, "stripLuaCliImports");
|
|
7623
|
+
__name(ensureDefaultExport, "ensureDefaultExport");
|
|
7624
|
+
__name(getPropertyText, "getPropertyText");
|
|
7625
|
+
__name(buildLuaPrimitiveMarker, "buildLuaPrimitiveMarker");
|
|
7626
|
+
}
|
|
7627
|
+
});
|
|
7628
|
+
|
|
7629
|
+
// src/compiler/utils/cross-file-specs.ts
|
|
7630
|
+
function buildCrossFileSpecs(plugins = pluginRegistry.getAll()) {
|
|
7631
|
+
const specs = [];
|
|
7632
|
+
for (const plugin of plugins) {
|
|
7633
|
+
if (!plugin.crossFileRewrite) continue;
|
|
7634
|
+
const classNames = [
|
|
7635
|
+
...plugin.legacyClassNames
|
|
7636
|
+
];
|
|
7637
|
+
const defineFunction = plugin.defineFunction || void 0;
|
|
7638
|
+
if ("copyAllFields" in plugin.crossFileRewrite && plugin.crossFileRewrite.copyAllFields) {
|
|
7639
|
+
specs.push({
|
|
7640
|
+
classNames,
|
|
7641
|
+
defineFunction,
|
|
7642
|
+
mode: "copyAllFields"
|
|
7643
|
+
});
|
|
7644
|
+
} else if ("fields" in plugin.crossFileRewrite) {
|
|
7645
|
+
specs.push({
|
|
7646
|
+
classNames,
|
|
7647
|
+
defineFunction,
|
|
7648
|
+
mode: "whitelist",
|
|
7649
|
+
fields: plugin.crossFileRewrite.fields
|
|
7650
|
+
});
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
return specs;
|
|
7654
|
+
}
|
|
7655
|
+
function buildSdkBaseClassNames(plugins = pluginRegistry.getAll()) {
|
|
7656
|
+
const names = /* @__PURE__ */ new Set();
|
|
7657
|
+
for (const plugin of plugins) {
|
|
7658
|
+
for (const cls of plugin.legacyClassNames) names.add(cls);
|
|
7659
|
+
}
|
|
7660
|
+
return names;
|
|
7661
|
+
}
|
|
7662
|
+
var init_cross_file_specs = __esm({
|
|
7663
|
+
"src/compiler/utils/cross-file-specs.ts"() {
|
|
7664
|
+
"use strict";
|
|
7665
|
+
init_registry();
|
|
7666
|
+
__name(buildCrossFileSpecs, "buildCrossFileSpecs");
|
|
7667
|
+
__name(buildSdkBaseClassNames, "buildSdkBaseClassNames");
|
|
7668
|
+
}
|
|
7669
|
+
});
|
|
7670
|
+
|
|
7258
7671
|
// src/compiler/plugins/voice.plugin.ts
|
|
7259
|
-
import
|
|
7260
|
-
import { Node as
|
|
7672
|
+
import fs6 from "fs/promises";
|
|
7673
|
+
import { Node as Node15 } from "ts-morph";
|
|
7261
7674
|
function astObjectToPlain(obj) {
|
|
7262
7675
|
const result = {};
|
|
7263
7676
|
for (const prop of obj.getProperties()) {
|
|
7264
|
-
if (
|
|
7677
|
+
if (Node15.isSpreadAssignment(prop)) {
|
|
7265
7678
|
const expr = prop.getExpression();
|
|
7266
7679
|
const evaluated = astValueToPlain(expr);
|
|
7267
7680
|
if (evaluated && typeof evaluated === "object" && !Array.isArray(evaluated)) {
|
|
@@ -7269,14 +7682,14 @@ function astObjectToPlain(obj) {
|
|
|
7269
7682
|
}
|
|
7270
7683
|
continue;
|
|
7271
7684
|
}
|
|
7272
|
-
if (
|
|
7685
|
+
if (Node15.isShorthandPropertyAssignment(prop)) {
|
|
7273
7686
|
const key2 = prop.getName();
|
|
7274
7687
|
if (!key2) continue;
|
|
7275
7688
|
const v2 = astValueToPlain(prop.getNameNode());
|
|
7276
7689
|
if (v2 !== void 0) result[key2] = v2;
|
|
7277
7690
|
continue;
|
|
7278
7691
|
}
|
|
7279
|
-
if (!
|
|
7692
|
+
if (!Node15.isPropertyAssignment(prop)) continue;
|
|
7280
7693
|
const key = prop.getName();
|
|
7281
7694
|
if (!key) continue;
|
|
7282
7695
|
const value = prop.getInitializer();
|
|
@@ -7287,16 +7700,16 @@ function astObjectToPlain(obj) {
|
|
|
7287
7700
|
return result;
|
|
7288
7701
|
}
|
|
7289
7702
|
function astValueToPlain(value) {
|
|
7290
|
-
if (
|
|
7703
|
+
if (Node15.isStringLiteral(value) || Node15.isNoSubstitutionTemplateLiteral(value)) {
|
|
7291
7704
|
return value.getLiteralText();
|
|
7292
7705
|
}
|
|
7293
|
-
if (
|
|
7706
|
+
if (Node15.isNumericLiteral(value)) {
|
|
7294
7707
|
return Number(value.getLiteralText());
|
|
7295
7708
|
}
|
|
7296
|
-
if (
|
|
7297
|
-
if (
|
|
7298
|
-
if (
|
|
7299
|
-
if (
|
|
7709
|
+
if (Node15.isTrueLiteral(value)) return true;
|
|
7710
|
+
if (Node15.isFalseLiteral(value)) return false;
|
|
7711
|
+
if (Node15.isObjectLiteralExpression(value)) return astObjectToPlain(value);
|
|
7712
|
+
if (Node15.isArrayLiteralExpression(value)) {
|
|
7300
7713
|
return value.getElements().map((el) => astValueToPlain(el)).filter((x) => x !== void 0);
|
|
7301
7714
|
}
|
|
7302
7715
|
return void 0;
|
|
@@ -7355,15 +7768,36 @@ function stripKeys(obj, keys) {
|
|
|
7355
7768
|
}
|
|
7356
7769
|
function leftmostIdentifierName(node) {
|
|
7357
7770
|
let current = node;
|
|
7358
|
-
while (
|
|
7771
|
+
while (Node15.isPropertyAccessExpression(current)) {
|
|
7359
7772
|
current = current.getExpression();
|
|
7360
7773
|
}
|
|
7361
|
-
return
|
|
7774
|
+
return Node15.isIdentifier(current) ? current.getText() : void 0;
|
|
7775
|
+
}
|
|
7776
|
+
function resolveProviderAlias(node, localName) {
|
|
7777
|
+
const sourceFile = node.getSourceFile();
|
|
7778
|
+
for (const imp of sourceFile.getImportDeclarations()) {
|
|
7779
|
+
const moduleSpec = imp.getModuleSpecifierValue();
|
|
7780
|
+
const livekitPlugin = moduleSpec.startsWith("@livekit/agents-plugin-");
|
|
7781
|
+
const isLuaCliVoice = moduleSpec === "lua-cli/voice";
|
|
7782
|
+
const isLivekitAgents = moduleSpec === "@livekit/agents";
|
|
7783
|
+
if (!isLuaCliVoice && !livekitPlugin && !isLivekitAgents) continue;
|
|
7784
|
+
for (const named of imp.getNamedImports()) {
|
|
7785
|
+
const alias = named.getAliasNode()?.getText();
|
|
7786
|
+
const exported = named.getName();
|
|
7787
|
+
const bound = alias ?? exported;
|
|
7788
|
+
if (bound === localName) return exported;
|
|
7789
|
+
}
|
|
7790
|
+
const ns = imp.getNamespaceImport();
|
|
7791
|
+
if (ns && ns.getText() === localName && livekitPlugin) {
|
|
7792
|
+
return moduleSpec.replace("@livekit/agents-plugin-", "");
|
|
7793
|
+
}
|
|
7794
|
+
}
|
|
7795
|
+
return localName;
|
|
7362
7796
|
}
|
|
7363
7797
|
function extractRealtimeFromNewExpression(newExpr, classExpr, field) {
|
|
7364
7798
|
if (classExpr.getName() !== "RealtimeModel") return void 0;
|
|
7365
7799
|
const realtimeNode = classExpr.getExpression();
|
|
7366
|
-
if (!
|
|
7800
|
+
if (!Node15.isPropertyAccessExpression(realtimeNode) || realtimeNode.getName() !== "realtime") {
|
|
7367
7801
|
return void 0;
|
|
7368
7802
|
}
|
|
7369
7803
|
if (field !== "llm") {
|
|
@@ -7374,7 +7808,8 @@ function extractRealtimeFromNewExpression(newExpr, classExpr, field) {
|
|
|
7374
7808
|
}
|
|
7375
7809
|
};
|
|
7376
7810
|
}
|
|
7377
|
-
const
|
|
7811
|
+
const providerLocal = leftmostIdentifierName(realtimeNode.getExpression());
|
|
7812
|
+
const provider = providerLocal ? resolveProviderAlias(realtimeNode, providerLocal) : void 0;
|
|
7378
7813
|
if (!provider) {
|
|
7379
7814
|
return {
|
|
7380
7815
|
error: {
|
|
@@ -7393,7 +7828,7 @@ function extractRealtimeFromNewExpression(newExpr, classExpr, field) {
|
|
|
7393
7828
|
}
|
|
7394
7829
|
const optsArg = newExpr.getArguments()[0];
|
|
7395
7830
|
let options = {};
|
|
7396
|
-
if (optsArg &&
|
|
7831
|
+
if (optsArg && Node15.isObjectLiteralExpression(optsArg)) {
|
|
7397
7832
|
options = astObjectToPlain(optsArg);
|
|
7398
7833
|
}
|
|
7399
7834
|
return {
|
|
@@ -7406,7 +7841,7 @@ function extractRealtimeFromNewExpression(newExpr, classExpr, field) {
|
|
|
7406
7841
|
}
|
|
7407
7842
|
function extractFromNewExpression(newExpr, field) {
|
|
7408
7843
|
const expr = newExpr.getExpression();
|
|
7409
|
-
if (!
|
|
7844
|
+
if (!Node15.isPropertyAccessExpression(expr)) {
|
|
7410
7845
|
return {
|
|
7411
7846
|
error: {
|
|
7412
7847
|
field,
|
|
@@ -7416,7 +7851,7 @@ function extractFromNewExpression(newExpr, field) {
|
|
|
7416
7851
|
}
|
|
7417
7852
|
const realtimeResult = extractRealtimeFromNewExpression(newExpr, expr, field);
|
|
7418
7853
|
if (realtimeResult) return realtimeResult;
|
|
7419
|
-
const moduleName = expr.getExpression().getText();
|
|
7854
|
+
const moduleName = resolveProviderAlias(expr, expr.getExpression().getText());
|
|
7420
7855
|
const className = expr.getName();
|
|
7421
7856
|
if (!PLUGIN_CLASSES.includes(className)) {
|
|
7422
7857
|
return {
|
|
@@ -7436,7 +7871,7 @@ function extractFromNewExpression(newExpr, field) {
|
|
|
7436
7871
|
}
|
|
7437
7872
|
const optsArg = newExpr.getArguments()[0];
|
|
7438
7873
|
let options = {};
|
|
7439
|
-
if (optsArg &&
|
|
7874
|
+
if (optsArg && Node15.isObjectLiteralExpression(optsArg)) {
|
|
7440
7875
|
options = astObjectToPlain(optsArg);
|
|
7441
7876
|
}
|
|
7442
7877
|
if (moduleName === "inference") {
|
|
@@ -7484,7 +7919,7 @@ function extractFromNewExpression(newExpr, field) {
|
|
|
7484
7919
|
}
|
|
7485
7920
|
function unwrapType(node) {
|
|
7486
7921
|
let current = node;
|
|
7487
|
-
while (
|
|
7922
|
+
while (Node15.isAsExpression(current) || Node15.isSatisfiesExpression(current) || Node15.isParenthesizedExpression(current)) {
|
|
7488
7923
|
const inner = current.getExpression?.();
|
|
7489
7924
|
if (!inner) break;
|
|
7490
7925
|
current = inner;
|
|
@@ -7493,11 +7928,11 @@ function unwrapType(node) {
|
|
|
7493
7928
|
}
|
|
7494
7929
|
function extractModelField(config, field) {
|
|
7495
7930
|
const prop = config.getProperty(field);
|
|
7496
|
-
if (!prop || !
|
|
7931
|
+
if (!prop || !Node15.isPropertyAssignment(prop)) return {};
|
|
7497
7932
|
const initializer = prop.getInitializer();
|
|
7498
7933
|
if (!initializer) return {};
|
|
7499
7934
|
const value = unwrapType(initializer);
|
|
7500
|
-
if (
|
|
7935
|
+
if (Node15.isStringLiteral(value) || Node15.isNoSubstitutionTemplateLiteral(value)) {
|
|
7501
7936
|
const text = value.getLiteralText();
|
|
7502
7937
|
if (!text) {
|
|
7503
7938
|
return {
|
|
@@ -7509,7 +7944,7 @@ function extractModelField(config, field) {
|
|
|
7509
7944
|
}
|
|
7510
7945
|
return parseDescriptor(text, field);
|
|
7511
7946
|
}
|
|
7512
|
-
if (
|
|
7947
|
+
if (Node15.isObjectLiteralExpression(value)) {
|
|
7513
7948
|
if (field !== "tts") {
|
|
7514
7949
|
return {
|
|
7515
7950
|
error: {
|
|
@@ -7536,7 +7971,7 @@ function extractModelField(config, field) {
|
|
|
7536
7971
|
model: out
|
|
7537
7972
|
};
|
|
7538
7973
|
}
|
|
7539
|
-
if (
|
|
7974
|
+
if (Node15.isNewExpression(value)) {
|
|
7540
7975
|
return extractFromNewExpression(value, field);
|
|
7541
7976
|
}
|
|
7542
7977
|
return {
|
|
@@ -7549,20 +7984,23 @@ function extractModelField(config, field) {
|
|
|
7549
7984
|
function hasFunctionProperty(config, propertyName) {
|
|
7550
7985
|
const prop = config.getProperty(propertyName);
|
|
7551
7986
|
if (!prop) return false;
|
|
7552
|
-
if (
|
|
7553
|
-
if (!
|
|
7987
|
+
if (Node15.isMethodDeclaration(prop)) return true;
|
|
7988
|
+
if (!Node15.isPropertyAssignment(prop)) return false;
|
|
7554
7989
|
const value = prop.getInitializer();
|
|
7555
7990
|
if (!value) return false;
|
|
7556
|
-
if (
|
|
7557
|
-
if (
|
|
7991
|
+
if (Node15.isArrowFunction(value) || Node15.isFunctionExpression(value)) return true;
|
|
7992
|
+
if (Node15.isIdentifier(value)) return true;
|
|
7558
7993
|
return false;
|
|
7559
7994
|
}
|
|
7560
7995
|
function hasArrayProperty(config, propertyName) {
|
|
7561
7996
|
const prop = config.getProperty(propertyName);
|
|
7562
|
-
if (!prop || !
|
|
7997
|
+
if (!prop || !Node15.isPropertyAssignment(prop)) return false;
|
|
7563
7998
|
const value = prop.getInitializer();
|
|
7564
7999
|
if (!value) return false;
|
|
7565
|
-
|
|
8000
|
+
if (Node15.isArrayLiteralExpression(value)) return value.getElements().length > 0;
|
|
8001
|
+
if (Node15.isNullLiteral(value)) return false;
|
|
8002
|
+
if (Node15.isIdentifier(value) && value.getText() === "undefined") return false;
|
|
8003
|
+
return true;
|
|
7566
8004
|
}
|
|
7567
8005
|
function normalizePronunciations(raw) {
|
|
7568
8006
|
if (!raw) return {
|
|
@@ -7588,6 +8026,8 @@ var init_voice_plugin = __esm({
|
|
|
7588
8026
|
"src/compiler/plugins/voice.plugin.ts"() {
|
|
7589
8027
|
"use strict";
|
|
7590
8028
|
init_dist();
|
|
8029
|
+
init_primitive_rewrite();
|
|
8030
|
+
init_cross_file_specs();
|
|
7591
8031
|
init_types();
|
|
7592
8032
|
init_ast_helpers();
|
|
7593
8033
|
init_common();
|
|
@@ -7618,6 +8058,7 @@ var init_voice_plugin = __esm({
|
|
|
7618
8058
|
__name(parseDescriptor, "parseDescriptor");
|
|
7619
8059
|
__name(stripKeys, "stripKeys");
|
|
7620
8060
|
__name(leftmostIdentifierName, "leftmostIdentifierName");
|
|
8061
|
+
__name(resolveProviderAlias, "resolveProviderAlias");
|
|
7621
8062
|
__name(extractRealtimeFromNewExpression, "extractRealtimeFromNewExpression");
|
|
7622
8063
|
__name(extractFromNewExpression, "extractFromNewExpression");
|
|
7623
8064
|
__name(unwrapType, "unwrapType");
|
|
@@ -7635,6 +8076,14 @@ var init_voice_plugin = __esm({
|
|
|
7635
8076
|
legacyClassNames = [
|
|
7636
8077
|
"LuaVoice"
|
|
7637
8078
|
];
|
|
8079
|
+
// Voice's cross-file rewrite uses a narrow whitelist because configs can
|
|
8080
|
+
// have nested provider SDK calls (new deepgram.STT, new elevenlabs.TTS)
|
|
8081
|
+
// that the top-level rewrite (in generateEntryPoint) handles separately.
|
|
8082
|
+
crossFileRewrite = {
|
|
8083
|
+
fields: [
|
|
8084
|
+
"name"
|
|
8085
|
+
]
|
|
8086
|
+
};
|
|
7638
8087
|
extractFromConfig(config, exportName, sourcePath, position, pattern) {
|
|
7639
8088
|
const common = this.extractCommonFields(config, exportName, sourcePath, position);
|
|
7640
8089
|
if (!common) return null;
|
|
@@ -7761,8 +8210,8 @@ var init_voice_plugin = __esm({
|
|
|
7761
8210
|
}, "isMissingTopLevelRequired");
|
|
7762
8211
|
for (const issue of parsed.error.issues) {
|
|
7763
8212
|
if (isMissingTopLevelRequired(issue)) continue;
|
|
7764
|
-
const
|
|
7765
|
-
errors.push(validationError(`Voice config invalid at \`${
|
|
8213
|
+
const path19 = issue.path.length > 0 ? issue.path.join(".") : "<root>";
|
|
8214
|
+
errors.push(validationError(`Voice config invalid at \`${path19}\`: ${issue.message}`, {
|
|
7766
8215
|
line
|
|
7767
8216
|
}));
|
|
7768
8217
|
}
|
|
@@ -7775,43 +8224,45 @@ var init_voice_plugin = __esm({
|
|
|
7775
8224
|
};
|
|
7776
8225
|
}
|
|
7777
8226
|
/**
|
|
7778
|
-
* Entry-point emitter for
|
|
7779
|
-
*
|
|
7780
|
-
* the
|
|
8227
|
+
* Entry-point emitter for hook-bearing voices.
|
|
8228
|
+
*
|
|
8229
|
+
* Architecturally, the bundle must NOT re-evaluate `new LuaVoice({...})` in
|
|
8230
|
+
* the worker sandbox — that call's only purpose is compile-time metadata
|
|
8231
|
+
* extraction (provider/class/options for stt/tts/llm), and re-running it
|
|
8232
|
+
* with stripped SDK imports requires runtime stub injection (a Proxy that
|
|
8233
|
+
* covers only a fraction of the dev's possible introspection patterns).
|
|
8234
|
+
*
|
|
8235
|
+
* Instead, this method does a source-level AST rewrite:
|
|
8236
|
+
* 1. Parse the dev's source file
|
|
8237
|
+
* 2. Find the LuaVoice / defineVoice call site
|
|
8238
|
+
* 3. Splice the hook function-expression texts + tool entries directly
|
|
8239
|
+
* into a synthesized `{ __lua_primitive__, onEnter, ..., tools }`
|
|
8240
|
+
* object literal at the same module-scope position
|
|
8241
|
+
* 4. Strip the stripped lua-cli / lua-cli/voice imports
|
|
7781
8242
|
*
|
|
7782
|
-
*
|
|
7783
|
-
*
|
|
7784
|
-
*
|
|
8243
|
+
* Closure references (module-level helpers, consts, types) survive
|
|
8244
|
+
* because the splice happens at the same lexical position as the
|
|
8245
|
+
* original call site.
|
|
7785
8246
|
*
|
|
7786
8247
|
* Only invoked by the compiler when `buildArtifact` returns undefined
|
|
7787
|
-
* (i.e. when the voice declares hooks or voice-only tools)
|
|
7788
|
-
* the conditional in `buildArtifact` below.
|
|
8248
|
+
* (i.e. when the voice declares hooks or voice-only tools).
|
|
7789
8249
|
*/
|
|
7790
8250
|
generateEntryPoint(metadata) {
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
}
|
|
7807
|
-
}
|
|
7808
|
-
}
|
|
7809
|
-
|
|
7810
|
-
export const onEnter = __voice__ && __voice__.onEnter;
|
|
7811
|
-
export const onUserTurnCompleted = __voice__ && __voice__.onUserTurnCompleted;
|
|
7812
|
-
export const onExit = __voice__ && __voice__.onExit;
|
|
7813
|
-
export const tools = __luaTools;
|
|
7814
|
-
`;
|
|
8251
|
+
return rewritePrimitiveSource(metadata, {
|
|
8252
|
+
constructorNames: [
|
|
8253
|
+
"LuaVoice"
|
|
8254
|
+
],
|
|
8255
|
+
defineFunctionName: this.defineFunction,
|
|
8256
|
+
buildLiteral: /* @__PURE__ */ __name((arg, ctx) => `{
|
|
8257
|
+
${buildLuaPrimitiveMarker(ctx.metadata, "voice")},
|
|
8258
|
+
onEnter: ${getPropertyText(arg, "onEnter") ?? "undefined"},
|
|
8259
|
+
onUserTurnCompleted: ${getPropertyText(arg, "onUserTurnCompleted") ?? "undefined"},
|
|
8260
|
+
onExit: ${getPropertyText(arg, "onExit") ?? "undefined"},
|
|
8261
|
+
tools: ${getPropertyText(arg, "tools") ?? "[]"}
|
|
8262
|
+
}`, "buildLiteral"),
|
|
8263
|
+
crossFileSpecs: buildCrossFileSpecs(),
|
|
8264
|
+
sdkBaseClassNames: buildSdkBaseClassNames()
|
|
8265
|
+
});
|
|
7815
8266
|
}
|
|
7816
8267
|
/**
|
|
7817
8268
|
* Emit a JSON metadata sidecar OR fall through to esbuild bundling.
|
|
@@ -7841,7 +8292,7 @@ export const tools = __luaTools;
|
|
|
7841
8292
|
description: metadata.description,
|
|
7842
8293
|
metadata: sanitized
|
|
7843
8294
|
}, null, 2);
|
|
7844
|
-
const originalSource = await
|
|
8295
|
+
const originalSource = await fs6.readFile(metadata.sourcePath, "utf-8");
|
|
7845
8296
|
return {
|
|
7846
8297
|
code,
|
|
7847
8298
|
sourceMap: "",
|
|
@@ -7994,8 +8445,8 @@ var init_registry = __esm({
|
|
|
7994
8445
|
});
|
|
7995
8446
|
|
|
7996
8447
|
// src/compiler/bundler.ts
|
|
7997
|
-
import
|
|
7998
|
-
import
|
|
8448
|
+
import fs7 from "fs/promises";
|
|
8449
|
+
import path6 from "path";
|
|
7999
8450
|
import crypto4 from "crypto";
|
|
8000
8451
|
import { build } from "esbuild";
|
|
8001
8452
|
var Bundler;
|
|
@@ -8003,6 +8454,8 @@ var init_bundler = __esm({
|
|
|
8003
8454
|
"src/compiler/bundler.ts"() {
|
|
8004
8455
|
"use strict";
|
|
8005
8456
|
init_types();
|
|
8457
|
+
init_primitive_rewrite();
|
|
8458
|
+
init_cross_file_specs();
|
|
8006
8459
|
Bundler = class {
|
|
8007
8460
|
static {
|
|
8008
8461
|
__name(this, "Bundler");
|
|
@@ -8010,24 +8463,43 @@ var init_bundler = __esm({
|
|
|
8010
8463
|
options;
|
|
8011
8464
|
project;
|
|
8012
8465
|
verbose;
|
|
8466
|
+
// Snapshotted at construction. Plugins registered after this Bundler
|
|
8467
|
+
// is instantiated (test fixtures, "lua-cli as a library" usage) won't appear.
|
|
8468
|
+
// Today the registry is module-load-time only, so this is fine.
|
|
8469
|
+
crossFileSpecs = buildCrossFileSpecs();
|
|
8470
|
+
sdkBaseClassNames = buildSdkBaseClassNames();
|
|
8013
8471
|
constructor(options, project, verbose) {
|
|
8014
8472
|
this.options = options;
|
|
8015
8473
|
this.project = project;
|
|
8016
8474
|
this.verbose = verbose;
|
|
8017
8475
|
}
|
|
8018
8476
|
/**
|
|
8019
|
-
* Strip lua-cli
|
|
8020
|
-
*
|
|
8477
|
+
* Strip lua-cli / lua-cli/skill / lua-cli/voice / api-exports imports from
|
|
8478
|
+
* a source file, then rewrite every SDK class constructor / define-function
|
|
8479
|
+
* call in the file to a bare object literal (`{ name, execute, ... }`).
|
|
8480
|
+
*
|
|
8481
|
+
* After this transform:
|
|
8482
|
+
* - SDK class identifiers (LuaTool, LuaJob, defineWebhook, ...) no longer
|
|
8483
|
+
* appear in the source. The call sites that used them are replaced with
|
|
8484
|
+
* inline object literals carrying the runtime fields. By construction,
|
|
8485
|
+
* the bundle has zero references to stripped SDK identifiers, so the
|
|
8486
|
+
* sandbox doesn't need any runtime stub for them.
|
|
8487
|
+
* - Platform-API identifiers (Data, User, AI, Agents, Jobs, Lua, env, ...)
|
|
8488
|
+
* remain as free identifiers in the dev's execute / hook bodies. esbuild
|
|
8489
|
+
* leaves them alone (they're not imported, not local), and at runtime
|
|
8490
|
+
* they resolve to the sandbox's injected globals.
|
|
8491
|
+
*
|
|
8492
|
+
* Replaces the prior `buildLuaCliStubBlock` runtime-stub approach (BAC-234).
|
|
8021
8493
|
*/
|
|
8022
8494
|
stripLuaCliImportsAST(code, filename = "temp.ts") {
|
|
8023
8495
|
try {
|
|
8024
8496
|
const tempFile = this.project.createSourceFile(`__strip_${filename}`, code, {
|
|
8025
8497
|
overwrite: true
|
|
8026
8498
|
});
|
|
8027
|
-
|
|
8028
|
-
|
|
8029
|
-
const
|
|
8030
|
-
if (
|
|
8499
|
+
rewriteCrossFileCallsInSourceFile(tempFile, this.crossFileSpecs, this.sdkBaseClassNames);
|
|
8500
|
+
tempFile.getImportDeclarations().forEach((imp) => {
|
|
8501
|
+
const spec = imp.getModuleSpecifierValue();
|
|
8502
|
+
if (spec === "lua-cli" || spec === "lua-cli/skill" || spec === "lua-cli/voice" || spec.includes("api-exports")) {
|
|
8031
8503
|
imp.remove();
|
|
8032
8504
|
}
|
|
8033
8505
|
});
|
|
@@ -8035,16 +8507,17 @@ var init_bundler = __esm({
|
|
|
8035
8507
|
this.project.removeSourceFile(tempFile);
|
|
8036
8508
|
return result;
|
|
8037
8509
|
} catch (error) {
|
|
8038
|
-
|
|
8510
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
8511
|
+
throw new Error(`[lua-cli] AST rewrite failed for ${filename}: ${msg}. Source: bare SDK identifiers would survive into the bundle and fail at runtime; aborting compile.`);
|
|
8039
8512
|
}
|
|
8040
8513
|
}
|
|
8041
8514
|
/**
|
|
8042
8515
|
* Bundle a primitive's entry point using esbuild.
|
|
8043
8516
|
*/
|
|
8044
8517
|
async bundle(metadata, entryPointCode) {
|
|
8045
|
-
const tempDir =
|
|
8046
|
-
const outfile =
|
|
8047
|
-
const sourceDir =
|
|
8518
|
+
const tempDir = path6.join(this.options.outDir, ".temp");
|
|
8519
|
+
const outfile = path6.join(tempDir, `${metadata.kind}-${metadata.name}.bundle.js`);
|
|
8520
|
+
const sourceDir = path6.dirname(metadata.sourcePath);
|
|
8048
8521
|
if (this.options.debug) {
|
|
8049
8522
|
this.verbose(` Source: ${metadata.sourcePath}`);
|
|
8050
8523
|
this.verbose(` Output: ${outfile}`);
|
|
@@ -8074,15 +8547,15 @@ var init_bundler = __esm({
|
|
|
8074
8547
|
],
|
|
8075
8548
|
logLevel: this.options.debug ? "debug" : "silent"
|
|
8076
8549
|
});
|
|
8077
|
-
const code = await
|
|
8550
|
+
const code = await fs7.readFile(outfile, "utf-8");
|
|
8078
8551
|
let sourceMap = "";
|
|
8079
8552
|
try {
|
|
8080
|
-
sourceMap = await
|
|
8553
|
+
sourceMap = await fs7.readFile(outfile + ".map", "utf-8");
|
|
8081
8554
|
} catch {
|
|
8082
8555
|
}
|
|
8083
|
-
const originalSource = await
|
|
8556
|
+
const originalSource = await fs7.readFile(metadata.sourcePath, "utf-8");
|
|
8084
8557
|
const hash = crypto4.createHash("sha256").update(code).digest("hex").slice(0, 16);
|
|
8085
|
-
const stats = await
|
|
8558
|
+
const stats = await fs7.stat(outfile);
|
|
8086
8559
|
return {
|
|
8087
8560
|
code,
|
|
8088
8561
|
sourceMap,
|
|
@@ -8099,14 +8572,14 @@ var init_bundler = __esm({
|
|
|
8099
8572
|
const bundler = this;
|
|
8100
8573
|
const sourcePath = metadata.sourcePath;
|
|
8101
8574
|
const exportName = metadata.exportName;
|
|
8102
|
-
const sourceDir =
|
|
8575
|
+
const sourceDir = path6.dirname(sourcePath);
|
|
8103
8576
|
return {
|
|
8104
8577
|
name: "lua-virtual-source",
|
|
8105
8578
|
setup(build2) {
|
|
8106
8579
|
build2.onResolve({
|
|
8107
8580
|
filter: /.*/
|
|
8108
8581
|
}, (args2) => {
|
|
8109
|
-
const resolved = args2.path.startsWith(".") ?
|
|
8582
|
+
const resolved = args2.path.startsWith(".") ? path6.resolve(args2.resolveDir, args2.path) : args2.path;
|
|
8110
8583
|
const normalizedResolved = resolved.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
8111
8584
|
const normalizedSource = sourcePath.replace(/\.(ts|tsx|js|jsx)$/, "");
|
|
8112
8585
|
if (normalizedResolved === normalizedSource) {
|
|
@@ -8122,8 +8595,8 @@ var init_bundler = __esm({
|
|
|
8122
8595
|
namespace: "lua-virtual-source"
|
|
8123
8596
|
}, async () => {
|
|
8124
8597
|
const sourceFile = bundler.project.getSourceFile(sourcePath);
|
|
8125
|
-
let content = sourceFile?.getText() ?? await
|
|
8126
|
-
content = bundler.stripLuaCliImportsAST(content,
|
|
8598
|
+
let content = sourceFile?.getText() ?? await fs7.readFile(sourcePath, "utf-8");
|
|
8599
|
+
content = bundler.stripLuaCliImportsAST(content, path6.basename(sourcePath));
|
|
8127
8600
|
const virtualContent = metadata.isDefaultExport ? content : `${content}
|
|
8128
8601
|
export { ${exportName} as __lua_target__ };
|
|
8129
8602
|
`;
|
|
@@ -8143,8 +8616,6 @@ export { ${exportName} as __lua_target__ };
|
|
|
8143
8616
|
*/
|
|
8144
8617
|
createLuaCliShimPlugin() {
|
|
8145
8618
|
const stripImports = this.stripLuaCliImportsAST.bind(this);
|
|
8146
|
-
const debug = this.options.debug;
|
|
8147
|
-
const verbose = this.verbose.bind(this);
|
|
8148
8619
|
return {
|
|
8149
8620
|
name: "lua-cli-import-stripper",
|
|
8150
8621
|
setup(build2) {
|
|
@@ -8153,29 +8624,27 @@ export { ${exportName} as __lua_target__ };
|
|
|
8153
8624
|
namespace: "file"
|
|
8154
8625
|
}, async (args2) => {
|
|
8155
8626
|
if (args2.path.includes("node_modules")) return null;
|
|
8156
|
-
const contents = await
|
|
8627
|
+
const contents = await fs7.readFile(args2.path, "utf-8");
|
|
8157
8628
|
if (!contents.includes("lua-cli") && !contents.includes("api-exports")) {
|
|
8158
8629
|
return null;
|
|
8159
8630
|
}
|
|
8160
8631
|
try {
|
|
8161
|
-
const modifiedContents = stripImports(contents,
|
|
8632
|
+
const modifiedContents = stripImports(contents, path6.basename(args2.path));
|
|
8162
8633
|
if (modifiedContents !== contents) {
|
|
8163
8634
|
return {
|
|
8164
8635
|
contents: modifiedContents,
|
|
8165
8636
|
loader: args2.path.endsWith(".ts") || args2.path.endsWith(".tsx") ? "ts" : "js",
|
|
8166
|
-
resolveDir:
|
|
8637
|
+
resolveDir: path6.dirname(args2.path)
|
|
8167
8638
|
};
|
|
8168
8639
|
}
|
|
8169
8640
|
return null;
|
|
8170
8641
|
} catch (error) {
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
}
|
|
8174
|
-
return null;
|
|
8642
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
8643
|
+
throw new Error(`[lua-cli] AST rewrite failed for ${args2.path}: ${msg}. Aborting compile (silent fallback would corrupt the bundle).`);
|
|
8175
8644
|
}
|
|
8176
8645
|
});
|
|
8177
8646
|
build2.onResolve({
|
|
8178
|
-
filter: /^lua-cli(\/skill)?$/
|
|
8647
|
+
filter: /^lua-cli(\/(skill|voice))?$/
|
|
8179
8648
|
}, () => ({
|
|
8180
8649
|
path: "lua-cli-empty",
|
|
8181
8650
|
namespace: "lua-cli-empty"
|
|
@@ -8201,9 +8670,9 @@ export { ${exportName} as __lua_target__ };
|
|
|
8201
8670
|
});
|
|
8202
8671
|
|
|
8203
8672
|
// src/compiler/agent-traverser.ts
|
|
8204
|
-
import { Project, Node as
|
|
8205
|
-
import
|
|
8206
|
-
import
|
|
8673
|
+
import { Project as Project2, Node as Node16 } from "ts-morph";
|
|
8674
|
+
import path7 from "path";
|
|
8675
|
+
import fs8 from "fs";
|
|
8207
8676
|
var PRIMITIVE_TYPES, AgentTraverser;
|
|
8208
8677
|
var init_agent_traverser = __esm({
|
|
8209
8678
|
"src/compiler/agent-traverser.ts"() {
|
|
@@ -8275,8 +8744,8 @@ var init_agent_traverser = __esm({
|
|
|
8275
8744
|
constructor(rootDir, debug = false) {
|
|
8276
8745
|
this.rootDir = rootDir;
|
|
8277
8746
|
this.debug = debug;
|
|
8278
|
-
this.project = new
|
|
8279
|
-
tsConfigFilePath:
|
|
8747
|
+
this.project = new Project2({
|
|
8748
|
+
tsConfigFilePath: path7.join(rootDir, "tsconfig.json"),
|
|
8280
8749
|
skipAddingFilesFromTsConfig: true
|
|
8281
8750
|
});
|
|
8282
8751
|
registerProjectRootDir(this.project, this.rootDir);
|
|
@@ -8360,15 +8829,15 @@ var init_agent_traverser = __esm({
|
|
|
8360
8829
|
*/
|
|
8361
8830
|
detectAgent() {
|
|
8362
8831
|
const priorityFiles = [
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8832
|
+
path7.join(this.rootDir, "index.ts"),
|
|
8833
|
+
path7.join(this.rootDir, "src", "index.ts"),
|
|
8834
|
+
path7.join(this.rootDir, "agent.ts"),
|
|
8835
|
+
path7.join(this.rootDir, "src", "agent.ts"),
|
|
8836
|
+
path7.join(this.rootDir, "main.ts"),
|
|
8837
|
+
path7.join(this.rootDir, "src", "main.ts")
|
|
8369
8838
|
];
|
|
8370
8839
|
for (const filePath of priorityFiles) {
|
|
8371
|
-
if (
|
|
8840
|
+
if (fs8.existsSync(filePath)) {
|
|
8372
8841
|
try {
|
|
8373
8842
|
const sourceFile = this.project.addSourceFileAtPath(filePath);
|
|
8374
8843
|
const agent = this.detectAgentInFile(sourceFile);
|
|
@@ -8424,7 +8893,7 @@ var init_agent_traverser = __esm({
|
|
|
8424
8893
|
*/
|
|
8425
8894
|
extractArrayRefs(config, propName) {
|
|
8426
8895
|
const prop = config.getProperty(propName);
|
|
8427
|
-
if (!prop || !
|
|
8896
|
+
if (!prop || !Node16.isPropertyAssignment(prop)) return [];
|
|
8428
8897
|
const value = prop.getInitializer();
|
|
8429
8898
|
if (!value) return [];
|
|
8430
8899
|
const ctx = {
|
|
@@ -8509,7 +8978,7 @@ var init_agent_traverser = __esm({
|
|
|
8509
8978
|
for (const assign of file.getExportAssignments()) {
|
|
8510
8979
|
if (assign.isExportEquals()) continue;
|
|
8511
8980
|
const expr = assign.getExpression();
|
|
8512
|
-
if (!
|
|
8981
|
+
if (!Node16.isIdentifier(expr)) continue;
|
|
8513
8982
|
const targetName = expr.getText();
|
|
8514
8983
|
defaultMatch = detected.find((d) => d.exportName === targetName);
|
|
8515
8984
|
if (defaultMatch) break;
|
|
@@ -8520,7 +8989,7 @@ var init_agent_traverser = __esm({
|
|
|
8520
8989
|
console.warn(formatSarifWarning({
|
|
8521
8990
|
ruleId: "lua/missing-primitive-declaration",
|
|
8522
8991
|
filePath: sourcePath,
|
|
8523
|
-
message: `agent references ${kind} "${refName}" but ${
|
|
8992
|
+
message: `agent references ${kind} "${refName}" but ${path7.basename(sourcePath)} does not define a matching primitive`,
|
|
8524
8993
|
hint: `export a named ${plugin.displayName.toLowerCase()} declaration as "${refName}", or adjust the import so it points to the file that does`
|
|
8525
8994
|
}));
|
|
8526
8995
|
return null;
|
|
@@ -8540,20 +9009,20 @@ var init_agent_traverser = __esm({
|
|
|
8540
9009
|
});
|
|
8541
9010
|
|
|
8542
9011
|
// src/compiler/utils/workspace.ts
|
|
8543
|
-
import
|
|
8544
|
-
import
|
|
9012
|
+
import fs9 from "fs";
|
|
9013
|
+
import path8 from "path";
|
|
8545
9014
|
function findWorkspaceRoot(rootDir) {
|
|
8546
|
-
const resolvedInput =
|
|
9015
|
+
const resolvedInput = path8.resolve(rootDir);
|
|
8547
9016
|
const cached = workspaceRootCache.get(resolvedInput);
|
|
8548
9017
|
if (cached !== void 0) return cached;
|
|
8549
9018
|
let current = resolvedInput;
|
|
8550
|
-
const { root } =
|
|
9019
|
+
const { root } = path8.parse(current);
|
|
8551
9020
|
while (true) {
|
|
8552
9021
|
if (isWorkspaceRoot(current)) {
|
|
8553
9022
|
workspaceRootCache.set(resolvedInput, current);
|
|
8554
9023
|
return current;
|
|
8555
9024
|
}
|
|
8556
|
-
const parent =
|
|
9025
|
+
const parent = path8.dirname(current);
|
|
8557
9026
|
if (parent === current || current === root) break;
|
|
8558
9027
|
current = parent;
|
|
8559
9028
|
}
|
|
@@ -8561,22 +9030,22 @@ function findWorkspaceRoot(rootDir) {
|
|
|
8561
9030
|
return resolvedInput;
|
|
8562
9031
|
}
|
|
8563
9032
|
function isWorkspaceRoot(dir) {
|
|
8564
|
-
if (fileExists(
|
|
8565
|
-
if (fileExists(
|
|
8566
|
-
if (packageJsonHasWorkspaces(
|
|
8567
|
-
if (dirExists(
|
|
9033
|
+
if (fileExists(path8.join(dir, "pnpm-workspace.yaml"))) return true;
|
|
9034
|
+
if (fileExists(path8.join(dir, "lerna.json"))) return true;
|
|
9035
|
+
if (packageJsonHasWorkspaces(path8.join(dir, "package.json"))) return true;
|
|
9036
|
+
if (dirExists(path8.join(dir, ".git"))) return true;
|
|
8568
9037
|
return false;
|
|
8569
9038
|
}
|
|
8570
9039
|
function fileExists(p) {
|
|
8571
9040
|
try {
|
|
8572
|
-
return
|
|
9041
|
+
return fs9.statSync(p).isFile();
|
|
8573
9042
|
} catch {
|
|
8574
9043
|
return false;
|
|
8575
9044
|
}
|
|
8576
9045
|
}
|
|
8577
9046
|
function dirExists(p) {
|
|
8578
9047
|
try {
|
|
8579
|
-
return
|
|
9048
|
+
return fs9.statSync(p).isDirectory();
|
|
8580
9049
|
} catch {
|
|
8581
9050
|
return false;
|
|
8582
9051
|
}
|
|
@@ -8584,7 +9053,7 @@ function dirExists(p) {
|
|
|
8584
9053
|
function packageJsonHasWorkspaces(pkgPath) {
|
|
8585
9054
|
if (!fileExists(pkgPath)) return false;
|
|
8586
9055
|
try {
|
|
8587
|
-
const raw =
|
|
9056
|
+
const raw = fs9.readFileSync(pkgPath, "utf-8");
|
|
8588
9057
|
const json = JSON.parse(raw);
|
|
8589
9058
|
if (!json.workspaces) return false;
|
|
8590
9059
|
return Array.isArray(json.workspaces) || typeof json.workspaces === "object";
|
|
@@ -8606,9 +9075,9 @@ var init_workspace = __esm({
|
|
|
8606
9075
|
});
|
|
8607
9076
|
|
|
8608
9077
|
// src/compiler/compiler.ts
|
|
8609
|
-
import
|
|
8610
|
-
import
|
|
8611
|
-
import { Project as
|
|
9078
|
+
import fs10 from "fs/promises";
|
|
9079
|
+
import path9 from "path";
|
|
9080
|
+
import { Project as Project3 } from "ts-morph";
|
|
8612
9081
|
async function compile(options) {
|
|
8613
9082
|
const compiler = new Compiler(options);
|
|
8614
9083
|
return compiler.compile();
|
|
@@ -8659,8 +9128,8 @@ var init_compiler = __esm({
|
|
|
8659
9128
|
runtimeValidation: true,
|
|
8660
9129
|
...options
|
|
8661
9130
|
};
|
|
8662
|
-
this.project = new
|
|
8663
|
-
tsConfigFilePath:
|
|
9131
|
+
this.project = new Project3({
|
|
9132
|
+
tsConfigFilePath: path9.join(options.rootDir, "tsconfig.json")
|
|
8664
9133
|
});
|
|
8665
9134
|
registerProjectRootDir(this.project, this.options.rootDir);
|
|
8666
9135
|
this.bundler = new Bundler({
|
|
@@ -8737,10 +9206,10 @@ var init_compiler = __esm({
|
|
|
8737
9206
|
return await this.createResult(false, [], errors, warnings, startTime);
|
|
8738
9207
|
}
|
|
8739
9208
|
this.verbose("\u{1F4E6} Bundling primitives...");
|
|
8740
|
-
await
|
|
9209
|
+
await fs10.mkdir(this.options.outDir, {
|
|
8741
9210
|
recursive: true
|
|
8742
9211
|
});
|
|
8743
|
-
await
|
|
9212
|
+
await fs10.mkdir(path9.join(this.options.outDir, ".temp"), {
|
|
8744
9213
|
recursive: true
|
|
8745
9214
|
});
|
|
8746
9215
|
const CONCURRENCY = 4;
|
|
@@ -8760,7 +9229,7 @@ var init_compiler = __esm({
|
|
|
8760
9229
|
this.verbose("\u{1F4BE} Writing artifacts...");
|
|
8761
9230
|
await this.writeArtifacts(compiledPrimitives);
|
|
8762
9231
|
if (!this.options.debug) {
|
|
8763
|
-
await
|
|
9232
|
+
await fs10.rm(path9.join(this.options.outDir, ".temp"), {
|
|
8764
9233
|
recursive: true,
|
|
8765
9234
|
force: true
|
|
8766
9235
|
});
|
|
@@ -8803,7 +9272,7 @@ var init_compiler = __esm({
|
|
|
8803
9272
|
*/
|
|
8804
9273
|
getWorkspaceRoot() {
|
|
8805
9274
|
if (this._workspaceRoot === void 0) {
|
|
8806
|
-
this._workspaceRoot = findWorkspaceRoot(
|
|
9275
|
+
this._workspaceRoot = findWorkspaceRoot(path9.resolve(this.options.rootDir));
|
|
8807
9276
|
}
|
|
8808
9277
|
return this._workspaceRoot;
|
|
8809
9278
|
}
|
|
@@ -8817,18 +9286,18 @@ var init_compiler = __esm({
|
|
|
8817
9286
|
* - Files outside the detected workspace root (not our code)
|
|
8818
9287
|
*/
|
|
8819
9288
|
collectExternalWorkspaceFiles(traverser) {
|
|
8820
|
-
const rootDir =
|
|
9289
|
+
const rootDir = path9.resolve(this.options.rootDir);
|
|
8821
9290
|
const workspaceRoot = this.getWorkspaceRoot();
|
|
8822
9291
|
if (workspaceRoot === rootDir) return [];
|
|
8823
9292
|
const loaded = traverser.getAllLoadedSourceFilePaths();
|
|
8824
9293
|
const result = [];
|
|
8825
9294
|
const seen = /* @__PURE__ */ new Set();
|
|
8826
9295
|
for (const raw of loaded) {
|
|
8827
|
-
const abs =
|
|
9296
|
+
const abs = path9.resolve(raw);
|
|
8828
9297
|
if (seen.has(abs)) continue;
|
|
8829
9298
|
seen.add(abs);
|
|
8830
9299
|
if (isInside(abs, rootDir)) continue;
|
|
8831
|
-
if (abs.includes(`${
|
|
9300
|
+
if (abs.includes(`${path9.sep}node_modules${path9.sep}`)) continue;
|
|
8832
9301
|
if (!isInside(abs, workspaceRoot)) continue;
|
|
8833
9302
|
result.push(abs);
|
|
8834
9303
|
}
|
|
@@ -8961,9 +9430,9 @@ var init_compiler = __esm({
|
|
|
8961
9430
|
* @param primitives - All compiled primitives to write
|
|
8962
9431
|
*/
|
|
8963
9432
|
async writeArtifacts(primitives) {
|
|
8964
|
-
const artifactsDir =
|
|
8965
|
-
const sourcesDir =
|
|
8966
|
-
await
|
|
9433
|
+
const artifactsDir = path9.join(this.options.outDir, "artifacts");
|
|
9434
|
+
const sourcesDir = path9.join(this.options.outDir, "sources");
|
|
9435
|
+
await fs10.mkdir(sourcesDir, {
|
|
8967
9436
|
recursive: true
|
|
8968
9437
|
});
|
|
8969
9438
|
const writtenSources = /* @__PURE__ */ new Map();
|
|
@@ -8971,7 +9440,7 @@ var init_compiler = __esm({
|
|
|
8971
9440
|
this.verbose(" \u{1F4C2} Collecting project files...");
|
|
8972
9441
|
const projectFiles = await this.storeProjectFiles(sourcesDir, writtenSources);
|
|
8973
9442
|
const manifest = await this.createManifest(primitives, projectFiles);
|
|
8974
|
-
await
|
|
9443
|
+
await fs10.writeFile(path9.join(this.options.outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
8975
9444
|
this.verbose(` \u{1F4E6} Total files stored: ${writtenSources.size} (deduplicated)`);
|
|
8976
9445
|
this.verbose(` \u{1F4C1} Project files: ${projectFiles.length}`);
|
|
8977
9446
|
if (this.options.verbose || this.options.debug) {
|
|
@@ -8983,25 +9452,25 @@ var init_compiler = __esm({
|
|
|
8983
9452
|
*/
|
|
8984
9453
|
async writePrimitiveArtifacts(primitives, artifactsDir, sourcesDir, writtenSources) {
|
|
8985
9454
|
for (const primitive of primitives) {
|
|
8986
|
-
const primitiveDir =
|
|
8987
|
-
await
|
|
9455
|
+
const primitiveDir = path9.join(artifactsDir, primitive.kind);
|
|
9456
|
+
await fs10.mkdir(primitiveDir, {
|
|
8988
9457
|
recursive: true
|
|
8989
9458
|
});
|
|
8990
9459
|
const baseName = primitive.name;
|
|
8991
|
-
await
|
|
9460
|
+
await fs10.writeFile(path9.join(primitiveDir, `${baseName}.js`), primitive.artifact.code);
|
|
8992
9461
|
if (primitive.artifact.sourceMap) {
|
|
8993
|
-
await
|
|
9462
|
+
await fs10.writeFile(path9.join(primitiveDir, `${baseName}.js.map`), primitive.artifact.sourceMap);
|
|
8994
9463
|
}
|
|
8995
9464
|
const sourceHash = hashContent(primitive.artifact.originalSource);
|
|
8996
9465
|
if (!writtenSources.has(sourceHash)) {
|
|
8997
9466
|
const ext = primitive.sourcePath.endsWith(".tsx") ? ".tsx" : ".ts";
|
|
8998
|
-
await
|
|
8999
|
-
const relativePath =
|
|
9467
|
+
await fs10.writeFile(path9.join(sourcesDir, `${sourceHash}${ext}`), primitive.artifact.originalSource);
|
|
9468
|
+
const relativePath = path9.relative(this.options.rootDir, primitive.sourcePath);
|
|
9000
9469
|
writtenSources.set(sourceHash, relativePath);
|
|
9001
9470
|
}
|
|
9002
9471
|
const sidecarPlugin = pluginRegistry.get(primitive.kind);
|
|
9003
9472
|
const sidecarMetadata = sidecarPlugin?.sanitizeForPersistence ? sidecarPlugin.sanitizeForPersistence(primitive.metadata) : primitive.metadata;
|
|
9004
|
-
await
|
|
9473
|
+
await fs10.writeFile(path9.join(primitiveDir, `${baseName}.json`), JSON.stringify({
|
|
9005
9474
|
kind: primitive.kind,
|
|
9006
9475
|
name: primitive.name,
|
|
9007
9476
|
description: primitive.description,
|
|
@@ -9023,12 +9492,12 @@ var init_compiler = __esm({
|
|
|
9023
9492
|
const allFiles = await this.collectProjectFiles();
|
|
9024
9493
|
const workspaceRoot = this.getWorkspaceRoot();
|
|
9025
9494
|
for (const file of allFiles) {
|
|
9026
|
-
const absPath = file.external ?
|
|
9027
|
-
const content = await
|
|
9495
|
+
const absPath = file.external ? path9.join(workspaceRoot, file.relativePath) : path9.join(this.options.rootDir, file.relativePath);
|
|
9496
|
+
const content = await fs10.readFile(absPath, "utf-8");
|
|
9028
9497
|
const hash = hashContent(content);
|
|
9029
9498
|
if (!writtenSources.has(hash)) {
|
|
9030
|
-
const ext =
|
|
9031
|
-
await
|
|
9499
|
+
const ext = path9.extname(file.relativePath) || ".txt";
|
|
9500
|
+
await fs10.writeFile(path9.join(sourcesDir, `${hash}${ext}`), content);
|
|
9032
9501
|
writtenSources.set(hash, file.relativePath);
|
|
9033
9502
|
}
|
|
9034
9503
|
projectFiles.push({
|
|
@@ -9104,12 +9573,12 @@ var init_compiler = __esm({
|
|
|
9104
9573
|
async collectProjectFiles() {
|
|
9105
9574
|
const files = [];
|
|
9106
9575
|
const scanDir = /* @__PURE__ */ __name(async (dir, relativeBase = "") => {
|
|
9107
|
-
const entries = await
|
|
9576
|
+
const entries = await fs10.readdir(dir, {
|
|
9108
9577
|
withFileTypes: true
|
|
9109
9578
|
});
|
|
9110
9579
|
for (const entry of entries) {
|
|
9111
9580
|
const relativePath = relativeBase ? `${relativeBase}/${entry.name}` : entry.name;
|
|
9112
|
-
const fullPath =
|
|
9581
|
+
const fullPath = path9.join(dir, entry.name);
|
|
9113
9582
|
if (entry.isDirectory()) {
|
|
9114
9583
|
if (shouldSkipDirectory(entry.name)) continue;
|
|
9115
9584
|
await scanDir(fullPath, relativePath);
|
|
@@ -9126,10 +9595,10 @@ var init_compiler = __esm({
|
|
|
9126
9595
|
const workspaceRoot = this.getWorkspaceRoot();
|
|
9127
9596
|
const externalSeen = /* @__PURE__ */ new Set();
|
|
9128
9597
|
for (const abs of this.externalWorkspaceFiles) {
|
|
9129
|
-
const rel =
|
|
9598
|
+
const rel = path9.relative(workspaceRoot, abs).split(path9.sep).join("/");
|
|
9130
9599
|
if (!rel || rel.startsWith("..")) continue;
|
|
9131
9600
|
if (externalSeen.has(rel)) continue;
|
|
9132
|
-
const name =
|
|
9601
|
+
const name = path9.basename(abs);
|
|
9133
9602
|
if (shouldSkipFile(rel) || shouldSkipFile(name)) continue;
|
|
9134
9603
|
externalSeen.add(rel);
|
|
9135
9604
|
files.push({
|
|
@@ -9230,13 +9699,13 @@ var init_compiler = __esm({
|
|
|
9230
9699
|
});
|
|
9231
9700
|
|
|
9232
9701
|
// src/compiler/utils/file-discovery.ts
|
|
9233
|
-
import
|
|
9234
|
-
import
|
|
9702
|
+
import path10 from "path";
|
|
9703
|
+
import fs11 from "fs";
|
|
9235
9704
|
function findEntryPoint(projectDir) {
|
|
9236
9705
|
const baseDir = projectDir || process.cwd();
|
|
9237
9706
|
for (const relativePath of ENTRY_POINT_PRIORITY) {
|
|
9238
|
-
const fullPath =
|
|
9239
|
-
if (
|
|
9707
|
+
const fullPath = path10.join(baseDir, relativePath);
|
|
9708
|
+
if (fs11.existsSync(fullPath)) {
|
|
9240
9709
|
return fullPath;
|
|
9241
9710
|
}
|
|
9242
9711
|
}
|
|
@@ -9272,9 +9741,9 @@ var init_file_discovery = __esm({
|
|
|
9272
9741
|
});
|
|
9273
9742
|
|
|
9274
9743
|
// src/compiler/source-writer.ts
|
|
9275
|
-
import { Project as
|
|
9276
|
-
import
|
|
9277
|
-
import
|
|
9744
|
+
import { Project as Project4, Node as Node17 } from "ts-morph";
|
|
9745
|
+
import fs12 from "fs";
|
|
9746
|
+
import path11 from "path";
|
|
9278
9747
|
function resolveEntryPath(options) {
|
|
9279
9748
|
let indexPath;
|
|
9280
9749
|
try {
|
|
@@ -9286,14 +9755,14 @@ function resolveEntryPath(options) {
|
|
|
9286
9755
|
indexPath = entryPoint;
|
|
9287
9756
|
} else {
|
|
9288
9757
|
const baseDir = options?.projectDir || process.cwd();
|
|
9289
|
-
indexPath =
|
|
9758
|
+
indexPath = path11.join(baseDir, "src", "index.ts");
|
|
9290
9759
|
}
|
|
9291
9760
|
}
|
|
9292
9761
|
} catch {
|
|
9293
9762
|
const baseDir = options?.projectDir || process.cwd();
|
|
9294
|
-
indexPath =
|
|
9763
|
+
indexPath = path11.join(baseDir, "src", "index.ts");
|
|
9295
9764
|
}
|
|
9296
|
-
if (!
|
|
9765
|
+
if (!fs12.existsSync(indexPath)) {
|
|
9297
9766
|
console.warn(`Warning: Entry file not found at ${indexPath}`);
|
|
9298
9767
|
return null;
|
|
9299
9768
|
}
|
|
@@ -9315,20 +9784,20 @@ function updateAgentConfig(updates, options) {
|
|
|
9315
9784
|
const indexPath = resolveEntryPath(options);
|
|
9316
9785
|
if (!indexPath) return false;
|
|
9317
9786
|
try {
|
|
9318
|
-
const project = new
|
|
9787
|
+
const project = new Project4({
|
|
9319
9788
|
skipAddingFilesFromTsConfig: true
|
|
9320
9789
|
});
|
|
9321
9790
|
const sourceFile = project.addSourceFileAtPath(indexPath);
|
|
9322
9791
|
let updated = false;
|
|
9323
9792
|
sourceFile.forEachDescendant((node) => {
|
|
9324
|
-
if (
|
|
9793
|
+
if (Node17.isNewExpression(node) && node.getExpression().getText() === "LuaAgent") {
|
|
9325
9794
|
const args2 = node.getArguments();
|
|
9326
|
-
if (args2.length > 0 &&
|
|
9795
|
+
if (args2.length > 0 && Node17.isObjectLiteralExpression(args2[0])) {
|
|
9327
9796
|
const configObj = args2[0];
|
|
9328
9797
|
const replacedKeys = /* @__PURE__ */ new Set();
|
|
9329
9798
|
let lastReplacedIndex = -1;
|
|
9330
9799
|
configObj.getProperties().forEach((prop, index) => {
|
|
9331
|
-
if (
|
|
9800
|
+
if (Node17.isPropertyAssignment(prop)) {
|
|
9332
9801
|
const propName = prop.getName();
|
|
9333
9802
|
if (Object.prototype.hasOwnProperty.call(filteredUpdates, propName)) {
|
|
9334
9803
|
const newValue = filteredUpdates[propName];
|
|
@@ -9384,21 +9853,21 @@ function removeAgentConfigProperty(propertyName, options) {
|
|
|
9384
9853
|
const indexPath = resolveEntryPath(options);
|
|
9385
9854
|
if (!indexPath) return false;
|
|
9386
9855
|
try {
|
|
9387
|
-
const project = new
|
|
9856
|
+
const project = new Project4({
|
|
9388
9857
|
skipAddingFilesFromTsConfig: true
|
|
9389
9858
|
});
|
|
9390
9859
|
const sourceFile = project.addSourceFileAtPath(indexPath);
|
|
9391
9860
|
let foundConstructor = false;
|
|
9392
9861
|
let removed = false;
|
|
9393
9862
|
sourceFile.forEachDescendant((node) => {
|
|
9394
|
-
if (
|
|
9863
|
+
if (Node17.isNewExpression(node) && node.getExpression().getText() === "LuaAgent") {
|
|
9395
9864
|
const args2 = node.getArguments();
|
|
9396
|
-
if (args2.length > 0 &&
|
|
9865
|
+
if (args2.length > 0 && Node17.isObjectLiteralExpression(args2[0])) {
|
|
9397
9866
|
foundConstructor = true;
|
|
9398
9867
|
const configObj = args2[0];
|
|
9399
9868
|
const props = configObj.getProperties();
|
|
9400
9869
|
for (const prop of props) {
|
|
9401
|
-
if (
|
|
9870
|
+
if (Node17.isPropertyAssignment(prop) && prop.getName() === propertyName) {
|
|
9402
9871
|
prop.remove();
|
|
9403
9872
|
removed = true;
|
|
9404
9873
|
break;
|
|
@@ -13283,6 +13752,164 @@ __name(promptAuthMethod, "promptAuthMethod");
|
|
|
13283
13752
|
|
|
13284
13753
|
// src/commands/configure.ts
|
|
13285
13754
|
init_analytics();
|
|
13755
|
+
|
|
13756
|
+
// src/utils/versioning-mode-cache.ts
|
|
13757
|
+
import * as fs3 from "fs";
|
|
13758
|
+
import * as path3 from "path";
|
|
13759
|
+
|
|
13760
|
+
// src/api/agent-version.api.service.ts
|
|
13761
|
+
init_http_client();
|
|
13762
|
+
var AgentVersionApi = class extends HttpClient {
|
|
13763
|
+
static {
|
|
13764
|
+
__name(this, "AgentVersionApi");
|
|
13765
|
+
}
|
|
13766
|
+
apiKey;
|
|
13767
|
+
agentId;
|
|
13768
|
+
constructor(baseUrl, apiKey, agentId) {
|
|
13769
|
+
super(baseUrl);
|
|
13770
|
+
this.apiKey = apiKey;
|
|
13771
|
+
this.agentId = agentId;
|
|
13772
|
+
}
|
|
13773
|
+
get basePath() {
|
|
13774
|
+
return `/developer/agents/${encodeURIComponent(this.agentId)}`;
|
|
13775
|
+
}
|
|
13776
|
+
get authHeader() {
|
|
13777
|
+
return {
|
|
13778
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
13779
|
+
};
|
|
13780
|
+
}
|
|
13781
|
+
// ---------------------------------------------------------------------------
|
|
13782
|
+
// Versioning mode
|
|
13783
|
+
// ---------------------------------------------------------------------------
|
|
13784
|
+
async getVersioningMode() {
|
|
13785
|
+
return this.httpGet(`${this.basePath}/versioning/mode`, this.authHeader);
|
|
13786
|
+
}
|
|
13787
|
+
// ---------------------------------------------------------------------------
|
|
13788
|
+
// Version CRUD
|
|
13789
|
+
// ---------------------------------------------------------------------------
|
|
13790
|
+
async createVersion(body) {
|
|
13791
|
+
return this.httpPost(`${this.basePath}/versions`, body, this.authHeader);
|
|
13792
|
+
}
|
|
13793
|
+
async listVersions(query) {
|
|
13794
|
+
const params = new URLSearchParams();
|
|
13795
|
+
if (query?.all !== void 0) params.append("all", String(query.all));
|
|
13796
|
+
if (query?.limit !== void 0) params.append("limit", String(query.limit));
|
|
13797
|
+
if (query?.status !== void 0) params.append("status", query.status);
|
|
13798
|
+
const qs = params.toString();
|
|
13799
|
+
const url = qs ? `${this.basePath}/versions?${qs}` : `${this.basePath}/versions`;
|
|
13800
|
+
return this.httpGet(url, this.authHeader);
|
|
13801
|
+
}
|
|
13802
|
+
async getVersion(version) {
|
|
13803
|
+
return this.httpGet(`${this.basePath}/versions/${version}`, this.authHeader);
|
|
13804
|
+
}
|
|
13805
|
+
async deleteVersion(version) {
|
|
13806
|
+
return this.httpDelete(`${this.basePath}/versions/${version}`, this.authHeader);
|
|
13807
|
+
}
|
|
13808
|
+
// ---------------------------------------------------------------------------
|
|
13809
|
+
// Diff
|
|
13810
|
+
// ---------------------------------------------------------------------------
|
|
13811
|
+
async diffVersions(from, to) {
|
|
13812
|
+
const url = `${this.basePath}/versions/diff?from=${from}&to=${to}`;
|
|
13813
|
+
return this.httpGet(url, this.authHeader);
|
|
13814
|
+
}
|
|
13815
|
+
// ---------------------------------------------------------------------------
|
|
13816
|
+
// Promote
|
|
13817
|
+
// ---------------------------------------------------------------------------
|
|
13818
|
+
async promoteVersion(version) {
|
|
13819
|
+
return this.httpPost(`${this.basePath}/versions/${version}/promote`, {}, this.authHeader);
|
|
13820
|
+
}
|
|
13821
|
+
// ---------------------------------------------------------------------------
|
|
13822
|
+
// Patch commit hash — called by `lua version create` after a successful git
|
|
13823
|
+
// commit + tag to propagate the SHA to the backend AgentVersion record.
|
|
13824
|
+
// Failure is non-fatal; the version snapshot is valid whether or not this
|
|
13825
|
+
// PATCH lands.
|
|
13826
|
+
// ---------------------------------------------------------------------------
|
|
13827
|
+
async patchCommitHash(version, commitHash) {
|
|
13828
|
+
return this.httpPatch(`${this.basePath}/versions/${version}/commit-hash`, {
|
|
13829
|
+
commitHash
|
|
13830
|
+
}, this.authHeader);
|
|
13831
|
+
}
|
|
13832
|
+
};
|
|
13833
|
+
|
|
13834
|
+
// src/utils/versioning-mode-cache.ts
|
|
13835
|
+
init_constants();
|
|
13836
|
+
init_auth_error();
|
|
13837
|
+
init_constants();
|
|
13838
|
+
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
13839
|
+
function readCacheFile() {
|
|
13840
|
+
try {
|
|
13841
|
+
const raw = fs3.readFileSync(CLI_CACHE_FILE, "utf-8");
|
|
13842
|
+
return JSON.parse(raw);
|
|
13843
|
+
} catch {
|
|
13844
|
+
return {};
|
|
13845
|
+
}
|
|
13846
|
+
}
|
|
13847
|
+
__name(readCacheFile, "readCacheFile");
|
|
13848
|
+
function writeCacheFile(data) {
|
|
13849
|
+
try {
|
|
13850
|
+
fs3.mkdirSync(path3.dirname(CLI_CACHE_FILE), {
|
|
13851
|
+
recursive: true
|
|
13852
|
+
});
|
|
13853
|
+
fs3.writeFileSync(CLI_CACHE_FILE, JSON.stringify(data, null, 2));
|
|
13854
|
+
} catch {
|
|
13855
|
+
}
|
|
13856
|
+
}
|
|
13857
|
+
__name(writeCacheFile, "writeCacheFile");
|
|
13858
|
+
function isFresh(entry) {
|
|
13859
|
+
const age = Date.now() - new Date(entry.cachedAt).getTime();
|
|
13860
|
+
return age >= 0 && age < CACHE_TTL_MS;
|
|
13861
|
+
}
|
|
13862
|
+
__name(isFresh, "isFresh");
|
|
13863
|
+
async function getVersioningModeCached(apiKey, agentId) {
|
|
13864
|
+
const file = readCacheFile();
|
|
13865
|
+
const existing = file.versioningMode?.[agentId];
|
|
13866
|
+
if (existing && isFresh(existing)) {
|
|
13867
|
+
return {
|
|
13868
|
+
enabled: existing.enabled
|
|
13869
|
+
};
|
|
13870
|
+
}
|
|
13871
|
+
try {
|
|
13872
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
13873
|
+
const response = await api.getVersioningMode();
|
|
13874
|
+
if (!response.success || !response.data) {
|
|
13875
|
+
if (existing) return {
|
|
13876
|
+
enabled: existing.enabled
|
|
13877
|
+
};
|
|
13878
|
+
return {
|
|
13879
|
+
enabled: false
|
|
13880
|
+
};
|
|
13881
|
+
}
|
|
13882
|
+
const enabled = response.data.enabled === true;
|
|
13883
|
+
file.versioningMode = file.versioningMode ?? {};
|
|
13884
|
+
file.versioningMode[agentId] = {
|
|
13885
|
+
enabled,
|
|
13886
|
+
cachedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13887
|
+
};
|
|
13888
|
+
writeCacheFile(file);
|
|
13889
|
+
return {
|
|
13890
|
+
enabled
|
|
13891
|
+
};
|
|
13892
|
+
} catch (err) {
|
|
13893
|
+
if (err instanceof AuthenticationError) throw err;
|
|
13894
|
+
if (err instanceof Error && /access denied|forbidden|403|401/i.test(err.message)) throw err;
|
|
13895
|
+
if (existing) return {
|
|
13896
|
+
enabled: existing.enabled
|
|
13897
|
+
};
|
|
13898
|
+
return {
|
|
13899
|
+
enabled: false
|
|
13900
|
+
};
|
|
13901
|
+
}
|
|
13902
|
+
}
|
|
13903
|
+
__name(getVersioningModeCached, "getVersioningModeCached");
|
|
13904
|
+
function invalidateVersioningModeCache() {
|
|
13905
|
+
const file = readCacheFile();
|
|
13906
|
+
if (!file.versioningMode) return;
|
|
13907
|
+
delete file.versioningMode;
|
|
13908
|
+
writeCacheFile(file);
|
|
13909
|
+
}
|
|
13910
|
+
__name(invalidateVersioningModeCache, "invalidateVersioningModeCache");
|
|
13911
|
+
|
|
13912
|
+
// src/commands/configure.ts
|
|
13286
13913
|
async function configureCommand(options = {}) {
|
|
13287
13914
|
return withErrorHandling(async () => {
|
|
13288
13915
|
const { apiKey, email, otp } = options;
|
|
@@ -13292,11 +13919,13 @@ async function configureCommand(options = {}) {
|
|
|
13292
13919
|
authMethod = "api-key";
|
|
13293
13920
|
nonInteractive = true;
|
|
13294
13921
|
await handleApiKeyAuthNonInteractive(apiKey);
|
|
13922
|
+
invalidateVersioningModeCache();
|
|
13295
13923
|
} else if (email) {
|
|
13296
13924
|
authMethod = "email";
|
|
13297
13925
|
nonInteractive = true;
|
|
13298
13926
|
if (otp) {
|
|
13299
13927
|
await handleEmailOtpVerify(email, otp);
|
|
13928
|
+
invalidateVersioningModeCache();
|
|
13300
13929
|
} else {
|
|
13301
13930
|
await handleEmailOtpRequest(email);
|
|
13302
13931
|
}
|
|
@@ -13305,8 +13934,10 @@ async function configureCommand(options = {}) {
|
|
|
13305
13934
|
clearPromptLines(2);
|
|
13306
13935
|
if (authMethod === "api-key") {
|
|
13307
13936
|
await handleApiKeyAuth();
|
|
13937
|
+
invalidateVersioningModeCache();
|
|
13308
13938
|
} else if (authMethod === "email") {
|
|
13309
13939
|
await handleEmailAuth();
|
|
13940
|
+
invalidateVersioningModeCache();
|
|
13310
13941
|
}
|
|
13311
13942
|
}
|
|
13312
13943
|
trackEvent("cli_auth_completed", {
|
|
@@ -13978,8 +14609,8 @@ init_compile_constants();
|
|
|
13978
14609
|
init_artifact_loader();
|
|
13979
14610
|
init_backup_api_service();
|
|
13980
14611
|
init_constants();
|
|
13981
|
-
import
|
|
13982
|
-
import
|
|
14612
|
+
import fs13 from "fs";
|
|
14613
|
+
import path12 from "path";
|
|
13983
14614
|
var BACKUP_CACHE_FILENAME = "backup-manifest.json";
|
|
13984
14615
|
function calculateProjectHash(projectFiles) {
|
|
13985
14616
|
return combineFileHashes(projectFiles);
|
|
@@ -13992,11 +14623,11 @@ function getCurrentProjectHash(projectPath = process.cwd()) {
|
|
|
13992
14623
|
}
|
|
13993
14624
|
__name(getCurrentProjectHash, "getCurrentProjectHash");
|
|
13994
14625
|
function loadSourceByHash(hash, relativePath, projectPath = process.cwd()) {
|
|
13995
|
-
const sourcesDir =
|
|
13996
|
-
const ext =
|
|
13997
|
-
const sourcePath =
|
|
13998
|
-
if (
|
|
13999
|
-
return
|
|
14626
|
+
const sourcesDir = path12.join(projectPath, COMPILE_DIRS.DIST_V2, "sources");
|
|
14627
|
+
const ext = path12.extname(relativePath) || ".txt";
|
|
14628
|
+
const sourcePath = path12.join(sourcesDir, `${hash}${ext}`);
|
|
14629
|
+
if (fs13.existsSync(sourcePath)) {
|
|
14630
|
+
return fs13.readFileSync(sourcePath, "utf-8");
|
|
14000
14631
|
}
|
|
14001
14632
|
return null;
|
|
14002
14633
|
}
|
|
@@ -14015,30 +14646,30 @@ function prepareFileRefs(projectPath = process.cwd()) {
|
|
|
14015
14646
|
}
|
|
14016
14647
|
__name(prepareFileRefs, "prepareFileRefs");
|
|
14017
14648
|
function reconcileManifestWithDisk(projectPath = process.cwd()) {
|
|
14018
|
-
const manifestPath =
|
|
14019
|
-
if (!
|
|
14649
|
+
const manifestPath = path12.join(projectPath, COMPILE_DIRS.DIST_V2, "manifest.json");
|
|
14650
|
+
if (!fs13.existsSync(manifestPath)) return;
|
|
14020
14651
|
const manifest = loadManifest(projectPath);
|
|
14021
|
-
const sourcesDir =
|
|
14022
|
-
|
|
14652
|
+
const sourcesDir = path12.join(projectPath, COMPILE_DIRS.DIST_V2, "sources");
|
|
14653
|
+
fs13.mkdirSync(sourcesDir, {
|
|
14023
14654
|
recursive: true
|
|
14024
14655
|
});
|
|
14025
14656
|
let changed = false;
|
|
14026
14657
|
for (const file of manifest.projectFiles) {
|
|
14027
14658
|
if (file.external) continue;
|
|
14028
|
-
const absPath =
|
|
14029
|
-
if (!
|
|
14659
|
+
const absPath = path12.join(projectPath, file.relativePath);
|
|
14660
|
+
if (!fs13.existsSync(absPath)) continue;
|
|
14030
14661
|
let content;
|
|
14031
14662
|
try {
|
|
14032
|
-
content =
|
|
14663
|
+
content = fs13.readFileSync(absPath, "utf-8");
|
|
14033
14664
|
} catch {
|
|
14034
14665
|
continue;
|
|
14035
14666
|
}
|
|
14036
14667
|
const freshHash = hashContent(content);
|
|
14037
14668
|
if (freshHash === file.hash) continue;
|
|
14038
|
-
const ext =
|
|
14039
|
-
const sourceTargetPath =
|
|
14669
|
+
const ext = path12.extname(file.relativePath) || ".txt";
|
|
14670
|
+
const sourceTargetPath = path12.join(sourcesDir, `${freshHash}${ext}`);
|
|
14040
14671
|
try {
|
|
14041
|
-
|
|
14672
|
+
fs13.writeFileSync(sourceTargetPath, content, "utf-8");
|
|
14042
14673
|
} catch {
|
|
14043
14674
|
continue;
|
|
14044
14675
|
}
|
|
@@ -14047,7 +14678,7 @@ function reconcileManifestWithDisk(projectPath = process.cwd()) {
|
|
|
14047
14678
|
changed = true;
|
|
14048
14679
|
}
|
|
14049
14680
|
if (changed) {
|
|
14050
|
-
|
|
14681
|
+
fs13.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
14051
14682
|
}
|
|
14052
14683
|
}
|
|
14053
14684
|
__name(reconcileManifestWithDisk, "reconcileManifestWithDisk");
|
|
@@ -14120,7 +14751,7 @@ function checkRestoreConflicts(manifest, targetDir) {
|
|
|
14120
14751
|
const existingFiles = [];
|
|
14121
14752
|
for (const file of manifest.files) {
|
|
14122
14753
|
const filePath = resolveBackupFileTarget2(file, targetDir);
|
|
14123
|
-
if (
|
|
14754
|
+
if (fs13.existsSync(filePath)) {
|
|
14124
14755
|
existingFiles.push(file.relativePath);
|
|
14125
14756
|
} else {
|
|
14126
14757
|
newFiles.push(file.relativePath);
|
|
@@ -14146,16 +14777,16 @@ function createBackupTracking(projectHash) {
|
|
|
14146
14777
|
}
|
|
14147
14778
|
__name(createBackupTracking, "createBackupTracking");
|
|
14148
14779
|
function getBackupCachePath(projectPath = process.cwd()) {
|
|
14149
|
-
return
|
|
14780
|
+
return path12.join(projectPath, ".lua", BACKUP_CACHE_FILENAME);
|
|
14150
14781
|
}
|
|
14151
14782
|
__name(getBackupCachePath, "getBackupCachePath");
|
|
14152
14783
|
function writeBackupManifestCache(cache, projectPath = process.cwd()) {
|
|
14153
14784
|
const cachePath = getBackupCachePath(projectPath);
|
|
14154
14785
|
try {
|
|
14155
|
-
|
|
14786
|
+
fs13.mkdirSync(path12.dirname(cachePath), {
|
|
14156
14787
|
recursive: true
|
|
14157
14788
|
});
|
|
14158
|
-
|
|
14789
|
+
fs13.writeFileSync(cachePath, JSON.stringify(cache, null, 2), "utf-8");
|
|
14159
14790
|
} catch (error) {
|
|
14160
14791
|
const message = error instanceof Error ? error.message : String(error);
|
|
14161
14792
|
console.warn(`Could not write backup manifest cache: ${message}`);
|
|
@@ -14164,9 +14795,9 @@ function writeBackupManifestCache(cache, projectPath = process.cwd()) {
|
|
|
14164
14795
|
__name(writeBackupManifestCache, "writeBackupManifestCache");
|
|
14165
14796
|
function readBackupManifestCache(projectPath = process.cwd()) {
|
|
14166
14797
|
const cachePath = getBackupCachePath(projectPath);
|
|
14167
|
-
if (!
|
|
14798
|
+
if (!fs13.existsSync(cachePath)) return null;
|
|
14168
14799
|
try {
|
|
14169
|
-
const raw =
|
|
14800
|
+
const raw = fs13.readFileSync(cachePath, "utf-8");
|
|
14170
14801
|
const parsed = JSON.parse(raw);
|
|
14171
14802
|
if (typeof parsed.lastHash !== "string" || typeof parsed.lastPushedAt !== "string" || !Array.isArray(parsed.files) || !parsed.files.every((f) => f && typeof f.relativePath === "string" && typeof f.hash === "string")) {
|
|
14172
14803
|
return null;
|
|
@@ -14193,18 +14824,18 @@ function detectLocalConflictsForPull(incomingFiles, projectPath = process.cwd())
|
|
|
14193
14824
|
f.hash
|
|
14194
14825
|
]));
|
|
14195
14826
|
const conflicts = /* @__PURE__ */ new Set();
|
|
14196
|
-
const projectRoot =
|
|
14827
|
+
const projectRoot = path12.resolve(projectPath);
|
|
14197
14828
|
for (const incoming of incomingFiles) {
|
|
14198
14829
|
if (COMPILE_MANAGED_FILES.has(incoming.relativePath)) continue;
|
|
14199
14830
|
if (incoming.external) continue;
|
|
14200
|
-
const absPath =
|
|
14201
|
-
if (absPath !== projectRoot && !absPath.startsWith(projectRoot +
|
|
14831
|
+
const absPath = path12.resolve(projectRoot, incoming.relativePath);
|
|
14832
|
+
if (absPath !== projectRoot && !absPath.startsWith(projectRoot + path12.sep)) {
|
|
14202
14833
|
continue;
|
|
14203
14834
|
}
|
|
14204
|
-
if (!
|
|
14835
|
+
if (!fs13.existsSync(absPath)) continue;
|
|
14205
14836
|
let diskHash;
|
|
14206
14837
|
try {
|
|
14207
|
-
const bytes =
|
|
14838
|
+
const bytes = fs13.readFileSync(absPath, "utf-8");
|
|
14208
14839
|
diskHash = hashContent(bytes);
|
|
14209
14840
|
} catch {
|
|
14210
14841
|
conflicts.add(incoming.relativePath);
|
|
@@ -14231,7 +14862,7 @@ function detectLocalConflictsForPull(incomingFiles, projectPath = process.cwd())
|
|
|
14231
14862
|
__name(detectLocalConflictsForPull, "detectLocalConflictsForPull");
|
|
14232
14863
|
async function fetchBackupManifestForPull(apiKey, agentId) {
|
|
14233
14864
|
try {
|
|
14234
|
-
const backupApi = new
|
|
14865
|
+
const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
14235
14866
|
const response = await backupApi.getBackupManifest();
|
|
14236
14867
|
return {
|
|
14237
14868
|
fetched: response.data ?? null
|
|
@@ -14262,7 +14893,7 @@ __name(decideBackupFreshness, "decideBackupFreshness");
|
|
|
14262
14893
|
async function checkServerBackupNewerThanLocal(apiKey, agentId, projectPath = process.cwd()) {
|
|
14263
14894
|
const local = readBackupManifestCache(projectPath);
|
|
14264
14895
|
try {
|
|
14265
|
-
const api = new
|
|
14896
|
+
const api = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
14266
14897
|
const resp = await api.getBackupMetadata();
|
|
14267
14898
|
const metadata = resp.success && resp.data ? {
|
|
14268
14899
|
projectHash: resp.data.projectHash
|
|
@@ -14275,7 +14906,7 @@ async function checkServerBackupNewerThanLocal(apiKey, agentId, projectPath = pr
|
|
|
14275
14906
|
__name(checkServerBackupNewerThanLocal, "checkServerBackupNewerThanLocal");
|
|
14276
14907
|
async function checkBackupAvailability(apiKey, agentId) {
|
|
14277
14908
|
try {
|
|
14278
|
-
const backupApi = new
|
|
14909
|
+
const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
14279
14910
|
const metadata = await backupApi.getBackupMetadata();
|
|
14280
14911
|
if (metadata.data && metadata.data.fileCount > 0) {
|
|
14281
14912
|
return {
|
|
@@ -14297,7 +14928,7 @@ __name(checkBackupAvailability, "checkBackupAvailability");
|
|
|
14297
14928
|
async function restoreFromBackupForSync(apiKey, agentId, expectedPrimitives = [], projectPath, preFetchedManifest) {
|
|
14298
14929
|
const targetDir = projectPath || process.cwd();
|
|
14299
14930
|
try {
|
|
14300
|
-
const backupApi = new
|
|
14931
|
+
const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
14301
14932
|
const manifest = preFetchedManifest ?? (await backupApi.getBackupManifest()).data ?? null;
|
|
14302
14933
|
if (!manifest || !manifest.files?.length) {
|
|
14303
14934
|
return {
|
|
@@ -14383,17 +15014,17 @@ function writeBackupFilesWithByteCompare(manifest, blobs, targetDir) {
|
|
|
14383
15014
|
}
|
|
14384
15015
|
restoredContents.set(makeRestoredContentsKey(file), content);
|
|
14385
15016
|
const filePath = resolveBackupFileTarget2(file, targetDir);
|
|
14386
|
-
if (
|
|
14387
|
-
const existing =
|
|
15017
|
+
if (fs13.existsSync(filePath)) {
|
|
15018
|
+
const existing = fs13.readFileSync(filePath);
|
|
14388
15019
|
if (existing.equals(content)) {
|
|
14389
15020
|
filesUnchanged++;
|
|
14390
15021
|
continue;
|
|
14391
15022
|
}
|
|
14392
15023
|
}
|
|
14393
|
-
|
|
15024
|
+
fs13.mkdirSync(path12.dirname(filePath), {
|
|
14394
15025
|
recursive: true
|
|
14395
15026
|
});
|
|
14396
|
-
|
|
15027
|
+
fs13.writeFileSync(filePath, content);
|
|
14397
15028
|
filesWritten++;
|
|
14398
15029
|
}
|
|
14399
15030
|
return {
|
|
@@ -16119,7 +16750,7 @@ async function checkAndRestoreBackup(apiKey, agentId, options) {
|
|
|
16119
16750
|
if (!confirm) return false;
|
|
16120
16751
|
}
|
|
16121
16752
|
try {
|
|
16122
|
-
const backupApi = new
|
|
16753
|
+
const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
|
|
16123
16754
|
const urlsResponse = await backupApi.getBlobUrls(manifest.files.map((f) => f.hash));
|
|
16124
16755
|
if (!urlsResponse.success || !urlsResponse.data) {
|
|
16125
16756
|
writeError(`Failed to fetch download URLs: ${urlsResponse.error?.message ?? "unknown error"}`);
|
|
@@ -16173,6 +16804,7 @@ async function destroyCommand(options) {
|
|
|
16173
16804
|
if (options?.force) {
|
|
16174
16805
|
const deleted2 = deleteApiKey();
|
|
16175
16806
|
if (deleted2) {
|
|
16807
|
+
invalidateVersioningModeCache();
|
|
16176
16808
|
writeSuccess("\u2705 API key deleted successfully.");
|
|
16177
16809
|
} else {
|
|
16178
16810
|
writeProgress("\u274C Failed to delete API key.");
|
|
@@ -16198,6 +16830,7 @@ async function destroyCommand(options) {
|
|
|
16198
16830
|
if (confirm) {
|
|
16199
16831
|
deleted = deleteApiKey();
|
|
16200
16832
|
if (deleted) {
|
|
16833
|
+
invalidateVersioningModeCache();
|
|
16201
16834
|
writeSuccess("\u2705 API key deleted successfully.");
|
|
16202
16835
|
} else {
|
|
16203
16836
|
writeProgress("\u274C Failed to delete API key.");
|
|
@@ -16268,13 +16901,13 @@ __name(apiKeyCommand, "apiKeyCommand");
|
|
|
16268
16901
|
init_cli();
|
|
16269
16902
|
init_files();
|
|
16270
16903
|
init_auth();
|
|
16271
|
-
import
|
|
16904
|
+
import path14 from "path";
|
|
16272
16905
|
|
|
16273
16906
|
// src/commands/sync.ts
|
|
16274
16907
|
init_dist();
|
|
16275
16908
|
init_cli();
|
|
16276
|
-
import
|
|
16277
|
-
import
|
|
16909
|
+
import fs14 from "fs";
|
|
16910
|
+
import path13 from "path";
|
|
16278
16911
|
|
|
16279
16912
|
// src/utils/prompt-handler.ts
|
|
16280
16913
|
init_cli();
|
|
@@ -16485,8 +17118,8 @@ init_mcp_server_handler();
|
|
|
16485
17118
|
async function syncCommand(options) {
|
|
16486
17119
|
return withErrorHandling(async () => {
|
|
16487
17120
|
const preCompileYaml = readYamlConfig();
|
|
16488
|
-
const yamlPath =
|
|
16489
|
-
const preCompileYamlBytes =
|
|
17121
|
+
const yamlPath = path13.resolve(process.cwd(), "lua.skill.yaml");
|
|
17122
|
+
const preCompileYamlBytes = fs14.existsSync(yamlPath) ? fs14.readFileSync(yamlPath, "utf-8") : null;
|
|
16490
17123
|
let syncCompletedSuccessfully = false;
|
|
16491
17124
|
try {
|
|
16492
17125
|
writeProgress("\u{1F504} Compiling to get latest local state...");
|
|
@@ -16547,7 +17180,7 @@ async function syncCommand(options) {
|
|
|
16547
17180
|
} finally {
|
|
16548
17181
|
if (!syncCompletedSuccessfully && preCompileYamlBytes !== null) {
|
|
16549
17182
|
try {
|
|
16550
|
-
|
|
17183
|
+
fs14.writeFileSync(yamlPath, preCompileYamlBytes, "utf-8");
|
|
16551
17184
|
} catch {
|
|
16552
17185
|
}
|
|
16553
17186
|
}
|
|
@@ -18104,7 +18737,7 @@ async function compileCommand(options) {
|
|
|
18104
18737
|
}
|
|
18105
18738
|
writeProgress("\u{1F528} Compiling...");
|
|
18106
18739
|
const rootDir = process.cwd();
|
|
18107
|
-
const outDir =
|
|
18740
|
+
const outDir = path14.join(rootDir, "dist-v2");
|
|
18108
18741
|
const result = await compile({
|
|
18109
18742
|
rootDir,
|
|
18110
18743
|
outDir,
|
|
@@ -18267,17 +18900,18 @@ init_cli();
|
|
|
18267
18900
|
init_command_utils();
|
|
18268
18901
|
|
|
18269
18902
|
// src/utils/sandbox.ts
|
|
18270
|
-
import
|
|
18271
|
-
import
|
|
18903
|
+
import vm3 from "vm";
|
|
18904
|
+
import path17 from "path";
|
|
18272
18905
|
|
|
18273
18906
|
// ../shared-sandbox/dist/index.mjs
|
|
18274
18907
|
import vm from "vm";
|
|
18275
18908
|
import { createRequire } from "module";
|
|
18276
|
-
import
|
|
18909
|
+
import path15 from "path";
|
|
18277
18910
|
import dns from "dns";
|
|
18278
18911
|
import net from "net";
|
|
18279
18912
|
import { promisify } from "util";
|
|
18280
18913
|
import { Agent as UndiciAgent } from "undici";
|
|
18914
|
+
import vm2 from "vm";
|
|
18281
18915
|
var __defProp4 = Object.defineProperty;
|
|
18282
18916
|
var __name4 = /* @__PURE__ */ __name((target, value) => __defProp4(target, "name", { value, configurable: true }), "__name");
|
|
18283
18917
|
function buildSandboxProcess(opts) {
|
|
@@ -18442,7 +19076,7 @@ var REQUIRE_BLOCKLIST = /* @__PURE__ */ new Set([
|
|
|
18442
19076
|
var SANDBOX_FAKE_DIRNAME = "/";
|
|
18443
19077
|
var SANDBOX_FAKE_FILENAME = "/index.ts";
|
|
18444
19078
|
function buildSandboxRequire(opts) {
|
|
18445
|
-
const realRequire = createRequire(
|
|
19079
|
+
const realRequire = createRequire(path15.join(opts.cwd, "package.json"));
|
|
18446
19080
|
const wrapped = /* @__PURE__ */ __name4((id) => {
|
|
18447
19081
|
if (REQUIRE_BLOCKLIST.has(id)) {
|
|
18448
19082
|
const evt = {
|
|
@@ -19088,16 +19722,38 @@ function applyGlobalSelfReference(context) {
|
|
|
19088
19722
|
}
|
|
19089
19723
|
__name(applyGlobalSelfReference, "applyGlobalSelfReference");
|
|
19090
19724
|
__name4(applyGlobalSelfReference, "applyGlobalSelfReference");
|
|
19725
|
+
function resolveExtraAllowedCidrs() {
|
|
19726
|
+
const csv = process.env.LUA_ALLOWED_EGRESS_CIDRS;
|
|
19727
|
+
if (!csv) return [];
|
|
19728
|
+
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
19729
|
+
}
|
|
19730
|
+
__name(resolveExtraAllowedCidrs, "resolveExtraAllowedCidrs");
|
|
19731
|
+
__name4(resolveExtraAllowedCidrs, "resolveExtraAllowedCidrs");
|
|
19732
|
+
function wrapBundleAsCjsModule(source) {
|
|
19733
|
+
return "(function(module, exports, require) {\n" + source + "\n})(module, module.exports, require);";
|
|
19734
|
+
}
|
|
19735
|
+
__name(wrapBundleAsCjsModule, "wrapBundleAsCjsModule");
|
|
19736
|
+
__name4(wrapBundleAsCjsModule, "wrapBundleAsCjsModule");
|
|
19737
|
+
function runBundleInContext(context, source, options) {
|
|
19738
|
+
const wrapped = wrapBundleAsCjsModule(source);
|
|
19739
|
+
vm2.runInContext(wrapped, context, {
|
|
19740
|
+
filename: options.filename,
|
|
19741
|
+
timeout: options.timeoutMs ?? 1e3,
|
|
19742
|
+
lineOffset: -1
|
|
19743
|
+
});
|
|
19744
|
+
}
|
|
19745
|
+
__name(runBundleInContext, "runBundleInContext");
|
|
19746
|
+
__name4(runBundleInContext, "runBundleInContext");
|
|
19091
19747
|
|
|
19092
19748
|
// src/utils/env-loader.utils.ts
|
|
19093
|
-
import
|
|
19094
|
-
import
|
|
19749
|
+
import path16 from "path";
|
|
19750
|
+
import fs15 from "fs";
|
|
19095
19751
|
function parseEnvFile(filePath) {
|
|
19096
|
-
if (!
|
|
19752
|
+
if (!fs15.existsSync(filePath)) {
|
|
19097
19753
|
return {};
|
|
19098
19754
|
}
|
|
19099
19755
|
try {
|
|
19100
|
-
const content =
|
|
19756
|
+
const content = fs15.readFileSync(filePath, "utf8");
|
|
19101
19757
|
if (!content.trim()) return {};
|
|
19102
19758
|
const envVars = {};
|
|
19103
19759
|
content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).forEach((line) => {
|
|
@@ -19123,7 +19779,7 @@ async function loadEnvironmentVariables(context) {
|
|
|
19123
19779
|
}
|
|
19124
19780
|
__name(loadEnvironmentVariables, "loadEnvironmentVariables");
|
|
19125
19781
|
function loadSandboxEnvVariables() {
|
|
19126
|
-
const envFilePath =
|
|
19782
|
+
const envFilePath = path16.join(process.cwd(), ".env");
|
|
19127
19783
|
const envMap = parseEnvFile(envFilePath);
|
|
19128
19784
|
return Object.entries(envMap).map(([key, value]) => ({
|
|
19129
19785
|
key,
|
|
@@ -19200,12 +19856,12 @@ function resolveEgressMode() {
|
|
|
19200
19856
|
return "off";
|
|
19201
19857
|
}
|
|
19202
19858
|
__name(resolveEgressMode, "resolveEgressMode");
|
|
19203
|
-
function
|
|
19859
|
+
function resolveExtraAllowedCidrs2() {
|
|
19204
19860
|
const csv = process.env.LUA_ALLOWED_EGRESS_CIDRS;
|
|
19205
19861
|
if (!csv) return [];
|
|
19206
19862
|
return csv.split(",").map((s) => s.trim()).filter(Boolean);
|
|
19207
19863
|
}
|
|
19208
|
-
__name(
|
|
19864
|
+
__name(resolveExtraAllowedCidrs2, "resolveExtraAllowedCidrs");
|
|
19209
19865
|
function defaultSecurityEventLogger(evt) {
|
|
19210
19866
|
console.warn("[sandbox]", JSON.stringify(evt));
|
|
19211
19867
|
}
|
|
@@ -19218,7 +19874,7 @@ function loadEnvironmentVariables2() {
|
|
|
19218
19874
|
envVars[key] = value;
|
|
19219
19875
|
}
|
|
19220
19876
|
}
|
|
19221
|
-
const envFilePath =
|
|
19877
|
+
const envFilePath = path17.join(process.cwd(), ".env");
|
|
19222
19878
|
const fileEnvVars = parseEnvFile(envFilePath);
|
|
19223
19879
|
Object.assign(envVars, fileEnvVars);
|
|
19224
19880
|
return envVars;
|
|
@@ -19353,7 +20009,7 @@ function createSandbox(options) {
|
|
|
19353
20009
|
extraGlobals,
|
|
19354
20010
|
requireMode: resolveRequireMode(),
|
|
19355
20011
|
egressMode: resolveEgressMode(),
|
|
19356
|
-
egressExtraAllowedCidrs:
|
|
20012
|
+
egressExtraAllowedCidrs: resolveExtraAllowedCidrs2(),
|
|
19357
20013
|
onSecurityEvent: defaultSecurityEventLogger
|
|
19358
20014
|
});
|
|
19359
20015
|
}
|
|
@@ -19361,11 +20017,14 @@ __name(createSandbox, "createSandbox");
|
|
|
19361
20017
|
async function executeTool(options) {
|
|
19362
20018
|
const { toolCode, inputs } = options;
|
|
19363
20019
|
const sandbox = createSandbox(options);
|
|
19364
|
-
const context =
|
|
20020
|
+
const context = vm3.createContext(sandbox);
|
|
19365
20021
|
applyGlobalSelfReference(context);
|
|
19366
20022
|
const isBundledArtifact = toolCode.includes("__lua_primitive__");
|
|
19367
20023
|
if (isBundledArtifact) {
|
|
19368
|
-
|
|
20024
|
+
runBundleInContext(context, toolCode, {
|
|
20025
|
+
filename: "tool.bundle.js",
|
|
20026
|
+
timeoutMs: 18e4
|
|
20027
|
+
});
|
|
19369
20028
|
const moduleExports = context.module.exports;
|
|
19370
20029
|
const primitive = moduleExports.default?.primitive || moduleExports.primitive;
|
|
19371
20030
|
if (!primitive || !primitive.execute) {
|
|
@@ -19393,7 +20052,7 @@ module.exports = async (input) => {
|
|
|
19393
20052
|
}
|
|
19394
20053
|
};
|
|
19395
20054
|
`;
|
|
19396
|
-
|
|
20055
|
+
vm3.runInContext(commonJsWrapper, context);
|
|
19397
20056
|
const executeFunction = context.module.exports;
|
|
19398
20057
|
return await executeFunction(inputs);
|
|
19399
20058
|
}
|
|
@@ -19402,7 +20061,7 @@ __name(executeTool, "executeTool");
|
|
|
19402
20061
|
async function executeWebhook(options) {
|
|
19403
20062
|
const { webhookCode, query, headers, body } = options;
|
|
19404
20063
|
const sandbox = createSandbox(options);
|
|
19405
|
-
const context =
|
|
20064
|
+
const context = vm3.createContext(sandbox);
|
|
19406
20065
|
applyGlobalSelfReference(context);
|
|
19407
20066
|
const event = {
|
|
19408
20067
|
query: query ?? {},
|
|
@@ -19412,7 +20071,10 @@ async function executeWebhook(options) {
|
|
|
19412
20071
|
};
|
|
19413
20072
|
const isBundledArtifact = webhookCode.includes("__lua_primitive__");
|
|
19414
20073
|
if (isBundledArtifact) {
|
|
19415
|
-
|
|
20074
|
+
runBundleInContext(context, webhookCode, {
|
|
20075
|
+
filename: "webhook.bundle.js",
|
|
20076
|
+
timeoutMs: 18e4
|
|
20077
|
+
});
|
|
19416
20078
|
const moduleExports = context.module.exports;
|
|
19417
20079
|
const primitive = moduleExports.default?.primitive || moduleExports.primitive;
|
|
19418
20080
|
if (!primitive || !primitive.execute) {
|
|
@@ -19440,7 +20102,7 @@ module.exports = async (event) => {
|
|
|
19440
20102
|
}
|
|
19441
20103
|
};
|
|
19442
20104
|
`;
|
|
19443
|
-
|
|
20105
|
+
vm3.runInContext(commonJsWrapper, context);
|
|
19444
20106
|
const executeFunction = context.module.exports;
|
|
19445
20107
|
return await executeFunction(event);
|
|
19446
20108
|
}
|
|
@@ -19449,7 +20111,7 @@ __name(executeWebhook, "executeWebhook");
|
|
|
19449
20111
|
async function executeJob(options) {
|
|
19450
20112
|
const { jobCode, jobData, apiKey, agentId } = options;
|
|
19451
20113
|
const sandbox = createSandbox(options);
|
|
19452
|
-
const context =
|
|
20114
|
+
const context = vm3.createContext(sandbox);
|
|
19453
20115
|
applyGlobalSelfReference(context);
|
|
19454
20116
|
let jobInstance = void 0;
|
|
19455
20117
|
if (jobData) {
|
|
@@ -19475,7 +20137,10 @@ async function executeJob(options) {
|
|
|
19475
20137
|
}
|
|
19476
20138
|
const isBundledArtifact = jobCode.includes("__lua_primitive__");
|
|
19477
20139
|
if (isBundledArtifact) {
|
|
19478
|
-
|
|
20140
|
+
runBundleInContext(context, jobCode, {
|
|
20141
|
+
filename: "job.bundle.js",
|
|
20142
|
+
timeoutMs: 18e4
|
|
20143
|
+
});
|
|
19479
20144
|
const moduleExports = context.module.exports;
|
|
19480
20145
|
const primitive = moduleExports.default?.primitive || moduleExports.primitive;
|
|
19481
20146
|
if (!primitive || !primitive.execute) {
|
|
@@ -19503,7 +20168,7 @@ module.exports = async (job) => {
|
|
|
19503
20168
|
}
|
|
19504
20169
|
};
|
|
19505
20170
|
`;
|
|
19506
|
-
|
|
20171
|
+
vm3.runInContext(commonJsWrapper, context);
|
|
19507
20172
|
const executeFunction = context.module.exports;
|
|
19508
20173
|
return await executeFunction(jobInstance);
|
|
19509
20174
|
}
|
|
@@ -19515,11 +20180,14 @@ async function executePreProcessor(options) {
|
|
|
19515
20180
|
const UserDataApi2 = (await Promise.resolve().then(() => (init_user_data_api_service(), user_data_api_service_exports))).default;
|
|
19516
20181
|
const userService = new UserDataApi2(BASE_URLS.API, apiKey, agentId);
|
|
19517
20182
|
const userInstance = await userService.get();
|
|
19518
|
-
const context =
|
|
20183
|
+
const context = vm3.createContext(sandbox);
|
|
19519
20184
|
applyGlobalSelfReference(context);
|
|
19520
20185
|
const isBundledArtifact = processorCode.includes("__lua_primitive__");
|
|
19521
20186
|
if (isBundledArtifact) {
|
|
19522
|
-
|
|
20187
|
+
runBundleInContext(context, processorCode, {
|
|
20188
|
+
filename: "preprocessor.bundle.js",
|
|
20189
|
+
timeoutMs: 18e4
|
|
20190
|
+
});
|
|
19523
20191
|
const moduleExports = context.module.exports;
|
|
19524
20192
|
const primitive = moduleExports.default?.primitive || moduleExports.primitive;
|
|
19525
20193
|
if (!primitive || !primitive.execute) {
|
|
@@ -19547,7 +20215,7 @@ module.exports = async (input) => {
|
|
|
19547
20215
|
}
|
|
19548
20216
|
};
|
|
19549
20217
|
`;
|
|
19550
|
-
|
|
20218
|
+
vm3.runInContext(commonJsWrapper, context);
|
|
19551
20219
|
const executeFunction = context.module.exports;
|
|
19552
20220
|
return await executeFunction({
|
|
19553
20221
|
user: userInstance,
|
|
@@ -19563,11 +20231,14 @@ async function executePostProcessor(options) {
|
|
|
19563
20231
|
const UserDataApi2 = (await Promise.resolve().then(() => (init_user_data_api_service(), user_data_api_service_exports))).default;
|
|
19564
20232
|
const userService = new UserDataApi2(BASE_URLS.API, apiKey, agentId);
|
|
19565
20233
|
const userInstance = await userService.get();
|
|
19566
|
-
const context =
|
|
20234
|
+
const context = vm3.createContext(sandbox);
|
|
19567
20235
|
applyGlobalSelfReference(context);
|
|
19568
20236
|
const isBundledArtifact = processorCode.includes("__lua_primitive__");
|
|
19569
20237
|
if (isBundledArtifact) {
|
|
19570
|
-
|
|
20238
|
+
runBundleInContext(context, processorCode, {
|
|
20239
|
+
filename: "postprocessor.bundle.js",
|
|
20240
|
+
timeoutMs: 18e4
|
|
20241
|
+
});
|
|
19571
20242
|
const moduleExports = context.module.exports;
|
|
19572
20243
|
const primitive = moduleExports.default?.primitive || moduleExports.primitive;
|
|
19573
20244
|
if (!primitive || !primitive.execute) {
|
|
@@ -19592,7 +20263,7 @@ module.exports = async (input) => {
|
|
|
19592
20263
|
}
|
|
19593
20264
|
};
|
|
19594
20265
|
`;
|
|
19595
|
-
|
|
20266
|
+
vm3.runInContext(commonJsWrapper, context);
|
|
19596
20267
|
const executeFunction = context.module.exports;
|
|
19597
20268
|
return await executeFunction({
|
|
19598
20269
|
user: userInstance,
|
|
@@ -21089,6 +21760,7 @@ init_dist();
|
|
|
21089
21760
|
init_files();
|
|
21090
21761
|
init_cli();
|
|
21091
21762
|
init_command_utils();
|
|
21763
|
+
init_auth();
|
|
21092
21764
|
init_semver();
|
|
21093
21765
|
init_auth_error();
|
|
21094
21766
|
init_constants();
|
|
@@ -21155,7 +21827,7 @@ async function runBackupPush(opts) {
|
|
|
21155
21827
|
projectHash: manifestProjectHash
|
|
21156
21828
|
};
|
|
21157
21829
|
}
|
|
21158
|
-
const backupApi = new
|
|
21830
|
+
const backupApi = new backup_api_service_default(BASE_URLS.API, opts.apiKey, opts.agentId);
|
|
21159
21831
|
const allHashes = opts.fresh ? [
|
|
21160
21832
|
...new Set(fileRefs.map((f) => f.hash))
|
|
21161
21833
|
] : getAllFileHashes(projectPath);
|
|
@@ -21216,8 +21888,8 @@ async function runBackupPush(opts) {
|
|
|
21216
21888
|
}
|
|
21217
21889
|
__name(runBackupPush, "runBackupPush");
|
|
21218
21890
|
async function uploadBlobsFromDisk(uploadUrls, files, projectPath, concurrency = 10) {
|
|
21219
|
-
const
|
|
21220
|
-
const
|
|
21891
|
+
const fs17 = await import("fs");
|
|
21892
|
+
const path19 = await import("path");
|
|
21221
21893
|
const zlib2 = await import("zlib");
|
|
21222
21894
|
const hashToPath = /* @__PURE__ */ new Map();
|
|
21223
21895
|
for (const f of files) {
|
|
@@ -21231,8 +21903,8 @@ async function uploadBlobsFromDisk(uploadUrls, files, projectPath, concurrency =
|
|
|
21231
21903
|
if (!rel) {
|
|
21232
21904
|
throw new Error(`No file found for hash: ${hash}`);
|
|
21233
21905
|
}
|
|
21234
|
-
const abs =
|
|
21235
|
-
const content =
|
|
21906
|
+
const abs = path19.join(projectPath, rel);
|
|
21907
|
+
const content = fs17.readFileSync(abs);
|
|
21236
21908
|
const compressed = zlib2.gzipSync(content);
|
|
21237
21909
|
const response = await fetch(uploadUrls[hash], {
|
|
21238
21910
|
method: "PUT",
|
|
@@ -21323,6 +21995,262 @@ init_analytics();
|
|
|
21323
21995
|
init_dist2();
|
|
21324
21996
|
init_skills_api_service();
|
|
21325
21997
|
|
|
21998
|
+
// src/utils/try-git-commit.ts
|
|
21999
|
+
init_cli();
|
|
22000
|
+
init_files();
|
|
22001
|
+
|
|
22002
|
+
// src/utils/git.ts
|
|
22003
|
+
import { spawn } from "child_process";
|
|
22004
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
22005
|
+
async function runGit(args2, opts = {}) {
|
|
22006
|
+
return new Promise((resolve6, reject) => {
|
|
22007
|
+
const child = spawn("git", args2, {
|
|
22008
|
+
cwd: opts.cwd,
|
|
22009
|
+
shell: false,
|
|
22010
|
+
stdio: [
|
|
22011
|
+
"ignore",
|
|
22012
|
+
"pipe",
|
|
22013
|
+
"pipe"
|
|
22014
|
+
]
|
|
22015
|
+
});
|
|
22016
|
+
let stdout = "";
|
|
22017
|
+
let stderr = "";
|
|
22018
|
+
let settled = false;
|
|
22019
|
+
const timer = setTimeout(() => {
|
|
22020
|
+
settled = true;
|
|
22021
|
+
child.kill("SIGKILL");
|
|
22022
|
+
reject(new Error(`git ${args2.join(" ")} timed out after ${opts.timeout ?? DEFAULT_TIMEOUT_MS}ms`));
|
|
22023
|
+
}, opts.timeout ?? DEFAULT_TIMEOUT_MS);
|
|
22024
|
+
child.stdout?.on("data", (chunk) => {
|
|
22025
|
+
stdout += chunk.toString();
|
|
22026
|
+
});
|
|
22027
|
+
child.stdout?.on("error", (err) => {
|
|
22028
|
+
if (settled) return;
|
|
22029
|
+
settled = true;
|
|
22030
|
+
clearTimeout(timer);
|
|
22031
|
+
reject(err);
|
|
22032
|
+
});
|
|
22033
|
+
child.stderr?.on("data", (chunk) => {
|
|
22034
|
+
stderr += chunk.toString();
|
|
22035
|
+
});
|
|
22036
|
+
child.stderr?.on("error", () => {
|
|
22037
|
+
});
|
|
22038
|
+
child.on("error", (err) => {
|
|
22039
|
+
if (settled) return;
|
|
22040
|
+
settled = true;
|
|
22041
|
+
clearTimeout(timer);
|
|
22042
|
+
reject(err);
|
|
22043
|
+
});
|
|
22044
|
+
child.on("close", (code) => {
|
|
22045
|
+
if (settled) return;
|
|
22046
|
+
settled = true;
|
|
22047
|
+
clearTimeout(timer);
|
|
22048
|
+
resolve6({
|
|
22049
|
+
stdout,
|
|
22050
|
+
stderr,
|
|
22051
|
+
code: code ?? 0
|
|
22052
|
+
});
|
|
22053
|
+
});
|
|
22054
|
+
});
|
|
22055
|
+
}
|
|
22056
|
+
__name(runGit, "runGit");
|
|
22057
|
+
function classifyGitError(err, stderr = "") {
|
|
22058
|
+
if (err && typeof err === "object" && "code" in err && err.code === "ENOENT") {
|
|
22059
|
+
return "no-git";
|
|
22060
|
+
}
|
|
22061
|
+
const s = stderr.toLowerCase();
|
|
22062
|
+
if (s.includes("not a git repository")) return "no-repo";
|
|
22063
|
+
if (s.includes("head detached") || s.includes("does not point to a branch") || s.includes("src refspec head does not match")) return "detached-head";
|
|
22064
|
+
if (s.includes("pre-commit hook") || s.includes("hook failed")) return "hook-failed";
|
|
22065
|
+
if (s.includes("already exists")) return "tag-exists";
|
|
22066
|
+
if (s.includes("nothing to commit")) return "nothing-to-commit";
|
|
22067
|
+
if (s.includes("authentication failed") || s.includes("could not read username")) return "auth";
|
|
22068
|
+
return "unknown";
|
|
22069
|
+
}
|
|
22070
|
+
__name(classifyGitError, "classifyGitError");
|
|
22071
|
+
async function isGitAvailable() {
|
|
22072
|
+
try {
|
|
22073
|
+
const { code } = await runGit([
|
|
22074
|
+
"--version"
|
|
22075
|
+
]);
|
|
22076
|
+
return code === 0;
|
|
22077
|
+
} catch {
|
|
22078
|
+
return false;
|
|
22079
|
+
}
|
|
22080
|
+
}
|
|
22081
|
+
__name(isGitAvailable, "isGitAvailable");
|
|
22082
|
+
async function isInsideGitRepo(cwd) {
|
|
22083
|
+
try {
|
|
22084
|
+
const { code } = await runGit([
|
|
22085
|
+
"rev-parse",
|
|
22086
|
+
"--is-inside-work-tree"
|
|
22087
|
+
], {
|
|
22088
|
+
cwd
|
|
22089
|
+
});
|
|
22090
|
+
return code === 0;
|
|
22091
|
+
} catch {
|
|
22092
|
+
return false;
|
|
22093
|
+
}
|
|
22094
|
+
}
|
|
22095
|
+
__name(isInsideGitRepo, "isInsideGitRepo");
|
|
22096
|
+
async function gitUserConfigured(cwd) {
|
|
22097
|
+
const readOne = /* @__PURE__ */ __name(async (key) => {
|
|
22098
|
+
try {
|
|
22099
|
+
const { stdout, code } = await runGit([
|
|
22100
|
+
"config",
|
|
22101
|
+
"--get",
|
|
22102
|
+
key
|
|
22103
|
+
], {
|
|
22104
|
+
cwd
|
|
22105
|
+
});
|
|
22106
|
+
if (code !== 0) return void 0;
|
|
22107
|
+
const trimmed = stdout.trim();
|
|
22108
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
22109
|
+
} catch {
|
|
22110
|
+
return void 0;
|
|
22111
|
+
}
|
|
22112
|
+
}, "readOne");
|
|
22113
|
+
const [name, email] = await Promise.all([
|
|
22114
|
+
readOne("user.name"),
|
|
22115
|
+
readOne("user.email")
|
|
22116
|
+
]);
|
|
22117
|
+
return {
|
|
22118
|
+
name,
|
|
22119
|
+
email
|
|
22120
|
+
};
|
|
22121
|
+
}
|
|
22122
|
+
__name(gitUserConfigured, "gitUserConfigured");
|
|
22123
|
+
async function getCommitSha(cwd) {
|
|
22124
|
+
try {
|
|
22125
|
+
const { stdout, code } = await runGit([
|
|
22126
|
+
"rev-parse",
|
|
22127
|
+
"HEAD"
|
|
22128
|
+
], {
|
|
22129
|
+
cwd
|
|
22130
|
+
});
|
|
22131
|
+
if (code !== 0) return null;
|
|
22132
|
+
const sha = stdout.trim();
|
|
22133
|
+
return sha.length > 0 ? sha : null;
|
|
22134
|
+
} catch {
|
|
22135
|
+
return null;
|
|
22136
|
+
}
|
|
22137
|
+
}
|
|
22138
|
+
__name(getCommitSha, "getCommitSha");
|
|
22139
|
+
|
|
22140
|
+
// src/utils/try-git-commit.ts
|
|
22141
|
+
init_analytics();
|
|
22142
|
+
async function tryGitCommit(opts) {
|
|
22143
|
+
const config = readYamlConfig();
|
|
22144
|
+
if (!config?.git?.enabled) {
|
|
22145
|
+
return {
|
|
22146
|
+
committed: false
|
|
22147
|
+
};
|
|
22148
|
+
}
|
|
22149
|
+
const runOpts = {
|
|
22150
|
+
cwd: opts.cwd
|
|
22151
|
+
};
|
|
22152
|
+
if (!opts.allowEmpty) {
|
|
22153
|
+
try {
|
|
22154
|
+
const addResult = await runGit([
|
|
22155
|
+
"add",
|
|
22156
|
+
"-A"
|
|
22157
|
+
], runOpts);
|
|
22158
|
+
if (addResult.code !== 0) {
|
|
22159
|
+
const reason = classifyGitError(null, addResult.stderr);
|
|
22160
|
+
reportFailure("add", reason);
|
|
22161
|
+
return {
|
|
22162
|
+
committed: false
|
|
22163
|
+
};
|
|
22164
|
+
}
|
|
22165
|
+
} catch (err) {
|
|
22166
|
+
const reason = classifyGitError(err);
|
|
22167
|
+
reportFailure("add", reason);
|
|
22168
|
+
return {
|
|
22169
|
+
committed: false
|
|
22170
|
+
};
|
|
22171
|
+
}
|
|
22172
|
+
}
|
|
22173
|
+
const commitArgs = [
|
|
22174
|
+
"commit"
|
|
22175
|
+
];
|
|
22176
|
+
if (opts.allowEmpty) commitArgs.push("--allow-empty");
|
|
22177
|
+
commitArgs.push("-m", opts.message);
|
|
22178
|
+
try {
|
|
22179
|
+
const commitResult = await runGit(commitArgs, runOpts);
|
|
22180
|
+
if (commitResult.code !== 0) {
|
|
22181
|
+
const reason = classifyGitError(null, commitResult.stderr);
|
|
22182
|
+
if (reason !== "nothing-to-commit") {
|
|
22183
|
+
reportFailure("commit", reason);
|
|
22184
|
+
}
|
|
22185
|
+
return {
|
|
22186
|
+
committed: false
|
|
22187
|
+
};
|
|
22188
|
+
}
|
|
22189
|
+
} catch (err) {
|
|
22190
|
+
const reason = classifyGitError(err);
|
|
22191
|
+
if (reason !== "nothing-to-commit") {
|
|
22192
|
+
reportFailure("commit", reason);
|
|
22193
|
+
}
|
|
22194
|
+
return {
|
|
22195
|
+
committed: false
|
|
22196
|
+
};
|
|
22197
|
+
}
|
|
22198
|
+
const sha = await getCommitSha(opts.cwd) ?? void 0;
|
|
22199
|
+
let tagged;
|
|
22200
|
+
if (opts.tag) {
|
|
22201
|
+
try {
|
|
22202
|
+
const tagResult = await runGit([
|
|
22203
|
+
"tag",
|
|
22204
|
+
opts.tag
|
|
22205
|
+
], runOpts);
|
|
22206
|
+
if (tagResult.code !== 0) {
|
|
22207
|
+
const reason = classifyGitError(null, tagResult.stderr);
|
|
22208
|
+
reportFailure("tag", reason);
|
|
22209
|
+
tagged = false;
|
|
22210
|
+
} else {
|
|
22211
|
+
tagged = true;
|
|
22212
|
+
}
|
|
22213
|
+
} catch (err) {
|
|
22214
|
+
const reason = classifyGitError(err);
|
|
22215
|
+
reportFailure("tag", reason);
|
|
22216
|
+
tagged = false;
|
|
22217
|
+
}
|
|
22218
|
+
}
|
|
22219
|
+
trackEvent("cli_git_sideeffect_succeeded", {
|
|
22220
|
+
action: opts.action,
|
|
22221
|
+
has_sha: Boolean(sha),
|
|
22222
|
+
has_tag: tagged === true
|
|
22223
|
+
});
|
|
22224
|
+
return {
|
|
22225
|
+
committed: true,
|
|
22226
|
+
sha,
|
|
22227
|
+
tagged
|
|
22228
|
+
};
|
|
22229
|
+
}
|
|
22230
|
+
__name(tryGitCommit, "tryGitCommit");
|
|
22231
|
+
function reportFailure(action, reason) {
|
|
22232
|
+
writeInfo(`\u26A0\uFE0F Git ${action} skipped: ${reason}`);
|
|
22233
|
+
trackEvent("cli_git_sideeffect_failed", {
|
|
22234
|
+
action,
|
|
22235
|
+
reason
|
|
22236
|
+
});
|
|
22237
|
+
}
|
|
22238
|
+
__name(reportFailure, "reportFailure");
|
|
22239
|
+
|
|
22240
|
+
// src/utils/git-messages.ts
|
|
22241
|
+
var GIT_MESSAGES = {
|
|
22242
|
+
pushStaged: "lua: push staged code",
|
|
22243
|
+
createVersion: /* @__PURE__ */ __name((version, message) => {
|
|
22244
|
+
const trimmed = message?.trim();
|
|
22245
|
+
return trimmed ? `lua: create version v${version}: ${trimmed}` : `lua: create version v${version}`;
|
|
22246
|
+
}, "createVersion"),
|
|
22247
|
+
promote: /* @__PURE__ */ __name((version) => `lua: promote v${version} to production`, "promote"),
|
|
22248
|
+
delete: /* @__PURE__ */ __name((version) => `lua: delete version v${version}`, "delete"),
|
|
22249
|
+
pullLatest: "lua: pull latest backup",
|
|
22250
|
+
pullVersion: /* @__PURE__ */ __name((version) => `lua: pull version v${version}`, "pullVersion")
|
|
22251
|
+
};
|
|
22252
|
+
var tagName = /* @__PURE__ */ __name((version) => `lua/v${version}`, "tagName");
|
|
22253
|
+
|
|
21326
22254
|
// src/commands/push-helpers.ts
|
|
21327
22255
|
function pickPushAllNextStepVariant(opts) {
|
|
21328
22256
|
if (opts.pushedSomething && opts.failedCount === 0) return "success";
|
|
@@ -21637,6 +22565,34 @@ async function pushCommand(type, cmdObj) {
|
|
|
21637
22565
|
allowAll: true
|
|
21638
22566
|
});
|
|
21639
22567
|
}
|
|
22568
|
+
const earlyApiKey = loadApiKey();
|
|
22569
|
+
const earlyConfig = readYamlConfig();
|
|
22570
|
+
const earlyAgentId = earlyConfig?.agent?.agentId;
|
|
22571
|
+
const versioning = earlyApiKey && earlyAgentId ? await getVersioningModeCached(earlyApiKey, earlyAgentId) : {
|
|
22572
|
+
enabled: false
|
|
22573
|
+
};
|
|
22574
|
+
const isStageAll = !type && versioning.enabled;
|
|
22575
|
+
const isGranular = Boolean(type && type !== "all" && versioning.enabled);
|
|
22576
|
+
const isAutoDeployNoOp = versioning.enabled && (type === "all" || !type) && Boolean(options.autoDeploy);
|
|
22577
|
+
if (isAutoDeployNoOp) {
|
|
22578
|
+
writeInfo("\u26A0\uFE0F --auto-deploy is ignored when agent versioning is on. Use `lua version promote <version>` after `lua version create`.");
|
|
22579
|
+
options.autoDeploy = false;
|
|
22580
|
+
}
|
|
22581
|
+
if (options.entityName && !type) {
|
|
22582
|
+
console.log("\nUsage:");
|
|
22583
|
+
console.log(" lua push skill --name mySkill --set-version 1.0.5 Push specific skill");
|
|
22584
|
+
console.log(" lua push webhook --name myWebhook --set-version 2.0.0 Push specific webhook");
|
|
22585
|
+
throw new Error("Type must be specified when using the --name option.");
|
|
22586
|
+
}
|
|
22587
|
+
if (isStageAll) {
|
|
22588
|
+
return await pushAllCommand({
|
|
22589
|
+
...options,
|
|
22590
|
+
autoDeployNoopWarned: isAutoDeployNoOp
|
|
22591
|
+
});
|
|
22592
|
+
}
|
|
22593
|
+
if (isGranular) {
|
|
22594
|
+
writeInfo("\u26A0\uFE0F Granular push is deprecated when agent versioning is on. Use `lua push` (no args) to stage all changes, then `lua version create`.");
|
|
22595
|
+
}
|
|
21640
22596
|
if (type === "all") {
|
|
21641
22597
|
if (!options.force) {
|
|
21642
22598
|
console.log("\nUsage:");
|
|
@@ -21644,13 +22600,10 @@ async function pushCommand(type, cmdObj) {
|
|
|
21644
22600
|
console.log(" lua push all --force --auto-deploy Push and deploy all to production");
|
|
21645
22601
|
throw new Error('The "all" type requires the --force flag');
|
|
21646
22602
|
}
|
|
21647
|
-
return await pushAllCommand(
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
console.log(" lua push skill --name mySkill --set-version 1.0.5 Push specific skill");
|
|
21652
|
-
console.log(" lua push webhook --name myWebhook --set-version 2.0.0 Push specific webhook");
|
|
21653
|
-
throw new Error("Type must be specified when using the --name option.");
|
|
22603
|
+
return await pushAllCommand({
|
|
22604
|
+
...options,
|
|
22605
|
+
autoDeployNoopWarned: isAutoDeployNoOp
|
|
22606
|
+
});
|
|
21654
22607
|
}
|
|
21655
22608
|
if (type) {
|
|
21656
22609
|
selectedType = type;
|
|
@@ -21791,13 +22744,17 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
|
|
|
21791
22744
|
bundles_total: versionedPushDeployResult?.bundleStats?.total ?? 0,
|
|
21792
22745
|
bundles_uploaded: versionedPushDeployResult?.bundleStats?.uploaded ?? 0,
|
|
21793
22746
|
bundles_existed: versionedPushDeployResult?.bundleStats?.alreadyExisted ?? 0,
|
|
21794
|
-
//
|
|
21795
|
-
//
|
|
21796
|
-
//
|
|
22747
|
+
// `--include-source` telemetry. Tracks adoption of the flag and whether
|
|
22748
|
+
// the per-skill source attach actually lands cleanly — useful for the
|
|
22749
|
+
// eventual "flip default to ON" decision.
|
|
21797
22750
|
include_source_requested: options.includeSource || false,
|
|
21798
22751
|
include_source_attempted: trackedIncludeSource?.attempted ?? 0,
|
|
21799
22752
|
include_source_attached: trackedIncludeSource?.attached ?? 0,
|
|
21800
|
-
include_source_failed: trackedIncludeSource?.failed ?? 0
|
|
22753
|
+
include_source_failed: trackedIncludeSource?.failed ?? 0,
|
|
22754
|
+
// Agent-versioning telemetry. Driven by isStageAll / isGranular.
|
|
22755
|
+
versioning_mode: versioning.enabled ? isGranular ? "granular" : "all" : "flag-off",
|
|
22756
|
+
granular_deprecation_warned: isGranular,
|
|
22757
|
+
auto_deploy_noop_warned: isAutoDeployNoOp
|
|
21801
22758
|
});
|
|
21802
22759
|
const productionDeployedActually = versionedPushDeployResult?.productionDeploySucceeded === true || !!agentOutcome && !agentOutcome.cancelled && agentOutcome.productionDeployedWithAutoDeploy;
|
|
21803
22760
|
const personaAutoDeployRanAndFailed = selectedType === "agent" && options.autoDeploy && !!agentOutcome && !agentOutcome.cancelled && "personaAutoDeployFailed" in agentOutcome && agentOutcome.personaAutoDeployFailed;
|
|
@@ -22090,6 +23047,7 @@ async function pushAllCommand(options) {
|
|
|
22090
23047
|
}
|
|
22091
23048
|
const apiKey = await requireAuthOrExit(false);
|
|
22092
23049
|
const agentId = config.agent.agentId;
|
|
23050
|
+
const pushAllVersioning = await getVersioningModeCached(apiKey, agentId);
|
|
22093
23051
|
let manifest;
|
|
22094
23052
|
try {
|
|
22095
23053
|
manifest = loadManifest();
|
|
@@ -22386,15 +23344,26 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
|
|
|
22386
23344
|
bundles_total: bundleStatsAggregate.total,
|
|
22387
23345
|
bundles_uploaded: bundleStatsAggregate.uploaded,
|
|
22388
23346
|
bundles_existed: bundleStatsAggregate.existed,
|
|
22389
|
-
//
|
|
23347
|
+
// `--include-source` telemetry, parallel to the single-push
|
|
22390
23348
|
// `cli_push_completed` shape. Without these the `lua push all` path —
|
|
22391
|
-
//
|
|
22392
|
-
//
|
|
23349
|
+
// the highest-volume one for multi-skill agents — would be invisible
|
|
23350
|
+
// to adoption monitoring.
|
|
22393
23351
|
include_source_requested: options.includeSource || false,
|
|
22394
23352
|
include_source_attempted: includeSourceStats?.attempted ?? 0,
|
|
22395
23353
|
include_source_attached: includeSourceStats?.attached ?? 0,
|
|
22396
|
-
include_source_failed: includeSourceStats?.failed ?? 0
|
|
23354
|
+
include_source_failed: includeSourceStats?.failed ?? 0,
|
|
23355
|
+
// Agent-versioning telemetry.
|
|
23356
|
+
versioning_mode: pushAllVersioning.enabled ? "stage-all" : "flag-off",
|
|
23357
|
+
granular_deprecation_warned: false,
|
|
23358
|
+
auto_deploy_noop_warned: options.autoDeployNoopWarned || false
|
|
22397
23359
|
});
|
|
23360
|
+
try {
|
|
23361
|
+
await tryGitCommit({
|
|
23362
|
+
message: GIT_MESSAGES.pushStaged,
|
|
23363
|
+
action: "push-staged"
|
|
23364
|
+
});
|
|
23365
|
+
} catch {
|
|
23366
|
+
}
|
|
22398
23367
|
const pushedSomething = allResults.length > 0 || mcpPushedCount > 0 || !!personaPushResult || backupSuccess;
|
|
22399
23368
|
const variant = pickPushAllNextStepVariant({
|
|
22400
23369
|
pushedSomething,
|
|
@@ -22402,7 +23371,11 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
|
|
|
22402
23371
|
});
|
|
22403
23372
|
if (variant === "success") {
|
|
22404
23373
|
console.log("");
|
|
22405
|
-
if (
|
|
23374
|
+
if (pushAllVersioning.enabled) {
|
|
23375
|
+
if (!options.suppressVersionCreateHint) {
|
|
23376
|
+
writeInfo(`Run \`lua version create [-m "<message>"]\` to snapshot the staged state into a named version, then \`lua version promote <version>\` to deploy.`);
|
|
23377
|
+
}
|
|
23378
|
+
} else if (options.autoDeploy) {
|
|
22406
23379
|
writeHintBlock({
|
|
22407
23380
|
headline: "All deployed. Generate test traffic first, then inspect:",
|
|
22408
23381
|
lines: [
|
|
@@ -22670,6 +23643,10 @@ async function deployCommand(type, cmdObj) {
|
|
|
22670
23643
|
selectedType = answer.type;
|
|
22671
23644
|
}
|
|
22672
23645
|
const apiKey = await requireAuthOrExit();
|
|
23646
|
+
const versioning = await getVersioningModeCached(apiKey, agentId);
|
|
23647
|
+
if (versioning.enabled) {
|
|
23648
|
+
writeInfo("\u26A0\uFE0F `lua deploy` is deprecated when agent versioning is on. Use `lua version promote <version>` for instant, atomic promotion.");
|
|
23649
|
+
}
|
|
22673
23650
|
let personaDeployed = false;
|
|
22674
23651
|
let versionedOutcome = null;
|
|
22675
23652
|
if (selectedType === "persona") {
|
|
@@ -22682,7 +23659,8 @@ async function deployCommand(type, cmdObj) {
|
|
|
22682
23659
|
primitive_type: selectedType,
|
|
22683
23660
|
force_mode: options.force || false,
|
|
22684
23661
|
entity_selected_by_name: !!options.name,
|
|
22685
|
-
version_selected_by_flag: !!options.version
|
|
23662
|
+
version_selected_by_flag: !!options.version,
|
|
23663
|
+
granular_deprecation_warned: versioning.enabled
|
|
22686
23664
|
});
|
|
22687
23665
|
const deployed = selectedType === "persona" ? personaDeployed : versionedOutcome?.deployed ?? false;
|
|
22688
23666
|
const hintPrintedAlready = selectedType !== "persona" && !!versionedOutcome?.hintPrinted;
|
|
@@ -23176,11 +24154,11 @@ init_cli();
|
|
|
23176
24154
|
|
|
23177
24155
|
// src/utils/sandbox-storage.ts
|
|
23178
24156
|
init_constants();
|
|
23179
|
-
import { readFileSync as
|
|
23180
|
-
import { dirname as
|
|
24157
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
|
|
24158
|
+
import { dirname as dirname6 } from "path";
|
|
23181
24159
|
function readStore() {
|
|
23182
24160
|
try {
|
|
23183
|
-
const raw =
|
|
24161
|
+
const raw = readFileSync10(SANDBOX_STORAGE_FILE, "utf8");
|
|
23184
24162
|
const parsed = JSON.parse(raw);
|
|
23185
24163
|
return {
|
|
23186
24164
|
skills: parsed.skills ?? {},
|
|
@@ -23200,10 +24178,10 @@ function readStore() {
|
|
|
23200
24178
|
__name(readStore, "readStore");
|
|
23201
24179
|
function writeStore(store) {
|
|
23202
24180
|
try {
|
|
23203
|
-
|
|
24181
|
+
mkdirSync7(dirname6(SANDBOX_STORAGE_FILE), {
|
|
23204
24182
|
recursive: true
|
|
23205
24183
|
});
|
|
23206
|
-
|
|
24184
|
+
writeFileSync7(SANDBOX_STORAGE_FILE, JSON.stringify(store, null, 2), "utf8");
|
|
23207
24185
|
} catch {
|
|
23208
24186
|
}
|
|
23209
24187
|
}
|
|
@@ -23707,7 +24685,15 @@ var MIME_TYPES = {
|
|
|
23707
24685
|
".json": "application/json",
|
|
23708
24686
|
// Email
|
|
23709
24687
|
".eml": "message/rfc822",
|
|
23710
|
-
".msg": "application/vnd.ms-outlook"
|
|
24688
|
+
".msg": "application/vnd.ms-outlook",
|
|
24689
|
+
// Audio. lua-core picks the path per provider: types in the provider's
|
|
24690
|
+
// native allowlist go straight to the model, the rest are transcribed by
|
|
24691
|
+
// Deepgram via FileConversionService.
|
|
24692
|
+
".m4a": "audio/mp4",
|
|
24693
|
+
".mp3": "audio/mpeg",
|
|
24694
|
+
".wav": "audio/wav",
|
|
24695
|
+
".ogg": "audio/ogg",
|
|
24696
|
+
".opus": "audio/opus"
|
|
23711
24697
|
};
|
|
23712
24698
|
var IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
23713
24699
|
"image/png",
|
|
@@ -24517,8 +25503,8 @@ init_cli();
|
|
|
24517
25503
|
init_constants();
|
|
24518
25504
|
init_command_utils();
|
|
24519
25505
|
init_developer_api_service();
|
|
24520
|
-
import
|
|
24521
|
-
import
|
|
25506
|
+
import fs16 from "fs";
|
|
25507
|
+
import path18 from "path";
|
|
24522
25508
|
import inquirer10 from "inquirer";
|
|
24523
25509
|
init_analytics();
|
|
24524
25510
|
function resolveEnvironment(env, hasNonInteractiveFlags) {
|
|
@@ -24877,10 +25863,10 @@ function variablesToEnvContent(variables) {
|
|
|
24877
25863
|
}
|
|
24878
25864
|
__name(variablesToEnvContent, "variablesToEnvContent");
|
|
24879
25865
|
function saveSandboxEnvVariables(variables) {
|
|
24880
|
-
const envFilePath =
|
|
25866
|
+
const envFilePath = path18.join(process.cwd(), ".env");
|
|
24881
25867
|
try {
|
|
24882
25868
|
const content = variablesToEnvContent(variables);
|
|
24883
|
-
|
|
25869
|
+
fs16.writeFileSync(envFilePath, content, "utf8");
|
|
24884
25870
|
return true;
|
|
24885
25871
|
} catch (error) {
|
|
24886
25872
|
console.error("\u274C Error saving .env file:", error);
|
|
@@ -29372,7 +30358,7 @@ init_auth();
|
|
|
29372
30358
|
init_auth_api_service();
|
|
29373
30359
|
init_files();
|
|
29374
30360
|
init_artifact_loader();
|
|
29375
|
-
import { existsSync as existsSync7, readFileSync as
|
|
30361
|
+
import { existsSync as existsSync7, readFileSync as readFileSync11 } from "fs";
|
|
29376
30362
|
import { join as join6 } from "path";
|
|
29377
30363
|
import { performance } from "perf_hooks";
|
|
29378
30364
|
import * as os from "os";
|
|
@@ -29723,7 +30709,7 @@ function gatherTelemetry() {
|
|
|
29723
30709
|
} else {
|
|
29724
30710
|
try {
|
|
29725
30711
|
if (existsSync7(TELEMETRY_FILE)) {
|
|
29726
|
-
const raw =
|
|
30712
|
+
const raw = readFileSync11(TELEMETRY_FILE, "utf8");
|
|
29727
30713
|
const cfg = JSON.parse(raw);
|
|
29728
30714
|
if (typeof cfg.enabled === "boolean") enabled = cfg.enabled;
|
|
29729
30715
|
}
|
|
@@ -38904,7 +39890,7 @@ __name(telemetryCommand, "telemetryCommand");
|
|
|
38904
39890
|
init_cli();
|
|
38905
39891
|
init_command_utils();
|
|
38906
39892
|
init_analytics();
|
|
38907
|
-
import { writeFileSync as
|
|
39893
|
+
import { writeFileSync as writeFileSync8, existsSync as existsSync8, unlinkSync as unlinkSync2 } from "fs";
|
|
38908
39894
|
import { resolve as resolve4, join as join7 } from "path";
|
|
38909
39895
|
init_artifact_loader();
|
|
38910
39896
|
init_types();
|
|
@@ -39065,7 +40051,7 @@ async function governanceCommand(action) {
|
|
|
39065
40051
|
}
|
|
39066
40052
|
}
|
|
39067
40053
|
const content = generateFile(setup);
|
|
39068
|
-
|
|
40054
|
+
writeFileSync8(filePath, content, "utf-8");
|
|
39069
40055
|
const relativePath = filePath.replace(process.cwd() + "/", "");
|
|
39070
40056
|
writeSuccess(`Created ${relativePath}`);
|
|
39071
40057
|
console.log("");
|
|
@@ -39329,14 +40315,14 @@ init_analytics();
|
|
|
39329
40315
|
init_command_utils();
|
|
39330
40316
|
init_artifact_loader();
|
|
39331
40317
|
init_types();
|
|
39332
|
-
import { spawn as
|
|
40318
|
+
import { spawn as spawn3 } from "child_process";
|
|
39333
40319
|
import { existsSync as existsSync9, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
|
|
39334
40320
|
import { join as join8, relative, resolve as resolve5 } from "path";
|
|
39335
40321
|
init_voice_api_service();
|
|
39336
40322
|
init_constants();
|
|
39337
40323
|
|
|
39338
40324
|
// src/commands/voice-terminal.ts
|
|
39339
|
-
import { spawn, spawnSync } from "child_process";
|
|
40325
|
+
import { spawn as spawn2, spawnSync } from "child_process";
|
|
39340
40326
|
import { platform as platform3 } from "os";
|
|
39341
40327
|
import { AudioFrame, AudioSource, AudioStream, LocalAudioTrack, Room, RoomEvent, TrackKind, TrackPublishOptions, TrackSource } from "@livekit/rtc-node";
|
|
39342
40328
|
|
|
@@ -39599,7 +40585,7 @@ function spawnCapture() {
|
|
|
39599
40585
|
String(FRAME_SAMPLES * 2),
|
|
39600
40586
|
"-"
|
|
39601
40587
|
];
|
|
39602
|
-
const proc =
|
|
40588
|
+
const proc = spawn2("sox", args2, {
|
|
39603
40589
|
stdio: [
|
|
39604
40590
|
"ignore",
|
|
39605
40591
|
"pipe",
|
|
@@ -39630,7 +40616,7 @@ function spawnPlayback() {
|
|
|
39630
40616
|
"-",
|
|
39631
40617
|
"-d"
|
|
39632
40618
|
];
|
|
39633
|
-
const proc =
|
|
40619
|
+
const proc = spawn2("sox", args2, {
|
|
39634
40620
|
stdio: [
|
|
39635
40621
|
"pipe",
|
|
39636
40622
|
"ignore",
|
|
@@ -39960,7 +40946,7 @@ function buildRunnerArgs(runner, opts) {
|
|
|
39960
40946
|
__name(buildRunnerArgs, "buildRunnerArgs");
|
|
39961
40947
|
async function spawnRunner(runner, args2, cwd) {
|
|
39962
40948
|
return new Promise((resolveExit) => {
|
|
39963
|
-
const proc =
|
|
40949
|
+
const proc = spawn3("npx", [
|
|
39964
40950
|
runner,
|
|
39965
40951
|
...args2
|
|
39966
40952
|
], {
|
|
@@ -40353,6 +41339,12 @@ async function sourceRollbackCommand(opts) {
|
|
|
40353
41339
|
const config = readYamlConfig();
|
|
40354
41340
|
const agentId = config?.agent?.agentId;
|
|
40355
41341
|
if (!agentId) throw new Error("No agentId in lua.skill.yaml. Run `lua init` first.");
|
|
41342
|
+
if (!opts.silent) {
|
|
41343
|
+
const versioning = await getVersioningModeCached(apiKey, agentId);
|
|
41344
|
+
if (versioning.enabled) {
|
|
41345
|
+
writeInfo("\u26A0\uFE0F `lua source rollback` is deprecated when agent versioning is on. Use `lua version promote <version>` \u2014 instant, no re-upload required.");
|
|
41346
|
+
}
|
|
41347
|
+
}
|
|
40356
41348
|
const fetchM = opts.fetchManifest ?? defaultFetchManifest;
|
|
40357
41349
|
const fetchU = opts.fetchUrls ?? defaultFetchUrls;
|
|
40358
41350
|
const dlBlobs = opts.downloadBlobs ?? downloadBlobsParallel;
|
|
@@ -40423,6 +41415,560 @@ function defaultRestore(manifest, blobs, targetDir) {
|
|
|
40423
41415
|
}
|
|
40424
41416
|
__name(defaultRestore, "defaultRestore");
|
|
40425
41417
|
|
|
41418
|
+
// src/commands/version.ts
|
|
41419
|
+
init_cli();
|
|
41420
|
+
init_command_utils();
|
|
41421
|
+
init_analytics();
|
|
41422
|
+
init_files();
|
|
41423
|
+
init_constants();
|
|
41424
|
+
|
|
41425
|
+
// src/utils/parse-version.ts
|
|
41426
|
+
function parseVersion2(arg) {
|
|
41427
|
+
if (!arg) throw new Error(`Invalid version "${arg}": must be a positive integer like "3" or "v3".`);
|
|
41428
|
+
const stripped = arg.replace(/^v/i, "");
|
|
41429
|
+
const n = Number.parseInt(stripped, 10);
|
|
41430
|
+
if (!Number.isFinite(n) || n <= 0 || String(n) !== stripped) {
|
|
41431
|
+
throw new Error(`Invalid version "${arg}": must be a positive integer like "3" or "v3".`);
|
|
41432
|
+
}
|
|
41433
|
+
return n;
|
|
41434
|
+
}
|
|
41435
|
+
__name(parseVersion2, "parseVersion");
|
|
41436
|
+
|
|
41437
|
+
// src/commands/version.ts
|
|
41438
|
+
async function assertVersioningEnabled(apiKey, agentId) {
|
|
41439
|
+
const { enabled } = await getVersioningModeCached(apiKey, agentId);
|
|
41440
|
+
if (!enabled) {
|
|
41441
|
+
throw new Error("Agent versioning is not enabled for your organization. Contact your admin to enable it, or use `lua push <primitive>` for the legacy flow.");
|
|
41442
|
+
}
|
|
41443
|
+
}
|
|
41444
|
+
__name(assertVersioningEnabled, "assertVersioningEnabled");
|
|
41445
|
+
async function versionCreateCommand(options = {}) {
|
|
41446
|
+
return withErrorHandling(async () => {
|
|
41447
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41448
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41449
|
+
let config = readYamlConfig();
|
|
41450
|
+
let backupVersion = config?.backup?.activeVersion;
|
|
41451
|
+
if (options.autoPush) {
|
|
41452
|
+
await pushAllCommand({
|
|
41453
|
+
force: true,
|
|
41454
|
+
includeSource: true,
|
|
41455
|
+
suppressVersionCreateHint: true
|
|
41456
|
+
});
|
|
41457
|
+
config = readYamlConfig();
|
|
41458
|
+
backupVersion = config?.backup?.activeVersion;
|
|
41459
|
+
if (backupVersion == null) {
|
|
41460
|
+
throw new Error("Backup tracking lost after push. Aborting.");
|
|
41461
|
+
}
|
|
41462
|
+
}
|
|
41463
|
+
if (backupVersion == null) {
|
|
41464
|
+
throw new Error("No backup exists for this agent. Run `lua push` first, or pass `--auto-push` to push and snapshot in one step.");
|
|
41465
|
+
}
|
|
41466
|
+
let message = options.message;
|
|
41467
|
+
const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41468
|
+
const isCi = isCiModeEnabled();
|
|
41469
|
+
if (!message && isTTY && !isCi) {
|
|
41470
|
+
const answers = await safePrompt([
|
|
41471
|
+
{
|
|
41472
|
+
type: "input",
|
|
41473
|
+
name: "input",
|
|
41474
|
+
message: "Optional description (blank to skip):"
|
|
41475
|
+
}
|
|
41476
|
+
]);
|
|
41477
|
+
message = answers?.input?.trim() || void 0;
|
|
41478
|
+
}
|
|
41479
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41480
|
+
const result = await api.createVersion({
|
|
41481
|
+
message,
|
|
41482
|
+
sourceManifestVersion: backupVersion,
|
|
41483
|
+
commitHash: options.commitHash
|
|
41484
|
+
});
|
|
41485
|
+
if (!result.success || !result.data) {
|
|
41486
|
+
throw new Error(result.error?.message ?? "Failed to create version");
|
|
41487
|
+
}
|
|
41488
|
+
writeInfo(`\u2713 Created v${result.data.version} (staged). Run \`lua version promote v${result.data.version}\` to deploy.`);
|
|
41489
|
+
try {
|
|
41490
|
+
const gitResult = await tryGitCommit({
|
|
41491
|
+
message: GIT_MESSAGES.createVersion(result.data.version, message),
|
|
41492
|
+
action: "version-create",
|
|
41493
|
+
tag: tagName(result.data.version),
|
|
41494
|
+
allowEmpty: true
|
|
41495
|
+
});
|
|
41496
|
+
if (gitResult.committed && gitResult.sha) {
|
|
41497
|
+
await api.patchCommitHash(result.data.version, gitResult.sha);
|
|
41498
|
+
}
|
|
41499
|
+
} catch {
|
|
41500
|
+
}
|
|
41501
|
+
trackEvent("cli_version_create_completed", {
|
|
41502
|
+
auto_push: Boolean(options.autoPush),
|
|
41503
|
+
has_message: Boolean(message),
|
|
41504
|
+
non_interactive: !isTTY || isCi
|
|
41505
|
+
});
|
|
41506
|
+
}, "version create");
|
|
41507
|
+
}
|
|
41508
|
+
__name(versionCreateCommand, "versionCreateCommand");
|
|
41509
|
+
async function versionListCommand(options = {}) {
|
|
41510
|
+
return withErrorHandling(async () => {
|
|
41511
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41512
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41513
|
+
const query = {};
|
|
41514
|
+
if (options.all) query.all = true;
|
|
41515
|
+
if (options.limit != null) query.limit = options.limit;
|
|
41516
|
+
if (options.status) query.status = options.status;
|
|
41517
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41518
|
+
const response = await api.listVersions(query);
|
|
41519
|
+
if (!response.success || !response.data) {
|
|
41520
|
+
throw new Error(response.error?.message ?? "Failed to list versions");
|
|
41521
|
+
}
|
|
41522
|
+
const versions = response.data;
|
|
41523
|
+
if (options.json) {
|
|
41524
|
+
console.log(JSON.stringify(versions, null, 2));
|
|
41525
|
+
} else if (versions.length === 0) {
|
|
41526
|
+
writeInfo("(no versions yet \u2014 run `lua version create` to make one)");
|
|
41527
|
+
} else {
|
|
41528
|
+
console.log("VERSION STATUS CREATED BY MESSAGE");
|
|
41529
|
+
for (const v of versions) {
|
|
41530
|
+
const star = v.status === "active" ? "*" : " ";
|
|
41531
|
+
const date = new Date(v.createdAt).toISOString().slice(0, 16).replace("T", " ");
|
|
41532
|
+
const status = v.status.padEnd(11);
|
|
41533
|
+
const by = (v.createdBy || "").slice(0, 10).padEnd(10);
|
|
41534
|
+
const msg = (v.message || "").slice(0, 60);
|
|
41535
|
+
console.log(`v${v.version}${star} ${status} ${date} ${by}${msg}`);
|
|
41536
|
+
}
|
|
41537
|
+
}
|
|
41538
|
+
trackEvent("cli_version_list_completed", {
|
|
41539
|
+
count: versions.length,
|
|
41540
|
+
status_filter: options.status ?? "all"
|
|
41541
|
+
});
|
|
41542
|
+
}, "version list");
|
|
41543
|
+
}
|
|
41544
|
+
__name(versionListCommand, "versionListCommand");
|
|
41545
|
+
async function versionShowCommand(versionArg, options = {}) {
|
|
41546
|
+
return withErrorHandling(async () => {
|
|
41547
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41548
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41549
|
+
const version = parseVersion2(versionArg);
|
|
41550
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41551
|
+
const response = await api.getVersion(version);
|
|
41552
|
+
if (!response.success || !response.data) {
|
|
41553
|
+
throw new Error(response.error?.message ?? `Version v${version} not found`);
|
|
41554
|
+
}
|
|
41555
|
+
const v = response.data;
|
|
41556
|
+
if (options.json) {
|
|
41557
|
+
console.log(JSON.stringify(v, null, 2));
|
|
41558
|
+
} else {
|
|
41559
|
+
console.log(`Version v${v.version} (${v.status})`);
|
|
41560
|
+
console.log(` Created: ${v.createdAt} by ${v.createdBy}`);
|
|
41561
|
+
if (v.message) console.log(` Message: ${v.message}`);
|
|
41562
|
+
if (v.commitHash) console.log(` Commit: ${v.commitHash}`);
|
|
41563
|
+
console.log(` Model: ${v.snapshot.model}`);
|
|
41564
|
+
console.log(` Snapshot:`);
|
|
41565
|
+
console.log(` Skills: ${v.snapshot.skills.length}`);
|
|
41566
|
+
console.log(` Webhooks: ${v.snapshot.webhooks.length}`);
|
|
41567
|
+
console.log(` Jobs: ${v.snapshot.jobs.length}`);
|
|
41568
|
+
console.log(` Preprocessors: ${v.snapshot.preprocessors.length}`);
|
|
41569
|
+
console.log(` Postprocessors: ${v.snapshot.postprocessors.length}`);
|
|
41570
|
+
console.log(` MCP servers: ${v.snapshot.mcpServers.length}`);
|
|
41571
|
+
console.log(` Persona: ${v.snapshot.persona.versionId || "(none)"}`);
|
|
41572
|
+
}
|
|
41573
|
+
trackEvent("cli_version_show_completed", {
|
|
41574
|
+
version,
|
|
41575
|
+
json: Boolean(options.json)
|
|
41576
|
+
});
|
|
41577
|
+
}, "version show");
|
|
41578
|
+
}
|
|
41579
|
+
__name(versionShowCommand, "versionShowCommand");
|
|
41580
|
+
async function versionDiffCommand(fromArg, toArg, options = {}) {
|
|
41581
|
+
return withErrorHandling(async () => {
|
|
41582
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41583
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41584
|
+
const from = parseVersion2(fromArg);
|
|
41585
|
+
const to = parseVersion2(toArg);
|
|
41586
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41587
|
+
const response = await api.diffVersions(from, to);
|
|
41588
|
+
if (!response.success || !response.data) {
|
|
41589
|
+
throw new Error(response.error?.message ?? "Failed to diff versions");
|
|
41590
|
+
}
|
|
41591
|
+
const diff = response.data;
|
|
41592
|
+
if (options.json) {
|
|
41593
|
+
console.log(JSON.stringify(diff, null, 2));
|
|
41594
|
+
} else {
|
|
41595
|
+
console.log(`Diff v${from} \u2192 v${to}`);
|
|
41596
|
+
const sections = [
|
|
41597
|
+
{
|
|
41598
|
+
name: "Skills",
|
|
41599
|
+
entry: diff.skills,
|
|
41600
|
+
key: "skillId"
|
|
41601
|
+
},
|
|
41602
|
+
{
|
|
41603
|
+
name: "Webhooks",
|
|
41604
|
+
entry: diff.webhooks,
|
|
41605
|
+
key: "webhookId"
|
|
41606
|
+
},
|
|
41607
|
+
{
|
|
41608
|
+
name: "Jobs",
|
|
41609
|
+
entry: diff.jobs,
|
|
41610
|
+
key: "jobId"
|
|
41611
|
+
},
|
|
41612
|
+
{
|
|
41613
|
+
name: "Preprocessors",
|
|
41614
|
+
entry: diff.preprocessors,
|
|
41615
|
+
key: "id"
|
|
41616
|
+
},
|
|
41617
|
+
{
|
|
41618
|
+
name: "Postprocessors",
|
|
41619
|
+
entry: diff.postprocessors,
|
|
41620
|
+
key: "id"
|
|
41621
|
+
}
|
|
41622
|
+
];
|
|
41623
|
+
for (const { name, entry, key } of sections) {
|
|
41624
|
+
const total = entry.added.length + entry.removed.length + entry.changed.length;
|
|
41625
|
+
if (total === 0) {
|
|
41626
|
+
console.log(`${name}: (no changes)`);
|
|
41627
|
+
continue;
|
|
41628
|
+
}
|
|
41629
|
+
console.log(`${name}:`);
|
|
41630
|
+
for (const a of entry.added) {
|
|
41631
|
+
console.log(` + ${a[key]}@${a.version} (added)`);
|
|
41632
|
+
}
|
|
41633
|
+
for (const r of entry.removed) {
|
|
41634
|
+
console.log(` - ${r[key]}@${r.version} (removed)`);
|
|
41635
|
+
}
|
|
41636
|
+
for (const c of entry.changed) {
|
|
41637
|
+
console.log(` ~ ${c[key]} ${c.from.version} \u2192 ${c.to.version}`);
|
|
41638
|
+
}
|
|
41639
|
+
}
|
|
41640
|
+
const mcp = diff.mcpServers;
|
|
41641
|
+
if (mcp.added.length || mcp.removed.length || mcp.changed.length) {
|
|
41642
|
+
console.log("MCP servers:");
|
|
41643
|
+
mcp.added.forEach((m) => console.log(` + ${m.id} (added)`));
|
|
41644
|
+
mcp.removed.forEach((m) => console.log(` - ${m.id} (removed)`));
|
|
41645
|
+
mcp.changed.forEach((m) => console.log(` ~ ${m.id} (config changed)`));
|
|
41646
|
+
} else {
|
|
41647
|
+
console.log("MCP servers: (no changes)");
|
|
41648
|
+
}
|
|
41649
|
+
console.log(`Persona: ${diff.persona ? `${diff.persona.from} \u2192 ${diff.persona.to}` : "(unchanged)"}`);
|
|
41650
|
+
console.log(`Model: ${diff.model ? `${diff.model.from} \u2192 ${diff.model.to}` : "(unchanged)"}`);
|
|
41651
|
+
}
|
|
41652
|
+
trackEvent("cli_version_diff_completed", {
|
|
41653
|
+
from_to_distance: Math.abs(to - from)
|
|
41654
|
+
});
|
|
41655
|
+
}, "version diff");
|
|
41656
|
+
}
|
|
41657
|
+
__name(versionDiffCommand, "versionDiffCommand");
|
|
41658
|
+
async function versionPromoteCommand(versionArg) {
|
|
41659
|
+
return withErrorHandling(async () => {
|
|
41660
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41661
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41662
|
+
const version = parseVersion2(versionArg);
|
|
41663
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41664
|
+
const response = await api.promoteVersion(version);
|
|
41665
|
+
if (!response.success) {
|
|
41666
|
+
const errCode = response.error?.code;
|
|
41667
|
+
if (errCode === "VERSION_ALREADY_ACTIVE") {
|
|
41668
|
+
writeInfo(`v${version} is already active. No change.`);
|
|
41669
|
+
return;
|
|
41670
|
+
}
|
|
41671
|
+
throw new Error(response.error?.message ?? `Failed to promote v${version}`);
|
|
41672
|
+
}
|
|
41673
|
+
if (!response.data) {
|
|
41674
|
+
throw new Error(`Promote returned no data`);
|
|
41675
|
+
}
|
|
41676
|
+
const { promoted, previousActive } = response.data;
|
|
41677
|
+
const rollback = previousActive != null && previousActive > promoted;
|
|
41678
|
+
if (previousActive == null) {
|
|
41679
|
+
writeInfo(`\u2713 Promoted v${promoted}. (No previous active version.)`);
|
|
41680
|
+
} else {
|
|
41681
|
+
writeInfo(`\u2713 Promoted v${promoted}. Previous active: v${previousActive}.`);
|
|
41682
|
+
}
|
|
41683
|
+
try {
|
|
41684
|
+
await tryGitCommit({
|
|
41685
|
+
message: GIT_MESSAGES.promote(promoted),
|
|
41686
|
+
action: "version-promote",
|
|
41687
|
+
allowEmpty: true
|
|
41688
|
+
});
|
|
41689
|
+
} catch {
|
|
41690
|
+
}
|
|
41691
|
+
trackEvent("cli_version_promote_completed", {
|
|
41692
|
+
from_version: previousActive,
|
|
41693
|
+
to_version: promoted,
|
|
41694
|
+
rollback
|
|
41695
|
+
});
|
|
41696
|
+
}, "version promote");
|
|
41697
|
+
}
|
|
41698
|
+
__name(versionPromoteCommand, "versionPromoteCommand");
|
|
41699
|
+
async function versionDeleteCommand(versionArg, options = {}) {
|
|
41700
|
+
return withErrorHandling(async () => {
|
|
41701
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41702
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41703
|
+
if (versionArg === "current" || versionArg === "active") {
|
|
41704
|
+
throw new Error(`Cannot delete the active version directly. Use \`lua version promote <other>\` to roll back first, then delete.`);
|
|
41705
|
+
}
|
|
41706
|
+
const version = parseVersion2(versionArg);
|
|
41707
|
+
const isTTY = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41708
|
+
const isCi = isCiModeEnabled();
|
|
41709
|
+
if (!options.force && isTTY && !isCi) {
|
|
41710
|
+
const answer = await safePrompt([
|
|
41711
|
+
{
|
|
41712
|
+
type: "confirm",
|
|
41713
|
+
name: "confirm",
|
|
41714
|
+
message: `Delete v${version}?`,
|
|
41715
|
+
default: false
|
|
41716
|
+
}
|
|
41717
|
+
]);
|
|
41718
|
+
if (!answer?.confirm) {
|
|
41719
|
+
writeInfo("Aborted.");
|
|
41720
|
+
return;
|
|
41721
|
+
}
|
|
41722
|
+
}
|
|
41723
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41724
|
+
const response = await api.deleteVersion(version);
|
|
41725
|
+
if (!response.success) {
|
|
41726
|
+
const errCode = response.error?.code;
|
|
41727
|
+
if (errCode === "CANNOT_DELETE_ACTIVE_VERSION") {
|
|
41728
|
+
throw new Error(`Cannot delete v${version}: it is the active version. Promote a different version first.`);
|
|
41729
|
+
}
|
|
41730
|
+
if (errCode === "CANNOT_DELETE_LAST_VERSION") {
|
|
41731
|
+
throw new Error(`Cannot delete v${version}: it is the only remaining version.`);
|
|
41732
|
+
}
|
|
41733
|
+
throw new Error(response.error?.message ?? `Failed to delete v${version}`);
|
|
41734
|
+
}
|
|
41735
|
+
writeInfo(`\u2713 Deleted v${version}.`);
|
|
41736
|
+
try {
|
|
41737
|
+
await tryGitCommit({
|
|
41738
|
+
message: GIT_MESSAGES.delete(version),
|
|
41739
|
+
action: "version-delete",
|
|
41740
|
+
allowEmpty: true
|
|
41741
|
+
});
|
|
41742
|
+
} catch {
|
|
41743
|
+
}
|
|
41744
|
+
trackEvent("cli_version_delete_completed", {
|
|
41745
|
+
version,
|
|
41746
|
+
force: Boolean(options.force)
|
|
41747
|
+
});
|
|
41748
|
+
}, "version delete");
|
|
41749
|
+
}
|
|
41750
|
+
__name(versionDeleteCommand, "versionDeleteCommand");
|
|
41751
|
+
|
|
41752
|
+
// src/commands/git.ts
|
|
41753
|
+
init_cli();
|
|
41754
|
+
init_files();
|
|
41755
|
+
init_analytics();
|
|
41756
|
+
var NO_YAML_MESSAGE = "No lua.skill.yaml found. Please run this command from a skill directory.";
|
|
41757
|
+
function failConnect(status, banner, errorMessage) {
|
|
41758
|
+
if (banner) writeError(banner);
|
|
41759
|
+
trackEvent("cli_git_connect_completed", {
|
|
41760
|
+
...status,
|
|
41761
|
+
succeeded: false
|
|
41762
|
+
});
|
|
41763
|
+
throw new Error(errorMessage);
|
|
41764
|
+
}
|
|
41765
|
+
__name(failConnect, "failConnect");
|
|
41766
|
+
async function gitConnectCommand() {
|
|
41767
|
+
return withErrorHandling(async () => {
|
|
41768
|
+
const config = readYamlConfig();
|
|
41769
|
+
if (!config) {
|
|
41770
|
+
failConnect({
|
|
41771
|
+
git_available: false,
|
|
41772
|
+
in_repo: false,
|
|
41773
|
+
user_configured: false
|
|
41774
|
+
}, null, NO_YAML_MESSAGE);
|
|
41775
|
+
}
|
|
41776
|
+
if (!await isGitAvailable()) {
|
|
41777
|
+
failConnect({
|
|
41778
|
+
git_available: false,
|
|
41779
|
+
in_repo: false,
|
|
41780
|
+
user_configured: false
|
|
41781
|
+
}, "\u2717 Git binary not found on PATH.\n Fix: install git from https://git-scm.com/downloads, then re-run `lua git connect`.", "git is not installed");
|
|
41782
|
+
}
|
|
41783
|
+
if (!await isInsideGitRepo()) {
|
|
41784
|
+
failConnect({
|
|
41785
|
+
git_available: true,
|
|
41786
|
+
in_repo: false,
|
|
41787
|
+
user_configured: false
|
|
41788
|
+
}, "\u2717 This directory is not inside a git repository.\n Fix: run `git init` in your project root, then re-run `lua git connect`.", "not inside a git repository");
|
|
41789
|
+
}
|
|
41790
|
+
const identity = await gitUserConfigured();
|
|
41791
|
+
if (!identity.email) {
|
|
41792
|
+
failConnect({
|
|
41793
|
+
git_available: true,
|
|
41794
|
+
in_repo: true,
|
|
41795
|
+
user_configured: false
|
|
41796
|
+
}, '\u2717 Git user.email is not configured.\n Fix: git config --global user.email "you@example.com"', "git user.email is not configured");
|
|
41797
|
+
}
|
|
41798
|
+
if (!identity.name) {
|
|
41799
|
+
failConnect({
|
|
41800
|
+
git_available: true,
|
|
41801
|
+
in_repo: true,
|
|
41802
|
+
user_configured: false
|
|
41803
|
+
}, '\u2717 Git user.name is not configured.\n Fix: git config --global user.name "Your Name"', "git user.name is not configured");
|
|
41804
|
+
}
|
|
41805
|
+
config.git = {
|
|
41806
|
+
enabled: true
|
|
41807
|
+
};
|
|
41808
|
+
writeYamlConfig(config);
|
|
41809
|
+
writeSuccess("\u2713 Git integration enabled. Future `lua push`, `lua version *`, and `lua pull` runs will auto-commit.");
|
|
41810
|
+
trackEvent("cli_git_connect_completed", {
|
|
41811
|
+
git_available: true,
|
|
41812
|
+
in_repo: true,
|
|
41813
|
+
user_configured: true,
|
|
41814
|
+
succeeded: true
|
|
41815
|
+
});
|
|
41816
|
+
}, "git connect");
|
|
41817
|
+
}
|
|
41818
|
+
__name(gitConnectCommand, "gitConnectCommand");
|
|
41819
|
+
async function gitDisconnectCommand() {
|
|
41820
|
+
return withErrorHandling(async () => {
|
|
41821
|
+
const config = readYamlConfig();
|
|
41822
|
+
if (!config) {
|
|
41823
|
+
throw new Error(NO_YAML_MESSAGE);
|
|
41824
|
+
}
|
|
41825
|
+
config.git = {
|
|
41826
|
+
enabled: false
|
|
41827
|
+
};
|
|
41828
|
+
writeYamlConfig(config);
|
|
41829
|
+
writeSuccess("\u2713 Git integration disabled. Existing commits and tags are untouched.");
|
|
41830
|
+
trackEvent("cli_git_disconnect_completed", {});
|
|
41831
|
+
}, "git disconnect");
|
|
41832
|
+
}
|
|
41833
|
+
__name(gitDisconnectCommand, "gitDisconnectCommand");
|
|
41834
|
+
async function gitStatusCommand() {
|
|
41835
|
+
return withErrorHandling(async () => {
|
|
41836
|
+
const config = readYamlConfig();
|
|
41837
|
+
const enabled = Boolean(config?.git?.enabled);
|
|
41838
|
+
if (!enabled) {
|
|
41839
|
+
writeInfo("Git integration: disabled (run `lua git connect` to enable)");
|
|
41840
|
+
trackEvent("cli_git_status_completed", {
|
|
41841
|
+
enabled: false
|
|
41842
|
+
});
|
|
41843
|
+
return;
|
|
41844
|
+
}
|
|
41845
|
+
const settled = await Promise.allSettled([
|
|
41846
|
+
runGit([
|
|
41847
|
+
"--version"
|
|
41848
|
+
]),
|
|
41849
|
+
gitUserConfigured(),
|
|
41850
|
+
runGit([
|
|
41851
|
+
"log",
|
|
41852
|
+
"--grep",
|
|
41853
|
+
"^lua: ",
|
|
41854
|
+
"-n",
|
|
41855
|
+
"1",
|
|
41856
|
+
"--format=%h %s"
|
|
41857
|
+
]),
|
|
41858
|
+
// tryGitCommit creates lightweight tags (`git tag <name>`), which have
|
|
41859
|
+
// no taggerdate field. creatordate works for both flavors and returns
|
|
41860
|
+
// the committerdate of the referenced commit — chronological order
|
|
41861
|
+
// matches our pattern of tagging immediately after the commit.
|
|
41862
|
+
runGit([
|
|
41863
|
+
"for-each-ref",
|
|
41864
|
+
"--sort=-creatordate",
|
|
41865
|
+
"refs/tags/lua/",
|
|
41866
|
+
"--count=1",
|
|
41867
|
+
"--format=%(refname:short)"
|
|
41868
|
+
])
|
|
41869
|
+
]);
|
|
41870
|
+
const versionResult = settled[0].status === "fulfilled" ? settled[0].value : {
|
|
41871
|
+
stdout: "",
|
|
41872
|
+
stderr: "",
|
|
41873
|
+
code: 1
|
|
41874
|
+
};
|
|
41875
|
+
const identity = settled[1].status === "fulfilled" ? settled[1].value : {
|
|
41876
|
+
name: void 0,
|
|
41877
|
+
email: void 0
|
|
41878
|
+
};
|
|
41879
|
+
const lastCommitResult = settled[2].status === "fulfilled" ? settled[2].value : {
|
|
41880
|
+
stdout: "",
|
|
41881
|
+
stderr: "",
|
|
41882
|
+
code: 1
|
|
41883
|
+
};
|
|
41884
|
+
const lastTagResult = settled[3].status === "fulfilled" ? settled[3].value : {
|
|
41885
|
+
stdout: "",
|
|
41886
|
+
stderr: "",
|
|
41887
|
+
code: 1
|
|
41888
|
+
};
|
|
41889
|
+
const versionLine = versionResult.code === 0 ? `${versionResult.stdout.trim()} (\u2713)` : "(not detected)";
|
|
41890
|
+
const identityLine = identity.name && identity.email ? `${identity.name} <${identity.email}> (\u2713)` : "(not configured)";
|
|
41891
|
+
const lastCommit = lastCommitResult.code === 0 && lastCommitResult.stdout.trim() ? lastCommitResult.stdout.trim() : "(none yet)";
|
|
41892
|
+
const lastTag = lastTagResult.code === 0 && lastTagResult.stdout.trim() ? lastTagResult.stdout.trim() : "(none yet)";
|
|
41893
|
+
writeInfo(`Git integration: enabled`);
|
|
41894
|
+
writeInfo(`Project repo: ${process.cwd()}`);
|
|
41895
|
+
writeInfo(`Git binary: ${versionLine}`);
|
|
41896
|
+
writeInfo(`User identity: ${identityLine}`);
|
|
41897
|
+
writeInfo(`Last lua commit: ${lastCommit}`);
|
|
41898
|
+
writeInfo(`Last lua tag: ${lastTag}`);
|
|
41899
|
+
trackEvent("cli_git_status_completed", {
|
|
41900
|
+
enabled: true
|
|
41901
|
+
});
|
|
41902
|
+
}, "git status");
|
|
41903
|
+
}
|
|
41904
|
+
__name(gitStatusCommand, "gitStatusCommand");
|
|
41905
|
+
|
|
41906
|
+
// src/commands/pull.ts
|
|
41907
|
+
init_cli();
|
|
41908
|
+
init_command_utils();
|
|
41909
|
+
init_analytics();
|
|
41910
|
+
init_backup_api_service();
|
|
41911
|
+
init_constants();
|
|
41912
|
+
async function pullCommand(options = {}) {
|
|
41913
|
+
return withErrorHandling(async () => {
|
|
41914
|
+
const { apiKey, agentId } = await initializeCommand();
|
|
41915
|
+
const force = Boolean(options.force);
|
|
41916
|
+
if (options.version) {
|
|
41917
|
+
await assertVersioningEnabled(apiKey, agentId);
|
|
41918
|
+
const version = parseVersion2(options.version);
|
|
41919
|
+
const api = new AgentVersionApi(BASE_URLS.API, apiKey, agentId);
|
|
41920
|
+
const response = await api.getVersion(version);
|
|
41921
|
+
if (!response.success || !response.data) {
|
|
41922
|
+
throw new Error(response.error?.message ?? `Version v${version} not found`);
|
|
41923
|
+
}
|
|
41924
|
+
const sourceManifestVersion = response.data.sourceManifestVersion;
|
|
41925
|
+
if (sourceManifestVersion == null) {
|
|
41926
|
+
throw new Error(`Version v${version} has no source backup linked. Cannot pull source for this version.`);
|
|
41927
|
+
}
|
|
41928
|
+
writeInfo(`Pulling source for agent version v${version} (backup v${sourceManifestVersion})\u2026`);
|
|
41929
|
+
await sourceRollbackCommand({
|
|
41930
|
+
version: sourceManifestVersion,
|
|
41931
|
+
force,
|
|
41932
|
+
silent: true
|
|
41933
|
+
});
|
|
41934
|
+
try {
|
|
41935
|
+
await tryGitCommit({
|
|
41936
|
+
message: GIT_MESSAGES.pullVersion(version),
|
|
41937
|
+
action: "pull-version"
|
|
41938
|
+
});
|
|
41939
|
+
} catch {
|
|
41940
|
+
}
|
|
41941
|
+
trackEvent("cli_pull_completed", {
|
|
41942
|
+
has_version_arg: true
|
|
41943
|
+
});
|
|
41944
|
+
return;
|
|
41945
|
+
}
|
|
41946
|
+
const backupApi = new BackupApi(BASE_URLS.API, apiKey, agentId);
|
|
41947
|
+
const backupResp = await backupApi.getBackupVersions();
|
|
41948
|
+
if (!backupResp.success || !backupResp.data?.versions?.length) {
|
|
41949
|
+
throw new Error("No backup versions available to pull.");
|
|
41950
|
+
}
|
|
41951
|
+
const latest = backupResp.data.versions[0].version;
|
|
41952
|
+
writeInfo(`Pulling latest source backup (v${latest})\u2026`);
|
|
41953
|
+
await sourceRollbackCommand({
|
|
41954
|
+
version: latest,
|
|
41955
|
+
force,
|
|
41956
|
+
silent: true
|
|
41957
|
+
});
|
|
41958
|
+
try {
|
|
41959
|
+
await tryGitCommit({
|
|
41960
|
+
message: GIT_MESSAGES.pullLatest,
|
|
41961
|
+
action: "pull-latest"
|
|
41962
|
+
});
|
|
41963
|
+
} catch {
|
|
41964
|
+
}
|
|
41965
|
+
trackEvent("cli_pull_completed", {
|
|
41966
|
+
has_version_arg: false
|
|
41967
|
+
});
|
|
41968
|
+
}, "pull");
|
|
41969
|
+
}
|
|
41970
|
+
__name(pullCommand, "pullCommand");
|
|
41971
|
+
|
|
40426
41972
|
// src/cli/command-definitions.ts
|
|
40427
41973
|
init_cli();
|
|
40428
41974
|
function setupAuthCommands(program2) {
|
|
@@ -41051,6 +42597,50 @@ Examples:
|
|
|
41051
42597
|
$ lua voice test --runner vitest Force vitest
|
|
41052
42598
|
`).action(voiceTestCommand);
|
|
41053
42599
|
voice.command("list").description("List LuaVoice primitives in the compiled manifest").option("--json", "Output as JSON").action(voiceListCommand);
|
|
42600
|
+
const versionGroup = program2.command("version").description("\u{1F3F7}\uFE0F Manage agent versions (atomic snapshots of agent state)");
|
|
42601
|
+
versionGroup.command("create").description("Snapshot current staged state into a new version").option("-m, --message <message>", "Optional description for this version").option("--auto-push", "Push first if local changes are not yet staged").option("--commit-hash <hash>", "Optional git commit hash to associate with this version").addHelpText("after", `
|
|
42602
|
+
Examples:
|
|
42603
|
+
$ lua version create Snapshot current state
|
|
42604
|
+
$ lua version create -m "Add FAQ skill" Include a description
|
|
42605
|
+
$ lua version create --auto-push Push then snapshot in one step
|
|
42606
|
+
`).action((opts) => versionCreateCommand(opts));
|
|
42607
|
+
versionGroup.command("list").description("List versions of the current agent").option("--all", "Show all versions (no server-side cap)").option("--limit <n>", "Cap output to this many entries", (v) => parseInt(v, 10)).option("--status <status>", "Filter by status: active | staged | all", "all").option("--json", "Output as JSON").addHelpText("after", `
|
|
42608
|
+
Examples:
|
|
42609
|
+
$ lua version list List all versions (default)
|
|
42610
|
+
$ lua version list --status active Show only active versions
|
|
42611
|
+
$ lua version list --limit 10 Show the 10 most recent
|
|
42612
|
+
$ lua version list --json Machine-readable output
|
|
42613
|
+
`).action((opts) => versionListCommand(opts));
|
|
42614
|
+
versionGroup.command("show <version>").description("Show full snapshot of a specific version").option("--json", "Output as JSON").addHelpText("after", `
|
|
42615
|
+
Examples:
|
|
42616
|
+
$ lua version show 3 Show version 3 details
|
|
42617
|
+
$ lua version show v3 --json JSON output
|
|
42618
|
+
`).action((version, opts) => versionShowCommand(version, opts));
|
|
42619
|
+
versionGroup.command("diff <from> <to>").description("Compare two versions side-by-side").option("--json", "Output diff as JSON").addHelpText("after", `
|
|
42620
|
+
Examples:
|
|
42621
|
+
$ lua version diff 2 3 Compare v2 \u2192 v3
|
|
42622
|
+
$ lua version diff v2 v3 --json Machine-readable diff
|
|
42623
|
+
`).action((from, to, opts) => versionDiffCommand(from, to, opts));
|
|
42624
|
+
versionGroup.command("promote <version>").description("Promote a version to active (atomic, instant)").addHelpText("after", `
|
|
42625
|
+
Examples:
|
|
42626
|
+
$ lua version promote 3 Promote v3 to the active version
|
|
42627
|
+
$ lua version promote v3 Same (v-prefix accepted)
|
|
42628
|
+
`).action((version) => versionPromoteCommand(version));
|
|
42629
|
+
versionGroup.command("delete <version>").description("Soft-delete a version").option("--force", "Skip confirmation prompt").addHelpText("after", `
|
|
42630
|
+
Examples:
|
|
42631
|
+
$ lua version delete 3 Delete v3 (confirms first)
|
|
42632
|
+
$ lua version delete v3 --force Skip confirmation
|
|
42633
|
+
`).action((version, opts) => versionDeleteCommand(version, opts));
|
|
42634
|
+
const gitGroup = program2.command("git").description("Manage opt-in git auto-commits for this project");
|
|
42635
|
+
gitGroup.command("connect").description("Enable git auto-commits (runs sanity checks, writes git.enabled: true)").action(() => gitConnectCommand());
|
|
42636
|
+
gitGroup.command("disconnect").description("Disable git auto-commits (existing commits/tags untouched)").action(() => gitDisconnectCommand());
|
|
42637
|
+
gitGroup.command("status").description("Show git integration config + last lua-issued commit/tag").action(() => gitStatusCommand());
|
|
42638
|
+
program2.command("pull").description("\u{1F4E5} Pull the agent's source code locally").option("--version <version>", "Pull source linked to a specific agent version (requires versioning)").option("--force", "Skip confirmation prompt").addHelpText("after", `
|
|
42639
|
+
Examples:
|
|
42640
|
+
$ lua pull Restore the latest source backup
|
|
42641
|
+
$ lua pull --version 3 Restore the source snapshot from agent version 3
|
|
42642
|
+
$ lua pull --version v3 --force Skip the confirmation prompt
|
|
42643
|
+
`).action((opts) => pullCommand(opts));
|
|
41054
42644
|
const sourceCmd = program2.command("source").description("\u{1F5C2}\uFE0F Manage workspace source versions");
|
|
41055
42645
|
sourceCmd.command("list").description("List source versions for the current agent").option("--all", "Show all versions instead of the most recent 50", false).option("--limit <n>", "Number of versions to show", "50").addHelpText("after", `
|
|
41056
42646
|
Examples:
|