@hasna/terminal 3.7.1 → 3.7.2
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/mcp/server.js +19 -5
- package/package.json +1 -1
- package/src/mcp/server.ts +18 -5
package/dist/mcp/server.js
CHANGED
|
@@ -54,6 +54,15 @@ function exec(command, cwd, timeout, allowRewrite = false) {
|
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
|
+
/** Resolve a path — supports relative paths against cwd, just like a shell */
|
|
58
|
+
function resolvePath(p, cwd) {
|
|
59
|
+
if (!p)
|
|
60
|
+
return cwd ?? process.cwd();
|
|
61
|
+
if (p.startsWith("/") || p.startsWith("~"))
|
|
62
|
+
return p;
|
|
63
|
+
const { join } = require("path");
|
|
64
|
+
return join(cwd ?? process.cwd(), p);
|
|
65
|
+
}
|
|
57
66
|
// ── server ───────────────────────────────────────────────────────────────────
|
|
58
67
|
export function createServer() {
|
|
59
68
|
const server = new McpServer({
|
|
@@ -483,8 +492,9 @@ export function createServer() {
|
|
|
483
492
|
offset: z.number().optional().describe("Start line (0-indexed)"),
|
|
484
493
|
limit: z.number().optional().describe("Max lines to return"),
|
|
485
494
|
summarize: z.boolean().optional().describe("Return AI summary instead of full content (saves ~90% tokens)"),
|
|
486
|
-
}, async ({ path, offset, limit, summarize }) => {
|
|
495
|
+
}, async ({ path: rawPath, offset, limit, summarize }) => {
|
|
487
496
|
const start = Date.now();
|
|
497
|
+
const path = resolvePath(rawPath);
|
|
488
498
|
const result = cachedRead(path, { offset, limit });
|
|
489
499
|
if (summarize && result.content.length > 500) {
|
|
490
500
|
// AI-native file summary — ask directly what the file does
|
|
@@ -560,8 +570,9 @@ export function createServer() {
|
|
|
560
570
|
// ── symbols: file structure outline ───────────────────────────────────────
|
|
561
571
|
server.tool("symbols", "Get a structured outline of any source file — functions, classes, methods, interfaces, exports with line numbers. Works for ALL languages (TypeScript, Python, Go, Rust, Java, C#, Ruby, PHP, etc.). AI-powered, not regex.", {
|
|
562
572
|
path: z.string().describe("File path to extract symbols from"),
|
|
563
|
-
}, async ({ path:
|
|
573
|
+
}, async ({ path: rawPath }) => {
|
|
564
574
|
const start = Date.now();
|
|
575
|
+
const filePath = resolvePath(rawPath);
|
|
565
576
|
const result = cachedRead(filePath, {});
|
|
566
577
|
if (!result.content || result.content.startsWith("Error:")) {
|
|
567
578
|
return { content: [{ type: "text", text: JSON.stringify({ error: `Cannot read ${filePath}` }) }] };
|
|
@@ -602,8 +613,9 @@ Line numbers must be accurate (count from 1).`,
|
|
|
602
613
|
server.tool("read_symbol", "Read a specific function, class, or interface by name from a source file. Returns only the code block — not the entire file. Saves 70-85% tokens vs reading the whole file.", {
|
|
603
614
|
path: z.string().describe("Source file path"),
|
|
604
615
|
name: z.string().describe("Symbol name (function, class, interface)"),
|
|
605
|
-
}, async ({ path:
|
|
616
|
+
}, async ({ path: rawPath, name }) => {
|
|
606
617
|
const start = Date.now();
|
|
618
|
+
const filePath = resolvePath(rawPath);
|
|
607
619
|
const result = cachedRead(filePath, {});
|
|
608
620
|
if (!result.content || result.content.startsWith("Error:")) {
|
|
609
621
|
return { content: [{ type: "text", text: JSON.stringify({ error: `Cannot read ${filePath}` }) }] };
|
|
@@ -711,8 +723,9 @@ Match by function name, class name, method name (including ClassName.method), in
|
|
|
711
723
|
find: z.string().describe("Text to find (exact match)"),
|
|
712
724
|
replace: z.string().describe("Replacement text"),
|
|
713
725
|
all: z.boolean().optional().describe("Replace all occurrences (default: first only)"),
|
|
714
|
-
}, async ({ file, find, replace, all }) => {
|
|
726
|
+
}, async ({ file: rawFile, find, replace, all }) => {
|
|
715
727
|
const start = Date.now();
|
|
728
|
+
const file = resolvePath(rawFile);
|
|
716
729
|
const { readFileSync, writeFileSync } = await import("fs");
|
|
717
730
|
try {
|
|
718
731
|
let content = readFileSync(file, "utf8");
|
|
@@ -738,8 +751,9 @@ Match by function name, class name, method name (including ClassName.method), in
|
|
|
738
751
|
file: z.string().describe("File path to search in"),
|
|
739
752
|
items: z.array(z.string()).describe("Names or patterns to look up"),
|
|
740
753
|
context: z.number().optional().describe("Lines of context around each match (default: 3)"),
|
|
741
|
-
}, async ({ file, items, context }) => {
|
|
754
|
+
}, async ({ file: rawFile, items, context }) => {
|
|
742
755
|
const start = Date.now();
|
|
756
|
+
const file = resolvePath(rawFile);
|
|
743
757
|
const { readFileSync } = await import("fs");
|
|
744
758
|
try {
|
|
745
759
|
const content = readFileSync(file, "utf8");
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -58,6 +58,14 @@ function exec(command: string, cwd?: string, timeout?: number, allowRewrite: boo
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/** Resolve a path — supports relative paths against cwd, just like a shell */
|
|
62
|
+
function resolvePath(p: string, cwd?: string): string {
|
|
63
|
+
if (!p) return cwd ?? process.cwd();
|
|
64
|
+
if (p.startsWith("/") || p.startsWith("~")) return p;
|
|
65
|
+
const { join } = require("path");
|
|
66
|
+
return join(cwd ?? process.cwd(), p);
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
// ── server ───────────────────────────────────────────────────────────────────
|
|
62
70
|
|
|
63
71
|
export function createServer(): McpServer {
|
|
@@ -685,8 +693,9 @@ export function createServer(): McpServer {
|
|
|
685
693
|
limit: z.number().optional().describe("Max lines to return"),
|
|
686
694
|
summarize: z.boolean().optional().describe("Return AI summary instead of full content (saves ~90% tokens)"),
|
|
687
695
|
},
|
|
688
|
-
async ({ path, offset, limit, summarize }) => {
|
|
696
|
+
async ({ path: rawPath, offset, limit, summarize }) => {
|
|
689
697
|
const start = Date.now();
|
|
698
|
+
const path = resolvePath(rawPath);
|
|
690
699
|
const result = cachedRead(path, { offset, limit });
|
|
691
700
|
|
|
692
701
|
if (summarize && result.content.length > 500) {
|
|
@@ -782,8 +791,9 @@ export function createServer(): McpServer {
|
|
|
782
791
|
{
|
|
783
792
|
path: z.string().describe("File path to extract symbols from"),
|
|
784
793
|
},
|
|
785
|
-
async ({ path:
|
|
794
|
+
async ({ path: rawPath }) => {
|
|
786
795
|
const start = Date.now();
|
|
796
|
+
const filePath = resolvePath(rawPath);
|
|
787
797
|
const result = cachedRead(filePath, {});
|
|
788
798
|
if (!result.content || result.content.startsWith("Error:")) {
|
|
789
799
|
return { content: [{ type: "text" as const, text: JSON.stringify({ error: `Cannot read ${filePath}` }) }] };
|
|
@@ -836,8 +846,9 @@ Line numbers must be accurate (count from 1).`,
|
|
|
836
846
|
path: z.string().describe("Source file path"),
|
|
837
847
|
name: z.string().describe("Symbol name (function, class, interface)"),
|
|
838
848
|
},
|
|
839
|
-
async ({ path:
|
|
849
|
+
async ({ path: rawPath, name }) => {
|
|
840
850
|
const start = Date.now();
|
|
851
|
+
const filePath = resolvePath(rawPath);
|
|
841
852
|
const result = cachedRead(filePath, {});
|
|
842
853
|
if (!result.content || result.content.startsWith("Error:")) {
|
|
843
854
|
return { content: [{ type: "text" as const, text: JSON.stringify({ error: `Cannot read ${filePath}` }) }] };
|
|
@@ -966,8 +977,9 @@ Match by function name, class name, method name (including ClassName.method), in
|
|
|
966
977
|
replace: z.string().describe("Replacement text"),
|
|
967
978
|
all: z.boolean().optional().describe("Replace all occurrences (default: first only)"),
|
|
968
979
|
},
|
|
969
|
-
async ({ file, find, replace, all }) => {
|
|
980
|
+
async ({ file: rawFile, find, replace, all }) => {
|
|
970
981
|
const start = Date.now();
|
|
982
|
+
const file = resolvePath(rawFile);
|
|
971
983
|
const { readFileSync, writeFileSync } = await import("fs");
|
|
972
984
|
try {
|
|
973
985
|
let content = readFileSync(file, "utf8");
|
|
@@ -997,8 +1009,9 @@ Match by function name, class name, method name (including ClassName.method), in
|
|
|
997
1009
|
items: z.array(z.string()).describe("Names or patterns to look up"),
|
|
998
1010
|
context: z.number().optional().describe("Lines of context around each match (default: 3)"),
|
|
999
1011
|
},
|
|
1000
|
-
async ({ file, items, context }) => {
|
|
1012
|
+
async ({ file: rawFile, items, context }) => {
|
|
1001
1013
|
const start = Date.now();
|
|
1014
|
+
const file = resolvePath(rawFile);
|
|
1002
1015
|
const { readFileSync } = await import("fs");
|
|
1003
1016
|
try {
|
|
1004
1017
|
const content = readFileSync(file, "utf8");
|