@codacy/verity-cli 0.34.5-experimental.7268b07 → 0.34.5-experimental.f1c33b5

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/bin/verity.js CHANGED
@@ -16946,7 +16946,9 @@ var TOP_KEYS = /* @__PURE__ */ new Set([
16946
16946
  "tool_configuration",
16947
16947
  "created_by",
16948
16948
  "version",
16949
- "verityignore"
16949
+ "verityignore",
16950
+ "extends",
16951
+ "overrides"
16950
16952
  ]);
16951
16953
  var KNOWLEDGE_SPEC_KEYS = /* @__PURE__ */ new Set([
16952
16954
  "project_name",
@@ -16973,6 +16975,12 @@ var PATTERN_KEYS = /* @__PURE__ */ new Set([
16973
16975
  ]);
16974
16976
  var DIMENSION_KEYS = /* @__PURE__ */ new Set(["id", "description", "signals"]);
16975
16977
  var SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "med", "low"]);
16978
+ var PACK_REF = /^[a-z0-9][a-z0-9-]{0,39}\/[a-z0-9][a-z0-9-]{0,39}(@[A-Za-z0-9._-]{1,40})?$/;
16979
+ var MAX_EXTENDS = 32;
16980
+ var MAX_OVERRIDES = 500;
16981
+ var MAX_OVERRIDE_LIST = 50;
16982
+ var OVERRIDE_ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,119}$/;
16983
+ var OVERRIDE_TOKEN = /^[A-Za-z0-9_.\/*?{}[\],@!:+=-]{1,300}$/;
16976
16984
  var isPlainObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
16977
16985
  var PRINTABLE = /^[^\u0000-\u001f\u007f]+$/;
16978
16986
  var CONTROL_EXCEPT_WHITESPACE = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/;
@@ -17001,6 +17009,51 @@ function checkValues(v, path, depth) {
17001
17009
  }
17002
17010
  return { ok: true };
17003
17011
  }
17012
+ function checkPackSettings(content) {
17013
+ if ("extends" in content) {
17014
+ const list2 = content.extends;
17015
+ if (!Array.isArray(list2)) return fail("extends must be an array");
17016
+ if (list2.length > MAX_EXTENDS) return fail(`extends has more than ${MAX_EXTENDS} entries`);
17017
+ const seen = /* @__PURE__ */ new Set();
17018
+ for (const [i2, ref] of list2.entries()) {
17019
+ if (typeof ref !== "string" || !PACK_REF.test(ref)) {
17020
+ return fail(`extends[${i2}] must be a pack reference such as verity/core or verity/core@2026.11`);
17021
+ }
17022
+ if (seen.has(ref)) return fail(`extends[${i2}] repeats ${ref}`);
17023
+ seen.add(ref);
17024
+ }
17025
+ }
17026
+ if ("overrides" in content) {
17027
+ const overrides = content.overrides;
17028
+ if (!isPlainObject(overrides)) return fail("overrides must be an object");
17029
+ const entries = Object.entries(overrides);
17030
+ if (entries.length > MAX_OVERRIDES) return fail(`overrides has more than ${MAX_OVERRIDES} entries`);
17031
+ for (const [id, value] of entries) {
17032
+ if (!OVERRIDE_ID.test(id)) return fail("overrides has a key that is not a pattern id (letters, digits, - _ . :)");
17033
+ const at = `overrides.${id}`;
17034
+ if (value === "off") continue;
17035
+ if (!isPlainObject(value)) return fail(`${at} must be off or an object of settings`);
17036
+ for (const [name2, v] of Object.entries(value)) {
17037
+ if (!OVERRIDE_ID.test(name2)) return fail(`${at} has a setting name that is not a slug (letters, digits, - _ . :)`);
17038
+ const where2 = `${at}.${name2}`;
17039
+ if (Array.isArray(v)) {
17040
+ if (v.length > MAX_OVERRIDE_LIST) return fail(`${where2} has more than ${MAX_OVERRIDE_LIST} entries`);
17041
+ if (!v.every((x) => typeof x === "string" && OVERRIDE_TOKEN.test(x))) {
17042
+ return fail(`${where2} must hold settings, not prose: ids, severities or globs without spaces`);
17043
+ }
17044
+ } else if (typeof v === "string") {
17045
+ if (!OVERRIDE_TOKEN.test(v)) return fail(`${where2} must be a setting, not prose: an id, a severity or a glob without spaces`);
17046
+ } else if (typeof v !== "boolean" && !(typeof v === "number" && Number.isFinite(v))) {
17047
+ return fail(`${where2} must be text, a number, true or false, or a list of text`);
17048
+ }
17049
+ }
17050
+ if ("severity" in value && !SEVERITIES.has(String(value.severity))) {
17051
+ return fail(`${at}.severity must be one of critical, high, medium, low`);
17052
+ }
17053
+ }
17054
+ }
17055
+ return { ok: true };
17056
+ }
17004
17057
  function unknownKey(obj, allowed, where2) {
17005
17058
  const extra = Object.keys(obj).find((k) => !allowed.has(k));
17006
17059
  return extra === void 0 ? null : fail(`${where2}.${extra} is not a known field`);
@@ -17027,10 +17080,10 @@ function checkEntries(list2, section, allowed, withSeverity) {
17027
17080
  function validateStandardContent(content, opts = {}) {
17028
17081
  const requireAll = opts.requireAll ?? true;
17029
17082
  if (!isPlainObject(content)) return fail("content is required and must be an object");
17030
- const size = new TextEncoder().encode(JSON.stringify(content)).length;
17031
- if (size > MAX_STANDARD_BYTES) return fail(`content is ${size} bytes; the limit is ${MAX_STANDARD_BYTES}`);
17032
17083
  const values = checkValues(content, "", 0);
17033
17084
  if (!values.ok) return values;
17085
+ const size = new TextEncoder().encode(JSON.stringify(content)).length;
17086
+ if (size > MAX_STANDARD_BYTES) return fail(`content is ${size} bytes; the limit is ${MAX_STANDARD_BYTES}`);
17034
17087
  const missing = ["knowledge_spec", "quality_dimensions", "security_patterns", "process_constraints"].filter((k) => !(k in content));
17035
17088
  if (requireAll && missing.length > 0) return fail(`content is missing required keys: ${missing.join(", ")}`);
17036
17089
  const extraTop = unknownKey(content, TOP_KEYS, "content");
@@ -17059,6 +17112,8 @@ function validateStandardContent(content, opts = {}) {
17059
17112
  const custom = checkEntries(content.custom_patterns, "custom_patterns", PATTERN_KEYS, true);
17060
17113
  if (!custom.ok) return custom;
17061
17114
  }
17115
+ const pack = checkPackSettings(content);
17116
+ if (!pack.ok) return pack;
17062
17117
  for (const key of ["created_by", "version"]) {
17063
17118
  if (key in content && content[key] !== null && typeof content[key] !== "string") return fail(`${key} must be a string`);
17064
17119
  }
@@ -28395,7 +28450,7 @@ function channelSilence(input) {
28395
28450
  // src/lib/cli-version.ts
28396
28451
  function cliVersion() {
28397
28452
  try {
28398
- return true ? "0.34.5-experimental.7268b07" : "dev";
28453
+ return true ? "0.34.5-experimental.f1c33b5" : "dev";
28399
28454
  } catch {
28400
28455
  return "dev";
28401
28456
  }
@@ -41826,6 +41881,7 @@ async function hooksStep(ui, ctx) {
41826
41881
 
41827
41882
  // src/commands/init/standard.ts
41828
41883
  var import_node_fs75 = require("node:fs");
41884
+ var import_yaml9 = __toESM2(require_dist());
41829
41885
 
41830
41886
  // src/commands/init/rules.ts
41831
41887
  async function projectLabel(token, serviceUrl, verbose) {
@@ -41850,6 +41906,12 @@ async function rulesOffered(ui, globals) {
41850
41906
  }
41851
41907
  return status === "on" || status === "unknown";
41852
41908
  }
41909
+ async function rulesOn(globals) {
41910
+ const token = await resolveToken(globals.token);
41911
+ const url = await resolveServiceUrl(globals.serviceUrl);
41912
+ if (!token.ok || !url.ok) return false;
41913
+ return await generationStatus({ serviceUrl: url.data, token: token.data.token, verbose: globals.verbose }) === "on";
41914
+ }
41853
41915
  async function askToSend(ui, profile) {
41854
41916
  const { rail, screen } = ui;
41855
41917
  const lines = consentLines(profile);
@@ -41990,6 +42052,18 @@ function sayAdopted(ui, team) {
41990
42052
  }
41991
42053
 
41992
42054
  // src/commands/init/standard.ts
42055
+ function hasProjectRules() {
42056
+ const raw = readRepoFile(STANDARD_FILE);
42057
+ if (raw === null) return true;
42058
+ try {
42059
+ const content = (0, import_yaml9.parse)(raw);
42060
+ const rules = content?.custom_patterns;
42061
+ if (rules === void 0 || rules === null) return false;
42062
+ return !Array.isArray(rules) || rules.length > 0;
42063
+ } catch {
42064
+ return true;
42065
+ }
42066
+ }
41993
42067
  async function deriveFromCatalogue(ui, globals) {
41994
42068
  const url = await resolveServiceUrl(globals.serviceUrl);
41995
42069
  try {
@@ -42046,6 +42120,9 @@ async function standardStep(ui, ctx) {
42046
42120
  rail.line(sync.version !== null ? `It was only on this machine. It is shared now as v${sync.version}.` : "It is only on this machine:", sync.version !== null ? "muted" : "warn");
42047
42121
  for (const line2 of sync.lines) if (!line2.startsWith("Standard pushed")) rail.line(terminalText(line2, 600), "warn");
42048
42122
  }
42123
+ if (!hasProjectRules() && await rulesOn(ctx.globals)) {
42124
+ rail.line("It has no project rules yet. Add them from a repo profile: verity standard generate");
42125
+ }
42049
42126
  return end({ source: "kept", version: sync.status === "pushed" ? sync.version : null, profile: notAsked });
42050
42127
  }
42051
42128
  const team = await lookUpTeamStandard(ctx);
@@ -42159,7 +42236,31 @@ var import_node_path64 = require("node:path");
42159
42236
  var import_node_child_process22 = require("node:child_process");
42160
42237
  var LEGACY_NPM_PACKAGE = "@codacy/gate-cli";
42161
42238
  function defaultNpmRemover(pkg) {
42239
+ let listing = "";
42240
+ try {
42241
+ listing = (0, import_node_child_process22.execSync)(`npm ls -g --depth=0 --json ${pkg}`, { stdio: "pipe", timeout: 6e4 }).toString();
42242
+ } catch (err2) {
42243
+ const stdout = err2.stdout;
42244
+ listing = stdout ? stdout.toString() : "";
42245
+ }
42246
+ const installed2 = parseGlobalListing(listing, pkg);
42247
+ if (installed2 === false) return "absent";
42162
42248
  (0, import_node_child_process22.execSync)(`npm rm -g ${pkg}`, { stdio: "pipe", timeout: 12e4 });
42249
+ return installed2 ? "removed" : "unknown";
42250
+ }
42251
+ function parseGlobalListing(listing, pkg) {
42252
+ let parsed;
42253
+ try {
42254
+ parsed = JSON.parse(listing);
42255
+ } catch {
42256
+ return null;
42257
+ }
42258
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
42259
+ if ("error" in parsed) return null;
42260
+ const deps = parsed.dependencies;
42261
+ if (deps === void 0) return false;
42262
+ if (!deps || typeof deps !== "object" || Array.isArray(deps)) return null;
42263
+ return Object.prototype.hasOwnProperty.call(deps, pkg);
42163
42264
  }
42164
42265
  function git2(cwd, args2) {
42165
42266
  (0, import_node_child_process22.execFileSync)("git", hardenedGitArgv(args2), { cwd, stdio: "pipe", env: hardenedGitEnv() });
@@ -42314,8 +42415,11 @@ async function migrateLocalTelemetry(root, actions) {
42314
42415
  function removeLegacyPackage(movedProjectDir, npmRemover, actions) {
42315
42416
  if (!movedProjectDir) return;
42316
42417
  try {
42317
- npmRemover(LEGACY_NPM_PACKAGE);
42318
- actions.push(`Removed legacy global package ${LEGACY_NPM_PACKAGE}`);
42418
+ const outcome = npmRemover(LEGACY_NPM_PACKAGE);
42419
+ if (outcome === "removed") actions.push(`Removed legacy global package ${LEGACY_NPM_PACKAGE}`);
42420
+ if (outcome === "unknown") {
42421
+ actions.push(`Ran npm rm -g ${LEGACY_NPM_PACKAGE} in case the old GATE.md CLI was installed (npm could not list its global packages)`);
42422
+ }
42319
42423
  } catch (err2) {
42320
42424
  printWarn(
42321
42425
  `Could not remove ${LEGACY_NPM_PACKAGE} (${err2.message}). Remove it manually: npm rm -g ${LEGACY_NPM_PACKAGE}`
@@ -42410,6 +42514,25 @@ function carryLegacyContents(gateDir, verityDir) {
42410
42514
  walk2("");
42411
42515
  return copied;
42412
42516
  }
42517
+ function hasLegacyStandard(root = repoRoot()) {
42518
+ if (!isRealDir((0, import_node_path64.join)(root, ".gate"))) return false;
42519
+ try {
42520
+ if (!(0, import_node_fs76.lstatSync)((0, import_node_path64.join)(root, ".gate", "standard.yaml")).isFile()) return false;
42521
+ } catch {
42522
+ return false;
42523
+ }
42524
+ const verityDir = (0, import_node_path64.join)(root, ".verity");
42525
+ if (pathEntryExists(verityDir) && !isRealDir(verityDir)) return false;
42526
+ return !pathEntryExists((0, import_node_path64.join)(verityDir, "standard.yaml"));
42527
+ }
42528
+ function pathEntryExists(path) {
42529
+ try {
42530
+ (0, import_node_fs76.lstatSync)(path);
42531
+ return true;
42532
+ } catch {
42533
+ return false;
42534
+ }
42535
+ }
42413
42536
  function isRealDir(path) {
42414
42537
  try {
42415
42538
  const st = (0, import_node_fs76.lstatSync)(path);
@@ -42442,6 +42565,7 @@ async function needsMigration(root = repoRoot()) {
42442
42565
  if ((0, import_node_fs76.existsSync)((0, import_node_path64.join)(gateDir, "memory")) && !(0, import_node_fs76.existsSync)((0, import_node_path64.join)(verityDir, "memory"))) {
42443
42566
  return true;
42444
42567
  }
42568
+ if (hasLegacyStandard(root)) return true;
42445
42569
  }
42446
42570
  const claudeMd = (0, import_node_path64.join)(root, "CLAUDE.md");
42447
42571
  if ((0, import_node_fs76.existsSync)(claudeMd) && hasLegacyMemoryBlock(readFileSyncSafe(claudeMd))) {
@@ -42663,7 +42787,7 @@ async function recordAnswers(ui, momentIds, telemetry) {
42663
42787
  await writeSetupState({
42664
42788
  moments: momentIds,
42665
42789
  ...telemetry ? { telemetry } : {},
42666
- init: { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.34.5-experimental.7268b07" : "dev" }
42790
+ init: { completed_at: (/* @__PURE__ */ new Date()).toISOString(), cli_version: true ? "0.34.5-experimental.f1c33b5" : "dev" }
42667
42791
  });
42668
42792
  } catch (err2) {
42669
42793
  ui.rail.line(`Could not record the setup answers: ${terminalText(err2.message, 200)}`, "warn");
@@ -42797,6 +42921,7 @@ function registerInitCommand(program2) {
42797
42921
 
42798
42922
  // src/commands/doctor.ts
42799
42923
  var import_node_fs78 = require("node:fs");
42924
+ var LEGACY_STANDARD_FILE = ".gate/standard.yaml";
42800
42925
  async function buildReport() {
42801
42926
  const prereqs = await checkPrereqs({ install: false });
42802
42927
  const state = await readSetupState();
@@ -42806,6 +42931,9 @@ async function buildReport() {
42806
42931
  const telemetry = await checkTelemetry();
42807
42932
  const artifacts = {
42808
42933
  standard: (0, import_node_fs78.existsSync)(projectPath(STANDARD_FILE)),
42934
+ // The migration's own answer, not a bare existsSync: /verity:init skips a
42935
+ // question on this, so it must be true only when init will carry the file.
42936
+ legacyStandard: hasLegacyStandard(repoRoot()),
42809
42937
  verityMd: (0, import_node_fs78.existsSync)(projectPath(VERITY_MD_FILE))
42810
42938
  };
42811
42939
  const next = [];
@@ -42813,9 +42941,13 @@ async function buildReport() {
42813
42941
  if (c.status !== "ok" && c.remedy) next.push(c.remedy);
42814
42942
  }
42815
42943
  if (!state?.init) next.push('Run "verity init" \u2014 the deterministic setup phase has not completed here.');
42944
+ const legacyOnly = !artifacts.standard && artifacts.legacyStandard;
42945
+ if (legacyOnly) {
42946
+ next.push(`Run "verity init" \u2014 it moves the old GATE.md install, with its Standard (${LEGACY_STANDARD_FILE}), to .verity/.`);
42947
+ }
42816
42948
  const missing = [
42817
- !artifacts.standard && ".verity/standard.yaml",
42818
- !artifacts.verityMd && "VERITY.md"
42949
+ !artifacts.standard && !legacyOnly && ".verity/standard.yaml",
42950
+ !artifacts.verityMd && !legacyOnly && "VERITY.md"
42819
42951
  ].filter((x) => !!x);
42820
42952
  if (missing.length === 2) {
42821
42953
  next.push('Run "verity standard synthesize --push" \u2014 it derives the Standard and VERITY.md from this codebase.');
@@ -42948,7 +43080,7 @@ function registerDoctorCommand(program2) {
42948
43080
  if (process.platform === "win32") printWarn(WINDOWS_STATIC_NOTE);
42949
43081
  else printInfo("Static analysis: Trivy (dependencies, malicious packages, secrets)");
42950
43082
  printInfo("Artifacts:");
42951
- printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : "missing"}`);
43083
+ printInfo(` .verity/standard.yaml: ${report.artifacts.standard ? "\u2713" : report.artifacts.legacyStandard ? `not yet (an old GATE.md Standard is at ${LEGACY_STANDARD_FILE}; verity init moves it)` : "missing"}`);
42952
43084
  printInfo(` VERITY.md: ${report.artifacts.verityMd ? "\u2713" : "missing"}`);
42953
43085
  printInfo(
42954
43086
  ` .verity/memory/: ${report.memory.trackedFiles > 0 ? `${report.memory.trackedFiles} file(s) tracked in git \u2014 they appear in every diff` : report.memory.posture === "ignored" ? "machine-local \u2713" : "not tracked"}`
@@ -44640,10 +44772,10 @@ function registerLeanCommand(program2) {
44640
44772
  }
44641
44773
 
44642
44774
  // src/cli.ts
44643
- program.name("verity").description("CLI for Verity quality gate service").version("0.34.5-experimental.7268b07").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
44775
+ program.name("verity").description("CLI for Verity quality gate service").version("0.34.5-experimental.f1c33b5").option("--token <token>", "Override authentication token").option("--service-url <url>", "Override service URL").option("--verbose", "Log HTTP requests/responses to stderr").hook("preAction", async (_thisCommand, actionCommand) => {
44644
44776
  const isTelemetryHelper = actionCommand.name() === "headers" && actionCommand.parent?.name() === "telemetry";
44645
44777
  if (!isTelemetryHelper) {
44646
- installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.5-experimental.7268b07");
44778
+ installStderrLog(actionCommand.name(), process.argv.slice(2), "0.34.5-experimental.f1c33b5");
44647
44779
  }
44648
44780
  setUserNamedServiceUrl(program.opts().serviceUrl);
44649
44781
  try {
@@ -36,10 +36,12 @@ Use this one report:
36
36
  - **`blocked` is true** → show the `prerequisites[].remedy` lines and stop.
37
37
  - **`hooks.versions.skew` is set** → tell the user first, in one line, with
38
38
  `hooks.versions.skew.remedy`.
39
- - **`artifacts.standard` is true** → this project already has a Standard here.
40
- Do not ask question 2. Init keeps the Standard and sends no profile.
39
+ - **`artifacts.standard` or `artifacts.legacyStandard` is true** → this project
40
+ already has a Standard here. `legacyStandard` is an old GATE.md Standard at
41
+ `.gate/standard.yaml`: init moves it to `.verity/` first, then keeps it. Do not
42
+ ask question 2. Init keeps the Standard and sends no profile.
41
43
 
42
- When `artifacts.standard` is false, also run:
44
+ When both are false, also run:
43
45
 
44
46
  ```bash
45
47
  verity standard history
@@ -98,8 +100,8 @@ contents of their repositories.
98
100
  | `Create a new one with the built-in rules` | The new Standard becomes the next version for the whole team. It has the built-in rules only. Nothing is sent. |
99
101
 
100
102
  **2b — "Let Verity write review rules for this repository?"** (only when
101
- `artifacts.standard` is false, 2a does not apply, and the status is `on` or
102
- `unknown`)
103
+ `artifacts.standard` and `artifacts.legacyStandard` are both false, 2a does not
104
+ apply, and the status is `on` or `unknown`)
103
105
 
104
106
  | Option | Description |
105
107
  |---|---|
@@ -165,7 +167,8 @@ It prints one JSON object on stdout:
165
167
  in a terminal later. Go to Step 3.
166
168
 
167
169
  **After a new sign-in, check the Standard again.** If Step 0 could not run
168
- `verity standard history` (it failed) and `artifacts.standard` is false, run it
170
+ `verity standard history` (it failed) and `artifacts.standard` and
171
+ `artifacts.legacyStandard` are both false, run it
169
172
  now. If it lists versions, ask question 2a now, in its own prompt. Its answer
170
173
  replaces the answer to 2b. Also run `verity standard generate --status` again.
171
174
  If it prints `off` or `unsupported`, the answer to 2b has no effect: pass
@@ -242,6 +245,15 @@ Summarise from this report and from init's output, not from memory:
242
245
  commit;
243
246
  - anything untracked, and that the staged removal is the user's to commit;
244
247
  - sign-in state;
248
+ - formal verification, when init printed "Formal verification at push: on". Say
249
+ it as a fact, in init's words: at a push, Verity checks a small model of the
250
+ riskiest changed function and replays any counterexample on the real code;
251
+ that function's source is sent to Verity; only a reproduced bug blocks; turn
252
+ it off with `verity config formal off`. It is a default, like the moments. Do
253
+ not suggest turning it off, and do not connect it to the user's answers to
254
+ other questions;
255
+ - when init printed that the kept Standard has no project rules yet, that line
256
+ and its command (`verity standard generate`);
245
257
  - each line of `next`, if any.
246
258
 
247
259
  ---
@@ -254,3 +266,5 @@ Summarise from this report and from init's output, not from memory:
254
266
  - **Do not answer a question for the user**, and do not leave a flag off because
255
267
  it seems obvious. An omitted answer is an unattended one.
256
268
  - **Do not run plain `verity login`.** See Step 2.
269
+ - **Do not advise turning off a default** (the moments, formal verification)
270
+ unless the user asks. Say what it does and how to change it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codacy/verity-cli",
3
- "version": "0.34.5-experimental.7268b07",
3
+ "version": "0.34.5-experimental.f1c33b5",
4
4
  "description": "CLI for Verity quality gate service",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://verity.md",
@@ -37,7 +37,7 @@
37
37
  "tree-sitter-javascript": "0.25.0",
38
38
  "tree-sitter-python": "0.25.0",
39
39
  "tree-sitter-typescript": "0.23.2",
40
- "tsx": "^4.21.0",
40
+ "tsx": "^4.23.15",
41
41
  "typescript": "^5.4",
42
42
  "web-tree-sitter": "0.27.0"
43
43
  },