@tpsdev-ai/flair 0.44.0 → 0.44.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.
- package/dist/cli.js +85 -58
- package/dist/lib/mcp-spec.js +16 -2
- package/docs/upgrade.md +2 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -20,7 +20,7 @@ import { probeInstance } from "./probe.js";
|
|
|
20
20
|
import { sweepFleet, renderFleetSweepTable, FLEET_EXIT_OK, } from "./fleet-verify.js";
|
|
21
21
|
import { markStale, sortOldestVersionFirst } from "./fleet-presence.js";
|
|
22
22
|
import { detectClients, renderWiringSummary, wireClaudeCode, wireCodex, wireGemini, wireCursor, clientConfigPath, codexConfigHasFlairSection } from "./install/clients.js";
|
|
23
|
-
import { flairCliVersion, mcpServerSpec, unpinnedSpecWarning } from "./lib/mcp-spec.js";
|
|
23
|
+
import { flairCliVersion, clearFlairCliVersionCache, mcpServerSpec, unpinnedSpecWarning } from "./lib/mcp-spec.js";
|
|
24
24
|
import { resolveAgentKeyPath, loadEd25519PrivateKeyFromFile, signClientAssertion, buildTokenRequestForm, getMcpAccessToken, McpTokenRequestError, defaultMcpClientId, defaultMcpTokenEndpoint, defaultMcpResource, defaultMcpIssuer, MAX_ASSERTION_LIFETIME_SECONDS, } from "./mcp-client-assertion.js";
|
|
25
25
|
import { enableMcp, disableMcp, mcpStatus, checkLocalOriginRefusal, selfVerifyMcpMetadata, } from "./lib/mcp-enable.js";
|
|
26
26
|
import { readClientMcpBlock, checkClaudeMdBootstrap, inspectSessionStartHook, upgradeSessionStartHookCommand, fixClaudeMdBootstrap, fixSessionStartHook, applyOrReportClaudeMdBootstrap, applyOrReportSessionStartHook, resolveWireFlairUrl, planAgentIterations, inferSoleAgentId, fixCommandAgentHint, describeAgentGateFinding, embeddingsSkipRemedy, classifyKeyFile, resolveCollisionSafeName, pruneDateStamp, PRUNED_DIR_NAME, } from "./doctor-client.js";
|
|
@@ -2318,6 +2318,25 @@ export function shouldPrintUpgradeLine(status, showAll) {
|
|
|
2318
2318
|
return false;
|
|
2319
2319
|
return true;
|
|
2320
2320
|
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Returns the human-readable suffix for a package status line in
|
|
2323
|
+
* `flair upgrade` / `flair upgrade --check` output.
|
|
2324
|
+
*
|
|
2325
|
+
* flair-mcp is zero-install via npx — its suffix must never suggest a
|
|
2326
|
+
* global install (flair#1168).
|
|
2327
|
+
*/
|
|
2328
|
+
export function upgradeStatusSuffix(name, status) {
|
|
2329
|
+
if (status === "current")
|
|
2330
|
+
return " (current)";
|
|
2331
|
+
if (status === "missing") {
|
|
2332
|
+
return name === "@tpsdev-ai/flair-mcp"
|
|
2333
|
+
? " (zero-install via npx — run: flair doctor --fix)"
|
|
2334
|
+
: " (run: npm install -g)";
|
|
2335
|
+
}
|
|
2336
|
+
if (status === "optional")
|
|
2337
|
+
return " (install via: openclaw plugins install @tpsdev-ai/openclaw-flair)";
|
|
2338
|
+
return "";
|
|
2339
|
+
}
|
|
2321
2340
|
/**
|
|
2322
2341
|
* Pure flag resolution for `flair upgrade`'s restart/verify defaults
|
|
2323
2342
|
* (flair#635 decision: restart is now the default; `--no-restart` opts
|
|
@@ -9451,10 +9470,7 @@ program
|
|
|
9451
9470
|
: status === "optional" ? "○"
|
|
9452
9471
|
: "❔";
|
|
9453
9472
|
const installedLabel = installed ?? (status === "optional" ? "not installed (openclaw not detected)" : "not detected");
|
|
9454
|
-
const suffix = status
|
|
9455
|
-
: status === "missing" ? " (run: npm install -g)"
|
|
9456
|
-
: status === "optional" ? " (install via: openclaw plugins install @tpsdev-ai/openclaw-flair)"
|
|
9457
|
-
: "";
|
|
9473
|
+
const suffix = upgradeStatusSuffix(name, status);
|
|
9458
9474
|
console.log(` ${icon} ${name}: ${installedLabel} → ${latest}${suffix}`);
|
|
9459
9475
|
}
|
|
9460
9476
|
catch { /* skip unavailable packages */ }
|
|
@@ -9480,8 +9496,15 @@ program
|
|
|
9480
9496
|
return;
|
|
9481
9497
|
}
|
|
9482
9498
|
if (missing.length > 0 && outdated.length === 0) {
|
|
9499
|
+
const npmMissing = missing.filter((f) => f.name !== "@tpsdev-ai/flair-mcp");
|
|
9500
|
+
const mcpMissing = missing.filter((f) => f.name === "@tpsdev-ai/flair-mcp");
|
|
9483
9501
|
console.log(`\n❔ ${missing.length} package${missing.length > 1 ? "s" : ""} not detected — all detected packages are up to date.`);
|
|
9484
|
-
|
|
9502
|
+
if (npmMissing.length > 0) {
|
|
9503
|
+
console.log(` Install missing: npm install -g ${npmMissing.map((f) => f.name).join(" ")}`);
|
|
9504
|
+
}
|
|
9505
|
+
if (mcpMissing.length > 0) {
|
|
9506
|
+
console.log(` flair-mcp is zero-install via npx — run: flair doctor --fix to re-wire the hook`);
|
|
9507
|
+
}
|
|
9485
9508
|
return;
|
|
9486
9509
|
}
|
|
9487
9510
|
if (checkOnly) {
|
|
@@ -9690,6 +9713,61 @@ program
|
|
|
9690
9713
|
console.error(` ❌ ${pkg} upgrade failed: ${err.message}`);
|
|
9691
9714
|
}
|
|
9692
9715
|
}
|
|
9716
|
+
// flair#1167: `npm install -g` replaced package.json in-place, so the
|
|
9717
|
+
// module-load-cached CLI version is stale. Clear it so mcpServerSpec()
|
|
9718
|
+
// resolves the NEW version for the pin refresh below.
|
|
9719
|
+
clearFlairCliVersionCache();
|
|
9720
|
+
// ── Refresh wired MCP client configs (flair#1135, flair#1167) ──────────
|
|
9721
|
+
// After a successful package install, the flair-mcp package on disk is
|
|
9722
|
+
// newer than the pinned version in wired client configs. Re-run wiring for
|
|
9723
|
+
// already-wired clients so the pin stays in lockstep with the installed
|
|
9724
|
+
// version. Runs BEFORE the restart so --no-restart and --no-verify paths
|
|
9725
|
+
// also get the refresh (flair#1167). Best-effort: failures warn but never
|
|
9726
|
+
// fail the upgrade.
|
|
9727
|
+
await (async () => {
|
|
9728
|
+
const agentId = resolveAgentIdOrEnv({}) ?? (() => {
|
|
9729
|
+
try {
|
|
9730
|
+
const keyFiles = readdirSync(defaultKeysDir()).filter((f) => f.endsWith(".key"));
|
|
9731
|
+
return keyFiles.length > 0 ? keyFiles[0].replace(/\.key$/, "") : null;
|
|
9732
|
+
}
|
|
9733
|
+
catch {
|
|
9734
|
+
return null;
|
|
9735
|
+
}
|
|
9736
|
+
})();
|
|
9737
|
+
if (!agentId) {
|
|
9738
|
+
console.log("\n (no agent id known — skip MCP client pin refresh; run `flair init` to refresh manually)");
|
|
9739
|
+
return;
|
|
9740
|
+
}
|
|
9741
|
+
const httpUrl = `http://127.0.0.1:${upgradePort}`;
|
|
9742
|
+
const mcpEnv = { FLAIR_AGENT_ID: agentId, FLAIR_URL: httpUrl };
|
|
9743
|
+
const detected = detectClients().filter(c => c.detected);
|
|
9744
|
+
if (detected.length === 0)
|
|
9745
|
+
return;
|
|
9746
|
+
console.log("\n Refreshing MCP client pins...");
|
|
9747
|
+
for (const client of detected) {
|
|
9748
|
+
const configPath = clientConfigPath(client.id);
|
|
9749
|
+
if (!existsSync(configPath))
|
|
9750
|
+
continue;
|
|
9751
|
+
// Only refresh clients that are already wired — don't wire new ones.
|
|
9752
|
+
let hasFlair = false;
|
|
9753
|
+
try {
|
|
9754
|
+
const raw = readFileSync(configPath, "utf-8");
|
|
9755
|
+
if (client.id === "codex") {
|
|
9756
|
+
hasFlair = codexConfigHasFlairSection(raw);
|
|
9757
|
+
}
|
|
9758
|
+
else {
|
|
9759
|
+
const cfg = JSON.parse(raw);
|
|
9760
|
+
hasFlair = !!cfg.mcpServers?.flair;
|
|
9761
|
+
}
|
|
9762
|
+
}
|
|
9763
|
+
catch { /* unreadable/malformed — skip */ }
|
|
9764
|
+
if (!hasFlair)
|
|
9765
|
+
continue;
|
|
9766
|
+
const env = { ...mcpEnv, FLAIR_CLIENT: client.id };
|
|
9767
|
+
const result = client.wire(env);
|
|
9768
|
+
console.log(` ${result.ok ? "✓" : "•"} ${result.message}`);
|
|
9769
|
+
}
|
|
9770
|
+
})();
|
|
9693
9771
|
// ── Restart + verify + rollback (flair#635) ─────────────────────────────
|
|
9694
9772
|
// Decision (2026-07-08): restart is now the default post-upgrade step —
|
|
9695
9773
|
// installing new code without restarting leaves the OLD process serving
|
|
@@ -9908,55 +9986,6 @@ program
|
|
|
9908
9986
|
authedGet: (path) => verifyAuthedGet(baseUrl, path, defaultKeysDir()),
|
|
9909
9987
|
});
|
|
9910
9988
|
const verdict = decideAfterVerify(verify, previousFlairVersion);
|
|
9911
|
-
// ── Refresh wired MCP client configs (flair#1135) ──────────────────────
|
|
9912
|
-
// After a successful upgrade, the flair-mcp package on disk is newer than
|
|
9913
|
-
// the pinned version in wired client configs. Re-run wiring for
|
|
9914
|
-
// already-wired clients so the pin stays in lockstep with the installed
|
|
9915
|
-
// version. Best-effort: failures warn but never fail the upgrade.
|
|
9916
|
-
const refreshWiredClients = async () => {
|
|
9917
|
-
const agentId = resolveAgentIdOrEnv({}) ?? (() => {
|
|
9918
|
-
try {
|
|
9919
|
-
const keyFiles = readdirSync(defaultKeysDir()).filter((f) => f.endsWith(".key"));
|
|
9920
|
-
return keyFiles.length > 0 ? keyFiles[0].replace(/\.key$/, "") : null;
|
|
9921
|
-
}
|
|
9922
|
-
catch {
|
|
9923
|
-
return null;
|
|
9924
|
-
}
|
|
9925
|
-
})();
|
|
9926
|
-
if (!agentId) {
|
|
9927
|
-
console.log("\n (no agent id known — skip MCP client pin refresh; run `flair init` to refresh manually)");
|
|
9928
|
-
return;
|
|
9929
|
-
}
|
|
9930
|
-
const httpUrl = `http://127.0.0.1:${upgradePort}`;
|
|
9931
|
-
const mcpEnv = { FLAIR_AGENT_ID: agentId, FLAIR_URL: httpUrl };
|
|
9932
|
-
const detected = detectClients().filter(c => c.detected);
|
|
9933
|
-
if (detected.length === 0)
|
|
9934
|
-
return;
|
|
9935
|
-
console.log("\n Refreshing MCP client pins...");
|
|
9936
|
-
for (const client of detected) {
|
|
9937
|
-
const configPath = clientConfigPath(client.id);
|
|
9938
|
-
if (!existsSync(configPath))
|
|
9939
|
-
continue;
|
|
9940
|
-
// Only refresh clients that are already wired — don't wire new ones.
|
|
9941
|
-
let hasFlair = false;
|
|
9942
|
-
try {
|
|
9943
|
-
const raw = readFileSync(configPath, "utf-8");
|
|
9944
|
-
if (client.id === "codex") {
|
|
9945
|
-
hasFlair = codexConfigHasFlairSection(raw);
|
|
9946
|
-
}
|
|
9947
|
-
else {
|
|
9948
|
-
const cfg = JSON.parse(raw);
|
|
9949
|
-
hasFlair = !!cfg.mcpServers?.flair;
|
|
9950
|
-
}
|
|
9951
|
-
}
|
|
9952
|
-
catch { /* unreadable/malformed — skip */ }
|
|
9953
|
-
if (!hasFlair)
|
|
9954
|
-
continue;
|
|
9955
|
-
const env = { ...mcpEnv, FLAIR_CLIENT: client.id };
|
|
9956
|
-
const result = client.wire(env);
|
|
9957
|
-
console.log(` ${result.ok ? "✓" : "•"} ${result.message}`);
|
|
9958
|
-
}
|
|
9959
|
-
};
|
|
9960
9989
|
if (verdict.kind === "ok") {
|
|
9961
9990
|
// flair#1022: the verified facts are unchanged and still stated — the
|
|
9962
9991
|
// upgrade did land. What changes is the MARKER and the claim around it.
|
|
@@ -9972,7 +10001,6 @@ program
|
|
|
9972
10001
|
else
|
|
9973
10002
|
console.log(line);
|
|
9974
10003
|
}
|
|
9975
|
-
await refreshWiredClients();
|
|
9976
10004
|
return;
|
|
9977
10005
|
}
|
|
9978
10006
|
// flair#741 follow-through: a healthy instance the verifier just couldn't
|
|
@@ -9999,7 +10027,6 @@ program
|
|
|
9999
10027
|
console.error(line);
|
|
10000
10028
|
}
|
|
10001
10029
|
}
|
|
10002
|
-
await refreshWiredClients();
|
|
10003
10030
|
return;
|
|
10004
10031
|
}
|
|
10005
10032
|
console.error(`❌ post-restart verification failed: ${verdict.reason}`);
|
|
@@ -12130,7 +12157,7 @@ program
|
|
|
12130
12157
|
console.log(` ${render.icons.warn} SessionStart hook: wired in ${render.wrap(render.c.dim, hook.path)}, but its command did not run just now`);
|
|
12131
12158
|
console.log(` ${render.wrap(render.c.dim, hook.detail ?? "")}`);
|
|
12132
12159
|
console.log(` ${render.wrap(render.c.dim, "The hook command could not be executed. Check that npx can resolve")}`);
|
|
12133
|
-
console.log(` ${render.wrap(render.c.dim, "@tpsdev-ai/flair-mcp — a cold cache
|
|
12160
|
+
console.log(` ${render.wrap(render.c.dim, "@tpsdev-ai/flair-mcp — a cold npx cache or network issue")}`);
|
|
12134
12161
|
console.log(` ${render.wrap(render.c.dim, "issue can prevent the adapter from running on its first invocation.")}`);
|
|
12135
12162
|
console.log(` ${render.wrap(render.c.dim, "Fix:")} flair doctor --fix ${render.wrap(render.c.dim, "(rewrites the hook to the current silent-failure form)")}`);
|
|
12136
12163
|
}
|
package/dist/lib/mcp-spec.js
CHANGED
|
@@ -55,8 +55,14 @@ export function resolveFlairCliVersion(startDir) {
|
|
|
55
55
|
let cachedVersion;
|
|
56
56
|
/**
|
|
57
57
|
* This CLI's own version — the single source for `--version`, the CLI↔server
|
|
58
|
-
* handshake, `upgrade --check`, and the MCP pin. Cached: the answer
|
|
59
|
-
* change within a process, and several commands ask repeatedly.
|
|
58
|
+
* handshake, `upgrade --check`, and the MCP pin. Cached: the answer normally
|
|
59
|
+
* cannot change within a process, and several commands ask repeatedly.
|
|
60
|
+
*
|
|
61
|
+
* The one exception is `flair upgrade`: `npm install -g` replaces package.json
|
|
62
|
+
* in-place while the process is still running, so the cached version becomes
|
|
63
|
+
* stale. Callers that run after an in-process upgrade must call
|
|
64
|
+
* {@link clearFlairCliVersionCache} first so the next read resolves the new
|
|
65
|
+
* version from disk (flair#1167).
|
|
60
66
|
*/
|
|
61
67
|
export function flairCliVersion() {
|
|
62
68
|
if (cachedVersion === undefined) {
|
|
@@ -64,6 +70,14 @@ export function flairCliVersion() {
|
|
|
64
70
|
}
|
|
65
71
|
return cachedVersion;
|
|
66
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Clear the cached CLI version so the next call to {@link flairCliVersion}
|
|
75
|
+
* re-resolves from the package.json on disk. Needed after an in-process
|
|
76
|
+
* `npm install -g` replaces the package (flair#1167).
|
|
77
|
+
*/
|
|
78
|
+
export function clearFlairCliVersionCache() {
|
|
79
|
+
cachedVersion = undefined;
|
|
80
|
+
}
|
|
67
81
|
/** True when `version` is usable as a pin. */
|
|
68
82
|
export function isResolvedVersion(version) {
|
|
69
83
|
return !!version && version !== UNKNOWN_VERSION;
|
package/docs/upgrade.md
CHANGED
|
@@ -177,7 +177,8 @@ If you'd rather upgrade by hand instead of `flair upgrade`:
|
|
|
177
177
|
|
|
178
178
|
```bash
|
|
179
179
|
npm install -g @tpsdev-ai/flair@latest
|
|
180
|
-
|
|
180
|
+
# flair-mcp is zero-install via npx — no global install needed.
|
|
181
|
+
# flair doctor --fix rewires the hook to the current npx form.
|
|
181
182
|
flair restart
|
|
182
183
|
```
|
|
183
184
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tpsdev-ai/flair",
|
|
3
|
-
"version": "0.44.
|
|
3
|
+
"version": "0.44.2",
|
|
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",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"node": ">=22"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@harperfast/oauth": "2.
|
|
64
|
+
"@harperfast/oauth": "2.5.0",
|
|
65
65
|
"@types/js-yaml": "4.0.9",
|
|
66
66
|
"commander": "14.0.3",
|
|
67
67
|
"harper": "5.2.0",
|