skimpyclaw 0.3.15 → 0.4.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.
- package/README.md +47 -37
- package/dist/__tests__/adapter-types.test.d.ts +4 -0
- package/dist/__tests__/adapter-types.test.js +63 -0
- package/dist/__tests__/anthropic-adapter.test.d.ts +4 -0
- package/dist/__tests__/anthropic-adapter.test.js +264 -0
- package/dist/__tests__/api.test.js +0 -1
- package/dist/__tests__/cli.integration.test.js +2 -4
- package/dist/__tests__/cli.test.js +0 -1
- package/dist/__tests__/code-agents-notifications.test.js +137 -0
- package/dist/__tests__/code-agents-parser.test.js +19 -1
- package/dist/__tests__/code-agents-preflight.test.js +3 -28
- package/dist/__tests__/code-agents-utils.test.js +34 -9
- package/dist/__tests__/code-agents-worktrees.test.js +116 -0
- package/dist/__tests__/codex-adapter.test.js +184 -0
- package/dist/__tests__/codex-auth.test.js +66 -0
- package/dist/__tests__/codex-provider-gating.test.js +35 -0
- package/dist/__tests__/codex-unified-loop.test.js +111 -0
- package/dist/__tests__/config-security.test.js +127 -0
- package/dist/__tests__/config.test.js +23 -0
- package/dist/__tests__/context-manager.test.js +243 -164
- package/dist/__tests__/cron-run.test.js +250 -0
- package/dist/__tests__/cron.test.js +12 -38
- package/dist/__tests__/digests.test.js +67 -0
- package/dist/__tests__/discord-attachments.test.js +211 -0
- package/dist/__tests__/discord-docs.test.d.ts +1 -0
- package/dist/__tests__/discord-docs.test.js +27 -0
- package/dist/__tests__/discord-thread-agents.test.d.ts +1 -0
- package/dist/__tests__/discord-thread-agents.test.js +115 -0
- package/dist/__tests__/discord-thread-context.test.d.ts +1 -0
- package/dist/__tests__/discord-thread-context.test.js +42 -0
- package/dist/__tests__/doctor.formatters.test.js +4 -4
- package/dist/__tests__/doctor.index.test.js +1 -1
- package/dist/__tests__/doctor.runner.test.js +3 -15
- package/dist/__tests__/env-sanitizer.test.d.ts +1 -0
- package/dist/__tests__/env-sanitizer.test.js +45 -0
- package/dist/__tests__/exec-approval.test.js +61 -0
- package/dist/__tests__/fetch-tool.test.d.ts +1 -0
- package/dist/__tests__/fetch-tool.test.js +85 -0
- package/dist/__tests__/gateway-status-auth.test.d.ts +1 -0
- package/dist/__tests__/gateway-status-auth.test.js +72 -0
- package/dist/__tests__/heartbeat.test.js +3 -3
- package/dist/__tests__/interactive-sessions.test.d.ts +1 -0
- package/dist/__tests__/interactive-sessions.test.js +96 -0
- package/dist/__tests__/langfuse.test.js +6 -18
- package/dist/__tests__/model-selection.test.js +3 -4
- package/dist/__tests__/providers-init.test.js +2 -8
- package/dist/__tests__/providers-routing.test.js +1 -1
- package/dist/__tests__/providers-utils.test.js +13 -3
- package/dist/__tests__/sessions.test.js +14 -10
- package/dist/__tests__/setup.test.js +12 -29
- package/dist/__tests__/skills.test.js +10 -7
- package/dist/__tests__/stream-formatter.test.d.ts +1 -0
- package/dist/__tests__/stream-formatter.test.js +114 -0
- package/dist/__tests__/token-efficiency.test.js +131 -15
- package/dist/__tests__/tool-loop.test.d.ts +4 -0
- package/dist/__tests__/tool-loop.test.js +505 -0
- package/dist/__tests__/tools.test.js +100 -276
- package/dist/__tests__/utils.test.d.ts +1 -0
- package/dist/__tests__/utils.test.js +14 -0
- package/dist/__tests__/voice.test.js +21 -0
- package/dist/agent.js +35 -4
- package/dist/api.js +113 -37
- package/dist/channels/discord/attachments.d.ts +50 -0
- package/dist/channels/discord/attachments.js +137 -0
- package/dist/channels/discord/delegation.d.ts +5 -0
- package/dist/channels/discord/delegation.js +136 -0
- package/dist/channels/discord/handlers.js +694 -7
- package/dist/channels/discord/index.d.ts +16 -1
- package/dist/channels/discord/index.js +64 -1
- package/dist/channels/discord/thread-agents.d.ts +54 -0
- package/dist/channels/discord/thread-agents.js +323 -0
- package/dist/channels/discord/threads.d.ts +58 -0
- package/dist/channels/discord/threads.js +192 -0
- package/dist/channels/discord/types.js +4 -2
- package/dist/channels/discord/utils.d.ts +16 -0
- package/dist/channels/discord/utils.js +86 -6
- package/dist/channels/telegram/index.d.ts +1 -1
- package/dist/channels/telegram/types.js +1 -1
- package/dist/channels/telegram/utils.js +9 -3
- package/dist/channels.d.ts +1 -1
- package/dist/cli.js +20 -400
- package/dist/code-agents/executor.d.ts +1 -1
- package/dist/code-agents/executor.js +101 -45
- package/dist/code-agents/index.d.ts +2 -7
- package/dist/code-agents/index.js +111 -80
- package/dist/code-agents/interactive-resume.d.ts +6 -0
- package/dist/code-agents/interactive-resume.js +98 -0
- package/dist/code-agents/interactive-sessions.d.ts +20 -0
- package/dist/code-agents/interactive-sessions.js +132 -0
- package/dist/code-agents/parser.js +5 -1
- package/dist/code-agents/registry.d.ts +7 -1
- package/dist/code-agents/registry.js +11 -23
- package/dist/code-agents/stream-formatter.d.ts +8 -0
- package/dist/code-agents/stream-formatter.js +92 -0
- package/dist/code-agents/types.d.ts +16 -24
- package/dist/code-agents/utils.d.ts +35 -11
- package/dist/code-agents/utils.js +348 -95
- package/dist/code-agents/worktrees.d.ts +37 -0
- package/dist/code-agents/worktrees.js +116 -0
- package/dist/config.d.ts +2 -4
- package/dist/config.js +123 -23
- package/dist/cron.d.ts +1 -6
- package/dist/cron.js +175 -82
- package/dist/dashboard/assets/index-B345aOO-.js +65 -0
- package/dist/dashboard/assets/index-ZWK4dalJ.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/digests.d.ts +1 -0
- package/dist/digests.js +132 -42
- package/dist/doctor/checks.d.ts +0 -3
- package/dist/doctor/checks.js +1 -108
- package/dist/doctor/runner.js +1 -4
- package/dist/env-sanitizer.d.ts +2 -0
- package/dist/env-sanitizer.js +61 -0
- package/dist/exec-approval.d.ts +11 -1
- package/dist/exec-approval.js +17 -4
- package/dist/gateway.d.ts +3 -1
- package/dist/gateway.js +17 -7
- package/dist/heartbeat.js +1 -6
- package/dist/langfuse.js +3 -29
- package/dist/model-selection.js +3 -1
- package/dist/providers/adapter.d.ts +118 -0
- package/dist/providers/adapter.js +6 -0
- package/dist/providers/adapters/anthropic-adapter.d.ts +22 -0
- package/dist/providers/adapters/anthropic-adapter.js +204 -0
- package/dist/providers/adapters/codex-adapter.d.ts +26 -0
- package/dist/providers/adapters/codex-adapter.js +203 -0
- package/dist/providers/anthropic.d.ts +1 -0
- package/dist/providers/anthropic.js +10 -272
- package/dist/providers/codex.d.ts +21 -0
- package/dist/providers/codex.js +149 -330
- package/dist/providers/content.d.ts +1 -1
- package/dist/providers/content.js +2 -2
- package/dist/providers/context-manager.d.ts +18 -6
- package/dist/providers/context-manager.js +199 -223
- package/dist/providers/index.d.ts +9 -1
- package/dist/providers/index.js +73 -64
- package/dist/providers/loop-utils.d.ts +20 -0
- package/dist/providers/loop-utils.js +30 -0
- package/dist/providers/tool-loop.d.ts +12 -0
- package/dist/providers/tool-loop.js +251 -0
- package/dist/providers/utils.d.ts +19 -3
- package/dist/providers/utils.js +100 -29
- package/dist/secure-store.d.ts +8 -0
- package/dist/secure-store.js +80 -0
- package/dist/service.js +3 -28
- package/dist/sessions.d.ts +3 -0
- package/dist/sessions.js +147 -18
- package/dist/setup-templates.js +13 -25
- package/dist/setup.d.ts +10 -6
- package/dist/setup.js +84 -292
- package/dist/skills.js +3 -11
- package/dist/tools/agent-delegation.d.ts +19 -0
- package/dist/tools/agent-delegation.js +49 -0
- package/dist/tools/bash-tool.js +89 -34
- package/dist/tools/definitions.d.ts +199 -302
- package/dist/tools/definitions.js +70 -123
- package/dist/tools/execute-context.d.ts +13 -4
- package/dist/tools/fetch-tool.js +109 -13
- package/dist/tools/file-tools.js +7 -1
- package/dist/tools.d.ts +7 -7
- package/dist/tools.js +133 -151
- package/dist/types.d.ts +37 -30
- package/dist/utils.js +4 -6
- package/dist/voice.d.ts +1 -1
- package/dist/voice.js +17 -4
- package/package.json +33 -23
- package/templates/TOOLS.md +0 -27
- package/dist/__tests__/audit.test.js +0 -122
- package/dist/__tests__/code-agents-orchestrator.test.js +0 -216
- package/dist/__tests__/code-agents-sandbox.test.js +0 -163
- package/dist/__tests__/orchestrator.test.js +0 -425
- package/dist/__tests__/sandbox-bridge.test.js +0 -116
- package/dist/__tests__/sandbox-manager.test.js +0 -144
- package/dist/__tests__/sandbox-mount-security.test.js +0 -139
- package/dist/__tests__/sandbox-runtime.test.js +0 -176
- package/dist/__tests__/subagent.test.js +0 -240
- package/dist/__tests__/telegram.test.js +0 -42
- package/dist/code-agents/orchestrator.d.ts +0 -29
- package/dist/code-agents/orchestrator.js +0 -694
- package/dist/code-agents/worktree.d.ts +0 -40
- package/dist/code-agents/worktree.js +0 -215
- package/dist/dashboard/assets/index-BoTHPby4.js +0 -65
- package/dist/dashboard/assets/index-D4mufvBg.css +0 -1
- package/dist/dashboard.d.ts +0 -8
- package/dist/dashboard.js +0 -4071
- package/dist/discord.d.ts +0 -8
- package/dist/discord.js +0 -792
- package/dist/mcp-context-a8c.d.ts +0 -13
- package/dist/mcp-context-a8c.js +0 -34
- package/dist/orchestrator.d.ts +0 -15
- package/dist/orchestrator.js +0 -676
- package/dist/providers/openai.d.ts +0 -10
- package/dist/providers/openai.js +0 -355
- package/dist/sandbox/bridge.d.ts +0 -5
- package/dist/sandbox/bridge.js +0 -63
- package/dist/sandbox/index.d.ts +0 -5
- package/dist/sandbox/index.js +0 -4
- package/dist/sandbox/manager.d.ts +0 -7
- package/dist/sandbox/manager.js +0 -100
- package/dist/sandbox/mount-security.d.ts +0 -12
- package/dist/sandbox/mount-security.js +0 -122
- package/dist/sandbox/runtime.d.ts +0 -39
- package/dist/sandbox/runtime.js +0 -192
- package/dist/sandbox-utils.d.ts +0 -6
- package/dist/sandbox-utils.js +0 -36
- package/dist/subagent.d.ts +0 -19
- package/dist/subagent.js +0 -407
- package/dist/telegram.d.ts +0 -2
- package/dist/telegram.js +0 -11
- package/dist/tools/browser-tool.d.ts +0 -3
- package/dist/tools/browser-tool.js +0 -266
- package/sandbox/Dockerfile +0 -40
- /package/dist/__tests__/{audit.test.d.ts → code-agents-notifications.test.d.ts} +0 -0
- /package/dist/__tests__/{code-agents-orchestrator.test.d.ts → code-agents-worktrees.test.d.ts} +0 -0
- /package/dist/__tests__/{code-agents-sandbox.test.d.ts → codex-adapter.test.d.ts} +0 -0
- /package/dist/__tests__/{orchestrator.test.d.ts → codex-auth.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-bridge.test.d.ts → codex-provider-gating.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-manager.test.d.ts → codex-unified-loop.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-mount-security.test.d.ts → config-security.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-runtime.test.d.ts → cron-run.test.d.ts} +0 -0
- /package/dist/__tests__/{subagent.test.d.ts → digests.test.d.ts} +0 -0
- /package/dist/__tests__/{telegram.test.d.ts → discord-attachments.test.d.ts} +0 -0
|
@@ -5,7 +5,6 @@ const TOOL_NAME_MAP = {
|
|
|
5
5
|
'Write': 'write_file',
|
|
6
6
|
'Glob': 'list_directory',
|
|
7
7
|
'Bash': 'bash',
|
|
8
|
-
'Browser': 'browser',
|
|
9
8
|
};
|
|
10
9
|
// Reverse map: internal name -> Claude Code name
|
|
11
10
|
const INTERNAL_TO_CC = Object.fromEntries(Object.entries(TOOL_NAME_MAP).map(([cc, internal]) => [internal, cc]));
|
|
@@ -21,156 +20,104 @@ export function toClaudeCodeName(name) {
|
|
|
21
20
|
export const BUILTIN_TOOL_DEFINITIONS = [
|
|
22
21
|
{
|
|
23
22
|
name: 'Read',
|
|
24
|
-
|
|
25
|
-
input_schema: {
|
|
26
|
-
type: 'object',
|
|
27
|
-
properties: {
|
|
28
|
-
file_path: { type: 'string', description: 'Absolute path to the file to read' },
|
|
29
|
-
},
|
|
30
|
-
required: ['file_path'],
|
|
31
|
-
},
|
|
23
|
+
input_schema: { type: 'object', properties: { path: {} } },
|
|
32
24
|
},
|
|
33
25
|
{
|
|
34
26
|
name: 'Write',
|
|
35
|
-
|
|
36
|
-
input_schema: {
|
|
37
|
-
type: 'object',
|
|
38
|
-
properties: {
|
|
39
|
-
file_path: { type: 'string', description: 'Absolute path to the file to write' },
|
|
40
|
-
content: { type: 'string', description: 'Content to write to the file' },
|
|
41
|
-
},
|
|
42
|
-
required: ['file_path', 'content'],
|
|
43
|
-
},
|
|
27
|
+
input_schema: { type: 'object', properties: { path: {}, content: {} }, required: ['path', 'content'] },
|
|
44
28
|
},
|
|
45
29
|
{
|
|
46
30
|
name: 'Glob',
|
|
47
|
-
|
|
48
|
-
input_schema: {
|
|
49
|
-
type: 'object',
|
|
50
|
-
properties: {
|
|
51
|
-
path: { type: 'string', description: 'Absolute path to the directory to list' },
|
|
52
|
-
},
|
|
53
|
-
required: ['path'],
|
|
54
|
-
},
|
|
31
|
+
input_schema: { type: 'object', properties: { pattern: {} } },
|
|
55
32
|
},
|
|
56
33
|
{
|
|
57
34
|
name: 'Bash',
|
|
58
|
-
|
|
59
|
-
input_schema: {
|
|
60
|
-
type: 'object',
|
|
61
|
-
properties: {
|
|
62
|
-
command: { type: 'string', description: 'Shell command to execute' },
|
|
63
|
-
cwd: { type: 'string', description: 'Working directory (optional)' },
|
|
64
|
-
},
|
|
65
|
-
required: ['command'],
|
|
66
|
-
},
|
|
35
|
+
input_schema: { type: 'object', properties: { cmd: {} } },
|
|
67
36
|
},
|
|
68
37
|
];
|
|
69
|
-
export const BROWSER_TOOL_DEFINITION = {
|
|
70
|
-
name: 'Browser',
|
|
71
|
-
description: `Control a browser via Playwright. Actions (case-insensitive):
|
|
72
|
-
- open: Navigate to URL. Required: url
|
|
73
|
-
- click: Click element. Required: selector
|
|
74
|
-
- type: Fill input. Required: selector, text
|
|
75
|
-
- select: Pick dropdown option. Required: selector, text (value)
|
|
76
|
-
- hover: Hover element. Required: selector
|
|
77
|
-
- scroll: Scroll page. Optional: selector (scrollIntoView), direction (up/down), amount (pixels)
|
|
78
|
-
- waitFor: Wait for element/text. Required: selector OR text
|
|
79
|
-
- evaluate: Run JavaScript in page. Required: script. Returns JSON result.
|
|
80
|
-
- getText: Get visible text. Optional: selector (defaults to full page body text)
|
|
81
|
-
- screenshot: Capture page. Optional: file_path
|
|
82
|
-
- wait: Delay. Required: timeMs
|
|
83
|
-
- close: Close browser`,
|
|
84
|
-
input_schema: {
|
|
85
|
-
type: 'object',
|
|
86
|
-
properties: {
|
|
87
|
-
action: { type: 'string', description: 'Action to perform (see description)' },
|
|
88
|
-
type: { type: 'string', description: 'Browser type: chromium | firefox | webkit (optional, config default)' },
|
|
89
|
-
url: { type: 'string', description: 'URL to open (open action)' },
|
|
90
|
-
selector: { type: 'string', description: 'CSS selector (click/type/waitFor/getText/scroll/select/hover)' },
|
|
91
|
-
text: { type: 'string', description: 'Text to type, wait for, or select value (type/waitFor/select)' },
|
|
92
|
-
script: { type: 'string', description: 'JavaScript code to evaluate in page (evaluate action)' },
|
|
93
|
-
direction: { type: 'string', description: 'Scroll direction: up or down (scroll action, default: down)' },
|
|
94
|
-
amount: { type: 'number', description: 'Pixels to scroll (scroll action, default: one viewport height)' },
|
|
95
|
-
file_path: { type: 'string', description: 'Absolute path to save screenshot (optional)' },
|
|
96
|
-
timeoutMs: { type: 'number', description: 'Timeout in ms (optional)' },
|
|
97
|
-
timeMs: { type: 'number', description: 'Time to wait in ms (wait action)' },
|
|
98
|
-
headless: { type: 'boolean', description: 'Override headless for open (optional)' },
|
|
99
|
-
slowMoMs: { type: 'number', description: 'Slow motion delay per action (ms) (optional)' },
|
|
100
|
-
userAgent: { type: 'string', description: 'Override user agent (optional)' },
|
|
101
|
-
viewport: {
|
|
102
|
-
type: 'object',
|
|
103
|
-
properties: {
|
|
104
|
-
width: { type: 'number' },
|
|
105
|
-
height: { type: 'number' },
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
// executablePath and profileDir are config-only for security (no model overrides)
|
|
109
|
-
},
|
|
110
|
-
required: ['action'],
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
38
|
export const FETCH_TOOL_DEFINITION = {
|
|
114
39
|
name: 'Fetch',
|
|
115
|
-
|
|
116
|
-
input_schema: {
|
|
117
|
-
type: 'object',
|
|
118
|
-
properties: {
|
|
119
|
-
url: { type: 'string', description: 'URL to fetch' },
|
|
120
|
-
method: { type: 'string', description: 'HTTP method (GET, POST, PUT, DELETE, PATCH). Default: GET' },
|
|
121
|
-
headers: {
|
|
122
|
-
type: 'object',
|
|
123
|
-
description: 'Request headers (e.g. {"Authorization": "Bearer ..."})',
|
|
124
|
-
additionalProperties: { type: 'string' },
|
|
125
|
-
},
|
|
126
|
-
body: { type: 'string', description: 'Request body (for POST/PUT/PATCH)' },
|
|
127
|
-
},
|
|
128
|
-
required: ['url'],
|
|
129
|
-
},
|
|
40
|
+
input_schema: { type: 'object', properties: { url: {} } },
|
|
130
41
|
};
|
|
131
|
-
// Legacy export for backward compat — static list (built-ins +
|
|
132
|
-
export const TOOL_DEFINITIONS = [...BUILTIN_TOOL_DEFINITIONS,
|
|
42
|
+
// Legacy export for backward compat — static list (built-ins + fetch + no MCP)
|
|
43
|
+
export const TOOL_DEFINITIONS = [...BUILTIN_TOOL_DEFINITIONS, FETCH_TOOL_DEFINITION];
|
|
133
44
|
export const CODE_WITH_AGENT_TOOL = {
|
|
134
45
|
name: 'code_with_agent',
|
|
135
|
-
description: 'Delegate a coding task to a coding agent CLI (Claude Code or Codex). The agent will edit files, run commands, and return results. Always use this for code changes instead of writing code directly.',
|
|
136
|
-
input_schema: {
|
|
137
|
-
type: 'object',
|
|
138
|
-
properties: {
|
|
139
|
-
task: { type: 'string', description: 'Detailed coding task. Be specific: what to change, why, which files, expected behavior.' },
|
|
140
|
-
agent: { type: 'string', enum: ['claude', 'codex', 'kimi'], description: 'Which coding CLI to use. Omit to use configured default.' },
|
|
141
|
-
workdir: { type: 'string', description: 'Working directory (default: SkimpyClaw repo root)' },
|
|
142
|
-
model: { type: 'string', description: 'Model override (e.g. opus, gpt-5.3-codex)' },
|
|
143
|
-
max_turns: { type: 'number', description: 'Max agentic turns, Claude only (default: 30)' },
|
|
144
|
-
timeout_minutes: { type: 'number', description: 'Timeout in minutes (default: 10, max: 30)' },
|
|
145
|
-
validate: { type: 'boolean', description: 'Run build && test after completion using the auto-detected package manager (default: true)' },
|
|
146
|
-
},
|
|
147
|
-
required: ['task'],
|
|
148
|
-
},
|
|
149
|
-
};
|
|
150
|
-
export const CODE_WITH_TEAM_TOOL = {
|
|
151
|
-
name: 'code_with_team',
|
|
152
|
-
description: 'Decompose a complex task into subtasks and run multiple code_with_agent instances in parallel. SkimpyClaw manages coordination: decomposes the task, spawns N parallel agents, monitors progress, synthesizes results, and validates. Use for multi-file refactors, cross-layer changes, or tasks with independent subtasks.',
|
|
153
46
|
input_schema: {
|
|
154
47
|
type: 'object',
|
|
155
48
|
properties: {
|
|
156
|
-
task: { type: 'string'
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
49
|
+
task: { type: 'string' },
|
|
50
|
+
agent: { type: 'string' },
|
|
51
|
+
interactive: {
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
description: 'If true, spawn as an interactive session. Creates a Discord thread and resumes session on follow-up messages. Discord-only; claude or codex only. Default false.',
|
|
54
|
+
},
|
|
55
|
+
effort: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
enum: ['none', 'low', 'medium', 'high', 'xhigh'],
|
|
58
|
+
description: 'Optional reasoning effort for coding agents that support it.',
|
|
59
|
+
},
|
|
60
|
+
worktree: {
|
|
61
|
+
description: 'Use an isolated git worktree for this task. true forces one, false disables it, auto uses one for review/rebase-style tasks. Default auto.',
|
|
62
|
+
},
|
|
163
63
|
},
|
|
164
64
|
required: ['task'],
|
|
165
65
|
},
|
|
166
66
|
};
|
|
167
67
|
export const CHECK_CODE_AGENT_TOOL = {
|
|
168
68
|
name: 'check_code_agent',
|
|
169
|
-
|
|
69
|
+
input_schema: { type: 'object', properties: { id: { type: 'string' } } },
|
|
70
|
+
};
|
|
71
|
+
export const DELEGATE_TO_AGENT_TOOL = {
|
|
72
|
+
name: 'delegate_to_agent',
|
|
170
73
|
input_schema: {
|
|
171
74
|
type: 'object',
|
|
172
75
|
properties: {
|
|
173
|
-
|
|
76
|
+
alias: {
|
|
77
|
+
type: 'string',
|
|
78
|
+
description: 'Discord agent profile alias to delegate to, without @.',
|
|
79
|
+
},
|
|
80
|
+
task: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
description: 'Task or question for the target agent profile.',
|
|
83
|
+
},
|
|
84
|
+
mode: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
enum: ['new_thread'],
|
|
87
|
+
description: 'Delegation mode. Only new_thread is currently supported.',
|
|
88
|
+
},
|
|
89
|
+
wait: {
|
|
90
|
+
type: 'boolean',
|
|
91
|
+
description: 'If true, wait for the delegated agent response. Default false.',
|
|
92
|
+
},
|
|
174
93
|
},
|
|
94
|
+
required: ['alias', 'task'],
|
|
175
95
|
},
|
|
176
96
|
};
|
|
97
|
+
// Glob tool reference for dynamic loading
|
|
98
|
+
const GLOB_TOOL = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'Glob');
|
|
99
|
+
// Write tool reference for dynamic loading
|
|
100
|
+
const WRITE_TOOL = BUILTIN_TOOL_DEFINITIONS.find(t => t.name === 'Write');
|
|
101
|
+
// Core tools — always sent. Extended tools added when conversation references them.
|
|
102
|
+
export const CORE_TOOL_DEFINITIONS = [...BUILTIN_TOOL_DEFINITIONS.filter(t => t.name !== 'Glob' && t.name !== 'Write')];
|
|
103
|
+
export const EXTENDED_TOOL_DEFINITIONS = [WRITE_TOOL, GLOB_TOOL, FETCH_TOOL_DEFINITION, CODE_WITH_AGENT_TOOL, CHECK_CODE_AGENT_TOOL, DELEGATE_TO_AGENT_TOOL];
|
|
104
|
+
// Keywords that trigger inclusion of extended tools
|
|
105
|
+
const TOOL_TRIGGERS = {
|
|
106
|
+
Write: ['write', 'create file', 'save', 'update file', 'fix', 'edit', 'modify', 'change'],
|
|
107
|
+
Glob: ['glob', 'list_directory', 'find files', 'directory listing'],
|
|
108
|
+
Fetch: ['fetch', 'http://', 'https://', 'curl', 'api call'],
|
|
109
|
+
code_with_agent: ['code_with_agent', 'delegate', 'subagent', 'sub-agent'],
|
|
110
|
+
check_code_agent: ['check_code_agent', 'agent status', 'agent_id'],
|
|
111
|
+
delegate_to_agent: ['delegate_to_agent', 'delegate to agent', 'call agent', 'ask agent', '@agent'],
|
|
112
|
+
};
|
|
113
|
+
/** Return tool defs filtered by what's been used/mentioned in conversation */
|
|
114
|
+
export function getActiveToolDefs(messages) {
|
|
115
|
+
const msgStr = JSON.stringify(messages).toLowerCase();
|
|
116
|
+
const extra = [];
|
|
117
|
+
for (const t of EXTENDED_TOOL_DEFINITIONS) {
|
|
118
|
+
const triggers = TOOL_TRIGGERS[t.name] || [t.name.toLowerCase()];
|
|
119
|
+
if (triggers.some(kw => msgStr.includes(kw)))
|
|
120
|
+
extra.push(t);
|
|
121
|
+
}
|
|
122
|
+
return [...CORE_TOOL_DEFINITIONS, ...extra];
|
|
123
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { AbortSignalLike } from '../types.js';
|
|
1
2
|
export interface ExecuteToolContext {
|
|
2
3
|
/** Task ID for file lock acquisition (concurrent writes) */
|
|
3
4
|
lockTaskId?: string;
|
|
4
5
|
/** Abort signal for cancelling long-running tool loops */
|
|
5
|
-
abortSignal?:
|
|
6
|
+
abortSignal?: AbortSignalLike;
|
|
6
7
|
/** Chat ID for channel routing */
|
|
7
8
|
chatId?: number;
|
|
8
9
|
/** Full config for agent tools */
|
|
@@ -25,8 +26,16 @@ export interface ExecuteToolContext {
|
|
|
25
26
|
agentId?: string;
|
|
26
27
|
/** True when this context is from a cron job — enables spawn tools even without a chatId */
|
|
27
28
|
isCronJob?: boolean;
|
|
28
|
-
/**
|
|
29
|
-
sandboxConfig?: import('../types.js').SandboxConfig;
|
|
30
|
-
/** Session ID for sandbox container mapping */
|
|
29
|
+
/** Session ID used as file-lock scope + interactive-session key */
|
|
31
30
|
sessionId?: string;
|
|
31
|
+
/** Discord thread ID — set when command originates from a thread */
|
|
32
|
+
discordThreadId?: string;
|
|
33
|
+
/** Discord channel ID — parent channel when originating from a thread */
|
|
34
|
+
discordChannelId?: string;
|
|
35
|
+
/** True when Discord message originated from a DM (threads not supported) */
|
|
36
|
+
isDm?: boolean;
|
|
37
|
+
/** Discord agent profile alias for the current thread/profile turn */
|
|
38
|
+
threadAgentAlias?: string;
|
|
39
|
+
/** Nested agent delegation depth */
|
|
40
|
+
delegationDepth?: number;
|
|
32
41
|
}
|
package/dist/tools/fetch-tool.js
CHANGED
|
@@ -1,6 +1,84 @@
|
|
|
1
1
|
// Fetch tool — lightweight HTTP requests and web search without browser overhead
|
|
2
|
+
import { lookup } from 'dns/promises';
|
|
3
|
+
import { BlockList, isIP } from 'net';
|
|
2
4
|
const MAX_RESPONSE_CHARS = 50_000;
|
|
3
5
|
const TIMEOUT_MS = 30_000;
|
|
6
|
+
const MAX_REDIRECTS = 5;
|
|
7
|
+
const BLOCKED_HOSTNAMES = new Set([
|
|
8
|
+
'localhost',
|
|
9
|
+
'localhost.localdomain',
|
|
10
|
+
'metadata',
|
|
11
|
+
'metadata.google.internal',
|
|
12
|
+
'metadata.google.internal.',
|
|
13
|
+
'instance-data',
|
|
14
|
+
]);
|
|
15
|
+
const BLOCKED_HOST_SUFFIXES = ['.internal', '.local', '.lan', '.home', '.localhost'];
|
|
16
|
+
const IP_BLOCKLIST = (() => {
|
|
17
|
+
const blockList = new BlockList();
|
|
18
|
+
blockList.addSubnet('0.0.0.0', 8, 'ipv4');
|
|
19
|
+
blockList.addSubnet('10.0.0.0', 8, 'ipv4');
|
|
20
|
+
blockList.addSubnet('100.64.0.0', 10, 'ipv4');
|
|
21
|
+
blockList.addSubnet('127.0.0.0', 8, 'ipv4');
|
|
22
|
+
blockList.addSubnet('169.254.0.0', 16, 'ipv4');
|
|
23
|
+
blockList.addSubnet('172.16.0.0', 12, 'ipv4');
|
|
24
|
+
blockList.addSubnet('192.0.0.0', 24, 'ipv4');
|
|
25
|
+
blockList.addSubnet('192.0.2.0', 24, 'ipv4');
|
|
26
|
+
blockList.addSubnet('192.168.0.0', 16, 'ipv4');
|
|
27
|
+
blockList.addSubnet('198.18.0.0', 15, 'ipv4');
|
|
28
|
+
blockList.addSubnet('198.51.100.0', 24, 'ipv4');
|
|
29
|
+
blockList.addSubnet('203.0.113.0', 24, 'ipv4');
|
|
30
|
+
blockList.addSubnet('224.0.0.0', 4, 'ipv4');
|
|
31
|
+
blockList.addSubnet('240.0.0.0', 4, 'ipv4');
|
|
32
|
+
blockList.addAddress('::', 'ipv6');
|
|
33
|
+
blockList.addAddress('::1', 'ipv6');
|
|
34
|
+
blockList.addSubnet('fc00::', 7, 'ipv6');
|
|
35
|
+
blockList.addSubnet('fe80::', 10, 'ipv6');
|
|
36
|
+
blockList.addSubnet('ff00::', 8, 'ipv6');
|
|
37
|
+
blockList.addSubnet('2001:db8::', 32, 'ipv6');
|
|
38
|
+
return blockList;
|
|
39
|
+
})();
|
|
40
|
+
function isBlockedIpAddress(address) {
|
|
41
|
+
if (address.startsWith('::ffff:')) {
|
|
42
|
+
return isBlockedIpAddress(address.slice('::ffff:'.length));
|
|
43
|
+
}
|
|
44
|
+
const family = isIP(address);
|
|
45
|
+
if (family === 4)
|
|
46
|
+
return IP_BLOCKLIST.check(address, 'ipv4');
|
|
47
|
+
if (family === 6)
|
|
48
|
+
return IP_BLOCKLIST.check(address, 'ipv6');
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
async function validateTarget(rawUrl) {
|
|
52
|
+
const parsed = new URL(rawUrl);
|
|
53
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
54
|
+
throw new Error(`Unsupported protocol: ${parsed.protocol}`);
|
|
55
|
+
}
|
|
56
|
+
const hostname = parsed.hostname.toLowerCase().replace(/\.$/, '');
|
|
57
|
+
if (BLOCKED_HOSTNAMES.has(hostname)) {
|
|
58
|
+
throw new Error(`Blocked host: ${hostname}`);
|
|
59
|
+
}
|
|
60
|
+
if (BLOCKED_HOST_SUFFIXES.some(suffix => hostname.endsWith(suffix))) {
|
|
61
|
+
throw new Error(`Blocked internal host: ${hostname}`);
|
|
62
|
+
}
|
|
63
|
+
if (isIP(hostname) !== 0 && isBlockedIpAddress(hostname)) {
|
|
64
|
+
throw new Error(`Blocked target IP: ${hostname}`);
|
|
65
|
+
}
|
|
66
|
+
if (isIP(hostname) === 0) {
|
|
67
|
+
const resolved = await lookup(hostname, { all: true, verbatim: true });
|
|
68
|
+
if (!resolved.length) {
|
|
69
|
+
throw new Error(`Could not resolve host: ${hostname}`);
|
|
70
|
+
}
|
|
71
|
+
for (const rec of resolved) {
|
|
72
|
+
if (isBlockedIpAddress(rec.address)) {
|
|
73
|
+
throw new Error(`Blocked resolved IP for ${hostname}: ${rec.address}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return parsed;
|
|
78
|
+
}
|
|
79
|
+
function isRedirectStatus(status) {
|
|
80
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
81
|
+
}
|
|
4
82
|
/**
|
|
5
83
|
* Strip HTML tags and decode common entities. Returns plain text.
|
|
6
84
|
*/
|
|
@@ -31,22 +109,40 @@ export async function executeFetch(input, _config) {
|
|
|
31
109
|
if (!url)
|
|
32
110
|
return 'Error: url is required';
|
|
33
111
|
try {
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return `Error: Invalid URL: ${url}`;
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
112
|
+
let target = await validateTarget(url);
|
|
40
113
|
const defaultHeaders = {
|
|
41
114
|
'User-Agent': 'SkimpyClaw/1.0',
|
|
42
115
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
116
|
+
let requestMethod = method.toUpperCase();
|
|
117
|
+
let requestBody = body || undefined;
|
|
118
|
+
let response = null;
|
|
119
|
+
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
120
|
+
response = await fetch(target, {
|
|
121
|
+
method: requestMethod,
|
|
122
|
+
headers: { ...defaultHeaders, ...headers },
|
|
123
|
+
body: requestBody,
|
|
124
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
125
|
+
redirect: 'manual',
|
|
126
|
+
});
|
|
127
|
+
if (!isRedirectStatus(response.status)) {
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
if (hop === MAX_REDIRECTS) {
|
|
131
|
+
return `Error: Too many redirects (>${MAX_REDIRECTS})`;
|
|
132
|
+
}
|
|
133
|
+
const location = response.headers.get('location');
|
|
134
|
+
if (!location) {
|
|
135
|
+
return `Error: Redirect response missing Location header (HTTP ${response.status})`;
|
|
136
|
+
}
|
|
137
|
+
target = await validateTarget(new URL(location, target).toString());
|
|
138
|
+
if ((response.status === 301 || response.status === 302 || response.status === 303) && requestMethod !== 'GET' && requestMethod !== 'HEAD') {
|
|
139
|
+
requestMethod = 'GET';
|
|
140
|
+
requestBody = undefined;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (!response) {
|
|
144
|
+
return 'Error: Request did not produce a response';
|
|
145
|
+
}
|
|
50
146
|
const status = `${response.status} ${response.statusText}`;
|
|
51
147
|
const contentType = response.headers.get('content-type') || '';
|
|
52
148
|
let responseBody;
|
package/dist/tools/file-tools.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, readdirSync, existsSync, statSync, mkdirSync } from 'fs';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
3
4
|
import { isPathAllowed } from './path-utils.js';
|
|
5
|
+
/** Expand ~ to home directory */
|
|
6
|
+
function expandTilde(p) {
|
|
7
|
+
return p.startsWith('~/') ? join(homedir(), p.slice(2)) : p;
|
|
8
|
+
}
|
|
4
9
|
export function executeReadFile(path, config) {
|
|
10
|
+
path = expandTilde(path);
|
|
5
11
|
if (!isPathAllowed(path, config.allowedPaths)) {
|
|
6
12
|
return `Error: Path not allowed. Permitted: ${config.allowedPaths.join(', ')}`;
|
|
7
13
|
}
|
|
@@ -23,7 +29,7 @@ function executeWriteFile(path, content, config) {
|
|
|
23
29
|
mkdirSync(dir, { recursive: true });
|
|
24
30
|
}
|
|
25
31
|
writeFileSync(path, content, 'utf-8');
|
|
26
|
-
return `
|
|
32
|
+
return `OK`;
|
|
27
33
|
}
|
|
28
34
|
/**
|
|
29
35
|
* Write with file locking when a lockTaskId is provided (concurrent context).
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import type { ToolConfig } from './types.js';
|
|
2
|
-
import { fromClaudeCodeName, toClaudeCodeName, BUILTIN_TOOL_DEFINITIONS,
|
|
2
|
+
import { fromClaudeCodeName, toClaudeCodeName, BUILTIN_TOOL_DEFINITIONS, FETCH_TOOL_DEFINITION, TOOL_DEFINITIONS, CODE_WITH_AGENT_TOOL, CHECK_CODE_AGENT_TOOL, DELEGATE_TO_AGENT_TOOL } from './tools/definitions.js';
|
|
3
3
|
import type { ExecuteToolContext } from './tools/execute-context.js';
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
export { fromClaudeCodeName, toClaudeCodeName, BUILTIN_TOOL_DEFINITIONS, BROWSER_TOOL_DEFINITION, FETCH_TOOL_DEFINITION, TOOL_DEFINITIONS, CODE_WITH_AGENT_TOOL, CODE_WITH_TEAM_TOOL, CHECK_CODE_AGENT_TOOL, cleanupBrowser, };
|
|
4
|
+
export { getActiveCodeAgents, getRecentCodeAgents, getAllCodeAgents, getCodeAgent, cancelCodeAgent, restoreCodeAgentTasks, setCodeAgentConfig, runValidation, runCodeAgentBackground, buildCodeAgentArgs, parseStreamJsonForLive, } from './code-agents/index.js';
|
|
5
|
+
export { fromClaudeCodeName, toClaudeCodeName, BUILTIN_TOOL_DEFINITIONS, FETCH_TOOL_DEFINITION, TOOL_DEFINITIONS, CODE_WITH_AGENT_TOOL, CHECK_CODE_AGENT_TOOL, DELEGATE_TO_AGENT_TOOL, };
|
|
7
6
|
export type { ExecuteToolContext };
|
|
8
|
-
export type { CodeAgentTask
|
|
7
|
+
export type { CodeAgentTask } from './code-agents/index.js';
|
|
9
8
|
export declare function discoverMcpTools(): Promise<any[]>;
|
|
10
9
|
export declare function clearMcpToolCache(): void;
|
|
11
10
|
/** Force-reconnect the MCP runtime (clears cached runtime and tool discovery). */
|
|
12
11
|
export declare function reconnectMcp(): Promise<void>;
|
|
13
12
|
/**
|
|
14
|
-
* Get all available tool definitions: built-ins +
|
|
13
|
+
* Get all available tool definitions: built-ins + fetch + MCP (auto-discovered) + agent tools.
|
|
15
14
|
* This is the primary way to get tools — replaces the static TOOL_DEFINITIONS export.
|
|
16
|
-
* Pass includeAgentTools: true to include code_with_agent
|
|
15
|
+
* Pass includeAgentTools: true to include code_with_agent and check_code_agent.
|
|
17
16
|
* Results are cached for 60s to avoid rebuilding the array on every agent turn.
|
|
18
17
|
*/
|
|
19
18
|
export declare function getToolDefinitions(config?: ToolConfig, options?: {
|
|
@@ -22,5 +21,6 @@ export declare function getToolDefinitions(config?: ToolConfig, options?: {
|
|
|
22
21
|
projects?: Record<string, string>;
|
|
23
22
|
}): Promise<any[]>;
|
|
24
23
|
export declare function clearToolDefsCache(): void;
|
|
24
|
+
export declare function normalizeMcpToolArgsForExecution(server: string, tool: string, args: Record<string, any>): Record<string, any>;
|
|
25
25
|
export declare function cleanupMcp(): Promise<void>;
|
|
26
26
|
export declare function executeTool(name: string, input: Record<string, any>, config: ToolConfig, context?: ExecuteToolContext): Promise<string>;
|