@tikoci/rosetta 0.8.3 → 0.8.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tikoci/rosetta",
3
- "version": "0.8.3",
3
+ "version": "0.8.4",
4
4
  "description": "RouterOS documentation as SQLite FTS5 — RAG search + command glossary via MCP",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/browse.ts CHANGED
@@ -31,6 +31,7 @@ import {
31
31
  browseCommands,
32
32
  browseCommandsAtVersion,
33
33
  checkCommandVersions,
34
+ compareVersions,
34
35
  diffCommandVersions,
35
36
  fetchCurrentVersions,
36
37
  getDudePage,
@@ -1966,7 +1967,13 @@ async function doSearchChangelogs(query: string): Promise<void> {
1966
1967
  if (part.toLowerCase() === "breaking") { breakingOnly = true; continue; }
1967
1968
  // Version range: "7.20..7.22"
1968
1969
  const rangeMatch = part.match(/^(\d+\.\d+[.\w]*)\.\.(\d+\.\d+[.\w]*)$/);
1969
- if (rangeMatch) { fromVersion = rangeMatch[1]; toVersion = rangeMatch[2]; continue; }
1970
+ if (rangeMatch) {
1971
+ const [a, b] = [rangeMatch[1], rangeMatch[2]];
1972
+ // Normalise: always put the lower version first
1973
+ if (compareVersions(a, b) <= 0) { fromVersion = a; toVersion = b; }
1974
+ else { fromVersion = b; toVersion = a; }
1975
+ continue;
1976
+ }
1970
1977
  // Single version: "7.22"
1971
1978
  if (/^\d+\.\d+/.test(part)) { version = part; continue; }
1972
1979
  searchTerms.push(part);
@@ -1979,6 +1986,8 @@ async function doSearchChangelogs(query: string): Promise<void> {
1979
1986
  version,
1980
1987
  fromVersion,
1981
1988
  toVersion,
1989
+ inclusiveFrom: fromVersion !== undefined, // X..Y range is [X, Y] inclusive on both ends
1990
+ sortAscending: fromVersion !== undefined, // range queries read chronologically (oldest first)
1982
1991
  category,
1983
1992
  breakingOnly,
1984
1993
  limit: 50,
package/src/query.ts CHANGED
@@ -1852,6 +1852,7 @@ export type ChangelogResult = {
1852
1852
  is_breaking: number;
1853
1853
  description: string;
1854
1854
  excerpt: string;
1855
+ sort_order: number;
1855
1856
  };
1856
1857
 
1857
1858
  /** Get all versions that have changelog data, sorted numerically. */
@@ -1862,14 +1863,22 @@ function getChangelogVersions(): string[] {
1862
1863
  return rows.map((r) => r.version).sort(compareVersions);
1863
1864
  }
1864
1865
 
1865
- /** Filter versions to those within (fromVersion, toVersion] range (fromVersion exclusive, toVersion inclusive). */
1866
+ /**
1867
+ * Filter versions to those within a range.
1868
+ * Default: (fromVersion, toVersion] — fromVersion exclusive, toVersion inclusive.
1869
+ * Pass inclusiveFrom=true for [fromVersion, toVersion] (both ends inclusive).
1870
+ */
1866
1871
  function filterVersionRange(
1867
1872
  versions: string[],
1868
1873
  fromVersion?: string,
1869
1874
  toVersion?: string,
1875
+ inclusiveFrom = false,
1870
1876
  ): string[] {
1871
1877
  return versions.filter((v) => {
1872
- if (fromVersion && compareVersions(v, fromVersion) <= 0) return false;
1878
+ if (fromVersion) {
1879
+ const cmp = compareVersions(v, fromVersion);
1880
+ if (inclusiveFrom ? cmp < 0 : cmp <= 0) return false;
1881
+ }
1873
1882
  if (toVersion && compareVersions(v, toVersion) > 0) return false;
1874
1883
  return true;
1875
1884
  });
@@ -1882,6 +1891,8 @@ export function searchChangelogs(
1882
1891
  version?: string;
1883
1892
  fromVersion?: string;
1884
1893
  toVersion?: string;
1894
+ inclusiveFrom?: boolean;
1895
+ sortAscending?: boolean;
1885
1896
  category?: string;
1886
1897
  breakingOnly?: boolean;
1887
1898
  limit?: number;
@@ -1896,23 +1907,30 @@ export function searchChangelogs(
1896
1907
  versionList = [options.version];
1897
1908
  } else if (options.fromVersion || options.toVersion) {
1898
1909
  const all = getChangelogVersions();
1899
- versionList = filterVersionRange(all, options.fromVersion, options.toVersion);
1910
+ versionList = filterVersionRange(all, options.fromVersion, options.toVersion, options.inclusiveFrom);
1900
1911
  if (versionList.length === 0) return [];
1901
1912
  }
1902
1913
 
1914
+ let results: ChangelogResult[];
1915
+
1903
1916
  // No FTS query — browse by filters only
1904
1917
  if (terms.length === 0) {
1905
- return browseChangelogs(versionList, options.category, options.breakingOnly, limit);
1906
- }
1918
+ results = browseChangelogs(versionList, options.category, options.breakingOnly, limit);
1919
+ } else {
1920
+ // FTS search with AND, then fallback to OR
1921
+ let ftsQuery = buildFtsQuery(terms, "AND");
1922
+ if (!ftsQuery) return [];
1923
+ results = runChangelogFtsQuery(ftsQuery, versionList, options.category, options.breakingOnly, limit);
1907
1924
 
1908
- // FTS search with AND, then fallback to OR
1909
- let ftsQuery = buildFtsQuery(terms, "AND");
1910
- if (!ftsQuery) return [];
1911
- let results = runChangelogFtsQuery(ftsQuery, versionList, options.category, options.breakingOnly, limit);
1925
+ if (results.length === 0 && terms.length > 1) {
1926
+ ftsQuery = buildFtsQuery(terms, "OR");
1927
+ results = runChangelogFtsQuery(ftsQuery, versionList, options.category, options.breakingOnly, limit);
1928
+ }
1929
+ }
1912
1930
 
1913
- if (results.length === 0 && terms.length > 1) {
1914
- ftsQuery = buildFtsQuery(terms, "OR");
1915
- results = runChangelogFtsQuery(ftsQuery, versionList, options.category, options.breakingOnly, limit);
1931
+ // Re-sort by version when caller wants chronological order (oldest first)
1932
+ if (options.sortAscending) {
1933
+ results.sort((a, b) => compareVersions(a.version, b.version) || a.sort_order - b.sort_order);
1916
1934
  }
1917
1935
 
1918
1936
  return results;
@@ -1946,7 +1964,7 @@ function browseChangelogs(
1946
1964
  }
1947
1965
 
1948
1966
  const sql = `SELECT c.version, c.released, c.category, c.is_breaking,
1949
- c.description, substr(c.description, 1, 200) as excerpt
1967
+ c.description, substr(c.description, 1, 200) as excerpt, c.sort_order
1950
1968
  FROM changelogs c
1951
1969
  WHERE ${where.join(" AND ")}
1952
1970
  ORDER BY c.sort_order
@@ -1982,7 +2000,7 @@ function runChangelogFtsQuery(
1982
2000
  }
1983
2001
 
1984
2002
  const sql = `SELECT c.version, c.released, c.category, c.is_breaking,
1985
- c.description,
2003
+ c.description, c.sort_order,
1986
2004
  snippet(changelogs_fts, 1, '**', '**', '...', 25) as excerpt
1987
2005
  FROM changelogs_fts fts
1988
2006
  JOIN changelogs c ON c.id = fts.rowid