@wipcomputer/wip-ldm-os 0.4.72 → 0.4.73-alpha.2

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.
Files changed (2) hide show
  1. package/bin/ldm.js +79 -13
  2. package/package.json +1 -1
package/bin/ldm.js CHANGED
@@ -46,6 +46,53 @@ function installLog(msg) {
46
46
  } catch {}
47
47
  }
48
48
 
49
+ // ── Semver comparison (#XX) ──
50
+ // Proper semver comparison that handles prereleases correctly.
51
+ // 0.4.73-alpha.1 > 0.4.72 (higher base version, prerelease doesn't matter)
52
+ // 0.4.72-alpha.1 < 0.4.72 (same base version, prerelease is older than stable)
53
+ // 0.4.73 > 0.4.72 (straightforward)
54
+ // Returns true if version `a` is strictly newer than version `b`.
55
+ function semverNewer(a, b) {
56
+ if (!a || !b || a === b) return false;
57
+ // Split into base and prerelease: "0.4.73-alpha.1" -> ["0.4.73", "alpha.1"]
58
+ const [aBase, aPre] = a.split('-', 2);
59
+ const [bBase, bPre] = b.split('-', 2);
60
+ const aParts = aBase.split('.').map(Number);
61
+ const bParts = bBase.split('.').map(Number);
62
+ // Compare base version (major.minor.patch)
63
+ for (let i = 0; i < 3; i++) {
64
+ const av = aParts[i] || 0;
65
+ const bv = bParts[i] || 0;
66
+ if (av > bv) return true;
67
+ if (av < bv) return false;
68
+ }
69
+ // Base versions are equal. Stable > prerelease.
70
+ // If a has no prerelease and b does, a is newer (stable release of same base).
71
+ // If a has prerelease and b doesn't, a is older (prerelease of same base).
72
+ if (!aPre && bPre) return true; // a=0.4.72, b=0.4.72-alpha.1 -> a is newer
73
+ if (aPre && !bPre) return false; // a=0.4.72-alpha.1, b=0.4.72 -> a is older
74
+ // Both have prereleases with same base. Compare prerelease segments lexically.
75
+ if (aPre && bPre) {
76
+ const aSegs = aPre.split('.');
77
+ const bSegs = bPre.split('.');
78
+ for (let i = 0; i < Math.max(aSegs.length, bSegs.length); i++) {
79
+ const as = aSegs[i] || '';
80
+ const bs = bSegs[i] || '';
81
+ // Numeric segments compared numerically
82
+ const an = /^\d+$/.test(as) ? Number(as) : NaN;
83
+ const bn = /^\d+$/.test(bs) ? Number(bs) : NaN;
84
+ if (!isNaN(an) && !isNaN(bn)) {
85
+ if (an > bn) return true;
86
+ if (an < bn) return false;
87
+ } else {
88
+ if (as > bs) return true;
89
+ if (as < bs) return false;
90
+ }
91
+ }
92
+ }
93
+ return false;
94
+ }
95
+
49
96
  // Read our own version from package.json
50
97
  const pkgPath = join(__dirname, '..', 'package.json');
51
98
  let PKG_VERSION = '0.2.0';
@@ -148,6 +195,8 @@ const NONE_FLAG = args.includes('--none');
148
195
  const FIX_FLAG = args.includes('--fix');
149
196
  const CLEANUP_FLAG = args.includes('--cleanup');
150
197
  const CHECK_FLAG = args.includes('--check');
198
+ const ALPHA_FLAG = args.includes('--alpha');
199
+ const BETA_FLAG = args.includes('--beta');
151
200
 
152
201
  function readJSON(path) {
153
202
  try {
@@ -170,7 +219,7 @@ function checkCliVersion() {
170
219
  encoding: 'utf8',
171
220
  timeout: 10000,
172
221
  }).trim();
173
- if (result && result !== PKG_VERSION) {
222
+ if (result && semverNewer(result, PKG_VERSION)) {
174
223
  console.log('');
175
224
  console.log(` CLI is outdated: v${PKG_VERSION} installed, v${result} available.`);
176
225
  console.log(` Run: npm install -g @wipcomputer/wip-ldm-os@${result}`);
@@ -1191,6 +1240,8 @@ async function cmdInstall() {
1191
1240
  --json JSON output
1192
1241
  --yes Auto-accept catalog prompts
1193
1242
  --none Skip catalog prompts
1243
+ --alpha Check @alpha npm tag for updates (prerelease track)
1244
+ --beta Check @beta npm tag for updates (prerelease track)
1194
1245
  `);
1195
1246
  process.exit(0);
1196
1247
  }
@@ -1498,13 +1549,19 @@ async function cmdInstallCatalog() {
1498
1549
  // Self-update: check if CLI itself is outdated. Update first, then re-exec.
1499
1550
  // This breaks the chicken-and-egg: new features in ldm install are always
1500
1551
  // available because the installer upgrades itself before doing anything else.
1552
+ // --alpha and --beta flags check the corresponding npm dist-tag instead of @latest.
1501
1553
  if (!DRY_RUN && !process.env.LDM_SELF_UPDATED) {
1502
1554
  try {
1503
- const latest = execSync('npm view @wipcomputer/wip-ldm-os version 2>/dev/null', {
1555
+ const npmTag = ALPHA_FLAG ? 'alpha' : BETA_FLAG ? 'beta' : 'latest';
1556
+ const trackLabel = npmTag === 'latest' ? '' : ` (${npmTag} track)`;
1557
+ const npmViewCmd = npmTag === 'latest'
1558
+ ? 'npm view @wipcomputer/wip-ldm-os version 2>/dev/null'
1559
+ : `npm view @wipcomputer/wip-ldm-os dist-tags.${npmTag} 2>/dev/null`;
1560
+ const latest = execSync(npmViewCmd, {
1504
1561
  encoding: 'utf8', timeout: 15000,
1505
1562
  }).trim();
1506
- if (latest && latest !== PKG_VERSION) {
1507
- console.log(` LDM OS CLI v${PKG_VERSION} -> v${latest}. Updating first...`);
1563
+ if (latest && semverNewer(latest, PKG_VERSION)) {
1564
+ console.log(` LDM OS CLI v${PKG_VERSION} -> v${latest}${trackLabel}. Updating first...`);
1508
1565
  try {
1509
1566
  execSync(`npm install -g @wipcomputer/wip-ldm-os@${latest}`, { stdio: 'inherit', timeout: 60000 });
1510
1567
  console.log(` CLI updated to v${latest}. Re-running with new code...`);
@@ -1761,7 +1818,7 @@ async function cmdInstallCatalog() {
1761
1818
  const cliLatest = execSync('npm view @wipcomputer/wip-ldm-os version 2>/dev/null', {
1762
1819
  encoding: 'utf8', timeout: 10000,
1763
1820
  }).trim();
1764
- if (cliLatest && cliLatest !== PKG_VERSION) {
1821
+ if (cliLatest && semverNewer(cliLatest, PKG_VERSION)) {
1765
1822
  npmUpdates.push({
1766
1823
  name: 'LDM OS CLI',
1767
1824
  catalogNpm: '@wipcomputer/wip-ldm-os',
@@ -1819,13 +1876,18 @@ async function cmdInstallCatalog() {
1819
1876
  }
1820
1877
 
1821
1878
  // Check npm for updates (fast, one HTTP call)
1879
+ // --alpha and --beta flags check the corresponding npm dist-tag
1822
1880
  if (npmPkg) {
1823
1881
  try {
1824
- const latestVersion = execSync(`npm view ${npmPkg} version 2>/dev/null`, {
1882
+ const npmTag = ALPHA_FLAG ? 'alpha' : BETA_FLAG ? 'beta' : 'latest';
1883
+ const npmViewCmd = npmTag === 'latest'
1884
+ ? `npm view ${npmPkg} version 2>/dev/null`
1885
+ : `npm view ${npmPkg} dist-tags.${npmTag} 2>/dev/null`;
1886
+ const latestVersion = execSync(npmViewCmd, {
1825
1887
  encoding: 'utf8', timeout: 10000,
1826
1888
  }).trim();
1827
1889
 
1828
- if (latestVersion && latestVersion !== currentVersion) {
1890
+ if (latestVersion && semverNewer(latestVersion, currentVersion)) {
1829
1891
  npmUpdates.push({
1830
1892
  name,
1831
1893
  catalogRepo: repoUrl,
@@ -1852,7 +1914,7 @@ async function cmdInstallCatalog() {
1852
1914
  const tagMatch = tags.match(/refs\/tags\/v?(\d+\.\d+\.\d+)/);
1853
1915
  if (tagMatch) {
1854
1916
  const latestVersion = tagMatch[1];
1855
- if (latestVersion !== currentVersion) {
1917
+ if (semverNewer(latestVersion, currentVersion)) {
1856
1918
  npmUpdates.push({
1857
1919
  name,
1858
1920
  catalogRepo: repoUrl,
@@ -1885,10 +1947,14 @@ async function cmdInstallCatalog() {
1885
1947
  if (!currentVersion) continue;
1886
1948
 
1887
1949
  try {
1888
- const latestVersion = execSync(`npm view ${catalogComp.npm} version 2>/dev/null`, {
1950
+ const npmTag = ALPHA_FLAG ? 'alpha' : BETA_FLAG ? 'beta' : 'latest';
1951
+ const npmViewCmd = npmTag === 'latest'
1952
+ ? `npm view ${catalogComp.npm} version 2>/dev/null`
1953
+ : `npm view ${catalogComp.npm} dist-tags.${npmTag} 2>/dev/null`;
1954
+ const latestVersion = execSync(npmViewCmd, {
1889
1955
  encoding: 'utf8', timeout: 10000,
1890
1956
  }).trim();
1891
- if (latestVersion && latestVersion !== currentVersion) {
1957
+ if (latestVersion && semverNewer(latestVersion, currentVersion)) {
1892
1958
  npmUpdates.push({
1893
1959
  name: binName,
1894
1960
  catalogRepo: catalogComp.repo,
@@ -1921,7 +1987,7 @@ async function cmdInstallCatalog() {
1921
1987
  const latest = execSync(`npm view ${comp.npm} version 2>/dev/null`, {
1922
1988
  encoding: 'utf8', timeout: 10000,
1923
1989
  }).trim();
1924
- if (latest && latest !== currentVersion) {
1990
+ if (latest && semverNewer(latest, currentVersion)) {
1925
1991
  // Remove any sub-tool entries that belong to this parent.
1926
1992
  const parentMatches = new Set(comp.registryMatches || []);
1927
1993
  for (let i = npmUpdates.length - 1; i >= 0; i--) {
@@ -2563,7 +2629,7 @@ function cmdStatus() {
2563
2629
  const latest = execSync('npm view @wipcomputer/wip-ldm-os version 2>/dev/null', {
2564
2630
  encoding: 'utf8', timeout: 10000,
2565
2631
  }).trim();
2566
- if (latest && latest !== PKG_VERSION) cliUpdate = latest;
2632
+ if (latest && semverNewer(latest, PKG_VERSION)) cliUpdate = latest;
2567
2633
  } catch {}
2568
2634
 
2569
2635
  // Check extensions against npm using registry source info (#262)
@@ -2583,7 +2649,7 @@ function cmdStatus() {
2583
2649
  const latest = execSync(`npm view ${npmPkg} version 2>/dev/null`, {
2584
2650
  encoding: 'utf8', timeout: 10000,
2585
2651
  }).trim();
2586
- if (latest && latest !== currentVersion) {
2652
+ if (latest && semverNewer(latest, currentVersion)) {
2587
2653
  updates.push({ name, current: currentVersion, latest, npm: npmPkg });
2588
2654
  }
2589
2655
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.72",
3
+ "version": "0.4.73-alpha.2",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {