lua-cli 3.16.2 → 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/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 BackupApi(BASE_URLS.API, apiKey, agentId);
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) {
@@ -5053,11 +5067,11 @@ var init_mcp_server_plugin = __esm({
5053
5067
  // ../shared-source-sync/dist/index.mjs
5054
5068
  import { createHash } from "crypto";
5055
5069
  import { extname } from "path";
5056
- import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync2 } from "fs";
5070
+ import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync2 } from "fs";
5057
5071
  import { join as join4, sep } from "path";
5058
5072
  import { gunzipSync, gzipSync } from "zlib";
5059
- import { existsSync as existsSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync22, statSync as statSync22, writeFileSync as writeFileSync5 } from "fs";
5060
- import { dirname as dirname3, join as join22, resolve, sep as sep2 } from "path";
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";
5061
5075
  import { mkdirSync as mkdirSync22, readdirSync as readdirSync22, readFileSync as readFileSync32, statSync as statSync3, writeFileSync as writeFileSync22 } from "fs";
5062
5076
  import { dirname as dirname22, join as join32, sep as sep3 } from "path";
5063
5077
  import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "zlib";
@@ -5117,7 +5131,7 @@ function walkWorkspace(rootDir, opts = {}) {
5117
5131
  if (stats.size > maxBytes) continue;
5118
5132
  let content;
5119
5133
  try {
5120
- content = readFileSync6(abs);
5134
+ content = readFileSync7(abs);
5121
5135
  } catch {
5122
5136
  continue;
5123
5137
  }
@@ -5234,10 +5248,10 @@ function restoreFromBlobs(manifest, blobs, targetDir, opts = {}) {
5234
5248
  continue;
5235
5249
  }
5236
5250
  }
5237
- mkdirSync5(dirname3(targetPath), {
5251
+ mkdirSync6(dirname4(targetPath), {
5238
5252
  recursive: true
5239
5253
  });
5240
- writeFileSync5(targetPath, content);
5254
+ writeFileSync6(targetPath, content);
5241
5255
  filesWritten++;
5242
5256
  }
5243
5257
  return {
@@ -5432,12 +5446,12 @@ var init_dist2 = __esm({
5432
5446
  this.options = options;
5433
5447
  this.fetchFn = options.fetch ?? fetch;
5434
5448
  }
5435
- url(path18) {
5449
+ url(path19) {
5436
5450
  const base = this.options.baseUrl.replace(/\/$/, "");
5437
- return `${base}/developer/agents/${encodeURIComponent(this.options.agentId)}${path18}`;
5451
+ return `${base}/developer/agents/${encodeURIComponent(this.options.agentId)}${path19}`;
5438
5452
  }
5439
- async json(method, path18, body) {
5440
- const endpoint = this.url(path18);
5453
+ async json(method, path19, body) {
5454
+ const endpoint = this.url(path19);
5441
5455
  const res = await this.fetchFn(endpoint, {
5442
5456
  method,
5443
5457
  headers: {
@@ -5456,7 +5470,7 @@ var init_dist2 = __esm({
5456
5470
  } catch {
5457
5471
  text2 = void 0;
5458
5472
  }
5459
- throw new BackupHttpError(`Backup request failed: ${method} ${path18} \u2192 ${res.status} ${res.statusText}`, res.status, endpoint, text2);
5473
+ throw new BackupHttpError(`Backup request failed: ${method} ${path19} \u2192 ${res.status} ${res.statusText}`, res.status, endpoint, text2);
5460
5474
  }
5461
5475
  const text = await res.text();
5462
5476
  if (!text) return void 0;
@@ -5523,16 +5537,16 @@ var init_dist2 = __esm({
5523
5537
  });
5524
5538
 
5525
5539
  // src/compiler/utils/common.ts
5526
- import path3 from "path";
5540
+ import path4 from "path";
5527
5541
  function hashContent(content) {
5528
5542
  return hashContentTruncated(content);
5529
5543
  }
5530
5544
  function isInside(child, parent) {
5531
- const resolvedChild = path3.resolve(child);
5532
- const resolvedParent = path3.resolve(parent);
5545
+ const resolvedChild = path4.resolve(child);
5546
+ const resolvedParent = path4.resolve(parent);
5533
5547
  if (resolvedChild === resolvedParent) return true;
5534
- const rel = path3.relative(resolvedParent, resolvedChild);
5535
- return !!rel && !rel.startsWith("..") && !path3.isAbsolute(rel);
5548
+ const rel = path4.relative(resolvedParent, resolvedChild);
5549
+ return !!rel && !rel.startsWith("..") && !path4.isAbsolute(rel);
5536
5550
  }
5537
5551
  function classifyProjectFile(name) {
5538
5552
  if (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js")) {
@@ -5561,20 +5575,20 @@ var init_common = __esm({
5561
5575
  });
5562
5576
 
5563
5577
  // src/compiler/utils/path-resolver.ts
5564
- import * as fs3 from "fs";
5565
- import * as path4 from "path";
5578
+ import * as fs4 from "fs";
5579
+ import * as path5 from "path";
5566
5580
  function getTsConfigPathMappings(rootDir) {
5567
- const resolvedRoot = path4.resolve(rootDir);
5581
+ const resolvedRoot = path5.resolve(rootDir);
5568
5582
  if (mappingsCache.has(resolvedRoot)) {
5569
5583
  return mappingsCache.get(resolvedRoot) ?? null;
5570
5584
  }
5571
- const tsconfigPath = path4.join(resolvedRoot, "tsconfig.json");
5572
- if (!fs3.existsSync(tsconfigPath)) {
5585
+ const tsconfigPath = path5.join(resolvedRoot, "tsconfig.json");
5586
+ if (!fs4.existsSync(tsconfigPath)) {
5573
5587
  mappingsCache.set(resolvedRoot, null);
5574
5588
  return null;
5575
5589
  }
5576
5590
  try {
5577
- const tsconfigContent = fs3.readFileSync(tsconfigPath, "utf-8");
5591
+ const tsconfigContent = fs4.readFileSync(tsconfigPath, "utf-8");
5578
5592
  const tsconfig = JSON.parse(tsconfigContent);
5579
5593
  const compilerOptions = tsconfig.compilerOptions || {};
5580
5594
  if (compilerOptions.paths) {
@@ -5601,7 +5615,7 @@ function resolvePathAlias(specifier, rootDir) {
5601
5615
  if (match) {
5602
5616
  const captured = match[1] || "";
5603
5617
  const targetPath = targets[0].replace("*", captured);
5604
- return path4.join(mappings.rootDir, mappings.baseUrl, targetPath);
5618
+ return path5.join(mappings.rootDir, mappings.baseUrl, targetPath);
5605
5619
  }
5606
5620
  }
5607
5621
  return null;
@@ -5613,20 +5627,20 @@ function resolveModuleSpecifier(specifier, fromFile, rootDir) {
5613
5627
  return tryExtensions(aliasResolved);
5614
5628
  }
5615
5629
  if (normalized.startsWith("./") || normalized.startsWith("../")) {
5616
- const basePath = path4.resolve(path4.dirname(fromFile), normalized);
5630
+ const basePath = path5.resolve(path5.dirname(fromFile), normalized);
5617
5631
  return tryExtensions(basePath);
5618
5632
  }
5619
5633
  return void 0;
5620
5634
  }
5621
5635
  function tryExtensions(basePath) {
5622
5636
  for (const ext of MODULE_EXTENSIONS) {
5623
- const full = ext.startsWith("/") ? path4.join(basePath, ext) : basePath + ext;
5624
- if (fs3.existsSync(full)) return full;
5637
+ const full = ext.startsWith("/") ? path5.join(basePath, ext) : basePath + ext;
5638
+ if (fs4.existsSync(full)) return full;
5625
5639
  }
5626
5640
  return void 0;
5627
5641
  }
5628
5642
  function registerProjectRootDir(project, rootDir) {
5629
- projectRootDirs.set(project, path4.resolve(rootDir));
5643
+ projectRootDirs.set(project, path5.resolve(rootDir));
5630
5644
  }
5631
5645
  function getProjectRootDir(project) {
5632
5646
  return projectRootDirs.get(project);
@@ -6226,7 +6240,7 @@ var init_reference_resolver = __esm({
6226
6240
  });
6227
6241
 
6228
6242
  // src/compiler/plugins/skill.plugin.ts
6229
- import fs4 from "fs/promises";
6243
+ import fs5 from "fs/promises";
6230
6244
  import { Node as Node11 } from "ts-morph";
6231
6245
  function findEnclosingVariableDeclaration(config) {
6232
6246
  let current = config.getParent();
@@ -6559,7 +6573,7 @@ var init_skill_plugin = __esm({
6559
6573
  description: metadata.description,
6560
6574
  metadata: this.sanitizeForPersistence(metadata.metadata)
6561
6575
  }, null, 2);
6562
- const originalSource = await fs4.readFile(metadata.sourcePath, "utf-8");
6576
+ const originalSource = await fs5.readFile(metadata.sourcePath, "utf-8");
6563
6577
  return {
6564
6578
  code,
6565
6579
  sourceMap: "",
@@ -7313,10 +7327,10 @@ var init_device_trigger_plugin = __esm({
7313
7327
  });
7314
7328
 
7315
7329
  // src/compiler/utils/primitive-rewrite.ts
7316
- import { readFileSync as readFileSync8 } from "fs";
7330
+ import { readFileSync as readFileSync9 } from "fs";
7317
7331
  import { Node as Node14, Project, ts as ts3 } from "ts-morph";
7318
7332
  function rewritePrimitiveSource(metadata, opts) {
7319
- const sourceCode = readFileSync8(metadata.sourcePath, "utf-8");
7333
+ const sourceCode = readFileSync9(metadata.sourcePath, "utf-8");
7320
7334
  const localProject = new Project({
7321
7335
  useInMemoryFileSystem: true,
7322
7336
  compilerOptions: {
@@ -7655,7 +7669,7 @@ var init_cross_file_specs = __esm({
7655
7669
  });
7656
7670
 
7657
7671
  // src/compiler/plugins/voice.plugin.ts
7658
- import fs5 from "fs/promises";
7672
+ import fs6 from "fs/promises";
7659
7673
  import { Node as Node15 } from "ts-morph";
7660
7674
  function astObjectToPlain(obj) {
7661
7675
  const result = {};
@@ -8196,8 +8210,8 @@ var init_voice_plugin = __esm({
8196
8210
  }, "isMissingTopLevelRequired");
8197
8211
  for (const issue of parsed.error.issues) {
8198
8212
  if (isMissingTopLevelRequired(issue)) continue;
8199
- const path18 = issue.path.length > 0 ? issue.path.join(".") : "<root>";
8200
- errors.push(validationError(`Voice config invalid at \`${path18}\`: ${issue.message}`, {
8213
+ const path19 = issue.path.length > 0 ? issue.path.join(".") : "<root>";
8214
+ errors.push(validationError(`Voice config invalid at \`${path19}\`: ${issue.message}`, {
8201
8215
  line
8202
8216
  }));
8203
8217
  }
@@ -8278,7 +8292,7 @@ var init_voice_plugin = __esm({
8278
8292
  description: metadata.description,
8279
8293
  metadata: sanitized
8280
8294
  }, null, 2);
8281
- const originalSource = await fs5.readFile(metadata.sourcePath, "utf-8");
8295
+ const originalSource = await fs6.readFile(metadata.sourcePath, "utf-8");
8282
8296
  return {
8283
8297
  code,
8284
8298
  sourceMap: "",
@@ -8431,8 +8445,8 @@ var init_registry = __esm({
8431
8445
  });
8432
8446
 
8433
8447
  // src/compiler/bundler.ts
8434
- import fs6 from "fs/promises";
8435
- import path5 from "path";
8448
+ import fs7 from "fs/promises";
8449
+ import path6 from "path";
8436
8450
  import crypto4 from "crypto";
8437
8451
  import { build } from "esbuild";
8438
8452
  var Bundler;
@@ -8501,9 +8515,9 @@ var init_bundler = __esm({
8501
8515
  * Bundle a primitive's entry point using esbuild.
8502
8516
  */
8503
8517
  async bundle(metadata, entryPointCode) {
8504
- const tempDir = path5.join(this.options.outDir, ".temp");
8505
- const outfile = path5.join(tempDir, `${metadata.kind}-${metadata.name}.bundle.js`);
8506
- const sourceDir = path5.dirname(metadata.sourcePath);
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);
8507
8521
  if (this.options.debug) {
8508
8522
  this.verbose(` Source: ${metadata.sourcePath}`);
8509
8523
  this.verbose(` Output: ${outfile}`);
@@ -8533,15 +8547,15 @@ var init_bundler = __esm({
8533
8547
  ],
8534
8548
  logLevel: this.options.debug ? "debug" : "silent"
8535
8549
  });
8536
- const code = await fs6.readFile(outfile, "utf-8");
8550
+ const code = await fs7.readFile(outfile, "utf-8");
8537
8551
  let sourceMap = "";
8538
8552
  try {
8539
- sourceMap = await fs6.readFile(outfile + ".map", "utf-8");
8553
+ sourceMap = await fs7.readFile(outfile + ".map", "utf-8");
8540
8554
  } catch {
8541
8555
  }
8542
- const originalSource = await fs6.readFile(metadata.sourcePath, "utf-8");
8556
+ const originalSource = await fs7.readFile(metadata.sourcePath, "utf-8");
8543
8557
  const hash = crypto4.createHash("sha256").update(code).digest("hex").slice(0, 16);
8544
- const stats = await fs6.stat(outfile);
8558
+ const stats = await fs7.stat(outfile);
8545
8559
  return {
8546
8560
  code,
8547
8561
  sourceMap,
@@ -8558,14 +8572,14 @@ var init_bundler = __esm({
8558
8572
  const bundler = this;
8559
8573
  const sourcePath = metadata.sourcePath;
8560
8574
  const exportName = metadata.exportName;
8561
- const sourceDir = path5.dirname(sourcePath);
8575
+ const sourceDir = path6.dirname(sourcePath);
8562
8576
  return {
8563
8577
  name: "lua-virtual-source",
8564
8578
  setup(build2) {
8565
8579
  build2.onResolve({
8566
8580
  filter: /.*/
8567
8581
  }, (args2) => {
8568
- const resolved = args2.path.startsWith(".") ? path5.resolve(args2.resolveDir, args2.path) : args2.path;
8582
+ const resolved = args2.path.startsWith(".") ? path6.resolve(args2.resolveDir, args2.path) : args2.path;
8569
8583
  const normalizedResolved = resolved.replace(/\.(ts|tsx|js|jsx)$/, "");
8570
8584
  const normalizedSource = sourcePath.replace(/\.(ts|tsx|js|jsx)$/, "");
8571
8585
  if (normalizedResolved === normalizedSource) {
@@ -8581,8 +8595,8 @@ var init_bundler = __esm({
8581
8595
  namespace: "lua-virtual-source"
8582
8596
  }, async () => {
8583
8597
  const sourceFile = bundler.project.getSourceFile(sourcePath);
8584
- let content = sourceFile?.getText() ?? await fs6.readFile(sourcePath, "utf-8");
8585
- content = bundler.stripLuaCliImportsAST(content, path5.basename(sourcePath));
8598
+ let content = sourceFile?.getText() ?? await fs7.readFile(sourcePath, "utf-8");
8599
+ content = bundler.stripLuaCliImportsAST(content, path6.basename(sourcePath));
8586
8600
  const virtualContent = metadata.isDefaultExport ? content : `${content}
8587
8601
  export { ${exportName} as __lua_target__ };
8588
8602
  `;
@@ -8610,17 +8624,17 @@ export { ${exportName} as __lua_target__ };
8610
8624
  namespace: "file"
8611
8625
  }, async (args2) => {
8612
8626
  if (args2.path.includes("node_modules")) return null;
8613
- const contents = await fs6.readFile(args2.path, "utf-8");
8627
+ const contents = await fs7.readFile(args2.path, "utf-8");
8614
8628
  if (!contents.includes("lua-cli") && !contents.includes("api-exports")) {
8615
8629
  return null;
8616
8630
  }
8617
8631
  try {
8618
- const modifiedContents = stripImports(contents, path5.basename(args2.path));
8632
+ const modifiedContents = stripImports(contents, path6.basename(args2.path));
8619
8633
  if (modifiedContents !== contents) {
8620
8634
  return {
8621
8635
  contents: modifiedContents,
8622
8636
  loader: args2.path.endsWith(".ts") || args2.path.endsWith(".tsx") ? "ts" : "js",
8623
- resolveDir: path5.dirname(args2.path)
8637
+ resolveDir: path6.dirname(args2.path)
8624
8638
  };
8625
8639
  }
8626
8640
  return null;
@@ -8657,8 +8671,8 @@ export { ${exportName} as __lua_target__ };
8657
8671
 
8658
8672
  // src/compiler/agent-traverser.ts
8659
8673
  import { Project as Project2, Node as Node16 } from "ts-morph";
8660
- import path6 from "path";
8661
- import fs7 from "fs";
8674
+ import path7 from "path";
8675
+ import fs8 from "fs";
8662
8676
  var PRIMITIVE_TYPES, AgentTraverser;
8663
8677
  var init_agent_traverser = __esm({
8664
8678
  "src/compiler/agent-traverser.ts"() {
@@ -8731,7 +8745,7 @@ var init_agent_traverser = __esm({
8731
8745
  this.rootDir = rootDir;
8732
8746
  this.debug = debug;
8733
8747
  this.project = new Project2({
8734
- tsConfigFilePath: path6.join(rootDir, "tsconfig.json"),
8748
+ tsConfigFilePath: path7.join(rootDir, "tsconfig.json"),
8735
8749
  skipAddingFilesFromTsConfig: true
8736
8750
  });
8737
8751
  registerProjectRootDir(this.project, this.rootDir);
@@ -8815,15 +8829,15 @@ var init_agent_traverser = __esm({
8815
8829
  */
8816
8830
  detectAgent() {
8817
8831
  const priorityFiles = [
8818
- path6.join(this.rootDir, "index.ts"),
8819
- path6.join(this.rootDir, "src", "index.ts"),
8820
- path6.join(this.rootDir, "agent.ts"),
8821
- path6.join(this.rootDir, "src", "agent.ts"),
8822
- path6.join(this.rootDir, "main.ts"),
8823
- path6.join(this.rootDir, "src", "main.ts")
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")
8824
8838
  ];
8825
8839
  for (const filePath of priorityFiles) {
8826
- if (fs7.existsSync(filePath)) {
8840
+ if (fs8.existsSync(filePath)) {
8827
8841
  try {
8828
8842
  const sourceFile = this.project.addSourceFileAtPath(filePath);
8829
8843
  const agent = this.detectAgentInFile(sourceFile);
@@ -8975,7 +8989,7 @@ var init_agent_traverser = __esm({
8975
8989
  console.warn(formatSarifWarning({
8976
8990
  ruleId: "lua/missing-primitive-declaration",
8977
8991
  filePath: sourcePath,
8978
- message: `agent references ${kind} "${refName}" but ${path6.basename(sourcePath)} does not define a matching primitive`,
8992
+ message: `agent references ${kind} "${refName}" but ${path7.basename(sourcePath)} does not define a matching primitive`,
8979
8993
  hint: `export a named ${plugin.displayName.toLowerCase()} declaration as "${refName}", or adjust the import so it points to the file that does`
8980
8994
  }));
8981
8995
  return null;
@@ -8995,20 +9009,20 @@ var init_agent_traverser = __esm({
8995
9009
  });
8996
9010
 
8997
9011
  // src/compiler/utils/workspace.ts
8998
- import fs8 from "fs";
8999
- import path7 from "path";
9012
+ import fs9 from "fs";
9013
+ import path8 from "path";
9000
9014
  function findWorkspaceRoot(rootDir) {
9001
- const resolvedInput = path7.resolve(rootDir);
9015
+ const resolvedInput = path8.resolve(rootDir);
9002
9016
  const cached = workspaceRootCache.get(resolvedInput);
9003
9017
  if (cached !== void 0) return cached;
9004
9018
  let current = resolvedInput;
9005
- const { root } = path7.parse(current);
9019
+ const { root } = path8.parse(current);
9006
9020
  while (true) {
9007
9021
  if (isWorkspaceRoot(current)) {
9008
9022
  workspaceRootCache.set(resolvedInput, current);
9009
9023
  return current;
9010
9024
  }
9011
- const parent = path7.dirname(current);
9025
+ const parent = path8.dirname(current);
9012
9026
  if (parent === current || current === root) break;
9013
9027
  current = parent;
9014
9028
  }
@@ -9016,22 +9030,22 @@ function findWorkspaceRoot(rootDir) {
9016
9030
  return resolvedInput;
9017
9031
  }
9018
9032
  function isWorkspaceRoot(dir) {
9019
- if (fileExists(path7.join(dir, "pnpm-workspace.yaml"))) return true;
9020
- if (fileExists(path7.join(dir, "lerna.json"))) return true;
9021
- if (packageJsonHasWorkspaces(path7.join(dir, "package.json"))) return true;
9022
- if (dirExists(path7.join(dir, ".git"))) return true;
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;
9023
9037
  return false;
9024
9038
  }
9025
9039
  function fileExists(p) {
9026
9040
  try {
9027
- return fs8.statSync(p).isFile();
9041
+ return fs9.statSync(p).isFile();
9028
9042
  } catch {
9029
9043
  return false;
9030
9044
  }
9031
9045
  }
9032
9046
  function dirExists(p) {
9033
9047
  try {
9034
- return fs8.statSync(p).isDirectory();
9048
+ return fs9.statSync(p).isDirectory();
9035
9049
  } catch {
9036
9050
  return false;
9037
9051
  }
@@ -9039,7 +9053,7 @@ function dirExists(p) {
9039
9053
  function packageJsonHasWorkspaces(pkgPath) {
9040
9054
  if (!fileExists(pkgPath)) return false;
9041
9055
  try {
9042
- const raw = fs8.readFileSync(pkgPath, "utf-8");
9056
+ const raw = fs9.readFileSync(pkgPath, "utf-8");
9043
9057
  const json = JSON.parse(raw);
9044
9058
  if (!json.workspaces) return false;
9045
9059
  return Array.isArray(json.workspaces) || typeof json.workspaces === "object";
@@ -9061,8 +9075,8 @@ var init_workspace = __esm({
9061
9075
  });
9062
9076
 
9063
9077
  // src/compiler/compiler.ts
9064
- import fs9 from "fs/promises";
9065
- import path8 from "path";
9078
+ import fs10 from "fs/promises";
9079
+ import path9 from "path";
9066
9080
  import { Project as Project3 } from "ts-morph";
9067
9081
  async function compile(options) {
9068
9082
  const compiler = new Compiler(options);
@@ -9115,7 +9129,7 @@ var init_compiler = __esm({
9115
9129
  ...options
9116
9130
  };
9117
9131
  this.project = new Project3({
9118
- tsConfigFilePath: path8.join(options.rootDir, "tsconfig.json")
9132
+ tsConfigFilePath: path9.join(options.rootDir, "tsconfig.json")
9119
9133
  });
9120
9134
  registerProjectRootDir(this.project, this.options.rootDir);
9121
9135
  this.bundler = new Bundler({
@@ -9192,10 +9206,10 @@ var init_compiler = __esm({
9192
9206
  return await this.createResult(false, [], errors, warnings, startTime);
9193
9207
  }
9194
9208
  this.verbose("\u{1F4E6} Bundling primitives...");
9195
- await fs9.mkdir(this.options.outDir, {
9209
+ await fs10.mkdir(this.options.outDir, {
9196
9210
  recursive: true
9197
9211
  });
9198
- await fs9.mkdir(path8.join(this.options.outDir, ".temp"), {
9212
+ await fs10.mkdir(path9.join(this.options.outDir, ".temp"), {
9199
9213
  recursive: true
9200
9214
  });
9201
9215
  const CONCURRENCY = 4;
@@ -9215,7 +9229,7 @@ var init_compiler = __esm({
9215
9229
  this.verbose("\u{1F4BE} Writing artifacts...");
9216
9230
  await this.writeArtifacts(compiledPrimitives);
9217
9231
  if (!this.options.debug) {
9218
- await fs9.rm(path8.join(this.options.outDir, ".temp"), {
9232
+ await fs10.rm(path9.join(this.options.outDir, ".temp"), {
9219
9233
  recursive: true,
9220
9234
  force: true
9221
9235
  });
@@ -9258,7 +9272,7 @@ var init_compiler = __esm({
9258
9272
  */
9259
9273
  getWorkspaceRoot() {
9260
9274
  if (this._workspaceRoot === void 0) {
9261
- this._workspaceRoot = findWorkspaceRoot(path8.resolve(this.options.rootDir));
9275
+ this._workspaceRoot = findWorkspaceRoot(path9.resolve(this.options.rootDir));
9262
9276
  }
9263
9277
  return this._workspaceRoot;
9264
9278
  }
@@ -9272,18 +9286,18 @@ var init_compiler = __esm({
9272
9286
  * - Files outside the detected workspace root (not our code)
9273
9287
  */
9274
9288
  collectExternalWorkspaceFiles(traverser) {
9275
- const rootDir = path8.resolve(this.options.rootDir);
9289
+ const rootDir = path9.resolve(this.options.rootDir);
9276
9290
  const workspaceRoot = this.getWorkspaceRoot();
9277
9291
  if (workspaceRoot === rootDir) return [];
9278
9292
  const loaded = traverser.getAllLoadedSourceFilePaths();
9279
9293
  const result = [];
9280
9294
  const seen = /* @__PURE__ */ new Set();
9281
9295
  for (const raw of loaded) {
9282
- const abs = path8.resolve(raw);
9296
+ const abs = path9.resolve(raw);
9283
9297
  if (seen.has(abs)) continue;
9284
9298
  seen.add(abs);
9285
9299
  if (isInside(abs, rootDir)) continue;
9286
- if (abs.includes(`${path8.sep}node_modules${path8.sep}`)) continue;
9300
+ if (abs.includes(`${path9.sep}node_modules${path9.sep}`)) continue;
9287
9301
  if (!isInside(abs, workspaceRoot)) continue;
9288
9302
  result.push(abs);
9289
9303
  }
@@ -9416,9 +9430,9 @@ var init_compiler = __esm({
9416
9430
  * @param primitives - All compiled primitives to write
9417
9431
  */
9418
9432
  async writeArtifacts(primitives) {
9419
- const artifactsDir = path8.join(this.options.outDir, "artifacts");
9420
- const sourcesDir = path8.join(this.options.outDir, "sources");
9421
- await fs9.mkdir(sourcesDir, {
9433
+ const artifactsDir = path9.join(this.options.outDir, "artifacts");
9434
+ const sourcesDir = path9.join(this.options.outDir, "sources");
9435
+ await fs10.mkdir(sourcesDir, {
9422
9436
  recursive: true
9423
9437
  });
9424
9438
  const writtenSources = /* @__PURE__ */ new Map();
@@ -9426,7 +9440,7 @@ var init_compiler = __esm({
9426
9440
  this.verbose(" \u{1F4C2} Collecting project files...");
9427
9441
  const projectFiles = await this.storeProjectFiles(sourcesDir, writtenSources);
9428
9442
  const manifest = await this.createManifest(primitives, projectFiles);
9429
- await fs9.writeFile(path8.join(this.options.outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
9443
+ await fs10.writeFile(path9.join(this.options.outDir, "manifest.json"), JSON.stringify(manifest, null, 2));
9430
9444
  this.verbose(` \u{1F4E6} Total files stored: ${writtenSources.size} (deduplicated)`);
9431
9445
  this.verbose(` \u{1F4C1} Project files: ${projectFiles.length}`);
9432
9446
  if (this.options.verbose || this.options.debug) {
@@ -9438,25 +9452,25 @@ var init_compiler = __esm({
9438
9452
  */
9439
9453
  async writePrimitiveArtifacts(primitives, artifactsDir, sourcesDir, writtenSources) {
9440
9454
  for (const primitive of primitives) {
9441
- const primitiveDir = path8.join(artifactsDir, primitive.kind);
9442
- await fs9.mkdir(primitiveDir, {
9455
+ const primitiveDir = path9.join(artifactsDir, primitive.kind);
9456
+ await fs10.mkdir(primitiveDir, {
9443
9457
  recursive: true
9444
9458
  });
9445
9459
  const baseName = primitive.name;
9446
- await fs9.writeFile(path8.join(primitiveDir, `${baseName}.js`), primitive.artifact.code);
9460
+ await fs10.writeFile(path9.join(primitiveDir, `${baseName}.js`), primitive.artifact.code);
9447
9461
  if (primitive.artifact.sourceMap) {
9448
- await fs9.writeFile(path8.join(primitiveDir, `${baseName}.js.map`), primitive.artifact.sourceMap);
9462
+ await fs10.writeFile(path9.join(primitiveDir, `${baseName}.js.map`), primitive.artifact.sourceMap);
9449
9463
  }
9450
9464
  const sourceHash = hashContent(primitive.artifact.originalSource);
9451
9465
  if (!writtenSources.has(sourceHash)) {
9452
9466
  const ext = primitive.sourcePath.endsWith(".tsx") ? ".tsx" : ".ts";
9453
- await fs9.writeFile(path8.join(sourcesDir, `${sourceHash}${ext}`), primitive.artifact.originalSource);
9454
- const relativePath = path8.relative(this.options.rootDir, primitive.sourcePath);
9467
+ await fs10.writeFile(path9.join(sourcesDir, `${sourceHash}${ext}`), primitive.artifact.originalSource);
9468
+ const relativePath = path9.relative(this.options.rootDir, primitive.sourcePath);
9455
9469
  writtenSources.set(sourceHash, relativePath);
9456
9470
  }
9457
9471
  const sidecarPlugin = pluginRegistry.get(primitive.kind);
9458
9472
  const sidecarMetadata = sidecarPlugin?.sanitizeForPersistence ? sidecarPlugin.sanitizeForPersistence(primitive.metadata) : primitive.metadata;
9459
- await fs9.writeFile(path8.join(primitiveDir, `${baseName}.json`), JSON.stringify({
9473
+ await fs10.writeFile(path9.join(primitiveDir, `${baseName}.json`), JSON.stringify({
9460
9474
  kind: primitive.kind,
9461
9475
  name: primitive.name,
9462
9476
  description: primitive.description,
@@ -9478,12 +9492,12 @@ var init_compiler = __esm({
9478
9492
  const allFiles = await this.collectProjectFiles();
9479
9493
  const workspaceRoot = this.getWorkspaceRoot();
9480
9494
  for (const file of allFiles) {
9481
- const absPath = file.external ? path8.join(workspaceRoot, file.relativePath) : path8.join(this.options.rootDir, file.relativePath);
9482
- const content = await fs9.readFile(absPath, "utf-8");
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");
9483
9497
  const hash = hashContent(content);
9484
9498
  if (!writtenSources.has(hash)) {
9485
- const ext = path8.extname(file.relativePath) || ".txt";
9486
- await fs9.writeFile(path8.join(sourcesDir, `${hash}${ext}`), content);
9499
+ const ext = path9.extname(file.relativePath) || ".txt";
9500
+ await fs10.writeFile(path9.join(sourcesDir, `${hash}${ext}`), content);
9487
9501
  writtenSources.set(hash, file.relativePath);
9488
9502
  }
9489
9503
  projectFiles.push({
@@ -9559,12 +9573,12 @@ var init_compiler = __esm({
9559
9573
  async collectProjectFiles() {
9560
9574
  const files = [];
9561
9575
  const scanDir = /* @__PURE__ */ __name(async (dir, relativeBase = "") => {
9562
- const entries = await fs9.readdir(dir, {
9576
+ const entries = await fs10.readdir(dir, {
9563
9577
  withFileTypes: true
9564
9578
  });
9565
9579
  for (const entry of entries) {
9566
9580
  const relativePath = relativeBase ? `${relativeBase}/${entry.name}` : entry.name;
9567
- const fullPath = path8.join(dir, entry.name);
9581
+ const fullPath = path9.join(dir, entry.name);
9568
9582
  if (entry.isDirectory()) {
9569
9583
  if (shouldSkipDirectory(entry.name)) continue;
9570
9584
  await scanDir(fullPath, relativePath);
@@ -9581,10 +9595,10 @@ var init_compiler = __esm({
9581
9595
  const workspaceRoot = this.getWorkspaceRoot();
9582
9596
  const externalSeen = /* @__PURE__ */ new Set();
9583
9597
  for (const abs of this.externalWorkspaceFiles) {
9584
- const rel = path8.relative(workspaceRoot, abs).split(path8.sep).join("/");
9598
+ const rel = path9.relative(workspaceRoot, abs).split(path9.sep).join("/");
9585
9599
  if (!rel || rel.startsWith("..")) continue;
9586
9600
  if (externalSeen.has(rel)) continue;
9587
- const name = path8.basename(abs);
9601
+ const name = path9.basename(abs);
9588
9602
  if (shouldSkipFile(rel) || shouldSkipFile(name)) continue;
9589
9603
  externalSeen.add(rel);
9590
9604
  files.push({
@@ -9685,13 +9699,13 @@ var init_compiler = __esm({
9685
9699
  });
9686
9700
 
9687
9701
  // src/compiler/utils/file-discovery.ts
9688
- import path9 from "path";
9689
- import fs10 from "fs";
9702
+ import path10 from "path";
9703
+ import fs11 from "fs";
9690
9704
  function findEntryPoint(projectDir) {
9691
9705
  const baseDir = projectDir || process.cwd();
9692
9706
  for (const relativePath of ENTRY_POINT_PRIORITY) {
9693
- const fullPath = path9.join(baseDir, relativePath);
9694
- if (fs10.existsSync(fullPath)) {
9707
+ const fullPath = path10.join(baseDir, relativePath);
9708
+ if (fs11.existsSync(fullPath)) {
9695
9709
  return fullPath;
9696
9710
  }
9697
9711
  }
@@ -9728,8 +9742,8 @@ var init_file_discovery = __esm({
9728
9742
 
9729
9743
  // src/compiler/source-writer.ts
9730
9744
  import { Project as Project4, Node as Node17 } from "ts-morph";
9731
- import fs11 from "fs";
9732
- import path10 from "path";
9745
+ import fs12 from "fs";
9746
+ import path11 from "path";
9733
9747
  function resolveEntryPath(options) {
9734
9748
  let indexPath;
9735
9749
  try {
@@ -9741,14 +9755,14 @@ function resolveEntryPath(options) {
9741
9755
  indexPath = entryPoint;
9742
9756
  } else {
9743
9757
  const baseDir = options?.projectDir || process.cwd();
9744
- indexPath = path10.join(baseDir, "src", "index.ts");
9758
+ indexPath = path11.join(baseDir, "src", "index.ts");
9745
9759
  }
9746
9760
  }
9747
9761
  } catch {
9748
9762
  const baseDir = options?.projectDir || process.cwd();
9749
- indexPath = path10.join(baseDir, "src", "index.ts");
9763
+ indexPath = path11.join(baseDir, "src", "index.ts");
9750
9764
  }
9751
- if (!fs11.existsSync(indexPath)) {
9765
+ if (!fs12.existsSync(indexPath)) {
9752
9766
  console.warn(`Warning: Entry file not found at ${indexPath}`);
9753
9767
  return null;
9754
9768
  }
@@ -13738,6 +13752,164 @@ __name(promptAuthMethod, "promptAuthMethod");
13738
13752
 
13739
13753
  // src/commands/configure.ts
13740
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
13741
13913
  async function configureCommand(options = {}) {
13742
13914
  return withErrorHandling(async () => {
13743
13915
  const { apiKey, email, otp } = options;
@@ -13747,11 +13919,13 @@ async function configureCommand(options = {}) {
13747
13919
  authMethod = "api-key";
13748
13920
  nonInteractive = true;
13749
13921
  await handleApiKeyAuthNonInteractive(apiKey);
13922
+ invalidateVersioningModeCache();
13750
13923
  } else if (email) {
13751
13924
  authMethod = "email";
13752
13925
  nonInteractive = true;
13753
13926
  if (otp) {
13754
13927
  await handleEmailOtpVerify(email, otp);
13928
+ invalidateVersioningModeCache();
13755
13929
  } else {
13756
13930
  await handleEmailOtpRequest(email);
13757
13931
  }
@@ -13760,8 +13934,10 @@ async function configureCommand(options = {}) {
13760
13934
  clearPromptLines(2);
13761
13935
  if (authMethod === "api-key") {
13762
13936
  await handleApiKeyAuth();
13937
+ invalidateVersioningModeCache();
13763
13938
  } else if (authMethod === "email") {
13764
13939
  await handleEmailAuth();
13940
+ invalidateVersioningModeCache();
13765
13941
  }
13766
13942
  }
13767
13943
  trackEvent("cli_auth_completed", {
@@ -14433,8 +14609,8 @@ init_compile_constants();
14433
14609
  init_artifact_loader();
14434
14610
  init_backup_api_service();
14435
14611
  init_constants();
14436
- import fs12 from "fs";
14437
- import path11 from "path";
14612
+ import fs13 from "fs";
14613
+ import path12 from "path";
14438
14614
  var BACKUP_CACHE_FILENAME = "backup-manifest.json";
14439
14615
  function calculateProjectHash(projectFiles) {
14440
14616
  return combineFileHashes(projectFiles);
@@ -14447,11 +14623,11 @@ function getCurrentProjectHash(projectPath = process.cwd()) {
14447
14623
  }
14448
14624
  __name(getCurrentProjectHash, "getCurrentProjectHash");
14449
14625
  function loadSourceByHash(hash, relativePath, projectPath = process.cwd()) {
14450
- const sourcesDir = path11.join(projectPath, COMPILE_DIRS.DIST_V2, "sources");
14451
- const ext = path11.extname(relativePath) || ".txt";
14452
- const sourcePath = path11.join(sourcesDir, `${hash}${ext}`);
14453
- if (fs12.existsSync(sourcePath)) {
14454
- return fs12.readFileSync(sourcePath, "utf-8");
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");
14455
14631
  }
14456
14632
  return null;
14457
14633
  }
@@ -14470,30 +14646,30 @@ function prepareFileRefs(projectPath = process.cwd()) {
14470
14646
  }
14471
14647
  __name(prepareFileRefs, "prepareFileRefs");
14472
14648
  function reconcileManifestWithDisk(projectPath = process.cwd()) {
14473
- const manifestPath = path11.join(projectPath, COMPILE_DIRS.DIST_V2, "manifest.json");
14474
- if (!fs12.existsSync(manifestPath)) return;
14649
+ const manifestPath = path12.join(projectPath, COMPILE_DIRS.DIST_V2, "manifest.json");
14650
+ if (!fs13.existsSync(manifestPath)) return;
14475
14651
  const manifest = loadManifest(projectPath);
14476
- const sourcesDir = path11.join(projectPath, COMPILE_DIRS.DIST_V2, "sources");
14477
- fs12.mkdirSync(sourcesDir, {
14652
+ const sourcesDir = path12.join(projectPath, COMPILE_DIRS.DIST_V2, "sources");
14653
+ fs13.mkdirSync(sourcesDir, {
14478
14654
  recursive: true
14479
14655
  });
14480
14656
  let changed = false;
14481
14657
  for (const file of manifest.projectFiles) {
14482
14658
  if (file.external) continue;
14483
- const absPath = path11.join(projectPath, file.relativePath);
14484
- if (!fs12.existsSync(absPath)) continue;
14659
+ const absPath = path12.join(projectPath, file.relativePath);
14660
+ if (!fs13.existsSync(absPath)) continue;
14485
14661
  let content;
14486
14662
  try {
14487
- content = fs12.readFileSync(absPath, "utf-8");
14663
+ content = fs13.readFileSync(absPath, "utf-8");
14488
14664
  } catch {
14489
14665
  continue;
14490
14666
  }
14491
14667
  const freshHash = hashContent(content);
14492
14668
  if (freshHash === file.hash) continue;
14493
- const ext = path11.extname(file.relativePath) || ".txt";
14494
- const sourceTargetPath = path11.join(sourcesDir, `${freshHash}${ext}`);
14669
+ const ext = path12.extname(file.relativePath) || ".txt";
14670
+ const sourceTargetPath = path12.join(sourcesDir, `${freshHash}${ext}`);
14495
14671
  try {
14496
- fs12.writeFileSync(sourceTargetPath, content, "utf-8");
14672
+ fs13.writeFileSync(sourceTargetPath, content, "utf-8");
14497
14673
  } catch {
14498
14674
  continue;
14499
14675
  }
@@ -14502,7 +14678,7 @@ function reconcileManifestWithDisk(projectPath = process.cwd()) {
14502
14678
  changed = true;
14503
14679
  }
14504
14680
  if (changed) {
14505
- fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
14681
+ fs13.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8");
14506
14682
  }
14507
14683
  }
14508
14684
  __name(reconcileManifestWithDisk, "reconcileManifestWithDisk");
@@ -14575,7 +14751,7 @@ function checkRestoreConflicts(manifest, targetDir) {
14575
14751
  const existingFiles = [];
14576
14752
  for (const file of manifest.files) {
14577
14753
  const filePath = resolveBackupFileTarget2(file, targetDir);
14578
- if (fs12.existsSync(filePath)) {
14754
+ if (fs13.existsSync(filePath)) {
14579
14755
  existingFiles.push(file.relativePath);
14580
14756
  } else {
14581
14757
  newFiles.push(file.relativePath);
@@ -14601,16 +14777,16 @@ function createBackupTracking(projectHash) {
14601
14777
  }
14602
14778
  __name(createBackupTracking, "createBackupTracking");
14603
14779
  function getBackupCachePath(projectPath = process.cwd()) {
14604
- return path11.join(projectPath, ".lua", BACKUP_CACHE_FILENAME);
14780
+ return path12.join(projectPath, ".lua", BACKUP_CACHE_FILENAME);
14605
14781
  }
14606
14782
  __name(getBackupCachePath, "getBackupCachePath");
14607
14783
  function writeBackupManifestCache(cache, projectPath = process.cwd()) {
14608
14784
  const cachePath = getBackupCachePath(projectPath);
14609
14785
  try {
14610
- fs12.mkdirSync(path11.dirname(cachePath), {
14786
+ fs13.mkdirSync(path12.dirname(cachePath), {
14611
14787
  recursive: true
14612
14788
  });
14613
- fs12.writeFileSync(cachePath, JSON.stringify(cache, null, 2), "utf-8");
14789
+ fs13.writeFileSync(cachePath, JSON.stringify(cache, null, 2), "utf-8");
14614
14790
  } catch (error) {
14615
14791
  const message = error instanceof Error ? error.message : String(error);
14616
14792
  console.warn(`Could not write backup manifest cache: ${message}`);
@@ -14619,9 +14795,9 @@ function writeBackupManifestCache(cache, projectPath = process.cwd()) {
14619
14795
  __name(writeBackupManifestCache, "writeBackupManifestCache");
14620
14796
  function readBackupManifestCache(projectPath = process.cwd()) {
14621
14797
  const cachePath = getBackupCachePath(projectPath);
14622
- if (!fs12.existsSync(cachePath)) return null;
14798
+ if (!fs13.existsSync(cachePath)) return null;
14623
14799
  try {
14624
- const raw = fs12.readFileSync(cachePath, "utf-8");
14800
+ const raw = fs13.readFileSync(cachePath, "utf-8");
14625
14801
  const parsed = JSON.parse(raw);
14626
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")) {
14627
14803
  return null;
@@ -14648,18 +14824,18 @@ function detectLocalConflictsForPull(incomingFiles, projectPath = process.cwd())
14648
14824
  f.hash
14649
14825
  ]));
14650
14826
  const conflicts = /* @__PURE__ */ new Set();
14651
- const projectRoot = path11.resolve(projectPath);
14827
+ const projectRoot = path12.resolve(projectPath);
14652
14828
  for (const incoming of incomingFiles) {
14653
14829
  if (COMPILE_MANAGED_FILES.has(incoming.relativePath)) continue;
14654
14830
  if (incoming.external) continue;
14655
- const absPath = path11.resolve(projectRoot, incoming.relativePath);
14656
- if (absPath !== projectRoot && !absPath.startsWith(projectRoot + path11.sep)) {
14831
+ const absPath = path12.resolve(projectRoot, incoming.relativePath);
14832
+ if (absPath !== projectRoot && !absPath.startsWith(projectRoot + path12.sep)) {
14657
14833
  continue;
14658
14834
  }
14659
- if (!fs12.existsSync(absPath)) continue;
14835
+ if (!fs13.existsSync(absPath)) continue;
14660
14836
  let diskHash;
14661
14837
  try {
14662
- const bytes = fs12.readFileSync(absPath, "utf-8");
14838
+ const bytes = fs13.readFileSync(absPath, "utf-8");
14663
14839
  diskHash = hashContent(bytes);
14664
14840
  } catch {
14665
14841
  conflicts.add(incoming.relativePath);
@@ -14686,7 +14862,7 @@ function detectLocalConflictsForPull(incomingFiles, projectPath = process.cwd())
14686
14862
  __name(detectLocalConflictsForPull, "detectLocalConflictsForPull");
14687
14863
  async function fetchBackupManifestForPull(apiKey, agentId) {
14688
14864
  try {
14689
- const backupApi = new BackupApi(BASE_URLS.API, apiKey, agentId);
14865
+ const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
14690
14866
  const response = await backupApi.getBackupManifest();
14691
14867
  return {
14692
14868
  fetched: response.data ?? null
@@ -14717,7 +14893,7 @@ __name(decideBackupFreshness, "decideBackupFreshness");
14717
14893
  async function checkServerBackupNewerThanLocal(apiKey, agentId, projectPath = process.cwd()) {
14718
14894
  const local = readBackupManifestCache(projectPath);
14719
14895
  try {
14720
- const api = new BackupApi(BASE_URLS.API, apiKey, agentId);
14896
+ const api = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
14721
14897
  const resp = await api.getBackupMetadata();
14722
14898
  const metadata = resp.success && resp.data ? {
14723
14899
  projectHash: resp.data.projectHash
@@ -14730,7 +14906,7 @@ async function checkServerBackupNewerThanLocal(apiKey, agentId, projectPath = pr
14730
14906
  __name(checkServerBackupNewerThanLocal, "checkServerBackupNewerThanLocal");
14731
14907
  async function checkBackupAvailability(apiKey, agentId) {
14732
14908
  try {
14733
- const backupApi = new BackupApi(BASE_URLS.API, apiKey, agentId);
14909
+ const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
14734
14910
  const metadata = await backupApi.getBackupMetadata();
14735
14911
  if (metadata.data && metadata.data.fileCount > 0) {
14736
14912
  return {
@@ -14752,7 +14928,7 @@ __name(checkBackupAvailability, "checkBackupAvailability");
14752
14928
  async function restoreFromBackupForSync(apiKey, agentId, expectedPrimitives = [], projectPath, preFetchedManifest) {
14753
14929
  const targetDir = projectPath || process.cwd();
14754
14930
  try {
14755
- const backupApi = new BackupApi(BASE_URLS.API, apiKey, agentId);
14931
+ const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
14756
14932
  const manifest = preFetchedManifest ?? (await backupApi.getBackupManifest()).data ?? null;
14757
14933
  if (!manifest || !manifest.files?.length) {
14758
14934
  return {
@@ -14838,17 +15014,17 @@ function writeBackupFilesWithByteCompare(manifest, blobs, targetDir) {
14838
15014
  }
14839
15015
  restoredContents.set(makeRestoredContentsKey(file), content);
14840
15016
  const filePath = resolveBackupFileTarget2(file, targetDir);
14841
- if (fs12.existsSync(filePath)) {
14842
- const existing = fs12.readFileSync(filePath);
15017
+ if (fs13.existsSync(filePath)) {
15018
+ const existing = fs13.readFileSync(filePath);
14843
15019
  if (existing.equals(content)) {
14844
15020
  filesUnchanged++;
14845
15021
  continue;
14846
15022
  }
14847
15023
  }
14848
- fs12.mkdirSync(path11.dirname(filePath), {
15024
+ fs13.mkdirSync(path12.dirname(filePath), {
14849
15025
  recursive: true
14850
15026
  });
14851
- fs12.writeFileSync(filePath, content);
15027
+ fs13.writeFileSync(filePath, content);
14852
15028
  filesWritten++;
14853
15029
  }
14854
15030
  return {
@@ -16574,7 +16750,7 @@ async function checkAndRestoreBackup(apiKey, agentId, options) {
16574
16750
  if (!confirm) return false;
16575
16751
  }
16576
16752
  try {
16577
- const backupApi = new BackupApi(BASE_URLS.API, apiKey, agentId);
16753
+ const backupApi = new backup_api_service_default(BASE_URLS.API, apiKey, agentId);
16578
16754
  const urlsResponse = await backupApi.getBlobUrls(manifest.files.map((f) => f.hash));
16579
16755
  if (!urlsResponse.success || !urlsResponse.data) {
16580
16756
  writeError(`Failed to fetch download URLs: ${urlsResponse.error?.message ?? "unknown error"}`);
@@ -16628,6 +16804,7 @@ async function destroyCommand(options) {
16628
16804
  if (options?.force) {
16629
16805
  const deleted2 = deleteApiKey();
16630
16806
  if (deleted2) {
16807
+ invalidateVersioningModeCache();
16631
16808
  writeSuccess("\u2705 API key deleted successfully.");
16632
16809
  } else {
16633
16810
  writeProgress("\u274C Failed to delete API key.");
@@ -16653,6 +16830,7 @@ async function destroyCommand(options) {
16653
16830
  if (confirm) {
16654
16831
  deleted = deleteApiKey();
16655
16832
  if (deleted) {
16833
+ invalidateVersioningModeCache();
16656
16834
  writeSuccess("\u2705 API key deleted successfully.");
16657
16835
  } else {
16658
16836
  writeProgress("\u274C Failed to delete API key.");
@@ -16723,13 +16901,13 @@ __name(apiKeyCommand, "apiKeyCommand");
16723
16901
  init_cli();
16724
16902
  init_files();
16725
16903
  init_auth();
16726
- import path13 from "path";
16904
+ import path14 from "path";
16727
16905
 
16728
16906
  // src/commands/sync.ts
16729
16907
  init_dist();
16730
16908
  init_cli();
16731
- import fs13 from "fs";
16732
- import path12 from "path";
16909
+ import fs14 from "fs";
16910
+ import path13 from "path";
16733
16911
 
16734
16912
  // src/utils/prompt-handler.ts
16735
16913
  init_cli();
@@ -16940,8 +17118,8 @@ init_mcp_server_handler();
16940
17118
  async function syncCommand(options) {
16941
17119
  return withErrorHandling(async () => {
16942
17120
  const preCompileYaml = readYamlConfig();
16943
- const yamlPath = path12.resolve(process.cwd(), "lua.skill.yaml");
16944
- const preCompileYamlBytes = fs13.existsSync(yamlPath) ? fs13.readFileSync(yamlPath, "utf-8") : null;
17121
+ const yamlPath = path13.resolve(process.cwd(), "lua.skill.yaml");
17122
+ const preCompileYamlBytes = fs14.existsSync(yamlPath) ? fs14.readFileSync(yamlPath, "utf-8") : null;
16945
17123
  let syncCompletedSuccessfully = false;
16946
17124
  try {
16947
17125
  writeProgress("\u{1F504} Compiling to get latest local state...");
@@ -17002,7 +17180,7 @@ async function syncCommand(options) {
17002
17180
  } finally {
17003
17181
  if (!syncCompletedSuccessfully && preCompileYamlBytes !== null) {
17004
17182
  try {
17005
- fs13.writeFileSync(yamlPath, preCompileYamlBytes, "utf-8");
17183
+ fs14.writeFileSync(yamlPath, preCompileYamlBytes, "utf-8");
17006
17184
  } catch {
17007
17185
  }
17008
17186
  }
@@ -18559,7 +18737,7 @@ async function compileCommand(options) {
18559
18737
  }
18560
18738
  writeProgress("\u{1F528} Compiling...");
18561
18739
  const rootDir = process.cwd();
18562
- const outDir = path13.join(rootDir, "dist-v2");
18740
+ const outDir = path14.join(rootDir, "dist-v2");
18563
18741
  const result = await compile({
18564
18742
  rootDir,
18565
18743
  outDir,
@@ -18723,12 +18901,12 @@ init_command_utils();
18723
18901
 
18724
18902
  // src/utils/sandbox.ts
18725
18903
  import vm3 from "vm";
18726
- import path16 from "path";
18904
+ import path17 from "path";
18727
18905
 
18728
18906
  // ../shared-sandbox/dist/index.mjs
18729
18907
  import vm from "vm";
18730
18908
  import { createRequire } from "module";
18731
- import path14 from "path";
18909
+ import path15 from "path";
18732
18910
  import dns from "dns";
18733
18911
  import net from "net";
18734
18912
  import { promisify } from "util";
@@ -18898,7 +19076,7 @@ var REQUIRE_BLOCKLIST = /* @__PURE__ */ new Set([
18898
19076
  var SANDBOX_FAKE_DIRNAME = "/";
18899
19077
  var SANDBOX_FAKE_FILENAME = "/index.ts";
18900
19078
  function buildSandboxRequire(opts) {
18901
- const realRequire = createRequire(path14.join(opts.cwd, "package.json"));
19079
+ const realRequire = createRequire(path15.join(opts.cwd, "package.json"));
18902
19080
  const wrapped = /* @__PURE__ */ __name4((id) => {
18903
19081
  if (REQUIRE_BLOCKLIST.has(id)) {
18904
19082
  const evt = {
@@ -19568,14 +19746,14 @@ __name(runBundleInContext, "runBundleInContext");
19568
19746
  __name4(runBundleInContext, "runBundleInContext");
19569
19747
 
19570
19748
  // src/utils/env-loader.utils.ts
19571
- import path15 from "path";
19572
- import fs14 from "fs";
19749
+ import path16 from "path";
19750
+ import fs15 from "fs";
19573
19751
  function parseEnvFile(filePath) {
19574
- if (!fs14.existsSync(filePath)) {
19752
+ if (!fs15.existsSync(filePath)) {
19575
19753
  return {};
19576
19754
  }
19577
19755
  try {
19578
- const content = fs14.readFileSync(filePath, "utf8");
19756
+ const content = fs15.readFileSync(filePath, "utf8");
19579
19757
  if (!content.trim()) return {};
19580
19758
  const envVars = {};
19581
19759
  content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#")).forEach((line) => {
@@ -19601,7 +19779,7 @@ async function loadEnvironmentVariables(context) {
19601
19779
  }
19602
19780
  __name(loadEnvironmentVariables, "loadEnvironmentVariables");
19603
19781
  function loadSandboxEnvVariables() {
19604
- const envFilePath = path15.join(process.cwd(), ".env");
19782
+ const envFilePath = path16.join(process.cwd(), ".env");
19605
19783
  const envMap = parseEnvFile(envFilePath);
19606
19784
  return Object.entries(envMap).map(([key, value]) => ({
19607
19785
  key,
@@ -19696,7 +19874,7 @@ function loadEnvironmentVariables2() {
19696
19874
  envVars[key] = value;
19697
19875
  }
19698
19876
  }
19699
- const envFilePath = path16.join(process.cwd(), ".env");
19877
+ const envFilePath = path17.join(process.cwd(), ".env");
19700
19878
  const fileEnvVars = parseEnvFile(envFilePath);
19701
19879
  Object.assign(envVars, fileEnvVars);
19702
19880
  return envVars;
@@ -21582,6 +21760,7 @@ init_dist();
21582
21760
  init_files();
21583
21761
  init_cli();
21584
21762
  init_command_utils();
21763
+ init_auth();
21585
21764
  init_semver();
21586
21765
  init_auth_error();
21587
21766
  init_constants();
@@ -21648,7 +21827,7 @@ async function runBackupPush(opts) {
21648
21827
  projectHash: manifestProjectHash
21649
21828
  };
21650
21829
  }
21651
- const backupApi = new BackupApi(BASE_URLS.API, opts.apiKey, opts.agentId);
21830
+ const backupApi = new backup_api_service_default(BASE_URLS.API, opts.apiKey, opts.agentId);
21652
21831
  const allHashes = opts.fresh ? [
21653
21832
  ...new Set(fileRefs.map((f) => f.hash))
21654
21833
  ] : getAllFileHashes(projectPath);
@@ -21709,8 +21888,8 @@ async function runBackupPush(opts) {
21709
21888
  }
21710
21889
  __name(runBackupPush, "runBackupPush");
21711
21890
  async function uploadBlobsFromDisk(uploadUrls, files, projectPath, concurrency = 10) {
21712
- const fs16 = await import("fs");
21713
- const path18 = await import("path");
21891
+ const fs17 = await import("fs");
21892
+ const path19 = await import("path");
21714
21893
  const zlib2 = await import("zlib");
21715
21894
  const hashToPath = /* @__PURE__ */ new Map();
21716
21895
  for (const f of files) {
@@ -21724,8 +21903,8 @@ async function uploadBlobsFromDisk(uploadUrls, files, projectPath, concurrency =
21724
21903
  if (!rel) {
21725
21904
  throw new Error(`No file found for hash: ${hash}`);
21726
21905
  }
21727
- const abs = path18.join(projectPath, rel);
21728
- const content = fs16.readFileSync(abs);
21906
+ const abs = path19.join(projectPath, rel);
21907
+ const content = fs17.readFileSync(abs);
21729
21908
  const compressed = zlib2.gzipSync(content);
21730
21909
  const response = await fetch(uploadUrls[hash], {
21731
21910
  method: "PUT",
@@ -21816,6 +21995,262 @@ init_analytics();
21816
21995
  init_dist2();
21817
21996
  init_skills_api_service();
21818
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
+
21819
22254
  // src/commands/push-helpers.ts
21820
22255
  function pickPushAllNextStepVariant(opts) {
21821
22256
  if (opts.pushedSomething && opts.failedCount === 0) return "success";
@@ -22130,6 +22565,34 @@ async function pushCommand(type, cmdObj) {
22130
22565
  allowAll: true
22131
22566
  });
22132
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
+ }
22133
22596
  if (type === "all") {
22134
22597
  if (!options.force) {
22135
22598
  console.log("\nUsage:");
@@ -22137,13 +22600,10 @@ async function pushCommand(type, cmdObj) {
22137
22600
  console.log(" lua push all --force --auto-deploy Push and deploy all to production");
22138
22601
  throw new Error('The "all" type requires the --force flag');
22139
22602
  }
22140
- return await pushAllCommand(options);
22141
- }
22142
- if (options.entityName && !type) {
22143
- console.log("\nUsage:");
22144
- console.log(" lua push skill --name mySkill --set-version 1.0.5 Push specific skill");
22145
- console.log(" lua push webhook --name myWebhook --set-version 2.0.0 Push specific webhook");
22146
- throw new Error("Type must be specified when using the --name option.");
22603
+ return await pushAllCommand({
22604
+ ...options,
22605
+ autoDeployNoopWarned: isAutoDeployNoOp
22606
+ });
22147
22607
  }
22148
22608
  if (type) {
22149
22609
  selectedType = type;
@@ -22284,13 +22744,17 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
22284
22744
  bundles_total: versionedPushDeployResult?.bundleStats?.total ?? 0,
22285
22745
  bundles_uploaded: versionedPushDeployResult?.bundleStats?.uploaded ?? 0,
22286
22746
  bundles_existed: versionedPushDeployResult?.bundleStats?.alreadyExisted ?? 0,
22287
- // Phase 2 `--include-source` telemetry. Tracks adoption of the flag
22288
- // and whether the per-skill source attach actually lands cleanly —
22289
- // useful for the eventual "flip default to ON" decision in Slice 5.
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.
22290
22750
  include_source_requested: options.includeSource || false,
22291
22751
  include_source_attempted: trackedIncludeSource?.attempted ?? 0,
22292
22752
  include_source_attached: trackedIncludeSource?.attached ?? 0,
22293
- 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
22294
22758
  });
22295
22759
  const productionDeployedActually = versionedPushDeployResult?.productionDeploySucceeded === true || !!agentOutcome && !agentOutcome.cancelled && agentOutcome.productionDeployedWithAutoDeploy;
22296
22760
  const personaAutoDeployRanAndFailed = selectedType === "agent" && options.autoDeploy && !!agentOutcome && !agentOutcome.cancelled && "personaAutoDeployFailed" in agentOutcome && agentOutcome.personaAutoDeployFailed;
@@ -22583,6 +23047,7 @@ async function pushAllCommand(options) {
22583
23047
  }
22584
23048
  const apiKey = await requireAuthOrExit(false);
22585
23049
  const agentId = config.agent.agentId;
23050
+ const pushAllVersioning = await getVersioningModeCached(apiKey, agentId);
22586
23051
  let manifest;
22587
23052
  try {
22588
23053
  manifest = loadManifest();
@@ -22879,15 +23344,26 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
22879
23344
  bundles_total: bundleStatsAggregate.total,
22880
23345
  bundles_uploaded: bundleStatsAggregate.uploaded,
22881
23346
  bundles_existed: bundleStatsAggregate.existed,
22882
- // Phase 2 `--include-source` telemetry, parallel to the single-push
23347
+ // `--include-source` telemetry, parallel to the single-push
22883
23348
  // `cli_push_completed` shape. Without these the `lua push all` path —
22884
- // arguably the highest-volume one for multi-skill agents — would be
22885
- // invisible to adoption monitoring.
23349
+ // the highest-volume one for multi-skill agents — would be invisible
23350
+ // to adoption monitoring.
22886
23351
  include_source_requested: options.includeSource || false,
22887
23352
  include_source_attempted: includeSourceStats?.attempted ?? 0,
22888
23353
  include_source_attached: includeSourceStats?.attached ?? 0,
22889
- 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
22890
23359
  });
23360
+ try {
23361
+ await tryGitCommit({
23362
+ message: GIT_MESSAGES.pushStaged,
23363
+ action: "push-staged"
23364
+ });
23365
+ } catch {
23366
+ }
22891
23367
  const pushedSomething = allResults.length > 0 || mcpPushedCount > 0 || !!personaPushResult || backupSuccess;
22892
23368
  const variant = pickPushAllNextStepVariant({
22893
23369
  pushedSomething,
@@ -22895,7 +23371,11 @@ Until the backup catches up, \`lua init\` for this agent will restore an older s
22895
23371
  });
22896
23372
  if (variant === "success") {
22897
23373
  console.log("");
22898
- if (options.autoDeploy) {
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) {
22899
23379
  writeHintBlock({
22900
23380
  headline: "All deployed. Generate test traffic first, then inspect:",
22901
23381
  lines: [
@@ -23163,6 +23643,10 @@ async function deployCommand(type, cmdObj) {
23163
23643
  selectedType = answer.type;
23164
23644
  }
23165
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
+ }
23166
23650
  let personaDeployed = false;
23167
23651
  let versionedOutcome = null;
23168
23652
  if (selectedType === "persona") {
@@ -23175,7 +23659,8 @@ async function deployCommand(type, cmdObj) {
23175
23659
  primitive_type: selectedType,
23176
23660
  force_mode: options.force || false,
23177
23661
  entity_selected_by_name: !!options.name,
23178
- version_selected_by_flag: !!options.version
23662
+ version_selected_by_flag: !!options.version,
23663
+ granular_deprecation_warned: versioning.enabled
23179
23664
  });
23180
23665
  const deployed = selectedType === "persona" ? personaDeployed : versionedOutcome?.deployed ?? false;
23181
23666
  const hintPrintedAlready = selectedType !== "persona" && !!versionedOutcome?.hintPrinted;
@@ -23669,11 +24154,11 @@ init_cli();
23669
24154
 
23670
24155
  // src/utils/sandbox-storage.ts
23671
24156
  init_constants();
23672
- import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync6 } from "fs";
23673
- import { dirname as dirname5 } from "path";
24157
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "fs";
24158
+ import { dirname as dirname6 } from "path";
23674
24159
  function readStore() {
23675
24160
  try {
23676
- const raw = readFileSync9(SANDBOX_STORAGE_FILE, "utf8");
24161
+ const raw = readFileSync10(SANDBOX_STORAGE_FILE, "utf8");
23677
24162
  const parsed = JSON.parse(raw);
23678
24163
  return {
23679
24164
  skills: parsed.skills ?? {},
@@ -23693,10 +24178,10 @@ function readStore() {
23693
24178
  __name(readStore, "readStore");
23694
24179
  function writeStore(store) {
23695
24180
  try {
23696
- mkdirSync6(dirname5(SANDBOX_STORAGE_FILE), {
24181
+ mkdirSync7(dirname6(SANDBOX_STORAGE_FILE), {
23697
24182
  recursive: true
23698
24183
  });
23699
- writeFileSync6(SANDBOX_STORAGE_FILE, JSON.stringify(store, null, 2), "utf8");
24184
+ writeFileSync7(SANDBOX_STORAGE_FILE, JSON.stringify(store, null, 2), "utf8");
23700
24185
  } catch {
23701
24186
  }
23702
24187
  }
@@ -24200,7 +24685,15 @@ var MIME_TYPES = {
24200
24685
  ".json": "application/json",
24201
24686
  // Email
24202
24687
  ".eml": "message/rfc822",
24203
- ".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"
24204
24697
  };
24205
24698
  var IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
24206
24699
  "image/png",
@@ -25010,8 +25503,8 @@ init_cli();
25010
25503
  init_constants();
25011
25504
  init_command_utils();
25012
25505
  init_developer_api_service();
25013
- import fs15 from "fs";
25014
- import path17 from "path";
25506
+ import fs16 from "fs";
25507
+ import path18 from "path";
25015
25508
  import inquirer10 from "inquirer";
25016
25509
  init_analytics();
25017
25510
  function resolveEnvironment(env, hasNonInteractiveFlags) {
@@ -25370,10 +25863,10 @@ function variablesToEnvContent(variables) {
25370
25863
  }
25371
25864
  __name(variablesToEnvContent, "variablesToEnvContent");
25372
25865
  function saveSandboxEnvVariables(variables) {
25373
- const envFilePath = path17.join(process.cwd(), ".env");
25866
+ const envFilePath = path18.join(process.cwd(), ".env");
25374
25867
  try {
25375
25868
  const content = variablesToEnvContent(variables);
25376
- fs15.writeFileSync(envFilePath, content, "utf8");
25869
+ fs16.writeFileSync(envFilePath, content, "utf8");
25377
25870
  return true;
25378
25871
  } catch (error) {
25379
25872
  console.error("\u274C Error saving .env file:", error);
@@ -29865,7 +30358,7 @@ init_auth();
29865
30358
  init_auth_api_service();
29866
30359
  init_files();
29867
30360
  init_artifact_loader();
29868
- import { existsSync as existsSync7, readFileSync as readFileSync10 } from "fs";
30361
+ import { existsSync as existsSync7, readFileSync as readFileSync11 } from "fs";
29869
30362
  import { join as join6 } from "path";
29870
30363
  import { performance } from "perf_hooks";
29871
30364
  import * as os from "os";
@@ -30216,7 +30709,7 @@ function gatherTelemetry() {
30216
30709
  } else {
30217
30710
  try {
30218
30711
  if (existsSync7(TELEMETRY_FILE)) {
30219
- const raw = readFileSync10(TELEMETRY_FILE, "utf8");
30712
+ const raw = readFileSync11(TELEMETRY_FILE, "utf8");
30220
30713
  const cfg = JSON.parse(raw);
30221
30714
  if (typeof cfg.enabled === "boolean") enabled = cfg.enabled;
30222
30715
  }
@@ -39397,7 +39890,7 @@ __name(telemetryCommand, "telemetryCommand");
39397
39890
  init_cli();
39398
39891
  init_command_utils();
39399
39892
  init_analytics();
39400
- import { writeFileSync as writeFileSync7, existsSync as existsSync8, unlinkSync as unlinkSync2 } from "fs";
39893
+ import { writeFileSync as writeFileSync8, existsSync as existsSync8, unlinkSync as unlinkSync2 } from "fs";
39401
39894
  import { resolve as resolve4, join as join7 } from "path";
39402
39895
  init_artifact_loader();
39403
39896
  init_types();
@@ -39558,7 +40051,7 @@ async function governanceCommand(action) {
39558
40051
  }
39559
40052
  }
39560
40053
  const content = generateFile(setup);
39561
- writeFileSync7(filePath, content, "utf-8");
40054
+ writeFileSync8(filePath, content, "utf-8");
39562
40055
  const relativePath = filePath.replace(process.cwd() + "/", "");
39563
40056
  writeSuccess(`Created ${relativePath}`);
39564
40057
  console.log("");
@@ -39822,14 +40315,14 @@ init_analytics();
39822
40315
  init_command_utils();
39823
40316
  init_artifact_loader();
39824
40317
  init_types();
39825
- import { spawn as spawn2 } from "child_process";
40318
+ import { spawn as spawn3 } from "child_process";
39826
40319
  import { existsSync as existsSync9, readdirSync as readdirSync3, statSync as statSync4 } from "fs";
39827
40320
  import { join as join8, relative, resolve as resolve5 } from "path";
39828
40321
  init_voice_api_service();
39829
40322
  init_constants();
39830
40323
 
39831
40324
  // src/commands/voice-terminal.ts
39832
- import { spawn, spawnSync } from "child_process";
40325
+ import { spawn as spawn2, spawnSync } from "child_process";
39833
40326
  import { platform as platform3 } from "os";
39834
40327
  import { AudioFrame, AudioSource, AudioStream, LocalAudioTrack, Room, RoomEvent, TrackKind, TrackPublishOptions, TrackSource } from "@livekit/rtc-node";
39835
40328
 
@@ -40092,7 +40585,7 @@ function spawnCapture() {
40092
40585
  String(FRAME_SAMPLES * 2),
40093
40586
  "-"
40094
40587
  ];
40095
- const proc = spawn("sox", args2, {
40588
+ const proc = spawn2("sox", args2, {
40096
40589
  stdio: [
40097
40590
  "ignore",
40098
40591
  "pipe",
@@ -40123,7 +40616,7 @@ function spawnPlayback() {
40123
40616
  "-",
40124
40617
  "-d"
40125
40618
  ];
40126
- const proc = spawn("sox", args2, {
40619
+ const proc = spawn2("sox", args2, {
40127
40620
  stdio: [
40128
40621
  "pipe",
40129
40622
  "ignore",
@@ -40453,7 +40946,7 @@ function buildRunnerArgs(runner, opts) {
40453
40946
  __name(buildRunnerArgs, "buildRunnerArgs");
40454
40947
  async function spawnRunner(runner, args2, cwd) {
40455
40948
  return new Promise((resolveExit) => {
40456
- const proc = spawn2("npx", [
40949
+ const proc = spawn3("npx", [
40457
40950
  runner,
40458
40951
  ...args2
40459
40952
  ], {
@@ -40846,6 +41339,12 @@ async function sourceRollbackCommand(opts) {
40846
41339
  const config = readYamlConfig();
40847
41340
  const agentId = config?.agent?.agentId;
40848
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
+ }
40849
41348
  const fetchM = opts.fetchManifest ?? defaultFetchManifest;
40850
41349
  const fetchU = opts.fetchUrls ?? defaultFetchUrls;
40851
41350
  const dlBlobs = opts.downloadBlobs ?? downloadBlobsParallel;
@@ -40916,6 +41415,560 @@ function defaultRestore(manifest, blobs, targetDir) {
40916
41415
  }
40917
41416
  __name(defaultRestore, "defaultRestore");
40918
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
+
40919
41972
  // src/cli/command-definitions.ts
40920
41973
  init_cli();
40921
41974
  function setupAuthCommands(program2) {
@@ -41544,6 +42597,50 @@ Examples:
41544
42597
  $ lua voice test --runner vitest Force vitest
41545
42598
  `).action(voiceTestCommand);
41546
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));
41547
42644
  const sourceCmd = program2.command("source").description("\u{1F5C2}\uFE0F Manage workspace source versions");
41548
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", `
41549
42646
  Examples: