nanos-lint 3.3.0 → 3.4.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/README.md CHANGED
@@ -73,6 +73,23 @@ To pre-populate all required assets (both LuaLS binary and nanos world annotatio
73
73
  npx nanos-lint warmup
74
74
  ```
75
75
 
76
+ Offline execution uses only local dependencies and skips all nanos-lint network requests:
77
+
78
+ ```sh
79
+ nanos-lint warmup # provision online
80
+ nanos-lint check Packages/events --offline
81
+ npx --offline nanos-lint check Packages/events --offline
82
+ ```
83
+
84
+ For `latest`, offline mode selects the highest usable cached version (numeric tag order)
85
+ and reports it, then tries a bundled binary or PATH. `LUALS_BIN` overrides discovery.
86
+ Pinned versions require a matching cache or local executable. Custom annotations
87
+ (`--annotations` or `NANOS_ANNOTATIONS_PATH`), bundled annotations, and valid stale
88
+ cached annotations work offline. `warmup --offline` verifies local assets without
89
+ downloading them. Missing assets fail with provisioning instructions.
90
+ The flag controls nanos-lint; npm/npx may access the registry before it starts. Use
91
+ a preinstalled executable or npm's own `--offline` with an already cached package.
92
+
76
93
  ---
77
94
 
78
95
  ## GitHub Actions Integration
@@ -104,20 +121,23 @@ jobs:
104
121
 
105
122
  ### Action Inputs
106
123
 
107
- | Input | Description | Default |
108
- | :-------------- | :------------------------------------------------------------------------------------ | :-------- |
109
- | `path` | Path to workspace directory or Lua file to check | `.` |
110
- | `paths` | One or more workspace target paths or Lua files to check (newline or comma-separated) | `""` |
111
- | `dep` | External package dependency paths or definition files (newline or comma-separated) | `""` |
112
- | `checklevel` | Minimum severity to report (`Error`, `Warning`, `Information`, `Hint`) | `Warning` |
113
- | `config` | Path to a custom `.luarc.json` configuration file | `""` |
114
- | `annotations` | Path to a custom `annotations.lua` file | `""` |
115
- | `ignore` | Files or directories to ignore (supports glob patterns, newline or comma separated) | `""` |
116
- | `luals-version` | Version of `lua-language-server` to use | `latest` |
117
- | `fail-on-error` | Fail the workflow step if diagnostics are found | `true` |
118
- | `log-level` | Logging level (`error`, `warn`, `info`, `debug`, `silent`) | `warn` |
119
- | `realm` | Execution realm to check (`all`, `client`, `server`, `shared`) | `all` |
120
- | `cache` | Whether to cache the LuaLS binary and annotations across workflow runs | `true` |
124
+ | Input | Description | Default |
125
+ | :---------------- | :------------------------------------------------------------------------------------ | :-------- |
126
+ | `path` | Path to workspace directory or Lua file to check | `.` |
127
+ | `paths` | One or more workspace target paths or Lua files to check (newline or comma-separated) | `""` |
128
+ | `dep` | External package dependency paths or definition files (newline or comma-separated) | `""` |
129
+ | `checklevel` | Minimum severity to report (`Error`, `Warning`, `Information`, `Hint`) | `Warning` |
130
+ | `config` | Path to a custom `.luarc.json` configuration file | `""` |
131
+ | `annotations` | Path to a custom `annotations.lua` file | `""` |
132
+ | `ignore` | Files or directories to ignore (supports glob patterns, newline or comma separated) | `""` |
133
+ | `luals-version` | Version of `lua-language-server` to use | `latest` |
134
+ | `baseline` | Accepted diagnostic baseline; only new diagnostics fail | `""` |
135
+ | `write-baseline` | Record current diagnostics and exit successfully | `""` |
136
+ | `baseline-strict` | Also fail when baseline entries disappear (requires `baseline`) | `false` |
137
+ | `fail-on-error` | Fail the workflow step if diagnostics are found | `true` |
138
+ | `log-level` | Logging level (`error`, `warn`, `info`, `debug`, `silent`) | `warn` |
139
+ | `realm` | Execution realm to check (`all`, `client`, `server`, `shared`) | `all` |
140
+ | `cache` | Whether to cache the LuaLS binary and annotations across workflow runs | `true` |
121
141
 
122
142
  `paths` takes precedence over `path` when both are set; `path` is kept for backwards compatibility with the single-target form.
123
143
 
@@ -158,13 +178,54 @@ OPTIONS:
158
178
  --format=<format> Output format: pretty, json, github (default: pretty)
159
179
  --github Output in GitHub Actions format (shortcut for --format=github)
160
180
  --luals-version=<ver> Version of LuaLS to use (default: latest, falling back to 3.19.1 when offline)
181
+ --baseline <path> Report and fail only on new diagnostics
182
+ --write-baseline <path> Record diagnostics and exit 0
183
+ --baseline-strict Also fail on stale entries (requires --baseline)
161
184
  --no-fail Do not exit with code 1 if diagnostics are found
162
185
  --realm <realm> Execution realm to check: all, client, server, shared (default: all)
186
+ --offline Use local dependencies only; never access the network
163
187
  --no-progress Disable the interactive download, extraction and realm derivation progress display
188
+ -t, --template <path> (init command only) Use a custom JSONC scaffold template
164
189
  --vendor (init command only) Vendor annotations.lua into .nanos-lint/ inside workspace
165
190
  -f, --force (init and copy-annotations only) Overwrite existing files
166
191
  ```
167
192
 
193
+ ### Diagnostic Baselines
194
+
195
+ Use a diagnostic baseline to accept an existing backlog and fail on new problems:
196
+
197
+ ```sh
198
+ nanos-lint check . --write-baseline .nanos-lint/baseline.json
199
+ nanos-lint check . --baseline .nanos-lint/baseline.json
200
+ nanos-lint check . --baseline .nanos-lint/baseline.json --baseline-strict
201
+ ```
202
+
203
+ Recording writes all reported diagnostics in a deterministic versioned JSON file,
204
+ creates parent directories, and exits 0 (also with `--no-fail`). Comparison shows
205
+ only new diagnostics with a summary such as `12 new, 154 baselined, 166 total`.
206
+ JSON output retains every diagnostic and adds `baseline: true|false` plus
207
+ `baselineSummary` counts. GitHub annotations are emitted only for new diagnostics.
208
+
209
+ Matches use paths relative to the checked root, diagnostic code, whitespace-normalized
210
+ message, severity, and occurrence counts. Line changes preserve matches; additional
211
+ occurrences or severity changes are new problems. Removed occurrences are stale and
212
+ only fail with `--baseline-strict`. `--no-fail` suppresses diagnostic failure, including
213
+ strict staleness; invalid baseline files still fail. Missing, invalid, or incompatible
214
+ files require regeneration with `--write-baseline`. Recording and comparison are
215
+ mutually exclusive. Keep targets, realm, check level, configuration, and LuaLS version
216
+ consistent between runs; pin `--luals-version` to avoid diagnostic changes from upgrades.
217
+ Relative baseline paths are resolved from the working directory.
218
+
219
+ The GitHub Action exposes the same options as `baseline`, `write-baseline`, and
220
+ `baseline-strict` inputs:
221
+
222
+ ```yaml
223
+ - uses: vugi99/nanos-lint@v3
224
+ with:
225
+ baseline: .nanos-lint/baseline.json
226
+ baseline-strict: "false"
227
+ ```
228
+
168
229
  ### Progress Display
169
230
 
170
231
  Downloads and extractions (`LuaLS` archive, `annotations.lua`, realm derivation) report their
@@ -251,6 +312,23 @@ npx nanos-lint copy-annotations ./types
251
312
 
252
313
  `copy-annotations` refuses to overwrite an existing file unless `--force` is passed.
253
314
 
315
+ ### Custom Init Templates
316
+
317
+ Initialize packages from a shared configuration template:
318
+
319
+ ```sh
320
+ nanos-lint init Packages/events --template tools/team-luarc.json
321
+ nanos-lint init Packages/events -t tools/team-luarc.json --vendor --annotations tools/annotations.lua
322
+ ```
323
+
324
+ The custom JSON/JSONC file becomes the base configuration. Relative paths in its
325
+ settings are interpreted relative to the target workspace, so shared templates can
326
+ use entries such as `nanos.deps: ["../collider"]`. Custom settings and realm mappings
327
+ are preserved, including `{}` to disable realms. Omitted realm mappings receive
328
+ the conventional Server/Client/Shared defaults. Vendoring adds its annotation
329
+ library, ignore and exclusion entries without discarding template entries. Existing
330
+ `.luarc.json` files still require `--force` to overwrite.
331
+
254
332
  ### Realm Mapping (`nanos.realms`)
255
333
 
256
334
  nanos world runs two isolated Lua VMs: the server executes `Server/**` + `Shared/**`, the client executes `Client/**` + `Shared/**`. `nanos-lint` mirrors that split and lets you describe a non-standard layout in `.luarc.json`:
package/action.yml CHANGED
@@ -34,6 +34,18 @@ inputs:
34
34
  description: 'Version of LuaLS to use (or "latest")'
35
35
  required: false
36
36
  default: "latest"
37
+ baseline:
38
+ description: "Path to an accepted diagnostic baseline; only new diagnostics fail"
39
+ required: false
40
+ default: ""
41
+ write-baseline:
42
+ description: "Record current diagnostics to this baseline path and exit successfully"
43
+ required: false
44
+ default: ""
45
+ baseline-strict:
46
+ description: "Also fail on stale baseline entries (requires baseline)"
47
+ required: false
48
+ default: "false"
37
49
  fail-on-error:
38
50
  description: "Whether to fail the action step if diagnostic errors/warnings are found"
39
51
  required: false
@@ -93,6 +105,9 @@ runs:
93
105
  INPUT_CONFIG: ${{ inputs.config }}
94
106
  INPUT_ANNOTATIONS: ${{ inputs.annotations }}
95
107
  INPUT_LUALS_VERSION: ${{ inputs.luals-version }}
108
+ INPUT_BASELINE: ${{ inputs.baseline }}
109
+ INPUT_WRITE_BASELINE: ${{ inputs.write-baseline }}
110
+ INPUT_BASELINE_STRICT: ${{ inputs.baseline-strict }}
96
111
  INPUT_FAIL_ON_ERROR: ${{ inputs.fail-on-error }}
97
112
  INPUT_LOG_LEVEL: ${{ inputs.log-level }}
98
113
  INPUT_REALM: ${{ inputs.realm }}
@@ -153,6 +168,18 @@ runs:
153
168
  done <<< "$INPUT_IGNORE"
154
169
  fi
155
170
 
171
+ if [ -n "$INPUT_BASELINE" ]; then
172
+ ARGS+=("--baseline=$INPUT_BASELINE")
173
+ fi
174
+
175
+ if [ -n "$INPUT_WRITE_BASELINE" ]; then
176
+ ARGS+=("--write-baseline=$INPUT_WRITE_BASELINE")
177
+ fi
178
+
179
+ if [ "$INPUT_BASELINE_STRICT" = "true" ]; then
180
+ ARGS+=("--baseline-strict")
181
+ fi
182
+
156
183
  if [ "$INPUT_FAIL_ON_ERROR" = "false" ]; then
157
184
  ARGS+=("--no-fail")
158
185
  fi
@@ -172,5 +199,5 @@ runs:
172
199
  else
173
200
  # Exact version: a range could run a different release than the pinned
174
201
  # tag. Bump together with "version" in package.json.
175
- npx --yes nanos-lint@3.3.0 "${ARGS[@]}"
202
+ npx --yes nanos-lint@3.4.0 "${ARGS[@]}"
176
203
  fi
@@ -1465,21 +1465,21 @@ function initWorkspace(workspacePath, options) {
1465
1465
  const targetFile = path.join(workspacePath, ".luarc.json");
1466
1466
  if (fs.existsSync(targetFile) && !options?.force) throw new ConfigError(`.luarc.json already exists at ${targetFile}. Use --force to overwrite.`, "ERR_CONFIG_EXISTS", "Pass --force to overwrite the existing .luarc.json file.");
1467
1467
  if (options?.annotationsPath && !options.vendor) throw new ConfigError("--annotations requires --vendor: nanos-lint init does not pin or vendor annotations.lua by default.", "ERR_ANNOTATIONS_WITHOUT_VENDOR", "Run 'nanos-lint init --vendor --annotations <path>' (or pass vendor: true), or omit the custom path to use the managed annotations cache.");
1468
- const template = loadConfigFile(getDefaultTemplatePath());
1468
+ const template = loadConfigFile(path.resolve(options?.templatePath ?? getDefaultTemplatePath()));
1469
+ if (!template || typeof template !== "object" || Array.isArray(template)) throw new ConfigError("Init template must contain a configuration object.", "ERR_CONFIG_PARSE");
1470
+ template.nanos ??= {};
1471
+ template.nanos.realms ??= Object.fromEntries(DEFAULT_REALM_MAPPINGS.map(({ pattern, realm }) => [pattern, realm]));
1469
1472
  if (options?.vendor) {
1470
1473
  const sourceAnnotations = options.annotationsPath || getDefaultAnnotationsPath();
1471
1474
  if (!fs.existsSync(sourceAnnotations)) throw new ConfigError(`Definitions file not found at ${sourceAnnotations}. Make sure annotations have been downloaded or pass a valid file with --annotations.`, "ERR_ANNOTATIONS_NOT_FOUND", "Run 'nanos-lint warmup' to download annotations or provide --annotations <path>.");
1472
- const targetNanosDir = path.join(workspacePath, ".nanos-lint");
1473
- fs.mkdirSync(targetNanosDir, { recursive: true });
1474
- const targetAnnotations = path.join(targetNanosDir, "annotations.lua");
1475
+ const targetAnnotations = path.join(workspacePath, ".nanos-lint", "annotations.lua");
1476
+ fs.mkdirSync(path.dirname(targetAnnotations), { recursive: true });
1475
1477
  fs.copyFileSync(sourceAnnotations, targetAnnotations);
1476
1478
  template.workspace = template.workspace ?? {};
1477
- template.workspace.library = [".nanos-lint/annotations.lua"];
1478
- const existingIgnore = template.workspace.ignoreDir ?? [];
1479
- if (!existingIgnore.includes(".nanos-lint")) template.workspace.ignoreDir = [".nanos-lint", ...existingIgnore];
1479
+ template.workspace.library = [.../* @__PURE__ */ new Set([...template.workspace.library ?? [], ".nanos-lint/annotations.lua"])];
1480
+ template.workspace.ignoreDir = [.../* @__PURE__ */ new Set([".nanos-lint", ...template.workspace.ignoreDir ?? []])];
1480
1481
  template.files = template.files ?? {};
1481
- const existingExclude = template.files.exclude ?? [];
1482
- if (!existingExclude.includes(".nanos-lint/**")) template.files.exclude = [".nanos-lint/**", ...existingExclude];
1482
+ template.files.exclude = [.../* @__PURE__ */ new Set([".nanos-lint/**", ...template.files.exclude ?? []])];
1483
1483
  }
1484
1484
  fs.writeFileSync(targetFile, JSON.stringify(template, null, 2), "utf-8");
1485
1485
  return targetFile;
@@ -7135,6 +7135,40 @@ function resolveCheckTargets(rawPaths) {
7135
7135
  };
7136
7136
  }
7137
7137
  //#endregion
7138
+ //#region src/luals/offline.ts
7139
+ /** Validates an explicit local executable and checks a requested version against its output. */
7140
+ function validateOfflineBinary(binary, version) {
7141
+ const resolved = assertValidLuaLSBinary(binary, "offline local binary");
7142
+ if (version !== "latest") {
7143
+ if (!execFileSync(resolved, ["--version"], {
7144
+ encoding: "utf-8",
7145
+ timeout: 5e3
7146
+ }).split(/\s+/).some((part) => sanitizeLuaLSVersion(part) === version)) throw new LuaLSError(`Offline LuaLS binary ${resolved} does not match requested version ${version}.`, "ERR_LUALS_OFFLINE", `Run 'nanos-lint warmup --luals-version ${version}' online or set LUALS_BIN to a matching binary.`);
7147
+ }
7148
+ return resolved;
7149
+ }
7150
+ /** Resolves local LuaLS assets without changing cache entries or discovering remote releases. */
7151
+ function resolveOfflineLuaLS(version, cacheDir = getBaseLuaLSCacheDir()) {
7152
+ const requested = version === "latest" ? version : sanitizeLuaLSVersion(version);
7153
+ if (!requested) throw new LuaLSError(`Invalid LuaLS version: "${version}".`, "ERR_LUALS_INVALID_VERSION");
7154
+ if (process.env.LUALS_BIN) return validateOfflineBinary(process.env.LUALS_BIN, requested);
7155
+ const versions = listCachedLuaLSVersions(cacheDir).sort((a, b) => b.localeCompare(a, "en", { numeric: true }));
7156
+ const selected = requested === "latest" ? versions[0] : versions.find((v) => v === requested);
7157
+ if (selected) {
7158
+ logger.info(`[luals] Offline: using cached LuaLS ${selected}.`);
7159
+ return path.join(getCacheDir(selected, cacheDir), getPlatformInfo(selected).binaryRelativePath);
7160
+ }
7161
+ const bundled = path.join(getPackageRoot(), getPlatformInfo(FALLBACK_LUALS_VERSION).binaryRelativePath);
7162
+ if (fs.existsSync(bundled)) return validateOfflineBinary(bundled, requested);
7163
+ try {
7164
+ const found = execFileSync(process.platform === "win32" ? "where.exe" : "which", ["lua-language-server"], { encoding: "utf-8" }).trim().split(/\r?\n/)[0];
7165
+ if (found) return validateOfflineBinary(found, requested);
7166
+ } catch (err) {
7167
+ rethrowLuaLSPermissionError(err, "lua-language-server", "execute");
7168
+ }
7169
+ throw new LuaLSError(`Offline: no usable local LuaLS binary for ${requested}.`, "ERR_LUALS_OFFLINE", `Run 'nanos-lint warmup${requested === "latest" ? "" : ` --luals-version ${requested}`}' online or set LUALS_BIN to a matching local executable.`);
7170
+ }
7171
+ //#endregion
7138
7172
  //#region src/luals/files.ts
7139
7173
  /** Directories skipped unless the workspace config overrides `workspace.ignoreDir`. */
7140
7174
  const DEFAULT_IGNORE_DIRS = [
@@ -7303,6 +7337,7 @@ function isOfflineError(err) {
7303
7337
  }
7304
7338
  /** Resolves the executable path of a LuaLS binary from env, bundle, cache, or network download. */
7305
7339
  async function resolveLuaLSBinary(version = DEFAULT_LUALS_VERSION, options) {
7340
+ if (options?.offline) return resolveOfflineLuaLS(version, options.cacheDir);
7306
7341
  if (process.env.LUALS_BIN) return assertValidLuaLSBinary(process.env.LUALS_BIN, "LUALS_BIN");
7307
7342
  if (options?.reuseExisting !== false && (!version || version === "latest")) {
7308
7343
  const defaultInfo = getPlatformInfo(FALLBACK_LUALS_VERSION);
@@ -7448,7 +7483,7 @@ async function runLuaLSCheck(targetPath, configPath, options) {
7448
7483
  logger.debug(`[luals] Failed to resolve native realpath for target: ${err instanceof Error ? err.message : String(err)}`);
7449
7484
  }
7450
7485
  if (!fs.existsSync(absoluteTarget)) throw new LuaLSError(`Target path does not exist: ${targetPath}`, "ERR_TARGET_NOT_FOUND", "Verify that the target path exists and is accessible.");
7451
- const binary = options.lualsBin ? assertValidLuaLSBinary(options.lualsBin, "--luals-bin") : await resolveLuaLSBinary(options.lualsVersion);
7486
+ const binary = options.lualsBin ? options.offline ? validateOfflineBinary(options.lualsBin, options.lualsVersion ?? "latest") : assertValidLuaLSBinary(options.lualsBin, "--luals-bin") : await resolveLuaLSBinary(options.lualsVersion, { offline: options.offline });
7452
7487
  let checkDir = absoluteTarget;
7453
7488
  let targetFileOnly = null;
7454
7489
  if (fs.statSync(absoluteTarget).isFile()) {
@@ -7990,7 +8025,7 @@ function formatPretty(result, cwd = process.cwd(), useColor = shouldEnableColor(
7990
8025
  const c = getColors(useColor);
7991
8026
  const symCross = "✖ ";
7992
8027
  const symCheck = "✔ ";
7993
- if (result.passed) {
8028
+ if (result.passed && !result.baselineSummary) {
7994
8029
  const fileStr = pluralize(result.totalFilesChecked ?? result.totalFiles, "file");
7995
8030
  return `${c.green}${c.bold}${symCheck}Diagnosis completed, no problems found across ${fileStr}.${c.reset}`;
7996
8031
  }
@@ -8006,6 +8041,7 @@ function formatPretty(result, cwd = process.cwd(), useColor = shouldEnableColor(
8006
8041
  logger.debug(`Failed to read file snippet for ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
8007
8042
  }
8008
8043
  for (const d of diags) {
8044
+ if (d.baseline) continue;
8009
8045
  const line = d.range.start.line + 1;
8010
8046
  const col = d.range.start.character + 1;
8011
8047
  const badge = formatSeverityBadge(d.severity, useColor);
@@ -8031,8 +8067,10 @@ function formatPretty(result, cwd = process.cwd(), useColor = shouldEnableColor(
8031
8067
  else if (d.severity === 2) warnings++;
8032
8068
  }
8033
8069
  lines.push("");
8034
- const summary = formatProblemSummary(result.totalProblems, errors, warnings, result.totalFiles);
8035
- lines.push(`${c.red}${c.bold}${symCross}${summary}${c.reset}`);
8070
+ const counts = result.baselineSummary;
8071
+ const summary = counts ? `Diagnosis complete: ${counts.new} new, ${counts.baselined} baselined, ${counts.total} total (${counts.stale} stale baseline entries).` : formatProblemSummary(result.totalProblems, errors, warnings, result.totalFiles);
8072
+ const color = result.passed ? c.green : c.red;
8073
+ lines.push(`${color}${c.bold}${result.passed ? symCheck : symCross}${summary}${c.reset}`);
8036
8074
  return lines.join("\n");
8037
8075
  }
8038
8076
  /** Formats check diagnostics into GitHub Actions workflow annotation commands. */
@@ -8043,6 +8081,7 @@ function formatGitHubAnnotations(result, cwd = process.cwd()) {
8043
8081
  const filePath = fileUriToPath(rawUri);
8044
8082
  const escapedFile = (path.isAbsolute(filePath) ? path.relative(cwd, filePath).replace(/\\/g, "/") : filePath.replace(/\\/g, "/")).replace(/%/g, "%25").replace(/,/g, "%2C");
8045
8083
  for (const d of diags) {
8084
+ if (d.baseline) continue;
8046
8085
  const line = d.range.start.line + 1;
8047
8086
  const col = d.range.start.character + 1;
8048
8087
  const endLine = d.range.end.line + 1;
@@ -11319,6 +11358,10 @@ async function resolveAnnotations(options = {}) {
11319
11358
  if (fs.existsSync(bundled) && isAnnotationsValid(bundled)) return bundled;
11320
11359
  const cacheDir = options.cacheDir ?? getAnnotationsCacheDir();
11321
11360
  const cachedAnnotationsFile = path.join(cacheDir, ANNOTATIONS_FILENAME);
11361
+ if (options.offline) {
11362
+ if (isAnnotationsValid(cachedAnnotationsFile)) return cachedAnnotationsFile;
11363
+ throw new AnnotationsError(`Offline: no usable local annotations.lua at ${cachedAnnotationsFile}.`, "ERR_ANNOTATIONS_OFFLINE", "Run 'nanos-lint warmup' online or specify --annotations <path>.");
11364
+ }
11322
11365
  const metadata = readAnnotationsMetadata(cacheDir);
11323
11366
  const { dateStr } = getTodayDateString();
11324
11367
  if (fs.existsSync(cachedAnnotationsFile) && !isAnnotationsValid(cachedAnnotationsFile)) {
@@ -11374,7 +11417,10 @@ async function copyAnnotations(targetPath = DEFAULT_COPY_TARGET, options = {}) {
11374
11417
  let resolvedTarget = path.resolve(targetPath);
11375
11418
  if (targetPath.endsWith("/") || targetPath.endsWith("\\") || fs.existsSync(resolvedTarget) && fs.statSync(resolvedTarget).isDirectory() || path.extname(resolvedTarget).toLowerCase() !== ".lua") resolvedTarget = path.join(resolvedTarget, ANNOTATIONS_FILENAME);
11376
11419
  if (fs.existsSync(resolvedTarget) && !options.force) throw new AnnotationsError(`Target annotations file already exists: ${resolvedTarget}. Use --force to overwrite.`, "ERR_ANNOTATIONS_EXISTS", "Pass --force to overwrite the existing annotations file.");
11377
- const sourcePath = options.annotationsPath ? validateCustomAnnotationsPath(options.annotationsPath, "custom") : await resolveAnnotations({ cacheDir: options.cacheDir });
11420
+ const sourcePath = options.annotationsPath ? validateCustomAnnotationsPath(options.annotationsPath, "custom") : await resolveAnnotations({
11421
+ cacheDir: options.cacheDir,
11422
+ offline: options.offline
11423
+ });
11378
11424
  const targetDir = path.dirname(resolvedTarget);
11379
11425
  fs.mkdirSync(targetDir, { recursive: true });
11380
11426
  fs.copyFileSync(sourcePath, resolvedTarget);
@@ -11480,6 +11526,106 @@ function writeOutput(message) {
11480
11526
  if (logger.isOutputEnabled()) console.log(message);
11481
11527
  }
11482
11528
  //#endregion
11529
+ //#region src/baseline.ts
11530
+ /** Builds a line-independent diagnostic identity relative to the checked workspace root. */
11531
+ function entryFor(root, uri, diagnostic) {
11532
+ const file = fileUriToPath(uri);
11533
+ return {
11534
+ path: path.relative(root, path.isAbsolute(file) ? file : path.resolve(root, file)).replace(/\\/g, "/"),
11535
+ code: diagnostic.code ?? "",
11536
+ message: diagnostic.message.replace(/\s+/g, " ").trim(),
11537
+ severity: diagnostic.severity,
11538
+ count: 1
11539
+ };
11540
+ }
11541
+ /** Serializes the fields defining a diagnostic identity, excluding occurrence count. */
11542
+ function keyFor(entry) {
11543
+ return JSON.stringify([
11544
+ entry.path,
11545
+ entry.code,
11546
+ entry.message,
11547
+ entry.severity
11548
+ ]);
11549
+ }
11550
+ /** Records sorted diagnostic identities and multiplicities without source positions. */
11551
+ function createBaseline(result, root) {
11552
+ const entries = /* @__PURE__ */ new Map();
11553
+ for (const [uri, diagnostics] of Object.entries(result.diagnostics)) for (const diagnostic of diagnostics) {
11554
+ const entry = entryFor(root, uri, diagnostic);
11555
+ const key = keyFor(entry);
11556
+ const previous = entries.get(key);
11557
+ if (previous) previous.count++;
11558
+ else entries.set(key, entry);
11559
+ }
11560
+ return {
11561
+ version: 1,
11562
+ entries: [...entries.values()].sort((a, b) => {
11563
+ const left = keyFor(a);
11564
+ const right = keyFor(b);
11565
+ return left < right ? -1 : left > right ? 1 : 0;
11566
+ })
11567
+ };
11568
+ }
11569
+ /** Validates a persisted baseline and rejects ambiguous or incompatible entries. */
11570
+ function readBaseline(file) {
11571
+ try {
11572
+ const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
11573
+ if (parsed?.version !== 1 || !Array.isArray(parsed.entries)) throw new Error("Unsupported baseline schema (expected version 1).");
11574
+ const keys = /* @__PURE__ */ new Set();
11575
+ for (const entry of parsed.entries) {
11576
+ if (!entry || typeof entry.path !== "string" || !entry.path || typeof entry.code !== "string" || typeof entry.message !== "string" || !Number.isInteger(entry.severity) || entry.severity < 1 || entry.severity > 4 || !Number.isSafeInteger(entry.count) || entry.count < 1) throw new Error("Invalid baseline diagnostic entry.");
11577
+ const key = keyFor(entry);
11578
+ if (keys.has(key)) throw new Error("Duplicate baseline diagnostic entry.");
11579
+ keys.add(key);
11580
+ }
11581
+ return parsed;
11582
+ } catch (cause) {
11583
+ throw new ConfigError(`Cannot read diagnostic baseline ${file}: ${cause instanceof Error ? cause.message : String(cause)}`, "ERR_BASELINE_READ", "Regenerate with 'nanos-lint check <targets> --write-baseline <path>' using the same targets and options.", { cause });
11584
+ }
11585
+ }
11586
+ /** Atomically writes a deterministic baseline, creating its parent directory if needed. */
11587
+ function writeBaseline(file, result, root) {
11588
+ try {
11589
+ writeAtomicFileSync(path.resolve(file), `${JSON.stringify(createBaseline(result, root), null, 2)}\n`);
11590
+ } catch (cause) {
11591
+ throw new ConfigError(`Cannot write diagnostic baseline ${file}: ${cause instanceof Error ? cause.message : String(cause)}`, "ERR_BASELINE_WRITE", "Choose a writable baseline path.", { cause });
11592
+ }
11593
+ }
11594
+ /** Classifies each diagnostic against an occurrence budget and computes strict staleness. */
11595
+ function compareBaseline(result, baseline, root, strict = false) {
11596
+ const remaining = new Map(baseline.entries.map((entry) => [keyFor(entry), entry.count]));
11597
+ const diagnostics = {};
11598
+ let baselined = 0;
11599
+ let total = 0;
11600
+ for (const [uri, items] of Object.entries(result.diagnostics)) diagnostics[uri] = [...items].sort((a, b) => a.range.start.line - b.range.start.line || a.range.start.character - b.range.start.character).map((diagnostic) => {
11601
+ const key = keyFor(entryFor(root, uri, diagnostic));
11602
+ const count = remaining.get(key) ?? 0;
11603
+ const matched = count > 0;
11604
+ if (matched) {
11605
+ remaining.set(key, count - 1);
11606
+ baselined++;
11607
+ }
11608
+ total++;
11609
+ return {
11610
+ ...diagnostic,
11611
+ baseline: matched
11612
+ };
11613
+ });
11614
+ const stale = [...remaining.values()].reduce((sum, count) => sum + count, 0);
11615
+ const newProblems = total - baselined;
11616
+ return {
11617
+ ...result,
11618
+ diagnostics,
11619
+ passed: newProblems === 0 && (!strict || stale === 0),
11620
+ baselineSummary: {
11621
+ new: newProblems,
11622
+ baselined,
11623
+ total,
11624
+ stale
11625
+ }
11626
+ };
11627
+ }
11628
+ //#endregion
11483
11629
  //#region src/cli-check.ts
11484
11630
  /** Executes the check command on target paths with specified options. */
11485
11631
  async function executeCheckCommand(targetPaths = ["."], opts, setExitCode) {
@@ -11490,7 +11636,10 @@ async function executeCheckCommand(targetPaths = ["."], opts, setExitCode) {
11490
11636
  setProgressMode("off");
11491
11637
  logger.setDiagnosticStream("stderr");
11492
11638
  }
11639
+ if (opts.baseline && opts.writeBaseline || opts.baselineStrict && !opts.baseline) throw new ConfigError("Use either --baseline or --write-baseline; --baseline-strict requires --baseline.", "ERR_BASELINE_OPTIONS");
11640
+ const baseline = opts.baseline ? readBaseline(path.resolve(opts.baseline)) : void 0;
11493
11641
  const checkOptions = {
11642
+ offline: opts.offline,
11494
11643
  path: rootPath,
11495
11644
  paths: canonicalTargets,
11496
11645
  configpath: opts.config,
@@ -11505,7 +11654,10 @@ async function executeCheckCommand(targetPaths = ["."], opts, setExitCode) {
11505
11654
  const resolvedConfig = path.resolve(opts.config);
11506
11655
  if (!fs.existsSync(resolvedConfig)) throw new ConfigError(`Configuration file not found: ${resolvedConfig}`, "ERR_CONFIG_NOT_FOUND", "Verify the path passed to --config exists and is readable.");
11507
11656
  }
11508
- const annotationsPath = await resolveAnnotations({ customPath: opts.annotations });
11657
+ const annotationsPath = await resolveAnnotations({
11658
+ customPath: opts.annotations,
11659
+ offline: opts.offline
11660
+ });
11509
11661
  const userConfig = loadUserConfig(rootPath, checkOptions.configpath);
11510
11662
  const realmPlan = planRealmCheck({
11511
11663
  targetPath: rootPath,
@@ -11542,6 +11694,10 @@ async function executeCheckCommand(targetPaths = ["."], opts, setExitCode) {
11542
11694
  }
11543
11695
  }
11544
11696
  }
11697
+ if (opts.writeBaseline) {
11698
+ writeBaseline(opts.writeBaseline, result, rootPath);
11699
+ result = compareBaseline(result, createBaseline(result, rootPath), rootPath);
11700
+ } else if (baseline) result = compareBaseline(result, baseline, rootPath, opts.baselineStrict);
11545
11701
  const output = formatReport(result, checkOptions.format, process.cwd());
11546
11702
  if (output) writeOutput(output);
11547
11703
  if (!result.passed && checkOptions.failOnError) setExitCode(1);
@@ -11574,7 +11730,7 @@ function createProgram(options) {
11574
11730
  "info",
11575
11731
  "debug",
11576
11732
  "silent"
11577
- ]).default(DEFAULT_LOG_LEVEL)).option("--no-progress", "Disable the interactive download, extraction and realm derivation progress display").hook("preAction", (thisCommand, actionCommand) => {
11733
+ ]).default(DEFAULT_LOG_LEVEL)).option("--offline", "Use local dependencies only; never access the network").option("--no-progress", "Disable the interactive download, extraction and realm derivation progress display").hook("preAction", (thisCommand, actionCommand) => {
11578
11734
  const target = actionCommand || thisCommand;
11579
11735
  const opts = target.optsWithGlobals ? target.optsWithGlobals() : target.opts();
11580
11736
  if (opts.logLevel && isValidLogLevel(opts.logLevel)) logger.setLevel(opts.logLevel);
@@ -11592,7 +11748,7 @@ function createProgram(options) {
11592
11748
  "pretty",
11593
11749
  "json",
11594
11750
  "github"
11595
- ])).option("-i, --ignore <pattern>", "Files or directories to ignore (supports glob patterns, repeatable)", collectIgnorePatterns).option("-d, --dep <path>", "Path to package dependency or Lua definition file (repeatable)", collectDeps).option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`, DEFAULT_LUALS_VERSION).option("--no-fail", "Do not exit with code 1 if diagnostics are found").addOption(new Option("-l, --log-level <level>", "Logging level: error, warn, info, debug, silent").choices([
11751
+ ])).option("-i, --ignore <pattern>", "Files or directories to ignore (supports glob patterns, repeatable)", collectIgnorePatterns).option("-d, --dep <path>", "Path to package dependency or Lua definition file (repeatable)", collectDeps).option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`, DEFAULT_LUALS_VERSION).option("--baseline <path>", "Report and fail only on diagnostics absent from a saved baseline").option("--write-baseline <path>", "Record current diagnostics as a baseline and exit successfully").option("--baseline-strict", "Also fail on stale baseline entries (requires --baseline)").option("--no-fail", "Do not exit with code 1 if diagnostics are found").addOption(new Option("-l, --log-level <level>", "Logging level: error, warn, info, debug, silent").choices([
11596
11752
  "error",
11597
11753
  "warn",
11598
11754
  "info",
@@ -11603,38 +11759,48 @@ function createProgram(options) {
11603
11759
  "client",
11604
11760
  "server",
11605
11761
  "shared"
11606
- ]).default("all")).action(async (targetPaths = ["."], opts) => {
11762
+ ]).default("all")).action(async (targetPaths = ["."], opts, cmd) => {
11763
+ opts.offline = cmd.optsWithGlobals().offline;
11607
11764
  await executeCheckCommand(targetPaths, opts, setExitCode);
11608
11765
  });
11609
- program.command("init [path]").description("Scaffold a .luarc.json configuration in the workspace").option("-f, --force", "Overwrite existing .luarc.json configuration").option("--vendor", "Vendor annotations.lua into .nanos-lint/ inside workspace for portable standalone editor setup").option("--annotations <path>", "Path to custom annotations.lua file (requires --vendor)").action(async (targetPath = ".", opts) => {
11766
+ program.command("init [path]").description("Scaffold a .luarc.json configuration in the workspace").option("-t, --template <path>", "Custom JSONC .luarc.json scaffold template").option("-f, --force", "Overwrite existing .luarc.json configuration").option("--vendor", "Vendor annotations.lua into .nanos-lint/ inside workspace for portable standalone editor setup").option("--annotations <path>", "Path to custom annotations.lua file (requires --vendor)").action(async (targetPath = ".", opts, cmd) => {
11767
+ opts.offline = cmd.optsWithGlobals().offline;
11610
11768
  const shouldVendor = Boolean(opts.vendor);
11611
- const annotationsPath = shouldVendor ? await resolveAnnotations({ customPath: opts.annotations }) : opts.annotations;
11769
+ const annotationsPath = shouldVendor ? await resolveAnnotations({
11770
+ customPath: opts.annotations,
11771
+ offline: opts.offline
11772
+ }) : opts.annotations;
11612
11773
  writeOutput(`[init] Initialized nanos world LuaLS configuration: ${initWorkspace(path.resolve(targetPath), {
11613
11774
  force: opts.force,
11614
11775
  annotationsPath,
11615
- vendor: shouldVendor
11776
+ vendor: shouldVendor,
11777
+ templatePath: opts.template
11616
11778
  })}`);
11617
11779
  setExitCode(0);
11618
11780
  });
11619
- program.command("copy-annotations [destination]").alias("export-annotations").description("Copy cached nanos world annotations.lua definitions into a target file or directory (targets not ending in .lua are treated as directories)").option("-f, --force", "Overwrite existing annotations file").option("--annotations <path>", "Path to custom annotations.lua source file").action(async (destination, opts) => {
11781
+ program.command("copy-annotations [destination]").alias("export-annotations").description("Copy cached nanos world annotations.lua definitions into a target file or directory (targets not ending in .lua are treated as directories)").option("-f, --force", "Overwrite existing annotations file").option("--annotations <path>", "Path to custom annotations.lua source file").action(async (destination, opts, cmd) => {
11620
11782
  writeOutput(`[copy-annotations] Copied nanos world annotations to: ${await copyAnnotations(destination, {
11621
11783
  force: opts.force,
11622
- annotationsPath: opts.annotations
11784
+ annotationsPath: opts.annotations,
11785
+ offline: cmd.optsWithGlobals().offline
11623
11786
  })}`);
11624
11787
  setExitCode(0);
11625
11788
  });
11626
- program.command("warmup").alias("download").description("Pre-fetch and cache both LuaLS binary and annotations for offline execution").option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`).option("--annotations <path>", "Path to custom annotations.lua file").action(async (opts) => {
11627
- writeOutput(`[warmup] LuaLS binary ready: ${await resolveLuaLSBinary(opts?.lualsVersion || "latest")}`);
11628
- const annotationsPath = await resolveAnnotations({ customPath: opts?.annotations });
11789
+ program.command("warmup").alias("download").description("Pre-fetch and cache both LuaLS binary and annotations for offline execution").option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`).option("--annotations <path>", "Path to custom annotations.lua file").action(async (opts, cmd) => {
11790
+ writeOutput(`[warmup] LuaLS binary ready: ${await resolveLuaLSBinary(opts?.lualsVersion || "latest", { offline: cmd.optsWithGlobals().offline })}`);
11791
+ const annotationsPath = await resolveAnnotations({
11792
+ customPath: opts?.annotations,
11793
+ offline: cmd.optsWithGlobals().offline
11794
+ });
11629
11795
  const meta = readAnnotationsMetadata();
11630
11796
  writeOutput(`[warmup] nanos world annotations ready: ${annotationsPath}${meta?.commitId && meta.commitId !== "unknown" ? ` (commit ${meta.commitId.slice(0, 7)})` : ""}`);
11631
11797
  writeOutput("[warmup] Cache pre-warmed successfully. Ready for offline execution.");
11632
11798
  setExitCode(0);
11633
11799
  });
11634
- program.command("download-luals [version]").description("Download and cache the LuaLS binary").option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`).action(async (version, opts) => {
11800
+ program.command("download-luals [version]").description("Download and cache the LuaLS binary").option("--luals-version <ver>", `Version of LuaLS to use (default: ${DEFAULT_LUALS_VERSION})`).action(async (version, opts, cmd) => {
11635
11801
  const ver = version || opts?.lualsVersion || "latest";
11636
11802
  writeOutput(`[luals] Downloading LuaLS ${ver}...`);
11637
- writeOutput(`[luals] Ready at: ${await resolveLuaLSBinary(ver)}`);
11803
+ writeOutput(`[luals] Ready at: ${await resolveLuaLSBinary(ver, { offline: cmd.optsWithGlobals().offline })}`);
11638
11804
  setExitCode(0);
11639
11805
  });
11640
11806
  const handleCleanCache = () => {
@@ -11766,6 +11932,6 @@ if (isDirectExecution()) runCLI().then((code) => {
11766
11932
  process.exit(1);
11767
11933
  });
11768
11934
  //#endregion
11769
- export { resolveCheckTargets as $, VALID_LUALS_DIAGNOSTIC_CODES as $t, formatPretty as A, logger as An, validateArchiveMembers as At, collectDeps as B, deriveRealmAnnotationFiles as Bt, getAnnotationsMetadataFilePath as C, systemPaths as Cn, inspectZipMembers as Ct, readAnnotationsMetadata as D, LOG_LEVEL_PRIORITY as Dn, isZipArchive as Dt, isAnnotationsValid as E, LOG_LEVELS as En, isGzipArchive as Et, pluralize as F, resolveLatestLuaLSVersion as Ft, listCheckedFiles as G, createProgressBar as Gt, resolveLuaLSBinary as H, PROGRESS_MILESTONES as Ht, shouldEnableColor as I, resolveLuaLSVersion as It, findCommonAncestorDirectory as J, getProgressMode as Jt, computeUnrequestedExclusions as K, createSpinner as Kt, collectRealmFiles as L, sanitizeLuaLSVersion as Lt, formatReport as M, DEFAULT_LUALS_VERSION as Mt, formatSeverityBadge as N, FALLBACK_LUALS_VERSION as Nt, updateLastCheckedDate as O, Logger as On, parseTarTvSize as Ot, getColors as P, fetchLatestLuaLSVersionFromGitHub as Pt, matchesTargetPaths as Q, DEFAULT_REALM_MAPPINGS as Qt, planRealmCheck as R, ALLOWED_DOWNLOAD_DOMAINS as Rt, getAnnotationsCacheDir as S, getDirectorySize as Sn, getTarBinary as St, getTodayDateString as T, DEFAULT_LOG_LEVEL as Tn, isBinaryValid as Tt, runLuaLSCheck as U, PROGRESS_THROTTLE_MS as Ut, resolvePackageDependencies as V, splitAnnotationsByRealm as Vt, countCheckedFiles as W, SPINNER_FRAMES as Wt, getCanonicalPath as X, restoreTerminal as Xt, findProjectRoot as Y, isProgressInteractive as Yt, isFilesystemRoot as Z, setProgressMode as Zt, ANNOTATIONS_FILENAME as _, ConfigError as _n, MAX_ARCHIVE_MEMBER_COUNT as _t, formatCacheStatusPretty as a, initWorkspace as an, trackDownloadProgress as at, METADATA_FILENAME as b, cleanCache as bn, assertValidLuaLSBinary as bt, resolveAnnotations as c, mergeConfigs as cn, findExistingLuaLSDir as ct, GITHUB_COMMITS_API as d, resolveWorkspaceConfig as dn, getIsoWeek as dt, buildWorkspaceConfig as en, DOWNLOAD_TIMEOUT_MS as et, RAW_ANNOTATIONS_URL as f, stripJsonComments as fn, getLuaLSMetadataPath as ft, getRawAnnotationsUrl as g, CacheError as gn, writeLuaLSMetadata as gt, fetchRawAnnotationsContent as h, AnnotationsError as hn, readLuaLSMetadata as ht, runCLI as i, getPackageRoot as in, limitDownloadStream as it, formatProblemSummary as j, parseLogLevel as jn, getPlatformInfo as jt, formatGitHubAnnotations as k, isValidLogLevel as kn, rethrowLuaLSPermissionError as kt, DOCGEN_BRANCH as l, parseJsonc as ln, getBaseLuaLSCacheDir as lt, fetchLatestCommitId as m, writeTempConfig as mn, listCachedLuaLSVersions as mt, createProgram as n, getDefaultTemplatePath as nn, computeFileSha256 as nt, getCacheStatus as o, loadConfigFile as on, LUALS_METADATA_FILENAME as ot, downloadAndCacheAnnotations as p, stripTrailingSlashes as pn, listCachedLuaLSVersionDirs as pt, filterReportByTargetPaths as q, formatTransferSummary as qt, isDirectExecution as r, getDefinitionsDir as rn, downloadAndExtractLuaLS as rt, copyAnnotations as s, loadUserConfig as sn, cleanupOldCachedLuaLSVersions as st, collectIgnorePatterns as t, getDefaultAnnotationsPath as tn, MAX_ARCHIVE_SIZE_BYTES as tt, DOCGEN_REPO as u, resolveRealmMappings as un, getCacheDir as ut, MAX_ANNOTATIONS_SIZE_BYTES as v, LuaLSError as vn, MAX_DECOMPRESSED_SIZE_BYTES as vt, getCachedAnnotationsFilePath as w, fileUriToPath as wn, isBinaryRunnable as wt, MIN_ANNOTATIONS_SIZE_BYTES as x, formatBytes as xn, escapePowerShellSingleQuote as xt, MAX_COMMIT_JSON_SIZE_BYTES as y, NanosLintError as yn, MIN_DOWNLOADED_BINARY_SIZE_BYTES as yt, runRealmAwareCheck as z, isAllowedDownloadUrl as zt };
11935
+ export { findProjectRoot as $, isProgressInteractive as $t, isAnnotationsValid as A, LOG_LEVELS as An, isGzipArchive as At, shouldEnableColor as B, resolveLuaLSVersion as Bt, MAX_COMMIT_JSON_SIZE_BYTES as C, NanosLintError as Cn, MIN_DOWNLOADED_BINARY_SIZE_BYTES as Ct, getAnnotationsMetadataFilePath as D, systemPaths as Dn, inspectZipMembers as Dt, getAnnotationsCacheDir as E, getDirectorySize as En, getTarBinary as Et, formatProblemSummary as F, parseLogLevel as Fn, getPlatformInfo as Ft, resolvePackageDependencies as G, splitAnnotationsByRealm as Gt, planRealmCheck as H, ALLOWED_DOWNLOAD_DOMAINS as Ht, formatReport as I, DEFAULT_LUALS_VERSION as It, countCheckedFiles as J, SPINNER_FRAMES as Jt, resolveLuaLSBinary as K, PROGRESS_MILESTONES as Kt, formatSeverityBadge as L, FALLBACK_LUALS_VERSION as Lt, updateLastCheckedDate as M, Logger as Mn, parseTarTvSize as Mt, formatGitHubAnnotations as N, isValidLogLevel as Nn, rethrowLuaLSPermissionError as Nt, getCachedAnnotationsFilePath as O, fileUriToPath as On, isBinaryRunnable as Ot, formatPretty as P, logger as Pn, validateArchiveMembers as Pt, findCommonAncestorDirectory as Q, getProgressMode as Qt, getColors as R, fetchLatestLuaLSVersionFromGitHub as Rt, MAX_ANNOTATIONS_SIZE_BYTES as S, LuaLSError as Sn, MAX_DECOMPRESSED_SIZE_BYTES as St, MIN_ANNOTATIONS_SIZE_BYTES as T, formatBytes as Tn, escapePowerShellSingleQuote as Tt, runRealmAwareCheck as U, isAllowedDownloadUrl as Ut, collectRealmFiles as V, sanitizeLuaLSVersion as Vt, collectDeps as W, deriveRealmAnnotationFiles as Wt, computeUnrequestedExclusions as X, createSpinner as Xt, listCheckedFiles as Y, createProgressBar as Yt, filterReportByTargetPaths as Z, formatTransferSummary as Zt, downloadAndCacheAnnotations as _, stripTrailingSlashes as _n, listCachedLuaLSVersionDirs as _t, compareBaseline as a, getDefaultAnnotationsPath as an, MAX_ARCHIVE_SIZE_BYTES as at, getRawAnnotationsUrl as b, CacheError as bn, writeLuaLSMetadata as bt, writeBaseline as c, getPackageRoot as cn, limitDownloadStream as ct, copyAnnotations as d, loadUserConfig as dn, cleanupOldCachedLuaLSVersions as dt, restoreTerminal as en, getCanonicalPath as et, resolveAnnotations as f, mergeConfigs as fn, findExistingLuaLSDir as ft, RAW_ANNOTATIONS_URL as g, stripJsonComments as gn, getLuaLSMetadataPath as gt, GITHUB_COMMITS_API as h, resolveWorkspaceConfig as hn, getIsoWeek as ht, runCLI as i, buildWorkspaceConfig as in, DOWNLOAD_TIMEOUT_MS as it, readAnnotationsMetadata as j, LOG_LEVEL_PRIORITY as jn, isZipArchive as jt, getTodayDateString as k, DEFAULT_LOG_LEVEL as kn, isBinaryValid as kt, formatCacheStatusPretty as l, initWorkspace as ln, trackDownloadProgress as lt, DOCGEN_REPO as m, resolveRealmMappings as mn, getCacheDir as mt, createProgram as n, DEFAULT_REALM_MAPPINGS as nn, matchesTargetPaths as nt, createBaseline as o, getDefaultTemplatePath as on, computeFileSha256 as ot, DOCGEN_BRANCH as p, parseJsonc as pn, getBaseLuaLSCacheDir as pt, runLuaLSCheck as q, PROGRESS_THROTTLE_MS as qt, isDirectExecution as r, VALID_LUALS_DIAGNOSTIC_CODES as rn, resolveCheckTargets as rt, readBaseline as s, getDefinitionsDir as sn, downloadAndExtractLuaLS as st, collectIgnorePatterns as t, setProgressMode as tn, isFilesystemRoot as tt, getCacheStatus as u, loadConfigFile as un, LUALS_METADATA_FILENAME as ut, fetchLatestCommitId as v, writeTempConfig as vn, listCachedLuaLSVersions as vt, METADATA_FILENAME as w, cleanCache as wn, assertValidLuaLSBinary as wt, ANNOTATIONS_FILENAME as x, ConfigError as xn, MAX_ARCHIVE_MEMBER_COUNT as xt, fetchRawAnnotationsContent as y, AnnotationsError as yn, readLuaLSMetadata as yt, pluralize as z, resolveLatestLuaLSVersion as zt };
11770
11936
 
11771
- //# sourceMappingURL=cli-CsIAHyRZ.js.map
11937
+ //# sourceMappingURL=cli-DN7ZhC9e.js.map