codarch 0.3.22 → 0.3.24

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/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // apps/cli/src/commands/analyze.ts
4
- import fs11 from "node:fs";
5
- import path11 from "node:path";
4
+ import fs12 from "node:fs";
5
+ import path12 from "node:path";
6
6
 
7
7
  // packages/versions/src/manifest.ts
8
8
  var CC_JSON_VERSION = "2.0";
@@ -166,15 +166,15 @@ var ConfigError = class extends Error {
166
166
  this.name = "ConfigError";
167
167
  }
168
168
  };
169
- function asObject(value, path23) {
169
+ function asObject(value, path24) {
170
170
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
171
- throw new ConfigError(`${path23} debe ser un objeto`);
171
+ throw new ConfigError(`${path24} debe ser un objeto`);
172
172
  }
173
173
  return value;
174
174
  }
175
- function asString(value, path23) {
175
+ function asString(value, path24) {
176
176
  if (typeof value !== "string" || value.trim() === "") {
177
- throw new ConfigError(`${path23} debe ser un texto no vac\xEDo`);
177
+ throw new ConfigError(`${path24} debe ser un texto no vac\xEDo`);
178
178
  }
179
179
  return value.trim();
180
180
  }
@@ -597,18 +597,18 @@ function parseInlineProfiles(value) {
597
597
  });
598
598
  return profiles;
599
599
  }
600
- function parseProfileEntry(value, path23) {
601
- const entry = asObject(value, path23);
602
- const id = asString(entry.id, `${path23}.id`);
603
- const title = asString(entry.title, `${path23}.title`);
604
- const description = entry.description === void 0 ? "" : asString(entry.description, `${path23}.description`);
605
- const when = entry.when === void 0 ? "" : asString(entry.when, `${path23}.when`);
606
- const layers = parseLayerList(entry.layers, `${path23}.layers`);
600
+ function parseProfileEntry(value, path24) {
601
+ const entry = asObject(value, path24);
602
+ const id = asString(entry.id, `${path24}.id`);
603
+ const title = asString(entry.title, `${path24}.title`);
604
+ const description = entry.description === void 0 ? "" : asString(entry.description, `${path24}.description`);
605
+ const when = entry.when === void 0 ? "" : asString(entry.when, `${path24}.when`);
606
+ const layers = parseLayerList(entry.layers, `${path24}.layers`);
607
607
  if (layers.length === 0) {
608
- throw new ConfigError(`${path23} necesita al menos una capa`);
608
+ throw new ConfigError(`${path24} necesita al menos una capa`);
609
609
  }
610
610
  const layerNames = new Set(layers.map((layer) => layer.name));
611
- const rules = parseRuleList(entry.rules, layerNames, `${path23}.rules`).filter(
611
+ const rules = parseRuleList(entry.rules, layerNames, `${path24}.rules`).filter(
612
612
  (rule) => rule.type === "forbidden"
613
613
  );
614
614
  return { id, title, description, when, layers, rules };
@@ -715,35 +715,35 @@ function withFile(file, read) {
715
715
  throw error;
716
716
  }
717
717
  }
718
- function parseLayerList(value, path23 = "config.layers") {
718
+ function parseLayerList(value, path24 = "config.layers") {
719
719
  if (value === void 0) return [];
720
720
  if (!Array.isArray(value)) {
721
- throw new ConfigError(`${path23} debe ser una lista`);
721
+ throw new ConfigError(`${path24} debe ser una lista`);
722
722
  }
723
723
  const layers = [];
724
724
  const names = /* @__PURE__ */ new Set();
725
725
  value.forEach((raw, index) => {
726
- const layer = asObject(raw, `${path23}[${index}]`);
727
- const name = asString(layer.name, `${path23}[${index}].name`);
726
+ const layer = asObject(raw, `${path24}[${index}]`);
727
+ const name = asString(layer.name, `${path24}[${index}].name`);
728
728
  if (names.has(name)) {
729
729
  throw new ConfigError(`capa duplicada: ${name}`);
730
730
  }
731
731
  names.add(name);
732
732
  if (layer.patterns !== void 0 && layer.paths !== void 0) {
733
733
  throw new ConfigError(
734
- `${path23}[${index}] no puede tener patterns y paths a la vez`
734
+ `${path24}[${index}] no puede tener patterns y paths a la vez`
735
735
  );
736
736
  }
737
737
  const rawPatterns = layer.patterns ?? layer.paths;
738
738
  if (!Array.isArray(rawPatterns) || rawPatterns.length === 0) {
739
739
  throw new ConfigError(
740
- `${path23}[${index}].patterns debe ser una lista no vac\xEDa`
740
+ `${path24}[${index}].patterns debe ser una lista no vac\xEDa`
741
741
  );
742
742
  }
743
743
  const patterns = rawPatterns.map((rawPattern, patternIndex) => {
744
744
  const pattern = asString(
745
745
  rawPattern,
746
- `${path23}[${index}].patterns[${patternIndex}]`
746
+ `${path24}[${index}].patterns[${patternIndex}]`
747
747
  ).replaceAll("\\", "/").replace(/^\.\//, "");
748
748
  if (pattern.startsWith("/") || /^[A-Za-z]:\//.test(pattern)) {
749
749
  throw new ConfigError(
@@ -756,15 +756,15 @@ function parseLayerList(value, path23 = "config.layers") {
756
756
  });
757
757
  return layers;
758
758
  }
759
- function parseRuleList(value, layerNames, path23 = "config.rules") {
759
+ function parseRuleList(value, layerNames, path24 = "config.rules") {
760
760
  if (value === void 0) return [];
761
761
  if (!Array.isArray(value)) {
762
- throw new ConfigError(`${path23} debe ser una lista`);
762
+ throw new ConfigError(`${path24} debe ser una lista`);
763
763
  }
764
764
  const rules = [];
765
765
  const names = /* @__PURE__ */ new Set();
766
766
  value.forEach((raw, index) => {
767
- const at = `${path23}[${index}]`;
767
+ const at = `${path24}[${index}]`;
768
768
  const rule = asObject(raw, at);
769
769
  const name = asString(rule.name, `${at}.name`);
770
770
  if (names.has(name)) {
@@ -807,17 +807,17 @@ function parseRuleList(value, layerNames, path23 = "config.rules") {
807
807
  });
808
808
  return rules;
809
809
  }
810
- function parseSeverity(value, path23) {
810
+ function parseSeverity(value, path24) {
811
811
  if (value === void 0) return "error";
812
812
  if (typeof value !== "string" || !SEVERITIES.has(value)) {
813
- throw new ConfigError(`${path23} debe ser info, warn o error`);
813
+ throw new ConfigError(`${path24} debe ser info, warn o error`);
814
814
  }
815
815
  return value;
816
816
  }
817
- function optionalNumber(value, path23) {
817
+ function optionalNumber(value, path24) {
818
818
  if (value === void 0) return void 0;
819
819
  if (typeof value !== "number" || !Number.isFinite(value)) {
820
- throw new ConfigError(`${path23} debe ser un n\xFAmero`);
820
+ throw new ConfigError(`${path24} debe ser un n\xFAmero`);
821
821
  }
822
822
  return value;
823
823
  }
@@ -1508,22 +1508,22 @@ function liveNodes(snapshot) {
1508
1508
  });
1509
1509
  }
1510
1510
  const folderBodies = /* @__PURE__ */ new Map();
1511
- const visit = (node, path23) => {
1511
+ const visit = (node, path24) => {
1512
1512
  if (node.type === "File") {
1513
1513
  return fileBodies.get(node.id) ?? "";
1514
1514
  }
1515
1515
  const childBodies = [];
1516
1516
  for (const child of node.children ?? []) {
1517
- childBodies.push(visit(child, path23 ? `${path23}/${child.name}` : child.name));
1517
+ childBodies.push(visit(child, path24 ? `${path24}/${child.name}` : child.name));
1518
1518
  }
1519
1519
  const bodyHash2 = sha256Hex(childBodies.join("|"));
1520
- if (path23) {
1521
- folderBodies.set(path23, bodyHash2);
1520
+ if (path24) {
1521
+ folderBodies.set(path24, bodyHash2);
1522
1522
  nodes.push({
1523
1523
  level: "folder",
1524
1524
  kind: "folder",
1525
1525
  name: node.name,
1526
- path: path23,
1526
+ path: path24,
1527
1527
  bodyHash: bodyHash2,
1528
1528
  complexity: null,
1529
1529
  lines: null,
@@ -1665,15 +1665,15 @@ function verifyChains(chains, snapshot) {
1665
1665
  const prefix = `${root.name}/`;
1666
1666
  walkTree([root], (entry) => {
1667
1667
  if (entry.node.type !== "File") return;
1668
- const path23 = entry.path.startsWith(prefix) ? entry.path.slice(prefix.length) : entry.path;
1668
+ const path24 = entry.path.startsWith(prefix) ? entry.path.slice(prefix.length) : entry.path;
1669
1669
  const symbols = snapshot.lenses?.symbols?.nodes[entry.node.id] ?? [];
1670
1670
  for (const symbol of symbols) {
1671
1671
  checked++;
1672
- const chain = byName.get(`${path23}::${symbol.name}`);
1672
+ const chain = byName.get(`${path24}::${symbol.name}`);
1673
1673
  if (!chain) {
1674
1674
  mismatches.push({
1675
1675
  name: symbol.name,
1676
- path: path23,
1676
+ path: path24,
1677
1677
  reason: "este s\xEDmbolo no tiene cadena"
1678
1678
  });
1679
1679
  continue;
@@ -1682,7 +1682,7 @@ function verifyChains(chains, snapshot) {
1682
1682
  if (!last) {
1683
1683
  mismatches.push({
1684
1684
  name: symbol.name,
1685
- path: path23,
1685
+ path: path24,
1686
1686
  reason: "la cadena est\xE1 vac\xEDa"
1687
1687
  });
1688
1688
  continue;
@@ -1691,7 +1691,7 @@ function verifyChains(chains, snapshot) {
1691
1691
  if ((symbol.hash ?? "") !== last.bodyHash) {
1692
1692
  mismatches.push({
1693
1693
  name: symbol.name,
1694
- path: path23,
1694
+ path: path24,
1695
1695
  reason: "el hash del cuerpo no es el de la cadena"
1696
1696
  });
1697
1697
  }
@@ -1838,22 +1838,22 @@ function saveHistory(root, cc, now) {
1838
1838
  // packages/schema/src/errors.ts
1839
1839
  var CcJsonError = class extends Error {
1840
1840
  path;
1841
- constructor(message, path23) {
1842
- super(`${message} (en ${path23})`);
1841
+ constructor(message, path24) {
1842
+ super(`${message} (en ${path24})`);
1843
1843
  this.name = "CcJsonError";
1844
- this.path = path23;
1844
+ this.path = path24;
1845
1845
  }
1846
1846
  };
1847
1847
  function isRecord(value) {
1848
1848
  return typeof value === "object" && value !== null && !Array.isArray(value);
1849
1849
  }
1850
- function requireRecord(value, path23) {
1851
- if (!isRecord(value)) throw new CcJsonError("se esperaba un objeto", path23);
1850
+ function requireRecord(value, path24) {
1851
+ if (!isRecord(value)) throw new CcJsonError("se esperaba un objeto", path24);
1852
1852
  return value;
1853
1853
  }
1854
- function requireString(value, path23, field5) {
1854
+ function requireString(value, path24, field5) {
1855
1855
  if (typeof value !== "string" || value.length === 0) {
1856
- throw new CcJsonError(`"${field5}" debe ser una cadena no vac\xEDa`, path23);
1856
+ throw new CcJsonError(`"${field5}" debe ser una cadena no vac\xEDa`, path24);
1857
1857
  }
1858
1858
  return value;
1859
1859
  }
@@ -1863,9 +1863,9 @@ var ID_LENGTH = 16;
1863
1863
  function normalizeName(name) {
1864
1864
  return name.normalize("NFC");
1865
1865
  }
1866
- function pathSegments(path23) {
1866
+ function pathSegments(path24) {
1867
1867
  const segments = [];
1868
- for (const raw of path23.replace(/\\/g, "/").split("/")) {
1868
+ for (const raw of path24.replace(/\\/g, "/").split("/")) {
1869
1869
  const segment = normalizeName(raw);
1870
1870
  if (segment === "" || segment === ".") continue;
1871
1871
  if (segment === "..") {
@@ -1879,18 +1879,18 @@ function pathSegments(path23) {
1879
1879
  function canonicalPath(segments) {
1880
1880
  return `/${segments.map(normalizeName).join("/")}`;
1881
1881
  }
1882
- function idFromCanonicalPath(path23, type = "File") {
1883
- const canonical = path23.startsWith("/") ? path23 : `/${path23}`;
1882
+ function idFromCanonicalPath(path24, type = "File") {
1883
+ const canonical = path24.startsWith("/") ? path24 : `/${path24}`;
1884
1884
  return sha256Hex(type + canonical).slice(0, ID_LENGTH);
1885
1885
  }
1886
1886
  function nodeId(type, segments) {
1887
1887
  return idFromCanonicalPath(canonicalPath(segments), type);
1888
1888
  }
1889
- function fileId(path23) {
1890
- return nodeId("File", pathSegments(path23));
1889
+ function fileId(path24) {
1890
+ return nodeId("File", pathSegments(path24));
1891
1891
  }
1892
- function folderId(path23) {
1893
- return nodeId("Folder", pathSegments(path23));
1892
+ function folderId(path24) {
1893
+ return nodeId("Folder", pathSegments(path24));
1894
1894
  }
1895
1895
 
1896
1896
  // packages/schema/src/legacy.ts
@@ -1946,15 +1946,15 @@ function normalizeLegacyCcJson(input) {
1946
1946
  const metrics = {};
1947
1947
  const built = [];
1948
1948
  const ids = /* @__PURE__ */ new Map();
1949
- const buildNode = (value, parentPath, path23, depth) => {
1949
+ const buildNode = (value, parentPath, path24, depth) => {
1950
1950
  if (depth > MAX_DEPTH) {
1951
- throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH} superada`, path23);
1951
+ throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH} superada`, path24);
1952
1952
  }
1953
- const raw = requireRecord(value, path23);
1954
- const name = readNodeName(raw.name, `${path23}.name`);
1953
+ const raw = requireRecord(value, path24);
1954
+ const name = readNodeName(raw.name, `${path24}.name`);
1955
1955
  const type = raw.type;
1956
1956
  if (type !== "File" && type !== "Folder") {
1957
- throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path23}.type`);
1957
+ throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path24}.type`);
1958
1958
  }
1959
1959
  const fullPath = [...parentPath, name];
1960
1960
  const id = nodeId(type, fullPath.slice(1));
@@ -1962,13 +1962,13 @@ function normalizeLegacyCcJson(input) {
1962
1962
  if (previous !== void 0) {
1963
1963
  throw new CcJsonError(
1964
1964
  `id duplicado "${id}" para "${previous}" y "${fullPath.join("/")}"`,
1965
- `${path23}.name`
1965
+ `${path24}.name`
1966
1966
  );
1967
1967
  }
1968
1968
  ids.set(id, fullPath.join("/"));
1969
1969
  built.push({ id, name, fullPath: fullPath.join("/") });
1970
1970
  const node = { id, name, type };
1971
- const attributes = readMetrics(raw.attributes, `${path23}.attributes`);
1971
+ const attributes = readMetrics(raw.attributes, `${path24}.attributes`);
1972
1972
  if (attributes) metrics[id] = attributes;
1973
1973
  const contentHash = readOptionalString(raw.checksum) ?? readOptionalString(raw.contentHash);
1974
1974
  if (contentHash) node.contentHash = contentHash;
@@ -1976,14 +1976,14 @@ function normalizeLegacyCcJson(input) {
1976
1976
  if (link) node.link = link;
1977
1977
  if (raw.children !== void 0) {
1978
1978
  if (!Array.isArray(raw.children)) {
1979
- throw new CcJsonError('"children" debe ser un array', `${path23}.children`);
1979
+ throw new CcJsonError('"children" debe ser un array', `${path24}.children`);
1980
1980
  }
1981
1981
  if (type === "File" && raw.children.length > 0) {
1982
- throw new CcJsonError("un fichero no puede tener hijos", `${path23}.children`);
1982
+ throw new CcJsonError("un fichero no puede tener hijos", `${path24}.children`);
1983
1983
  }
1984
1984
  if (type === "Folder" && raw.children.length > 0) {
1985
1985
  node.children = raw.children.map(
1986
- (child, index) => buildNode(child, fullPath, `${path23}.children[${index}]`, depth + 1)
1986
+ (child, index) => buildNode(child, fullPath, `${path24}.children[${index}]`, depth + 1)
1987
1987
  );
1988
1988
  }
1989
1989
  }
@@ -2000,15 +2000,15 @@ function normalizeLegacyCcJson(input) {
2000
2000
  throw new CcJsonError('"edges" debe ser un array', `${base}.edges`);
2001
2001
  }
2002
2002
  edgesRaw.forEach((edge, index) => {
2003
- const path23 = `${base}.edges[${index}]`;
2004
- const raw = requireRecord(edge, path23);
2005
- const fromName = requireString(raw.fromNodeName, `${path23}.fromNodeName`, "fromNodeName");
2006
- const toName = requireString(raw.toNodeName, `${path23}.toNodeName`, "toNodeName");
2003
+ const path24 = `${base}.edges[${index}]`;
2004
+ const raw = requireRecord(edge, path24);
2005
+ const fromName = requireString(raw.fromNodeName, `${path24}.fromNodeName`, "fromNodeName");
2006
+ const toName = requireString(raw.toNodeName, `${path24}.toNodeName`, "toNodeName");
2007
2007
  const normalized = {
2008
- fromId: resolveEndpoint(fromName, pathIndex, stripNames, `${path23}.fromNodeName`),
2009
- toId: resolveEndpoint(toName, pathIndex, stripNames, `${path23}.toNodeName`)
2008
+ fromId: resolveEndpoint(fromName, pathIndex, stripNames, `${path24}.fromNodeName`),
2009
+ toId: resolveEndpoint(toName, pathIndex, stripNames, `${path24}.toNodeName`)
2010
2010
  };
2011
- const attributes = readMetrics(raw.attributes, `${path23}.attributes`);
2011
+ const attributes = readMetrics(raw.attributes, `${path24}.attributes`);
2012
2012
  if (attributes) normalized.attributes = attributes;
2013
2013
  if (typeof raw.isCyclic === "boolean") normalized.isCyclic = raw.isCyclic;
2014
2014
  if (typeof raw.isPointingUpwards === "boolean") {
@@ -2093,10 +2093,10 @@ function buildPathIndex(built, multipleRoots) {
2093
2093
  }
2094
2094
  return index;
2095
2095
  }
2096
- function resolveEndpoint(endpoint, index, stripNames, path23) {
2096
+ function resolveEndpoint(endpoint, index, stripNames, path24) {
2097
2097
  const segments = canonicalSegments(endpoint);
2098
2098
  if (segments.length === 0) {
2099
- throw new CcJsonError("extremo de arista vac\xEDo", path23);
2099
+ throw new CcJsonError("extremo de arista vac\xEDo", path24);
2100
2100
  }
2101
2101
  const candidates = [segments.join("/")];
2102
2102
  if (segments.length > 1 && stripNames.has(segments[0])) {
@@ -2108,7 +2108,7 @@ function resolveEndpoint(endpoint, index, stripNames, path23) {
2108
2108
  }
2109
2109
  const bare = index.get(segments[segments.length - 1]);
2110
2110
  if (bare) return bare;
2111
- throw new CcJsonError(`no se pudo resolver el nodo "${endpoint}"`, path23);
2111
+ throw new CcJsonError(`no se pudo resolver el nodo "${endpoint}"`, path24);
2112
2112
  }
2113
2113
  function canonicalSegments(value) {
2114
2114
  const result = [];
@@ -2123,85 +2123,85 @@ function canonicalSegments(value) {
2123
2123
  }
2124
2124
  return result;
2125
2125
  }
2126
- function readNodeName(value, path23) {
2127
- const name = normalizeName(requireString(value, path23, "name"));
2126
+ function readNodeName(value, path24) {
2127
+ const name = normalizeName(requireString(value, path24, "name"));
2128
2128
  if (name === "." || name === "..") {
2129
- throw new CcJsonError('el nombre no puede ser "." ni ".."', path23);
2129
+ throw new CcJsonError('el nombre no puede ser "." ni ".."', path24);
2130
2130
  }
2131
2131
  if (name.includes("/")) {
2132
- throw new CcJsonError('el nombre no puede contener "/"', path23);
2132
+ throw new CcJsonError('el nombre no puede contener "/"', path24);
2133
2133
  }
2134
2134
  return name;
2135
2135
  }
2136
2136
  function readOptionalString(value) {
2137
2137
  return typeof value === "string" && value.length > 0 ? value : void 0;
2138
2138
  }
2139
- function readMetrics(value, path23) {
2139
+ function readMetrics(value, path24) {
2140
2140
  if (value === void 0) return void 0;
2141
- const raw = requireRecord(value, path23);
2141
+ const raw = requireRecord(value, path24);
2142
2142
  const out = {};
2143
2143
  for (const [metric, metricValue] of Object.entries(raw)) {
2144
2144
  if (typeof metricValue !== "number" || !Number.isFinite(metricValue)) {
2145
2145
  throw new CcJsonError(
2146
2146
  `la m\xE9trica "${metric}" debe ser un n\xFAmero finito`,
2147
- `${path23}["${metric}"]`
2147
+ `${path24}["${metric}"]`
2148
2148
  );
2149
2149
  }
2150
2150
  out[metric] = metricValue;
2151
2151
  }
2152
2152
  return Object.keys(out).length > 0 ? out : void 0;
2153
2153
  }
2154
- function readAttributeTypes(value, path23) {
2154
+ function readAttributeTypes(value, path24) {
2155
2155
  if (value === void 0) return {};
2156
- const raw = requireRecord(value, path23);
2156
+ const raw = requireRecord(value, path24);
2157
2157
  if ("nodes" in raw || "edges" in raw) {
2158
- const nodes2 = raw.nodes === void 0 ? void 0 : readTypeMap(raw.nodes, `${path23}.nodes`);
2159
- const edges = raw.edges === void 0 ? void 0 : readTypeMap(raw.edges, `${path23}.edges`);
2158
+ const nodes2 = raw.nodes === void 0 ? void 0 : readTypeMap(raw.nodes, `${path24}.nodes`);
2159
+ const edges = raw.edges === void 0 ? void 0 : readTypeMap(raw.edges, `${path24}.edges`);
2160
2160
  return {
2161
2161
  ...nodes2 && Object.keys(nodes2).length > 0 ? { nodes: nodes2 } : {},
2162
2162
  ...edges && Object.keys(edges).length > 0 ? { edges } : {}
2163
2163
  };
2164
2164
  }
2165
- const nodes = readTypeMap(raw, path23);
2165
+ const nodes = readTypeMap(raw, path24);
2166
2166
  return Object.keys(nodes).length > 0 ? { nodes } : {};
2167
2167
  }
2168
- function readTypeMap(value, path23) {
2169
- const raw = requireRecord(value, path23);
2168
+ function readTypeMap(value, path24) {
2169
+ const raw = requireRecord(value, path24);
2170
2170
  const out = {};
2171
2171
  for (const [metric, type] of Object.entries(raw)) {
2172
2172
  if (type !== "absolute" && type !== "relative") {
2173
2173
  throw new CcJsonError(
2174
2174
  `el tipo de "${metric}" debe ser "absolute" o "relative"`,
2175
- `${path23}["${metric}"]`
2175
+ `${path24}["${metric}"]`
2176
2176
  );
2177
2177
  }
2178
2178
  out[metric] = type;
2179
2179
  }
2180
2180
  return out;
2181
2181
  }
2182
- function readDescriptors(value, path23) {
2182
+ function readDescriptors(value, path24) {
2183
2183
  if (value === void 0) return {};
2184
- const raw = requireRecord(value, path23);
2184
+ const raw = requireRecord(value, path24);
2185
2185
  if ("nodes" in raw || "edges" in raw) {
2186
- const nodes = raw.nodes === void 0 ? void 0 : readDescriptorMap(raw.nodes, `${path23}.nodes`);
2187
- const edges = raw.edges === void 0 ? void 0 : readDescriptorMap(raw.edges, `${path23}.edges`);
2186
+ const nodes = raw.nodes === void 0 ? void 0 : readDescriptorMap(raw.nodes, `${path24}.nodes`);
2187
+ const edges = raw.edges === void 0 ? void 0 : readDescriptorMap(raw.edges, `${path24}.edges`);
2188
2188
  return {
2189
2189
  ...nodes && Object.keys(nodes).length > 0 ? { nodes } : {},
2190
2190
  ...edges && Object.keys(edges).length > 0 ? { edges } : {}
2191
2191
  };
2192
2192
  }
2193
- const flat = readDescriptorMap(raw, path23);
2193
+ const flat = readDescriptorMap(raw, path24);
2194
2194
  return Object.keys(flat).length > 0 ? { flat } : {};
2195
2195
  }
2196
- function readDescriptorMap(value, path23) {
2197
- const raw = requireRecord(value, path23);
2196
+ function readDescriptorMap(value, path24) {
2197
+ const raw = requireRecord(value, path24);
2198
2198
  const out = {};
2199
2199
  for (const [metric, descriptor] of Object.entries(raw)) {
2200
- const record = requireRecord(descriptor, `${path23}["${metric}"]`);
2200
+ const record = requireRecord(descriptor, `${path24}["${metric}"]`);
2201
2201
  if (record.direction !== void 0 && typeof record.direction !== "number") {
2202
2202
  throw new CcJsonError(
2203
2203
  `"direction" de "${metric}" debe ser un n\xFAmero`,
2204
- `${path23}["${metric}"].direction`
2204
+ `${path24}["${metric}"].direction`
2205
2205
  );
2206
2206
  }
2207
2207
  out[metric] = record;
@@ -2226,26 +2226,26 @@ function parseCcJson2(input) {
2226
2226
  const roots = Array.isArray(filesRaw) ? filesRaw : [filesRaw];
2227
2227
  if (roots.length === 0) throw new CcJsonError("el \xE1rbol est\xE1 vac\xEDo", "$.files");
2228
2228
  const ids = /* @__PURE__ */ new Set();
2229
- const validateNode = (value, path23, depth) => {
2230
- if (depth > MAX_DEPTH2) throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH2} superada`, path23);
2231
- const raw = requireRecord(value, path23);
2232
- const id = requireString(raw.id, `${path23}.id`, "id");
2233
- if (ids.has(id)) throw new CcJsonError(`id duplicado "${id}"`, `${path23}.id`);
2229
+ const validateNode = (value, path24, depth) => {
2230
+ if (depth > MAX_DEPTH2) throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH2} superada`, path24);
2231
+ const raw = requireRecord(value, path24);
2232
+ const id = requireString(raw.id, `${path24}.id`, "id");
2233
+ if (ids.has(id)) throw new CcJsonError(`id duplicado "${id}"`, `${path24}.id`);
2234
2234
  ids.add(id);
2235
- const name = requireString(raw.name, `${path23}.name`, "name");
2235
+ const name = requireString(raw.name, `${path24}.name`, "name");
2236
2236
  const type = raw.type;
2237
2237
  if (type !== "File" && type !== "Folder") {
2238
- throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path23}.type`);
2238
+ throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path24}.type`);
2239
2239
  }
2240
2240
  const node = { id, name, type };
2241
2241
  if (typeof raw.contentHash === "string") node.contentHash = raw.contentHash;
2242
2242
  if (typeof raw.link === "string") node.link = raw.link;
2243
2243
  if (raw.children !== void 0) {
2244
2244
  if (!Array.isArray(raw.children)) {
2245
- throw new CcJsonError('"children" debe ser un array', `${path23}.children`);
2245
+ throw new CcJsonError('"children" debe ser un array', `${path24}.children`);
2246
2246
  }
2247
2247
  node.children = raw.children.map(
2248
- (child, index) => validateNode(child, `${path23}.children[${index}]`, depth + 1)
2248
+ (child, index) => validateNode(child, `${path24}.children[${index}]`, depth + 1)
2249
2249
  );
2250
2250
  }
2251
2251
  return node;
@@ -2276,10 +2276,10 @@ function parseCcJson2(input) {
2276
2276
  throw new CcJsonError('"edges" debe ser un array', "$.lenses.dependency.edges");
2277
2277
  }
2278
2278
  dependency.edges.forEach((edge, index) => {
2279
- const path23 = `$.lenses.dependency.edges[${index}]`;
2280
- const raw = requireRecord(edge, path23);
2281
- requireString(raw.fromId, `${path23}.fromId`, "fromId");
2282
- requireString(raw.toId, `${path23}.toId`, "toId");
2279
+ const path24 = `$.lenses.dependency.edges[${index}]`;
2280
+ const raw = requireRecord(edge, path24);
2281
+ requireString(raw.fromId, `${path24}.fromId`, "fromId");
2282
+ requireString(raw.toId, `${path24}.toId`, "toId");
2283
2283
  });
2284
2284
  }
2285
2285
  }
@@ -2431,9 +2431,9 @@ function topByMetric(cc, metric, limit = 10) {
2431
2431
  const ranked = [];
2432
2432
  for (const [id, values] of Object.entries(attributes)) {
2433
2433
  const value = values[metric];
2434
- const path23 = paths.get(id);
2435
- if (value === void 0 || path23 === void 0) continue;
2436
- ranked.push({ id, path: path23, value });
2434
+ const path24 = paths.get(id);
2435
+ if (value === void 0 || path24 === void 0) continue;
2436
+ ranked.push({ id, path: path24, value });
2437
2437
  }
2438
2438
  ranked.sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
2439
2439
  return ranked.slice(0, limit);
@@ -2919,11 +2919,11 @@ function summarize(index) {
2919
2919
  }
2920
2920
  function difference(present, absent) {
2921
2921
  const files = [];
2922
- for (const [id, path23] of present.paths) {
2922
+ for (const [id, path24] of present.paths) {
2923
2923
  if (absent.paths.has(id)) continue;
2924
2924
  files.push({
2925
2925
  id,
2926
- path: path23,
2926
+ path: path24,
2927
2927
  metrics: sortedMetrics(present.metrics[id])
2928
2928
  });
2929
2929
  }
@@ -2931,7 +2931,7 @@ function difference(present, absent) {
2931
2931
  }
2932
2932
  function changedFiles(base, head) {
2933
2933
  const changed = [];
2934
- for (const [id, path23] of head.paths) {
2934
+ for (const [id, path24] of head.paths) {
2935
2935
  if (!base.paths.has(id)) continue;
2936
2936
  const baseValues = base.metrics[id] ?? {};
2937
2937
  const headValues = head.metrics[id] ?? {};
@@ -2951,7 +2951,7 @@ function changedFiles(base, head) {
2951
2951
  delta: baseValue !== null && headValue !== null ? headValue - baseValue : null
2952
2952
  });
2953
2953
  }
2954
- if (changes.length > 0) changed.push({ id, path: path23, changes });
2954
+ if (changes.length > 0) changed.push({ id, path: path24, changes });
2955
2955
  }
2956
2956
  return changed.sort(compareChangedFiles);
2957
2957
  }
@@ -3184,8 +3184,8 @@ function suggestLayers(cc) {
3184
3184
  const edges = cc.lenses?.dependency?.edges ?? [];
3185
3185
  const groups = /* @__PURE__ */ new Map();
3186
3186
  let ungrouped = 0;
3187
- const groupOf = (path23) => {
3188
- const parts = path23.split("/").filter(Boolean);
3187
+ const groupOf = (path24) => {
3188
+ const parts = path24.split("/").filter(Boolean);
3189
3189
  if (parts.length === 0) return null;
3190
3190
  const directory = parts.slice(0, -1);
3191
3191
  if (directory.length === 0) {
@@ -3211,7 +3211,7 @@ function suggestLayers(cc) {
3211
3211
  group.files += 1;
3212
3212
  return group;
3213
3213
  };
3214
- for (const path23 of paths.values()) groupOf(path23);
3214
+ for (const path24 of paths.values()) groupOf(path24);
3215
3215
  const groupEdges = [];
3216
3216
  for (const edge of edges) {
3217
3217
  const fromPath = paths.get(edge.fromId);
@@ -3816,11 +3816,13 @@ function describeSymbol(name, kind, node, nameNode, complexity) {
3816
3816
  name,
3817
3817
  kind,
3818
3818
  line: node.startPosition.row + 1,
3819
+ // La ficha necesita el cuerpo entero para enseñar el código del símbolo
3820
+ // (ADR 0067): no solo las funciones tienen líneas.
3821
+ lines: node.endPosition.row - node.startPosition.row + 1,
3819
3822
  hash: bodyHash(node, nameNode)
3820
3823
  };
3821
3824
  if (kind === "function") {
3822
3825
  symbol.complexity = complexity ?? functionComplexity(node);
3823
- symbol.lines = node.endPosition.row - node.startPosition.row + 1;
3824
3826
  }
3825
3827
  return symbol;
3826
3828
  }
@@ -5326,8 +5328,8 @@ function buildSnapshot(input) {
5326
5328
  isCyclic: edge.isCyclic
5327
5329
  }));
5328
5330
  const dependencyNodes = {};
5329
- for (const [path23, metrics] of input.graph.metrics) {
5330
- dependencyNodes[fileId(path23)] = { level: metrics.dependencyLevel };
5331
+ for (const [path24, metrics] of input.graph.metrics) {
5332
+ dependencyNodes[fileId(path24)] = { level: metrics.dependencyLevel };
5331
5333
  }
5332
5334
  const migrationLens = input.migration ? migrationLensFrom(input.migration) : void 0;
5333
5335
  const symbolsSummary = {
@@ -5975,8 +5977,8 @@ function parseGitStatus(output) {
5975
5977
  continue;
5976
5978
  }
5977
5979
  if (kind === "2") {
5978
- const path23 = normalizeGitPath(tail(record, 9));
5979
- changes.push({ path: path23, kind: "renamed" });
5980
+ const path24 = normalizeGitPath(tail(record, 9));
5981
+ changes.push({ path: path24, kind: "renamed" });
5980
5982
  const from = normalizeGitPath(records[index + 1] ?? "");
5981
5983
  if (from) {
5982
5984
  changes.push({ path: from, kind: "deleted" });
@@ -6351,10 +6353,76 @@ function ensureGitignoreEntry(root, entry) {
6351
6353
  }
6352
6354
  }
6353
6355
 
6354
- // packages/parsers/src/safety.ts
6356
+ // packages/parsers/src/source.ts
6355
6357
  import fs8 from "node:fs";
6356
- import os from "node:os";
6357
6358
  import path8 from "node:path";
6359
+ var SOURCE_EXTENSIONS2 = /* @__PURE__ */ new Set([
6360
+ ".ts",
6361
+ ".tsx",
6362
+ ".mts",
6363
+ ".cts",
6364
+ ".js",
6365
+ ".jsx",
6366
+ ".mjs",
6367
+ ".cjs"
6368
+ ]);
6369
+ var DENIED_SEGMENTS = /* @__PURE__ */ new Set([
6370
+ ".git",
6371
+ "node_modules",
6372
+ ".codarch",
6373
+ ".codarch-history",
6374
+ "dist",
6375
+ "build",
6376
+ "coverage"
6377
+ ]);
6378
+ var MAX_LINES = 400;
6379
+ var MAX_BYTES = 1e6;
6380
+ function readSourceSnippet(root, relativePath3, start = 1, end = MAX_LINES) {
6381
+ const normalized = relativePath3.replaceAll("\\", "/").replace(/^\/+/, "");
6382
+ if (!normalized || normalized.includes("\0")) return null;
6383
+ if (normalized.startsWith("../") || normalized.includes("/../")) return null;
6384
+ const segments = normalized.split("/");
6385
+ if (segments.some((segment) => DENIED_SEGMENTS.has(segment))) return null;
6386
+ if (!SOURCE_EXTENSIONS2.has(path8.extname(normalized).toLowerCase())) return null;
6387
+ const rootPath = path8.resolve(root);
6388
+ const file = path8.resolve(rootPath, normalized);
6389
+ const prefix = rootPath.endsWith(path8.sep) ? rootPath : `${rootPath}${path8.sep}`;
6390
+ if (!file.startsWith(prefix)) return null;
6391
+ try {
6392
+ const stats = fs8.statSync(file);
6393
+ if (!stats.isFile() || stats.size > MAX_BYTES) return null;
6394
+ const realRoot = fs8.realpathSync(rootPath);
6395
+ const realFile = fs8.realpathSync(file);
6396
+ const realPrefix = realRoot.endsWith(path8.sep) ? realRoot : `${realRoot}${path8.sep}`;
6397
+ if (!realFile.startsWith(realPrefix)) return null;
6398
+ const text = fs8.readFileSync(file, "utf8");
6399
+ const all = text.split(/\r?\n/);
6400
+ const total = all.length;
6401
+ const first = Math.max(1, Math.trunc(start) || 1);
6402
+ const last = Math.min(
6403
+ total,
6404
+ Math.max(first, Math.trunc(end) || first),
6405
+ first + MAX_LINES - 1
6406
+ );
6407
+ if (first > total) {
6408
+ return { path: normalized, start: first, end: first, total, lines: [] };
6409
+ }
6410
+ return {
6411
+ path: normalized,
6412
+ start: first,
6413
+ end: last,
6414
+ total,
6415
+ lines: all.slice(first - 1, last)
6416
+ };
6417
+ } catch {
6418
+ return null;
6419
+ }
6420
+ }
6421
+
6422
+ // packages/parsers/src/safety.ts
6423
+ import fs9 from "node:fs";
6424
+ import os from "node:os";
6425
+ import path9 from "node:path";
6358
6426
  var UNIX_PROTECTED = [
6359
6427
  "/bin",
6360
6428
  "/boot",
@@ -6401,7 +6469,7 @@ function protegidas(platform, env) {
6401
6469
  return platform === "darwin" ? MAC_PROTECTED : UNIX_PROTECTED;
6402
6470
  }
6403
6471
  function plataforma(platform) {
6404
- return platform === "win32" ? path8.win32 : path8.posix;
6472
+ return platform === "win32" ? path9.win32 : path9.posix;
6405
6473
  }
6406
6474
  function comparable(value, platform) {
6407
6475
  const resolved = plataforma(platform).resolve(value);
@@ -6414,7 +6482,7 @@ function dentro(root, base, platform) {
6414
6482
  }
6415
6483
  function real(value) {
6416
6484
  try {
6417
- return fs8.realpathSync.native(value);
6485
+ return fs9.realpathSync.native(value);
6418
6486
  } catch {
6419
6487
  return value;
6420
6488
  }
@@ -6448,8 +6516,8 @@ function protectedRootReason(root, options = {}) {
6448
6516
  }
6449
6517
 
6450
6518
  // packages/parsers/src/watch.ts
6451
- import fs9 from "node:fs";
6452
- import path9 from "node:path";
6519
+ import fs10 from "node:fs";
6520
+ import path10 from "node:path";
6453
6521
 
6454
6522
  // packages/parsers/node_modules/chokidar/esm/index.js
6455
6523
  import { stat as statcb } from "fs";
@@ -6527,7 +6595,7 @@ var ReaddirpStream = class extends Readable {
6527
6595
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
6528
6596
  const statMethod = opts.lstat ? lstat : stat;
6529
6597
  if (wantBigintFsStats) {
6530
- this._stat = (path23) => statMethod(path23, { bigint: true });
6598
+ this._stat = (path24) => statMethod(path24, { bigint: true });
6531
6599
  } else {
6532
6600
  this._stat = statMethod;
6533
6601
  }
@@ -6552,8 +6620,8 @@ var ReaddirpStream = class extends Readable {
6552
6620
  const par = this.parent;
6553
6621
  const fil = par && par.files;
6554
6622
  if (fil && fil.length > 0) {
6555
- const { path: path23, depth } = par;
6556
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path23));
6623
+ const { path: path24, depth } = par;
6624
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path24));
6557
6625
  const awaited = await Promise.all(slice);
6558
6626
  for (const entry of awaited) {
6559
6627
  if (!entry)
@@ -6593,20 +6661,20 @@ var ReaddirpStream = class extends Readable {
6593
6661
  this.reading = false;
6594
6662
  }
6595
6663
  }
6596
- async _exploreDir(path23, depth) {
6664
+ async _exploreDir(path24, depth) {
6597
6665
  let files;
6598
6666
  try {
6599
- files = await readdir(path23, this._rdOptions);
6667
+ files = await readdir(path24, this._rdOptions);
6600
6668
  } catch (error) {
6601
6669
  this._onError(error);
6602
6670
  }
6603
- return { files, depth, path: path23 };
6671
+ return { files, depth, path: path24 };
6604
6672
  }
6605
- async _formatEntry(dirent, path23) {
6673
+ async _formatEntry(dirent, path24) {
6606
6674
  let entry;
6607
6675
  const basename5 = this._isDirent ? dirent.name : dirent;
6608
6676
  try {
6609
- const fullPath = presolve(pjoin(path23, basename5));
6677
+ const fullPath = presolve(pjoin(path24, basename5));
6610
6678
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
6611
6679
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
6612
6680
  } catch (err) {
@@ -7006,16 +7074,16 @@ var delFromSet = (main2, prop, item) => {
7006
7074
  };
7007
7075
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
7008
7076
  var FsWatchInstances = /* @__PURE__ */ new Map();
7009
- function createFsWatchInstance(path23, options, listener, errHandler, emitRaw) {
7077
+ function createFsWatchInstance(path24, options, listener, errHandler, emitRaw) {
7010
7078
  const handleEvent = (rawEvent, evPath) => {
7011
- listener(path23);
7012
- emitRaw(rawEvent, evPath, { watchedPath: path23 });
7013
- if (evPath && path23 !== evPath) {
7014
- fsWatchBroadcast(sysPath.resolve(path23, evPath), KEY_LISTENERS, sysPath.join(path23, evPath));
7079
+ listener(path24);
7080
+ emitRaw(rawEvent, evPath, { watchedPath: path24 });
7081
+ if (evPath && path24 !== evPath) {
7082
+ fsWatchBroadcast(sysPath.resolve(path24, evPath), KEY_LISTENERS, sysPath.join(path24, evPath));
7015
7083
  }
7016
7084
  };
7017
7085
  try {
7018
- return fs_watch(path23, {
7086
+ return fs_watch(path24, {
7019
7087
  persistent: options.persistent
7020
7088
  }, handleEvent);
7021
7089
  } catch (error) {
@@ -7031,12 +7099,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
7031
7099
  listener(val1, val2, val3);
7032
7100
  });
7033
7101
  };
7034
- var setFsWatchListener = (path23, fullPath, options, handlers) => {
7102
+ var setFsWatchListener = (path24, fullPath, options, handlers) => {
7035
7103
  const { listener, errHandler, rawEmitter } = handlers;
7036
7104
  let cont = FsWatchInstances.get(fullPath);
7037
7105
  let watcher;
7038
7106
  if (!options.persistent) {
7039
- watcher = createFsWatchInstance(path23, options, listener, errHandler, rawEmitter);
7107
+ watcher = createFsWatchInstance(path24, options, listener, errHandler, rawEmitter);
7040
7108
  if (!watcher)
7041
7109
  return;
7042
7110
  return watcher.close.bind(watcher);
@@ -7047,7 +7115,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
7047
7115
  addAndConvert(cont, KEY_RAW, rawEmitter);
7048
7116
  } else {
7049
7117
  watcher = createFsWatchInstance(
7050
- path23,
7118
+ path24,
7051
7119
  options,
7052
7120
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
7053
7121
  errHandler,
@@ -7062,7 +7130,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
7062
7130
  cont.watcherUnusable = true;
7063
7131
  if (isWindows && error.code === "EPERM") {
7064
7132
  try {
7065
- const fd = await open(path23, "r");
7133
+ const fd = await open(path24, "r");
7066
7134
  await fd.close();
7067
7135
  broadcastErr(error);
7068
7136
  } catch (err) {
@@ -7093,7 +7161,7 @@ var setFsWatchListener = (path23, fullPath, options, handlers) => {
7093
7161
  };
7094
7162
  };
7095
7163
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
7096
- var setFsWatchFileListener = (path23, fullPath, options, handlers) => {
7164
+ var setFsWatchFileListener = (path24, fullPath, options, handlers) => {
7097
7165
  const { listener, rawEmitter } = handlers;
7098
7166
  let cont = FsWatchFileInstances.get(fullPath);
7099
7167
  const copts = cont && cont.options;
@@ -7115,7 +7183,7 @@ var setFsWatchFileListener = (path23, fullPath, options, handlers) => {
7115
7183
  });
7116
7184
  const currmtime = curr.mtimeMs;
7117
7185
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
7118
- foreach(cont.listeners, (listener2) => listener2(path23, curr));
7186
+ foreach(cont.listeners, (listener2) => listener2(path24, curr));
7119
7187
  }
7120
7188
  })
7121
7189
  };
@@ -7143,13 +7211,13 @@ var NodeFsHandler = class {
7143
7211
  * @param listener on fs change
7144
7212
  * @returns closer for the watcher instance
7145
7213
  */
7146
- _watchWithNodeFs(path23, listener) {
7214
+ _watchWithNodeFs(path24, listener) {
7147
7215
  const opts = this.fsw.options;
7148
- const directory = sysPath.dirname(path23);
7149
- const basename5 = sysPath.basename(path23);
7216
+ const directory = sysPath.dirname(path24);
7217
+ const basename5 = sysPath.basename(path24);
7150
7218
  const parent = this.fsw._getWatchedDir(directory);
7151
7219
  parent.add(basename5);
7152
- const absolutePath = sysPath.resolve(path23);
7220
+ const absolutePath = sysPath.resolve(path24);
7153
7221
  const options = {
7154
7222
  persistent: opts.persistent
7155
7223
  };
@@ -7159,12 +7227,12 @@ var NodeFsHandler = class {
7159
7227
  if (opts.usePolling) {
7160
7228
  const enableBin = opts.interval !== opts.binaryInterval;
7161
7229
  options.interval = enableBin && isBinaryPath(basename5) ? opts.binaryInterval : opts.interval;
7162
- closer = setFsWatchFileListener(path23, absolutePath, options, {
7230
+ closer = setFsWatchFileListener(path24, absolutePath, options, {
7163
7231
  listener,
7164
7232
  rawEmitter: this.fsw._emitRaw
7165
7233
  });
7166
7234
  } else {
7167
- closer = setFsWatchListener(path23, absolutePath, options, {
7235
+ closer = setFsWatchListener(path24, absolutePath, options, {
7168
7236
  listener,
7169
7237
  errHandler: this._boundHandleError,
7170
7238
  rawEmitter: this.fsw._emitRaw
@@ -7186,7 +7254,7 @@ var NodeFsHandler = class {
7186
7254
  let prevStats = stats;
7187
7255
  if (parent.has(basename5))
7188
7256
  return;
7189
- const listener = async (path23, newStats) => {
7257
+ const listener = async (path24, newStats) => {
7190
7258
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
7191
7259
  return;
7192
7260
  if (!newStats || newStats.mtimeMs === 0) {
@@ -7200,11 +7268,11 @@ var NodeFsHandler = class {
7200
7268
  this.fsw._emit(EV.CHANGE, file, newStats2);
7201
7269
  }
7202
7270
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
7203
- this.fsw._closeFile(path23);
7271
+ this.fsw._closeFile(path24);
7204
7272
  prevStats = newStats2;
7205
7273
  const closer2 = this._watchWithNodeFs(file, listener);
7206
7274
  if (closer2)
7207
- this.fsw._addPathCloser(path23, closer2);
7275
+ this.fsw._addPathCloser(path24, closer2);
7208
7276
  } else {
7209
7277
  prevStats = newStats2;
7210
7278
  }
@@ -7236,7 +7304,7 @@ var NodeFsHandler = class {
7236
7304
  * @param item basename of this item
7237
7305
  * @returns true if no more processing is needed for this entry.
7238
7306
  */
7239
- async _handleSymlink(entry, directory, path23, item) {
7307
+ async _handleSymlink(entry, directory, path24, item) {
7240
7308
  if (this.fsw.closed) {
7241
7309
  return;
7242
7310
  }
@@ -7246,7 +7314,7 @@ var NodeFsHandler = class {
7246
7314
  this.fsw._incrReadyCount();
7247
7315
  let linkPath;
7248
7316
  try {
7249
- linkPath = await fsrealpath(path23);
7317
+ linkPath = await fsrealpath(path24);
7250
7318
  } catch (e) {
7251
7319
  this.fsw._emitReady();
7252
7320
  return true;
@@ -7256,12 +7324,12 @@ var NodeFsHandler = class {
7256
7324
  if (dir.has(item)) {
7257
7325
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
7258
7326
  this.fsw._symlinkPaths.set(full, linkPath);
7259
- this.fsw._emit(EV.CHANGE, path23, entry.stats);
7327
+ this.fsw._emit(EV.CHANGE, path24, entry.stats);
7260
7328
  }
7261
7329
  } else {
7262
7330
  dir.add(item);
7263
7331
  this.fsw._symlinkPaths.set(full, linkPath);
7264
- this.fsw._emit(EV.ADD, path23, entry.stats);
7332
+ this.fsw._emit(EV.ADD, path24, entry.stats);
7265
7333
  }
7266
7334
  this.fsw._emitReady();
7267
7335
  return true;
@@ -7290,9 +7358,9 @@ var NodeFsHandler = class {
7290
7358
  return;
7291
7359
  }
7292
7360
  const item = entry.path;
7293
- let path23 = sysPath.join(directory, item);
7361
+ let path24 = sysPath.join(directory, item);
7294
7362
  current.add(item);
7295
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path23, item)) {
7363
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path24, item)) {
7296
7364
  return;
7297
7365
  }
7298
7366
  if (this.fsw.closed) {
@@ -7301,8 +7369,8 @@ var NodeFsHandler = class {
7301
7369
  }
7302
7370
  if (item === target || !target && !previous.has(item)) {
7303
7371
  this.fsw._incrReadyCount();
7304
- path23 = sysPath.join(dir, sysPath.relative(dir, path23));
7305
- this._addToNodeFs(path23, initialAdd, wh, depth + 1);
7372
+ path24 = sysPath.join(dir, sysPath.relative(dir, path24));
7373
+ this._addToNodeFs(path24, initialAdd, wh, depth + 1);
7306
7374
  }
7307
7375
  }).on(EV.ERROR, this._boundHandleError);
7308
7376
  return new Promise((resolve4, reject) => {
@@ -7371,13 +7439,13 @@ var NodeFsHandler = class {
7371
7439
  * @param depth Child path actually targeted for watch
7372
7440
  * @param target Child path actually targeted for watch
7373
7441
  */
7374
- async _addToNodeFs(path23, initialAdd, priorWh, depth, target) {
7442
+ async _addToNodeFs(path24, initialAdd, priorWh, depth, target) {
7375
7443
  const ready = this.fsw._emitReady;
7376
- if (this.fsw._isIgnored(path23) || this.fsw.closed) {
7444
+ if (this.fsw._isIgnored(path24) || this.fsw.closed) {
7377
7445
  ready();
7378
7446
  return false;
7379
7447
  }
7380
- const wh = this.fsw._getWatchHelpers(path23);
7448
+ const wh = this.fsw._getWatchHelpers(path24);
7381
7449
  if (priorWh) {
7382
7450
  wh.filterPath = (entry) => priorWh.filterPath(entry);
7383
7451
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -7393,8 +7461,8 @@ var NodeFsHandler = class {
7393
7461
  const follow = this.fsw.options.followSymlinks;
7394
7462
  let closer;
7395
7463
  if (stats.isDirectory()) {
7396
- const absPath = sysPath.resolve(path23);
7397
- const targetPath = follow ? await fsrealpath(path23) : path23;
7464
+ const absPath = sysPath.resolve(path24);
7465
+ const targetPath = follow ? await fsrealpath(path24) : path24;
7398
7466
  if (this.fsw.closed)
7399
7467
  return;
7400
7468
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -7404,29 +7472,29 @@ var NodeFsHandler = class {
7404
7472
  this.fsw._symlinkPaths.set(absPath, targetPath);
7405
7473
  }
7406
7474
  } else if (stats.isSymbolicLink()) {
7407
- const targetPath = follow ? await fsrealpath(path23) : path23;
7475
+ const targetPath = follow ? await fsrealpath(path24) : path24;
7408
7476
  if (this.fsw.closed)
7409
7477
  return;
7410
7478
  const parent = sysPath.dirname(wh.watchPath);
7411
7479
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
7412
7480
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
7413
- closer = await this._handleDir(parent, stats, initialAdd, depth, path23, wh, targetPath);
7481
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path24, wh, targetPath);
7414
7482
  if (this.fsw.closed)
7415
7483
  return;
7416
7484
  if (targetPath !== void 0) {
7417
- this.fsw._symlinkPaths.set(sysPath.resolve(path23), targetPath);
7485
+ this.fsw._symlinkPaths.set(sysPath.resolve(path24), targetPath);
7418
7486
  }
7419
7487
  } else {
7420
7488
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
7421
7489
  }
7422
7490
  ready();
7423
7491
  if (closer)
7424
- this.fsw._addPathCloser(path23, closer);
7492
+ this.fsw._addPathCloser(path24, closer);
7425
7493
  return false;
7426
7494
  } catch (error) {
7427
7495
  if (this.fsw._handleError(error)) {
7428
7496
  ready();
7429
- return path23;
7497
+ return path24;
7430
7498
  }
7431
7499
  }
7432
7500
  }
@@ -7469,26 +7537,26 @@ function createPattern(matcher) {
7469
7537
  }
7470
7538
  return () => false;
7471
7539
  }
7472
- function normalizePath(path23) {
7473
- if (typeof path23 !== "string")
7540
+ function normalizePath(path24) {
7541
+ if (typeof path24 !== "string")
7474
7542
  throw new Error("string expected");
7475
- path23 = sysPath2.normalize(path23);
7476
- path23 = path23.replace(/\\/g, "/");
7543
+ path24 = sysPath2.normalize(path24);
7544
+ path24 = path24.replace(/\\/g, "/");
7477
7545
  let prepend = false;
7478
- if (path23.startsWith("//"))
7546
+ if (path24.startsWith("//"))
7479
7547
  prepend = true;
7480
7548
  const DOUBLE_SLASH_RE2 = /\/\//;
7481
- while (path23.match(DOUBLE_SLASH_RE2))
7482
- path23 = path23.replace(DOUBLE_SLASH_RE2, "/");
7549
+ while (path24.match(DOUBLE_SLASH_RE2))
7550
+ path24 = path24.replace(DOUBLE_SLASH_RE2, "/");
7483
7551
  if (prepend)
7484
- path23 = "/" + path23;
7485
- return path23;
7552
+ path24 = "/" + path24;
7553
+ return path24;
7486
7554
  }
7487
7555
  function matchPatterns(patterns, testString, stats) {
7488
- const path23 = normalizePath(testString);
7556
+ const path24 = normalizePath(testString);
7489
7557
  for (let index = 0; index < patterns.length; index++) {
7490
7558
  const pattern = patterns[index];
7491
- if (pattern(path23, stats)) {
7559
+ if (pattern(path24, stats)) {
7492
7560
  return true;
7493
7561
  }
7494
7562
  }
@@ -7528,19 +7596,19 @@ var toUnix = (string) => {
7528
7596
  }
7529
7597
  return str;
7530
7598
  };
7531
- var normalizePathToUnix = (path23) => toUnix(sysPath2.normalize(toUnix(path23)));
7532
- var normalizeIgnored = (cwd = "") => (path23) => {
7533
- if (typeof path23 === "string") {
7534
- return normalizePathToUnix(sysPath2.isAbsolute(path23) ? path23 : sysPath2.join(cwd, path23));
7599
+ var normalizePathToUnix = (path24) => toUnix(sysPath2.normalize(toUnix(path24)));
7600
+ var normalizeIgnored = (cwd = "") => (path24) => {
7601
+ if (typeof path24 === "string") {
7602
+ return normalizePathToUnix(sysPath2.isAbsolute(path24) ? path24 : sysPath2.join(cwd, path24));
7535
7603
  } else {
7536
- return path23;
7604
+ return path24;
7537
7605
  }
7538
7606
  };
7539
- var getAbsolutePath = (path23, cwd) => {
7540
- if (sysPath2.isAbsolute(path23)) {
7541
- return path23;
7607
+ var getAbsolutePath = (path24, cwd) => {
7608
+ if (sysPath2.isAbsolute(path24)) {
7609
+ return path24;
7542
7610
  }
7543
- return sysPath2.join(cwd, path23);
7611
+ return sysPath2.join(cwd, path24);
7544
7612
  };
7545
7613
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
7546
7614
  var DirEntry = class {
@@ -7595,10 +7663,10 @@ var DirEntry = class {
7595
7663
  var STAT_METHOD_F = "stat";
7596
7664
  var STAT_METHOD_L = "lstat";
7597
7665
  var WatchHelper = class {
7598
- constructor(path23, follow, fsw) {
7666
+ constructor(path24, follow, fsw) {
7599
7667
  this.fsw = fsw;
7600
- const watchPath = path23;
7601
- this.path = path23 = path23.replace(REPLACER_RE, "");
7668
+ const watchPath = path24;
7669
+ this.path = path24 = path24.replace(REPLACER_RE, "");
7602
7670
  this.watchPath = watchPath;
7603
7671
  this.fullWatchPath = sysPath2.resolve(watchPath);
7604
7672
  this.dirParts = [];
@@ -7720,20 +7788,20 @@ var FSWatcher = class extends EventEmitter {
7720
7788
  this._closePromise = void 0;
7721
7789
  let paths = unifyPaths(paths_);
7722
7790
  if (cwd) {
7723
- paths = paths.map((path23) => {
7724
- const absPath = getAbsolutePath(path23, cwd);
7791
+ paths = paths.map((path24) => {
7792
+ const absPath = getAbsolutePath(path24, cwd);
7725
7793
  return absPath;
7726
7794
  });
7727
7795
  }
7728
- paths.forEach((path23) => {
7729
- this._removeIgnoredPath(path23);
7796
+ paths.forEach((path24) => {
7797
+ this._removeIgnoredPath(path24);
7730
7798
  });
7731
7799
  this._userIgnored = void 0;
7732
7800
  if (!this._readyCount)
7733
7801
  this._readyCount = 0;
7734
7802
  this._readyCount += paths.length;
7735
- Promise.all(paths.map(async (path23) => {
7736
- const res = await this._nodeFsHandler._addToNodeFs(path23, !_internal, void 0, 0, _origAdd);
7803
+ Promise.all(paths.map(async (path24) => {
7804
+ const res = await this._nodeFsHandler._addToNodeFs(path24, !_internal, void 0, 0, _origAdd);
7737
7805
  if (res)
7738
7806
  this._emitReady();
7739
7807
  return res;
@@ -7755,17 +7823,17 @@ var FSWatcher = class extends EventEmitter {
7755
7823
  return this;
7756
7824
  const paths = unifyPaths(paths_);
7757
7825
  const { cwd } = this.options;
7758
- paths.forEach((path23) => {
7759
- if (!sysPath2.isAbsolute(path23) && !this._closers.has(path23)) {
7826
+ paths.forEach((path24) => {
7827
+ if (!sysPath2.isAbsolute(path24) && !this._closers.has(path24)) {
7760
7828
  if (cwd)
7761
- path23 = sysPath2.join(cwd, path23);
7762
- path23 = sysPath2.resolve(path23);
7829
+ path24 = sysPath2.join(cwd, path24);
7830
+ path24 = sysPath2.resolve(path24);
7763
7831
  }
7764
- this._closePath(path23);
7765
- this._addIgnoredPath(path23);
7766
- if (this._watched.has(path23)) {
7832
+ this._closePath(path24);
7833
+ this._addIgnoredPath(path24);
7834
+ if (this._watched.has(path24)) {
7767
7835
  this._addIgnoredPath({
7768
- path: path23,
7836
+ path: path24,
7769
7837
  recursive: true
7770
7838
  });
7771
7839
  }
@@ -7829,38 +7897,38 @@ var FSWatcher = class extends EventEmitter {
7829
7897
  * @param stats arguments to be passed with event
7830
7898
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
7831
7899
  */
7832
- async _emit(event, path23, stats) {
7900
+ async _emit(event, path24, stats) {
7833
7901
  if (this.closed)
7834
7902
  return;
7835
7903
  const opts = this.options;
7836
7904
  if (isWindows)
7837
- path23 = sysPath2.normalize(path23);
7905
+ path24 = sysPath2.normalize(path24);
7838
7906
  if (opts.cwd)
7839
- path23 = sysPath2.relative(opts.cwd, path23);
7840
- const args = [path23];
7907
+ path24 = sysPath2.relative(opts.cwd, path24);
7908
+ const args = [path24];
7841
7909
  if (stats != null)
7842
7910
  args.push(stats);
7843
7911
  const awf = opts.awaitWriteFinish;
7844
7912
  let pw;
7845
- if (awf && (pw = this._pendingWrites.get(path23))) {
7913
+ if (awf && (pw = this._pendingWrites.get(path24))) {
7846
7914
  pw.lastChange = /* @__PURE__ */ new Date();
7847
7915
  return this;
7848
7916
  }
7849
7917
  if (opts.atomic) {
7850
7918
  if (event === EVENTS.UNLINK) {
7851
- this._pendingUnlinks.set(path23, [event, ...args]);
7919
+ this._pendingUnlinks.set(path24, [event, ...args]);
7852
7920
  setTimeout(() => {
7853
- this._pendingUnlinks.forEach((entry, path24) => {
7921
+ this._pendingUnlinks.forEach((entry, path25) => {
7854
7922
  this.emit(...entry);
7855
7923
  this.emit(EVENTS.ALL, ...entry);
7856
- this._pendingUnlinks.delete(path24);
7924
+ this._pendingUnlinks.delete(path25);
7857
7925
  });
7858
7926
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
7859
7927
  return this;
7860
7928
  }
7861
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path23)) {
7929
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path24)) {
7862
7930
  event = EVENTS.CHANGE;
7863
- this._pendingUnlinks.delete(path23);
7931
+ this._pendingUnlinks.delete(path24);
7864
7932
  }
7865
7933
  }
7866
7934
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -7878,16 +7946,16 @@ var FSWatcher = class extends EventEmitter {
7878
7946
  this.emitWithAll(event, args);
7879
7947
  }
7880
7948
  };
7881
- this._awaitWriteFinish(path23, awf.stabilityThreshold, event, awfEmit);
7949
+ this._awaitWriteFinish(path24, awf.stabilityThreshold, event, awfEmit);
7882
7950
  return this;
7883
7951
  }
7884
7952
  if (event === EVENTS.CHANGE) {
7885
- const isThrottled = !this._throttle(EVENTS.CHANGE, path23, 50);
7953
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path24, 50);
7886
7954
  if (isThrottled)
7887
7955
  return this;
7888
7956
  }
7889
7957
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
7890
- const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path23) : path23;
7958
+ const fullPath = opts.cwd ? sysPath2.join(opts.cwd, path24) : path24;
7891
7959
  let stats2;
7892
7960
  try {
7893
7961
  stats2 = await stat3(fullPath);
@@ -7918,23 +7986,23 @@ var FSWatcher = class extends EventEmitter {
7918
7986
  * @param timeout duration of time to suppress duplicate actions
7919
7987
  * @returns tracking object or false if action should be suppressed
7920
7988
  */
7921
- _throttle(actionType, path23, timeout) {
7989
+ _throttle(actionType, path24, timeout) {
7922
7990
  if (!this._throttled.has(actionType)) {
7923
7991
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
7924
7992
  }
7925
7993
  const action = this._throttled.get(actionType);
7926
7994
  if (!action)
7927
7995
  throw new Error("invalid throttle");
7928
- const actionPath = action.get(path23);
7996
+ const actionPath = action.get(path24);
7929
7997
  if (actionPath) {
7930
7998
  actionPath.count++;
7931
7999
  return false;
7932
8000
  }
7933
8001
  let timeoutObject;
7934
8002
  const clear = () => {
7935
- const item = action.get(path23);
8003
+ const item = action.get(path24);
7936
8004
  const count = item ? item.count : 0;
7937
- action.delete(path23);
8005
+ action.delete(path24);
7938
8006
  clearTimeout(timeoutObject);
7939
8007
  if (item)
7940
8008
  clearTimeout(item.timeoutObject);
@@ -7942,7 +8010,7 @@ var FSWatcher = class extends EventEmitter {
7942
8010
  };
7943
8011
  timeoutObject = setTimeout(clear, timeout);
7944
8012
  const thr = { timeoutObject, clear, count: 0 };
7945
- action.set(path23, thr);
8013
+ action.set(path24, thr);
7946
8014
  return thr;
7947
8015
  }
7948
8016
  _incrReadyCount() {
@@ -7956,44 +8024,44 @@ var FSWatcher = class extends EventEmitter {
7956
8024
  * @param event
7957
8025
  * @param awfEmit Callback to be called when ready for event to be emitted.
7958
8026
  */
7959
- _awaitWriteFinish(path23, threshold, event, awfEmit) {
8027
+ _awaitWriteFinish(path24, threshold, event, awfEmit) {
7960
8028
  const awf = this.options.awaitWriteFinish;
7961
8029
  if (typeof awf !== "object")
7962
8030
  return;
7963
8031
  const pollInterval = awf.pollInterval;
7964
8032
  let timeoutHandler;
7965
- let fullPath = path23;
7966
- if (this.options.cwd && !sysPath2.isAbsolute(path23)) {
7967
- fullPath = sysPath2.join(this.options.cwd, path23);
8033
+ let fullPath = path24;
8034
+ if (this.options.cwd && !sysPath2.isAbsolute(path24)) {
8035
+ fullPath = sysPath2.join(this.options.cwd, path24);
7968
8036
  }
7969
8037
  const now = /* @__PURE__ */ new Date();
7970
8038
  const writes = this._pendingWrites;
7971
8039
  function awaitWriteFinishFn(prevStat) {
7972
8040
  statcb(fullPath, (err, curStat) => {
7973
- if (err || !writes.has(path23)) {
8041
+ if (err || !writes.has(path24)) {
7974
8042
  if (err && err.code !== "ENOENT")
7975
8043
  awfEmit(err);
7976
8044
  return;
7977
8045
  }
7978
8046
  const now2 = Number(/* @__PURE__ */ new Date());
7979
8047
  if (prevStat && curStat.size !== prevStat.size) {
7980
- writes.get(path23).lastChange = now2;
8048
+ writes.get(path24).lastChange = now2;
7981
8049
  }
7982
- const pw = writes.get(path23);
8050
+ const pw = writes.get(path24);
7983
8051
  const df = now2 - pw.lastChange;
7984
8052
  if (df >= threshold) {
7985
- writes.delete(path23);
8053
+ writes.delete(path24);
7986
8054
  awfEmit(void 0, curStat);
7987
8055
  } else {
7988
8056
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
7989
8057
  }
7990
8058
  });
7991
8059
  }
7992
- if (!writes.has(path23)) {
7993
- writes.set(path23, {
8060
+ if (!writes.has(path24)) {
8061
+ writes.set(path24, {
7994
8062
  lastChange: now,
7995
8063
  cancelWait: () => {
7996
- writes.delete(path23);
8064
+ writes.delete(path24);
7997
8065
  clearTimeout(timeoutHandler);
7998
8066
  return event;
7999
8067
  }
@@ -8004,8 +8072,8 @@ var FSWatcher = class extends EventEmitter {
8004
8072
  /**
8005
8073
  * Determines whether user has asked to ignore this path.
8006
8074
  */
8007
- _isIgnored(path23, stats) {
8008
- if (this.options.atomic && DOT_RE.test(path23))
8075
+ _isIgnored(path24, stats) {
8076
+ if (this.options.atomic && DOT_RE.test(path24))
8009
8077
  return true;
8010
8078
  if (!this._userIgnored) {
8011
8079
  const { cwd } = this.options;
@@ -8015,17 +8083,17 @@ var FSWatcher = class extends EventEmitter {
8015
8083
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
8016
8084
  this._userIgnored = anymatch(list, void 0);
8017
8085
  }
8018
- return this._userIgnored(path23, stats);
8086
+ return this._userIgnored(path24, stats);
8019
8087
  }
8020
- _isntIgnored(path23, stat4) {
8021
- return !this._isIgnored(path23, stat4);
8088
+ _isntIgnored(path24, stat4) {
8089
+ return !this._isIgnored(path24, stat4);
8022
8090
  }
8023
8091
  /**
8024
8092
  * Provides a set of common helpers and properties relating to symlink handling.
8025
8093
  * @param path file or directory pattern being watched
8026
8094
  */
8027
- _getWatchHelpers(path23) {
8028
- return new WatchHelper(path23, this.options.followSymlinks, this);
8095
+ _getWatchHelpers(path24) {
8096
+ return new WatchHelper(path24, this.options.followSymlinks, this);
8029
8097
  }
8030
8098
  // Directory helpers
8031
8099
  // -----------------
@@ -8057,63 +8125,63 @@ var FSWatcher = class extends EventEmitter {
8057
8125
  * @param item base path of item/directory
8058
8126
  */
8059
8127
  _remove(directory, item, isDirectory) {
8060
- const path23 = sysPath2.join(directory, item);
8061
- const fullPath = sysPath2.resolve(path23);
8062
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path23) || this._watched.has(fullPath);
8063
- if (!this._throttle("remove", path23, 100))
8128
+ const path24 = sysPath2.join(directory, item);
8129
+ const fullPath = sysPath2.resolve(path24);
8130
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path24) || this._watched.has(fullPath);
8131
+ if (!this._throttle("remove", path24, 100))
8064
8132
  return;
8065
8133
  if (!isDirectory && this._watched.size === 1) {
8066
8134
  this.add(directory, item, true);
8067
8135
  }
8068
- const wp = this._getWatchedDir(path23);
8136
+ const wp = this._getWatchedDir(path24);
8069
8137
  const nestedDirectoryChildren = wp.getChildren();
8070
- nestedDirectoryChildren.forEach((nested) => this._remove(path23, nested));
8138
+ nestedDirectoryChildren.forEach((nested) => this._remove(path24, nested));
8071
8139
  const parent = this._getWatchedDir(directory);
8072
8140
  const wasTracked = parent.has(item);
8073
8141
  parent.remove(item);
8074
8142
  if (this._symlinkPaths.has(fullPath)) {
8075
8143
  this._symlinkPaths.delete(fullPath);
8076
8144
  }
8077
- let relPath = path23;
8145
+ let relPath = path24;
8078
8146
  if (this.options.cwd)
8079
- relPath = sysPath2.relative(this.options.cwd, path23);
8147
+ relPath = sysPath2.relative(this.options.cwd, path24);
8080
8148
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
8081
8149
  const event = this._pendingWrites.get(relPath).cancelWait();
8082
8150
  if (event === EVENTS.ADD)
8083
8151
  return;
8084
8152
  }
8085
- this._watched.delete(path23);
8153
+ this._watched.delete(path24);
8086
8154
  this._watched.delete(fullPath);
8087
8155
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
8088
- if (wasTracked && !this._isIgnored(path23))
8089
- this._emit(eventName, path23);
8090
- this._closePath(path23);
8156
+ if (wasTracked && !this._isIgnored(path24))
8157
+ this._emit(eventName, path24);
8158
+ this._closePath(path24);
8091
8159
  }
8092
8160
  /**
8093
8161
  * Closes all watchers for a path
8094
8162
  */
8095
- _closePath(path23) {
8096
- this._closeFile(path23);
8097
- const dir = sysPath2.dirname(path23);
8098
- this._getWatchedDir(dir).remove(sysPath2.basename(path23));
8163
+ _closePath(path24) {
8164
+ this._closeFile(path24);
8165
+ const dir = sysPath2.dirname(path24);
8166
+ this._getWatchedDir(dir).remove(sysPath2.basename(path24));
8099
8167
  }
8100
8168
  /**
8101
8169
  * Closes only file-specific watchers
8102
8170
  */
8103
- _closeFile(path23) {
8104
- const closers = this._closers.get(path23);
8171
+ _closeFile(path24) {
8172
+ const closers = this._closers.get(path24);
8105
8173
  if (!closers)
8106
8174
  return;
8107
8175
  closers.forEach((closer) => closer());
8108
- this._closers.delete(path23);
8176
+ this._closers.delete(path24);
8109
8177
  }
8110
- _addPathCloser(path23, closer) {
8178
+ _addPathCloser(path24, closer) {
8111
8179
  if (!closer)
8112
8180
  return;
8113
- let list = this._closers.get(path23);
8181
+ let list = this._closers.get(path24);
8114
8182
  if (!list) {
8115
8183
  list = [];
8116
- this._closers.set(path23, list);
8184
+ this._closers.set(path24, list);
8117
8185
  }
8118
8186
  list.push(closer);
8119
8187
  }
@@ -8175,7 +8243,7 @@ function watchRepository(root, options) {
8175
8243
  let recursive = true;
8176
8244
  try {
8177
8245
  watchers.push(
8178
- fs9.watch(root, { recursive: true }, (_event, filename) => {
8246
+ fs10.watch(root, { recursive: true }, (_event, filename) => {
8179
8247
  if (filename) note(filename.toString());
8180
8248
  })
8181
8249
  );
@@ -8189,7 +8257,7 @@ function watchRepository(root, options) {
8189
8257
  let git = false;
8190
8258
  try {
8191
8259
  watchers.push(
8192
- fs9.watch(path9.join(root, ".git"), { recursive: false }, () => {
8260
+ fs10.watch(path10.join(root, ".git"), { recursive: false }, () => {
8193
8261
  gitChanged = true;
8194
8262
  schedule();
8195
8263
  })
@@ -8217,7 +8285,7 @@ function chokidarWatcherFor(root, delayMs, options) {
8217
8285
  // Un editor puede escribir el fichero en dos pasos; esperamos a que acabe.
8218
8286
  awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },
8219
8287
  ignored: (candidate) => {
8220
- const relative4 = path9.relative(root, candidate);
8288
+ const relative4 = path10.relative(root, candidate);
8221
8289
  if (relative4 === "") return false;
8222
8290
  return isLiveIgnored(relative4);
8223
8291
  }
@@ -8230,7 +8298,7 @@ function chokidarWatcherFor(root, delayMs, options) {
8230
8298
  options.onChange(paths);
8231
8299
  };
8232
8300
  watcher.on("all", (_event, changed) => {
8233
- pending.add(path9.relative(root, changed));
8301
+ pending.add(path10.relative(root, changed));
8234
8302
  if (timer) clearTimeout(timer);
8235
8303
  timer = setTimeout(flush, delayMs);
8236
8304
  });
@@ -8330,8 +8398,8 @@ function hashString(value) {
8330
8398
  }
8331
8399
  return hash >>> 0;
8332
8400
  }
8333
- function sectionForPath(path23) {
8334
- const folders = path23.split("/").filter(Boolean).slice(0, -1);
8401
+ function sectionForPath(path24) {
8402
+ const folders = path24.split("/").filter(Boolean).slice(0, -1);
8335
8403
  if (folders.length === 0) return "(ra\xEDz)";
8336
8404
  if (folders.length === 1) return folders[0];
8337
8405
  return folders.slice(0, 3).join("/");
@@ -8357,6 +8425,13 @@ function metricTitle(attributes, key) {
8357
8425
  }
8358
8426
  return key;
8359
8427
  }
8428
+ function metricDescription(attributes, key) {
8429
+ const descriptor = attributes?.[key];
8430
+ if (isRecord3(descriptor) && typeof descriptor.description === "string" && descriptor.description) {
8431
+ return descriptor.description;
8432
+ }
8433
+ return void 0;
8434
+ }
8360
8435
  function metricDirection(attributes, key) {
8361
8436
  const descriptor = attributes?.[key];
8362
8437
  if (isRecord3(descriptor) && typeof descriptor.direction === "number") {
@@ -8401,7 +8476,7 @@ function buildRenderModel(cc, options = {}) {
8401
8476
  const fileIndexById = /* @__PURE__ */ new Map();
8402
8477
  walkFiles(cc.files, (entry) => {
8403
8478
  const fullPath = entry.path;
8404
- const path23 = prefix && fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : fullPath;
8479
+ const path24 = prefix && fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : fullPath;
8405
8480
  const values = attributes[entry.node.id];
8406
8481
  const rawArea = valueOf(values, areaMetric);
8407
8482
  const index = files.length;
@@ -8409,7 +8484,7 @@ function buildRenderModel(cc, options = {}) {
8409
8484
  files.push({
8410
8485
  index,
8411
8486
  nodeId: entry.node.id,
8412
- path: path23,
8487
+ path: path24,
8413
8488
  name: entry.node.name,
8414
8489
  section: -1,
8415
8490
  area: Math.max(1, rawArea ?? 0),
@@ -8474,6 +8549,7 @@ function buildRenderModel(cc, options = {}) {
8474
8549
  return {
8475
8550
  key,
8476
8551
  title: metricTitle(descriptors, key),
8552
+ description: metricDescription(descriptors, key),
8477
8553
  direction: metricDirection(descriptors, key),
8478
8554
  min,
8479
8555
  max,
@@ -8572,7 +8648,7 @@ function buildRenderModel(cc, options = {}) {
8572
8648
  };
8573
8649
  }
8574
8650
  function buildRoots(cc, singleRoot, fileIndexById, files) {
8575
- const build = (node, path23) => {
8651
+ const build = (node, path24) => {
8576
8652
  if (node.type === "File") {
8577
8653
  const index = fileIndexById.get(node.id);
8578
8654
  const file = index === void 0 ? void 0 : files[index];
@@ -8580,7 +8656,7 @@ function buildRoots(cc, singleRoot, fileIndexById, files) {
8580
8656
  kind: "file",
8581
8657
  key: `f:${index ?? -1}`,
8582
8658
  name: node.name,
8583
- path: path23,
8659
+ path: path24,
8584
8660
  value: file?.area ?? 1,
8585
8661
  fileCount: 1,
8586
8662
  section: file?.section ?? 0,
@@ -8588,13 +8664,13 @@ function buildRoots(cc, singleRoot, fileIndexById, files) {
8588
8664
  };
8589
8665
  }
8590
8666
  const children = (node.children ?? []).map(
8591
- (child) => build(child, path23 ? `${path23}/${child.name}` : child.name)
8667
+ (child) => build(child, path24 ? `${path24}/${child.name}` : child.name)
8592
8668
  );
8593
8669
  const folder = {
8594
8670
  kind: "folder",
8595
- key: `d:${path23}`,
8671
+ key: `d:${path24}`,
8596
8672
  name: node.name,
8597
- path: path23,
8673
+ path: path24,
8598
8674
  value: children.reduce((sum, child) => sum + child.value, 0) || 1,
8599
8675
  fileCount: children.reduce((sum, child) => sum + child.fileCount, 0),
8600
8676
  section: -1,
@@ -9238,21 +9314,21 @@ function renderHtml(model) {
9238
9314
  }
9239
9315
 
9240
9316
  // apps/cli/src/config.ts
9241
- import path10 from "node:path";
9317
+ import path11 from "node:path";
9242
9318
  function defaultConfigPath(root = ".") {
9243
9319
  return findProjectConfig(root);
9244
9320
  }
9245
9321
  function loadProjectIgnore2(root, options = {}) {
9246
9322
  if (options.noConfig) return [];
9247
- const file = options.config ? path10.resolve(options.config) : defaultConfigPath(root);
9323
+ const file = options.config ? path11.resolve(options.config) : defaultConfigPath(root);
9248
9324
  return file ? loadIgnoreConfig(file) : [];
9249
9325
  }
9250
9326
 
9251
9327
  // apps/cli/src/io.ts
9252
- import fs10 from "node:fs";
9328
+ import fs11 from "node:fs";
9253
9329
  import zlib from "node:zlib";
9254
9330
  function readJsonFile2(file) {
9255
- const buffer = fs10.readFileSync(file);
9331
+ const buffer = fs11.readFileSync(file);
9256
9332
  const isGzip = buffer.length > 2 && buffer[0] === 31 && buffer[1] === 139;
9257
9333
  const raw = isGzip ? zlib.gunzipSync(buffer) : buffer;
9258
9334
  const text = raw.toString("utf8");
@@ -9321,18 +9397,18 @@ function runAnalyze(options) {
9321
9397
  }
9322
9398
  throw error;
9323
9399
  }
9324
- const rootPath = path11.resolve(root);
9325
- const outDirectory = path11.resolve(
9326
- options.out ?? path11.join(rootPath, ".codarch")
9400
+ const rootPath = path12.resolve(root);
9401
+ const outDirectory = path12.resolve(
9402
+ options.out ?? path12.join(rootPath, ".codarch")
9327
9403
  );
9328
- const snapshotPath = path11.join(outDirectory, "snapshot.cc.json");
9329
- const mapPath = path11.join(outDirectory, "map.html");
9404
+ const snapshotPath = path12.join(outDirectory, "snapshot.cc.json");
9405
+ const mapPath = path12.join(outDirectory, "map.html");
9330
9406
  try {
9331
- if (outDirectory === path11.join(rootPath, ".codarch") && !fs11.existsSync(outDirectory)) {
9407
+ if (outDirectory === path12.join(rootPath, ".codarch") && !fs12.existsSync(outDirectory)) {
9332
9408
  ensureGitignoreEntry(rootPath, ".codarch/");
9333
9409
  }
9334
- fs11.mkdirSync(outDirectory, { recursive: true });
9335
- fs11.writeFileSync(
9410
+ fs12.mkdirSync(outDirectory, { recursive: true });
9411
+ fs12.writeFileSync(
9336
9412
  snapshotPath,
9337
9413
  `${JSON.stringify(cc, null, 2)}
9338
9414
  `,
@@ -9354,7 +9430,7 @@ function runAnalyze(options) {
9354
9430
  title: options.title
9355
9431
  });
9356
9432
  const html = renderHtml(model);
9357
- fs11.writeFileSync(mapPath, html, "utf8");
9433
+ fs12.writeFileSync(mapPath, html, "utf8");
9358
9434
  mapBytes = Buffer.byteLength(html, "utf8");
9359
9435
  } catch (error) {
9360
9436
  mapError = error instanceof RenderError ? error.message : error.message;
@@ -9363,14 +9439,14 @@ function runAnalyze(options) {
9363
9439
  mapError = "no hay ficheros TypeScript/JavaScript que dibujar";
9364
9440
  }
9365
9441
  const snapshotBytes = Buffer.byteLength(
9366
- fs11.readFileSync(snapshotPath),
9442
+ fs12.readFileSync(snapshotPath),
9367
9443
  "utf8"
9368
9444
  );
9369
9445
  const lines = [];
9370
9446
  lines.push("");
9371
9447
  lines.push(" CodArch \xB7 an\xE1lisis");
9372
9448
  lines.push("");
9373
- lines.push(field("ra\xEDz", path11.resolve(root)));
9449
+ lines.push(field("ra\xEDz", path12.resolve(root)));
9374
9450
  lines.push(field("snapshot", `${snapshotPath} (${formatBytes(snapshotBytes)})`));
9375
9451
  if (mapError) {
9376
9452
  lines.push(field("mapa", `omitido (${mapError})`));
@@ -9409,7 +9485,7 @@ function runAnalyze(options) {
9409
9485
  lines.push(field("tiempo", `${num(result.durationMs)} ms`));
9410
9486
  if (options.history) {
9411
9487
  try {
9412
- const saved = saveHistory(path11.resolve(root), cc, /* @__PURE__ */ new Date());
9488
+ const saved = saveHistory(path12.resolve(root), cc, /* @__PURE__ */ new Date());
9413
9489
  lines.push(
9414
9490
  field(
9415
9491
  "historial",
@@ -9453,7 +9529,7 @@ function runAnalyze(options) {
9453
9529
  }
9454
9530
 
9455
9531
  // apps/cli/src/commands/diff.ts
9456
- import path14 from "node:path";
9532
+ import path15 from "node:path";
9457
9533
 
9458
9534
  // packages/addons/src/index.ts
9459
9535
  var AddonError = class extends Error {
@@ -9508,32 +9584,32 @@ function parseAddonManifest(input) {
9508
9584
  }
9509
9585
  };
9510
9586
  }
9511
- function parseAddonView(input, path23) {
9512
- const view = asObject2(input, path23);
9513
- rejectUnknown(view, VIEW_KEYS, path23);
9514
- const state = asObject2(view.state ?? {}, `${path23}.state`);
9515
- rejectUnknown(state, STATE_KEYS, `${path23}.state`);
9516
- const tab = optionalString(state.tab, `${path23}.state.tab`);
9587
+ function parseAddonView(input, path24) {
9588
+ const view = asObject2(input, path24);
9589
+ rejectUnknown(view, VIEW_KEYS, path24);
9590
+ const state = asObject2(view.state ?? {}, `${path24}.state`);
9591
+ rejectUnknown(state, STATE_KEYS, `${path24}.state`);
9592
+ const tab = optionalString(state.tab, `${path24}.state.tab`);
9517
9593
  const normalizedTab = tab === "lenses" ? "rules" : tab === "pr" ? "changes" : tab;
9518
9594
  if (normalizedTab !== void 0 && normalizedTab !== "file" && normalizedTab !== "rules" && normalizedTab !== "changes") {
9519
9595
  throw new AddonError(
9520
- `${path23}.state.tab debe ser file, rules o changes`
9596
+ `${path24}.state.tab debe ser file, rules o changes`
9521
9597
  );
9522
9598
  }
9523
9599
  if (state.labels !== void 0 && typeof state.labels !== "boolean") {
9524
- throw new AddonError(`${path23}.state.labels debe ser true o false`);
9600
+ throw new AddonError(`${path24}.state.labels debe ser true o false`);
9525
9601
  }
9526
9602
  return {
9527
- id: asString2(view.id, `${path23}.id`),
9528
- title: asString2(view.title, `${path23}.title`),
9529
- description: optionalString(view.description, `${path23}.description`),
9603
+ id: asString2(view.id, `${path24}.id`),
9604
+ title: asString2(view.title, `${path24}.title`),
9605
+ description: optionalString(view.description, `${path24}.description`),
9530
9606
  state: {
9531
- area: optionalString(state.area, `${path23}.state.area`),
9532
- color: optionalString(state.color, `${path23}.state.color`),
9533
- focus: optionalString(state.focus, `${path23}.state.focus`),
9534
- file: optionalString(state.file, `${path23}.state.file`),
9607
+ area: optionalString(state.area, `${path24}.state.area`),
9608
+ color: optionalString(state.color, `${path24}.state.color`),
9609
+ focus: optionalString(state.focus, `${path24}.state.focus`),
9610
+ file: optionalString(state.file, `${path24}.state.file`),
9535
9611
  tab: normalizedTab,
9536
- symbol: optionalString(state.symbol, `${path23}.state.symbol`),
9612
+ symbol: optionalString(state.symbol, `${path24}.state.symbol`),
9537
9613
  labels: state.labels
9538
9614
  }
9539
9615
  };
@@ -9600,64 +9676,64 @@ function addonError(name, error) {
9600
9676
  }
9601
9677
  return new AddonError(`addons/${name}: ${error.message}`);
9602
9678
  }
9603
- function rejectUnknown(value, known, path23) {
9679
+ function rejectUnknown(value, known, path24) {
9604
9680
  const allowed = new Set(known);
9605
9681
  for (const key of Object.keys(value)) {
9606
9682
  if (!allowed.has(key)) {
9607
9683
  throw new AddonError(
9608
- `${path23}: clave desconocida "${key}" (se admite: ${known.join(", ")})`
9684
+ `${path24}: clave desconocida "${key}" (se admite: ${known.join(", ")})`
9609
9685
  );
9610
9686
  }
9611
9687
  }
9612
9688
  }
9613
- function parsePathList(value, path23) {
9689
+ function parsePathList(value, path24) {
9614
9690
  if (value === void 0 || value === null) return [];
9615
9691
  if (!Array.isArray(value)) {
9616
- throw new AddonError(`${path23} debe ser una lista`);
9692
+ throw new AddonError(`${path24} debe ser una lista`);
9617
9693
  }
9618
9694
  return value.map((raw, index) => {
9619
- const file = asString2(raw, `${path23}[${index}]`);
9695
+ const file = asString2(raw, `${path24}[${index}]`);
9620
9696
  if (file.startsWith("/") || /^[A-Za-z]:[\\/]/.test(file) || file.startsWith("\\")) {
9621
9697
  throw new AddonError(
9622
- `${path23}[${index}] debe ser relativo a la carpeta del addon: ${file}`
9698
+ `${path24}[${index}] debe ser relativo a la carpeta del addon: ${file}`
9623
9699
  );
9624
9700
  }
9625
9701
  if (file.split(/[\\/]/).includes("..")) {
9626
9702
  throw new AddonError(
9627
- `${path23}[${index}] no puede salirse de la carpeta del addon: ${file}`
9703
+ `${path24}[${index}] no puede salirse de la carpeta del addon: ${file}`
9628
9704
  );
9629
9705
  }
9630
9706
  return file.replaceAll("\\", "/");
9631
9707
  });
9632
9708
  }
9633
- function asObject2(value, path23) {
9709
+ function asObject2(value, path24) {
9634
9710
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
9635
- throw new AddonError(`${path23} debe ser un objeto`);
9711
+ throw new AddonError(`${path24} debe ser un objeto`);
9636
9712
  }
9637
9713
  return value;
9638
9714
  }
9639
- function asString2(value, path23) {
9715
+ function asString2(value, path24) {
9640
9716
  if (typeof value !== "string" || value.trim() === "") {
9641
- throw new AddonError(`${path23} debe ser un texto no vac\xEDo`);
9717
+ throw new AddonError(`${path24} debe ser un texto no vac\xEDo`);
9642
9718
  }
9643
9719
  return value.trim();
9644
9720
  }
9645
- function optionalString(value, path23) {
9721
+ function optionalString(value, path24) {
9646
9722
  if (value === void 0 || value === null) return void 0;
9647
- return asString2(value, path23);
9723
+ return asString2(value, path24);
9648
9724
  }
9649
9725
 
9650
9726
  // packages/addons/src/node.ts
9651
- import fs12 from "node:fs";
9652
- import path12 from "node:path";
9727
+ import fs13 from "node:fs";
9728
+ import path13 from "node:path";
9653
9729
  import { parse as parseYaml3 } from "yaml";
9654
9730
  var ADDONS_DIR = "addons";
9655
9731
  var CONFIG_FILES = [".codarch.yml", ".codarch.yaml"];
9656
9732
  function loadAddons(root) {
9657
- const dir = path12.join(root, ADDONS_DIR);
9733
+ const dir = path13.join(root, ADDONS_DIR);
9658
9734
  let entries;
9659
9735
  try {
9660
- entries = fs12.readdirSync(dir, { withFileTypes: true });
9736
+ entries = fs13.readdirSync(dir, { withFileTypes: true });
9661
9737
  } catch {
9662
9738
  return { addons: [], errors: [] };
9663
9739
  }
@@ -9666,7 +9742,7 @@ function loadAddons(root) {
9666
9742
  const folders = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
9667
9743
  for (const name of folders) {
9668
9744
  try {
9669
- const addon = loadAddon(path12.join(dir, name));
9745
+ const addon = loadAddon(path13.join(dir, name));
9670
9746
  if (addon.manifest.name !== name) {
9671
9747
  throw new AddonError(
9672
9748
  `la carpeta se llama "${name}" y el manifiesto "${addon.manifest.name}": deben coincidir`
@@ -9680,9 +9756,9 @@ function loadAddons(root) {
9680
9756
  return { addons, errors };
9681
9757
  }
9682
9758
  function loadAddon(dir) {
9683
- const label = path12.basename(dir);
9759
+ const label = path13.basename(dir);
9684
9760
  const manifest = parseAddonManifest(
9685
- readJson(path12.join(dir, "addon.json"), `${label}/addon.json`)
9761
+ readJson(path13.join(dir, "addon.json"), `${label}/addon.json`)
9686
9762
  );
9687
9763
  return parseAddon({
9688
9764
  manifest,
@@ -9712,11 +9788,11 @@ function repoAddons(root) {
9712
9788
  }
9713
9789
  function declaredAddons(root) {
9714
9790
  for (const name of CONFIG_FILES) {
9715
- const file = path12.join(root, name);
9716
- if (!fs12.existsSync(file)) continue;
9791
+ const file = path13.join(root, name);
9792
+ if (!fs13.existsSync(file)) continue;
9717
9793
  let text;
9718
9794
  try {
9719
- text = fs12.readFileSync(file, "utf8");
9795
+ text = fs13.readFileSync(file, "utf8");
9720
9796
  } catch {
9721
9797
  return [];
9722
9798
  }
@@ -9732,10 +9808,10 @@ function declaredAddons(root) {
9732
9808
  function readYamlPieces(dir, files) {
9733
9809
  const pieces = [];
9734
9810
  for (const file of files) {
9735
- const full = path12.join(dir, file);
9811
+ const full = path13.join(dir, file);
9736
9812
  let text;
9737
9813
  try {
9738
- text = fs12.readFileSync(full, "utf8");
9814
+ text = fs13.readFileSync(full, "utf8");
9739
9815
  } catch (error) {
9740
9816
  throw new AddonError(`no se pudo leer ${file}: ${error.message}`);
9741
9817
  }
@@ -9753,7 +9829,7 @@ function readYamlPieces(dir, files) {
9753
9829
  function readJson(file, label) {
9754
9830
  let text;
9755
9831
  try {
9756
- text = fs12.readFileSync(file, "utf8");
9832
+ text = fs13.readFileSync(file, "utf8");
9757
9833
  } catch (error) {
9758
9834
  throw new AddonError(`no se pudo leer ${label}: ${error.message}`);
9759
9835
  }
@@ -9768,8 +9844,8 @@ function stripBom(text) {
9768
9844
  }
9769
9845
 
9770
9846
  // apps/cli/src/commands/compare.ts
9771
- import fs13 from "node:fs";
9772
- import path13 from "node:path";
9847
+ import fs14 from "node:fs";
9848
+ import path14 from "node:path";
9773
9849
  var numberFormat2 = new Intl.NumberFormat("es-ES");
9774
9850
  function num2(value) {
9775
9851
  return numberFormat2.format(value);
@@ -9793,13 +9869,13 @@ function compareSnapshots(base, head, options) {
9793
9869
  console.error(`no se pudo comparar: ${error.message}`);
9794
9870
  return 1;
9795
9871
  }
9796
- const outPath = path13.resolve(options.out ?? "report.json");
9872
+ const outPath = path14.resolve(options.out ?? "report.json");
9797
9873
  let reportBytes = 0;
9798
9874
  try {
9799
- fs13.mkdirSync(path13.dirname(outPath), { recursive: true });
9875
+ fs14.mkdirSync(path14.dirname(outPath), { recursive: true });
9800
9876
  const text = `${JSON.stringify(report, null, 2)}
9801
9877
  `;
9802
- fs13.writeFileSync(outPath, text, "utf8");
9878
+ fs14.writeFileSync(outPath, text, "utf8");
9803
9879
  reportBytes = Buffer.byteLength(text, "utf8");
9804
9880
  } catch (error) {
9805
9881
  console.error(
@@ -9974,7 +10050,7 @@ function runDiff(options) {
9974
10050
  if (!options.noConfig) {
9975
10051
  configPath = options.config ?? defaultConfigPath();
9976
10052
  if (configPath) {
9977
- const loaded = loadAddons(path14.dirname(path14.resolve(configPath)));
10053
+ const loaded = loadAddons(path15.dirname(path15.resolve(configPath)));
9978
10054
  for (const error of loaded.errors) {
9979
10055
  console.error(`aviso: ${error.message}`);
9980
10056
  }
@@ -10066,7 +10142,7 @@ function runInspect(options) {
10066
10142
  const metric = options.metric ?? defaultMetric(stats);
10067
10143
  const top = metric ? topByMetric(cc, metric, options.top) : [];
10068
10144
  const rootPrefix = cc.files.length === 1 ? `${cc.files[0]?.name}/` : "";
10069
- const displayPath2 = (path23) => rootPrefix && path23.startsWith(rootPrefix) ? path23.slice(rootPrefix.length) : path23;
10145
+ const displayPath2 = (path24) => rootPrefix && path24.startsWith(rootPrefix) ? path24.slice(rootPrefix.length) : path24;
10070
10146
  if (options.metric && !stats.metricCoverage.some((entry) => entry.name === options.metric)) {
10071
10147
  console.error(`la m\xE9trica "${options.metric}" no existe en este fichero`);
10072
10148
  return 1;
@@ -10145,8 +10221,8 @@ function runInspect(options) {
10145
10221
  }
10146
10222
 
10147
10223
  // apps/cli/src/commands/render.ts
10148
- import fs14 from "node:fs";
10149
- import path15 from "node:path";
10224
+ import fs15 from "node:fs";
10225
+ import path16 from "node:path";
10150
10226
  function defaultOutputPath(input) {
10151
10227
  const lower = input.toLowerCase();
10152
10228
  const suffixes = [".cc.json.gz", ".cc.json", ".json.gz", ".json", ".gz"];
@@ -10156,7 +10232,7 @@ function defaultOutputPath(input) {
10156
10232
  return `${input}.html`;
10157
10233
  }
10158
10234
  function defaultProjectName(input) {
10159
- let name = path15.basename(input.replace(/\\/g, "/"));
10235
+ let name = path16.basename(input.replace(/\\/g, "/"));
10160
10236
  const lower = name.toLowerCase();
10161
10237
  const suffixes = [".cc.json.gz", ".cc.json", ".json.gz", ".json", ".gz"];
10162
10238
  for (const suffix of suffixes) {
@@ -10223,8 +10299,8 @@ function runRender(options) {
10223
10299
  const elapsed = Date.now() - started;
10224
10300
  const out = options.out ?? defaultOutputPath(options.file);
10225
10301
  try {
10226
- fs14.mkdirSync(path15.dirname(path15.resolve(out)), { recursive: true });
10227
- fs14.writeFileSync(out, html, "utf8");
10302
+ fs15.mkdirSync(path16.dirname(path16.resolve(out)), { recursive: true });
10303
+ fs15.writeFileSync(out, html, "utf8");
10228
10304
  } catch (error) {
10229
10305
  console.error(`no se pudo escribir ${out}: ${error.message}`);
10230
10306
  return 1;
@@ -10265,13 +10341,13 @@ function runRender(options) {
10265
10341
  }
10266
10342
 
10267
10343
  // apps/cli/src/commands/serve.ts
10268
- import fs15 from "node:fs";
10344
+ import fs16 from "node:fs";
10269
10345
  import http from "node:http";
10270
- import path16 from "node:path";
10346
+ import path17 from "node:path";
10271
10347
  import { fileURLToPath } from "node:url";
10272
10348
 
10273
10349
  // apps/cli/src/version.ts
10274
- var VERSION = true ? "0.3.22" : "0.0.0";
10350
+ var VERSION = true ? "0.3.24" : "0.0.0";
10275
10351
 
10276
10352
  // apps/cli/src/commands/serve.ts
10277
10353
  var MIME = {
@@ -10297,7 +10373,7 @@ var IGNORED_BROWSE = /* @__PURE__ */ new Set([
10297
10373
  "target"
10298
10374
  ]);
10299
10375
  function runServe(options) {
10300
- const root = path16.resolve(options.root ?? ".");
10376
+ const root = path17.resolve(options.root ?? ".");
10301
10377
  const denied = protectedRootReason(root);
10302
10378
  if (denied) {
10303
10379
  console.error(
@@ -10383,8 +10459,8 @@ function runServe(options) {
10383
10459
  broadcast(clients, "watch", { watch: state.watch });
10384
10460
  };
10385
10461
  const switchRoot = (nextRoot) => {
10386
- const resolved = path16.resolve(nextRoot);
10387
- const stat4 = fs15.statSync(resolved);
10462
+ const resolved = path17.resolve(nextRoot);
10463
+ const stat4 = fs16.statSync(resolved);
10388
10464
  if (!stat4.isDirectory()) throw new Error("la ruta no es un directorio");
10389
10465
  const next = analyzeState(resolved, state.watch);
10390
10466
  stopWatcher();
@@ -10407,7 +10483,7 @@ function runServe(options) {
10407
10483
  };
10408
10484
  const meta = () => ({
10409
10485
  version: VERSION === "0.0.0" ? "dev" : VERSION,
10410
- root: path16.basename(state.root),
10486
+ root: path17.basename(state.root),
10411
10487
  rootPath: state.root,
10412
10488
  watch: state.watch,
10413
10489
  files: state.files,
@@ -10468,6 +10544,22 @@ function runServe(options) {
10468
10544
  }
10469
10545
  return;
10470
10546
  }
10547
+ if (pathname === "/api/source") {
10548
+ const relative4 = url.searchParams.get("path");
10549
+ if (!relative4) {
10550
+ sendError(response, 400, "falta path");
10551
+ return;
10552
+ }
10553
+ const start = Number(url.searchParams.get("start") ?? "1");
10554
+ const end = Number(url.searchParams.get("end") ?? "400");
10555
+ const snippet = readSourceSnippet(state.root, relative4, start, end);
10556
+ if (!snippet) {
10557
+ sendError(response, 404, "no hay c\xF3digo para esa ruta");
10558
+ return;
10559
+ }
10560
+ sendJson(response, snippet);
10561
+ return;
10562
+ }
10471
10563
  if (pathname === "/data/snapshot.cc.json") {
10472
10564
  sendJson(response, state.snapshot);
10473
10565
  return;
@@ -10498,7 +10590,7 @@ function runServe(options) {
10498
10590
  return;
10499
10591
  }
10500
10592
  if (pathname === "/data/chains.json") {
10501
- if (!fs15.existsSync(path16.join(state.root, ".codarch"))) {
10593
+ if (!fs16.existsSync(path17.join(state.root, ".codarch"))) {
10502
10594
  ensureGitignoreEntry(state.root, ".codarch/");
10503
10595
  }
10504
10596
  const symbol = url.searchParams.get("symbol");
@@ -10507,14 +10599,14 @@ function runServe(options) {
10507
10599
  }
10508
10600
  if (pathname.startsWith("/data/history/")) {
10509
10601
  const name = pathname.slice("/data/history/".length);
10510
- const file = path16.join(historyLocation(state.root).directory, name);
10602
+ const file = path17.join(historyLocation(state.root).directory, name);
10511
10603
  if (!file.startsWith(historyLocation(state.root).directory)) {
10512
10604
  sendError(response, 403, "ruta fuera del historial");
10513
10605
  return;
10514
10606
  }
10515
10607
  let body;
10516
10608
  try {
10517
- body = fs15.readFileSync(file);
10609
+ body = fs16.readFileSync(file);
10518
10610
  } catch {
10519
10611
  sendError(response, 404, "no hay esa foto en el historial");
10520
10612
  return;
@@ -10631,15 +10723,15 @@ function stateFrom(root, result, watch2) {
10631
10723
  };
10632
10724
  }
10633
10725
  function browseDirectories(root, requested) {
10634
- const target = requested?.trim() ? path16.resolve(requested) : root;
10635
- const stat4 = fs15.statSync(target);
10726
+ const target = requested?.trim() ? path17.resolve(requested) : root;
10727
+ const stat4 = fs16.statSync(target);
10636
10728
  if (!stat4.isDirectory()) throw new Error("la ruta no es un directorio");
10637
- const entries = fs15.readdirSync(target, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !IGNORED_BROWSE.has(entry.name)).sort((left, right) => left.name.localeCompare(right.name)).slice(0, 500).map((entry) => ({
10729
+ const entries = fs16.readdirSync(target, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !IGNORED_BROWSE.has(entry.name)).sort((left, right) => left.name.localeCompare(right.name)).slice(0, 500).map((entry) => ({
10638
10730
  name: entry.name,
10639
- path: path16.join(target, entry.name),
10731
+ path: path17.join(target, entry.name),
10640
10732
  kind: "directory"
10641
10733
  }));
10642
- const parent = path16.dirname(target);
10734
+ const parent = path17.dirname(target);
10643
10735
  return {
10644
10736
  path: target,
10645
10737
  parent: parent === target ? null : parent,
@@ -10675,9 +10767,9 @@ function originAllowed(request, options) {
10675
10767
  function findWebRoot() {
10676
10768
  const candidates = [
10677
10769
  fileURLToPath(new URL("./web", import.meta.url)),
10678
- path16.resolve(process.cwd(), "apps", "web", "dist"),
10679
- path16.resolve(
10680
- path16.dirname(fileURLToPath(import.meta.url)),
10770
+ path17.resolve(process.cwd(), "apps", "web", "dist"),
10771
+ path17.resolve(
10772
+ path17.dirname(fileURLToPath(import.meta.url)),
10681
10773
  "..",
10682
10774
  "..",
10683
10775
  "..",
@@ -10686,14 +10778,14 @@ function findWebRoot() {
10686
10778
  )
10687
10779
  ];
10688
10780
  for (const candidate of candidates) {
10689
- if (fs15.existsSync(path16.join(candidate, "index.html"))) return candidate;
10781
+ if (fs16.existsSync(path17.join(candidate, "index.html"))) return candidate;
10690
10782
  }
10691
10783
  return null;
10692
10784
  }
10693
10785
  function readReport(root) {
10694
- const file = path16.join(root, ".codarch", "report.json");
10786
+ const file = path17.join(root, ".codarch", "report.json");
10695
10787
  try {
10696
- return JSON.parse(fs15.readFileSync(file, "utf8"));
10788
+ return JSON.parse(fs16.readFileSync(file, "utf8"));
10697
10789
  } catch (error) {
10698
10790
  if (error.code !== "ENOENT") {
10699
10791
  console.error(`no se pudo leer ${file}: ${error.message}`);
@@ -10711,16 +10803,16 @@ function serveStatic(webRoot, pathname, headOnly, response) {
10711
10803
  return;
10712
10804
  }
10713
10805
  const relative4 = decoded === "/" ? "index.html" : decoded.replace(/^\/+/, "");
10714
- let file = path16.resolve(webRoot, relative4);
10715
- if (!isWithin2(webRoot, file) || !fs15.existsSync(file) || !fs15.statSync(file).isFile()) {
10716
- file = path16.join(webRoot, "index.html");
10806
+ let file = path17.resolve(webRoot, relative4);
10807
+ if (!isWithin2(webRoot, file) || !fs16.existsSync(file) || !fs16.statSync(file).isFile()) {
10808
+ file = path17.join(webRoot, "index.html");
10717
10809
  }
10718
10810
  try {
10719
- const body = fs15.readFileSync(file);
10811
+ const body = fs16.readFileSync(file);
10720
10812
  response.writeHead(200, {
10721
- "Content-Type": MIME[path16.extname(file).toLowerCase()] ?? "application/octet-stream",
10813
+ "Content-Type": MIME[path17.extname(file).toLowerCase()] ?? "application/octet-stream",
10722
10814
  "Content-Length": body.length,
10723
- "Cache-Control": file.includes(`${path16.sep}assets${path16.sep}`) ? "public, max-age=31536000, immutable" : "no-store",
10815
+ "Cache-Control": file.includes(`${path17.sep}assets${path17.sep}`) ? "public, max-age=31536000, immutable" : "no-store",
10724
10816
  "X-Content-Type-Options": "nosniff"
10725
10817
  });
10726
10818
  if (headOnly) response.end();
@@ -10731,8 +10823,8 @@ function serveStatic(webRoot, pathname, headOnly, response) {
10731
10823
  }
10732
10824
  }
10733
10825
  function isWithin2(root, candidate) {
10734
- const relative4 = path16.relative(root, candidate);
10735
- return relative4 === "" || !relative4.startsWith("..") && !path16.isAbsolute(relative4);
10826
+ const relative4 = path17.relative(root, candidate);
10827
+ return relative4 === "" || !relative4.startsWith("..") && !path17.isAbsolute(relative4);
10736
10828
  }
10737
10829
  function sendJson(response, value) {
10738
10830
  const body = `${JSON.stringify(value)}
@@ -10827,14 +10919,14 @@ function runProfiles(json) {
10827
10919
  }
10828
10920
 
10829
10921
  // apps/cli/src/commands/history.ts
10830
- import fs16 from "node:fs";
10831
- import path17 from "node:path";
10922
+ import fs17 from "node:fs";
10923
+ import path18 from "node:path";
10832
10924
  var numberFormat5 = new Intl.NumberFormat("es-ES");
10833
10925
  function num5(value) {
10834
10926
  return numberFormat5.format(value);
10835
10927
  }
10836
10928
  function runHistory(options) {
10837
- const root = path17.resolve(options.root ?? ".");
10929
+ const root = path18.resolve(options.root ?? ".");
10838
10930
  const index = readHistoryIndex(root);
10839
10931
  if (options.from && options.to) {
10840
10932
  return compareEntries(root, index.entries, options.from, options.to, options);
@@ -10912,10 +11004,10 @@ function compareEntries(root, entries, fromToken, toToken, options) {
10912
11004
  });
10913
11005
  }
10914
11006
  function loadEntry(directory, entry) {
10915
- const file = path17.join(directory, fileNameFor(entry));
11007
+ const file = path18.join(directory, fileNameFor(entry));
10916
11008
  let raw;
10917
11009
  try {
10918
- raw = fs16.readFileSync(file, "utf8");
11010
+ raw = fs17.readFileSync(file, "utf8");
10919
11011
  } catch (error) {
10920
11012
  console.error(`no se pudo leer ${file}: ${error.message}`);
10921
11013
  return null;
@@ -10936,9 +11028,9 @@ function fileNameFor(entry) {
10936
11028
  }
10937
11029
 
10938
11030
  // apps/cli/src/commands/chain.ts
10939
- import path18 from "node:path";
11031
+ import path19 from "node:path";
10940
11032
  function runChain(options) {
10941
- const root = path18.resolve(options.root ?? ".");
11033
+ const root = path19.resolve(options.root ?? ".");
10942
11034
  const index = readHistoryIndex(root);
10943
11035
  if (index.entries.length === 0) {
10944
11036
  console.error(
@@ -11023,10 +11115,10 @@ function eventLabel(type) {
11023
11115
  }
11024
11116
 
11025
11117
  // apps/cli/src/commands/verify.ts
11026
- import fs17 from "node:fs";
11027
- import path19 from "node:path";
11118
+ import fs18 from "node:fs";
11119
+ import path20 from "node:path";
11028
11120
  function runVerify(options) {
11029
- const root = path19.resolve(options.root ?? ".");
11121
+ const root = path20.resolve(options.root ?? ".");
11030
11122
  const index = readHistoryIndex(root);
11031
11123
  if (index.entries.length === 0) {
11032
11124
  console.error(
@@ -11070,21 +11162,21 @@ function runVerify(options) {
11070
11162
  return 2;
11071
11163
  }
11072
11164
  function readCurrentSnapshot(root, last) {
11073
- const current = path19.join(root, ".codarch", "snapshot.cc.json");
11165
+ const current = path20.join(root, ".codarch", "snapshot.cc.json");
11074
11166
  try {
11075
11167
  return parseCcJson(
11076
- JSON.parse(fs17.readFileSync(current, "utf8"))
11168
+ JSON.parse(fs18.readFileSync(current, "utf8"))
11077
11169
  );
11078
11170
  } catch {
11079
11171
  }
11080
11172
  if (!last) return null;
11081
- const history = path19.join(root, ".codarch-history");
11173
+ const history = path20.join(root, ".codarch-history");
11082
11174
  try {
11083
- const files = fs17.readdirSync(history).filter((file) => file.endsWith(".cc.json")).sort();
11175
+ const files = fs18.readdirSync(history).filter((file) => file.endsWith(".cc.json")).sort();
11084
11176
  const lastFile = files[files.length - 1];
11085
11177
  if (!lastFile) return null;
11086
11178
  return parseCcJson(
11087
- JSON.parse(fs17.readFileSync(path19.join(history, lastFile), "utf8"))
11179
+ JSON.parse(fs18.readFileSync(path20.join(history, lastFile), "utf8"))
11088
11180
  );
11089
11181
  } catch {
11090
11182
  return null;
@@ -11197,18 +11289,18 @@ function runSuggest(options) {
11197
11289
  }
11198
11290
 
11199
11291
  // apps/cli/src/commands/addons.ts
11200
- import fs19 from "node:fs";
11201
- import path21 from "node:path";
11292
+ import fs20 from "node:fs";
11293
+ import path22 from "node:path";
11202
11294
 
11203
11295
  // apps/cli/src/commands/installed.ts
11204
- import fs18 from "node:fs";
11205
- import path20 from "node:path";
11296
+ import fs19 from "node:fs";
11297
+ import path21 from "node:path";
11206
11298
  import { parseDocument } from "yaml";
11207
11299
  var CONFIG_FILES2 = [".codarch.yml", ".codarch.yaml"];
11208
11300
  function findConfig(root) {
11209
11301
  for (const file of CONFIG_FILES2) {
11210
- const full = path20.join(root, file);
11211
- if (fs18.existsSync(full)) return full;
11302
+ const full = path21.join(root, file);
11303
+ if (fs19.existsSync(full)) return full;
11212
11304
  }
11213
11305
  return null;
11214
11306
  }
@@ -11222,8 +11314,8 @@ function declaredIn(root, kind) {
11222
11314
  function declareIn(root, kind, name) {
11223
11315
  const file = findConfig(root);
11224
11316
  if (!file) {
11225
- fs18.writeFileSync(
11226
- path20.join(root, ".codarch.yml"),
11317
+ fs19.writeFileSync(
11318
+ path21.join(root, ".codarch.yml"),
11227
11319
  `version: ${CONFIG_VERSION}
11228
11320
 
11229
11321
  ${kind}:
@@ -11242,7 +11334,7 @@ ${kind}:
11242
11334
  if (asRecord(doc.doc.toJS()).version === void 0) {
11243
11335
  doc.doc.set("version", 1);
11244
11336
  }
11245
- fs18.writeFileSync(file, String(doc.doc), "utf8");
11337
+ fs19.writeFileSync(file, String(doc.doc), "utf8");
11246
11338
  return { ok: true };
11247
11339
  }
11248
11340
  function undeclareIn(root, kind, name) {
@@ -11256,13 +11348,13 @@ function undeclareIn(root, kind, name) {
11256
11348
  kind,
11257
11349
  declared.filter((entry) => entry !== name)
11258
11350
  );
11259
- fs18.writeFileSync(file, String(doc.doc), "utf8");
11351
+ fs19.writeFileSync(file, String(doc.doc), "utf8");
11260
11352
  return { ok: true };
11261
11353
  }
11262
11354
  function readDocument(file) {
11263
11355
  let text;
11264
11356
  try {
11265
- text = fs18.readFileSync(file, "utf8");
11357
+ text = fs19.readFileSync(file, "utf8");
11266
11358
  } catch (error) {
11267
11359
  return { ok: false, message: `no se pudo leer ${file}: ${error.message}` };
11268
11360
  }
@@ -11286,13 +11378,13 @@ function stringList(value) {
11286
11378
  return value.filter((entry) => typeof entry === "string");
11287
11379
  }
11288
11380
  function childDirectories(dir) {
11289
- if (!fs18.existsSync(dir)) return [];
11290
- return fs18.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !name.startsWith(".") && name !== "node_modules").sort();
11381
+ if (!fs19.existsSync(dir)) return [];
11382
+ return fs19.readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).filter((name) => !name.startsWith(".") && name !== "node_modules").sort();
11291
11383
  }
11292
11384
 
11293
11385
  // apps/cli/src/commands/addons.ts
11294
11386
  function runAddons(options) {
11295
- const root = path21.resolve(options.root);
11387
+ const root = path22.resolve(options.root);
11296
11388
  if (options.action === "list") return listAddons(root, options.json);
11297
11389
  if (!options.target) {
11298
11390
  console.error(
@@ -11307,7 +11399,7 @@ function listAddons(root, json) {
11307
11399
  const configFile = findConfig(root);
11308
11400
  const declared = declaredIn(root, "addons");
11309
11401
  const missing = declared.filter(
11310
- (name) => !fs19.existsSync(path21.join(root, ADDONS_DIR, name))
11402
+ (name) => !fs20.existsSync(path22.join(root, ADDONS_DIR, name))
11311
11403
  );
11312
11404
  const groups = [
11313
11405
  ...loaded.addons.map((addon) => ({
@@ -11331,7 +11423,7 @@ function listAddons(root, json) {
11331
11423
  JSON.stringify(
11332
11424
  {
11333
11425
  dir: ADDONS_DIR,
11334
- config: configFile ? path21.relative(root, configFile) : null,
11426
+ config: configFile ? path22.relative(root, configFile) : null,
11335
11427
  declared,
11336
11428
  addons: groups,
11337
11429
  missing
@@ -11393,7 +11485,7 @@ function listAddons(root, json) {
11393
11485
  return loaded.errors.length > 0 || missing.length > 0 ? 1 : 0;
11394
11486
  }
11395
11487
  function addAddon(root, target) {
11396
- const source = path21.resolve(root, target);
11488
+ const source = path22.resolve(root, target);
11397
11489
  let addon;
11398
11490
  try {
11399
11491
  addon = loadAddon(source);
@@ -11403,15 +11495,15 @@ function addAddon(root, target) {
11403
11495
  );
11404
11496
  return 1;
11405
11497
  }
11406
- const dest = path21.join(root, ADDONS_DIR, addon.manifest.name);
11407
- if (fs19.existsSync(dest)) {
11498
+ const dest = path22.join(root, ADDONS_DIR, addon.manifest.name);
11499
+ if (fs20.existsSync(dest)) {
11408
11500
  console.error(
11409
11501
  `${ADDONS_DIR}/${addon.manifest.name} ya existe. Qu\xEDtalo antes con: codarch addons remove ${addon.manifest.name}`
11410
11502
  );
11411
11503
  return 1;
11412
11504
  }
11413
- fs19.mkdirSync(path21.dirname(dest), { recursive: true });
11414
- fs19.cpSync(source, dest, { recursive: true });
11505
+ fs20.mkdirSync(path22.dirname(dest), { recursive: true });
11506
+ fs20.cpSync(source, dest, { recursive: true });
11415
11507
  const declared = declareIn(root, "addons", addon.manifest.name);
11416
11508
  if (!declared.ok) {
11417
11509
  console.error(declared.message);
@@ -11438,12 +11530,12 @@ function removeAddon(root, name) {
11438
11530
  console.error(`no es un nombre de addon: ${name}`);
11439
11531
  return 1;
11440
11532
  }
11441
- const dir = path21.join(root, ADDONS_DIR, name);
11442
- if (!fs19.existsSync(dir)) {
11533
+ const dir = path22.join(root, ADDONS_DIR, name);
11534
+ if (!fs20.existsSync(dir)) {
11443
11535
  console.error(`no existe ${ADDONS_DIR}/${name}`);
11444
11536
  return 1;
11445
11537
  }
11446
- fs19.rmSync(dir, { recursive: true, force: true });
11538
+ fs20.rmSync(dir, { recursive: true, force: true });
11447
11539
  const undeclared = undeclareIn(root, "addons", name);
11448
11540
  if (!undeclared.ok) {
11449
11541
  console.error(undeclared.message);
@@ -11456,12 +11548,12 @@ function removeAddon(root, name) {
11456
11548
  }
11457
11549
 
11458
11550
  // apps/cli/src/commands/plugins.ts
11459
- import fs20 from "node:fs";
11460
- import path22 from "node:path";
11551
+ import fs21 from "node:fs";
11552
+ import path23 from "node:path";
11461
11553
  var PLUGINS_DIR = "plugins";
11462
11554
  var ENTRY_FILES = ["index.tsx", "index.ts"];
11463
11555
  function runPlugins(options) {
11464
- const root = path22.resolve(options.root);
11556
+ const root = path23.resolve(options.root);
11465
11557
  if (options.action === "list") return listPlugins(root, options.json);
11466
11558
  if (!options.target) {
11467
11559
  console.error(
@@ -11472,11 +11564,11 @@ function runPlugins(options) {
11472
11564
  return options.action === "add" ? addPlugin(root, options.target) : removePlugin(root, options.target);
11473
11565
  }
11474
11566
  function listPlugins(root, json) {
11475
- const dir = path22.join(root, PLUGINS_DIR);
11567
+ const dir = path23.join(root, PLUGINS_DIR);
11476
11568
  const configFile = findConfig(root);
11477
11569
  const declared = declaredIn(root, "plugins");
11478
11570
  const entries = childDirectories(dir).map((name) => {
11479
- const loaded = readManifest(path22.join(dir, name), name);
11571
+ const loaded = readManifest(path23.join(dir, name), name);
11480
11572
  const isDeclared = declared.includes(name);
11481
11573
  if (!loaded.ok) return { name, declared: isDeclared, error: loaded.message };
11482
11574
  if (loaded.manifest.name !== name) {
@@ -11495,7 +11587,7 @@ function listPlugins(root, json) {
11495
11587
  JSON.stringify(
11496
11588
  {
11497
11589
  dir: PLUGINS_DIR,
11498
- config: configFile ? path22.relative(root, configFile) : null,
11590
+ config: configFile ? path23.relative(root, configFile) : null,
11499
11591
  declared,
11500
11592
  plugins: entries.map(
11501
11593
  (entry) => "error" in entry ? { name: entry.name, error: entry.error, declared: entry.declared } : {
@@ -11558,26 +11650,26 @@ function listPlugins(root, json) {
11558
11650
  return errors.length > 0 || missing.length > 0 ? 1 : 0;
11559
11651
  }
11560
11652
  function addPlugin(root, target) {
11561
- const source = path22.resolve(root, target);
11562
- if (!fs20.existsSync(source) || !fs20.statSync(source).isDirectory()) {
11653
+ const source = path23.resolve(root, target);
11654
+ if (!fs21.existsSync(source) || !fs21.statSync(source).isDirectory()) {
11563
11655
  console.error(`no es una carpeta: ${displayPath(root, source)}`);
11564
11656
  return 1;
11565
11657
  }
11566
- const loaded = readManifest(source, path22.basename(source));
11658
+ const loaded = readManifest(source, path23.basename(source));
11567
11659
  if (!loaded.ok) {
11568
11660
  console.error(`plugin inv\xE1lido: ${loaded.message}`);
11569
11661
  return 1;
11570
11662
  }
11571
11663
  const { manifest } = loaded;
11572
- const dest = path22.join(root, PLUGINS_DIR, manifest.name);
11573
- if (fs20.existsSync(dest)) {
11664
+ const dest = path23.join(root, PLUGINS_DIR, manifest.name);
11665
+ if (fs21.existsSync(dest)) {
11574
11666
  console.error(
11575
11667
  `${PLUGINS_DIR}/${manifest.name} ya existe. Qu\xEDtalo antes con: codarch plugins remove ${manifest.name}`
11576
11668
  );
11577
11669
  return 1;
11578
11670
  }
11579
- fs20.mkdirSync(path22.dirname(dest), { recursive: true });
11580
- fs20.cpSync(source, dest, { recursive: true });
11671
+ fs21.mkdirSync(path23.dirname(dest), { recursive: true });
11672
+ fs21.cpSync(source, dest, { recursive: true });
11581
11673
  const declared = declareIn(root, "plugins", manifest.name);
11582
11674
  if (!declared.ok) {
11583
11675
  console.error(declared.message);
@@ -11599,12 +11691,12 @@ function removePlugin(root, name) {
11599
11691
  console.error(`no es un nombre de plugin: ${name}`);
11600
11692
  return 1;
11601
11693
  }
11602
- const dir = path22.join(root, PLUGINS_DIR, name);
11603
- if (!fs20.existsSync(dir)) {
11694
+ const dir = path23.join(root, PLUGINS_DIR, name);
11695
+ if (!fs21.existsSync(dir)) {
11604
11696
  console.error(`no existe ${PLUGINS_DIR}/${name}`);
11605
11697
  return 1;
11606
11698
  }
11607
- fs20.rmSync(dir, { recursive: true, force: true });
11699
+ fs21.rmSync(dir, { recursive: true, force: true });
11608
11700
  const undeclared = undeclareIn(root, "plugins", name);
11609
11701
  if (!undeclared.ok) {
11610
11702
  console.error(undeclared.message);
@@ -11617,13 +11709,13 @@ function removePlugin(root, name) {
11617
11709
  return 0;
11618
11710
  }
11619
11711
  function readManifest(dir, fallbackName) {
11620
- const file = path22.join(dir, "plugin.json");
11621
- if (!fs20.existsSync(file)) {
11712
+ const file = path23.join(dir, "plugin.json");
11713
+ if (!fs21.existsSync(file)) {
11622
11714
  return { ok: false, message: `falta plugin.json en ${dir}` };
11623
11715
  }
11624
11716
  let raw;
11625
11717
  try {
11626
- raw = JSON.parse(fs20.readFileSync(file, "utf8").replace(/^\uFEFF/, ""));
11718
+ raw = JSON.parse(fs21.readFileSync(file, "utf8").replace(/^\uFEFF/, ""));
11627
11719
  } catch (error) {
11628
11720
  return { ok: false, message: `plugin.json no es JSON: ${error.message}` };
11629
11721
  }
@@ -11653,7 +11745,7 @@ function readManifest(dir, fallbackName) {
11653
11745
  if (names.length !== views.length) {
11654
11746
  return { ok: false, message: "contributes.views solo admite nombres" };
11655
11747
  }
11656
- if (!ENTRY_FILES.some((entry) => fs20.existsSync(path22.join(dir, entry)))) {
11748
+ if (!ENTRY_FILES.some((entry) => fs21.existsSync(path23.join(dir, entry)))) {
11657
11749
  return {
11658
11750
  ok: false,
11659
11751
  message: `falta el punto de entrada en ${dir}: ${ENTRY_FILES.join(" o ")}`
@@ -11673,7 +11765,7 @@ function readManifest(dir, fallbackName) {
11673
11765
  };
11674
11766
  }
11675
11767
  function displayPath(root, target) {
11676
- const relative4 = path22.relative(root, target);
11768
+ const relative4 = path23.relative(root, target);
11677
11769
  return relative4.startsWith("..") ? target : relative4;
11678
11770
  }
11679
11771