c8ctl-plugin-nano 1.3.2 → 1.3.3

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/c8ctl-plugin.js +94 -35
  2. package/package.json +6 -6
package/c8ctl-plugin.js CHANGED
@@ -63,6 +63,21 @@ function readBundledBinaryInfo() {
63
63
  }
64
64
  }
65
65
 
66
+ /** Run `<binary> --version` and extract a semver-ish token. Null on failure. */
67
+ function binaryVersion(binary) {
68
+ if (!binary) return null;
69
+ try {
70
+ const res = spawnSync(binary, ['--version'], { encoding: 'utf8', timeout: 3000 });
71
+ if (res.status === 0) {
72
+ const m = String(res.stdout || res.stderr || '').match(/(\d+\.\d+\.\d+[^\s]*)/);
73
+ if (m) return m[1];
74
+ }
75
+ } catch {
76
+ /* ignore */
77
+ }
78
+ return null;
79
+ }
80
+
66
81
  /**
67
82
  * Locate the nanobpmn binary shipped by the matching platform package
68
83
  * (an optionalDependency such as @nanobpm/c8ctl-plugin-nano-darwin-arm64).
@@ -855,6 +870,7 @@ async function statusCluster(req) {
855
870
  `${state.raft ? ' raft: on' : ''}${state.capture ? ' trace capture: on' : ''}`,
856
871
  );
857
872
  console.log(` binary: ${state.binary}`);
873
+ console.log(` version: ${binaryVersion(state.binary) ?? 'unknown'}`);
858
874
  console.log(` workspace: ${state.workspaceDir || getWorkspaceDir()}`);
859
875
  console.log(` data: ${getDataDir()}`);
860
876
  console.log('');
@@ -1186,8 +1202,22 @@ function isGlobalInstall() {
1186
1202
 
1187
1203
  function updatePlugin(req) {
1188
1204
  const { name, version: current } = pluginPackage();
1205
+
1206
+ // The nano server binary ships with the plugin as its platform package
1207
+ // (an optionalDependency pinned to the plugin version), so a plugin update is
1208
+ // what delivers a new server. Surface the resolved binary's version, and flag
1209
+ // it when the platform package isn't installed for this host.
1210
+ let nanoBin = null;
1211
+ try {
1212
+ nanoBin = findBinary({});
1213
+ } catch {
1214
+ nanoBin = null;
1215
+ }
1189
1216
  const bundled = readBundledBinaryInfo();
1190
- const nanoNote = bundled ? ` (bundled nano ${bundled.version})` : '';
1217
+ const nanoVer = nanoBin ? binaryVersion(nanoBin) : null;
1218
+ const nanoNote = nanoBin
1219
+ ? ` (nano server ${nanoVer ?? bundled?.version ?? 'present'})`
1220
+ : ' (nano server: not installed for this platform)';
1191
1221
  const manual = ` npm install -g ${name}@latest`;
1192
1222
 
1193
1223
  console.log(`Installed: ${name} v${current ?? '?'}${nanoNote}`);
@@ -1205,6 +1235,13 @@ function updatePlugin(req) {
1205
1235
  console.log('');
1206
1236
 
1207
1237
  if (current && compareSemver(current, latest) >= 0) {
1238
+ if (!nanoBin) {
1239
+ // Plugin is current but npm never fetched the matching server binary.
1240
+ console.log('Plugin is current, but the nano server binary is not installed for this platform.');
1241
+ console.log('Provision it by reinstalling the plugin so npm fetches the platform package:');
1242
+ console.log(' c8ctl sync plugin');
1243
+ return;
1244
+ }
1208
1245
  console.log('Already on the latest release — nothing to do.');
1209
1246
  return;
1210
1247
  }
@@ -1451,7 +1488,7 @@ function clearProcessosState() {
1451
1488
  * only when an *explicitly* configured source points at a missing file (so the
1452
1489
  * user gets an actionable error rather than a silent fallthrough).
1453
1490
  */
1454
- function findConfiguredProcessosBinary(req) {
1491
+ function findConfiguredProcessosBinary(req, { includeCached = true } = {}) {
1455
1492
  const cfg = readProcessosConfig();
1456
1493
  const sources = [
1457
1494
  { val: req?.binary && String(req.binary), from: '--binary' },
@@ -1467,9 +1504,7 @@ function findConfiguredProcessosBinary(req) {
1467
1504
  return abs;
1468
1505
  }
1469
1506
 
1470
- const cached = getProcessosCachedBinaryPath();
1471
- if (existsSync(cached)) return cached;
1472
-
1507
+ // A local source build wins over a downloaded copy for developers in the repo.
1473
1508
  let repo = null;
1474
1509
  try {
1475
1510
  repo = getRepoRoot();
@@ -1485,6 +1520,14 @@ function findConfiguredProcessosBinary(req) {
1485
1520
  if (existsSync(c)) return c;
1486
1521
  }
1487
1522
  }
1523
+
1524
+ // The auto-downloaded copy. The resolver skips it (includeCached:false) so it
1525
+ // can manage that copy with a version check and re-fetch newer published
1526
+ // builds; all other callers still see it as the installed binary.
1527
+ if (includeCached) {
1528
+ const cached = getProcessosCachedBinaryPath();
1529
+ if (existsSync(cached)) return cached;
1530
+ }
1488
1531
  return null;
1489
1532
  }
1490
1533
 
@@ -1598,33 +1641,55 @@ async function downloadProcessosBinary(url, dest) {
1598
1641
  * configured/local binary -> cached download -> fresh download -> error.
1599
1642
  */
1600
1643
  async function resolveProcessosBinary(req) {
1601
- const configured = findConfiguredProcessosBinary(req); // may throw on a missing configured path
1644
+ // An explicitly configured or local source build wins and is used as-is (no
1645
+ // auto-update). The auto-downloaded copy is handled below with a version
1646
+ // check so `start` can pull a newer published build.
1647
+ const configured = findConfiguredProcessosBinary(req, { includeCached: false });
1602
1648
  if (configured) return configured;
1603
1649
 
1604
1650
  const dlUrl = getProcessosDownloadUrl();
1651
+ const cached = getProcessosCachedBinaryPath();
1652
+
1605
1653
  if (dlUrl) {
1606
- const dest = getProcessosCachedBinaryPath();
1607
1654
  const meta = await fetchProcessosVersionMeta(dlUrl);
1608
- await downloadProcessosBinary(processosBinaryUrl(dlUrl), dest);
1609
- // Record what we fetched so the update notifier can compare later.
1610
- try {
1611
- mkdirSync(getProcessosBinDir(), { recursive: true });
1612
- writeFileSync(
1613
- getProcessosBinaryMetaPath(),
1614
- JSON.stringify({
1615
- version: meta?.version ?? null,
1616
- commit: meta?.commit ?? null,
1617
- updated: meta?.updated ?? null,
1618
- source: processosDownloadBase(dlUrl),
1619
- downloaded: new Date().toISOString(),
1620
- }),
1621
- );
1622
- } catch {
1623
- /* sidecar is best-effort */
1655
+ const have = readProcessosBinaryMeta();
1656
+ const remoteVer = meta?.version ?? null;
1657
+ const haveVer = have?.version ?? null;
1658
+ const haveCached = existsSync(cached);
1659
+
1660
+ // Download when there is no cached copy, or when the published version.json
1661
+ // reports a version different from the one recorded for the cached copy.
1662
+ // This also covers binaries cached before version tracking (no haveVer).
1663
+ const needDownload = !haveCached || (remoteVer && remoteVer !== haveVer);
1664
+ if (needDownload) {
1665
+ const logger = getLogger();
1666
+ if (haveCached && remoteVer) {
1667
+ logger.info(`Updating ProcessOS ${haveVer ?? '?'} -> ${remoteVer} ...`);
1668
+ }
1669
+ await downloadProcessosBinary(processosBinaryUrl(dlUrl), cached);
1670
+ // Record what we fetched so the update notifier/status can compare later.
1671
+ try {
1672
+ mkdirSync(getProcessosBinDir(), { recursive: true });
1673
+ writeFileSync(
1674
+ getProcessosBinaryMetaPath(),
1675
+ JSON.stringify({
1676
+ version: meta?.version ?? null,
1677
+ commit: meta?.commit ?? null,
1678
+ updated: meta?.updated ?? null,
1679
+ source: processosDownloadBase(dlUrl),
1680
+ downloaded: new Date().toISOString(),
1681
+ }),
1682
+ );
1683
+ } catch {
1684
+ /* sidecar is best-effort */
1685
+ }
1624
1686
  }
1625
- return dest;
1687
+ if (existsSync(cached)) return cached;
1626
1688
  }
1627
1689
 
1690
+ // A previously downloaded copy still runs even if the URL is now unset.
1691
+ if (existsSync(cached)) return cached;
1692
+
1628
1693
  throw new Error(
1629
1694
  `Could not find or download the ProcessOS binary.\n` +
1630
1695
  `Set the download URL you were given (PROCESSOS_DOWNLOAD_URL), point the plugin at a\n` +
@@ -1707,17 +1772,7 @@ function getInstalledProcessosVersion(req) {
1707
1772
  } catch {
1708
1773
  binary = null;
1709
1774
  }
1710
- if (!binary) return null;
1711
- try {
1712
- const res = spawnSync(binary, ['--version'], { encoding: 'utf8', timeout: 3000 });
1713
- if (res.status === 0) {
1714
- const m = String(res.stdout || '').match(/(\d+\.\d+\.\d+[^\s]*)/);
1715
- if (m) return m[1];
1716
- }
1717
- } catch {
1718
- /* ignore */
1719
- }
1720
- return null;
1775
+ return binaryVersion(binary);
1721
1776
  }
1722
1777
 
1723
1778
  /**
@@ -1990,10 +2045,14 @@ async function statusProcessos() {
1990
2045
 
1991
2046
  const alive = isPidAlive(state.pid);
1992
2047
  const healthy = alive ? await probeProcessosHealthy(state.url) : false;
2048
+ // Prefer the actual running binary's reported version; fall back to the
2049
+ // recorded download metadata if the binary can't be probed.
2050
+ const version = binaryVersion(state.binary) ?? getInstalledProcessosVersion() ?? 'unknown';
1993
2051
 
1994
2052
  console.log('ProcessOS status:');
1995
2053
  console.log('');
1996
2054
  console.log(` pid: ${state.pid} ${alive ? '(alive)' : '(dead — stale state)'}`);
2055
+ console.log(` version: ${version}`);
1997
2056
  console.log(` url: ${state.url}`);
1998
2057
  console.log(` health: ${healthy ? 'ok' : 'unreachable'} (${state.url}/health)`);
1999
2058
  console.log(` target: ${state.nanoUrl}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "c8ctl-plugin-nano",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "type": "module",
5
5
  "description": "c8ctl plugin to start, inspect, and stop a local Nano BPM (nanobpmn) cluster",
6
6
  "main": "c8ctl-plugin.js",
@@ -49,10 +49,10 @@
49
49
  "semantic-release": "^25.0.3"
50
50
  },
51
51
  "optionalDependencies": {
52
- "@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.3.2",
53
- "@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.3.2",
54
- "@nanobpm/c8ctl-plugin-nano-linux-x64": "1.3.2",
55
- "@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.3.2",
56
- "@nanobpm/c8ctl-plugin-nano-win32-x64": "1.3.2"
52
+ "@nanobpm/c8ctl-plugin-nano-darwin-arm64": "1.3.3",
53
+ "@nanobpm/c8ctl-plugin-nano-darwin-x64": "1.3.3",
54
+ "@nanobpm/c8ctl-plugin-nano-linux-x64": "1.3.3",
55
+ "@nanobpm/c8ctl-plugin-nano-linux-arm64": "1.3.3",
56
+ "@nanobpm/c8ctl-plugin-nano-win32-x64": "1.3.3"
57
57
  }
58
58
  }