@tpsdev-ai/flair 0.25.1 → 0.25.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.
package/README.md CHANGED
@@ -126,11 +126,11 @@ Every agent has an Ed25519 key pair. Requests are signed with `agentId:timestamp
126
126
  Memories are automatically embedded on write using [nomic-embed-text](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF) (768 dimensions). Search by meaning:
127
127
 
128
128
  ```bash
129
- # Write a memory
130
- flair memory write "Harper v5 sandbox blocks node:module but process.dlopen works"
129
+ # Write a memory (--agent is your registered agent id)
130
+ flair memory add --agent myagent "Harper v5 sandbox blocks node:module but process.dlopen works"
131
131
 
132
132
  # Find it later by concept, not exact words
133
- flair memory search "native addon loading in sandboxed runtimes"
133
+ flair memory search --agent myagent "native addon loading in sandboxed runtimes"
134
134
  # → [0.67] Harper v5 sandbox blocks node:module but process.dlopen works
135
135
  ```
136
136
 
package/dist/cli.js CHANGED
@@ -12,8 +12,8 @@ import { create as tarCreate, extract as tarExtract, list as tarList } from "tar
12
12
  import { keystore } from "./keystore.js";
13
13
  import { deploy as deployToFabric, validateOptions as validateDeployOptions, buildTargetUrl as buildDeployUrl } from "./deploy.js";
14
14
  import { fabricUpgrade } from "./fabric-upgrade.js";
15
- import { checkVersion, formatVersionNudge } from "./version-check.js";
16
- import { checkServerHandshake, formatHandshakeNudge } from "./version-handshake.js";
15
+ import { checkVersion, formatVersionNudge, primeVersionCheckCache, FLAIR_PKG_NAME } from "./version-check.js";
16
+ import { checkServerHandshake, formatHandshakeNudge, invalidateHandshakeCache } from "./version-handshake.js";
17
17
  import { probeInstance } from "./probe.js";
18
18
  import { sweepFleet, renderFleetSweepTable, FLEET_EXIT_OK, } from "./fleet-verify.js";
19
19
  import { markStale, sortOldestVersionFirst } from "./fleet-presence.js";
@@ -8053,6 +8053,12 @@ program
8053
8053
  continue;
8054
8054
  const data = await res.json();
8055
8055
  const latest = data.version ?? "unknown";
8056
+ if (name === FLAIR_PKG_NAME && latest !== "unknown") {
8057
+ try {
8058
+ primeVersionCheckCache(latest);
8059
+ }
8060
+ catch { /* best-effort */ }
8061
+ }
8056
8062
  const installed = probe();
8057
8063
  let status;
8058
8064
  if (installed === null) {
@@ -8722,6 +8728,15 @@ async function startFlairProcess(port) {
8722
8728
  async function restartFlair(port) {
8723
8729
  await stopFlairProcess(port);
8724
8730
  await startFlairProcess(port);
8731
+ // Bust the version-handshake cache so the next preAction nudge re-fetches
8732
+ // the LIVE version instead of the pre-restart cached one (the false
8733
+ // "server is running <old>" users hit for up to 60s post-upgrade+restart).
8734
+ // Same (rootPath, serverUrl) key the preAction hook computes (~line 2189)
8735
+ // — must match exactly, or this busts the wrong cache file.
8736
+ try {
8737
+ invalidateHandshakeCache(process.env.ROOTPATH ?? defaultDataDir(), `http://127.0.0.1:${port}`);
8738
+ }
8739
+ catch { /* best-effort — never fail a restart over cache cleanup */ }
8725
8740
  }
8726
8741
  program
8727
8742
  .command("restart")
@@ -12752,6 +12767,14 @@ program
12752
12767
  // its Node-version check passes. The shim imports this module, so import.meta.main
12753
12768
  // is false there — without this explicit entry point the CLI would load but never run.
12754
12769
  async function runCli() {
12770
+ // A bare `flair` (no command) is a help request, not a usage error — show
12771
+ // help and exit 0, rather than commander's default (help + exit 1). Flags
12772
+ // like -h/--help/-v have argv beyond the binary and fall through to
12773
+ // commander, which already exits 0 for them.
12774
+ if (process.argv.length <= 2) {
12775
+ program.outputHelp();
12776
+ process.exit(0);
12777
+ }
12755
12778
  await program.parseAsync();
12756
12779
  }
12757
12780
  // Run CLI directly when this file is the entry point — covers `node dist/cli.js`,
@@ -116,6 +116,19 @@ export async function checkVersion(installed, injected = {}) {
116
116
  }
117
117
  return { installed, latest: null, source: "unavailable" };
118
118
  }
119
+ /**
120
+ * Primes the version-check cache with an already-known `latest` — e.g. right
121
+ * after `flair upgrade` fetches the true latest fresh via its own direct
122
+ * registry call, so the NEXT `checkVersion` (from `flair status`/`doctor`)
123
+ * reflects it immediately instead of serving a stale cached value for up to
124
+ * `DEFAULT_TTL_MS`. Reuses `writeCacheFile`, which is already best-effort/
125
+ * never-throws — a failed cache write must never surface as a command error.
126
+ */
127
+ export function primeVersionCheckCache(latest, injected = {}) {
128
+ const cachePath = injected.cachePath ?? DEFAULT_CACHE_PATH;
129
+ const now = injected.now ?? (() => Date.now());
130
+ writeCacheFile(cachePath, { latest, checkedAt: now() });
131
+ }
119
132
  const NO_GAP = { severity: "none", majorBehind: false, releasesBehind: 0 };
120
133
  /**
121
134
  * Classify how far `installed` is behind `latest` using major.minor.patch
@@ -14,7 +14,7 @@
14
14
  * ROOTPATH, or a --target-switched remote), and a mismatch cached for one
15
15
  * must never bleed into a nudge about a different one.
16
16
  */
17
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
17
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
18
18
  import { createHash } from "node:crypto";
19
19
  import { dirname, join } from "node:path";
20
20
  import { homedir } from "node:os";
@@ -110,6 +110,25 @@ export async function checkServerHandshake(cliVersion, rootPath, serverUrl, inje
110
110
  }
111
111
  return { cliVersion, runningVersion: null, mismatch: false, source: "unavailable" };
112
112
  }
113
+ /**
114
+ * Deletes the cached running-version entry for a given (rootPath, serverUrl)
115
+ * pair — e.g. after `flair restart`/`flair upgrade` bounces the server, so
116
+ * the NEXT `checkServerHandshake` call re-fetches the live version instead
117
+ * of returning the pre-restart one for up to `DEFAULT_HANDSHAKE_TTL_MS`.
118
+ * Best-effort, like the rest of this module: a failed cache delete (missing
119
+ * file, permissions, read-only $HOME) must never surface as an error.
120
+ */
121
+ export function invalidateHandshakeCache(rootPath, serverUrl, injected = {}) {
122
+ const cacheDir = injected.cacheDir ?? DEFAULT_HANDSHAKE_CACHE_DIR;
123
+ try {
124
+ const path = cacheFilePath(cacheDir, rootPath, serverUrl);
125
+ if (existsSync(path))
126
+ rmSync(path);
127
+ }
128
+ catch {
129
+ // Best-effort — a failed cache delete must never surface as an error.
130
+ }
131
+ }
113
132
  /**
114
133
  * The one-line stderr nudge, or null when there's nothing worth printing
115
134
  * (no mismatch, or nothing to compare against). Exact wording per the spec:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tpsdev-ai/flair",
3
- "version": "0.25.1",
3
+ "version": "0.25.3",
4
4
  "packageManager": "bun@1.3.10",
5
5
  "description": "Identity, memory, and soul for AI agents. Cryptographic identity (Ed25519), semantic memory with local embeddings, and persistent personality — all in a single process.",
6
6
  "type": "module",