@saccolabs/tars 1.36.0 → 1.37.1
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/channels/channel-manager.d.ts +5 -0
- package/dist/channels/channel-manager.js +7 -0
- package/dist/channels/channel-manager.js.map +1 -1
- package/dist/channels/tui/tui-channel.d.ts +98 -0
- package/dist/channels/tui/tui-channel.js +362 -0
- package/dist/channels/tui/tui-channel.js.map +1 -0
- package/dist/channels/tui/tui-renderer.d.ts +49 -0
- package/dist/channels/tui/tui-renderer.js +112 -0
- package/dist/channels/tui/tui-renderer.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +9 -0
- package/dist/cli/commands/chat.js +51 -0
- package/dist/cli/commands/chat.js.map +1 -0
- package/dist/cli/commands/refresh.js +7 -1
- package/dist/cli/commands/refresh.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +9 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/suppress-warnings.d.ts +1 -0
- package/dist/cli/suppress-warnings.js +9 -0
- package/dist/cli/suppress-warnings.js.map +1 -0
- package/dist/supervisor/bootstrap.d.ts +48 -0
- package/dist/supervisor/bootstrap.js +602 -0
- package/dist/supervisor/bootstrap.js.map +1 -0
- package/dist/supervisor/main.js +5 -537
- package/dist/supervisor/main.js.map +1 -1
- package/dist/supervisor/mcp-bridge.js +10 -1
- package/dist/supervisor/mcp-bridge.js.map +1 -1
- package/dist/utils/logger.d.ts +5 -0
- package/dist/utils/logger.js +23 -0
- package/dist/utils/logger.js.map +1 -1
- package/extensions/search/dist/search-helper.js +43 -0
- package/extensions/search/dist/server.js +111 -0
- package/extensions/search/package-lock.json +1485 -0
- package/extensions/search/package.json +21 -0
- package/extensions/search/src/search-helper.ts +62 -0
- package/extensions/search/src/server.ts +127 -0
- package/extensions/search/tars-extension.json +11 -0
- package/extensions/search/tsconfig.json +14 -0
- package/package.json +2 -1
package/dist/utils/logger.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import winston from 'winston';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
2
4
|
/**
|
|
3
5
|
* Centralized logger for the supervisor application
|
|
4
6
|
*/
|
|
@@ -11,5 +13,26 @@ export const logger = winston.createLogger({
|
|
|
11
13
|
})),
|
|
12
14
|
transports: [new winston.transports.Console()]
|
|
13
15
|
});
|
|
16
|
+
/**
|
|
17
|
+
* Reconfigures the logger for TUI Chat Mode, diverting all output
|
|
18
|
+
* to a file to prevent polluting the interactive terminal.
|
|
19
|
+
*/
|
|
20
|
+
export function configureChatLogging(homeDir) {
|
|
21
|
+
logger.clear();
|
|
22
|
+
const logDir = path.join(homeDir, 'logs');
|
|
23
|
+
if (!fs.existsSync(logDir)) {
|
|
24
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
25
|
+
}
|
|
26
|
+
logger.add(new winston.transports.File({
|
|
27
|
+
filename: path.join(logDir, 'chat.log'),
|
|
28
|
+
level: process.env.LOG_LEVEL || 'info',
|
|
29
|
+
format: winston.format.combine(winston.format.timestamp({
|
|
30
|
+
format: 'YYYY-MM-DD HH:mm:ss'
|
|
31
|
+
}), winston.format.uncolorize(), // No ANSI color codes in log files
|
|
32
|
+
winston.format.printf(({ timestamp, level, message }) => {
|
|
33
|
+
return `${timestamp} [${level}]: ${message}`;
|
|
34
|
+
}))
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
14
37
|
export default logger;
|
|
15
38
|
//# sourceMappingURL=logger.js.map
|
package/dist/utils/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IACvC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;IACtC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC1B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;QACrB,MAAM,EAAE,qBAAqB;KAChC,CAAC,EACF,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,EACzB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;QACpD,OAAO,GAAG,SAAS,KAAK,KAAK,MAAM,OAAO,EAAE,CAAC;IACjD,CAAC,CAAC,CACL;IACD,UAAU,EAAE,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;CACjD,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAChD,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,CAAC,GAAG,CACN,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;QACxB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;QACvC,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACtC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAC1B,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;YACrB,MAAM,EAAE,qBAAqB;SAChC,CAAC,EACF,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,mCAAmC;QAChE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE;YACpD,OAAO,GAAG,SAAS,KAAK,KAAK,MAAM,OAAO,EAAE,CAAC;QACjD,CAAC,CAAC,CACL;KACJ,CAAC,CACL,CAAC;AACN,CAAC;AAED,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { search } from 'duck-duck-scrape';
|
|
2
|
+
import { parseHTML } from 'linkedom';
|
|
3
|
+
import TurndownService from 'turndown';
|
|
4
|
+
/**
|
|
5
|
+
* Executes a DuckDuckGo search query and returns mapped search results.
|
|
6
|
+
*/
|
|
7
|
+
export async function performWebSearch(query, limit = 5) {
|
|
8
|
+
const response = await search(query);
|
|
9
|
+
const rawResults = response.results || [];
|
|
10
|
+
return rawResults.slice(0, limit).map((r) => ({
|
|
11
|
+
title: r.title || '',
|
|
12
|
+
url: r.url || '',
|
|
13
|
+
snippet: r.description || r.snippet || ''
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Fetches HTML from a URL, removes noise/boilerplate, and converts it to clean Markdown.
|
|
18
|
+
*/
|
|
19
|
+
export async function fetchWebPage(url, maxLength = 15000) {
|
|
20
|
+
const res = await fetch(url, {
|
|
21
|
+
headers: {
|
|
22
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
if (!res.ok) {
|
|
26
|
+
throw new Error(`Failed to fetch page: HTTP ${res.status} ${res.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
const html = await res.text();
|
|
29
|
+
const { document } = parseHTML(html);
|
|
30
|
+
// Strip boilerplate, navigation, and script/style tags
|
|
31
|
+
const elementsToRemove = document.querySelectorAll('script, style, noscript, iframe, nav, header, footer, aside, svg, img, form, button');
|
|
32
|
+
elementsToRemove.forEach((el) => el.remove());
|
|
33
|
+
const bodyHtml = document.body ? document.body.innerHTML : document.documentElement.innerHTML;
|
|
34
|
+
const turndown = new TurndownService({
|
|
35
|
+
headingStyle: 'atx',
|
|
36
|
+
codeBlockStyle: 'fenced'
|
|
37
|
+
});
|
|
38
|
+
let markdown = turndown.turndown(bodyHtml).trim();
|
|
39
|
+
if (markdown.length > maxLength) {
|
|
40
|
+
markdown = markdown.substring(0, maxLength) + '\n\n...[Content truncated for brevity]...';
|
|
41
|
+
}
|
|
42
|
+
return markdown;
|
|
43
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
+
import { performWebSearch, fetchWebPage } from './search-helper.js';
|
|
5
|
+
const server = new Server({
|
|
6
|
+
name: 'tars-search',
|
|
7
|
+
version: '1.0.0'
|
|
8
|
+
}, {
|
|
9
|
+
capabilities: {
|
|
10
|
+
tools: {}
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
/**
|
|
14
|
+
* Tool Definitions
|
|
15
|
+
*/
|
|
16
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
17
|
+
return {
|
|
18
|
+
tools: [
|
|
19
|
+
{
|
|
20
|
+
name: 'web_search',
|
|
21
|
+
description: 'Search the web using DuckDuckGo (free, keyless) and return a list of matches.',
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
query: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
description: 'The search query to execute (e.g. "latest version of Node.js")'
|
|
28
|
+
},
|
|
29
|
+
limit: {
|
|
30
|
+
type: 'number',
|
|
31
|
+
description: 'Maximum number of results to return (default: 5, max: 10)',
|
|
32
|
+
minimum: 1,
|
|
33
|
+
maximum: 10
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
required: ['query']
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'web_fetch',
|
|
41
|
+
description: 'Fetch the text/Markdown content of a specific web URL, stripped of header/footer boilerplate.',
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
url: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'The URL to fetch content from'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
required: ['url']
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Tool Handlers
|
|
58
|
+
*/
|
|
59
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
60
|
+
const { name, arguments: args } = request.params;
|
|
61
|
+
try {
|
|
62
|
+
switch (name) {
|
|
63
|
+
case 'web_search': {
|
|
64
|
+
const { query, limit = 5 } = args;
|
|
65
|
+
if (!query)
|
|
66
|
+
throw new Error('Query is required.');
|
|
67
|
+
const results = await performWebSearch(query, limit);
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: JSON.stringify(results, null, 2)
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
case 'web_fetch': {
|
|
78
|
+
const { url } = args;
|
|
79
|
+
if (!url)
|
|
80
|
+
throw new Error('URL is required.');
|
|
81
|
+
const markdown = await fetchWebPage(url);
|
|
82
|
+
return {
|
|
83
|
+
content: [
|
|
84
|
+
{
|
|
85
|
+
type: 'text',
|
|
86
|
+
text: markdown
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
default:
|
|
92
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: 'text', text: `❌ Error: ${error.message}` }],
|
|
98
|
+
isError: true
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// Start Server
|
|
103
|
+
async function main() {
|
|
104
|
+
const transport = new StdioServerTransport();
|
|
105
|
+
await server.connect(transport);
|
|
106
|
+
console.error('tars-search MCP server running on stdio');
|
|
107
|
+
}
|
|
108
|
+
main().catch((error) => {
|
|
109
|
+
console.error('Server error:', error);
|
|
110
|
+
process.exit(1);
|
|
111
|
+
});
|