cmdr-agent 2.4.0 → 2.5.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/bin/cmdr.js +117 -27
- package/dist/bin/cmdr.js.map +1 -1
- package/dist/package.json +9 -4
- package/dist/src/cli/ink/App.d.ts +2 -2
- package/dist/src/cli/ink/App.d.ts.map +1 -1
- package/dist/src/cli/ink/App.js +118 -65
- package/dist/src/cli/ink/App.js.map +1 -1
- package/dist/src/cli/ink/PromptInput.d.ts +17 -0
- package/dist/src/cli/ink/PromptInput.d.ts.map +1 -0
- package/dist/src/cli/ink/PromptInput.js +202 -0
- package/dist/src/cli/ink/PromptInput.js.map +1 -0
- package/dist/src/cli/ink/StatusBar.d.ts +1 -1
- package/dist/src/cli/ink/StatusBar.d.ts.map +1 -1
- package/dist/src/cli/ink/StatusBar.js +116 -21
- package/dist/src/cli/ink/StatusBar.js.map +1 -1
- package/dist/src/cli/ink/input-buffer.d.ts +34 -0
- package/dist/src/cli/ink/input-buffer.d.ts.map +1 -0
- package/dist/src/cli/ink/input-buffer.js +152 -0
- package/dist/src/cli/ink/input-buffer.js.map +1 -0
- package/dist/src/cli/progress.d.ts +59 -0
- package/dist/src/cli/progress.d.ts.map +1 -0
- package/dist/src/cli/progress.js +172 -0
- package/dist/src/cli/progress.js.map +1 -0
- package/dist/src/cli/renderer.d.ts +14 -3
- package/dist/src/cli/renderer.d.ts.map +1 -1
- package/dist/src/cli/renderer.js +93 -32
- package/dist/src/cli/renderer.js.map +1 -1
- package/dist/src/cli/repl.d.ts.map +1 -1
- package/dist/src/cli/repl.js +46 -28
- package/dist/src/cli/repl.js.map +1 -1
- package/dist/src/cli/spinner.d.ts +4 -1
- package/dist/src/cli/spinner.d.ts.map +1 -1
- package/dist/src/cli/spinner.js +34 -1
- package/dist/src/cli/spinner.js.map +1 -1
- package/dist/src/cli/theme.d.ts +14 -12
- package/dist/src/cli/theme.d.ts.map +1 -1
- package/dist/src/cli/theme.js +192 -123
- package/dist/src/cli/theme.js.map +1 -1
- package/dist/src/cli/themes.d.ts +17 -1
- package/dist/src/cli/themes.d.ts.map +1 -1
- package/dist/src/cli/themes.js +125 -27
- package/dist/src/cli/themes.js.map +1 -1
- package/dist/src/core/agent-runner.d.ts +12 -0
- package/dist/src/core/agent-runner.d.ts.map +1 -1
- package/dist/src/core/agent-runner.js +176 -5
- package/dist/src/core/agent-runner.js.map +1 -1
- package/dist/src/core/event-bus.d.ts +12 -0
- package/dist/src/core/event-bus.d.ts.map +1 -1
- package/dist/src/core/event-bus.js.map +1 -1
- package/dist/src/core/presets.d.ts.map +1 -1
- package/dist/src/core/presets.js +1 -0
- package/dist/src/core/presets.js.map +1 -1
- package/dist/src/core/types.d.ts +17 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/core/types.js +8 -1
- package/dist/src/core/types.js.map +1 -1
- package/dist/src/llm/anthropic.d.ts +1 -0
- package/dist/src/llm/anthropic.d.ts.map +1 -1
- package/dist/src/llm/anthropic.js +20 -1
- package/dist/src/llm/anthropic.js.map +1 -1
- package/dist/src/llm/ollama.d.ts +2 -12
- package/dist/src/llm/ollama.d.ts.map +1 -1
- package/dist/src/llm/ollama.js +46 -250
- package/dist/src/llm/ollama.js.map +1 -1
- package/dist/src/llm/openai.d.ts +1 -0
- package/dist/src/llm/openai.d.ts.map +1 -1
- package/dist/src/llm/openai.js +21 -7
- package/dist/src/llm/openai.js.map +1 -1
- package/dist/src/llm/repair/retry-policy.d.ts +48 -0
- package/dist/src/llm/repair/retry-policy.d.ts.map +1 -0
- package/dist/src/llm/repair/retry-policy.js +85 -0
- package/dist/src/llm/repair/retry-policy.js.map +1 -0
- package/dist/src/llm/repair/tool-repair.d.ts +39 -0
- package/dist/src/llm/repair/tool-repair.d.ts.map +1 -0
- package/dist/src/llm/repair/tool-repair.js +313 -0
- package/dist/src/llm/repair/tool-repair.js.map +1 -0
- package/dist/src/llm/shared/text-cleanup.d.ts +16 -0
- package/dist/src/llm/shared/text-cleanup.d.ts.map +1 -0
- package/dist/src/llm/shared/text-cleanup.js +120 -0
- package/dist/src/llm/shared/text-cleanup.js.map +1 -0
- package/dist/src/llm/shared/tool-parsing.d.ts +70 -0
- package/dist/src/llm/shared/tool-parsing.d.ts.map +1 -0
- package/dist/src/llm/shared/tool-parsing.js +355 -0
- package/dist/src/llm/shared/tool-parsing.js.map +1 -0
- package/dist/src/llm/validation/tool-call-schema.d.ts +83 -0
- package/dist/src/llm/validation/tool-call-schema.d.ts.map +1 -0
- package/dist/src/llm/validation/tool-call-schema.js +145 -0
- package/dist/src/llm/validation/tool-call-schema.js.map +1 -0
- package/dist/src/tools/built-in/bash.d.ts +5 -1
- package/dist/src/tools/built-in/bash.d.ts.map +1 -1
- package/dist/src/tools/built-in/bash.js +34 -46
- package/dist/src/tools/built-in/bash.js.map +1 -1
- package/dist/src/tools/built-in/index.d.ts +2 -1
- package/dist/src/tools/built-in/index.d.ts.map +1 -1
- package/dist/src/tools/built-in/index.js +3 -1
- package/dist/src/tools/built-in/index.js.map +1 -1
- package/dist/src/tools/built-in/pdf-report.d.ts +39 -0
- package/dist/src/tools/built-in/pdf-report.d.ts.map +1 -0
- package/dist/src/tools/built-in/pdf-report.js +326 -0
- package/dist/src/tools/built-in/pdf-report.js.map +1 -0
- package/dist/src/tools/executor.d.ts +7 -1
- package/dist/src/tools/executor.d.ts.map +1 -1
- package/dist/src/tools/executor.js +20 -5
- package/dist/src/tools/executor.js.map +1 -1
- package/dist/src/tools/shell/shell-executor.d.ts +71 -0
- package/dist/src/tools/shell/shell-executor.d.ts.map +1 -0
- package/dist/src/tools/shell/shell-executor.js +238 -0
- package/dist/src/tools/shell/shell-executor.js.map +1 -0
- package/package.json +9 -4
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Built-in bash tool — execute shell commands.
|
|
2
|
+
* Built-in bash/shell tool — execute shell commands cross-platform.
|
|
3
|
+
*
|
|
4
|
+
* Uses the ShellExecutor for platform-aware execution.
|
|
5
|
+
* On Unix: uses bash/zsh/sh (auto-detected).
|
|
6
|
+
* On Windows: uses PowerShell or cmd.exe (auto-detected).
|
|
3
7
|
*/
|
|
4
|
-
import { spawn } from 'child_process';
|
|
5
8
|
import { z } from 'zod';
|
|
6
9
|
import { defineTool } from '../registry.js';
|
|
7
10
|
import { sanitizeBashCommand } from './bash-security.js';
|
|
11
|
+
import { execute, detectPlatform } from '../shell/shell-executor.js';
|
|
8
12
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
13
|
+
const MAX_RESULT_SIZE = 30_000; // 30KB — matches Claude Code's BashTool limit
|
|
9
14
|
export const bashTool = defineTool({
|
|
10
15
|
name: 'bash',
|
|
11
|
-
description: 'Execute a
|
|
16
|
+
description: 'Execute a shell command and return stdout/stderr. ' +
|
|
12
17
|
'Use for file operations, running scripts, installing packages, etc. ' +
|
|
13
|
-
|
|
18
|
+
`Runs in ${detectPlatform() === 'windows' ? 'PowerShell/cmd' : 'bash'} (auto-detected).`,
|
|
14
19
|
inputSchema: z.object({
|
|
15
|
-
command: z.string().describe('The
|
|
20
|
+
command: z.string().describe('The shell command to execute.'),
|
|
16
21
|
timeout: z.number().optional().describe(`Timeout in ms. Defaults to ${DEFAULT_TIMEOUT_MS}.`),
|
|
17
22
|
cwd: z.string().optional().describe('Working directory for the command.'),
|
|
18
23
|
}),
|
|
@@ -24,50 +29,33 @@ export const bashTool = defineTool({
|
|
|
24
29
|
}
|
|
25
30
|
const timeoutMs = input.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
26
31
|
const cwd = input.cwd ?? context.cwd ?? process.cwd();
|
|
27
|
-
const
|
|
32
|
+
const result = await execute({
|
|
33
|
+
command: check.sanitized,
|
|
34
|
+
cwd,
|
|
35
|
+
timeoutMs,
|
|
36
|
+
signal: context.abortSignal,
|
|
37
|
+
});
|
|
28
38
|
const parts = [];
|
|
29
|
-
if (stdout)
|
|
30
|
-
parts.push(stdout);
|
|
31
|
-
if (stderr)
|
|
32
|
-
parts.push(`[stderr]\n${stderr}`);
|
|
33
|
-
if (
|
|
34
|
-
parts.push(`[
|
|
39
|
+
if (result.stdout)
|
|
40
|
+
parts.push(result.stdout);
|
|
41
|
+
if (result.stderr)
|
|
42
|
+
parts.push(`[stderr]\n${result.stderr}`);
|
|
43
|
+
if (result.timedOut)
|
|
44
|
+
parts.push(`[timed out after ${timeoutMs}ms]`);
|
|
45
|
+
if (result.interrupted)
|
|
46
|
+
parts.push('[interrupted by user]');
|
|
47
|
+
if (result.exitCode !== 0)
|
|
48
|
+
parts.push(`[exit code: ${result.exitCode}]`);
|
|
49
|
+
let output = parts.join('\n') || '(no output)';
|
|
50
|
+
// Truncate large outputs to prevent context overflow
|
|
51
|
+
if (output.length > MAX_RESULT_SIZE) {
|
|
52
|
+
const truncated = output.slice(0, MAX_RESULT_SIZE);
|
|
53
|
+
output = truncated + `\n[output truncated: ${output.length} chars total, showing first ${MAX_RESULT_SIZE}]`;
|
|
54
|
+
}
|
|
35
55
|
return {
|
|
36
|
-
data:
|
|
37
|
-
isError: exitCode !== 0,
|
|
56
|
+
data: output,
|
|
57
|
+
isError: result.exitCode !== 0,
|
|
38
58
|
};
|
|
39
59
|
},
|
|
40
60
|
});
|
|
41
|
-
function runCommand(command, cwd, timeoutMs, signal) {
|
|
42
|
-
return new Promise((resolve) => {
|
|
43
|
-
const stdoutChunks = [];
|
|
44
|
-
const stderrChunks = [];
|
|
45
|
-
const child = spawn('bash', ['-c', command], {
|
|
46
|
-
cwd,
|
|
47
|
-
env: process.env,
|
|
48
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
49
|
-
});
|
|
50
|
-
child.stdout.on('data', (chunk) => stdoutChunks.push(chunk));
|
|
51
|
-
child.stderr.on('data', (chunk) => stderrChunks.push(chunk));
|
|
52
|
-
const timer = setTimeout(() => {
|
|
53
|
-
child.kill('SIGKILL');
|
|
54
|
-
}, timeoutMs);
|
|
55
|
-
const onAbort = () => child.kill('SIGKILL');
|
|
56
|
-
signal?.addEventListener('abort', onAbort, { once: true });
|
|
57
|
-
child.on('close', (code) => {
|
|
58
|
-
clearTimeout(timer);
|
|
59
|
-
signal?.removeEventListener('abort', onAbort);
|
|
60
|
-
resolve({
|
|
61
|
-
stdout: Buffer.concat(stdoutChunks).toString('utf-8'),
|
|
62
|
-
stderr: Buffer.concat(stderrChunks).toString('utf-8'),
|
|
63
|
-
exitCode: code ?? 1,
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
child.on('error', (err) => {
|
|
67
|
-
clearTimeout(timer);
|
|
68
|
-
signal?.removeEventListener('abort', onAbort);
|
|
69
|
-
resolve({ stdout: '', stderr: err.message, exitCode: 1 });
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
61
|
//# sourceMappingURL=bash.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../../src/tools/built-in/bash.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../../src/tools/built-in/bash.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,7 +26,8 @@ import { cronCreateTool, cronListTool, cronDeleteTool } from './cron-tools.js';
|
|
|
26
26
|
import { enterPlanModeTool, exitPlanModeTool } from './plan-tools.js';
|
|
27
27
|
import { mcpListResourcesTool, mcpReadResourceTool } from './mcp-resource-tools.js';
|
|
28
28
|
import { graphImpactTool, graphQueryTool, graphReviewTool } from './graph-tools.js';
|
|
29
|
-
|
|
29
|
+
import { pdfReportTool } from './pdf-report.js';
|
|
30
|
+
export { bashTool, fileReadTool, fileWriteTool, fileEditTool, grepTool, globTool, gitDiffTool, gitLogTool, gitCommitTool, gitBranchTool, gitWorktreeTool, lspDiagnosticsTool, notebookReadTool, notebookEditTool, notebookRunTool, thinkTool, webFetchTool, webSearchTool, askUserTool, memoryReadTool, memoryWriteTool, todoWriteTool, taskCreateTool, taskListTool, taskGetTool, taskStopTool, cronCreateTool, cronListTool, cronDeleteTool, enterPlanModeTool, exitPlanModeTool, mcpListResourcesTool, mcpReadResourceTool, graphImpactTool, graphQueryTool, graphReviewTool, pdfReportTool, };
|
|
30
31
|
export declare const BUILT_IN_TOOLS: ToolDefinition<any>[];
|
|
31
32
|
export declare function registerBuiltInTools(registry: ToolRegistry): void;
|
|
32
33
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE/C,OAAO,EACL,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EACnD,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EACzE,eAAe,EAAE,kBAAkB,EACnC,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EACnD,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EACpF,aAAa,EACb,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EACvD,cAAc,EAAE,YAAY,EAAE,cAAc,EAC5C,iBAAiB,EAAE,gBAAgB,EACnC,oBAAoB,EAAE,mBAAmB,EACzC,eAAe,EAAE,cAAc,EAAE,eAAe,EAChD,aAAa,GACd,CAAA;AAGD,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,EAa/C,CAAA;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAMjE"}
|
|
@@ -24,7 +24,8 @@ import { cronCreateTool, cronListTool, cronDeleteTool } from './cron-tools.js';
|
|
|
24
24
|
import { enterPlanModeTool, exitPlanModeTool } from './plan-tools.js';
|
|
25
25
|
import { mcpListResourcesTool, mcpReadResourceTool } from './mcp-resource-tools.js';
|
|
26
26
|
import { graphImpactTool, graphQueryTool, graphReviewTool } from './graph-tools.js';
|
|
27
|
-
|
|
27
|
+
import { pdfReportTool } from './pdf-report.js';
|
|
28
|
+
export { bashTool, fileReadTool, fileWriteTool, fileEditTool, grepTool, globTool, gitDiffTool, gitLogTool, gitCommitTool, gitBranchTool, gitWorktreeTool, lspDiagnosticsTool, notebookReadTool, notebookEditTool, notebookRunTool, thinkTool, webFetchTool, webSearchTool, askUserTool, memoryReadTool, memoryWriteTool, todoWriteTool, taskCreateTool, taskListTool, taskGetTool, taskStopTool, cronCreateTool, cronListTool, cronDeleteTool, enterPlanModeTool, exitPlanModeTool, mcpListResourcesTool, mcpReadResourceTool, graphImpactTool, graphQueryTool, graphReviewTool, pdfReportTool, };
|
|
28
29
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
30
|
export const BUILT_IN_TOOLS = [
|
|
30
31
|
bashTool, fileReadTool, fileWriteTool, fileEditTool,
|
|
@@ -38,6 +39,7 @@ export const BUILT_IN_TOOLS = [
|
|
|
38
39
|
enterPlanModeTool, exitPlanModeTool,
|
|
39
40
|
mcpListResourcesTool, mcpReadResourceTool,
|
|
40
41
|
graphImpactTool, graphQueryTool, graphReviewTool,
|
|
42
|
+
pdfReportTool,
|
|
41
43
|
];
|
|
42
44
|
export function registerBuiltInTools(registry) {
|
|
43
45
|
for (const tool of BUILT_IN_TOOLS) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/tools/built-in/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACnF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAC9C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzF,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AACrE,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/tools/built-in/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in pdf_report tool — generate structured multi-page PDF reports.
|
|
3
|
+
*
|
|
4
|
+
* Provides a high-level JSON API so the LLM doesn't need to write raw
|
|
5
|
+
* reportlab/Python code. The tool takes structured sections and produces
|
|
6
|
+
* a professional PDF with title page, TOC, headers, tables, and page numbers.
|
|
7
|
+
*/
|
|
8
|
+
export declare const pdfReportTool: import("../registry.js").ToolDefinition<{
|
|
9
|
+
title: string;
|
|
10
|
+
sections: {
|
|
11
|
+
content: ({
|
|
12
|
+
type: "table";
|
|
13
|
+
headers: string[];
|
|
14
|
+
rows: string[][];
|
|
15
|
+
} | {
|
|
16
|
+
type: "text";
|
|
17
|
+
body: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: "bullets";
|
|
20
|
+
items: string[];
|
|
21
|
+
} | {
|
|
22
|
+
type: "code";
|
|
23
|
+
body: string;
|
|
24
|
+
language?: string | undefined;
|
|
25
|
+
} | {
|
|
26
|
+
type: "key_value";
|
|
27
|
+
pairs: {
|
|
28
|
+
key: string;
|
|
29
|
+
value: string;
|
|
30
|
+
}[];
|
|
31
|
+
})[];
|
|
32
|
+
title: string;
|
|
33
|
+
}[];
|
|
34
|
+
outputPath: string;
|
|
35
|
+
date?: string | undefined;
|
|
36
|
+
subtitle?: string | undefined;
|
|
37
|
+
author?: string | undefined;
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=pdf-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-report.d.ts","sourceRoot":"","sources":["../../../../src/tools/built-in/pdf-report.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8PH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4DxB,CAAA"}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in pdf_report tool — generate structured multi-page PDF reports.
|
|
3
|
+
*
|
|
4
|
+
* Provides a high-level JSON API so the LLM doesn't need to write raw
|
|
5
|
+
* reportlab/Python code. The tool takes structured sections and produces
|
|
6
|
+
* a professional PDF with title page, TOC, headers, tables, and page numbers.
|
|
7
|
+
*/
|
|
8
|
+
import { writeFile, mkdir } from 'fs/promises';
|
|
9
|
+
import { resolve, dirname } from 'path';
|
|
10
|
+
import { spawn } from 'child_process';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { defineTool } from '../registry.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Schema
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const tableSchema = z.object({
|
|
17
|
+
type: z.literal('table'),
|
|
18
|
+
headers: z.array(z.string()).describe('Column headers'),
|
|
19
|
+
rows: z.array(z.array(z.string())).describe('Row data'),
|
|
20
|
+
});
|
|
21
|
+
const textSchema = z.object({
|
|
22
|
+
type: z.literal('text'),
|
|
23
|
+
body: z.string().describe('Paragraph text (supports \\n for line breaks)'),
|
|
24
|
+
});
|
|
25
|
+
const bulletSchema = z.object({
|
|
26
|
+
type: z.literal('bullets'),
|
|
27
|
+
items: z.array(z.string()).describe('Bullet point items'),
|
|
28
|
+
});
|
|
29
|
+
const codeSchema = z.object({
|
|
30
|
+
type: z.literal('code'),
|
|
31
|
+
language: z.string().optional().describe('Language label'),
|
|
32
|
+
body: z.string().describe('Code block content'),
|
|
33
|
+
});
|
|
34
|
+
const keyValueSchema = z.object({
|
|
35
|
+
type: z.literal('key_value'),
|
|
36
|
+
pairs: z.array(z.object({
|
|
37
|
+
key: z.string(),
|
|
38
|
+
value: z.string(),
|
|
39
|
+
})).describe('Key-value pairs displayed as a two-column layout'),
|
|
40
|
+
});
|
|
41
|
+
const contentBlock = z.discriminatedUnion('type', [
|
|
42
|
+
tableSchema, textSchema, bulletSchema, codeSchema, keyValueSchema,
|
|
43
|
+
]);
|
|
44
|
+
const sectionSchema = z.object({
|
|
45
|
+
title: z.string().describe('Section heading'),
|
|
46
|
+
content: z.array(contentBlock).describe('Content blocks in this section'),
|
|
47
|
+
});
|
|
48
|
+
const reportInput = z.object({
|
|
49
|
+
title: z.string().describe('Report title for the cover page'),
|
|
50
|
+
subtitle: z.string().optional().describe('Subtitle or project name'),
|
|
51
|
+
author: z.string().optional().describe('Author name'),
|
|
52
|
+
date: z.string().optional().describe('Date string (defaults to today)'),
|
|
53
|
+
sections: z.array(sectionSchema).min(1).describe('Report sections in order'),
|
|
54
|
+
outputPath: z.string().describe('Output file path for the PDF'),
|
|
55
|
+
});
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
// Python generator template
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
function buildPythonScript() {
|
|
60
|
+
return `#!/usr/bin/env python3
|
|
61
|
+
"""Auto-generated PDF report script. Reads data from a JSON file."""
|
|
62
|
+
import json, sys, os
|
|
63
|
+
|
|
64
|
+
try:
|
|
65
|
+
from reportlab.lib.pagesizes import letter
|
|
66
|
+
from reportlab.lib.units import inch
|
|
67
|
+
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
68
|
+
from reportlab.lib.colors import HexColor
|
|
69
|
+
from reportlab.lib.enums import TA_CENTER, TA_LEFT
|
|
70
|
+
from reportlab.platypus import (
|
|
71
|
+
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
|
|
72
|
+
PageBreak, Preformatted, ListFlowable, ListItem,
|
|
73
|
+
)
|
|
74
|
+
from reportlab.lib import colors
|
|
75
|
+
except ImportError:
|
|
76
|
+
print("ERROR: reportlab not installed. Run: pip install reportlab", file=sys.stderr)
|
|
77
|
+
sys.exit(1)
|
|
78
|
+
|
|
79
|
+
if len(sys.argv) < 3:
|
|
80
|
+
print("Usage: python3 report.py <data.json> <output.pdf>", file=sys.stderr)
|
|
81
|
+
sys.exit(1)
|
|
82
|
+
|
|
83
|
+
with open(sys.argv[1], 'r', encoding='utf-8') as f:
|
|
84
|
+
data = json.load(f)
|
|
85
|
+
output_path = sys.argv[2]
|
|
86
|
+
|
|
87
|
+
# ── Styles ──────────────────────────────────────────────
|
|
88
|
+
styles = getSampleStyleSheet()
|
|
89
|
+
styles.add(ParagraphStyle(
|
|
90
|
+
name='CoverTitle', fontSize=28, leading=34,
|
|
91
|
+
alignment=TA_CENTER, spaceAfter=12,
|
|
92
|
+
textColor=HexColor('#1a1a2e'),
|
|
93
|
+
))
|
|
94
|
+
styles.add(ParagraphStyle(
|
|
95
|
+
name='CoverSubtitle', fontSize=16, leading=20,
|
|
96
|
+
alignment=TA_CENTER, spaceAfter=8,
|
|
97
|
+
textColor=HexColor('#4a4a6a'),
|
|
98
|
+
))
|
|
99
|
+
styles.add(ParagraphStyle(
|
|
100
|
+
name='CoverMeta', fontSize=12, leading=16,
|
|
101
|
+
alignment=TA_CENTER, spaceAfter=4,
|
|
102
|
+
textColor=HexColor('#6a6a8a'),
|
|
103
|
+
))
|
|
104
|
+
styles.add(ParagraphStyle(
|
|
105
|
+
name='SectionHead', fontSize=18, leading=22,
|
|
106
|
+
spaceAfter=12, spaceBefore=20,
|
|
107
|
+
textColor=HexColor('#1a1a2e'),
|
|
108
|
+
borderWidth=1, borderColor=HexColor('#e0e0e0'),
|
|
109
|
+
borderPadding=(0, 0, 4, 0),
|
|
110
|
+
))
|
|
111
|
+
styles.add(ParagraphStyle(
|
|
112
|
+
name='BodyText2', fontSize=10, leading=14,
|
|
113
|
+
spaceAfter=8, spaceBefore=4,
|
|
114
|
+
))
|
|
115
|
+
styles.add(ParagraphStyle(
|
|
116
|
+
name='CodeBlock', fontName='Courier', fontSize=8, leading=10,
|
|
117
|
+
spaceAfter=8, spaceBefore=4, backColor=HexColor('#f5f5f5'),
|
|
118
|
+
borderWidth=0.5, borderColor=HexColor('#cccccc'),
|
|
119
|
+
borderPadding=6, leftIndent=12, rightIndent=12,
|
|
120
|
+
))
|
|
121
|
+
styles.add(ParagraphStyle(
|
|
122
|
+
name='BulletText', fontSize=10, leading=14,
|
|
123
|
+
spaceAfter=3, leftIndent=20, bulletIndent=10,
|
|
124
|
+
))
|
|
125
|
+
styles.add(ParagraphStyle(
|
|
126
|
+
name='TOCEntry', fontSize=11, leading=16,
|
|
127
|
+
spaceAfter=4, leftIndent=20,
|
|
128
|
+
textColor=HexColor('#333366'),
|
|
129
|
+
))
|
|
130
|
+
|
|
131
|
+
# ── Page numbering ──────────────────────────────────────
|
|
132
|
+
def add_page_number(canvas, doc):
|
|
133
|
+
page_num = canvas.getPageNumber()
|
|
134
|
+
text = f"Page {page_num}"
|
|
135
|
+
canvas.saveState()
|
|
136
|
+
canvas.setFont('Helvetica', 8)
|
|
137
|
+
canvas.setFillColor(HexColor('#888888'))
|
|
138
|
+
canvas.drawCentredString(letter[0] / 2, 0.5 * inch, text)
|
|
139
|
+
canvas.restoreState()
|
|
140
|
+
|
|
141
|
+
# ── Build story ─────────────────────────────────────────
|
|
142
|
+
story = []
|
|
143
|
+
|
|
144
|
+
# Cover page
|
|
145
|
+
story.append(Spacer(1, 2 * inch))
|
|
146
|
+
story.append(Paragraph(data['title'], styles['CoverTitle']))
|
|
147
|
+
if data.get('subtitle'):
|
|
148
|
+
story.append(Paragraph(data['subtitle'], styles['CoverSubtitle']))
|
|
149
|
+
story.append(Spacer(1, 0.5 * inch))
|
|
150
|
+
if data.get('author'):
|
|
151
|
+
story.append(Paragraph(f"Author: {data['author']}", styles['CoverMeta']))
|
|
152
|
+
story.append(Paragraph(f"Date: {data['date']}", styles['CoverMeta']))
|
|
153
|
+
story.append(PageBreak())
|
|
154
|
+
|
|
155
|
+
# Table of Contents
|
|
156
|
+
story.append(Paragraph("Table of Contents", styles['SectionHead']))
|
|
157
|
+
story.append(Spacer(1, 0.2 * inch))
|
|
158
|
+
for i, section in enumerate(data['sections'], 1):
|
|
159
|
+
story.append(Paragraph(f"{i}. {section['title']}", styles['TOCEntry']))
|
|
160
|
+
story.append(PageBreak())
|
|
161
|
+
|
|
162
|
+
# Sections
|
|
163
|
+
for section in data['sections']:
|
|
164
|
+
story.append(Paragraph(section['title'], styles['SectionHead']))
|
|
165
|
+
|
|
166
|
+
for block in section.get('content', []):
|
|
167
|
+
btype = block['type']
|
|
168
|
+
|
|
169
|
+
if btype == 'text':
|
|
170
|
+
for para in block['body'].split('\\n\\n'):
|
|
171
|
+
if para.strip():
|
|
172
|
+
story.append(Paragraph(para.strip().replace('\\n', '<br/>'), styles['BodyText2']))
|
|
173
|
+
|
|
174
|
+
elif btype == 'bullets':
|
|
175
|
+
items = []
|
|
176
|
+
for item in block['items']:
|
|
177
|
+
items.append(ListItem(Paragraph(item, styles['BodyText2']), bulletColor=HexColor('#333366')))
|
|
178
|
+
story.append(ListFlowable(items, bulletType='bullet', start='bulletchar'))
|
|
179
|
+
story.append(Spacer(1, 0.1 * inch))
|
|
180
|
+
|
|
181
|
+
elif btype == 'table':
|
|
182
|
+
headers = block['headers']
|
|
183
|
+
rows = block['rows']
|
|
184
|
+
all_data = [headers] + rows
|
|
185
|
+
t = Table(all_data, repeatRows=1)
|
|
186
|
+
t.setStyle(TableStyle([
|
|
187
|
+
('BACKGROUND', (0, 0), (-1, 0), HexColor('#1a1a2e')),
|
|
188
|
+
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
|
|
189
|
+
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
|
|
190
|
+
('FONTSIZE', (0, 0), (-1, 0), 9),
|
|
191
|
+
('FONTSIZE', (0, 1), (-1, -1), 8),
|
|
192
|
+
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
|
|
193
|
+
('GRID', (0, 0), (-1, -1), 0.5, HexColor('#cccccc')),
|
|
194
|
+
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, HexColor('#f8f8ff')]),
|
|
195
|
+
('TOPPADDING', (0, 0), (-1, -1), 4),
|
|
196
|
+
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
|
197
|
+
('LEFTPADDING', (0, 0), (-1, -1), 6),
|
|
198
|
+
('RIGHTPADDING', (0, 0), (-1, -1), 6),
|
|
199
|
+
]))
|
|
200
|
+
story.append(t)
|
|
201
|
+
story.append(Spacer(1, 0.15 * inch))
|
|
202
|
+
|
|
203
|
+
elif btype == 'code':
|
|
204
|
+
label = block.get('language', '')
|
|
205
|
+
if label:
|
|
206
|
+
story.append(Paragraph(f"<i>{label}</i>", styles['BodyText2']))
|
|
207
|
+
story.append(Preformatted(block['body'], styles['CodeBlock']))
|
|
208
|
+
|
|
209
|
+
elif btype == 'key_value':
|
|
210
|
+
kv_data = [[p['key'], p['value']] for p in block['pairs']]
|
|
211
|
+
t = Table(kv_data, colWidths=[2.2 * inch, 4.3 * inch])
|
|
212
|
+
t.setStyle(TableStyle([
|
|
213
|
+
('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
|
|
214
|
+
('FONTSIZE', (0, 0), (-1, -1), 9),
|
|
215
|
+
('ALIGN', (0, 0), (0, -1), 'RIGHT'),
|
|
216
|
+
('ALIGN', (1, 0), (1, -1), 'LEFT'),
|
|
217
|
+
('GRID', (0, 0), (-1, -1), 0.3, HexColor('#e0e0e0')),
|
|
218
|
+
('ROWBACKGROUNDS', (0, 0), (-1, -1), [colors.white, HexColor('#f8f8ff')]),
|
|
219
|
+
('TOPPADDING', (0, 0), (-1, -1), 4),
|
|
220
|
+
('BOTTOMPADDING', (0, 0), (-1, -1), 4),
|
|
221
|
+
('LEFTPADDING', (0, 0), (-1, -1), 6),
|
|
222
|
+
('RIGHTPADDING', (0, 0), (-1, -1), 6),
|
|
223
|
+
]))
|
|
224
|
+
story.append(t)
|
|
225
|
+
story.append(Spacer(1, 0.15 * inch))
|
|
226
|
+
|
|
227
|
+
story.append(Spacer(1, 0.3 * inch))
|
|
228
|
+
|
|
229
|
+
# ── Generate ────────────────────────────────────────────
|
|
230
|
+
doc = SimpleDocTemplate(
|
|
231
|
+
output_path,
|
|
232
|
+
pagesize=letter,
|
|
233
|
+
topMargin=0.75 * inch,
|
|
234
|
+
bottomMargin=0.75 * inch,
|
|
235
|
+
leftMargin=0.75 * inch,
|
|
236
|
+
rightMargin=0.75 * inch,
|
|
237
|
+
title=data['title'],
|
|
238
|
+
author=data.get('author', ''),
|
|
239
|
+
)
|
|
240
|
+
doc.build(story, onFirstPage=add_page_number, onLaterPages=add_page_number)
|
|
241
|
+
print(f"Generated: {output_path} ({len(data['sections'])} sections, {sum(len(s.get('content',[])) for s in data['sections'])} content blocks)")
|
|
242
|
+
`;
|
|
243
|
+
}
|
|
244
|
+
// ---------------------------------------------------------------------------
|
|
245
|
+
// Tool definition
|
|
246
|
+
// ---------------------------------------------------------------------------
|
|
247
|
+
export const pdfReportTool = defineTool({
|
|
248
|
+
name: 'pdf_report',
|
|
249
|
+
description: 'Generate a professional multi-page PDF report with structured sections. ' +
|
|
250
|
+
'Provide a title, sections (each with content blocks: text, bullets, tables, code, key_value), ' +
|
|
251
|
+
'and an output path. The tool handles formatting, cover page, table of contents, and page numbers. ' +
|
|
252
|
+
'Requires Python 3 and reportlab (auto-installs if missing).',
|
|
253
|
+
inputSchema: reportInput,
|
|
254
|
+
execute: async (input, context) => {
|
|
255
|
+
const cwd = context.cwd ?? process.cwd();
|
|
256
|
+
const outputPath = resolve(cwd, input.outputPath);
|
|
257
|
+
// Generate the Python script and write data as separate JSON file (avoids escaping issues)
|
|
258
|
+
const script = buildPythonScript();
|
|
259
|
+
const scriptPath = resolve(cwd, '.cmdr_report_gen.py');
|
|
260
|
+
const dataPath = resolve(cwd, '.cmdr_report_data.json');
|
|
261
|
+
try {
|
|
262
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
263
|
+
await writeFile(scriptPath, script, 'utf-8');
|
|
264
|
+
await writeFile(dataPath, JSON.stringify({
|
|
265
|
+
title: input.title,
|
|
266
|
+
subtitle: input.subtitle || '',
|
|
267
|
+
author: input.author || '',
|
|
268
|
+
date: input.date || new Date().toISOString().split('T')[0],
|
|
269
|
+
sections: input.sections,
|
|
270
|
+
}), 'utf-8');
|
|
271
|
+
// Ensure reportlab is installed (try with --break-system-packages for macOS PEP 668)
|
|
272
|
+
const check = await runPython(cwd, ['-c', 'import reportlab']);
|
|
273
|
+
if (check.exitCode !== 0) {
|
|
274
|
+
const install = await runPython(cwd, ['-m', 'pip', 'install', '--break-system-packages', 'reportlab', '-q']);
|
|
275
|
+
if (install.exitCode !== 0) {
|
|
276
|
+
// Fallback without --break-system-packages
|
|
277
|
+
await runPython(cwd, ['-m', 'pip', 'install', 'reportlab', '-q']);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Generate PDF
|
|
281
|
+
const result = await runPython(cwd, [scriptPath, dataPath, outputPath]);
|
|
282
|
+
// Clean up temp files
|
|
283
|
+
try {
|
|
284
|
+
const { unlink } = await import('fs/promises');
|
|
285
|
+
await unlink(scriptPath).catch(() => { });
|
|
286
|
+
await unlink(dataPath).catch(() => { });
|
|
287
|
+
}
|
|
288
|
+
catch { /* best effort */ }
|
|
289
|
+
if (result.exitCode !== 0) {
|
|
290
|
+
return { data: `PDF generation failed:\n${result.stderr || result.stdout}`, isError: true };
|
|
291
|
+
}
|
|
292
|
+
return { data: result.stdout.trim() || `Generated PDF: ${input.outputPath}` };
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
296
|
+
return { data: `PDF generation error: ${msg}`, isError: true };
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
function runPython(cwd, args) {
|
|
301
|
+
return new Promise((resolve) => {
|
|
302
|
+
const stdoutChunks = [];
|
|
303
|
+
const stderrChunks = [];
|
|
304
|
+
const child = spawn('python3', args, {
|
|
305
|
+
cwd,
|
|
306
|
+
env: process.env,
|
|
307
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
308
|
+
});
|
|
309
|
+
child.stdout.on('data', (chunk) => stdoutChunks.push(chunk));
|
|
310
|
+
child.stderr.on('data', (chunk) => stderrChunks.push(chunk));
|
|
311
|
+
const timer = setTimeout(() => child.kill('SIGKILL'), 30_000);
|
|
312
|
+
child.on('close', (code) => {
|
|
313
|
+
clearTimeout(timer);
|
|
314
|
+
resolve({
|
|
315
|
+
stdout: Buffer.concat(stdoutChunks).toString('utf-8'),
|
|
316
|
+
stderr: Buffer.concat(stderrChunks).toString('utf-8'),
|
|
317
|
+
exitCode: code ?? 1,
|
|
318
|
+
});
|
|
319
|
+
});
|
|
320
|
+
child.on('error', (err) => {
|
|
321
|
+
clearTimeout(timer);
|
|
322
|
+
resolve({ stdout: '', stderr: err.message, exitCode: 1 });
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
//# sourceMappingURL=pdf-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-report.js","sourceRoot":"","sources":["../../../../src/tools/built-in/pdf-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool executor with concurrency control and error isolation.
|
|
2
|
+
* Tool executor with concurrency control, Zod validation, and error isolation.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors Claude Code's tool execution flow:
|
|
5
|
+
* 1. Tool lookup (with unknown tool rejection)
|
|
6
|
+
* 2. Zod schema validation (with corrective error messages)
|
|
7
|
+
* 3. Concurrency-limited execution
|
|
8
|
+
* 4. Error isolation (tool failures don't crash the agent loop)
|
|
3
9
|
*/
|
|
4
10
|
import type { ToolResult, ToolUseContext } from '../core/types.js';
|
|
5
11
|
import type { ToolRegistry } from './registry.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/executor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../../src/tools/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAGjD,MAAM,WAAW,mBAAmB;IAClC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC/B;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;gBAEtC,QAAQ,EAAE,YAAY,EAAE,OAAO,GAAE,mBAAwB;IAK/D,OAAO,CACX,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,UAAU,CAAC;IA6BhB,YAAY,CAChB,KAAK,EAAE,aAAa,EAAE,EACtB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAUnC,OAAO,CAAC,OAAO;IAaf,OAAO,CAAC,OAAO;CAKhB"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tool executor with concurrency control and error isolation.
|
|
2
|
+
* Tool executor with concurrency control, Zod validation, and error isolation.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors Claude Code's tool execution flow:
|
|
5
|
+
* 1. Tool lookup (with unknown tool rejection)
|
|
6
|
+
* 2. Zod schema validation (with corrective error messages)
|
|
7
|
+
* 3. Concurrency-limited execution
|
|
8
|
+
* 4. Error isolation (tool failures don't crash the agent loop)
|
|
3
9
|
*/
|
|
10
|
+
import { validateToolInput } from '../llm/validation/tool-call-schema.js';
|
|
4
11
|
export class ToolExecutor {
|
|
5
12
|
registry;
|
|
6
13
|
active = 0;
|
|
@@ -13,13 +20,21 @@ export class ToolExecutor {
|
|
|
13
20
|
async execute(name, input, context) {
|
|
14
21
|
const tool = this.registry.get(name);
|
|
15
22
|
if (!tool) {
|
|
16
|
-
|
|
23
|
+
const availableTools = this.registry.list().map(t => t.name).join(', ');
|
|
24
|
+
return {
|
|
25
|
+
data: `Unknown tool: "${name}". Available tools: ${availableTools}`,
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Validate input through Zod schema with corrective error messages
|
|
30
|
+
const validation = validateToolInput(name, input, tool.inputSchema);
|
|
31
|
+
if (!validation.ok) {
|
|
32
|
+
return { data: validation.message, isError: true };
|
|
17
33
|
}
|
|
18
34
|
try {
|
|
19
|
-
const parsed = tool.inputSchema.parse(input);
|
|
20
35
|
await this.acquire();
|
|
21
36
|
try {
|
|
22
|
-
return await tool.execute(parsed, context);
|
|
37
|
+
return await tool.execute(validation.parsed, context);
|
|
23
38
|
}
|
|
24
39
|
finally {
|
|
25
40
|
this.release();
|
|
@@ -27,7 +42,7 @@ export class ToolExecutor {
|
|
|
27
42
|
}
|
|
28
43
|
catch (err) {
|
|
29
44
|
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
-
return { data: `Tool "${name}" error: ${message}`, isError: true };
|
|
45
|
+
return { data: `Tool "${name}" execution error: ${message}`, isError: true };
|
|
31
46
|
}
|
|
32
47
|
}
|
|
33
48
|
async executeBatch(calls, context) {
|