memhouse 0.18.6 → 0.18.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/memhouse.js CHANGED
@@ -28,6 +28,7 @@ const {
28
28
  SCHEMA_VERSION, MIN_WRITER_SCHEMA, MIGRATIONS, META_TYPES, createStatement,
29
29
  } = require(path.join(REPO_ROOT, 'memhouse', 'house', 'house'));
30
30
  const envfile = require(path.join(REPO_ROOT, 'memhouse', 'envfile'));
31
+ const chan = require(path.join(REPO_ROOT, 'memhouse', 'channel'));
31
32
  const { consumeSecretChunk } = require(path.join(REPO_ROOT, 'memhouse', 'secret-input'));
32
33
  const { capabilitiesFrom } = require(path.join(REPO_ROOT, 'memhouse', 'capabilities'));
33
34
  const { unknownFlags, allowedFlags, suggestFlag } = require(path.join(REPO_ROOT, 'memhouse', 'flags'));
@@ -1612,6 +1613,7 @@ async function cmdStatus() {
1612
1613
  daemons: { shipper: pidOf('shipper'), dashboard: pidOf('dashboard') },
1613
1614
  dashboard_url: pidOf('dashboard') ? `http://localhost:${runningPort(cfg)}` : null,
1614
1615
  shipper: shipperHealth(),
1616
+ update: null, // filled below from the registry; null when current, offline, or a checkout build
1615
1617
  // Which machine this is, in the rooms' own terms. All of a member's machines write
1616
1618
  // into one set of rooms, so `WHERE host = ...` is how the pilot separates this laptop
1617
1619
  // from the other one — and they cannot type it if nothing ever prints it.
@@ -1628,6 +1630,10 @@ async function cmdStatus() {
1628
1630
  out.messages = Number(m[0]?.msgs || 0);
1629
1631
  out.freshest = m[0]?.freshest || null;
1630
1632
  out.fleet = await fleetState(cfg);
1633
+ // Nobody runs `update --check`. A member sat four days behind a release that fixed the
1634
+ // very thing they were about to hit, with nothing on any screen saying so.
1635
+ try { out.update = chan.behind({ version: PKG.version, pinned: cfg.channel || null, tags: await chan.fetchTags() }); }
1636
+ catch { /* offline: say nothing rather than guess */ }
1631
1637
  } catch (e) { out.connected = false; out.error = netReason(e); }
1632
1638
 
1633
1639
  if (JSON_OUT) { console.log(JSON.stringify(out, null, 2)); return out.connected ? 0 : 1; }
@@ -1673,6 +1679,7 @@ async function cmdStatus() {
1673
1679
  : fail ? warn(`shipper: running — ${out.shipper.via} — but ${fail}`)
1674
1680
  : ok(`shipper: running — ${out.shipper.via}`));
1675
1681
  }
1682
+ if (out.update) console.log(warn(`update available: ${out.update.target} on '${out.update.channel}' — you have ${PKG.version} — run: memhouse update`));
1676
1683
  console.log(out.daemons.dashboard ? ok(`dashboard: running (pid ${out.daemons.dashboard})`) : warn('dashboard: not running'));
1677
1684
  if (out.daemons.dashboard) console.log(` dashboard → http://localhost:${runningPort(cfg)}`);
1678
1685
  // Exit non-zero when the house is unreachable. `status` is what a health check, a
@@ -2022,6 +2029,12 @@ async function cmdDoctor() {
2022
2029
  const moved = await adoptMovedHouse(cfg, { fix: false });
2023
2030
  if (moved === 'moved') add(false, `rooms moved to mem.${physicalRoom('messages', cfg.user).replace(/_messages$/, '')}_* — this env still says MEMHOUSE_DB=${cfg.db}`, 'memhouse update (rewrites the env and restarts the shipper)');
2024
2031
  } catch { /* connection problems are reported above */ }
2032
+ {
2033
+ // The same shape doctor gives everything else: what is wrong, and the command.
2034
+ let up = null;
2035
+ try { up = chan.behind({ version: PKG.version, pinned: cfg.channel || null, tags: await chan.fetchTags() }); } catch { /* offline */ }
2036
+ if (up) add(false, `memhouse ${PKG.version} — ${up.target} is out on '${up.channel}'`, 'memhouse update');
2037
+ }
2025
2038
  const sh = shipperHealth();
2026
2039
  const shFail = require(path.join(REPO_ROOT, 'memhouse', 'shipper', 'passlog')).describeFailure(sh.lastPass);
2027
2040
  add(sh.running && !shFail, `shipper${sh.via ? ` — ${sh.via}` : ''}${shFail ? ` — ${shFail}` : ''}`,
@@ -2162,7 +2175,6 @@ function installKind() {
2162
2175
  // Each of those has cost a real machine real sessions. This command owns all three.
2163
2176
  async function cmdUpdate() {
2164
2177
  const { kind, root } = installKind();
2165
- const chan = require(path.join(REPO_ROOT, 'memhouse', 'channel'));
2166
2178
  const cfg0 = resolveConfig();
2167
2179
  // --channel pins for this run AND every later one: the point of pinning is that the next
2168
2180
  // person to type `memhouse update` does not have to remember it.
@@ -60,4 +60,27 @@ async function fetchTags(fetchImpl = globalThis.fetch) {
60
60
  } catch { return null; }
61
61
  }
62
62
 
63
- module.exports = { pickChannel, fetchTags, isPrerelease, lineOf };
63
+ /**
64
+ * Is this install behind its channel? Pure — the caller supplies the tags, so nothing here
65
+ * reaches the network and `status` stays offline-safe.
66
+ *
67
+ * Only a strictly newer target counts: a prerelease, a version ahead of the tag, or a
68
+ * registry that did not answer all return null, because "unknown" must never read as
69
+ * "you are behind" on a health screen someone gates on.
70
+ *
71
+ * @returns {{target: string, channel: string}|null}
72
+ */
73
+ function behind({ version, pinned = null, tags = null }) {
74
+ if (!tags) return null;
75
+ const pick = pickChannel({ version, pinned, tags });
76
+ if (!pick.target || pick.target === version) return null;
77
+ const n = (v) => String(v).split('-')[0].split('.').map(Number);
78
+ const [a, b] = [n(pick.target), n(version)];
79
+ for (let i = 0; i < 3; i++) {
80
+ if ((a[i] || 0) > (b[i] || 0)) return { target: pick.target, channel: pick.channel };
81
+ if ((a[i] || 0) < (b[i] || 0)) return null;
82
+ }
83
+ return null;
84
+ }
85
+
86
+ module.exports = { behind, pickChannel, fetchTags, isPrerelease, lineOf };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mem",
3
3
  "description": "Conversation memory for AI agents over the memhouse typed ClickHouse store: recall past sessions and answer from them, run analytics, check the house, bring people in, and administer the server. Skills install as /mem:recall, /mem:sql, /mem:house, /mem:access, and /mem:admin.",
4
- "version": "0.18.6",
4
+ "version": "0.18.7",
5
5
  "author": {
6
6
  "name": "Ramazan Polat"
7
7
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memhouse",
3
- "version": "0.18.6",
3
+ "version": "0.18.7",
4
4
  "description": "memhouse \u2014 agent conversation memory across 17 editors: parse-on-client shippers, a typed ClickHouse store with one set of rooms per member, kernel-agency install, and the agentlytics dashboard",
5
5
  "main": "bin/memhouse.js",
6
6
  "bin": {