@luckydraw/cumulus 0.27.41 → 0.28.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/gateway/adapters/webchat.d.ts +5 -7
- package/dist/gateway/adapters/webchat.d.ts.map +1 -1
- package/dist/gateway/adapters/webchat.js +204 -57
- package/dist/gateway/adapters/webchat.js.map +1 -1
- package/dist/gateway/config.d.ts +48 -0
- package/dist/gateway/config.d.ts.map +1 -1
- package/dist/gateway/config.js +90 -0
- package/dist/gateway/config.js.map +1 -1
- package/dist/gateway/daemon.d.ts.map +1 -1
- package/dist/gateway/daemon.js +272 -28
- package/dist/gateway/daemon.js.map +1 -1
- package/dist/gateway/gateway-agents-mcp.js +570 -31
- package/dist/gateway/gateway-agents-mcp.js.map +1 -1
- package/dist/gateway/hooks.d.ts +101 -0
- package/dist/gateway/hooks.d.ts.map +1 -0
- package/dist/gateway/hooks.js +200 -0
- package/dist/gateway/hooks.js.map +1 -0
- package/dist/gateway/scheduler.d.ts +50 -0
- package/dist/gateway/scheduler.d.ts.map +1 -0
- package/dist/gateway/scheduler.js +263 -0
- package/dist/gateway/scheduler.js.map +1 -0
- package/dist/gateway/server.d.ts +16 -1
- package/dist/gateway/server.d.ts.map +1 -1
- package/dist/gateway/server.js +451 -22
- package/dist/gateway/server.js.map +1 -1
- package/dist/gateway/static/blex.min.js +74 -17
- package/dist/gateway/static/chat.html +1 -4
- package/dist/gateway/static/dashboard.html +151 -0
- package/dist/gateway/static/dashboard.js +229 -0
- package/dist/gateway/static/widget.js +656 -460
- package/dist/index.d.ts +13 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/agentic-loop.d.ts +124 -0
- package/dist/lib/agentic-loop.d.ts.map +1 -0
- package/dist/lib/agentic-loop.js +338 -0
- package/dist/lib/agentic-loop.js.map +1 -0
- package/dist/lib/config.d.ts +28 -15
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +47 -41
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/gateway.d.ts +34 -3
- package/dist/lib/gateway.d.ts.map +1 -1
- package/dist/lib/gateway.js +584 -37
- package/dist/lib/gateway.js.map +1 -1
- package/dist/lib/huggingface-provider.d.ts +26 -0
- package/dist/lib/huggingface-provider.d.ts.map +1 -0
- package/dist/lib/huggingface-provider.js +338 -0
- package/dist/lib/huggingface-provider.js.map +1 -0
- package/dist/lib/provider.d.ts +71 -0
- package/dist/lib/provider.d.ts.map +1 -0
- package/dist/lib/provider.js +90 -0
- package/dist/lib/provider.js.map +1 -0
- package/dist/lib/tools/ask-user-question.d.ts +14 -0
- package/dist/lib/tools/ask-user-question.d.ts.map +1 -0
- package/dist/lib/tools/ask-user-question.js +74 -0
- package/dist/lib/tools/ask-user-question.js.map +1 -0
- package/dist/lib/tools/bash.d.ts +6 -0
- package/dist/lib/tools/bash.d.ts.map +1 -0
- package/dist/lib/tools/bash.js +85 -0
- package/dist/lib/tools/bash.js.map +1 -0
- package/dist/lib/tools/edit.d.ts +6 -0
- package/dist/lib/tools/edit.d.ts.map +1 -0
- package/dist/lib/tools/edit.js +79 -0
- package/dist/lib/tools/edit.js.map +1 -0
- package/dist/lib/tools/glob.d.ts +6 -0
- package/dist/lib/tools/glob.d.ts.map +1 -0
- package/dist/lib/tools/glob.js +91 -0
- package/dist/lib/tools/glob.js.map +1 -0
- package/dist/lib/tools/grep.d.ts +6 -0
- package/dist/lib/tools/grep.d.ts.map +1 -0
- package/dist/lib/tools/grep.js +110 -0
- package/dist/lib/tools/grep.js.map +1 -0
- package/dist/lib/tools/index.d.ts +29 -0
- package/dist/lib/tools/index.d.ts.map +1 -0
- package/dist/lib/tools/index.js +52 -0
- package/dist/lib/tools/index.js.map +1 -0
- package/dist/lib/tools/read.d.ts +6 -0
- package/dist/lib/tools/read.d.ts.map +1 -0
- package/dist/lib/tools/read.js +80 -0
- package/dist/lib/tools/read.js.map +1 -0
- package/dist/lib/tools/tool-search.d.ts +30 -0
- package/dist/lib/tools/tool-search.d.ts.map +1 -0
- package/dist/lib/tools/tool-search.js +108 -0
- package/dist/lib/tools/tool-search.js.map +1 -0
- package/dist/lib/tools/web-fetch.d.ts +9 -0
- package/dist/lib/tools/web-fetch.d.ts.map +1 -0
- package/dist/lib/tools/web-fetch.js +114 -0
- package/dist/lib/tools/web-fetch.js.map +1 -0
- package/dist/lib/tools/web-search.d.ts +12 -0
- package/dist/lib/tools/web-search.d.ts.map +1 -0
- package/dist/lib/tools/web-search.js +89 -0
- package/dist/lib/tools/web-search.js.map +1 -0
- package/dist/lib/tools/write.d.ts +6 -0
- package/dist/lib/tools/write.d.ts.map +1 -0
- package/dist/lib/tools/write.js +44 -0
- package/dist/lib/tools/write.js.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Provider abstraction.
|
|
3
|
+
*
|
|
4
|
+
* Normalizes the interface across different LLM APIs so the agentic loop
|
|
5
|
+
* doesn't care who generates the response.
|
|
6
|
+
*/
|
|
7
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
8
|
+
// ─── Anthropic Provider ──────────────────────────────────────────────────────
|
|
9
|
+
const DEFAULT_MAX_TOKENS = 16384;
|
|
10
|
+
const MAX_RETRIES = 3;
|
|
11
|
+
const RETRY_DELAYS = [1000, 2000, 4000]; // exponential backoff
|
|
12
|
+
export class AnthropicProvider {
|
|
13
|
+
client;
|
|
14
|
+
constructor(apiKey) {
|
|
15
|
+
this.client = new Anthropic({
|
|
16
|
+
apiKey: apiKey || process.env.ANTHROPIC_API_KEY,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async chat(options) {
|
|
20
|
+
const { model, system, messages, tools, maxTokens, onEvent, signal } = options;
|
|
21
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
22
|
+
try {
|
|
23
|
+
return await this._streamChat(model, system, messages, tools, maxTokens, onEvent, signal);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const status = err.status;
|
|
27
|
+
const isRetryable = status === 429 || status === 529 || status === 500;
|
|
28
|
+
const isOversize = status === 413;
|
|
29
|
+
if (isOversize) {
|
|
30
|
+
// Context too large — caller should trim messages and retry
|
|
31
|
+
throw Object.assign(new Error('Context too large (413)'), { status: 413 });
|
|
32
|
+
}
|
|
33
|
+
if (isRetryable && attempt < MAX_RETRIES) {
|
|
34
|
+
const delay = RETRY_DELAYS[attempt] || 4000;
|
|
35
|
+
console.warn(`[AnthropicProvider] ${status} error, retrying in ${delay}ms (attempt ${attempt + 1}/${MAX_RETRIES})`);
|
|
36
|
+
await sleep(delay);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Should not reach here
|
|
43
|
+
throw new Error('Max retries exceeded');
|
|
44
|
+
}
|
|
45
|
+
async _streamChat(model, system, messages, tools, maxTokens, onEvent, signal) {
|
|
46
|
+
const stream = this.client.messages.stream({
|
|
47
|
+
model,
|
|
48
|
+
max_tokens: maxTokens || DEFAULT_MAX_TOKENS,
|
|
49
|
+
system: system,
|
|
50
|
+
messages,
|
|
51
|
+
tools: tools.length > 0 ? tools : undefined,
|
|
52
|
+
}, signal ? { signal } : undefined);
|
|
53
|
+
stream.on('text', (text) => {
|
|
54
|
+
onEvent?.({ type: 'text', text });
|
|
55
|
+
});
|
|
56
|
+
stream.on('contentBlock', (block) => {
|
|
57
|
+
if (block.type === 'tool_use') {
|
|
58
|
+
const toolCall = {
|
|
59
|
+
id: block.id,
|
|
60
|
+
name: block.name,
|
|
61
|
+
input: block.input,
|
|
62
|
+
};
|
|
63
|
+
onEvent?.({ type: 'tool_use_complete', toolCall });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const finalMessage = await stream.finalMessage();
|
|
67
|
+
const usage = {
|
|
68
|
+
input_tokens: finalMessage.usage.input_tokens,
|
|
69
|
+
output_tokens: finalMessage.usage.output_tokens,
|
|
70
|
+
cache_read_input_tokens: finalMessage.usage
|
|
71
|
+
.cache_read_input_tokens,
|
|
72
|
+
cache_creation_input_tokens: finalMessage.usage
|
|
73
|
+
.cache_creation_input_tokens,
|
|
74
|
+
};
|
|
75
|
+
onEvent?.({
|
|
76
|
+
type: 'done',
|
|
77
|
+
stopReason: finalMessage.stop_reason || 'end_turn',
|
|
78
|
+
usage,
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
content: finalMessage.content,
|
|
82
|
+
stopReason: finalMessage.stop_reason || 'end_turn',
|
|
83
|
+
usage,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function sleep(ms) {
|
|
88
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/lib/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AskUserQuestion tool — pauses the agentic loop to ask the user a question.
|
|
3
|
+
*
|
|
4
|
+
* This tool is intercepted by the agentic loop before execution. When the LLM
|
|
5
|
+
* calls it, the loop yields a `needsInput` result instead of executing the tool
|
|
6
|
+
* locally. The caller (gateway) sends the question to the user, waits for a
|
|
7
|
+
* response, then resumes the loop with the user's answer as the tool_result.
|
|
8
|
+
*
|
|
9
|
+
* Renders as blex:poll (multiple options) or blex:confirm (yes/no) in webchat.
|
|
10
|
+
*/
|
|
11
|
+
import type { Tool } from './index.js';
|
|
12
|
+
export declare const ASK_USER_QUESTION_TOOL = "AskUserQuestion";
|
|
13
|
+
export declare const askUserQuestionTool: Tool;
|
|
14
|
+
//# sourceMappingURL=ask-user-question.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-user-question.d.ts","sourceRoot":"","sources":["../../../src/lib/tools/ask-user-question.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,sBAAsB,oBAAoB,CAAC;AAExD,eAAO,MAAM,mBAAmB,EAAE,IAkEjC,CAAC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AskUserQuestion tool — pauses the agentic loop to ask the user a question.
|
|
3
|
+
*
|
|
4
|
+
* This tool is intercepted by the agentic loop before execution. When the LLM
|
|
5
|
+
* calls it, the loop yields a `needsInput` result instead of executing the tool
|
|
6
|
+
* locally. The caller (gateway) sends the question to the user, waits for a
|
|
7
|
+
* response, then resumes the loop with the user's answer as the tool_result.
|
|
8
|
+
*
|
|
9
|
+
* Renders as blex:poll (multiple options) or blex:confirm (yes/no) in webchat.
|
|
10
|
+
*/
|
|
11
|
+
export const ASK_USER_QUESTION_TOOL = 'AskUserQuestion';
|
|
12
|
+
export const askUserQuestionTool = {
|
|
13
|
+
definition: {
|
|
14
|
+
name: ASK_USER_QUESTION_TOOL,
|
|
15
|
+
description: 'Ask the user one or more questions and wait for their response. Use this when you need ' +
|
|
16
|
+
'clarification, confirmation, or choices from the user before proceeding. ' +
|
|
17
|
+
'The agentic loop pauses until the user responds.\n\n' +
|
|
18
|
+
'For a SINGLE question: provide `question` + optional `options`.\n' +
|
|
19
|
+
'For MULTIPLE questions: provide `questions` array (renders as a multi-question carousel).\n' +
|
|
20
|
+
'If no options are provided and allowFreeform is false, it becomes a yes/no confirm.',
|
|
21
|
+
input_schema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
question: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'The question to ask the user (for single-question mode).',
|
|
27
|
+
},
|
|
28
|
+
options: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
items: { type: 'string' },
|
|
31
|
+
description: 'Optional list of choices for a single question. ' +
|
|
32
|
+
'If omitted and allowFreeform is false, renders as a yes/no confirmation.',
|
|
33
|
+
},
|
|
34
|
+
allowFreeform: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'If true, the user can type a free-text answer in addition to (or instead of) picking an option. ' +
|
|
37
|
+
'Default: false.',
|
|
38
|
+
},
|
|
39
|
+
questions: {
|
|
40
|
+
type: 'array',
|
|
41
|
+
description: 'For multi-question carousels. Each item has question, options, and optional multiSelect/writeIn. ' +
|
|
42
|
+
'When provided, `question` and `options` are ignored.',
|
|
43
|
+
items: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
question: { type: 'string', description: 'The question text.' },
|
|
47
|
+
options: {
|
|
48
|
+
type: 'array',
|
|
49
|
+
items: { type: 'string' },
|
|
50
|
+
description: 'Choices for this question.',
|
|
51
|
+
},
|
|
52
|
+
multiSelect: {
|
|
53
|
+
type: 'boolean',
|
|
54
|
+
description: 'Allow selecting multiple options. Default: false.',
|
|
55
|
+
},
|
|
56
|
+
writeIn: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
description: 'Allow a free-text write-in answer. Default: false.',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
required: ['question', 'options'],
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
required: [],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
// This executor should never actually run — the agentic loop intercepts this
|
|
69
|
+
// tool before execution. If it somehow executes, return a sensible fallback.
|
|
70
|
+
async execute(input, _cwd) {
|
|
71
|
+
return `[AskUserQuestion was not intercepted by the loop. Question: ${input.question}]`;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=ask-user-question.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ask-user-question.js","sourceRoot":"","sources":["../../../src/lib/tools/ask-user-question.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,CAAC,MAAM,sBAAsB,GAAG,iBAAiB,CAAC;AAExD,MAAM,CAAC,MAAM,mBAAmB,GAAS;IACvC,UAAU,EAAE;QACV,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EACT,yFAAyF;YACzF,2EAA2E;YAC3E,sDAAsD;YACtD,mEAAmE;YACnE,6FAA6F;YAC7F,qFAAqF;QACvF,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,0DAA0D;iBACxE;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,OAAO;oBACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBACzB,WAAW,EACT,kDAAkD;wBAClD,0EAA0E;iBAC7E;gBACD,aAAa,EAAE;oBACb,IAAI,EAAE,SAAS;oBACf,WAAW,EACT,kGAAkG;wBAClG,iBAAiB;iBACpB;gBACD,SAAS,EAAE;oBACT,IAAI,EAAE,OAAO;oBACb,WAAW,EACT,mGAAmG;wBACnG,sDAAsD;oBACxD,KAAK,EAAE;wBACL,IAAI,EAAE,QAAQ;wBACd,UAAU,EAAE;4BACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;4BAC/D,OAAO,EAAE;gCACP,IAAI,EAAE,OAAO;gCACb,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gCACzB,WAAW,EAAE,4BAA4B;6BAC1C;4BACD,WAAW,EAAE;gCACX,IAAI,EAAE,SAAS;gCACf,WAAW,EAAE,mDAAmD;6BACjE;4BACD,OAAO,EAAE;gCACP,IAAI,EAAE,SAAS;gCACf,WAAW,EAAE,oDAAoD;6BAClE;yBACF;wBACD,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC;qBAClC;iBACF;aACF;YACD,QAAQ,EAAE,EAAE;SACb;KACF;IAED,6EAA6E;IAC7E,6EAA6E;IAC7E,KAAK,CAAC,OAAO,CAAC,KAA8B,EAAE,IAAY;QACxD,OAAO,+DAA+D,KAAK,CAAC,QAAQ,GAAG,CAAC;IAC1F,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/lib/tools/bash.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAMvC,eAAO,MAAM,QAAQ,EAAE,IAqFtB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash tool — execute shell commands with timeout.
|
|
3
|
+
*/
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
const DEFAULT_TIMEOUT = 120_000; // 2 minutes
|
|
6
|
+
const MAX_TIMEOUT = 600_000; // 10 minutes
|
|
7
|
+
const MAX_OUTPUT = 100_000; // 100KB output cap
|
|
8
|
+
export const bashTool = {
|
|
9
|
+
definition: {
|
|
10
|
+
name: 'Bash',
|
|
11
|
+
description: 'Execute a shell command and return its output. ' +
|
|
12
|
+
'The working directory is the project directory. ' +
|
|
13
|
+
'Commands time out after 2 minutes by default (configurable up to 10 minutes).',
|
|
14
|
+
input_schema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
command: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
description: 'The bash command to execute',
|
|
20
|
+
},
|
|
21
|
+
timeout: {
|
|
22
|
+
type: 'number',
|
|
23
|
+
description: 'Timeout in milliseconds (default: 120000, max: 600000)',
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ['command'],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
async execute(input, cwd) {
|
|
30
|
+
const command = input.command;
|
|
31
|
+
const timeout = Math.min(input.timeout || DEFAULT_TIMEOUT, MAX_TIMEOUT);
|
|
32
|
+
return new Promise(resolve => {
|
|
33
|
+
let stdout = '';
|
|
34
|
+
let stderr = '';
|
|
35
|
+
let killed = false;
|
|
36
|
+
const proc = spawn('bash', ['-c', command], {
|
|
37
|
+
cwd,
|
|
38
|
+
env: { ...process.env, TERM: 'dumb' },
|
|
39
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
40
|
+
});
|
|
41
|
+
const timer = setTimeout(() => {
|
|
42
|
+
killed = true;
|
|
43
|
+
proc.kill('SIGTERM');
|
|
44
|
+
setTimeout(() => proc.kill('SIGKILL'), 5000);
|
|
45
|
+
}, timeout);
|
|
46
|
+
proc.stdout.on('data', (data) => {
|
|
47
|
+
stdout += data.toString();
|
|
48
|
+
if (stdout.length > MAX_OUTPUT) {
|
|
49
|
+
stdout = stdout.slice(0, MAX_OUTPUT) + '\n\n[Output truncated at 100KB]';
|
|
50
|
+
killed = true;
|
|
51
|
+
proc.kill('SIGTERM');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
proc.stderr.on('data', (data) => {
|
|
55
|
+
stderr += data.toString();
|
|
56
|
+
if (stderr.length > MAX_OUTPUT) {
|
|
57
|
+
stderr = stderr.slice(0, MAX_OUTPUT);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
proc.on('close', code => {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
let result = '';
|
|
63
|
+
if (stdout)
|
|
64
|
+
result += stdout;
|
|
65
|
+
if (stderr) {
|
|
66
|
+
if (result)
|
|
67
|
+
result += '\n';
|
|
68
|
+
result += `STDERR:\n${stderr}`;
|
|
69
|
+
}
|
|
70
|
+
if (killed) {
|
|
71
|
+
result += `\n\n[Command timed out after ${timeout}ms]`;
|
|
72
|
+
}
|
|
73
|
+
else if (code !== 0 && code !== null) {
|
|
74
|
+
result += `\nExit code: ${code}`;
|
|
75
|
+
}
|
|
76
|
+
resolve(result || `(no output, exit code ${code})`);
|
|
77
|
+
});
|
|
78
|
+
proc.on('error', err => {
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
resolve(`Error executing command: ${err.message}`);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=bash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/lib/tools/bash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.d.ts","sourceRoot":"","sources":["../../../src/lib/tools/edit.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,eAAO,MAAM,QAAQ,EAAE,IA8EtB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edit tool — exact string replacement in files.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
export const editTool = {
|
|
7
|
+
definition: {
|
|
8
|
+
name: 'Edit',
|
|
9
|
+
description: 'Perform exact string replacements in files. The old_string must be unique in the file ' +
|
|
10
|
+
'unless replace_all is true. Use this for surgical edits — prefer over Write for modifying existing files.',
|
|
11
|
+
input_schema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
file_path: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Absolute path to the file to modify',
|
|
17
|
+
},
|
|
18
|
+
old_string: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'The exact text to find and replace',
|
|
21
|
+
},
|
|
22
|
+
new_string: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
description: 'The replacement text',
|
|
25
|
+
},
|
|
26
|
+
replace_all: {
|
|
27
|
+
type: 'boolean',
|
|
28
|
+
description: 'If true, replace all occurrences. Default: false.',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ['file_path', 'old_string', 'new_string'],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
async execute(input, cwd) {
|
|
35
|
+
const filePath = resolvePath(input.file_path, cwd);
|
|
36
|
+
const oldString = input.old_string;
|
|
37
|
+
const newString = input.new_string;
|
|
38
|
+
const replaceAll = input.replace_all || false;
|
|
39
|
+
if (!fs.existsSync(filePath)) {
|
|
40
|
+
return `Error: File not found: ${filePath}`;
|
|
41
|
+
}
|
|
42
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
43
|
+
if (oldString === newString) {
|
|
44
|
+
return 'Error: old_string and new_string are identical';
|
|
45
|
+
}
|
|
46
|
+
if (!content.includes(oldString)) {
|
|
47
|
+
// Provide context: show similar lines
|
|
48
|
+
const lines = content.split('\n');
|
|
49
|
+
const needle = oldString.trim().split('\n')[0].trim();
|
|
50
|
+
const similar = lines
|
|
51
|
+
.filter(l => l.includes(needle.slice(0, 20)))
|
|
52
|
+
.slice(0, 3)
|
|
53
|
+
.map(l => ` ${l.trim()}`);
|
|
54
|
+
let msg = `Error: old_string not found in ${filePath}`;
|
|
55
|
+
if (similar.length > 0) {
|
|
56
|
+
msg += `\nSimilar lines found:\n${similar.join('\n')}`;
|
|
57
|
+
}
|
|
58
|
+
return msg;
|
|
59
|
+
}
|
|
60
|
+
if (!replaceAll) {
|
|
61
|
+
const count = content.split(oldString).length - 1;
|
|
62
|
+
if (count > 1) {
|
|
63
|
+
return `Error: old_string appears ${count} times in ${filePath}. Use replace_all: true to replace all, or provide more context to make old_string unique.`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const updated = replaceAll
|
|
67
|
+
? content.split(oldString).join(newString)
|
|
68
|
+
: content.replace(oldString, newString);
|
|
69
|
+
fs.writeFileSync(filePath, updated, 'utf-8');
|
|
70
|
+
const replacements = replaceAll ? content.split(oldString).length - 1 : 1;
|
|
71
|
+
return `Edited ${filePath}: ${replacements} replacement(s) made`;
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
function resolvePath(filePath, cwd) {
|
|
75
|
+
if (path.isAbsolute(filePath))
|
|
76
|
+
return filePath;
|
|
77
|
+
return path.resolve(cwd, filePath);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=edit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/lib/tools/edit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.d.ts","sourceRoot":"","sources":["../../../src/lib/tools/glob.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,eAAO,MAAM,QAAQ,EAAE,IAqDtB,CAAC"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glob tool — find files by pattern.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
const MAX_RESULTS = 500;
|
|
7
|
+
export const globTool = {
|
|
8
|
+
definition: {
|
|
9
|
+
name: 'Glob',
|
|
10
|
+
description: 'Find files matching a glob pattern. Returns file paths sorted by modification time (newest first).',
|
|
11
|
+
input_schema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
pattern: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Glob pattern to match (e.g., "**/*.ts", "src/**/*.test.ts")',
|
|
17
|
+
},
|
|
18
|
+
path: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Directory to search in. Defaults to current working directory.',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
required: ['pattern'],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
async execute(input, cwd) {
|
|
27
|
+
const pattern = input.pattern;
|
|
28
|
+
const searchPath = input.path || cwd;
|
|
29
|
+
try {
|
|
30
|
+
const files = await globMatch(pattern, searchPath);
|
|
31
|
+
if (files.length === 0) {
|
|
32
|
+
return '(no matching files)';
|
|
33
|
+
}
|
|
34
|
+
// Sort by mtime (newest first)
|
|
35
|
+
const withStats = files.map(f => {
|
|
36
|
+
try {
|
|
37
|
+
const stat = fs.statSync(f);
|
|
38
|
+
return { path: f, mtime: stat.mtimeMs };
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return { path: f, mtime: 0 };
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
withStats.sort((a, b) => b.mtime - a.mtime);
|
|
45
|
+
const result = withStats.slice(0, MAX_RESULTS).map(f => f.path);
|
|
46
|
+
let output = result.join('\n');
|
|
47
|
+
if (files.length > MAX_RESULTS) {
|
|
48
|
+
output += `\n\n(${files.length - MAX_RESULTS} more files not shown)`;
|
|
49
|
+
}
|
|
50
|
+
return output;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return `Error: ${err.message}`;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Simple glob matching using Node's fs.
|
|
59
|
+
* Handles **, *, and ? patterns.
|
|
60
|
+
*/
|
|
61
|
+
async function globMatch(pattern, baseDir) {
|
|
62
|
+
// Use node:fs with recursive readdir + minimatch-style filtering
|
|
63
|
+
// For simplicity, use a shell glob via find or bash
|
|
64
|
+
const { execFileSync } = await import('child_process');
|
|
65
|
+
try {
|
|
66
|
+
// Use bash globbing (simplest, most reliable)
|
|
67
|
+
const result = execFileSync('bash', ['-c', `shopt -s globstar nullglob; printf '%s\\n' ${pattern}`], {
|
|
68
|
+
cwd: baseDir,
|
|
69
|
+
encoding: 'utf-8',
|
|
70
|
+
maxBuffer: 1024 * 1024,
|
|
71
|
+
timeout: 10_000,
|
|
72
|
+
});
|
|
73
|
+
return result
|
|
74
|
+
.trim()
|
|
75
|
+
.split('\n')
|
|
76
|
+
.filter(line => line.length > 0)
|
|
77
|
+
.map(f => path.resolve(baseDir, f))
|
|
78
|
+
.filter(f => {
|
|
79
|
+
try {
|
|
80
|
+
return fs.statSync(f).isFile();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../../src/lib/tools/glob.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/lib/tools/grep.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAIvC,eAAO,MAAM,QAAQ,EAAE,IAwFtB,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grep tool — search file contents using ripgrep.
|
|
3
|
+
*/
|
|
4
|
+
import { execFileSync } from 'child_process';
|
|
5
|
+
const MAX_RESULTS = 200;
|
|
6
|
+
export const grepTool = {
|
|
7
|
+
definition: {
|
|
8
|
+
name: 'Grep',
|
|
9
|
+
description: 'Search file contents using regular expressions (powered by ripgrep). ' +
|
|
10
|
+
'Returns matching file paths by default, or matching lines with content mode.',
|
|
11
|
+
input_schema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
pattern: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Regular expression pattern to search for',
|
|
17
|
+
},
|
|
18
|
+
path: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'File or directory to search in. Defaults to current working directory.',
|
|
21
|
+
},
|
|
22
|
+
output_mode: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
enum: ['files_with_matches', 'content', 'count'],
|
|
25
|
+
description: 'Output mode. Default: files_with_matches.',
|
|
26
|
+
},
|
|
27
|
+
glob: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Glob pattern to filter files (e.g., "*.ts", "*.{js,jsx}")',
|
|
30
|
+
},
|
|
31
|
+
type: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
description: 'File type to search (e.g., "ts", "py", "js")',
|
|
34
|
+
},
|
|
35
|
+
context: {
|
|
36
|
+
type: 'number',
|
|
37
|
+
description: 'Number of context lines before and after each match',
|
|
38
|
+
},
|
|
39
|
+
'-i': {
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
description: 'Case insensitive search',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
required: ['pattern'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
async execute(input, cwd) {
|
|
48
|
+
const pattern = input.pattern;
|
|
49
|
+
const searchPath = input.path || cwd;
|
|
50
|
+
const outputMode = input.output_mode || 'files_with_matches';
|
|
51
|
+
const globPattern = input.glob;
|
|
52
|
+
const fileType = input.type;
|
|
53
|
+
const context = input.context;
|
|
54
|
+
const caseInsensitive = input['-i'];
|
|
55
|
+
// Build rg args
|
|
56
|
+
const args = ['--no-heading'];
|
|
57
|
+
if (outputMode === 'files_with_matches') {
|
|
58
|
+
args.push('-l');
|
|
59
|
+
}
|
|
60
|
+
else if (outputMode === 'count') {
|
|
61
|
+
args.push('-c');
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
args.push('-n'); // line numbers for content mode
|
|
65
|
+
}
|
|
66
|
+
if (caseInsensitive)
|
|
67
|
+
args.push('-i');
|
|
68
|
+
if (globPattern)
|
|
69
|
+
args.push('--glob', globPattern);
|
|
70
|
+
if (fileType)
|
|
71
|
+
args.push('--type', fileType);
|
|
72
|
+
if (context && outputMode === 'content')
|
|
73
|
+
args.push('-C', String(context));
|
|
74
|
+
args.push('--max-count', String(MAX_RESULTS));
|
|
75
|
+
args.push('--', pattern, searchPath);
|
|
76
|
+
try {
|
|
77
|
+
const rgPath = findRg();
|
|
78
|
+
const result = execFileSync(rgPath, args, {
|
|
79
|
+
cwd,
|
|
80
|
+
encoding: 'utf-8',
|
|
81
|
+
maxBuffer: 1024 * 1024, // 1MB
|
|
82
|
+
timeout: 30_000,
|
|
83
|
+
});
|
|
84
|
+
return result.trim() || '(no matches)';
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
const execErr = err;
|
|
88
|
+
if (execErr.status === 1) {
|
|
89
|
+
return '(no matches)';
|
|
90
|
+
}
|
|
91
|
+
return `Error: ${execErr.stderr || 'grep failed'}`;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
function findRg() {
|
|
96
|
+
// Try common locations
|
|
97
|
+
const candidates = ['rg', '/usr/bin/rg', '/usr/local/bin/rg'];
|
|
98
|
+
for (const candidate of candidates) {
|
|
99
|
+
try {
|
|
100
|
+
execFileSync('which', [candidate], { encoding: 'utf-8', stdio: 'pipe' });
|
|
101
|
+
return candidate;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// continue
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Fallback to PATH
|
|
108
|
+
return 'rg';
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=grep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/lib/tools/grep.ts"],"names":[],"mappings":"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"}
|