@bluefields/cli 0.2.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/LICENSE +661 -0
- package/README.md +181 -0
- package/dist/anchor.d.ts +24 -0
- package/dist/anchor.js +48 -0
- package/dist/anchor.js.map +1 -0
- package/dist/attestation.d.ts +50 -0
- package/dist/attestation.js +90 -0
- package/dist/attestation.js.map +1 -0
- package/dist/bluefield.d.ts +180 -0
- package/dist/bluefield.js +382 -0
- package/dist/bluefield.js.map +1 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +310 -0
- package/dist/cli.js.map +1 -0
- package/dist/constants.d.ts +28 -0
- package/dist/constants.js +30 -0
- package/dist/constants.js.map +1 -0
- package/dist/fs-storage.d.ts +20 -0
- package/dist/fs-storage.js +60 -0
- package/dist/fs-storage.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/keystore.d.ts +40 -0
- package/dist/keystore.js +77 -0
- package/dist/keystore.js.map +1 -0
- package/dist/mcp-server.d.ts +40 -0
- package/dist/mcp-server.js +252 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/paths.d.ts +52 -0
- package/dist/paths.js +77 -0
- package/dist/paths.js.map +1 -0
- package/dist/quiet.d.ts +11 -0
- package/dist/quiet.js +14 -0
- package/dist/quiet.js.map +1 -0
- package/dist/store.d.ts +46 -0
- package/dist/store.js +233 -0
- package/dist/store.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local MCP server (stdio, JSON-RPC 2.0, newline-delimited).
|
|
3
|
+
*
|
|
4
|
+
* Exposes the Bluefield local store as tools an agent can call natively:
|
|
5
|
+
* `scrape`, `log`, `diff`, `verify`, `export`, `identity`. Unlike
|
|
6
|
+
* `@bluefields/mcp-server` (a thin HTTP client to the hosted API), every tool
|
|
7
|
+
* here runs entirely LOCALLY against the on-disk store — no API key, no
|
|
8
|
+
* network beyond the fetch itself, no telemetry.
|
|
9
|
+
*
|
|
10
|
+
* The protocol surface we need (initialize, tools/list, tools/call) is small
|
|
11
|
+
* enough to implement directly, mirroring the pattern in `@bluefields/mcp-server`
|
|
12
|
+
* rather than taking an MCP-SDK dependency.
|
|
13
|
+
*/
|
|
14
|
+
import './quiet.js';
|
|
15
|
+
import { type Bluefield } from './bluefield.js';
|
|
16
|
+
interface ToolDef {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
inputSchema: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
export declare const TOOLS: ToolDef[];
|
|
22
|
+
interface JsonRpcRequest {
|
|
23
|
+
jsonrpc: '2.0';
|
|
24
|
+
id?: string | number | null;
|
|
25
|
+
method: string;
|
|
26
|
+
params?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
interface JsonRpcResponse {
|
|
29
|
+
jsonrpc: '2.0';
|
|
30
|
+
id: string | number | null;
|
|
31
|
+
result?: unknown;
|
|
32
|
+
error?: {
|
|
33
|
+
code: number;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export declare function handleRequest(msg: JsonRpcRequest, bf: Bluefield): Promise<JsonRpcResponse | null>;
|
|
38
|
+
/** Run the stdio JSON-RPC loop until stdin closes. */
|
|
39
|
+
export declare function runMcpServer(): Promise<void>;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Local MCP server (stdio, JSON-RPC 2.0, newline-delimited).
|
|
4
|
+
*
|
|
5
|
+
* Exposes the Bluefield local store as tools an agent can call natively:
|
|
6
|
+
* `scrape`, `log`, `diff`, `verify`, `export`, `identity`. Unlike
|
|
7
|
+
* `@bluefields/mcp-server` (a thin HTTP client to the hosted API), every tool
|
|
8
|
+
* here runs entirely LOCALLY against the on-disk store — no API key, no
|
|
9
|
+
* network beyond the fetch itself, no telemetry.
|
|
10
|
+
*
|
|
11
|
+
* The protocol surface we need (initialize, tools/list, tools/call) is small
|
|
12
|
+
* enough to implement directly, mirroring the pattern in `@bluefields/mcp-server`
|
|
13
|
+
* rather than taking an MCP-SDK dependency.
|
|
14
|
+
*/
|
|
15
|
+
import './quiet.js'; // MUST be first — silences engine logs before fetcher loads
|
|
16
|
+
import process from 'node:process';
|
|
17
|
+
import { openBluefield } from './bluefield.js';
|
|
18
|
+
import { PROJECT_NAME, STANDARD_FULL } from './constants.js';
|
|
19
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
20
|
+
const SERVER_INFO = { name: `${PROJECT_NAME.toLowerCase()}-local`, version: '0.1.0' };
|
|
21
|
+
export const TOOLS = [
|
|
22
|
+
{
|
|
23
|
+
name: 'scrape',
|
|
24
|
+
description: `Capture a URL into the local ${PROJECT_NAME} store: fetch, content-address on disk, and sign an offline-verifiable provenance manifest (${STANDARD_FULL}). Returns the snapshot id, content hash, and whether it changed since the last capture.`,
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['url'],
|
|
28
|
+
properties: {
|
|
29
|
+
url: { type: 'string', description: 'The URL to capture.' },
|
|
30
|
+
sign: { type: 'boolean', description: 'Sign the manifest (default true).' },
|
|
31
|
+
extract: {
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
description: 'Run structured extraction (needs ANTHROPIC_API_KEY).',
|
|
34
|
+
},
|
|
35
|
+
schema: { type: 'object', description: 'JSON schema for structured extraction.' },
|
|
36
|
+
intent: { type: 'string', description: 'One-sentence extraction hint.' },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'log',
|
|
42
|
+
description: 'List snapshot history, newest first — all snapshots or just one URL.',
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
url: { type: 'string', description: 'Filter to this URL (optional).' },
|
|
47
|
+
limit: { type: 'number', description: 'Max rows (default 50).' },
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'diff',
|
|
53
|
+
description: 'Diff two snapshots (by id-prefix or URL). With one URL and no `to`, diffs its two most recent snapshots. Set `structured` to diff extracted data instead of raw content.',
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: 'object',
|
|
56
|
+
required: ['from'],
|
|
57
|
+
properties: {
|
|
58
|
+
from: { type: 'string', description: 'Snapshot ref A (id-prefix or URL).' },
|
|
59
|
+
to: { type: 'string', description: 'Snapshot ref B (optional).' },
|
|
60
|
+
structured: { type: 'boolean', description: 'Diff structured data (JSON Patch).' },
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'verify',
|
|
66
|
+
description: "Verify a snapshot offline: recompute its content hash and check the Ed25519 signature against a trusted key. Returns whether it's authentic and untampered.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
required: ['ref'],
|
|
70
|
+
properties: {
|
|
71
|
+
ref: { type: 'string', description: 'Snapshot ref (id-prefix or URL).' },
|
|
72
|
+
trustEmbedded: { type: 'boolean', description: 'Trust the bundle-embedded key (TOFU).' },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'export',
|
|
78
|
+
description: 'Export a snapshot as raw content + a portable proof bundle (manifest + signature + public key) into a directory.',
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
required: ['ref'],
|
|
82
|
+
properties: {
|
|
83
|
+
ref: { type: 'string', description: 'Snapshot ref (id-prefix or URL).' },
|
|
84
|
+
out: { type: 'string', description: 'Destination directory (default cwd).' },
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'identity',
|
|
90
|
+
description: "Show this machine's public signing identity (keyId + public JWK). Safe to share.",
|
|
91
|
+
inputSchema: { type: 'object', properties: {} },
|
|
92
|
+
},
|
|
93
|
+
];
|
|
94
|
+
const asString = (v) => (typeof v === 'string' ? v : undefined);
|
|
95
|
+
const textResult = (v) => ({
|
|
96
|
+
content: [{ type: 'text', text: typeof v === 'string' ? v : JSON.stringify(v, null, 2) }],
|
|
97
|
+
});
|
|
98
|
+
/** Dispatch one tool call against the local library. */
|
|
99
|
+
async function callTool(bf, name, args) {
|
|
100
|
+
switch (name) {
|
|
101
|
+
case 'scrape': {
|
|
102
|
+
const url = asString(args.url);
|
|
103
|
+
if (!url)
|
|
104
|
+
throw new Error('scrape: `url` is required');
|
|
105
|
+
return textResult(await bf.scrape(url, {
|
|
106
|
+
sign: args.sign !== false,
|
|
107
|
+
extract: args.extract === true,
|
|
108
|
+
schema: args.schema ?? null,
|
|
109
|
+
intent: asString(args.intent) ?? null,
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
case 'log':
|
|
113
|
+
return textResult(await bf.log(asString(args.url) ?? null, {
|
|
114
|
+
limit: typeof args.limit === 'number' ? args.limit : 50,
|
|
115
|
+
}));
|
|
116
|
+
case 'diff': {
|
|
117
|
+
const from = asString(args.from);
|
|
118
|
+
if (!from)
|
|
119
|
+
throw new Error('diff: `from` is required');
|
|
120
|
+
return textResult(await bf.diff(from, asString(args.to), {
|
|
121
|
+
mode: args.structured === true ? 'structured' : 'content',
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
case 'verify': {
|
|
125
|
+
const ref = asString(args.ref);
|
|
126
|
+
if (!ref)
|
|
127
|
+
throw new Error('verify: `ref` is required');
|
|
128
|
+
return textResult(await bf.verify(ref, { trustEmbedded: args.trustEmbedded === true }));
|
|
129
|
+
}
|
|
130
|
+
case 'export': {
|
|
131
|
+
const ref = asString(args.ref);
|
|
132
|
+
if (!ref)
|
|
133
|
+
throw new Error('export: `ref` is required');
|
|
134
|
+
return textResult(await bf.export(ref, asString(args.out) ?? '.'));
|
|
135
|
+
}
|
|
136
|
+
case 'identity':
|
|
137
|
+
return textResult(bf.publicIdentity());
|
|
138
|
+
default:
|
|
139
|
+
throw new Error(`unknown tool: ${name}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export async function handleRequest(msg, bf) {
|
|
143
|
+
const id = msg.id ?? null;
|
|
144
|
+
switch (msg.method) {
|
|
145
|
+
case 'initialize':
|
|
146
|
+
return {
|
|
147
|
+
jsonrpc: '2.0',
|
|
148
|
+
id,
|
|
149
|
+
result: {
|
|
150
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
151
|
+
capabilities: { tools: {} },
|
|
152
|
+
serverInfo: SERVER_INFO,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
case 'notifications/initialized':
|
|
156
|
+
return null;
|
|
157
|
+
case 'ping':
|
|
158
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
159
|
+
case 'tools/list':
|
|
160
|
+
return { jsonrpc: '2.0', id, result: { tools: TOOLS } };
|
|
161
|
+
case 'tools/call': {
|
|
162
|
+
const name = asString(msg.params?.name) ?? '';
|
|
163
|
+
const raw = msg.params?.arguments;
|
|
164
|
+
const args = (raw && typeof raw === 'object' ? raw : {});
|
|
165
|
+
try {
|
|
166
|
+
return { jsonrpc: '2.0', id, result: await callTool(bf, name, args) };
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
// Tool errors are returned as an error result, not a protocol error,
|
|
170
|
+
// so the agent sees the message and can recover.
|
|
171
|
+
return {
|
|
172
|
+
jsonrpc: '2.0',
|
|
173
|
+
id,
|
|
174
|
+
result: {
|
|
175
|
+
isError: true,
|
|
176
|
+
content: [{ type: 'text', text: err instanceof Error ? err.message : String(err) }],
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
default:
|
|
182
|
+
return {
|
|
183
|
+
jsonrpc: '2.0',
|
|
184
|
+
id,
|
|
185
|
+
error: { code: -32601, message: `method not found: ${msg.method}` },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Run the stdio JSON-RPC loop until stdin closes. */
|
|
190
|
+
export async function runMcpServer() {
|
|
191
|
+
const bf = await openBluefield();
|
|
192
|
+
const write = (line) => process.stdout.write(line);
|
|
193
|
+
process.stdin.setEncoding('utf8');
|
|
194
|
+
await new Promise((resolve, reject) => {
|
|
195
|
+
let buffer = '';
|
|
196
|
+
let inFlight = 0;
|
|
197
|
+
let ended = false;
|
|
198
|
+
const settleIfDone = () => {
|
|
199
|
+
if (ended && inFlight === 0 && buffer.indexOf('\n') < 0)
|
|
200
|
+
resolve();
|
|
201
|
+
};
|
|
202
|
+
const dispatch = (msg) => {
|
|
203
|
+
inFlight++;
|
|
204
|
+
handleRequest(msg, bf)
|
|
205
|
+
.catch((err) => ({
|
|
206
|
+
jsonrpc: '2.0',
|
|
207
|
+
id: msg.id ?? null,
|
|
208
|
+
error: { code: -32603, message: err instanceof Error ? err.message : String(err) },
|
|
209
|
+
}))
|
|
210
|
+
.then((res) => {
|
|
211
|
+
if (res)
|
|
212
|
+
write(`${JSON.stringify(res)}\n`);
|
|
213
|
+
})
|
|
214
|
+
.catch(() => {
|
|
215
|
+
/* a write failure must not crash the server */
|
|
216
|
+
})
|
|
217
|
+
.finally(() => {
|
|
218
|
+
inFlight--;
|
|
219
|
+
settleIfDone();
|
|
220
|
+
});
|
|
221
|
+
};
|
|
222
|
+
const pump = () => {
|
|
223
|
+
for (;;) {
|
|
224
|
+
const nl = buffer.indexOf('\n');
|
|
225
|
+
if (nl < 0)
|
|
226
|
+
break;
|
|
227
|
+
const line = buffer.slice(0, nl).trim();
|
|
228
|
+
buffer = buffer.slice(nl + 1);
|
|
229
|
+
if (!line)
|
|
230
|
+
continue;
|
|
231
|
+
try {
|
|
232
|
+
dispatch(JSON.parse(line));
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
/* skip malformed frame */
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
settleIfDone();
|
|
239
|
+
};
|
|
240
|
+
process.stdin.on('data', (chunk) => {
|
|
241
|
+
buffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
|
|
242
|
+
pump();
|
|
243
|
+
});
|
|
244
|
+
process.stdin.on('end', () => {
|
|
245
|
+
ended = true;
|
|
246
|
+
pump();
|
|
247
|
+
});
|
|
248
|
+
process.stdin.on('error', reject);
|
|
249
|
+
});
|
|
250
|
+
await bf.close();
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store-location resolution — "where does this machine keep its snapshots?".
|
|
3
|
+
*
|
|
4
|
+
* Resolution order (git-like):
|
|
5
|
+
* 1. `$BF_HOME` if set → explicit override
|
|
6
|
+
* 2. nearest `.bf/` walking up from `cwd` → repo-local project store
|
|
7
|
+
* 3. `~/.bluefield/` → global default store
|
|
8
|
+
*
|
|
9
|
+
* The PRIVATE signing key is deliberately NOT stored inside the resolved
|
|
10
|
+
* store root: it always lives under `~/.bluefield/keys` (the user's global
|
|
11
|
+
* identity). That keeps a project-local `.bf/` safe to commit/share/inspect —
|
|
12
|
+
* it only ever holds public material (objects, manifests, public JWKs, db).
|
|
13
|
+
*/
|
|
14
|
+
/** Absolute path to the user's global home store (`~/.bluefield`). */
|
|
15
|
+
export declare function globalHome(): string;
|
|
16
|
+
/**
|
|
17
|
+
* The signing-keys directory: `~/.bluefield/keys` by default, relocatable via
|
|
18
|
+
* `BF_KEYS_DIR`. Kept deliberately separate from the (possibly project-local)
|
|
19
|
+
* store root so the private identity never lands inside a shareable `.bf`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function keysDir(env?: NodeJS.ProcessEnv): string;
|
|
22
|
+
/**
|
|
23
|
+
* Find the nearest `.bf/` directory walking up from `startDir`. Returns null
|
|
24
|
+
* if none is found before the filesystem root.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findLocalStore(startDir?: string): string | null;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the active store root. Pure (no filesystem writes) so callers can
|
|
29
|
+
* decide whether to create it.
|
|
30
|
+
*/
|
|
31
|
+
export declare function resolveStoreRoot(opts?: {
|
|
32
|
+
cwd?: string;
|
|
33
|
+
env?: NodeJS.ProcessEnv;
|
|
34
|
+
}): string;
|
|
35
|
+
/** The set of directories that make up a store. */
|
|
36
|
+
export interface StorePaths {
|
|
37
|
+
root: string;
|
|
38
|
+
/** Content-addressed raw bodies: `objects/<ab>/<sha256>`. */
|
|
39
|
+
objects: string;
|
|
40
|
+
/** SignedManifest sidecars keyed by snapshot id. */
|
|
41
|
+
manifests: string;
|
|
42
|
+
/** PGlite data directory. */
|
|
43
|
+
db: string;
|
|
44
|
+
/** Extra pinned public keys the user trusts for `verify` (`*.jwk`). */
|
|
45
|
+
trusted: string;
|
|
46
|
+
/** Optional JSON config (proxy/LLM overrides, store display name). */
|
|
47
|
+
config: string;
|
|
48
|
+
/** Global keys dir — always under `~/.bluefield/keys`, never inside `root`. */
|
|
49
|
+
keys: string;
|
|
50
|
+
}
|
|
51
|
+
/** Compute the sub-paths of a store root (pure). */
|
|
52
|
+
export declare function storePaths(root: string): StorePaths;
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Store-location resolution — "where does this machine keep its snapshots?".
|
|
4
|
+
*
|
|
5
|
+
* Resolution order (git-like):
|
|
6
|
+
* 1. `$BF_HOME` if set → explicit override
|
|
7
|
+
* 2. nearest `.bf/` walking up from `cwd` → repo-local project store
|
|
8
|
+
* 3. `~/.bluefield/` → global default store
|
|
9
|
+
*
|
|
10
|
+
* The PRIVATE signing key is deliberately NOT stored inside the resolved
|
|
11
|
+
* store root: it always lives under `~/.bluefield/keys` (the user's global
|
|
12
|
+
* identity). That keeps a project-local `.bf/` safe to commit/share/inspect —
|
|
13
|
+
* it only ever holds public material (objects, manifests, public JWKs, db).
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync } from 'node:fs';
|
|
16
|
+
import { homedir } from 'node:os';
|
|
17
|
+
import { dirname, join, resolve } from 'node:path';
|
|
18
|
+
import { HOME_DIR_NAME, HOME_ENV, LOCAL_DIR_NAME } from './constants.js';
|
|
19
|
+
/** Absolute path to the user's global home store (`~/.bluefield`). */
|
|
20
|
+
export function globalHome() {
|
|
21
|
+
return join(homedir(), HOME_DIR_NAME);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The signing-keys directory: `~/.bluefield/keys` by default, relocatable via
|
|
25
|
+
* `BF_KEYS_DIR`. Kept deliberately separate from the (possibly project-local)
|
|
26
|
+
* store root so the private identity never lands inside a shareable `.bf`.
|
|
27
|
+
*/
|
|
28
|
+
export function keysDir(env = process.env) {
|
|
29
|
+
const override = env.BF_KEYS_DIR;
|
|
30
|
+
if (override?.trim())
|
|
31
|
+
return resolve(override.trim());
|
|
32
|
+
return join(globalHome(), 'keys');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Find the nearest `.bf/` directory walking up from `startDir`. Returns null
|
|
36
|
+
* if none is found before the filesystem root.
|
|
37
|
+
*/
|
|
38
|
+
export function findLocalStore(startDir = process.cwd()) {
|
|
39
|
+
let dir = resolve(startDir);
|
|
40
|
+
// Walk to the filesystem root; dirname('/') === '/' terminates the loop.
|
|
41
|
+
for (;;) {
|
|
42
|
+
const candidate = join(dir, LOCAL_DIR_NAME);
|
|
43
|
+
if (existsSync(candidate))
|
|
44
|
+
return candidate;
|
|
45
|
+
const parent = dirname(dir);
|
|
46
|
+
if (parent === dir)
|
|
47
|
+
return null;
|
|
48
|
+
dir = parent;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the active store root. Pure (no filesystem writes) so callers can
|
|
53
|
+
* decide whether to create it.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveStoreRoot(opts = {}) {
|
|
56
|
+
const env = opts.env ?? process.env;
|
|
57
|
+
const override = env[HOME_ENV];
|
|
58
|
+
if (override?.trim())
|
|
59
|
+
return resolve(override.trim());
|
|
60
|
+
const local = findLocalStore(opts.cwd);
|
|
61
|
+
if (local)
|
|
62
|
+
return local;
|
|
63
|
+
return globalHome();
|
|
64
|
+
}
|
|
65
|
+
/** Compute the sub-paths of a store root (pure). */
|
|
66
|
+
export function storePaths(root) {
|
|
67
|
+
return {
|
|
68
|
+
root,
|
|
69
|
+
objects: join(root, 'objects'),
|
|
70
|
+
manifests: join(root, 'manifests'),
|
|
71
|
+
db: join(root, 'db'),
|
|
72
|
+
trusted: join(root, 'trusted'),
|
|
73
|
+
config: join(root, 'config.json'),
|
|
74
|
+
keys: keysDir(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEzE,sEAAsE;AACtE,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AACxC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC1D,MAAM,QAAQ,GAAG,GAAG,CAAC,WAAW,CAAC;IACjC,IAAI,QAAQ,EAAE,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB,OAAO,CAAC,GAAG,EAAE;IAC7D,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,yEAAyE;IACzE,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC5C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAkD,EAAE;IACnF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/B,IAAI,QAAQ,EAAE,IAAI,EAAE;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IACxB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAmBD,oDAAoD;AACpD,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO;QACL,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAC9B,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC;QAClC,EAAE,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;QACpB,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC;QAC9B,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;QACjC,IAAI,EAAE,OAAO,EAAE;KAChB,CAAC;AACJ,CAAC"}
|
package/dist/quiet.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect module: default the engine's structured logger to silent for the
|
|
3
|
+
* CLI so pino's JSON output never pollutes stdout — critical for `--json` and
|
|
4
|
+
* for the MCP stdio transport, where stray stdout frames corrupt the protocol.
|
|
5
|
+
*
|
|
6
|
+
* MUST be the first import in every executable entry point (`cli.ts`,
|
|
7
|
+
* `mcp-server.ts`) so it runs before `@bluefields/fetcher` builds its layer
|
|
8
|
+
* logger (which reads `LOG_LEVEL` once, at module load). Users can opt back in
|
|
9
|
+
* with `LOG_LEVEL=info` (or debug/trace) in the environment.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
package/dist/quiet.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
2
|
+
/**
|
|
3
|
+
* Side-effect module: default the engine's structured logger to silent for the
|
|
4
|
+
* CLI so pino's JSON output never pollutes stdout — critical for `--json` and
|
|
5
|
+
* for the MCP stdio transport, where stray stdout frames corrupt the protocol.
|
|
6
|
+
*
|
|
7
|
+
* MUST be the first import in every executable entry point (`cli.ts`,
|
|
8
|
+
* `mcp-server.ts`) so it runs before `@bluefields/fetcher` builds its layer
|
|
9
|
+
* logger (which reads `LOG_LEVEL` once, at module load). Users can opt back in
|
|
10
|
+
* with `LOG_LEVEL=info` (or debug/trace) in the environment.
|
|
11
|
+
*/
|
|
12
|
+
process.env.LOG_LEVEL ??= 'silent';
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=quiet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quiet.js","sourceRoot":"","sources":["../src/quiet.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C;;;;;;;;;GASG;AAEH,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The local metadata store — an embedded Postgres (PGlite, WASM, in-process)
|
|
3
|
+
* that satisfies the `DbClient` the engine injects. NO hosted Postgres, no
|
|
4
|
+
* network, no KMS. The full Drizzle schema is applied to a file-backed PGlite
|
|
5
|
+
* data directory under `<store>/db`, so snapshot history survives across CLI
|
|
6
|
+
* invocations and `log`/`diff`/`watch`/`export` can query it with real SQL.
|
|
7
|
+
*
|
|
8
|
+
* This reuses the QA real-DB harness pattern (statement-by-statement, tolerant
|
|
9
|
+
* apply): a handful of migrations use Neon/pg_cron/pg_partman features PGlite
|
|
10
|
+
* lacks; those statements skip harmlessly while the engine tables are created
|
|
11
|
+
* from plain DDL. Two extra local adaptations then run:
|
|
12
|
+
*
|
|
13
|
+
* 1. DEFAULT partitions — `snapshots` / `cost_records` / `events` /
|
|
14
|
+
* `audit_log` are declared `PARTITION BY RANGE`, and without pg_partman
|
|
15
|
+
* they have no child partitions, so INSERTs would fail. We attach a
|
|
16
|
+
* `<table>_default DEFAULT` partition to each so rows land locally.
|
|
17
|
+
* 2. A single seed `customers` row — `cost_records.customer_id` is a NOT-NULL
|
|
18
|
+
* FK to `customers`, and the engine writes a cost row per fetch. One fixed
|
|
19
|
+
* local customer keeps the engine's billing plumbing satisfied with zero
|
|
20
|
+
* behavioural change.
|
|
21
|
+
*/
|
|
22
|
+
import { type DbClient } from '@bluefields/db';
|
|
23
|
+
import { PGlite } from '@electric-sql/pglite';
|
|
24
|
+
/**
|
|
25
|
+
* Fixed local identity for the single-user store. `cost_records` and
|
|
26
|
+
* `snapshots` are attributed to this synthetic customer; it never leaves the
|
|
27
|
+
* machine and carries no billing meaning.
|
|
28
|
+
*/
|
|
29
|
+
export declare const LOCAL_CUSTOMER_ID: "00000000-0000-4000-8000-000000000001";
|
|
30
|
+
export declare const LOCAL_CUSTOMER_EMAIL: "local@bluefield.invalid";
|
|
31
|
+
export declare const LOCAL_SUBSCRIPTION_ID: null;
|
|
32
|
+
/** A live handle to the local store. */
|
|
33
|
+
export interface Store {
|
|
34
|
+
db: DbClient;
|
|
35
|
+
client: PGlite;
|
|
36
|
+
/** How many migration statements were skipped (Neon/pg_cron/partman-only). */
|
|
37
|
+
skipped: number;
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Open (or create) the file-backed local store at `dbDir` and return an
|
|
42
|
+
* engine-compatible `DbClient`. Idempotent: re-opening an existing store
|
|
43
|
+
* re-applies DDL tolerantly (`IF NOT EXISTS` / already-exists skips) and
|
|
44
|
+
* re-seeds via `ON CONFLICT DO NOTHING`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function openStore(dbDir: string): Promise<Store>;
|