@functional-systems/lambdadb-cli 0.1.5-dev.19 → 0.1.5-dev.20
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/CHANGELOG.md +14 -0
- package/CONTRIBUTING.md +27 -0
- package/README.md +210 -3
- package/dist/agent-config.d.ts +21 -0
- package/dist/agent-config.js +124 -0
- package/dist/agent-config.js.map +1 -0
- package/dist/agents.d.ts +113 -0
- package/dist/agents.js +196 -0
- package/dist/agents.js.map +1 -0
- package/dist/cli.js +47 -12
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/init.d.ts +31 -0
- package/dist/init.js +211 -0
- package/dist/init.js.map +1 -0
- package/dist/mcp.d.ts +4 -0
- package/dist/mcp.js +46 -0
- package/dist/mcp.js.map +1 -0
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +8 -0
- package/dist/runtime.js.map +1 -1
- package/package.json +6 -3
- package/skills/lambdadb/SKILL.md +35 -0
- package/src/agent-config.ts +112 -0
- package/src/agents.ts +212 -0
- package/src/cli.ts +42 -8
- package/src/config.ts +2 -2
- package/src/init.ts +185 -0
- package/src/mcp.ts +45 -0
- package/src/runtime.ts +9 -0
package/dist/init.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { lstat, mkdir, readFile, realpath, rename, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { basename, dirname, join } from 'node:path';
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { configPath, loadSettings, resolveConfig, saveSettings, settings } from './config.js';
|
|
7
|
+
import { InputError } from './errors.js';
|
|
8
|
+
import { checkConnection, runtime } from './runtime.js';
|
|
9
|
+
import { mcpPackage } from './mcp.js';
|
|
10
|
+
import { mcpLaunch } from './agent-config.js';
|
|
11
|
+
import { agentAdapters, agentNames, detectAgents } from './agents.js';
|
|
12
|
+
const version = JSON.parse(await readFile(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
13
|
+
function selectedAgents(value) {
|
|
14
|
+
if (value === 'none')
|
|
15
|
+
return [];
|
|
16
|
+
const values = value?.split(',').map(v => v.trim());
|
|
17
|
+
if (!values?.length || values.some(v => !agentAdapters.some(adapter => adapter.id === v))) {
|
|
18
|
+
throw new InputError(`Choose --agents ${agentNames} (comma-separated subset), or --agents none.`);
|
|
19
|
+
}
|
|
20
|
+
return [...new Set(values)];
|
|
21
|
+
}
|
|
22
|
+
function availableScopes(chosen) {
|
|
23
|
+
return ['project', 'user'].filter(scope => chosen.every(agent => {
|
|
24
|
+
const adapter = agentAdapters.find(adapter => adapter.id === agent);
|
|
25
|
+
return !adapter.scopes || adapter.scopes.includes(scope);
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
async function readOptional(path) {
|
|
29
|
+
try {
|
|
30
|
+
return await readFile(path, 'utf8');
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code === 'ENOENT')
|
|
34
|
+
return undefined;
|
|
35
|
+
throw new InputError(`Cannot read ${path}. Check file permissions.`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function fileIdentity(path) {
|
|
39
|
+
try {
|
|
40
|
+
return await realpath(path);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error.code !== 'ENOENT')
|
|
44
|
+
throw new InputError(`Cannot resolve configuration path: ${path}.`);
|
|
45
|
+
const info = await lstat(path).catch(error => {
|
|
46
|
+
if (error.code === 'ENOENT')
|
|
47
|
+
return undefined;
|
|
48
|
+
throw new InputError(`Cannot resolve configuration path: ${path}.`);
|
|
49
|
+
});
|
|
50
|
+
if (info?.isSymbolicLink())
|
|
51
|
+
throw new InputError(`Configuration symbolic link has a missing target: ${path}. Restore its target before rerunning init.`);
|
|
52
|
+
return join(await fileIdentity(dirname(path)), basename(path));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async function plan(selected, chosen, scope, options, context) {
|
|
56
|
+
const changes = [];
|
|
57
|
+
const path = configPath(options);
|
|
58
|
+
changes.push({ path, before: await readOptional(path), after: JSON.stringify(selected, null, 2) + '\n', kind: 'CLI settings (no key)' });
|
|
59
|
+
const skill = await readFile(new URL('../skills/lambdadb/SKILL.md', import.meta.url), 'utf8');
|
|
60
|
+
for (const agent of chosen) {
|
|
61
|
+
const adapter = agentAdapters.find(adapter => adapter.id === agent);
|
|
62
|
+
const paths = await adapter.paths(scope, context);
|
|
63
|
+
const before = await readOptional(paths.mcp);
|
|
64
|
+
const after = adapter.configure(paths.mcp, before, mcpLaunch(selected, !!options.writeTools, version));
|
|
65
|
+
changes.push({ path: paths.mcp, before, after, kind: `${agent} MCP (${scope})` });
|
|
66
|
+
const skillPath = paths.skill;
|
|
67
|
+
if (!skillPath)
|
|
68
|
+
continue;
|
|
69
|
+
const previousSkill = await readOptional(skillPath);
|
|
70
|
+
// Preserve existing skills, including user edits, rather than taking ownership.
|
|
71
|
+
changes.push({ path: skillPath, before: previousSkill, after: previousSkill ?? skill, kind: `${agent} skill (${scope}${previousSkill && previousSkill !== skill ? ', existing skill preserved' : ''})` });
|
|
72
|
+
}
|
|
73
|
+
const unique = new Map();
|
|
74
|
+
for (const change of changes) {
|
|
75
|
+
const identity = await fileIdentity(change.path);
|
|
76
|
+
const previous = unique.get(identity);
|
|
77
|
+
if (!previous) {
|
|
78
|
+
unique.set(identity, { ...change, destination: identity, aliases: [] });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (change.path === configPath(options) || previous.path === configPath(options)) {
|
|
82
|
+
throw new InputError('The CLI --config path overlaps an agent configuration or skill path. Choose a separate CLI configuration path and rerun init.');
|
|
83
|
+
}
|
|
84
|
+
if (previous.before !== change.before || previous.after !== change.after) {
|
|
85
|
+
throw new InputError(`Agents request conflicting changes to ${change.path}. Select them separately and inspect the shared file before retrying.`);
|
|
86
|
+
}
|
|
87
|
+
previous.kind += `; ${change.kind}`;
|
|
88
|
+
if (change.path !== previous.path && !previous.aliases.includes(change.path))
|
|
89
|
+
previous.aliases.push(change.path);
|
|
90
|
+
}
|
|
91
|
+
return [...unique.values()];
|
|
92
|
+
}
|
|
93
|
+
async function apply(changes, options) {
|
|
94
|
+
// Detect concurrent edits before writing anything. Individual writes are atomic;
|
|
95
|
+
// a disk/permission failure can still leave a partial install, safe to rerun.
|
|
96
|
+
for (const change of changes) {
|
|
97
|
+
for (const path of [change.path, ...change.aliases]) {
|
|
98
|
+
if (await fileIdentity(path) !== change.destination)
|
|
99
|
+
throw new InputError(`Configuration changed during init: ${path}. Rerun init to review the new plan.`);
|
|
100
|
+
}
|
|
101
|
+
if (await readOptional(change.destination) !== change.before) {
|
|
102
|
+
throw new InputError(`Configuration changed during init: ${change.path}. Rerun init to review the new plan.`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const change of changes.filter(change => change.before !== change.after)) {
|
|
106
|
+
if (change.path === configPath(options)) {
|
|
107
|
+
await saveSettings({ ...options, config: change.destination });
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const temp = `${change.destination}.${randomUUID()}.tmp`;
|
|
111
|
+
try {
|
|
112
|
+
await mkdir(dirname(change.destination), { recursive: true });
|
|
113
|
+
await writeFile(temp, change.after, { flag: 'wx', mode: 0o600 });
|
|
114
|
+
await rename(temp, change.destination);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
throw new InputError(`Cannot update ${change.path}. Check permissions and rerun init; earlier files may already have been updated.`);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
await rm(temp, { force: true }).catch(() => { });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function initialize(options, output) {
|
|
125
|
+
const interactive = !options.nonInteractive && !options.json && !!process.stdin.isTTY && !!process.stderr.isTTY;
|
|
126
|
+
if (!interactive && !options.nonInteractive) {
|
|
127
|
+
throw new InputError(`Init needs a terminal. For automation or --json, pass --non-interactive --agents ${agentNames} (or none) --scope project (or user).`);
|
|
128
|
+
}
|
|
129
|
+
const context = { cwd: process.cwd(), home: homedir(), env: process.env };
|
|
130
|
+
const detected = await detectAgents(context);
|
|
131
|
+
output.diagnostic('Manual Console step: open https://console.lambdadb.ai, select an existing project, and obtain its API endpoint, project name and API key. Export the key securely; init never accepts or saves a key value.');
|
|
132
|
+
const prompt = interactive ? createInterface({ input: process.stdin, output: process.stderr }) : undefined;
|
|
133
|
+
const ask = async (label, fallback) => {
|
|
134
|
+
const cancellation = new AbortController();
|
|
135
|
+
const cancel = () => cancellation.abort();
|
|
136
|
+
prompt.once('SIGINT', cancel);
|
|
137
|
+
prompt.once('close', cancel);
|
|
138
|
+
try {
|
|
139
|
+
const answer = (await prompt.question(`${label}${fallback ? ` [${fallback}]` : ''}: `, { signal: cancellation.signal })).trim();
|
|
140
|
+
return answer || fallback;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (cancellation.signal.aborted)
|
|
144
|
+
throw new InputError('Init canceled. No files were changed.');
|
|
145
|
+
throw error;
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
prompt.removeListener('SIGINT', cancel);
|
|
149
|
+
prompt.removeListener('close', cancel);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
try {
|
|
153
|
+
if (interactive) {
|
|
154
|
+
const saved = await loadSettings(configPath(options));
|
|
155
|
+
options.endpoint = await ask('API endpoint', options.endpoint ?? process.env.LAMBDADB_ENDPOINT ?? saved.endpoint);
|
|
156
|
+
options.project = await ask('Existing project name', options.project ?? process.env.LAMBDADB_PROJECT ?? saved.project);
|
|
157
|
+
options.apiKeyEnv = await ask('Environment variable holding your API key (not its value)', options.apiKeyEnv ?? process.env.LAMBDADB_API_KEY_ENV ?? saved.apiKeyEnv ?? 'LAMBDADB_API_KEY');
|
|
158
|
+
output.protect(options.apiKeyEnv ? process.env[options.apiKeyEnv] : undefined);
|
|
159
|
+
output.diagnostic(`Detected agents (heuristic): ${detected.join(', ') || 'none'}. You may also select an undetected agent.`);
|
|
160
|
+
options.agents ??= await ask(`Agents: ${agentNames} (comma-separated), or none`, detected.join(',') || 'none');
|
|
161
|
+
const scopes = availableScopes(selectedAgents(options.agents));
|
|
162
|
+
options.scope ??= await ask(`Agent configuration scope: ${scopes.join(' or ')}`, scopes[0]);
|
|
163
|
+
if (options.writeTools === undefined)
|
|
164
|
+
options.writeTools = (await ask('Enable MCP write tools? Type yes to opt in', 'no')) === 'yes';
|
|
165
|
+
}
|
|
166
|
+
const chosen = selectedAgents(options.agents);
|
|
167
|
+
if (!['project', 'user'].includes(options.scope ?? ''))
|
|
168
|
+
throw new InputError('Specify --scope project or --scope user. CLI settings still use --config or the normal user configuration path.');
|
|
169
|
+
if (!availableScopes(chosen).includes(options.scope)) {
|
|
170
|
+
throw new InputError(`The selected agents do not all support --scope ${options.scope}. Use --scope ${availableScopes(chosen).join(' or --scope ')} or remove agents that do not support the selected scope.`);
|
|
171
|
+
}
|
|
172
|
+
// Use the existing precedence and validation for both saved settings and auth.
|
|
173
|
+
const selected = await settings(options, true);
|
|
174
|
+
options = { ...options, ...selected };
|
|
175
|
+
output.protect(process.env[selected.apiKeyEnv]);
|
|
176
|
+
if (!process.env[selected.apiKeyEnv]?.trim())
|
|
177
|
+
throw new InputError(`Export ${selected.apiKeyEnv} securely in this shell, then rerun init. Obtain a project API key in the LambdaDB Console; never pass its value as a flag.`);
|
|
178
|
+
const config = await resolveConfig(options, true);
|
|
179
|
+
const changes = await plan(selected, chosen, options.scope, options, context);
|
|
180
|
+
const files = changes.map(change => ({ path: change.path, ...(change.aliases.length ? { aliases: change.aliases } : {}), ...(change.destination !== change.path ? { destination: change.destination } : {}), kind: change.kind,
|
|
181
|
+
action: change.before === change.after ? 'unchanged' : change.before === undefined ? 'create' : 'update' }));
|
|
182
|
+
for (const file of files)
|
|
183
|
+
output.diagnostic(`${file.action}: ${[file.path, ...(file.aliases ?? [])].join(', ')}${file.destination ? ` -> ${file.destination}` : ''} — ${file.kind}`);
|
|
184
|
+
output.diagnostic(`MCP: ${mcpPackage}; write tools ${options.writeTools ? 'enabled (explicit opt-in)' : 'disabled'}. Agents must inherit ${selected.apiKeyEnv}; only its name is stored.`);
|
|
185
|
+
if (interactive && (await ask('Apply these changes after verifying collection-list access? Type yes', 'no')) !== 'yes') {
|
|
186
|
+
throw new InputError('Init canceled. No files were changed.');
|
|
187
|
+
}
|
|
188
|
+
const ctx = runtime(config);
|
|
189
|
+
let connection;
|
|
190
|
+
try {
|
|
191
|
+
connection = await checkConnection(ctx);
|
|
192
|
+
}
|
|
193
|
+
finally {
|
|
194
|
+
ctx.close();
|
|
195
|
+
}
|
|
196
|
+
await apply(changes, options);
|
|
197
|
+
const nextSteps = [
|
|
198
|
+
`Restart/reload selected agents from an environment containing ${selected.apiKeyEnv} and npx on PATH. GUI launches may not inherit shell exports.`,
|
|
199
|
+
agentAdapters.filter(adapter => chosen.includes(adapter.id)).map(adapter => adapter.instructions).join(' '),
|
|
200
|
+
'Agent prompt: Use LambdaDB MCP to list collections, inspect the collection I choose, then read up to five documents at branch:main with query omitted. Help me search an actual indexed field. Do not create or modify data.',
|
|
201
|
+
'CLI alternative: run lambdadb collections list --json and lambdadb collections describe --collection NAME --json. Save {"size":5} in first-query.json, then run lambdadb query --collection NAME --ref branch:main --file first-query.json --json. Replace NAME with the collection you chose.',
|
|
202
|
+
'If the project has no collections/data, populate it deliberately outside init. Connection success does not establish search readiness.',
|
|
203
|
+
];
|
|
204
|
+
return { ...connection, settings: selected, detectedAgents: detected, agents: chosen, scope: options.scope,
|
|
205
|
+
writeTools: !!options.writeTools, files, nextSteps };
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
prompt?.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Config } from './config.js';
|
|
2
|
+
export declare const mcpPackage = "@functional-systems/lambdadb-mcp@0.1.4";
|
|
3
|
+
export declare function mcpEnvironment(config: Config, writeTools: boolean): NodeJS.ProcessEnv;
|
|
4
|
+
export declare function serveMcp(config: Config, writeTools: boolean): Promise<number>;
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { InputError } from './errors.js';
|
|
3
|
+
// Stable stdio package; this CLI only adapts credentials and process lifecycle.
|
|
4
|
+
export const mcpPackage = '@functional-systems/lambdadb-mcp@0.1.4';
|
|
5
|
+
export function mcpEnvironment(config, writeTools) {
|
|
6
|
+
return {
|
|
7
|
+
...process.env,
|
|
8
|
+
LAMBDADB_BASE_URL: config.endpoint,
|
|
9
|
+
LAMBDADB_PROJECT_NAME: config.project,
|
|
10
|
+
LAMBDADB_PROJECT_API_KEY: config.apiKey,
|
|
11
|
+
LAMBDADB_MCP_ENABLE_WRITE_TOOLS: String(writeTools),
|
|
12
|
+
LAMBDADB_DEBUG: 'false',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export async function serveMcp(config, writeTools) {
|
|
16
|
+
// Never emit CLI results on stdout: it belongs exclusively to the MCP transport.
|
|
17
|
+
const child = spawn('npx', ['-y', mcpPackage], {
|
|
18
|
+
env: mcpEnvironment(config, writeTools), stdio: 'inherit', detached: process.platform !== 'win32',
|
|
19
|
+
// Windows needs the npm-provided .cmd launcher. Arguments contain no secrets.
|
|
20
|
+
...(process.platform === 'win32' ? { shell: true } : {}),
|
|
21
|
+
});
|
|
22
|
+
const forward = (signal) => {
|
|
23
|
+
try {
|
|
24
|
+
if (process.platform !== 'win32' && child.pid)
|
|
25
|
+
process.kill(-child.pid, signal);
|
|
26
|
+
else
|
|
27
|
+
child.kill(signal);
|
|
28
|
+
}
|
|
29
|
+
catch { /* The child may already have exited. */ }
|
|
30
|
+
};
|
|
31
|
+
const interrupt = () => forward('SIGINT');
|
|
32
|
+
const terminate = () => forward('SIGTERM');
|
|
33
|
+
process.once('SIGINT', interrupt);
|
|
34
|
+
process.once('SIGTERM', terminate);
|
|
35
|
+
try {
|
|
36
|
+
return await new Promise((resolve, reject) => {
|
|
37
|
+
child.once('error', () => reject(new InputError('Cannot start npx. Install Node.js/npm and make npx available on the agent PATH.')));
|
|
38
|
+
child.once('exit', (code, signal) => resolve(code ?? (signal === 'SIGINT' ? 130 : 143)));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
process.removeListener('SIGINT', interrupt);
|
|
43
|
+
process.removeListener('SIGTERM', terminate);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,gFAAgF;AAChF,MAAM,CAAC,MAAM,UAAU,GAAG,wCAAwC,CAAC;AAEnE,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,UAAmB;IAChE,OAAO;QACL,GAAG,OAAO,CAAC,GAAG;QACd,iBAAiB,EAAE,MAAM,CAAC,QAAQ;QAClC,qBAAqB,EAAE,MAAM,CAAC,OAAO;QACrC,wBAAwB,EAAE,MAAM,CAAC,MAAM;QACvC,+BAA+B,EAAE,MAAM,CAAC,UAAU,CAAC;QACnD,cAAc,EAAE,OAAO;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc,EAAE,UAAmB;IAChE,iFAAiF;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE;QAC7C,GAAG,EAAE,cAAc,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO;QACjG,8EAA8E;QAC9E,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,MAAsB,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,KAAK,CAAC,GAAG;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;;gBAC3E,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC,CAAC,wCAAwC,CAAC,CAAC;IACtD,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,iFAAiF,CAAC,CAAC,CAAC,CAAC;YACrI,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC3F,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC5C,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -5,3 +5,11 @@ export declare function runtime(config: Config): {
|
|
|
5
5
|
options: ClientRequestOptions;
|
|
6
6
|
close(): void;
|
|
7
7
|
};
|
|
8
|
+
export declare function checkConnection(ctx: Pick<ReturnType<typeof runtime>, 'client' | 'options'>): Promise<{
|
|
9
|
+
checks: {
|
|
10
|
+
name: string;
|
|
11
|
+
status: string;
|
|
12
|
+
}[];
|
|
13
|
+
writesVerified: boolean;
|
|
14
|
+
queryReadinessVerified: boolean;
|
|
15
|
+
}>;
|
package/dist/runtime.js
CHANGED
|
@@ -36,4 +36,12 @@ export function runtime(config) {
|
|
|
36
36
|
},
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
+
// Both doctor and init verify access without implying collection/query readiness.
|
|
40
|
+
export async function checkConnection(ctx) {
|
|
41
|
+
await ctx.client.listCollections({ size: 1 }, ctx.options);
|
|
42
|
+
return { checks: [
|
|
43
|
+
{ name: 'configuration', status: 'passed' },
|
|
44
|
+
{ name: 'authentication_and_project_collection_list', status: 'passed' },
|
|
45
|
+
], writesVerified: false, queryReadinessVerified: false };
|
|
46
|
+
}
|
|
39
47
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAA2C,MAAM,8BAA8B,CAAC;AAGnH,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,gFAAgF;IAChF,yEAAyE;IACzE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC3C,gFAAgF;IAChF,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,2BAA2B,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACrI,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnC,MAAM,OAAO,GAAyB;QACpC,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS;QACtD,OAAO,EAAE;YACP,QAAQ,EAAE,SAAS,EAAE,qBAAqB,EAAE,IAAI;YAChD,OAAO,EAAE,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE;SACrH;KACF,CAAC;IACF,+EAA+E;IAC/E,4DAA4D;IAC5D,wEAAwE;IACxE,MAAM,OAAO,GAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM;QACnF,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvC,cAAc,EAAE,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;KAC5C,CAAC,CAAC;IACH,OAAO;QACL,MAAM,EAAE,OAAO;QACf,KAAK;YACH,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC5C,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,cAAc,EAA2C,MAAM,8BAA8B,CAAC;AAGnH,MAAM,UAAU,OAAO,CAAC,MAAc;IACpC,gFAAgF;IAChF,yEAAyE;IACzE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC3C,gFAAgF;IAChF,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,2BAA2B,EAAE,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IACrI,QAAQ,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAClC,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnC,MAAM,OAAO,GAAyB;QACpC,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS;QACtD,OAAO,EAAE;YACP,QAAQ,EAAE,SAAS,EAAE,qBAAqB,EAAE,IAAI;YAChD,OAAO,EAAE,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE;SACrH;KACF,CAAC;IACF,+EAA+E;IAC/E,4DAA4D;IAC5D,wEAAwE;IACxE,MAAM,OAAO,GAAY,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,CAAC,MAAM;QACnF,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;QACvC,cAAc,EAAE,IAAI,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;KAC5C,CAAC,CAAC;IACH,OAAO;QACL,MAAM,EAAE,OAAO;QACf,KAAK;YACH,YAAY,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO,CAAC,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YAC5C,OAAO,CAAC,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QAC/C,CAAC;KACF,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAA2D;IAC/F,MAAM,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3D,OAAO,EAAE,MAAM,EAAE;YACf,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE;YAC3C,EAAE,IAAI,EAAE,4CAA4C,EAAE,MAAM,EAAE,QAAQ,EAAE;SACzE,EAAE,cAAc,EAAE,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,CAAC;AAC5D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@functional-systems/lambdadb-cli",
|
|
3
|
-
"version": "0.1.5-dev.
|
|
3
|
+
"version": "0.1.5-dev.20",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Project-scoped LambdaDB command-line tools",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"DESIGN.md",
|
|
15
15
|
"CONTRIBUTING.md",
|
|
16
16
|
"examples",
|
|
17
|
+
"skills",
|
|
17
18
|
"RELEASING.md",
|
|
18
19
|
"CHANGELOG.md"
|
|
19
20
|
],
|
|
@@ -33,7 +34,9 @@
|
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@functional-systems/lambdadb": "0.8.1",
|
|
36
|
-
"commander": "14.0.3"
|
|
37
|
+
"commander": "14.0.3",
|
|
38
|
+
"jsonc-parser": "3.3.1",
|
|
39
|
+
"smol-toml": "1.9.1"
|
|
37
40
|
},
|
|
38
41
|
"devDependencies": {
|
|
39
42
|
"@eslint/js": "^10.0.1",
|
|
@@ -52,5 +55,5 @@
|
|
|
52
55
|
"url": "https://github.com/lambdadb/lambdadb-cli/issues"
|
|
53
56
|
},
|
|
54
57
|
"license": "Apache-2.0",
|
|
55
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "b8233a163d60f44604b866f53520e7a0a73c9235"
|
|
56
59
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lambdadb
|
|
3
|
+
description: Inspect and search an existing LambdaDB project through LambdaDB MCP or the LambdaDB CLI.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# LambdaDB
|
|
7
|
+
|
|
8
|
+
Use the configured `lambdadb` MCP server for the selected existing project.
|
|
9
|
+
Start with `lambdadb_list_collections`, then `lambdadb_get_collection` to inspect
|
|
10
|
+
the chosen collection's index configuration. Ask the user to choose if the
|
|
11
|
+
intended collection or ref is unclear.
|
|
12
|
+
|
|
13
|
+
For a first read, call `lambdadb_query_collection` with the chosen
|
|
14
|
+
`collectionName`, `ref: {kind: "branch", name: "main"}`, and `size: 5`, omitting
|
|
15
|
+
`query` for match-all. Inspect returned documents before constructing a search
|
|
16
|
+
against actual indexed fields. Use an existing explicit ref when the user
|
|
17
|
+
specifies one. Empty results, a successful collection listing, and accepted
|
|
18
|
+
writes do not prove search/index readiness or relevance.
|
|
19
|
+
|
|
20
|
+
For CLI access, run `lambdadb --help` and the relevant command's `--help`.
|
|
21
|
+
Reads require an explicit `--ref`. For example, put `{"size":5}` in a query
|
|
22
|
+
file and run `lambdadb query --collection NAME --ref branch:main --file FILE --json`.
|
|
23
|
+
The query body follows the LambdaDB API, not SQL. Consult
|
|
24
|
+
https://docs.lambdadb.ai for field-specific query syntax.
|
|
25
|
+
|
|
26
|
+
Credentials come only from the selected environment variable in the agent's
|
|
27
|
+
launch environment. Never print keys or put them in files, arguments, or
|
|
28
|
+
generated examples. If MCP cannot start, check that variable and restart the
|
|
29
|
+
agent from an environment containing it; do not ask the user to paste a key
|
|
30
|
+
into chat. `lambdadb doctor` verifies authentication and collection-list access
|
|
31
|
+
only. Project/key creation remains a manual LambdaDB Console step.
|
|
32
|
+
|
|
33
|
+
MCP exposes read tools by default. Write tools require explicit setup opt-in;
|
|
34
|
+
their availability does not authorize creating collections or changing data.
|
|
35
|
+
Perform writes only when requested, using the user's collection and branch.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { applyEdits, modify, parse as parseJson, type ParseError } from 'jsonc-parser';
|
|
2
|
+
import { parse as parseToml } from 'smol-toml';
|
|
3
|
+
import type { Settings } from './config.js';
|
|
4
|
+
import { InputError } from './errors.js';
|
|
5
|
+
|
|
6
|
+
export type McpLaunch = { command: string; args: string[]; apiKeyEnv: string };
|
|
7
|
+
type Server = { command: string | string[]; args?: string[]; env_vars?: string[];
|
|
8
|
+
env?: Record<string, string>; environment?: Record<string, string>; type?: string };
|
|
9
|
+
type ServerFactory = (launch: McpLaunch) => Server;
|
|
10
|
+
type JsonMapPath = readonly string[] | ((value: Record<string, unknown>) => readonly string[]);
|
|
11
|
+
const begin = '# BEGIN lambdadb init';
|
|
12
|
+
const end = '# END lambdadb init';
|
|
13
|
+
|
|
14
|
+
export function mcpLaunch(selected: Required<Settings>, writeTools: boolean, cliVersion: string): McpLaunch {
|
|
15
|
+
return { command: 'npx', apiKeyEnv: selected.apiKeyEnv,
|
|
16
|
+
args: ['-y', `@functional-systems/lambdadb-cli@${cliVersion}`, 'mcp',
|
|
17
|
+
'--endpoint', selected.endpoint, '--project', selected.project, '--api-key-env', selected.apiKeyEnv,
|
|
18
|
+
...(writeTools ? ['--write-tools'] : [])] };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function object(value: unknown): value is Record<string, unknown> {
|
|
22
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Only entries generated by init may be updated. User additions to our entry
|
|
26
|
+
// cause a conflict instead of silently dropping their settings.
|
|
27
|
+
function managedServer(value: unknown, createServer: ServerFactory): boolean {
|
|
28
|
+
if (!object(value)) return false;
|
|
29
|
+
const command = Array.isArray(value.command) ? value.command[0] : value.command;
|
|
30
|
+
const a = Array.isArray(value.command) ? value.command.slice(1) : value.args;
|
|
31
|
+
if (command !== 'npx' || !Array.isArray(a)) return false;
|
|
32
|
+
if (a.some(v => typeof v !== 'string') || !/^@functional-systems\/lambdadb-cli@[\w.+-]+$/.test(a[1] ?? '')
|
|
33
|
+
|| a[0] !== '-y' || a[2] !== 'mcp' || a[3] !== '--endpoint' || a[5] !== '--project'
|
|
34
|
+
|| a[7] !== '--api-key-env' || ![9, 10].includes(a.length) || (a.length === 10 && a[9] !== '--write-tools')) return false;
|
|
35
|
+
const expected = createServer({ command: 'npx', args: a, apiKeyEnv: a[8] });
|
|
36
|
+
return Object.keys(value).length === Object.keys(expected).length
|
|
37
|
+
&& Object.entries(expected).every(([key, item]) => JSON.stringify(value[key]) === JSON.stringify(item));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function conflict(path: string): never {
|
|
41
|
+
throw new InputError(`Existing LambdaDB configuration in ${path} was not generated by init or has been edited. Preserve or rename that entry before rerunning init; no overwrite was performed.`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function jsonConfig(path: string, text: string | undefined, launch: McpLaunch, createServer: ServerFactory,
|
|
45
|
+
mapPath: JsonMapPath = ['mcpServers']): string {
|
|
46
|
+
const errors: ParseError[] = [];
|
|
47
|
+
const value: unknown = parseJson(text ?? '{}', errors, { allowTrailingComma: true });
|
|
48
|
+
if (errors.length || !object(value)) {
|
|
49
|
+
throw new InputError(`Invalid agent JSON configuration: ${path}. Fix it before rerunning init.`);
|
|
50
|
+
}
|
|
51
|
+
const keys = typeof mapPath === 'function' ? mapPath(value) : mapPath;
|
|
52
|
+
let container: Record<string, unknown> = value;
|
|
53
|
+
for (const key of keys) {
|
|
54
|
+
const child = container[key];
|
|
55
|
+
if (child !== undefined && !object(child)) {
|
|
56
|
+
throw new InputError(`Invalid agent JSON configuration: ${path}. ${keys.join('.')} must contain objects.`);
|
|
57
|
+
}
|
|
58
|
+
container = (child ?? {}) as Record<string, unknown>;
|
|
59
|
+
}
|
|
60
|
+
const previous = container.lambdadb;
|
|
61
|
+
if (previous !== undefined && !managedServer(previous, createServer)) conflict(path);
|
|
62
|
+
const desired = createServer(launch);
|
|
63
|
+
if (JSON.stringify(previous) === JSON.stringify(desired)) return text!;
|
|
64
|
+
const source = text ?? '{}\n';
|
|
65
|
+
return applyEdits(source, modify(source, [...keys, 'lambdadb'], desired, {
|
|
66
|
+
formattingOptions: { insertSpaces: true, tabSize: 2 },
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function strictJsonConfig(path: string, text: string | undefined, launch: McpLaunch, createServer: ServerFactory,
|
|
71
|
+
mapPath: JsonMapPath = ['mcpServers']): string {
|
|
72
|
+
try { JSON.parse(text ?? '{}'); }
|
|
73
|
+
catch { throw new InputError(`Init requires strict JSON for ${path}. Remove comments or trailing commas before rerunning init.`); }
|
|
74
|
+
return jsonConfig(path, text, launch, createServer, mapPath);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function tomlBlock(value: { args?: unknown; env_vars?: unknown }): string {
|
|
78
|
+
return `${begin}\n[mcp_servers.lambdadb]\ncommand = "npx"\nargs = ${JSON.stringify(value.args)}\nenv_vars = ${JSON.stringify(value.env_vars)}\n${end}\n`;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function tomlConfig(path: string, text: string | undefined, launch: McpLaunch, createServer: ServerFactory): string {
|
|
82
|
+
const source = text ?? '';
|
|
83
|
+
let parsed;
|
|
84
|
+
try { parsed = parseToml(source); }
|
|
85
|
+
catch { throw new InputError(`Invalid agent TOML configuration: ${path}. Fix it before rerunning init.`); }
|
|
86
|
+
const servers = parsed.mcp_servers;
|
|
87
|
+
if (servers !== undefined && !object(servers)) conflict(path);
|
|
88
|
+
const previous = object(servers) ? servers.lambdadb : undefined;
|
|
89
|
+
const block = tomlBlock(createServer(launch));
|
|
90
|
+
const start = source.indexOf(begin);
|
|
91
|
+
let after: string;
|
|
92
|
+
if (start < 0) {
|
|
93
|
+
if (previous !== undefined || source.includes(end)) conflict(path);
|
|
94
|
+
after = source + (source.endsWith('\n') || !source ? '' : '\n') + '\n' + block;
|
|
95
|
+
} else {
|
|
96
|
+
const finish = source.indexOf(end, start);
|
|
97
|
+
if (finish < 0 || source.indexOf(begin, start + begin.length) >= 0 || source.indexOf(end, finish + end.length) >= 0
|
|
98
|
+
|| !managedServer(previous, createServer)) conflict(path);
|
|
99
|
+
const stop = finish + end.length + (source[finish + end.length] === '\n' ? 1 : 0);
|
|
100
|
+
// Refuse to remove any unrelated sections/settings hidden inside markers.
|
|
101
|
+
let managed;
|
|
102
|
+
try { managed = parseToml(source.slice(start, stop)); } catch { conflict(path); }
|
|
103
|
+
if (Object.keys(managed).length !== 1 || !object(managed.mcp_servers)
|
|
104
|
+
|| Object.keys(managed.mcp_servers).length !== 1 || !managedServer(managed.mcp_servers.lambdadb, createServer)) conflict(path);
|
|
105
|
+
if (source.slice(start, stop) !== tomlBlock(previous as { args: unknown; env_vars: unknown })) conflict(path);
|
|
106
|
+
after = source.slice(0, start) + block + source.slice(stop);
|
|
107
|
+
}
|
|
108
|
+
// Appending a table is unsafe when an existing inline table seals mcp_servers.
|
|
109
|
+
try { parseToml(after); }
|
|
110
|
+
catch { throw new InputError(`Cannot safely add LambdaDB to ${path}. Expand inline MCP tables before rerunning init.`); }
|
|
111
|
+
return after;
|
|
112
|
+
}
|