@tpsdev-ai/flair 0.48.0 → 0.50.0
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 +2 -0
- package/dist/bridges/runtime/roundtrip.js +91 -2
- package/dist/build-info.json +3 -3
- package/dist/cli.js +903 -226
- package/dist/component-env.js +52 -4
- package/dist/deploy.js +20 -3
- package/dist/doctor-client.js +105 -32
- package/dist/federation/scheduler.js +24 -3
- package/dist/hook-install.js +96 -16
- package/dist/install/clients.js +318 -9
- package/dist/lib/auth-resolve.js +34 -3
- package/dist/lib/mcp-enable.js +134 -26
- package/dist/lib/scheduler-platform.js +132 -10
- package/dist/lib/scratch-owner.js +49 -0
- package/dist/rem/scheduler.js +23 -5
- package/dist/resources/AgentSeed.js +2 -0
- package/dist/resources/Memory.js +24 -5
- package/dist/resources/MemoryBootstrap.js +8 -4
- package/dist/resources/MemoryFeed.js +3 -0
- package/dist/resources/MemoryMaintenance.js +11 -2
- package/dist/resources/bm25-index-service.js +257 -0
- package/dist/resources/bm25-index.js +631 -0
- package/dist/resources/bm25.js +31 -1
- package/dist/resources/embeddings-boot.js +45 -3
- package/dist/resources/health.js +52 -7
- package/dist/resources/mcp-tools.js +1 -0
- package/dist/resources/memory-read-scope.js +2 -0
- package/dist/resources/search-readiness.js +100 -0
- package/dist/resources/semantic-retrieval-core.js +102 -23
- package/dist/resources/sort-comparators.js +45 -0
- package/dist/src/lib/scheduler-platform.js +132 -10
- package/dist/src/rem/scheduler.js +23 -5
- package/dist/version-check.js +59 -13
- package/docs/auth.md +5 -0
- package/docs/claude-code.md +10 -3
- package/docs/deepseek-harness.md +1 -1
- package/docs/deployment.md +11 -1
- package/docs/hosted-on-fabric.md +2 -0
- package/docs/integrations.md +78 -5
- package/docs/mcp-clients.md +85 -15
- package/docs/notes/mcp-oauth-model2.md +31 -13
- package/docs/quickstart-fabric.md +1 -1
- package/docs/quickstart.md +9 -9
- package/docs/standalone-local.md +3 -0
- package/docs/troubleshooting.md +25 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -213,6 +213,8 @@ Then add to your `CLAUDE.md`:
|
|
|
213
213
|
|
|
214
214
|
At the start of every session, run mcp__flair__bootstrap before responding.
|
|
215
215
|
|
|
216
|
+
(`mcp__flair__bootstrap` is Claude Code's namespaced name for the server's `bootstrap` tool.) Use `flair bootstrap --agent <id>` when MCP is not wired — previewing context, scripts, or any agent that can run a shell command.
|
|
217
|
+
|
|
216
218
|
The `flair-mcp` server exposes `memory_store`, `memory_search`, `memory_update`, `memory_get`, `memory_delete`, `relationship_store`, `bootstrap`, `soul_set`, `soul_get`, `flair_workspace_set` and `flair_orgevent`. Memory follows the agent across CLIs — same instance, same identity, switch harness without losing state.
|
|
217
219
|
|
|
218
220
|
Per-CLI config snippets (Gemini CLI's `~/.gemini/settings.json`, Codex CLI's `~/.codex/config.toml`) are in **[docs/mcp-clients.md](docs/mcp-clients.md)**; a deeper Claude Code walk-through is in [docs/claude-code.md](docs/claude-code.md).
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Implementation note: does NOT talk to Flair. Fixture-to-fixture only.
|
|
17
17
|
* Lives here so slice-3c code plugins can reuse the same harness.
|
|
18
18
|
*/
|
|
19
|
-
import { promises as fsp } from "node:fs";
|
|
19
|
+
import { promises as fsp, readdirSync, rmSync, statSync } from "node:fs";
|
|
20
20
|
import { join, isAbsolute } from "node:path";
|
|
21
21
|
import { tmpdir } from "node:os";
|
|
22
22
|
import { randomUUID } from "node:crypto";
|
|
@@ -25,6 +25,74 @@ import { parseRecords } from "./formats.js";
|
|
|
25
25
|
import { applyMap } from "./mapper.js";
|
|
26
26
|
import { evaluatePredicate } from "./predicate.js";
|
|
27
27
|
import { writeRecords } from "./writers.js";
|
|
28
|
+
import { hasScratchOwnerStamp, scratchOwnerIsLive, writeScratchOwnerStamp, } from "../../lib/scratch-owner.js";
|
|
29
|
+
/** mkdtemp prefix for this harness. Leaked trees of this name filled a host
|
|
30
|
+
* to zero bytes (flair#1032) — 7,188 leftovers, mostly `…-test-bridge-*`. */
|
|
31
|
+
export const BRIDGE_TEST_DIR_PREFIX = "flair-bridge-test-";
|
|
32
|
+
/** Grace for *unstamped* leftovers only (stamp not written yet, or a tree
|
|
33
|
+
* from before the owner file existed). Stamped trees use pid liveness. */
|
|
34
|
+
export const STALE_BRIDGE_TEST_DIR_MS = 60_000;
|
|
35
|
+
const IN_FLIGHT_BRIDGE_TEST_DIRS = new Set();
|
|
36
|
+
let bridgeTestExitHookInstalled = false;
|
|
37
|
+
function installBridgeTestExitHook() {
|
|
38
|
+
if (bridgeTestExitHookInstalled)
|
|
39
|
+
return;
|
|
40
|
+
bridgeTestExitHookInstalled = true;
|
|
41
|
+
// Exit only — no signal handlers. The integration suite SIGTERMs the
|
|
42
|
+
// runner as a fixture (federation-watch); a handler here would truncate it.
|
|
43
|
+
process.on("exit", () => {
|
|
44
|
+
for (const dir of IN_FLIGHT_BRIDGE_TEST_DIRS) {
|
|
45
|
+
try {
|
|
46
|
+
rmSync(dir, { recursive: true, force: true });
|
|
47
|
+
}
|
|
48
|
+
catch { /* best effort */ }
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Remove leftover `flair-bridge-test-*` trees from earlier interrupted runs.
|
|
54
|
+
*
|
|
55
|
+
* A process-exit hook cannot cover SIGKILL or a hard crash, so the next
|
|
56
|
+
* harness start has to sweep what the last one left. Skips in-flight trees
|
|
57
|
+
* in this process and any tree whose owner pid is still alive. Directory
|
|
58
|
+
* mtime is not a liveness signal (Linux does not update it when files
|
|
59
|
+
* inside subdirs are appended) — it is only a race guard for unstamped dirs.
|
|
60
|
+
*
|
|
61
|
+
* @returns number of trees removed
|
|
62
|
+
*/
|
|
63
|
+
export function sweepStaleBridgeTestDirs(opts) {
|
|
64
|
+
const root = opts?.root ?? tmpdir();
|
|
65
|
+
const olderThanMs = opts?.olderThanMs ?? STALE_BRIDGE_TEST_DIR_MS;
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
let names;
|
|
68
|
+
try {
|
|
69
|
+
names = readdirSync(root);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
let removed = 0;
|
|
75
|
+
for (const name of names) {
|
|
76
|
+
if (!name.startsWith(BRIDGE_TEST_DIR_PREFIX))
|
|
77
|
+
continue;
|
|
78
|
+
const dir = join(root, name);
|
|
79
|
+
if (IN_FLIGHT_BRIDGE_TEST_DIRS.has(dir))
|
|
80
|
+
continue;
|
|
81
|
+
if (scratchOwnerIsLive(dir))
|
|
82
|
+
continue;
|
|
83
|
+
try {
|
|
84
|
+
if (!hasScratchOwnerStamp(dir)) {
|
|
85
|
+
const st = statSync(dir);
|
|
86
|
+
if (now - st.mtimeMs < olderThanMs)
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
rmSync(dir, { recursive: true, force: true });
|
|
90
|
+
removed++;
|
|
91
|
+
}
|
|
92
|
+
catch { /* gone, or not ours to remove */ }
|
|
93
|
+
}
|
|
94
|
+
return removed;
|
|
95
|
+
}
|
|
28
96
|
/** Fields the spec (§8) requires to survive round-trip. */
|
|
29
97
|
export const ROUND_TRIP_STABLE_FIELDS = ["content", "subject", "tags", "durability"];
|
|
30
98
|
export async function runRoundTrip(opts) {
|
|
@@ -52,8 +120,29 @@ export async function runRoundTrip(opts) {
|
|
|
52
120
|
const importSource = descriptor.import.sources[0];
|
|
53
121
|
const exportTarget = descriptor.export.targets[0];
|
|
54
122
|
const resolvedFixture = resolvePath(cwd, opts.fixturePath ?? importSource.path);
|
|
55
|
-
|
|
123
|
+
// Sweep leftovers from interrupted runs *before* creating ours so a crash
|
|
124
|
+
// mid-call is all the next start has to find. In-flight trees in this
|
|
125
|
+
// process are skipped inside the sweep.
|
|
126
|
+
sweepStaleBridgeTestDirs();
|
|
127
|
+
const tmpDir = await fsp.mkdtemp(join(tmpdir(), `${BRIDGE_TEST_DIR_PREFIX}${descriptor.name}-`));
|
|
128
|
+
writeScratchOwnerStamp(tmpDir);
|
|
56
129
|
const tmpPath = join(tmpDir, `roundtrip.${suffixForFormat(exportTarget.format)}`);
|
|
130
|
+
IN_FLIGHT_BRIDGE_TEST_DIRS.add(tmpDir);
|
|
131
|
+
installBridgeTestExitHook();
|
|
132
|
+
try {
|
|
133
|
+
return await runRoundTripAgainst(descriptor, resolvedFixture, importSource, exportTarget, tmpPath);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
IN_FLIGHT_BRIDGE_TEST_DIRS.delete(tmpDir);
|
|
137
|
+
if (!opts.retainTmpDir) {
|
|
138
|
+
try {
|
|
139
|
+
await fsp.rm(tmpDir, { recursive: true, force: true });
|
|
140
|
+
}
|
|
141
|
+
catch { /* best effort */ }
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function runRoundTripAgainst(descriptor, resolvedFixture, importSource, exportTarget, tmpPath) {
|
|
57
146
|
// Pass 1: fixture → BridgeMemory[]
|
|
58
147
|
const pass1 = [];
|
|
59
148
|
for await (const { record } of parseRecords(descriptor.name, resolvedFixture, importSource.format)) {
|
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
3
|
-
"commit": "
|
|
4
|
-
"builtAt": "2026-08-
|
|
2
|
+
"version": "0.50.0",
|
|
3
|
+
"commit": "d643b7f8addb9fd033209fad1d405f7c935a7247",
|
|
4
|
+
"builtAt": "2026-08-25T23:24:38.875Z",
|
|
5
5
|
"builder": "tsc"
|
|
6
6
|
}
|