@baitong-dev/mcp-helpers 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/{file.d.ts → file/index.d.ts} +2 -2
- package/dist/file/index.js +75 -0
- package/dist/file/ripgrep.d.ts +187 -0
- package/dist/file/ripgrep.js +229 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/logger.d.ts +12 -0
- package/dist/logger.js +40 -0
- package/dist/{process.d.ts → process/index.d.ts} +1 -1
- package/dist/{process.js → process/index.js} +36 -2
- package/dist/process/simple-process.d.ts +16 -0
- package/dist/process/simple-process.js +51 -0
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +41 -0
- package/dist/tools/question.d.ts +91 -0
- package/dist/tools/question.js +140 -0
- package/dist/tools/tool.d.ts +9 -0
- package/dist/tools/tool.js +19 -0
- package/dist/util.d.ts +0 -1
- package/dist/util.js +3 -10
- package/package.json +3 -2
- package/dist/file.js +0 -40
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -4,7 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
5
|
};
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.MCP_HOME_DIR = void 0;
|
|
7
|
+
exports.MCP_WORKSPACE_DIR = exports.MCP_HOME_DIR = void 0;
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const os_1 = __importDefault(require("os"));
|
|
10
|
-
exports.MCP_HOME_DIR = process.env.MCP_HOME_DIR || path_1.default.join(os_1.default.homedir(), '
|
|
10
|
+
exports.MCP_HOME_DIR = process.env.MCP_HOME_DIR || path_1.default.join(os_1.default.homedir(), '.baitong');
|
|
11
|
+
exports.MCP_WORKSPACE_DIR = process.env.MCP_WORKSPACE_DIR || path_1.default.resolve(path_1.default.join(exports.MCP_HOME_DIR, 'workspace'));
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
export * as Ripgrep from './ripgrep';
|
|
2
2
|
/**
|
|
3
3
|
* Check if a path is a directory.
|
|
4
4
|
* @param path The path to check
|
|
5
5
|
* @returns Whether the path is a directory
|
|
6
6
|
*/
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function isDirectory(path: string): boolean;
|
|
8
8
|
/**
|
|
9
9
|
* 检查一个目录是否是另一个目录的子目录
|
|
10
10
|
* @param parent - 父目录路径
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Ripgrep = void 0;
|
|
40
|
+
exports.isDirectory = isDirectory;
|
|
41
|
+
exports.isSubdirectory = isSubdirectory;
|
|
42
|
+
const path_1 = __importDefault(require("path"));
|
|
43
|
+
const fs_1 = __importDefault(require("fs"));
|
|
44
|
+
exports.Ripgrep = __importStar(require("./ripgrep"));
|
|
45
|
+
/**
|
|
46
|
+
* Check if a path is a directory.
|
|
47
|
+
* @param path The path to check
|
|
48
|
+
* @returns Whether the path is a directory
|
|
49
|
+
*/
|
|
50
|
+
function isDirectory(path) {
|
|
51
|
+
try {
|
|
52
|
+
const stat = fs_1.default.statSync(path);
|
|
53
|
+
return stat.isDirectory();
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 检查一个目录是否是另一个目录的子目录
|
|
61
|
+
* @param parent - 父目录路径
|
|
62
|
+
* @param child - 要检查的子目录路径
|
|
63
|
+
* @param options - 配置选项
|
|
64
|
+
* @param options.includeSelf - 是否将自身视为子目录
|
|
65
|
+
* @returns - 同步返回 boolean,异步返回 Promise
|
|
66
|
+
*/
|
|
67
|
+
function isSubdirectory(parent, child, { includeSelf = false }) {
|
|
68
|
+
const parentPath = path_1.default.resolve(parent);
|
|
69
|
+
const childPath = path_1.default.isAbsolute(child) ? child : path_1.default.join(parentPath, child);
|
|
70
|
+
const relative = path_1.default.relative(parentPath, childPath);
|
|
71
|
+
if (includeSelf && childPath === parentPath) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return (relative && !relative.startsWith('..') && !path_1.default.isAbsolute(relative)) || false;
|
|
75
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
declare const Begin: z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"begin">;
|
|
4
|
+
data: z.ZodObject<{
|
|
5
|
+
path: z.ZodObject<{
|
|
6
|
+
text: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
export declare const Match: z.ZodObject<{
|
|
11
|
+
type: z.ZodLiteral<"match">;
|
|
12
|
+
data: z.ZodObject<{
|
|
13
|
+
path: z.ZodObject<{
|
|
14
|
+
text: z.ZodString;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
lines: z.ZodObject<{
|
|
17
|
+
text: z.ZodString;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
line_number: z.ZodNumber;
|
|
20
|
+
absolute_offset: z.ZodNumber;
|
|
21
|
+
submatches: z.ZodArray<z.ZodObject<{
|
|
22
|
+
match: z.ZodObject<{
|
|
23
|
+
text: z.ZodString;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
start: z.ZodNumber;
|
|
26
|
+
end: z.ZodNumber;
|
|
27
|
+
}, z.core.$strip>>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
declare const End: z.ZodObject<{
|
|
31
|
+
type: z.ZodLiteral<"end">;
|
|
32
|
+
data: z.ZodObject<{
|
|
33
|
+
path: z.ZodObject<{
|
|
34
|
+
text: z.ZodString;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
binary_offset: z.ZodNullable<z.ZodNumber>;
|
|
37
|
+
stats: z.ZodObject<{
|
|
38
|
+
elapsed: z.ZodObject<{
|
|
39
|
+
secs: z.ZodNumber;
|
|
40
|
+
nanos: z.ZodNumber;
|
|
41
|
+
human: z.ZodString;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
searches: z.ZodNumber;
|
|
44
|
+
searches_with_match: z.ZodNumber;
|
|
45
|
+
bytes_searched: z.ZodNumber;
|
|
46
|
+
bytes_printed: z.ZodNumber;
|
|
47
|
+
matched_lines: z.ZodNumber;
|
|
48
|
+
matches: z.ZodNumber;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
}, z.core.$strip>;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
declare const Summary: z.ZodObject<{
|
|
53
|
+
type: z.ZodLiteral<"summary">;
|
|
54
|
+
data: z.ZodObject<{
|
|
55
|
+
elapsed_total: z.ZodObject<{
|
|
56
|
+
human: z.ZodString;
|
|
57
|
+
nanos: z.ZodNumber;
|
|
58
|
+
secs: z.ZodNumber;
|
|
59
|
+
}, z.core.$strip>;
|
|
60
|
+
stats: z.ZodObject<{
|
|
61
|
+
elapsed: z.ZodObject<{
|
|
62
|
+
secs: z.ZodNumber;
|
|
63
|
+
nanos: z.ZodNumber;
|
|
64
|
+
human: z.ZodString;
|
|
65
|
+
}, z.core.$strip>;
|
|
66
|
+
searches: z.ZodNumber;
|
|
67
|
+
searches_with_match: z.ZodNumber;
|
|
68
|
+
bytes_searched: z.ZodNumber;
|
|
69
|
+
bytes_printed: z.ZodNumber;
|
|
70
|
+
matched_lines: z.ZodNumber;
|
|
71
|
+
matches: z.ZodNumber;
|
|
72
|
+
}, z.core.$strip>;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
declare const Result: z.ZodUnion<readonly [z.ZodObject<{
|
|
76
|
+
type: z.ZodLiteral<"begin">;
|
|
77
|
+
data: z.ZodObject<{
|
|
78
|
+
path: z.ZodObject<{
|
|
79
|
+
text: z.ZodString;
|
|
80
|
+
}, z.core.$strip>;
|
|
81
|
+
}, z.core.$strip>;
|
|
82
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
83
|
+
type: z.ZodLiteral<"match">;
|
|
84
|
+
data: z.ZodObject<{
|
|
85
|
+
path: z.ZodObject<{
|
|
86
|
+
text: z.ZodString;
|
|
87
|
+
}, z.core.$strip>;
|
|
88
|
+
lines: z.ZodObject<{
|
|
89
|
+
text: z.ZodString;
|
|
90
|
+
}, z.core.$strip>;
|
|
91
|
+
line_number: z.ZodNumber;
|
|
92
|
+
absolute_offset: z.ZodNumber;
|
|
93
|
+
submatches: z.ZodArray<z.ZodObject<{
|
|
94
|
+
match: z.ZodObject<{
|
|
95
|
+
text: z.ZodString;
|
|
96
|
+
}, z.core.$strip>;
|
|
97
|
+
start: z.ZodNumber;
|
|
98
|
+
end: z.ZodNumber;
|
|
99
|
+
}, z.core.$strip>>;
|
|
100
|
+
}, z.core.$strip>;
|
|
101
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
102
|
+
type: z.ZodLiteral<"end">;
|
|
103
|
+
data: z.ZodObject<{
|
|
104
|
+
path: z.ZodObject<{
|
|
105
|
+
text: z.ZodString;
|
|
106
|
+
}, z.core.$strip>;
|
|
107
|
+
binary_offset: z.ZodNullable<z.ZodNumber>;
|
|
108
|
+
stats: z.ZodObject<{
|
|
109
|
+
elapsed: z.ZodObject<{
|
|
110
|
+
secs: z.ZodNumber;
|
|
111
|
+
nanos: z.ZodNumber;
|
|
112
|
+
human: z.ZodString;
|
|
113
|
+
}, z.core.$strip>;
|
|
114
|
+
searches: z.ZodNumber;
|
|
115
|
+
searches_with_match: z.ZodNumber;
|
|
116
|
+
bytes_searched: z.ZodNumber;
|
|
117
|
+
bytes_printed: z.ZodNumber;
|
|
118
|
+
matched_lines: z.ZodNumber;
|
|
119
|
+
matches: z.ZodNumber;
|
|
120
|
+
}, z.core.$strip>;
|
|
121
|
+
}, z.core.$strip>;
|
|
122
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
123
|
+
type: z.ZodLiteral<"summary">;
|
|
124
|
+
data: z.ZodObject<{
|
|
125
|
+
elapsed_total: z.ZodObject<{
|
|
126
|
+
human: z.ZodString;
|
|
127
|
+
nanos: z.ZodNumber;
|
|
128
|
+
secs: z.ZodNumber;
|
|
129
|
+
}, z.core.$strip>;
|
|
130
|
+
stats: z.ZodObject<{
|
|
131
|
+
elapsed: z.ZodObject<{
|
|
132
|
+
secs: z.ZodNumber;
|
|
133
|
+
nanos: z.ZodNumber;
|
|
134
|
+
human: z.ZodString;
|
|
135
|
+
}, z.core.$strip>;
|
|
136
|
+
searches: z.ZodNumber;
|
|
137
|
+
searches_with_match: z.ZodNumber;
|
|
138
|
+
bytes_searched: z.ZodNumber;
|
|
139
|
+
bytes_printed: z.ZodNumber;
|
|
140
|
+
matched_lines: z.ZodNumber;
|
|
141
|
+
matches: z.ZodNumber;
|
|
142
|
+
}, z.core.$strip>;
|
|
143
|
+
}, z.core.$strip>;
|
|
144
|
+
}, z.core.$strip>]>;
|
|
145
|
+
export type Result = z.infer<typeof Result>;
|
|
146
|
+
export type Match = z.infer<typeof Match>;
|
|
147
|
+
export type Begin = z.infer<typeof Begin>;
|
|
148
|
+
export type End = z.infer<typeof End>;
|
|
149
|
+
export type Summary = z.infer<typeof Summary>;
|
|
150
|
+
export declare function filepath(): Promise<string>;
|
|
151
|
+
export declare function files(input: {
|
|
152
|
+
cwd: string;
|
|
153
|
+
glob?: string[];
|
|
154
|
+
hidden?: boolean;
|
|
155
|
+
follow?: boolean;
|
|
156
|
+
maxDepth?: number;
|
|
157
|
+
signal?: AbortSignal;
|
|
158
|
+
}): Promise<string[]>;
|
|
159
|
+
export declare function tree(input: {
|
|
160
|
+
cwd: string;
|
|
161
|
+
limit?: number;
|
|
162
|
+
signal?: AbortSignal;
|
|
163
|
+
}): Promise<string>;
|
|
164
|
+
export declare function search(input: {
|
|
165
|
+
cwd: string;
|
|
166
|
+
pattern: string;
|
|
167
|
+
glob?: string[];
|
|
168
|
+
limit?: number;
|
|
169
|
+
follow?: boolean;
|
|
170
|
+
}): Promise<{
|
|
171
|
+
path: {
|
|
172
|
+
text: string;
|
|
173
|
+
};
|
|
174
|
+
lines: {
|
|
175
|
+
text: string;
|
|
176
|
+
};
|
|
177
|
+
line_number: number;
|
|
178
|
+
absolute_offset: number;
|
|
179
|
+
submatches: {
|
|
180
|
+
match: {
|
|
181
|
+
text: string;
|
|
182
|
+
};
|
|
183
|
+
start: number;
|
|
184
|
+
end: number;
|
|
185
|
+
}[];
|
|
186
|
+
}[]>;
|
|
187
|
+
export {};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Match = void 0;
|
|
7
|
+
exports.filepath = filepath;
|
|
8
|
+
exports.files = files;
|
|
9
|
+
exports.tree = tree;
|
|
10
|
+
exports.search = search;
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
13
|
+
const zod_1 = __importDefault(require("zod"));
|
|
14
|
+
const bun_1 = require("bun");
|
|
15
|
+
const util_1 = require("../util");
|
|
16
|
+
const process_1 = require("../process");
|
|
17
|
+
const logger_1 = require("../logger");
|
|
18
|
+
const simple_process_1 = require("../process/simple-process");
|
|
19
|
+
const logger = new logger_1.Logger('ripgrep');
|
|
20
|
+
const Stats = zod_1.default.object({
|
|
21
|
+
elapsed: zod_1.default.object({
|
|
22
|
+
secs: zod_1.default.number(),
|
|
23
|
+
nanos: zod_1.default.number(),
|
|
24
|
+
human: zod_1.default.string()
|
|
25
|
+
}),
|
|
26
|
+
searches: zod_1.default.number(),
|
|
27
|
+
searches_with_match: zod_1.default.number(),
|
|
28
|
+
bytes_searched: zod_1.default.number(),
|
|
29
|
+
bytes_printed: zod_1.default.number(),
|
|
30
|
+
matched_lines: zod_1.default.number(),
|
|
31
|
+
matches: zod_1.default.number()
|
|
32
|
+
});
|
|
33
|
+
const Begin = zod_1.default.object({
|
|
34
|
+
type: zod_1.default.literal('begin'),
|
|
35
|
+
data: zod_1.default.object({
|
|
36
|
+
path: zod_1.default.object({
|
|
37
|
+
text: zod_1.default.string()
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
exports.Match = zod_1.default.object({
|
|
42
|
+
type: zod_1.default.literal('match'),
|
|
43
|
+
data: zod_1.default.object({
|
|
44
|
+
path: zod_1.default.object({
|
|
45
|
+
text: zod_1.default.string()
|
|
46
|
+
}),
|
|
47
|
+
lines: zod_1.default.object({
|
|
48
|
+
text: zod_1.default.string()
|
|
49
|
+
}),
|
|
50
|
+
line_number: zod_1.default.number(),
|
|
51
|
+
absolute_offset: zod_1.default.number(),
|
|
52
|
+
submatches: zod_1.default.array(zod_1.default.object({
|
|
53
|
+
match: zod_1.default.object({
|
|
54
|
+
text: zod_1.default.string()
|
|
55
|
+
}),
|
|
56
|
+
start: zod_1.default.number(),
|
|
57
|
+
end: zod_1.default.number()
|
|
58
|
+
}))
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
const End = zod_1.default.object({
|
|
62
|
+
type: zod_1.default.literal('end'),
|
|
63
|
+
data: zod_1.default.object({
|
|
64
|
+
path: zod_1.default.object({
|
|
65
|
+
text: zod_1.default.string()
|
|
66
|
+
}),
|
|
67
|
+
binary_offset: zod_1.default.number().nullable(),
|
|
68
|
+
stats: Stats
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
const Summary = zod_1.default.object({
|
|
72
|
+
type: zod_1.default.literal('summary'),
|
|
73
|
+
data: zod_1.default.object({
|
|
74
|
+
elapsed_total: zod_1.default.object({
|
|
75
|
+
human: zod_1.default.string(),
|
|
76
|
+
nanos: zod_1.default.number(),
|
|
77
|
+
secs: zod_1.default.number()
|
|
78
|
+
}),
|
|
79
|
+
stats: Stats
|
|
80
|
+
})
|
|
81
|
+
});
|
|
82
|
+
const Result = zod_1.default.union([Begin, exports.Match, End, Summary]);
|
|
83
|
+
const state = (0, util_1.lazy)(async () => {
|
|
84
|
+
if ((0, process_1.isBundledBinaryExists)('rg')) {
|
|
85
|
+
return { filepath: (0, process_1.getBundledBinaryPath)('rg') };
|
|
86
|
+
}
|
|
87
|
+
const system = Bun.which('rg');
|
|
88
|
+
if (system) {
|
|
89
|
+
const stat = await promises_1.default.stat(system).catch(() => undefined);
|
|
90
|
+
if (stat?.isFile())
|
|
91
|
+
return { filepath: system };
|
|
92
|
+
logger.warn('bun.which returned invalid rg path', { filepath: system });
|
|
93
|
+
}
|
|
94
|
+
throw new Error('rg not found');
|
|
95
|
+
});
|
|
96
|
+
async function filepath() {
|
|
97
|
+
const { filepath } = await state();
|
|
98
|
+
return filepath;
|
|
99
|
+
}
|
|
100
|
+
async function files(input) {
|
|
101
|
+
input.signal?.throwIfAborted();
|
|
102
|
+
const command = await filepath();
|
|
103
|
+
const args = ['--files', '--glob=!.git/*'];
|
|
104
|
+
if (input.follow)
|
|
105
|
+
args.push('--follow');
|
|
106
|
+
if (input.hidden !== false)
|
|
107
|
+
args.push('--hidden');
|
|
108
|
+
if (input.maxDepth !== undefined)
|
|
109
|
+
args.push(`--max-depth=${input.maxDepth}`);
|
|
110
|
+
if (input.glob) {
|
|
111
|
+
for (const g of input.glob) {
|
|
112
|
+
args.push(`--glob=${g}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Guard against invalid cwd to provide a consistent ENOENT error.
|
|
116
|
+
if (!(await promises_1.default.stat(input.cwd).catch(() => undefined))?.isDirectory()) {
|
|
117
|
+
throw Object.assign(new Error(`No such file or directory: '${input.cwd}'`), {
|
|
118
|
+
code: 'ENOENT',
|
|
119
|
+
errno: -2,
|
|
120
|
+
path: input.cwd
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
const proc = (0, simple_process_1.spawn)(command, args, {
|
|
124
|
+
cwd: input.cwd,
|
|
125
|
+
stdout: 'pipe',
|
|
126
|
+
stderr: 'ignore',
|
|
127
|
+
abort: input.signal
|
|
128
|
+
});
|
|
129
|
+
if (!proc.stdout) {
|
|
130
|
+
throw new Error('Process output not available');
|
|
131
|
+
}
|
|
132
|
+
const results = [];
|
|
133
|
+
let buffer = '';
|
|
134
|
+
const stream = proc.stdout;
|
|
135
|
+
for await (const chunk of stream) {
|
|
136
|
+
input.signal?.throwIfAborted();
|
|
137
|
+
buffer += typeof chunk === 'string' ? chunk : chunk.toString();
|
|
138
|
+
// Handle both Unix (\n) and Windows (\r\n) line endings
|
|
139
|
+
const lines = buffer.split(/\r?\n/);
|
|
140
|
+
buffer = lines.pop() || '';
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
if (line)
|
|
143
|
+
results.push(line);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (buffer)
|
|
147
|
+
results.push(buffer);
|
|
148
|
+
await proc.exited;
|
|
149
|
+
input.signal?.throwIfAborted();
|
|
150
|
+
return results;
|
|
151
|
+
}
|
|
152
|
+
async function tree(input) {
|
|
153
|
+
logger.info('tree', input);
|
|
154
|
+
const _files = await files({ cwd: input.cwd, signal: input.signal });
|
|
155
|
+
function dir(node, name) {
|
|
156
|
+
const existing = node.children.get(name);
|
|
157
|
+
if (existing)
|
|
158
|
+
return existing;
|
|
159
|
+
const next = { name, children: new Map() };
|
|
160
|
+
node.children.set(name, next);
|
|
161
|
+
return next;
|
|
162
|
+
}
|
|
163
|
+
const root = { name: '', children: new Map() };
|
|
164
|
+
for (const file of _files) {
|
|
165
|
+
if (file.includes('.baitong'))
|
|
166
|
+
continue;
|
|
167
|
+
const parts = file.split(path_1.default.sep);
|
|
168
|
+
if (parts.length < 2)
|
|
169
|
+
continue;
|
|
170
|
+
let node = root;
|
|
171
|
+
for (const part of parts.slice(0, -1)) {
|
|
172
|
+
node = dir(node, part);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function count(node) {
|
|
176
|
+
let total = 0;
|
|
177
|
+
for (const child of node.children.values()) {
|
|
178
|
+
total += 1 + count(child);
|
|
179
|
+
}
|
|
180
|
+
return total;
|
|
181
|
+
}
|
|
182
|
+
const total = count(root);
|
|
183
|
+
const limit = input.limit ?? total;
|
|
184
|
+
const lines = [];
|
|
185
|
+
const queue = [];
|
|
186
|
+
for (const child of Array.from(root.children.values()).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
187
|
+
queue.push({ node: child, path: child.name });
|
|
188
|
+
}
|
|
189
|
+
let used = 0;
|
|
190
|
+
for (let i = 0; i < queue.length && used < limit; i++) {
|
|
191
|
+
const { node, path } = queue[i];
|
|
192
|
+
lines.push(path);
|
|
193
|
+
used++;
|
|
194
|
+
for (const child of Array.from(node.children.values()).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
195
|
+
queue.push({ node: child, path: `${path}/${child.name}` });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (total > used)
|
|
199
|
+
lines.push(`[${total - used} truncated]`);
|
|
200
|
+
return lines.join('\n');
|
|
201
|
+
}
|
|
202
|
+
async function search(input) {
|
|
203
|
+
const args = [`${await filepath()}`, '--json', '--hidden', "--glob='!.git/*'"];
|
|
204
|
+
if (input.follow)
|
|
205
|
+
args.push('--follow');
|
|
206
|
+
if (input.glob) {
|
|
207
|
+
for (const g of input.glob) {
|
|
208
|
+
args.push(`--glob=${g}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (input.limit) {
|
|
212
|
+
args.push(`--max-count=${input.limit}`);
|
|
213
|
+
}
|
|
214
|
+
args.push('--');
|
|
215
|
+
args.push(input.pattern);
|
|
216
|
+
const command = args.join(' ');
|
|
217
|
+
const result = await (0, bun_1.$) `${{ raw: command }}`.cwd(input.cwd).quiet().nothrow();
|
|
218
|
+
if (result.exitCode !== 0) {
|
|
219
|
+
return [];
|
|
220
|
+
}
|
|
221
|
+
// Handle both Unix (\n) and Windows (\r\n) line endings
|
|
222
|
+
const lines = result.text().trim().split(/\r?\n/).filter(Boolean);
|
|
223
|
+
// Parse JSON lines from ripgrep output
|
|
224
|
+
return lines
|
|
225
|
+
.map(line => JSON.parse(line))
|
|
226
|
+
.map(parsed => Result.parse(parsed))
|
|
227
|
+
.filter(r => r.type === 'match')
|
|
228
|
+
.map(r => r.data);
|
|
229
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class Logger {
|
|
2
|
+
private name;
|
|
3
|
+
private isProduction;
|
|
4
|
+
constructor(name: string);
|
|
5
|
+
setProductionMode(isProduction: boolean): void;
|
|
6
|
+
info(...data: any[]): void;
|
|
7
|
+
error(...data: any[]): void;
|
|
8
|
+
warn(...data: any[]): void;
|
|
9
|
+
log(...data: any[]): void;
|
|
10
|
+
debug(...data: any[]): void;
|
|
11
|
+
verbose(...data: any[]): void;
|
|
12
|
+
}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Logger = void 0;
|
|
4
|
+
class Logger {
|
|
5
|
+
constructor(name) {
|
|
6
|
+
this.isProduction = false;
|
|
7
|
+
this.name = name;
|
|
8
|
+
}
|
|
9
|
+
setProductionMode(isProduction) {
|
|
10
|
+
this.isProduction = isProduction;
|
|
11
|
+
}
|
|
12
|
+
info(...data) {
|
|
13
|
+
console.info(`[${this.name}][INFO]`, ...data);
|
|
14
|
+
}
|
|
15
|
+
error(...data) {
|
|
16
|
+
console.error(`[${this.name}][ERROR]`, ...data);
|
|
17
|
+
}
|
|
18
|
+
warn(...data) {
|
|
19
|
+
console.warn(`[${this.name}][WARN]`, ...data);
|
|
20
|
+
}
|
|
21
|
+
log(...data) {
|
|
22
|
+
if (this.isProduction) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log(`[${this.name}][LOG]`, ...data);
|
|
26
|
+
}
|
|
27
|
+
debug(...data) {
|
|
28
|
+
if (this.isProduction) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
console.debug(`[${this.name}][DEBUG]`, ...data);
|
|
32
|
+
}
|
|
33
|
+
verbose(...data) {
|
|
34
|
+
if (this.isProduction) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.log(`[${this.name}][VERBOSE]`, ...data);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.Logger = Logger;
|
|
@@ -1,9 +1,42 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
3
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
37
|
};
|
|
6
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.SimpleProcess = void 0;
|
|
7
40
|
exports.windowsToGitBashPath = windowsToGitBashPath;
|
|
8
41
|
exports.gitBashToWindowsPath = gitBashToWindowsPath;
|
|
9
42
|
exports.findGitBash = findGitBash;
|
|
@@ -11,8 +44,9 @@ exports.isBundledBinaryExists = isBundledBinaryExists;
|
|
|
11
44
|
exports.getBundledBinaryPath = getBundledBinaryPath;
|
|
12
45
|
exports.getBundledBinaryEnvs = getBundledBinaryEnvs;
|
|
13
46
|
const path_1 = __importDefault(require("path"));
|
|
14
|
-
const config_1 = require("
|
|
47
|
+
const config_1 = require("../config");
|
|
15
48
|
const fs_1 = __importDefault(require("fs"));
|
|
49
|
+
exports.SimpleProcess = __importStar(require("./simple-process"));
|
|
16
50
|
/**
|
|
17
51
|
* 将 Windows 文件路径转换为 Git Bash 路径格式
|
|
18
52
|
* @param path - Windows 格式的文件路径 (如 "C:\\Users")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
export type Stdio = 'inherit' | 'pipe' | 'ignore';
|
|
3
|
+
export interface Options {
|
|
4
|
+
cwd?: string;
|
|
5
|
+
env?: NodeJS.ProcessEnv | null;
|
|
6
|
+
stdin?: Stdio;
|
|
7
|
+
stdout?: Stdio;
|
|
8
|
+
stderr?: Stdio;
|
|
9
|
+
abort?: AbortSignal;
|
|
10
|
+
kill?: NodeJS.Signals | number;
|
|
11
|
+
timeout?: number;
|
|
12
|
+
}
|
|
13
|
+
export type Child = ChildProcess & {
|
|
14
|
+
exited: Promise<number>;
|
|
15
|
+
};
|
|
16
|
+
export declare function spawn(command: string, args: readonly string[], options?: Options): Child;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.spawn = spawn;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
function spawn(command, args, options = {}) {
|
|
6
|
+
options.abort?.throwIfAborted();
|
|
7
|
+
const proc = (0, child_process_1.spawn)(command, args, {
|
|
8
|
+
cwd: options.cwd,
|
|
9
|
+
env: options.env === null ? {} : options.env ? { ...process.env, ...options.env } : undefined,
|
|
10
|
+
stdio: [options.stdin ?? 'ignore', options.stdout ?? 'ignore', options.stderr ?? 'ignore']
|
|
11
|
+
});
|
|
12
|
+
let aborted = false;
|
|
13
|
+
let timer;
|
|
14
|
+
const abort = () => {
|
|
15
|
+
if (aborted)
|
|
16
|
+
return;
|
|
17
|
+
if (proc.exitCode !== null || proc.signalCode !== null)
|
|
18
|
+
return;
|
|
19
|
+
aborted = true;
|
|
20
|
+
proc.kill(options.kill ?? 'SIGTERM');
|
|
21
|
+
const timeout = options.timeout ?? 5_000;
|
|
22
|
+
if (timeout <= 0)
|
|
23
|
+
return;
|
|
24
|
+
timer = setTimeout(() => {
|
|
25
|
+
proc.kill('SIGKILL');
|
|
26
|
+
}, timeout);
|
|
27
|
+
};
|
|
28
|
+
const exited = new Promise((resolve, reject) => {
|
|
29
|
+
const done = () => {
|
|
30
|
+
options.abort?.removeEventListener('abort', abort);
|
|
31
|
+
if (timer)
|
|
32
|
+
clearTimeout(timer);
|
|
33
|
+
};
|
|
34
|
+
proc.once('exit', (exitCode, signal) => {
|
|
35
|
+
done();
|
|
36
|
+
resolve(exitCode ?? (signal ? 1 : 0));
|
|
37
|
+
});
|
|
38
|
+
proc.once('error', error => {
|
|
39
|
+
done();
|
|
40
|
+
reject(error);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
if (options.abort) {
|
|
44
|
+
options.abort.addEventListener('abort', abort, { once: true });
|
|
45
|
+
if (options.abort.aborted)
|
|
46
|
+
abort();
|
|
47
|
+
}
|
|
48
|
+
const child = proc;
|
|
49
|
+
child.exited = exited;
|
|
50
|
+
return child;
|
|
51
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
36
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.Tool = void 0;
|
|
40
|
+
exports.Tool = __importStar(require("./tool"));
|
|
41
|
+
__exportStar(require("./question"), exports);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import z from 'zod';
|
|
3
|
+
import { Info as ToolInfo } from './tool';
|
|
4
|
+
import { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
5
|
+
import { ServerRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
6
|
+
import { ServerNotification } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
declare const Questions: z.ZodArray<z.ZodObject<{
|
|
8
|
+
header: z.ZodString;
|
|
9
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
10
|
+
options: z.ZodArray<z.ZodObject<{
|
|
11
|
+
label: z.ZodString;
|
|
12
|
+
description: z.ZodString;
|
|
13
|
+
}, z.core.$strip>>;
|
|
14
|
+
question: z.ZodString;
|
|
15
|
+
}, z.core.$strip>>;
|
|
16
|
+
type Questions = z.infer<typeof Questions>;
|
|
17
|
+
export declare class Question {
|
|
18
|
+
static Option: z.ZodObject<{
|
|
19
|
+
label: z.ZodString;
|
|
20
|
+
description: z.ZodString;
|
|
21
|
+
}, z.core.$strip>;
|
|
22
|
+
static Info: z.ZodObject<{
|
|
23
|
+
question: z.ZodString;
|
|
24
|
+
header: z.ZodString;
|
|
25
|
+
options: z.ZodArray<z.ZodObject<{
|
|
26
|
+
label: z.ZodString;
|
|
27
|
+
description: z.ZodString;
|
|
28
|
+
}, z.core.$strip>>;
|
|
29
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
30
|
+
custom: z.ZodOptional<z.ZodBoolean>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
static Questions: z.ZodArray<z.ZodObject<{
|
|
33
|
+
header: z.ZodString;
|
|
34
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
35
|
+
options: z.ZodArray<z.ZodObject<{
|
|
36
|
+
label: z.ZodString;
|
|
37
|
+
description: z.ZodString;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
question: z.ZodString;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
static Answer: z.ZodArray<z.ZodString>;
|
|
42
|
+
static Answers: z.ZodArray<z.ZodArray<z.ZodString>>;
|
|
43
|
+
static InfoSchema: z.ZodObject<{
|
|
44
|
+
method: z.ZodLiteral<"question:ask">;
|
|
45
|
+
params: z.ZodObject<{
|
|
46
|
+
requestId: z.ZodString;
|
|
47
|
+
toolInfo: z.ZodObject<{
|
|
48
|
+
sessionId: z.ZodString;
|
|
49
|
+
messageId: z.ZodString;
|
|
50
|
+
callId: z.ZodString;
|
|
51
|
+
}, z.core.$strip>;
|
|
52
|
+
questions: z.ZodArray<z.ZodObject<{
|
|
53
|
+
header: z.ZodString;
|
|
54
|
+
multiple: z.ZodOptional<z.ZodBoolean>;
|
|
55
|
+
options: z.ZodArray<z.ZodObject<{
|
|
56
|
+
label: z.ZodString;
|
|
57
|
+
description: z.ZodString;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
question: z.ZodString;
|
|
60
|
+
}, z.core.$strip>>;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
}, z.core.$strip>;
|
|
63
|
+
static AnswerSchema: z.ZodObject<{
|
|
64
|
+
method: z.ZodLiteral<"question:answer">;
|
|
65
|
+
params: z.ZodObject<{
|
|
66
|
+
requestId: z.ZodString;
|
|
67
|
+
toolInfo: z.ZodObject<{
|
|
68
|
+
sessionId: z.ZodString;
|
|
69
|
+
messageId: z.ZodString;
|
|
70
|
+
callId: z.ZodString;
|
|
71
|
+
}, z.core.$strip>;
|
|
72
|
+
answers: z.ZodArray<z.ZodArray<z.ZodString>>;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
}, z.core.$strip>;
|
|
75
|
+
private _server;
|
|
76
|
+
constructor(server: McpServer);
|
|
77
|
+
/**
|
|
78
|
+
* Ask questions to the user and wait for the answers.
|
|
79
|
+
* @param questions Questions to ask
|
|
80
|
+
* @param toolInfo ToolInfo
|
|
81
|
+
* @returns Answers
|
|
82
|
+
*/
|
|
83
|
+
ask(questions: Questions, toolInfo: ToolInfo, extra: RequestHandlerExtra<ServerRequest, ServerNotification>): Promise<{
|
|
84
|
+
title: string;
|
|
85
|
+
output: string;
|
|
86
|
+
metadata: {
|
|
87
|
+
answers: string[][];
|
|
88
|
+
};
|
|
89
|
+
}>;
|
|
90
|
+
}
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Question = void 0;
|
|
7
|
+
const zod_1 = __importDefault(require("zod"));
|
|
8
|
+
const tool_1 = require("./tool");
|
|
9
|
+
const Option = zod_1.default
|
|
10
|
+
.object({
|
|
11
|
+
label: zod_1.default.string().describe('Display text (1-5 words, concise)'),
|
|
12
|
+
description: zod_1.default.string().describe('Explanation of choice')
|
|
13
|
+
})
|
|
14
|
+
.meta({
|
|
15
|
+
ref: 'QuestionOption'
|
|
16
|
+
});
|
|
17
|
+
const Info = zod_1.default
|
|
18
|
+
.object({
|
|
19
|
+
question: zod_1.default.string().describe('Complete question'),
|
|
20
|
+
header: zod_1.default.string().describe('Very short label (max 30 chars)'),
|
|
21
|
+
options: zod_1.default.array(Option).describe('Available choices'),
|
|
22
|
+
multiple: zod_1.default.boolean().optional().describe('Allow selecting multiple choices'),
|
|
23
|
+
custom: zod_1.default.boolean().optional().describe('Allow typing a custom answer (default: true)')
|
|
24
|
+
})
|
|
25
|
+
.meta({
|
|
26
|
+
ref: 'QuestionInfo'
|
|
27
|
+
});
|
|
28
|
+
const Questions = zod_1.default.array(Info.omit({ custom: true })).describe('Questions to ask');
|
|
29
|
+
const Answer = zod_1.default.array(zod_1.default.string()).meta({
|
|
30
|
+
ref: 'QuestionAnswer'
|
|
31
|
+
});
|
|
32
|
+
const Answers = zod_1.default
|
|
33
|
+
.array(Answer)
|
|
34
|
+
.describe('User answers in order of questions (each answer is an array of selected labels)');
|
|
35
|
+
const InfoSchema = zod_1.default.object({
|
|
36
|
+
method: zod_1.default.literal('question:ask'),
|
|
37
|
+
params: zod_1.default.object({
|
|
38
|
+
requestId: zod_1.default.string().describe('Request ID'),
|
|
39
|
+
toolInfo: tool_1.Info,
|
|
40
|
+
questions: Questions
|
|
41
|
+
})
|
|
42
|
+
});
|
|
43
|
+
const AnswerSchema = zod_1.default.object({
|
|
44
|
+
method: zod_1.default.literal('question:answer'),
|
|
45
|
+
params: zod_1.default.object({
|
|
46
|
+
requestId: zod_1.default.string().describe('Request ID'),
|
|
47
|
+
toolInfo: tool_1.Info,
|
|
48
|
+
answers: Answers
|
|
49
|
+
})
|
|
50
|
+
});
|
|
51
|
+
class Question {
|
|
52
|
+
constructor(server) {
|
|
53
|
+
this._server = server;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Ask questions to the user and wait for the answers.
|
|
57
|
+
* @param questions Questions to ask
|
|
58
|
+
* @param toolInfo ToolInfo
|
|
59
|
+
* @returns Answers
|
|
60
|
+
*/
|
|
61
|
+
async ask(questions, toolInfo, extra) {
|
|
62
|
+
if (questions.length === 0) {
|
|
63
|
+
throw new Error('At least one question is required');
|
|
64
|
+
}
|
|
65
|
+
for (const question of questions) {
|
|
66
|
+
if (question.options.length === 0) {
|
|
67
|
+
throw new Error('At least one option is required for each question');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const requestId = (0, tool_1.createRequestId)(extra.requestId);
|
|
71
|
+
// 开始询问问题
|
|
72
|
+
let progressTimer;
|
|
73
|
+
try {
|
|
74
|
+
const startTime = Date.now();
|
|
75
|
+
const maxWaitTime = 10 * 60 * 1000;
|
|
76
|
+
const progressToken = extra._meta?.progressToken;
|
|
77
|
+
// 不断重置超时时间,防止用户长时间不回答
|
|
78
|
+
const heartbeat = () => {
|
|
79
|
+
if (!progressToken)
|
|
80
|
+
return;
|
|
81
|
+
progressTimer = setTimeout(() => {
|
|
82
|
+
const waitTime = Date.now() - startTime;
|
|
83
|
+
this._server.server.notification({
|
|
84
|
+
method: 'notifications/progress',
|
|
85
|
+
params: {
|
|
86
|
+
total: maxWaitTime,
|
|
87
|
+
progress: waitTime,
|
|
88
|
+
progressToken
|
|
89
|
+
}
|
|
90
|
+
}, { relatedRequestId: extra.requestId });
|
|
91
|
+
if (waitTime <= maxWaitTime) {
|
|
92
|
+
heartbeat();
|
|
93
|
+
}
|
|
94
|
+
}, 10 * 1000);
|
|
95
|
+
};
|
|
96
|
+
heartbeat();
|
|
97
|
+
// 发送问题请求并等待回答
|
|
98
|
+
const response = await this._server.server.request({
|
|
99
|
+
method: 'question:ask',
|
|
100
|
+
params: {
|
|
101
|
+
questions,
|
|
102
|
+
requestId,
|
|
103
|
+
toolInfo
|
|
104
|
+
}
|
|
105
|
+
}, AnswerSchema, {
|
|
106
|
+
timeout: maxWaitTime, // 10分钟超时
|
|
107
|
+
maxTotalTimeout: maxWaitTime,
|
|
108
|
+
relatedRequestId: extra.requestId
|
|
109
|
+
});
|
|
110
|
+
const answers = response.params.answers;
|
|
111
|
+
function format(answer) {
|
|
112
|
+
if (!answer?.length)
|
|
113
|
+
return 'Unanswered';
|
|
114
|
+
return answer.join(', ');
|
|
115
|
+
}
|
|
116
|
+
const formatted = questions
|
|
117
|
+
.map((q, i) => `"${q.question}"="${format(answers[i])}"`)
|
|
118
|
+
.join(', ');
|
|
119
|
+
const output = `User has answered your questions: ${formatted}. You can now continue with the user's answers in mind.`;
|
|
120
|
+
return {
|
|
121
|
+
title: `Asked ${questions.length} question${questions.length > 1 ? 's' : ''}`,
|
|
122
|
+
output,
|
|
123
|
+
metadata: {
|
|
124
|
+
answers
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
clearTimeout(progressTimer);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.Question = Question;
|
|
134
|
+
Question.Option = Option;
|
|
135
|
+
Question.Info = Info;
|
|
136
|
+
Question.Questions = Questions;
|
|
137
|
+
Question.Answer = Answer;
|
|
138
|
+
Question.Answers = Answers;
|
|
139
|
+
Question.InfoSchema = InfoSchema;
|
|
140
|
+
Question.AnswerSchema = AnswerSchema;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
import { RequestId } from '@modelcontextprotocol/sdk/types.js';
|
|
3
|
+
export declare const Info: z.ZodObject<{
|
|
4
|
+
sessionId: z.ZodString;
|
|
5
|
+
messageId: z.ZodString;
|
|
6
|
+
callId: z.ZodString;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
export type Info = z.infer<typeof Info>;
|
|
9
|
+
export declare function createRequestId(requestId: RequestId): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.Info = void 0;
|
|
7
|
+
exports.createRequestId = createRequestId;
|
|
8
|
+
const zod_1 = __importDefault(require("zod"));
|
|
9
|
+
const uuid_1 = require("uuid");
|
|
10
|
+
exports.Info = zod_1.default
|
|
11
|
+
.object({
|
|
12
|
+
sessionId: zod_1.default.string().describe('Session ID'),
|
|
13
|
+
messageId: zod_1.default.string().describe('Message ID'),
|
|
14
|
+
callId: zod_1.default.string().describe('Tool Call ID')
|
|
15
|
+
})
|
|
16
|
+
.meta({ ref: 'ToolInfo' });
|
|
17
|
+
function createRequestId(requestId) {
|
|
18
|
+
return (0, uuid_1.v5)(`${requestId}-${Date.now()}`, uuid_1.v5.DNS);
|
|
19
|
+
}
|
package/dist/util.d.ts
CHANGED
package/dist/util.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
1
|
"use strict";
|
|
3
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
3
|
exports.lazy = lazy;
|
|
@@ -13,15 +12,9 @@ function lazy(fn) {
|
|
|
13
12
|
const result = () => {
|
|
14
13
|
if (loaded)
|
|
15
14
|
return value;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
catch (e) {
|
|
22
|
-
// Don't mark as loaded if initialization failed
|
|
23
|
-
throw e;
|
|
24
|
-
}
|
|
15
|
+
value = fn();
|
|
16
|
+
loaded = true;
|
|
17
|
+
return value;
|
|
25
18
|
};
|
|
26
19
|
result.reset = () => {
|
|
27
20
|
loaded = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baitong-dev/mcp-helpers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
],
|
|
13
13
|
"description": "mcp-helpers",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@modelcontextprotocol/sdk": "^1.25.1"
|
|
15
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
16
|
+
"uuid": "^11.0.5"
|
|
16
17
|
},
|
|
17
18
|
"devDependencies": {
|
|
18
19
|
"typescript": "^5.9.2"
|
package/dist/file.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
"use strict";
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
-
};
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.isDir = isDir;
|
|
8
|
-
exports.isSubdirectory = isSubdirectory;
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
/**
|
|
11
|
-
* Check if a path is a directory.
|
|
12
|
-
* @param path The path to check
|
|
13
|
-
* @returns Whether the path is a directory
|
|
14
|
-
*/
|
|
15
|
-
async function isDir(path) {
|
|
16
|
-
try {
|
|
17
|
-
const stat = await Bun.file(path).stat();
|
|
18
|
-
return stat.isDirectory();
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* 检查一个目录是否是另一个目录的子目录
|
|
26
|
-
* @param parent - 父目录路径
|
|
27
|
-
* @param child - 要检查的子目录路径
|
|
28
|
-
* @param options - 配置选项
|
|
29
|
-
* @param options.includeSelf - 是否将自身视为子目录
|
|
30
|
-
* @returns - 同步返回 boolean,异步返回 Promise
|
|
31
|
-
*/
|
|
32
|
-
function isSubdirectory(parent, child, { includeSelf = false }) {
|
|
33
|
-
const parentPath = path_1.default.resolve(parent);
|
|
34
|
-
const childPath = path_1.default.isAbsolute(child) ? child : path_1.default.join(parentPath, child);
|
|
35
|
-
const relative = path_1.default.relative(parentPath, childPath);
|
|
36
|
-
if (includeSelf && childPath === parentPath) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
return (relative && !relative.startsWith('..') && !path_1.default.isAbsolute(relative)) || false;
|
|
40
|
-
}
|