@gagik.co/snippet-agent 0.1.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/.eslintrc.js +13 -0
- package/.prettierrc.json +1 -0
- package/README.md +23 -0
- package/dist/agent-class.d.ts +47 -0
- package/dist/agent-class.js +314 -0
- package/dist/agent.d.ts +1 -0
- package/dist/agent.js +392 -0
- package/dist/banner.d.ts +1 -0
- package/dist/banner.js +23 -0
- package/dist/confirmation-extension.d.ts +10 -0
- package/dist/confirmation-extension.js +213 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +141 -0
- package/dist/mongosh-interactive-mode.d.ts +33 -0
- package/dist/mongosh-interactive-mode.js +244 -0
- package/dist/project-agent.d.ts +1 -0
- package/dist/project-agent.js +36 -0
- package/dist/shell-context.d.ts +17 -0
- package/dist/shell-context.js +75 -0
- package/dist/skills-loader.d.ts +2 -0
- package/dist/skills-loader.js +69 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +8 -0
- package/dist/src/project-agent.d.ts +1 -0
- package/dist/src/project-agent.js +36 -0
- package/dist/stdout-patcher.d.ts +5 -0
- package/dist/stdout-patcher.js +41 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +7 -0
- package/dist/tools/mongosh-eval.d.ts +7 -0
- package/dist/tools/mongosh-eval.js +84 -0
- package/dist/tools/search-docs.d.ts +2 -0
- package/dist/tools/search-docs.js +106 -0
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools.d.ts +7 -0
- package/dist/tools.js +189 -0
- package/dist/types.d.ts +21 -0
- package/dist/types.js +2 -0
- package/package.json +38 -0
- package/skills/mongodb-connection.md +208 -0
- package/skills/mongodb-natural-language-querying.md +202 -0
- package/skills/mongodb-query-optimizer.md +265 -0
- package/skills/mongodb-schema-design.md +455 -0
- package/skills/mongodb-search-and-ai.md +357 -0
- package/skills/mongosh-shell.md +227 -0
- package/src/agent-class.ts +393 -0
- package/src/banner.ts +36 -0
- package/src/confirmation-extension.ts +297 -0
- package/src/index.ts +137 -0
- package/src/mongosh-interactive-mode.ts +420 -0
- package/src/shell-context.ts +97 -0
- package/src/skills-loader.ts +37 -0
- package/src/stdout-patcher.ts +48 -0
- package/src/tools/index.ts +4 -0
- package/src/tools/mongosh-eval.ts +115 -0
- package/src/tools/search-docs.ts +115 -0
- package/src/tools/types.ts +15 -0
- package/src/types.ts +23 -0
- package/tsconfig-lint.json +4 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createStdoutPatcher = createStdoutPatcher;
|
|
4
|
+
// Specific problematic Kitty protocol sequences to suppress
|
|
5
|
+
const KITTY_QUERY = '\x1b[?u';
|
|
6
|
+
const KITTY_ENABLE_7U = '\x1b[>7u';
|
|
7
|
+
const KITTY_ENABLE_4_2M = '\x1b[>4;2m';
|
|
8
|
+
function createStdoutPatcher() {
|
|
9
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
10
|
+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
|
|
11
|
+
let suppressKittyQueries = false;
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
const filterWrite = (original) => function (chunk, encoding, callback) {
|
|
14
|
+
if (suppressKittyQueries) {
|
|
15
|
+
const str = typeof chunk === 'string' ? chunk : chunk.toString();
|
|
16
|
+
// Only suppress specific Kitty protocol sequences (not general color codes)
|
|
17
|
+
const isKittySeq = str === KITTY_QUERY ||
|
|
18
|
+
str === KITTY_ENABLE_7U ||
|
|
19
|
+
str === KITTY_ENABLE_4_2M ||
|
|
20
|
+
str.endsWith(KITTY_QUERY) ||
|
|
21
|
+
str.endsWith(KITTY_ENABLE_7U) ||
|
|
22
|
+
str.endsWith(KITTY_ENABLE_4_2M);
|
|
23
|
+
if (isKittySeq) {
|
|
24
|
+
if (typeof callback === 'function')
|
|
25
|
+
callback();
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return original(chunk, encoding, callback);
|
|
30
|
+
};
|
|
31
|
+
process.stdout.write = filterWrite(originalStdoutWrite);
|
|
32
|
+
process.stderr.write = filterWrite(originalStderrWrite);
|
|
33
|
+
return {
|
|
34
|
+
enable: () => {
|
|
35
|
+
suppressKittyQueries = true;
|
|
36
|
+
},
|
|
37
|
+
disable: () => {
|
|
38
|
+
suppressKittyQueries = false;
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMongoshEvalTool = exports.createSearchDocsTool = void 0;
|
|
4
|
+
var search_docs_1 = require("./search-docs");
|
|
5
|
+
Object.defineProperty(exports, "createSearchDocsTool", { enumerable: true, get: function () { return search_docs_1.createSearchDocsTool; } });
|
|
6
|
+
var mongosh_eval_1 = require("./mongosh-eval");
|
|
7
|
+
Object.defineProperty(exports, "createMongoshEvalTool", { enumerable: true, get: function () { return mongosh_eval_1.createMongoshEvalTool; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ShellContext } from '../shell-context';
|
|
2
|
+
import type { Tool } from './types';
|
|
3
|
+
export type CreateMongoshEvalToolOptions = {
|
|
4
|
+
shellContext: ShellContext;
|
|
5
|
+
debugLogging: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function createMongoshEvalTool(options: CreateMongoshEvalToolOptions): Promise<Tool>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMongoshEvalTool = createMongoshEvalTool;
|
|
4
|
+
async function createMongoshEvalTool(options) {
|
|
5
|
+
const { shellContext, debugLogging } = options;
|
|
6
|
+
const { defineTool } = await import('@earendil-works/pi-coding-agent');
|
|
7
|
+
const { Type } = await import('@sinclair/typebox');
|
|
8
|
+
const { shellEvaluator, originalEval, formatResultValue, instanceState, capturedPrintOutput, } = shellContext;
|
|
9
|
+
return defineTool({
|
|
10
|
+
name: 'mongosh_eval',
|
|
11
|
+
label: 'mongosh eval',
|
|
12
|
+
description: 'Execute a mongosh shell expression against the connected MongoDB instance. ' +
|
|
13
|
+
'Supports the full mongosh API: queries, aggregations, admin commands ' +
|
|
14
|
+
'The expression runs in the same context as the interactive mongosh REPL.' +
|
|
15
|
+
'Note: make sure to double-check with the user before running destructive or risky operations.',
|
|
16
|
+
parameters: Type.Object({
|
|
17
|
+
expression: Type.String({
|
|
18
|
+
description: 'The mongosh expression to evaluate. Never run `use` to switch databases and instead refer to the database name explicitly. Examples: "db.getMongo()", "db.users.find().limit(5)", "db.serverStatus()", "db.getSiblingDB(\'movies\')". The last line of the output will be the result of the tool call.',
|
|
19
|
+
}),
|
|
20
|
+
}),
|
|
21
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
22
|
+
execute: async (_toolCallId, params) => {
|
|
23
|
+
const expr = params.expression;
|
|
24
|
+
// Clear captured output before execution
|
|
25
|
+
capturedPrintOutput.length = 0;
|
|
26
|
+
try {
|
|
27
|
+
let rawValue = await shellEvaluator.customEval(originalEval, expr, instanceState.context, 'mongosh_eval');
|
|
28
|
+
// Auto-call functions that take no arguments (e.g., `history` -> `history()`)
|
|
29
|
+
// This provides shell-like behavior for zero-argument functions
|
|
30
|
+
if (typeof rawValue === 'function') {
|
|
31
|
+
try {
|
|
32
|
+
rawValue = await rawValue();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// If calling fails, keep the original function reference
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const formatted = await formatResultValue(rawValue);
|
|
39
|
+
// Build output: captured print output takes priority, then add formatted result if present
|
|
40
|
+
let output;
|
|
41
|
+
if (capturedPrintOutput.length > 0) {
|
|
42
|
+
// Has captured print output - use it as primary output
|
|
43
|
+
output = capturedPrintOutput.join('\n');
|
|
44
|
+
// Also append formatted result if it's meaningful (not empty/undefined)
|
|
45
|
+
if (formatted) {
|
|
46
|
+
output += '\n' + formatted;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else if (formatted) {
|
|
50
|
+
// No captured output, but has formatted result
|
|
51
|
+
output = formatted;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// Nothing to show
|
|
55
|
+
output = '(no output)';
|
|
56
|
+
}
|
|
57
|
+
if (debugLogging) {
|
|
58
|
+
process.stderr.write(`[mongosh_eval] Output: ${output.substring(0, 200)}\n`);
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: 'text', text: output }],
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
details: { expression: expr },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
const errorMsg = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
68
|
+
if (debugLogging) {
|
|
69
|
+
process.stderr.write(`[mongosh_eval] Error: ${errorMsg}\n`);
|
|
70
|
+
}
|
|
71
|
+
const parts = [];
|
|
72
|
+
if (capturedPrintOutput.length > 0) {
|
|
73
|
+
parts.push(capturedPrintOutput.join('\n'));
|
|
74
|
+
}
|
|
75
|
+
parts.push(`Error: ${errorMsg}`);
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: 'text', text: parts.join('\n') }],
|
|
78
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
|
+
details: { error: errorMsg, expression: expr },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSearchDocsTool = createSearchDocsTool;
|
|
4
|
+
async function createSearchDocsTool() {
|
|
5
|
+
const { defineTool } = await import('@earendil-works/pi-coding-agent');
|
|
6
|
+
const { Type } = await import('@sinclair/typebox');
|
|
7
|
+
return defineTool({
|
|
8
|
+
name: 'search_docs',
|
|
9
|
+
label: 'search docs',
|
|
10
|
+
description: 'Search for information in the MongoDB documentation and knowledge base. ' +
|
|
11
|
+
'This includes official documentation, curated expert guidance, and other resources provided by MongoDB.',
|
|
12
|
+
parameters: Type.Object({
|
|
13
|
+
query: Type.String({
|
|
14
|
+
description: 'A natural language query to search for in the MongoDB knowledge base. ' +
|
|
15
|
+
'This should be a single question or a topic that is relevant to the MongoDB use case.',
|
|
16
|
+
}),
|
|
17
|
+
limit: Type.Optional(Type.Number({
|
|
18
|
+
description: 'The maximum number of results to return (1-100)',
|
|
19
|
+
default: 5,
|
|
20
|
+
minimum: 1,
|
|
21
|
+
maximum: 100,
|
|
22
|
+
})),
|
|
23
|
+
}),
|
|
24
|
+
execute: async (_toolCallId, params) => {
|
|
25
|
+
const { query, limit = 5 } = params;
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetch('https://knowledge.mongodb.com/api/v1/content/search', {
|
|
28
|
+
method: 'POST',
|
|
29
|
+
headers: {
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
'X-Request-Origin': 'mongodb-mongosh',
|
|
32
|
+
'User-Agent': 'mongodb-mongosh',
|
|
33
|
+
},
|
|
34
|
+
body: JSON.stringify({
|
|
35
|
+
query,
|
|
36
|
+
limit,
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
const errorText = await response.text();
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: 'text',
|
|
45
|
+
text: `Failed to search docs: ${response.status} ${response.statusText}${errorText ? `\n${errorText}` : ''}`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
|
+
details: { query, limit, error: errorText },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const data = (await response.json());
|
|
54
|
+
if (!data.results || data.results.length === 0) {
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: 'text',
|
|
59
|
+
text: 'No results found for this query.',
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
details: { query, limit, resultCount: 0 },
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const formattedResults = data.results
|
|
67
|
+
.map((result, index) => {
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push(`${index + 1}. ${result.title}`);
|
|
70
|
+
lines.push(` URL: ${result.url}`);
|
|
71
|
+
if (result.metadata?.tags?.length) {
|
|
72
|
+
lines.push(` Tags: ${result.metadata.tags.join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
lines.push('');
|
|
75
|
+
lines.push(result.text.split('\n').map((line) => ` ${line}`).join('\n'));
|
|
76
|
+
return lines.join('\n');
|
|
77
|
+
})
|
|
78
|
+
.join('\n\n');
|
|
79
|
+
return {
|
|
80
|
+
content: [
|
|
81
|
+
{
|
|
82
|
+
type: 'text',
|
|
83
|
+
text: `Found ${data.results.length} result${data.results.length === 1 ? '' : 's'} in MongoDB documentation:\n\n${formattedResults}`,
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
+
details: { query, limit, resultCount: data.results.length },
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: 'text',
|
|
96
|
+
text: `Error searching docs: ${errorMsg}`,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
isError: true,
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
|
+
details: { query, limit, error: errorMsg },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Tool = ReturnType<typeof import('@earendil-works/pi-coding-agent').defineTool>;
|
|
2
|
+
export type SearchDocsResult = {
|
|
3
|
+
results: Array<{
|
|
4
|
+
url: string;
|
|
5
|
+
title: string;
|
|
6
|
+
text: string;
|
|
7
|
+
metadata: {
|
|
8
|
+
tags: string[];
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
};
|
|
11
|
+
}>;
|
|
12
|
+
};
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ShellContext } from './shell-context';
|
|
2
|
+
export type Tool = ReturnType<typeof import('@earendil-works/pi-coding-agent').defineTool>;
|
|
3
|
+
export declare function createSearchDocsTool(): Promise<Tool>;
|
|
4
|
+
export declare function createMongoshEvalTool(options: {
|
|
5
|
+
shellContext: ShellContext;
|
|
6
|
+
debugLogging: boolean;
|
|
7
|
+
}): Promise<Tool>;
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSearchDocsTool = createSearchDocsTool;
|
|
4
|
+
exports.createMongoshEvalTool = createMongoshEvalTool;
|
|
5
|
+
async function createSearchDocsTool() {
|
|
6
|
+
const { defineTool } = await import('@earendil-works/pi-coding-agent');
|
|
7
|
+
const { Type } = await import('@sinclair/typebox');
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'search_docs',
|
|
10
|
+
label: 'search docs',
|
|
11
|
+
description: 'Search for information in the MongoDB documentation and knowledge base. ' +
|
|
12
|
+
'This includes official documentation, curated expert guidance, and other resources provided by MongoDB.',
|
|
13
|
+
parameters: Type.Object({
|
|
14
|
+
query: Type.String({
|
|
15
|
+
description: 'A natural language query to search for in the MongoDB knowledge base. ' +
|
|
16
|
+
'This should be a single question or a topic that is relevant to the MongoDB use case.',
|
|
17
|
+
}),
|
|
18
|
+
limit: Type.Optional(Type.Number({
|
|
19
|
+
description: 'The maximum number of results to return (1-100)',
|
|
20
|
+
default: 5,
|
|
21
|
+
minimum: 1,
|
|
22
|
+
maximum: 100,
|
|
23
|
+
})),
|
|
24
|
+
}),
|
|
25
|
+
execute: async (_toolCallId, params) => {
|
|
26
|
+
const { query, limit = 5 } = params;
|
|
27
|
+
try {
|
|
28
|
+
const response = await fetch('https://knowledge.mongodb.com/api/v1/content/search', {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
'X-Request-Origin': 'mongodb-mongosh',
|
|
33
|
+
'User-Agent': 'mongodb-mongosh',
|
|
34
|
+
},
|
|
35
|
+
body: JSON.stringify({
|
|
36
|
+
query,
|
|
37
|
+
limit,
|
|
38
|
+
}),
|
|
39
|
+
});
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const errorText = await response.text();
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: 'text',
|
|
46
|
+
text: `Failed to search docs: ${response.status} ${response.statusText}${errorText ? `\n${errorText}` : ''}`,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
isError: true,
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
details: { query, limit, error: errorText },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const data = (await response.json());
|
|
55
|
+
if (!data.results || data.results.length === 0) {
|
|
56
|
+
return {
|
|
57
|
+
content: [
|
|
58
|
+
{
|
|
59
|
+
type: 'text',
|
|
60
|
+
text: 'No results found for this query.',
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
details: { query, limit, resultCount: 0 },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const formattedResults = data.results
|
|
68
|
+
.map((result, index) => {
|
|
69
|
+
const lines = [];
|
|
70
|
+
lines.push(`${index + 1}. ${result.title}`);
|
|
71
|
+
lines.push(` URL: ${result.url}`);
|
|
72
|
+
if (result.metadata?.tags?.length) {
|
|
73
|
+
lines.push(` Tags: ${result.metadata.tags.join(', ')}`);
|
|
74
|
+
}
|
|
75
|
+
lines.push('');
|
|
76
|
+
lines.push(result.text.split('\n').map((line) => ` ${line}`).join('\n'));
|
|
77
|
+
return lines.join('\n');
|
|
78
|
+
})
|
|
79
|
+
.join('\n\n');
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: `Found ${data.results.length} result${data.results.length === 1 ? '' : 's'} in MongoDB documentation:\n\n${formattedResults}`,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
88
|
+
details: { query, limit, resultCount: data.results.length },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: 'text',
|
|
97
|
+
text: `Error searching docs: ${errorMsg}`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
isError: true,
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
102
|
+
details: { query, limit, error: errorMsg },
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async function createMongoshEvalTool(options) {
|
|
109
|
+
const { shellContext, debugLogging } = options;
|
|
110
|
+
const { defineTool } = await import('@earendil-works/pi-coding-agent');
|
|
111
|
+
const { Type } = await import('@sinclair/typebox');
|
|
112
|
+
const { shellEvaluator, originalEval, formatResultValue, instanceState, capturedPrintOutput, } = shellContext;
|
|
113
|
+
return defineTool({
|
|
114
|
+
name: 'mongosh_eval',
|
|
115
|
+
label: 'mongosh eval',
|
|
116
|
+
description: 'Execute a mongosh shell expression against the connected MongoDB instance. ' +
|
|
117
|
+
'Supports the full mongosh API: queries, aggregations, admin commands, ' +
|
|
118
|
+
'direct shell commands (show dbs, use <db>, it, etc.), and auto-awaiting. ' +
|
|
119
|
+
'The expression runs in the same context as the interactive mongosh REPL.' +
|
|
120
|
+
'Note: make sure to double-check with the user before running destructive or risky operations.',
|
|
121
|
+
parameters: Type.Object({
|
|
122
|
+
expression: Type.String({
|
|
123
|
+
description: 'The mongosh expression to evaluate. Examples: "db.getMongo()", "db.users.find().limit(5)", "show dbs", "use mydb", "db.serverStatus()". The last line of the output will be the result of the tool call.',
|
|
124
|
+
}),
|
|
125
|
+
}),
|
|
126
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
127
|
+
execute: async (_toolCallId, params) => {
|
|
128
|
+
const expr = params.expression;
|
|
129
|
+
// Clear captured output before execution
|
|
130
|
+
capturedPrintOutput.length = 0;
|
|
131
|
+
try {
|
|
132
|
+
let rawValue = await shellEvaluator.customEval(originalEval, expr, instanceState.context, 'mongosh_eval');
|
|
133
|
+
// Auto-call functions that take no arguments (e.g., `history` -> `history()`)
|
|
134
|
+
// This provides shell-like behavior for zero-argument functions
|
|
135
|
+
if (typeof rawValue === 'function') {
|
|
136
|
+
try {
|
|
137
|
+
rawValue = await rawValue();
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// If calling fails, keep the original function reference
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const formatted = await formatResultValue(rawValue);
|
|
144
|
+
// Build output: captured print output takes priority, then add formatted result if present
|
|
145
|
+
let output;
|
|
146
|
+
if (capturedPrintOutput.length > 0) {
|
|
147
|
+
// Has captured print output - use it as primary output
|
|
148
|
+
output = capturedPrintOutput.join('\n');
|
|
149
|
+
// Also append formatted result if it's meaningful (not empty/undefined)
|
|
150
|
+
if (formatted) {
|
|
151
|
+
output += '\n' + formatted;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else if (formatted) {
|
|
155
|
+
// No captured output, but has formatted result
|
|
156
|
+
output = formatted;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
// Nothing to show
|
|
160
|
+
output = '(no output)';
|
|
161
|
+
}
|
|
162
|
+
if (debugLogging) {
|
|
163
|
+
process.stderr.write(`[mongosh_eval] Output: ${output.substring(0, 200)}\n`);
|
|
164
|
+
}
|
|
165
|
+
return {
|
|
166
|
+
content: [{ type: 'text', text: output }],
|
|
167
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
168
|
+
details: { expression: expr },
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
const errorMsg = err instanceof Error ? `${err.name}: ${err.message}` : String(err);
|
|
173
|
+
if (debugLogging) {
|
|
174
|
+
process.stderr.write(`[mongosh_eval] Error: ${errorMsg}\n`);
|
|
175
|
+
}
|
|
176
|
+
const parts = [];
|
|
177
|
+
if (capturedPrintOutput.length > 0) {
|
|
178
|
+
parts.push(capturedPrintOutput.join('\n'));
|
|
179
|
+
}
|
|
180
|
+
parts.push(`Error: ${errorMsg}`);
|
|
181
|
+
return {
|
|
182
|
+
content: [{ type: 'text', text: parts.join('\n') }],
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
184
|
+
details: { error: errorMsg, expression: expr },
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type ShellInstanceState = {
|
|
2
|
+
evaluationListener: {
|
|
3
|
+
setConfig: (key: string, value: unknown) => void;
|
|
4
|
+
getConfig: <T>(key: string) => Promise<T>;
|
|
5
|
+
};
|
|
6
|
+
shellApi: Record<string, unknown>;
|
|
7
|
+
context: Record<string, unknown>;
|
|
8
|
+
};
|
|
9
|
+
export type CliContext = {
|
|
10
|
+
db: {
|
|
11
|
+
_mongo: {
|
|
12
|
+
_instanceState: ShellInstanceState;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
export type Skill = {
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
content: string;
|
|
20
|
+
source: string;
|
|
21
|
+
};
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gagik.co/snippet-agent",
|
|
3
|
+
"snippetName": "agent",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"description": "Integrates Pi coding agent with mongosh",
|
|
6
|
+
"author": "Gagik Amaryan",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"license": "Apache-2.0",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"prepare": "npm run build",
|
|
16
|
+
"check": "eslint src && tsc --noEmit",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"dev": "npm run build && mongosh --eval \"require('./dist/index.js')(globalThis);''\" --shell"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@earendil-works/pi-coding-agent": "^0.74.0",
|
|
23
|
+
"@earendil-works/pi-tui": "^0.74.0",
|
|
24
|
+
"@mongosh/shell-api": "^5.0.0",
|
|
25
|
+
"@mongosh/shell-evaluator": "^5.0.0",
|
|
26
|
+
"@mongosh/types": "^5.0.3",
|
|
27
|
+
"@sinclair/typebox": "^0.34.49",
|
|
28
|
+
"chalk": "^5.5.0",
|
|
29
|
+
"cli-highlight": "^2.1.11"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@mongodb-js/eslint-config-devtools": "^0.9.11",
|
|
33
|
+
"@mongodb-js/prettier-config-devtools": "^1.0.2",
|
|
34
|
+
"@types/node": "^20.17.48",
|
|
35
|
+
"typescript": "^5.0.0",
|
|
36
|
+
"vitest": "^4.0.16"
|
|
37
|
+
}
|
|
38
|
+
}
|