staff-mcp 1.0.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.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +89 -0
  3. package/README_zh.md +89 -0
  4. package/dist/constants.d.ts +2 -0
  5. package/dist/constants.js +3 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +26 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/security.d.ts +16 -0
  11. package/dist/security.js +43 -0
  12. package/dist/security.js.map +1 -0
  13. package/dist/server.d.ts +9 -0
  14. package/dist/server.js +25 -0
  15. package/dist/server.js.map +1 -0
  16. package/dist/src/constants.d.ts +2 -0
  17. package/dist/src/constants.js +3 -0
  18. package/dist/src/constants.js.map +1 -0
  19. package/dist/src/index.d.ts +2 -0
  20. package/dist/src/index.js +29 -0
  21. package/dist/src/index.js.map +1 -0
  22. package/dist/src/security.d.ts +21 -0
  23. package/dist/src/security.js +51 -0
  24. package/dist/src/security.js.map +1 -0
  25. package/dist/src/server.d.ts +10 -0
  26. package/dist/src/server.js +34 -0
  27. package/dist/src/server.js.map +1 -0
  28. package/dist/src/tools/file-tools.d.ts +6 -0
  29. package/dist/src/tools/file-tools.js +230 -0
  30. package/dist/src/tools/file-tools.js.map +1 -0
  31. package/dist/src/tools/lsp-tools.d.ts +10 -0
  32. package/dist/src/tools/lsp-tools.js +124 -0
  33. package/dist/src/tools/lsp-tools.js.map +1 -0
  34. package/dist/src/tools/shell-tools.d.ts +6 -0
  35. package/dist/src/tools/shell-tools.js +138 -0
  36. package/dist/src/tools/shell-tools.js.map +1 -0
  37. package/dist/src/tools/skill-manager.d.ts +14 -0
  38. package/dist/src/tools/skill-manager.js +97 -0
  39. package/dist/src/tools/skill-manager.js.map +1 -0
  40. package/dist/src/tools/skill-tools.d.ts +3 -0
  41. package/dist/src/tools/skill-tools.js +117 -0
  42. package/dist/src/tools/skill-tools.js.map +1 -0
  43. package/dist/src/tools/system-tools.d.ts +6 -0
  44. package/dist/src/tools/system-tools.js +36 -0
  45. package/dist/src/tools/system-tools.js.map +1 -0
  46. package/dist/src/transports/http.d.ts +5 -0
  47. package/dist/src/transports/http.js +58 -0
  48. package/dist/src/transports/http.js.map +1 -0
  49. package/dist/src/transports/stdio.d.ts +2 -0
  50. package/dist/src/transports/stdio.js +18 -0
  51. package/dist/src/transports/stdio.js.map +1 -0
  52. package/dist/tests/security.test.d.ts +1 -0
  53. package/dist/tests/security.test.js +21 -0
  54. package/dist/tests/security.test.js.map +1 -0
  55. package/dist/tools/file-tools.d.ts +6 -0
  56. package/dist/tools/file-tools.js +102 -0
  57. package/dist/tools/file-tools.js.map +1 -0
  58. package/dist/tools/lsp-tools.d.ts +6 -0
  59. package/dist/tools/lsp-tools.js +70 -0
  60. package/dist/tools/lsp-tools.js.map +1 -0
  61. package/dist/tools/shell-tools.d.ts +6 -0
  62. package/dist/tools/shell-tools.js +39 -0
  63. package/dist/tools/shell-tools.js.map +1 -0
  64. package/dist/transports/http.d.ts +5 -0
  65. package/dist/transports/http.js +58 -0
  66. package/dist/transports/http.js.map +1 -0
  67. package/dist/transports/stdio.d.ts +2 -0
  68. package/dist/transports/stdio.js +18 -0
  69. package/dist/transports/stdio.js.map +1 -0
  70. package/package.json +37 -0
@@ -0,0 +1,230 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { z } from "zod";
4
+ import { CHARACTER_LIMIT } from "../constants.js";
5
+ import { getPathDiagnostics } from "./lsp-tools.js";
6
+ /**
7
+ * Registers file-related tools using the latest registerTool API.
8
+ */
9
+ export function registerFileTools(server, security) {
10
+ // read_file
11
+ server.registerTool("read_file", {
12
+ description: "Read the content of a file from the allowed workspace.",
13
+ inputSchema: z.object({
14
+ path: z.string().describe("Relative path from the workspace to the file to read."),
15
+ startLine: z.number().optional().describe("1-based line number to start reading from."),
16
+ endLine: z.number().optional().describe("1-based line number to end reading at (inclusive)."),
17
+ }).strict(),
18
+ }, async ({ path: filePath, startLine, endLine }) => {
19
+ try {
20
+ const validatedPath = security.resolveAndValidatePath(filePath);
21
+ const fullContent = await fs.readFile(validatedPath, "utf-8");
22
+ const lines = fullContent.split(/\r?\n/);
23
+ let contentLines = lines;
24
+ let prefix = "";
25
+ if (startLine !== undefined || endLine !== undefined) {
26
+ const start = startLine ? Math.max(0, startLine - 1) : 0;
27
+ const end = endLine ? Math.min(lines.length, endLine) : lines.length;
28
+ contentLines = lines.slice(start, end);
29
+ prefix = `Showing lines ${start + 1}-${end} of ${lines.length}:\n`;
30
+ }
31
+ let content = contentLines.join("\n");
32
+ if (content.length > CHARACTER_LIMIT) {
33
+ content = content.substring(0, CHARACTER_LIMIT) + "\n\n...[Content truncated for brevity]";
34
+ }
35
+ return {
36
+ content: [{ type: "text", text: prefix + content }],
37
+ };
38
+ }
39
+ catch (error) {
40
+ return {
41
+ content: [{ type: "text", text: `Error reading file: ${error.message}` }],
42
+ isError: true,
43
+ };
44
+ }
45
+ });
46
+ // edit_file_by_replace
47
+ server.registerTool("edit_file_by_replace", {
48
+ description: "Replace a specific block of text in a file with new content. Use this for precise edits.",
49
+ inputSchema: z.object({
50
+ path: z.string().describe("Path to the file to edit."),
51
+ oldText: z.string().describe("The exact text block to be replaced. Be as specific as possible to avoid wrong matches."),
52
+ newText: z.string().describe("The new text content to replace with."),
53
+ }).strict(),
54
+ }, async ({ path: filePath, oldText, newText }) => {
55
+ try {
56
+ const validatedPath = security.resolveAndValidatePath(filePath);
57
+ const content = await fs.readFile(validatedPath, "utf-8");
58
+ // Simple fuzzy match: try exact first, then trimmed
59
+ let index = content.indexOf(oldText);
60
+ if (index === -1) {
61
+ // Try fuzzy: trim and normalize line endings
62
+ const normalize = (s) => s.replace(/\r\n/g, "\n").trim();
63
+ const normalizedContent = normalize(content);
64
+ const normalizedOld = normalize(oldText);
65
+ if (normalizedContent.includes(normalizedOld)) {
66
+ // If normalized matches, we need to find the actual position in the original content
67
+ // For simplicity, if exact match fails but normalized would work, we warn the model
68
+ return {
69
+ content: [{ type: "text", text: `Error: The oldText provided did not match exactly. Please ensure whitespace and line endings match or provide more context.` }],
70
+ isError: true,
71
+ };
72
+ }
73
+ return {
74
+ content: [{ type: "text", text: `Error: Could not find the text block to replace in ${filePath}. Check for typos or provide more context.` }],
75
+ isError: true,
76
+ };
77
+ }
78
+ const updatedContent = content.slice(0, index) + newText + content.slice(index + oldText.length);
79
+ await fs.writeFile(validatedPath, updatedContent, "utf-8");
80
+ let response = `Successfully updated ${filePath}`;
81
+ // Add diagnostics feedback for TS files
82
+ if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) {
83
+ const diagnostics = await getPathDiagnostics(filePath, security);
84
+ if (diagnostics) {
85
+ response += `\n\nWarning: TypeScript diagnostics found after editing:\n${diagnostics}`;
86
+ }
87
+ }
88
+ return {
89
+ content: [{ type: "text", text: response }],
90
+ };
91
+ }
92
+ catch (error) {
93
+ return {
94
+ content: [{ type: "text", text: `Error editing file: ${error.message}` }],
95
+ isError: true,
96
+ };
97
+ }
98
+ });
99
+ // write_file
100
+ server.registerTool("write_file", {
101
+ description: "Write or overwrite a file in the allowed workspace.",
102
+ inputSchema: z.object({
103
+ path: z.string().describe("Path to the file to write."),
104
+ content: z.string().describe("Content to write into the file."),
105
+ }).strict(),
106
+ }, async ({ path: filePath, content }) => {
107
+ try {
108
+ const validatedPath = security.resolveAndValidatePath(filePath);
109
+ await fs.mkdir(path.dirname(validatedPath), { recursive: true });
110
+ await fs.writeFile(validatedPath, content, "utf-8");
111
+ let response = `Successfully wrote file: ${filePath}`;
112
+ // Add diagnostics feedback for TS files
113
+ if (filePath.endsWith(".ts") || filePath.endsWith(".tsx")) {
114
+ const diagnostics = await getPathDiagnostics(filePath, security);
115
+ if (diagnostics) {
116
+ response += `\n\nWarning: TypeScript diagnostics found after writing:\n${diagnostics}`;
117
+ }
118
+ }
119
+ return {
120
+ content: [{ type: "text", text: response }],
121
+ };
122
+ }
123
+ catch (error) {
124
+ return {
125
+ content: [{ type: "text", text: `Error writing file: ${error.message}` }],
126
+ isError: true,
127
+ };
128
+ }
129
+ });
130
+ // delete_file
131
+ server.registerTool("delete_file", {
132
+ description: "Delete a file from the allowed workspace.",
133
+ inputSchema: z.object({
134
+ path: z.string().describe("Path to the file to delete."),
135
+ }).strict(),
136
+ }, async ({ path: filePath }) => {
137
+ try {
138
+ const validatedPath = security.resolveAndValidatePath(filePath);
139
+ await fs.unlink(validatedPath);
140
+ return {
141
+ content: [{ type: "text", text: `Successfully deleted file: ${filePath}` }],
142
+ };
143
+ }
144
+ catch (error) {
145
+ return {
146
+ content: [{ type: "text", text: `Error deleting file: ${error.message}` }],
147
+ isError: true,
148
+ };
149
+ }
150
+ });
151
+ // list_dir
152
+ server.registerTool("list_dir", {
153
+ description: "List files and directories within a specific path.",
154
+ inputSchema: z.object({
155
+ path: z.string().default(".").describe("Path to list (defaults to workspace root)."),
156
+ }).strict(),
157
+ }, async ({ path: dirPath }) => {
158
+ try {
159
+ const validatedPath = security.resolveAndValidatePath(dirPath);
160
+ const entries = await fs.readdir(validatedPath, { withFileTypes: true });
161
+ const result = entries.map(entry => {
162
+ return `${entry.isDirectory() ? "[DIR]" : "[FILE]"} ${entry.name}`;
163
+ }).join("\n");
164
+ return {
165
+ content: [{ type: "text", text: result || "(Directory is empty)" }],
166
+ };
167
+ }
168
+ catch (error) {
169
+ return {
170
+ content: [{ type: "text", text: `Error listing directory: ${error.message}` }],
171
+ isError: true,
172
+ };
173
+ }
174
+ });
175
+ // search_file_content
176
+ server.registerTool("search_file_content", {
177
+ description: "Perform a global regex search for a specific string across all files in the project.",
178
+ inputSchema: z.object({
179
+ regex: z.string().describe("The regular expression pattern to search for."),
180
+ includeGlob: z.string().optional().describe("Glob pattern to limit the search (e.g. src/**/*.ts)."),
181
+ }).strict(),
182
+ }, async ({ regex, includeGlob }) => {
183
+ try {
184
+ const searchRegex = new RegExp(regex, "g");
185
+ const results = [];
186
+ const baseDir = security.resolveAndValidatePath(".");
187
+ async function searchRecursively(currentDir) {
188
+ const entries = await fs.readdir(currentDir, { withFileTypes: true });
189
+ for (const entry of entries) {
190
+ const fullPath = path.join(currentDir, entry.name);
191
+ // Simple check to skip node_modules and .git
192
+ if (entry.name === "node_modules" || entry.name === ".git")
193
+ continue;
194
+ if (entry.isDirectory()) {
195
+ await searchRecursively(fullPath);
196
+ }
197
+ else if (entry.isFile()) {
198
+ const relPath = path.relative(baseDir, fullPath);
199
+ // Basic glob matching (simple version)
200
+ if (includeGlob && !relPath.includes(includeGlob.replace(/\*/g, "")))
201
+ continue;
202
+ const content = await fs.readFile(fullPath, "utf-8");
203
+ let match;
204
+ while ((match = searchRegex.exec(content)) !== null) {
205
+ // Find line number using cross-platform line endings
206
+ const lineNum = content.substring(0, match.index).split(/\r?\n/).length;
207
+ const context = content.split(/\r?\n/)[lineNum - 1];
208
+ results.push(`${relPath}:${lineNum} - ${context.trim()}`);
209
+ if (results.length > 100) {
210
+ results.push("... [Search results truncated after 100 matches]");
211
+ return;
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+ await searchRecursively(baseDir);
218
+ return {
219
+ content: [{ type: "text", text: results.join("\n") || "No matches found." }],
220
+ };
221
+ }
222
+ catch (error) {
223
+ return {
224
+ content: [{ type: "text", text: `Error during search: ${error.message}` }],
225
+ isError: true,
226
+ };
227
+ }
228
+ });
229
+ }
230
+ //# sourceMappingURL=file-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-tools.js","sourceRoot":"","sources":["../../../src/tools/file-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { SecurityManager } from "../security.js";
3
+ /**
4
+ * Internal helper to get diagnostics for a specific path.
5
+ */
6
+ export declare function getPathDiagnostics(checkPath: string, security: SecurityManager): Promise<string>;
7
+ /**
8
+ * Registers LSP-related tools using the latest registerTool API.
9
+ */
10
+ export declare function registerLspTools(server: McpServer, security: SecurityManager): void;
@@ -0,0 +1,124 @@
1
+ import { Project } from "ts-morph";
2
+ import { z } from "zod";
3
+ /**
4
+ * Internal helper to get diagnostics for a specific path.
5
+ */
6
+ export async function getPathDiagnostics(checkPath, security) {
7
+ const validatedPath = security.resolveAndValidatePath(checkPath);
8
+ const project = new Project();
9
+ project.addSourceFilesAtPaths([
10
+ validatedPath.endsWith(".ts") || validatedPath.endsWith(".js")
11
+ ? validatedPath
12
+ : `${validatedPath}/**/*.{ts,js,tsx,jsx}`
13
+ ]);
14
+ const diagnostics = project.getPreEmitDiagnostics();
15
+ return diagnostics.map(diag => {
16
+ const messageText = diag.getMessageText();
17
+ const line = diag.getLineNumber();
18
+ const file = diag.getSourceFile()?.getFilePath() || "Unknown file";
19
+ const formattedMessage = typeof messageText === "string" ? messageText : messageText.getMessageText();
20
+ return `[${file}:${line}] ${formattedMessage}`;
21
+ }).join("\n");
22
+ }
23
+ /**
24
+ * Registers LSP-related tools using the latest registerTool API.
25
+ */
26
+ export function registerLspTools(server, security) {
27
+ // get_document_symbols
28
+ server.registerTool("get_document_symbols", {
29
+ description: "Extract high-level symbols (classes, functions, interfaces) from a TypeScript file.",
30
+ inputSchema: z.object({
31
+ path: z.string().describe("TypeScript/JavaScript file path to analyze."),
32
+ }).strict(),
33
+ }, async ({ path: filePath }) => {
34
+ try {
35
+ const validatedPath = security.resolveAndValidatePath(filePath);
36
+ const project = new Project();
37
+ const sourceFile = project.addSourceFileAtPath(validatedPath);
38
+ const symbols = [];
39
+ sourceFile.getClasses().forEach(c => symbols.push(`[Class] ${c.getName()} (Line ${c.getStartLineNumber()})`));
40
+ sourceFile.getInterfaces().forEach(i => symbols.push(`[Interface] ${i.getName()} (Line ${i.getStartLineNumber()})`));
41
+ sourceFile.getFunctions().forEach(f => symbols.push(`[Function] ${f.getName()} (Line ${f.getStartLineNumber()})`));
42
+ sourceFile.getEnums().forEach(e => symbols.push(`[Enum] ${e.getName()} (Line ${e.getStartLineNumber()})`));
43
+ sourceFile.getTypeAliases().forEach(t => symbols.push(`[TypeAlias] ${t.getName()} (Line ${t.getStartLineNumber()})`));
44
+ return {
45
+ content: [{ type: "text", text: symbols.join("\n") || "(No significant symbols found)" }],
46
+ };
47
+ }
48
+ catch (error) {
49
+ return {
50
+ content: [{ type: "text", text: `LSP Error: ${error.message}` }],
51
+ isError: true,
52
+ };
53
+ }
54
+ });
55
+ // get_diagnostics
56
+ server.registerTool("get_diagnostics", {
57
+ description: "Get TypeScript diagnostics/errors for a file or directory.",
58
+ inputSchema: z.object({
59
+ path: z.string().describe("File or directory path to check for TypeScript diagnostics."),
60
+ }).strict(),
61
+ }, async ({ path: checkPath }) => {
62
+ try {
63
+ const output = await getPathDiagnostics(checkPath, security);
64
+ return {
65
+ content: [{ type: "text", text: output || "No TypeScript diagnostics found." }],
66
+ };
67
+ }
68
+ catch (error) {
69
+ return {
70
+ content: [{ type: "text", text: `LSP Error: ${error.message}` }],
71
+ isError: true,
72
+ };
73
+ }
74
+ });
75
+ // find_references
76
+ server.registerTool("find_references", {
77
+ description: "Find all references to a symbol (function, class, variable) in the project.",
78
+ inputSchema: z.object({
79
+ path: z.string().describe("File path where the symbol is defined."),
80
+ symbolName: z.string().describe("The name of the symbol to find references for."),
81
+ }).strict(),
82
+ }, async ({ path: filePath, symbolName }) => {
83
+ try {
84
+ const validatedPath = security.resolveAndValidatePath(filePath);
85
+ const project = new Project();
86
+ project.addSourceFilesAtPaths("**/*.ts");
87
+ const sourceFile = project.getSourceFile(validatedPath);
88
+ if (!sourceFile) {
89
+ throw new Error(`File not found: ${filePath}`);
90
+ }
91
+ // Search for the symbol
92
+ let node;
93
+ // Simple search by name in classes, functions, etc.
94
+ const allNodes = sourceFile.getDescendantsOfKind(1 /* Identifier */);
95
+ node = allNodes.find(n => n.getText() === symbolName);
96
+ if (!node) {
97
+ return {
98
+ content: [{ type: "text", text: `Could not find symbol "${symbolName}" in ${filePath}` }],
99
+ isError: true,
100
+ };
101
+ }
102
+ const references = node.findReferences();
103
+ const results = [];
104
+ for (const reference of references) {
105
+ for (const ref of reference.getReferences()) {
106
+ const refSourceFile = ref.getSourceFile();
107
+ const line = refSourceFile.getLineAndColumnAtPos(ref.getTextSpan().getStart()).line;
108
+ const relPath = security.resolveAndValidatePath(refSourceFile.getFilePath()); // Re-validate or just use relative
109
+ results.push(`${refSourceFile.getFilePath()}:${line}`);
110
+ }
111
+ }
112
+ return {
113
+ content: [{ type: "text", text: results.join("\n") || "No references found." }],
114
+ };
115
+ }
116
+ catch (error) {
117
+ return {
118
+ content: [{ type: "text", text: `LSP Error: ${error.message}` }],
119
+ isError: true,
120
+ };
121
+ }
122
+ });
123
+ }
124
+ //# sourceMappingURL=lsp-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lsp-tools.js","sourceRoot":"","sources":["../../../src/tools/lsp-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { SecurityManager } from "../security.js";
3
+ /**
4
+ * Registers shell-related tools using the latest registerTool API.
5
+ */
6
+ export declare function registerShellTools(server: McpServer, security: SecurityManager): void;
@@ -0,0 +1,138 @@
1
+ import { exec, spawn } from "child_process";
2
+ import { promisify } from "util";
3
+ import { z } from "zod";
4
+ import { DEFAULT_TIMEOUT } from "../constants.js";
5
+ const execAsync = promisify(exec);
6
+ // Store for background tasks
7
+ const backgroundTasks = new Map();
8
+ /**
9
+ * Registers shell-related tools using the latest registerTool API.
10
+ */
11
+ export function registerShellTools(server, security) {
12
+ server.registerTool("execute_command", {
13
+ description: "Execute a shell command in a specified directory (sandboxed).",
14
+ inputSchema: z.object({
15
+ command: z.string().describe("The shell command to execute."),
16
+ cwd: z.string().optional().describe("Directory to execute command from (must be allowed). Defaults to the workspace root."),
17
+ }).strict(),
18
+ }, async ({ command, cwd }) => {
19
+ try {
20
+ const validatedCwd = security.validateDirectory(cwd || ".");
21
+ const { stdout, stderr } = await execAsync(command, {
22
+ cwd: validatedCwd,
23
+ timeout: DEFAULT_TIMEOUT,
24
+ });
25
+ // Truncate output if too long
26
+ const formatOutput = (out) => {
27
+ const lines = out.split(/\r?\n/);
28
+ if (lines.length > 500) {
29
+ return lines.slice(0, 100).join("\n") +
30
+ `\n\n...[${lines.length - 200} lines truncated for brevity]...\n\n` +
31
+ lines.slice(-100).join("\n");
32
+ }
33
+ return out;
34
+ };
35
+ const output = [
36
+ stdout ? `STDOUT:\n${formatOutput(stdout)}` : "",
37
+ stderr ? `STDERR:\n${formatOutput(stderr)}` : "",
38
+ ].filter(Boolean).join("\n\n");
39
+ return {
40
+ content: [{ type: "text", text: output || "(No output from command)" }],
41
+ };
42
+ }
43
+ catch (error) {
44
+ // If timed out or error occurred, still try to return what we have or a meaningful error
45
+ return {
46
+ content: [{ type: "text", text: `Command execution failed or timed out: ${error.message}` }],
47
+ isError: true,
48
+ };
49
+ }
50
+ });
51
+ // start_background_task
52
+ server.registerTool("start_background_task", {
53
+ description: "Start a background process (e.g. dev server) in the workspace.",
54
+ inputSchema: z.object({
55
+ command: z.string().describe("The shell command to start."),
56
+ cwd: z.string().optional().describe("Directory to start from (defaults to workspace root)."),
57
+ }).strict(),
58
+ }, async ({ command, cwd }) => {
59
+ try {
60
+ const validatedCwd = security.validateDirectory(cwd || ".");
61
+ // Use a single string for spawn when shell: true is enabled.
62
+ // This is more cross-platform and handles arguments/quotes better.
63
+ const child = spawn(command, {
64
+ cwd: validatedCwd,
65
+ shell: true,
66
+ // On Windows, shell: true uses cmd.exe /c.
67
+ // On Unix, shell: true uses /bin/sh -c.
68
+ });
69
+ const taskId = `task_${Math.random().toString(36).substring(2, 9)}`;
70
+ const logs = [];
71
+ child.stdout?.on("data", (data) => {
72
+ logs.push(data.toString());
73
+ if (logs.length > 1000)
74
+ logs.shift(); // Keep last 1000 lines
75
+ });
76
+ child.stderr?.on("data", (data) => {
77
+ logs.push(`ERR: ${data.toString()}`);
78
+ if (logs.length > 1000)
79
+ logs.shift();
80
+ });
81
+ backgroundTasks.set(taskId, { process: child, logs });
82
+ child.on("exit", (code) => {
83
+ logs.push(`[Process exited with code ${code}]`);
84
+ // Note: We don't remove from map yet so logs can be read
85
+ });
86
+ return {
87
+ content: [{ type: "text", text: `Task started with ID: ${taskId}` }],
88
+ };
89
+ }
90
+ catch (error) {
91
+ return {
92
+ content: [{ type: "text", text: `Error starting task: ${error.message}` }],
93
+ isError: true,
94
+ };
95
+ }
96
+ });
97
+ // get_background_task_logs
98
+ server.registerTool("get_background_task_logs", {
99
+ description: "Read the latest logs from a running or recently exited background task.",
100
+ inputSchema: z.object({
101
+ taskId: z.string().describe("The ID of the task."),
102
+ tail: z.number().optional().default(100).describe("Number of lines to return from the end."),
103
+ }).strict(),
104
+ }, async ({ taskId, tail }) => {
105
+ const task = backgroundTasks.get(taskId);
106
+ if (!task) {
107
+ return {
108
+ content: [{ type: "text", text: `Task ${taskId} not found.` }],
109
+ isError: true,
110
+ };
111
+ }
112
+ const logs = task.logs.slice(-tail);
113
+ return {
114
+ content: [{ type: "text", text: logs.join("") || "(No logs yet)" }],
115
+ };
116
+ });
117
+ // kill_background_task
118
+ server.registerTool("kill_background_task", {
119
+ description: "Terminate a background task by its ID.",
120
+ inputSchema: z.object({
121
+ taskId: z.string().describe("The ID of the task to kill."),
122
+ }).strict(),
123
+ }, async ({ taskId }) => {
124
+ const task = backgroundTasks.get(taskId);
125
+ if (!task) {
126
+ return {
127
+ content: [{ type: "text", text: `Task ${taskId} not found.` }],
128
+ isError: true,
129
+ };
130
+ }
131
+ task.process.kill();
132
+ backgroundTasks.delete(taskId);
133
+ return {
134
+ content: [{ type: "text", text: `Task ${taskId} killed.` }],
135
+ };
136
+ });
137
+ }
138
+ //# sourceMappingURL=shell-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-tools.js","sourceRoot":"","sources":["../../../src/tools/shell-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface SkillInfo {
2
+ name: string;
3
+ description: string;
4
+ location: string;
5
+ content: string;
6
+ }
7
+ export declare class SkillManager {
8
+ private static readonly SEARCH_DIRS;
9
+ private static readonly SKILL_SUBDIRS;
10
+ static loadSkills(workingDir: string): Record<string, SkillInfo>;
11
+ private static scanDirSync;
12
+ private static addSkillSync;
13
+ private static parseMarkdown;
14
+ }