qlogicagent 0.2.1 → 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 +45 -45
- package/package.json +56 -42
- package/dist/agent/agent.d.ts +0 -43
- package/dist/agent/agent.js +0 -113
- package/dist/agent/tool-loop.d.ts +0 -64
- package/dist/agent/tool-loop.js +0 -575
- package/dist/agent/types.d.ts +0 -175
- package/dist/agent/types.js +0 -14
- package/dist/cli/main.d.ts +0 -11
- package/dist/cli/main.js +0 -23
- package/dist/cli/stdio-server.d.ts +0 -45
- package/dist/cli/stdio-server.js +0 -463
- package/dist/config/config.d.ts +0 -17
- package/dist/config/config.js +0 -21
- package/dist/contracts/hooks.d.ts +0 -120
- package/dist/contracts/hooks.js +0 -7
- package/dist/contracts/index.d.ts +0 -10
- package/dist/contracts/index.js +0 -10
- package/dist/contracts/planner.d.ts +0 -35
- package/dist/contracts/planner.js +0 -2
- package/dist/contracts/skill-candidate.d.ts +0 -63
- package/dist/contracts/skill-candidate.js +0 -195
- package/dist/contracts/todo.d.ts +0 -14
- package/dist/contracts/todo.js +0 -9
- package/dist/index.d.ts +0 -13
- package/dist/index.js +0 -15
- package/dist/llm/builtin-providers.d.ts +0 -10
- package/dist/llm/builtin-providers.js +0 -531
- package/dist/llm/index.d.ts +0 -15
- package/dist/llm/index.js +0 -14
- package/dist/llm/llm-client.d.ts +0 -43
- package/dist/llm/llm-client.js +0 -67
- package/dist/llm/model-catalog.d.ts +0 -53
- package/dist/llm/model-catalog.js +0 -191
- package/dist/llm/provider-def.d.ts +0 -59
- package/dist/llm/provider-def.js +0 -12
- package/dist/llm/provider-registry.d.ts +0 -54
- package/dist/llm/provider-registry.js +0 -147
- package/dist/llm/transport.d.ts +0 -62
- package/dist/llm/transport.js +0 -27
- package/dist/llm/transports/anthropic-messages.d.ts +0 -31
- package/dist/llm/transports/anthropic-messages.js +0 -293
- package/dist/llm/transports/openai-chat.d.ts +0 -36
- package/dist/llm/transports/openai-chat.js +0 -165
- package/dist/orchestration/agent-registry.d.ts +0 -41
- package/dist/orchestration/agent-registry.js +0 -116
- package/dist/orchestration/approval-aware-tool-plan.d.ts +0 -32
- package/dist/orchestration/approval-aware-tool-plan.js +0 -87
- package/dist/orchestration/context-compression.d.ts +0 -220
- package/dist/orchestration/context-compression.js +0 -583
- package/dist/orchestration/conversation-repair.d.ts +0 -61
- package/dist/orchestration/conversation-repair.js +0 -429
- package/dist/orchestration/curator-scheduler.d.ts +0 -119
- package/dist/orchestration/curator-scheduler.js +0 -135
- package/dist/orchestration/embedded-failover-policy.d.ts +0 -110
- package/dist/orchestration/embedded-failover-policy.js +0 -168
- package/dist/orchestration/error-classification.d.ts +0 -12
- package/dist/orchestration/error-classification.js +0 -77
- package/dist/orchestration/failover-classification.d.ts +0 -8
- package/dist/orchestration/failover-classification.js +0 -381
- package/dist/orchestration/failover-error.d.ts +0 -33
- package/dist/orchestration/failover-error.js +0 -198
- package/dist/orchestration/fork-subagent.d.ts +0 -100
- package/dist/orchestration/fork-subagent.js +0 -98
- package/dist/orchestration/index.d.ts +0 -120
- package/dist/orchestration/index.js +0 -267
- package/dist/orchestration/memory-flush-policy.d.ts +0 -57
- package/dist/orchestration/memory-flush-policy.js +0 -85
- package/dist/orchestration/memory-provider.d.ts +0 -14
- package/dist/orchestration/memory-provider.js +0 -2
- package/dist/orchestration/parallel-tool-calls.d.ts +0 -41
- package/dist/orchestration/parallel-tool-calls.js +0 -59
- package/dist/orchestration/prompt-cache-strategy.d.ts +0 -126
- package/dist/orchestration/prompt-cache-strategy.js +0 -228
- package/dist/orchestration/reactive-compact.d.ts +0 -73
- package/dist/orchestration/reactive-compact.js +0 -78
- package/dist/orchestration/retry-loop.d.ts +0 -22
- package/dist/orchestration/retry-loop.js +0 -24
- package/dist/orchestration/skill-candidate.d.ts +0 -52
- package/dist/orchestration/skill-candidate.js +0 -141
- package/dist/orchestration/skill-consolidation.d.ts +0 -123
- package/dist/orchestration/skill-consolidation.js +0 -220
- package/dist/orchestration/skill-improvement.d.ts +0 -59
- package/dist/orchestration/skill-improvement.js +0 -66
- package/dist/orchestration/skill-similarity.d.ts +0 -98
- package/dist/orchestration/skill-similarity.js +0 -131
- package/dist/orchestration/streaming-tool-executor.d.ts +0 -73
- package/dist/orchestration/streaming-tool-executor.js +0 -96
- package/dist/orchestration/team-orchestration.d.ts +0 -195
- package/dist/orchestration/team-orchestration.js +0 -369
- package/dist/orchestration/team-tool-loop-wiring.d.ts +0 -92
- package/dist/orchestration/team-tool-loop-wiring.js +0 -147
- package/dist/orchestration/tool-choice-policy.d.ts +0 -54
- package/dist/orchestration/tool-choice-policy.js +0 -164
- package/dist/orchestration/tool-loop-state.d.ts +0 -50
- package/dist/orchestration/tool-loop-state.js +0 -133
- package/dist/orchestration/tool-schema.d.ts +0 -39
- package/dist/orchestration/tool-schema.js +0 -297
- package/dist/orchestration/transcript-repair.d.ts +0 -42
- package/dist/orchestration/transcript-repair.js +0 -426
- package/dist/orchestration/turn-loop-guard.d.ts +0 -86
- package/dist/orchestration/turn-loop-guard.js +0 -92
- package/dist/orchestration/web-browser-policy.d.ts +0 -17
- package/dist/orchestration/web-browser-policy.js +0 -39
- package/dist/runtime/context-compression.d.ts +0 -61
- package/dist/runtime/context-compression.js +0 -274
- package/dist/runtime/hook-registry.d.ts +0 -12
- package/dist/runtime/hook-registry.js +0 -53
- package/dist/runtime/memory-hooks.d.ts +0 -23
- package/dist/runtime/memory-hooks.js +0 -65
- package/dist/runtime/tool-eligibility.d.ts +0 -59
- package/dist/runtime/tool-eligibility.js +0 -111
- package/dist/skills/index.d.ts +0 -108
- package/dist/skills/index.js +0 -82
- package/dist/skills/memory-extractor.d.ts +0 -64
- package/dist/skills/memory-extractor.js +0 -173
- package/dist/skills/memory-query-tool.d.ts +0 -43
- package/dist/skills/memory-query-tool.js +0 -127
- package/dist/skills/memory-store.d.ts +0 -66
- package/dist/skills/memory-store.js +0 -228
- package/dist/skills/memory-tool.d.ts +0 -67
- package/dist/skills/memory-tool.js +0 -192
- package/dist/skills/portable-tool.d.ts +0 -71
- package/dist/skills/portable-tool.js +0 -14
- package/dist/skills/qmemory-adapter.d.ts +0 -52
- package/dist/skills/qmemory-adapter.js +0 -165
- package/dist/skills/skill-frontmatter.d.ts +0 -19
- package/dist/skills/skill-frontmatter.js +0 -344
- package/dist/skills/skill-guard.d.ts +0 -23
- package/dist/skills/skill-guard.js +0 -229
- package/dist/skills/skill-loader.d.ts +0 -16
- package/dist/skills/skill-loader.js +0 -303
- package/dist/skills/skill-source.d.ts +0 -119
- package/dist/skills/skill-source.js +0 -126
- package/dist/skills/skill-types.d.ts +0 -199
- package/dist/skills/skill-types.js +0 -6
- package/dist/skills/think-tool.d.ts +0 -16
- package/dist/skills/think-tool.js +0 -59
- package/dist/skills/todo-tool.d.ts +0 -63
- package/dist/skills/todo-tool.js +0 -114
- package/dist/skills/tools/agent-tool.d.ts +0 -91
- package/dist/skills/tools/agent-tool.js +0 -142
- package/dist/skills/tools/apply-patch-tool.d.ts +0 -29
- package/dist/skills/tools/apply-patch-tool.js +0 -184
- package/dist/skills/tools/ask-user-tool.d.ts +0 -80
- package/dist/skills/tools/ask-user-tool.js +0 -121
- package/dist/skills/tools/brief-tool.d.ts +0 -74
- package/dist/skills/tools/brief-tool.js +0 -95
- package/dist/skills/tools/browser-tool.d.ts +0 -114
- package/dist/skills/tools/browser-tool.js +0 -155
- package/dist/skills/tools/checkpoint-tool.d.ts +0 -66
- package/dist/skills/tools/checkpoint-tool.js +0 -102
- package/dist/skills/tools/config-tool.d.ts +0 -63
- package/dist/skills/tools/config-tool.js +0 -143
- package/dist/skills/tools/cron-tool.d.ts +0 -116
- package/dist/skills/tools/cron-tool.js +0 -175
- package/dist/skills/tools/edit-tool.d.ts +0 -43
- package/dist/skills/tools/edit-tool.js +0 -70
- package/dist/skills/tools/exec-tool.d.ts +0 -102
- package/dist/skills/tools/exec-tool.js +0 -133
- package/dist/skills/tools/image-generate-tool.d.ts +0 -62
- package/dist/skills/tools/image-generate-tool.js +0 -67
- package/dist/skills/tools/instructions-tool.d.ts +0 -103
- package/dist/skills/tools/instructions-tool.js +0 -187
- package/dist/skills/tools/lsp-tool.d.ts +0 -153
- package/dist/skills/tools/lsp-tool.js +0 -227
- package/dist/skills/tools/mcp-client-types.d.ts +0 -269
- package/dist/skills/tools/mcp-client-types.js +0 -53
- package/dist/skills/tools/mcp-tool.d.ts +0 -249
- package/dist/skills/tools/mcp-tool.js +0 -503
- package/dist/skills/tools/memory-tool.d.ts +0 -74
- package/dist/skills/tools/memory-tool.js +0 -88
- package/dist/skills/tools/monitor-tool.d.ts +0 -113
- package/dist/skills/tools/monitor-tool.js +0 -131
- package/dist/skills/tools/music-generate-tool.d.ts +0 -55
- package/dist/skills/tools/music-generate-tool.js +0 -62
- package/dist/skills/tools/notify-tool.d.ts +0 -53
- package/dist/skills/tools/notify-tool.js +0 -62
- package/dist/skills/tools/patch-tool.d.ts +0 -45
- package/dist/skills/tools/patch-tool.js +0 -505
- package/dist/skills/tools/pdf-tool.d.ts +0 -66
- package/dist/skills/tools/pdf-tool.js +0 -88
- package/dist/skills/tools/plan-mode-tool.d.ts +0 -59
- package/dist/skills/tools/plan-mode-tool.js +0 -122
- package/dist/skills/tools/read-tool.d.ts +0 -51
- package/dist/skills/tools/read-tool.js +0 -84
- package/dist/skills/tools/repl-tool.d.ts +0 -70
- package/dist/skills/tools/repl-tool.js +0 -69
- package/dist/skills/tools/search-tool.d.ts +0 -112
- package/dist/skills/tools/search-tool.js +0 -225
- package/dist/skills/tools/send-message-tool.d.ts +0 -51
- package/dist/skills/tools/send-message-tool.js +0 -76
- package/dist/skills/tools/skill-list-tool.d.ts +0 -33
- package/dist/skills/tools/skill-list-tool.js +0 -54
- package/dist/skills/tools/skill-manage-tool.d.ts +0 -73
- package/dist/skills/tools/skill-manage-tool.js +0 -153
- package/dist/skills/tools/skill-view-tool.d.ts +0 -37
- package/dist/skills/tools/skill-view-tool.js +0 -72
- package/dist/skills/tools/sleep-tool.d.ts +0 -49
- package/dist/skills/tools/sleep-tool.js +0 -81
- package/dist/skills/tools/structured-output-tool.d.ts +0 -116
- package/dist/skills/tools/structured-output-tool.js +0 -176
- package/dist/skills/tools/task-tool.d.ts +0 -104
- package/dist/skills/tools/task-tool.js +0 -161
- package/dist/skills/tools/team-tool.d.ts +0 -89
- package/dist/skills/tools/team-tool.js +0 -105
- package/dist/skills/tools/tool-search-tool.d.ts +0 -51
- package/dist/skills/tools/tool-search-tool.js +0 -110
- package/dist/skills/tools/tts-tool.d.ts +0 -38
- package/dist/skills/tools/tts-tool.js +0 -45
- package/dist/skills/tools/video-edit-tool.d.ts +0 -69
- package/dist/skills/tools/video-edit-tool.js +0 -74
- package/dist/skills/tools/video-generate-tool.d.ts +0 -62
- package/dist/skills/tools/video-generate-tool.js +0 -66
- package/dist/skills/tools/video-merge-tool.d.ts +0 -105
- package/dist/skills/tools/video-merge-tool.js +0 -92
- package/dist/skills/tools/video-upscale-tool.d.ts +0 -45
- package/dist/skills/tools/video-upscale-tool.js +0 -52
- package/dist/skills/tools/web-fetch-tool.d.ts +0 -78
- package/dist/skills/tools/web-fetch-tool.js +0 -92
- package/dist/skills/tools/web-search-tool.d.ts +0 -57
- package/dist/skills/tools/web-search-tool.js +0 -86
- package/dist/skills/tools/worktree-tool.d.ts +0 -69
- package/dist/skills/tools/worktree-tool.js +0 -147
- package/dist/skills/tools/write-tool.d.ts +0 -45
- package/dist/skills/tools/write-tool.js +0 -81
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Search Tool — unified file name (glob) + content (grep) search.
|
|
3
|
-
// Fuses CC GlobTool + GrepTool into single PortableTool.
|
|
4
|
-
// Reference: claude-code-haha/src/tools/GlobTool/GlobTool.ts
|
|
5
|
-
// claude-code-haha/src/tools/GrepTool/GrepTool.ts
|
|
6
|
-
// Category: search
|
|
7
|
-
// ============================================================
|
|
8
|
-
export const SEARCH_TOOL_NAME = "search";
|
|
9
|
-
export const SEARCH_TOOL_SCHEMA = {
|
|
10
|
-
type: "object",
|
|
11
|
-
properties: {
|
|
12
|
-
mode: {
|
|
13
|
-
type: "string",
|
|
14
|
-
enum: ["filename", "content", "both"],
|
|
15
|
-
description: 'Search mode: "filename" to find files by name pattern (glob), ' +
|
|
16
|
-
'"content" to search within file contents (regex), ' +
|
|
17
|
-
'"both" to match both filename patterns and content simultaneously.',
|
|
18
|
-
},
|
|
19
|
-
pattern: {
|
|
20
|
-
type: "string",
|
|
21
|
-
description: "The pattern to search for. In filename mode this is a glob pattern " +
|
|
22
|
-
"(e.g. **/*.ts). In content mode this is a regular expression. " +
|
|
23
|
-
"In both mode this is treated as a regex for content, and fileGlob " +
|
|
24
|
-
"filters the filename set.",
|
|
25
|
-
},
|
|
26
|
-
path: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Directory to search in. Defaults to workdir/cwd if omitted.",
|
|
29
|
-
},
|
|
30
|
-
fileGlob: {
|
|
31
|
-
type: "string",
|
|
32
|
-
description: 'Glob pattern to filter files (e.g. "*.ts", "*.{js,tsx}"). ' +
|
|
33
|
-
"In content/both modes, only files matching this glob are searched.",
|
|
34
|
-
},
|
|
35
|
-
contextLines: {
|
|
36
|
-
type: "number",
|
|
37
|
-
description: "Number of context lines to show before and after each match " +
|
|
38
|
-
"(content/both modes only). Default: 0.",
|
|
39
|
-
},
|
|
40
|
-
caseInsensitive: {
|
|
41
|
-
type: "boolean",
|
|
42
|
-
description: "Case insensitive search (content/both modes). Default: false.",
|
|
43
|
-
},
|
|
44
|
-
headLimit: {
|
|
45
|
-
type: "number",
|
|
46
|
-
description: "Maximum number of result entries to return. Default 100 for filename, " +
|
|
47
|
-
"250 for content. Pass 0 for unlimited (use sparingly).",
|
|
48
|
-
},
|
|
49
|
-
offset: {
|
|
50
|
-
type: "number",
|
|
51
|
-
description: "Skip first N results before applying headLimit. Default: 0.",
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
|
-
required: ["mode", "pattern"],
|
|
55
|
-
};
|
|
56
|
-
// ── Constants ───────────────────────────────────────────────
|
|
57
|
-
const DEFAULT_FILENAME_LIMIT = 100;
|
|
58
|
-
const DEFAULT_CONTENT_LIMIT = 250;
|
|
59
|
-
const MAX_RESULT_CHARS = 100_000;
|
|
60
|
-
// ── Factory ─────────────────────────────────────────────────
|
|
61
|
-
export function createSearchTool(deps) {
|
|
62
|
-
return {
|
|
63
|
-
name: SEARCH_TOOL_NAME,
|
|
64
|
-
label: "Search",
|
|
65
|
-
description: "Search for files by name, search within file contents by regex, or both. " +
|
|
66
|
-
"In filename mode, pattern is a glob. In content mode, pattern is a regex. " +
|
|
67
|
-
"Results are paginated via headLimit + offset.",
|
|
68
|
-
parameters: SEARCH_TOOL_SCHEMA,
|
|
69
|
-
execute: async (_toolCallId, params) => {
|
|
70
|
-
const cwd = params.path
|
|
71
|
-
? (deps.resolvePath ? deps.resolvePath(params.path) : params.path)
|
|
72
|
-
: "";
|
|
73
|
-
const mode = params.mode;
|
|
74
|
-
if (mode === "filename") {
|
|
75
|
-
return executeFilenameSearch(deps, params, cwd);
|
|
76
|
-
}
|
|
77
|
-
else if (mode === "content") {
|
|
78
|
-
return executeContentSearch(deps, params, cwd);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
// "both" — run filename glob + content grep, merge results
|
|
82
|
-
return executeBothSearch(deps, params, cwd);
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
// ── Filename search ─────────────────────────────────────────
|
|
88
|
-
async function executeFilenameSearch(deps, params, cwd) {
|
|
89
|
-
const limit = params.headLimit ?? DEFAULT_FILENAME_LIMIT;
|
|
90
|
-
const { files, truncated } = await deps.glob(params.pattern, {
|
|
91
|
-
cwd,
|
|
92
|
-
limit: limit === 0 ? 10000 : limit,
|
|
93
|
-
});
|
|
94
|
-
const offset = params.offset ?? 0;
|
|
95
|
-
const sliced = offset > 0 ? files.slice(offset) : files;
|
|
96
|
-
const effectiveLimit = limit === 0 ? sliced.length : limit;
|
|
97
|
-
const finalFiles = sliced.slice(0, effectiveLimit);
|
|
98
|
-
const wasTruncated = truncated || sliced.length > effectiveLimit;
|
|
99
|
-
if (finalFiles.length === 0) {
|
|
100
|
-
return {
|
|
101
|
-
content: [{ type: "text", text: "No files found matching pattern." }],
|
|
102
|
-
details: { mode: "filename", totalMatches: 0, truncated: false },
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
let text = finalFiles.join("\n");
|
|
106
|
-
if (wasTruncated) {
|
|
107
|
-
text += `\n\n(Results truncated. ${finalFiles.length} shown. Use a more specific pattern or increase headLimit.)`;
|
|
108
|
-
}
|
|
109
|
-
text = truncateText(text, MAX_RESULT_CHARS);
|
|
110
|
-
return {
|
|
111
|
-
content: [{ type: "text", text }],
|
|
112
|
-
details: {
|
|
113
|
-
mode: "filename",
|
|
114
|
-
totalMatches: finalFiles.length,
|
|
115
|
-
truncated: wasTruncated,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
// ── Content search ──────────────────────────────────────────
|
|
120
|
-
async function executeContentSearch(deps, params, cwd) {
|
|
121
|
-
const headLimit = params.headLimit ?? DEFAULT_CONTENT_LIMIT;
|
|
122
|
-
const { matches, truncated } = await deps.grep(params.pattern, {
|
|
123
|
-
cwd,
|
|
124
|
-
fileGlob: params.fileGlob,
|
|
125
|
-
caseInsensitive: params.caseInsensitive,
|
|
126
|
-
contextLines: params.contextLines,
|
|
127
|
-
headLimit: headLimit === 0 ? undefined : headLimit,
|
|
128
|
-
offset: params.offset,
|
|
129
|
-
});
|
|
130
|
-
if (matches.length === 0) {
|
|
131
|
-
return {
|
|
132
|
-
content: [{ type: "text", text: "No matches found." }],
|
|
133
|
-
details: { mode: "content", totalMatches: 0, truncated: false },
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
const lines = [];
|
|
137
|
-
for (const m of matches) {
|
|
138
|
-
if (m.contextBefore && m.contextBefore.length > 0) {
|
|
139
|
-
for (const ctx of m.contextBefore) {
|
|
140
|
-
lines.push(` ${ctx}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
lines.push(`${m.path}:${m.line}: ${m.text}`);
|
|
144
|
-
if (m.contextAfter && m.contextAfter.length > 0) {
|
|
145
|
-
for (const ctx of m.contextAfter) {
|
|
146
|
-
lines.push(` ${ctx}`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
// Separator between match groups when context is present
|
|
150
|
-
if (params.contextLines && params.contextLines > 0) {
|
|
151
|
-
lines.push("--");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
let text = lines.join("\n");
|
|
155
|
-
if (truncated) {
|
|
156
|
-
text += `\n\n(Results truncated at ${matches.length} matches. Use offset/headLimit for pagination.)`;
|
|
157
|
-
}
|
|
158
|
-
text = truncateText(text, MAX_RESULT_CHARS);
|
|
159
|
-
return {
|
|
160
|
-
content: [{ type: "text", text }],
|
|
161
|
-
details: {
|
|
162
|
-
mode: "content",
|
|
163
|
-
totalMatches: matches.length,
|
|
164
|
-
truncated,
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
// ── Both mode ───────────────────────────────────────────────
|
|
169
|
-
async function executeBothSearch(deps, params, cwd) {
|
|
170
|
-
// Run both in parallel
|
|
171
|
-
const [globResult, grepResult] = await Promise.all([
|
|
172
|
-
params.fileGlob
|
|
173
|
-
? deps.glob(params.fileGlob, { cwd, limit: DEFAULT_FILENAME_LIMIT })
|
|
174
|
-
: Promise.resolve({ files: [], truncated: false }),
|
|
175
|
-
deps.grep(params.pattern, {
|
|
176
|
-
cwd,
|
|
177
|
-
fileGlob: params.fileGlob,
|
|
178
|
-
caseInsensitive: params.caseInsensitive,
|
|
179
|
-
contextLines: params.contextLines,
|
|
180
|
-
headLimit: params.headLimit ?? DEFAULT_CONTENT_LIMIT,
|
|
181
|
-
offset: params.offset,
|
|
182
|
-
}),
|
|
183
|
-
]);
|
|
184
|
-
// Deduplicate: files that appear in both glob and grep results
|
|
185
|
-
const contentFiles = new Set(grepResult.matches.map((m) => m.path));
|
|
186
|
-
const uniqueGlobFiles = globResult.files.filter((f) => !contentFiles.has(f));
|
|
187
|
-
const sections = [];
|
|
188
|
-
if (uniqueGlobFiles.length > 0) {
|
|
189
|
-
sections.push(`## Files matching glob (${uniqueGlobFiles.length}):\n${uniqueGlobFiles.join("\n")}`);
|
|
190
|
-
}
|
|
191
|
-
if (grepResult.matches.length > 0) {
|
|
192
|
-
const lines = [];
|
|
193
|
-
for (const m of grepResult.matches) {
|
|
194
|
-
lines.push(`${m.path}:${m.line}: ${m.text}`);
|
|
195
|
-
}
|
|
196
|
-
sections.push(`## Content matches (${grepResult.matches.length}):\n${lines.join("\n")}`);
|
|
197
|
-
}
|
|
198
|
-
if (sections.length === 0) {
|
|
199
|
-
return {
|
|
200
|
-
content: [{ type: "text", text: "No matches found in either filename or content." }],
|
|
201
|
-
details: { mode: "both", totalMatches: 0, truncated: false },
|
|
202
|
-
};
|
|
203
|
-
}
|
|
204
|
-
const truncated = globResult.truncated || grepResult.truncated;
|
|
205
|
-
let text = sections.join("\n\n");
|
|
206
|
-
if (truncated) {
|
|
207
|
-
text += "\n\n(Some results truncated. Use more specific patterns.)";
|
|
208
|
-
}
|
|
209
|
-
text = truncateText(text, MAX_RESULT_CHARS);
|
|
210
|
-
return {
|
|
211
|
-
content: [{ type: "text", text }],
|
|
212
|
-
details: {
|
|
213
|
-
mode: "both",
|
|
214
|
-
totalMatches: uniqueGlobFiles.length + grepResult.matches.length,
|
|
215
|
-
truncated,
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
// ── Util ────────────────────────────────────────────────────
|
|
220
|
-
function truncateText(text, limit) {
|
|
221
|
-
if (text.length <= limit)
|
|
222
|
-
return text;
|
|
223
|
-
const half = Math.floor(limit / 2) - 50;
|
|
224
|
-
return `${text.slice(0, half)}\n\n... [truncated ${text.length - limit} chars] ...\n\n${text.slice(-half)}`;
|
|
225
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { PortableTool } from "../portable-tool.js";
|
|
2
|
-
export declare const SEND_MESSAGE_TOOL_NAME: "send_message";
|
|
3
|
-
export interface SendMessageToolParams {
|
|
4
|
-
/** Target agent name or '*' for broadcast */
|
|
5
|
-
to: string;
|
|
6
|
-
/** Message content */
|
|
7
|
-
message: string;
|
|
8
|
-
/** Optional short summary for routing/display */
|
|
9
|
-
summary?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare const SEND_MESSAGE_TOOL_SCHEMA: {
|
|
12
|
-
readonly type: "object";
|
|
13
|
-
readonly properties: {
|
|
14
|
-
readonly to: {
|
|
15
|
-
readonly type: "string";
|
|
16
|
-
readonly description: string;
|
|
17
|
-
};
|
|
18
|
-
readonly message: {
|
|
19
|
-
readonly type: "string";
|
|
20
|
-
readonly description: "Message content to send to the target agent.";
|
|
21
|
-
};
|
|
22
|
-
readonly summary: {
|
|
23
|
-
readonly type: "string";
|
|
24
|
-
readonly description: "Optional short summary (for logging/routing).";
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
readonly required: readonly ["to", "message"];
|
|
28
|
-
};
|
|
29
|
-
export interface SendMessageResult {
|
|
30
|
-
success: boolean;
|
|
31
|
-
recipients?: string[];
|
|
32
|
-
error?: string;
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Host-provided message routing backend.
|
|
36
|
-
* Messages are delivered asynchronously via mailbox pattern.
|
|
37
|
-
*/
|
|
38
|
-
export interface SendMessageToolDeps {
|
|
39
|
-
/** Send message to target agent(s). Returns delivery status. */
|
|
40
|
-
sendMessage(params: {
|
|
41
|
-
to: string;
|
|
42
|
-
message: string;
|
|
43
|
-
summary?: string;
|
|
44
|
-
senderId: string;
|
|
45
|
-
}): Promise<SendMessageResult>;
|
|
46
|
-
/** Get the current agent's ID */
|
|
47
|
-
getSenderId(): string;
|
|
48
|
-
/** List available teammates */
|
|
49
|
-
listTeammates?(): string[];
|
|
50
|
-
}
|
|
51
|
-
export declare function createSendMessageTool(deps: SendMessageToolDeps): PortableTool<SendMessageToolParams>;
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Send Message Tool — agent-to-agent IPC within a team/swarm.
|
|
3
|
-
// Reference: claude-code-haha/src/tools/SendMessageTool/SendMessageTool.ts
|
|
4
|
-
// hermes-agent-main/tools/send_message_tool.py
|
|
5
|
-
// Category: system
|
|
6
|
-
// ============================================================
|
|
7
|
-
export const SEND_MESSAGE_TOOL_NAME = "send_message";
|
|
8
|
-
export const SEND_MESSAGE_TOOL_SCHEMA = {
|
|
9
|
-
type: "object",
|
|
10
|
-
properties: {
|
|
11
|
-
to: {
|
|
12
|
-
type: "string",
|
|
13
|
-
description: "Target agent name or '*' for broadcast to all team members. " +
|
|
14
|
-
"Must be a valid agent name within the current team.",
|
|
15
|
-
},
|
|
16
|
-
message: {
|
|
17
|
-
type: "string",
|
|
18
|
-
description: "Message content to send to the target agent.",
|
|
19
|
-
},
|
|
20
|
-
summary: {
|
|
21
|
-
type: "string",
|
|
22
|
-
description: "Optional short summary (for logging/routing).",
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
required: ["to", "message"],
|
|
26
|
-
};
|
|
27
|
-
export function createSendMessageTool(deps) {
|
|
28
|
-
return {
|
|
29
|
-
name: SEND_MESSAGE_TOOL_NAME,
|
|
30
|
-
label: "Send Message",
|
|
31
|
-
description: "Send a message to another agent in your team. Use '*' to broadcast to all teammates. " +
|
|
32
|
-
"Messages are delivered asynchronously. Use for coordination, delegation, and status updates.",
|
|
33
|
-
parameters: SEND_MESSAGE_TOOL_SCHEMA,
|
|
34
|
-
execute: async (_toolCallId, params) => {
|
|
35
|
-
if (!params.to || params.to.trim().length === 0) {
|
|
36
|
-
return {
|
|
37
|
-
content: [{ type: "text", text: "Error: 'to' is required (agent name or '*')." }],
|
|
38
|
-
details: { type: "send_message", error: "missing_target" },
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
if (!params.message || params.message.trim().length === 0) {
|
|
42
|
-
return {
|
|
43
|
-
content: [{ type: "text", text: "Error: message is required." }],
|
|
44
|
-
details: { type: "send_message", error: "empty_message" },
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
// Validate target exists (unless broadcast)
|
|
48
|
-
if (params.to !== "*" && deps.listTeammates) {
|
|
49
|
-
const teammates = deps.listTeammates();
|
|
50
|
-
if (!teammates.includes(params.to)) {
|
|
51
|
-
return {
|
|
52
|
-
content: [{ type: "text", text: `Error: agent "${params.to}" not found in team. Available: ${teammates.join(", ")}` }],
|
|
53
|
-
details: { type: "send_message", error: "target_not_found", available: teammates },
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
const result = await deps.sendMessage({
|
|
58
|
-
to: params.to.trim(),
|
|
59
|
-
message: params.message.trim(),
|
|
60
|
-
summary: params.summary,
|
|
61
|
-
senderId: deps.getSenderId(),
|
|
62
|
-
});
|
|
63
|
-
if (!result.success) {
|
|
64
|
-
return {
|
|
65
|
-
content: [{ type: "text", text: `Message delivery failed: ${result.error || "unknown error"}` }],
|
|
66
|
-
details: { type: "send_message", success: false, error: result.error },
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
const target = params.to === "*" ? `broadcast (${result.recipients?.length || 0} recipients)` : params.to;
|
|
70
|
-
return {
|
|
71
|
-
content: [{ type: "text", text: `Message sent to ${target}.` }],
|
|
72
|
-
details: { type: "send_message", success: true, to: params.to, recipients: result.recipients },
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { PortableTool } from "../portable-tool.js";
|
|
2
|
-
export declare const SKILL_LIST_TOOL_NAME: "skill_list";
|
|
3
|
-
export interface SkillListToolParams {
|
|
4
|
-
category?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare const SKILL_LIST_TOOL_SCHEMA: {
|
|
7
|
-
readonly type: "object";
|
|
8
|
-
readonly properties: {
|
|
9
|
-
readonly category: {
|
|
10
|
-
readonly type: "string";
|
|
11
|
-
readonly description: "Filter skills by category (e.g. 'devops', 'mlops'). Omit to list all.";
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
readonly required: readonly [];
|
|
15
|
-
};
|
|
16
|
-
export interface SkillListItem {
|
|
17
|
-
name: string;
|
|
18
|
-
description: string;
|
|
19
|
-
version?: string;
|
|
20
|
-
category?: string;
|
|
21
|
-
}
|
|
22
|
-
export interface SkillListOutput {
|
|
23
|
-
skills: SkillListItem[];
|
|
24
|
-
categories: string[];
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Host-provided skill registry for listing.
|
|
28
|
-
*/
|
|
29
|
-
export interface SkillListToolDeps {
|
|
30
|
-
/** List all available skills, optionally filtered by category. */
|
|
31
|
-
listSkills(category?: string): Promise<SkillListOutput>;
|
|
32
|
-
}
|
|
33
|
-
export declare function createSkillListTool(deps: SkillListToolDeps): PortableTool<SkillListToolParams>;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Skill List Tool — discover available skills.
|
|
3
|
-
// Reference: hermes-agent-2026.4.30/tools/skills_tool.py (skills_list)
|
|
4
|
-
// Category: skill
|
|
5
|
-
// ============================================================
|
|
6
|
-
export const SKILL_LIST_TOOL_NAME = "skill_list";
|
|
7
|
-
export const SKILL_LIST_TOOL_SCHEMA = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
category: {
|
|
11
|
-
type: "string",
|
|
12
|
-
description: "Filter skills by category (e.g. 'devops', 'mlops'). Omit to list all.",
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
required: [],
|
|
16
|
-
};
|
|
17
|
-
export function createSkillListTool(deps) {
|
|
18
|
-
return {
|
|
19
|
-
name: SKILL_LIST_TOOL_NAME,
|
|
20
|
-
label: "List Skills",
|
|
21
|
-
description: "List all available skills (reusable workflows/knowledge packages). " +
|
|
22
|
-
"Returns skill names, descriptions, and categories. " +
|
|
23
|
-
"Use skill_view to see full skill content.",
|
|
24
|
-
parameters: SKILL_LIST_TOOL_SCHEMA,
|
|
25
|
-
execute: async (_toolCallId, params) => {
|
|
26
|
-
const output = await deps.listSkills(params.category);
|
|
27
|
-
if (output.skills.length === 0) {
|
|
28
|
-
const msg = params.category
|
|
29
|
-
? `No skills found in category "${params.category}".`
|
|
30
|
-
: "No skills available.";
|
|
31
|
-
return {
|
|
32
|
-
content: [{ type: "text", text: msg }],
|
|
33
|
-
details: { type: "skill_list", count: 0 },
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
const lines = [`Available skills (${output.skills.length}):`];
|
|
37
|
-
if (output.categories.length > 0) {
|
|
38
|
-
lines.push(`Categories: ${output.categories.join(", ")}`);
|
|
39
|
-
}
|
|
40
|
-
lines.push("");
|
|
41
|
-
for (const s of output.skills) {
|
|
42
|
-
const cat = s.category ? ` [${s.category}]` : "";
|
|
43
|
-
const ver = s.version ? ` (v${s.version})` : "";
|
|
44
|
-
lines.push(`- **${s.name}**${ver}${cat}: ${s.description}`);
|
|
45
|
-
}
|
|
46
|
-
lines.push("");
|
|
47
|
-
lines.push("Use skill_view(name) to see full skill content.");
|
|
48
|
-
return {
|
|
49
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
50
|
-
details: { type: "skill_list", count: output.skills.length, categories: output.categories },
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import type { PortableTool } from "../portable-tool.js";
|
|
2
|
-
export declare const SKILL_MANAGE_TOOL_NAME: "skill_manage";
|
|
3
|
-
export type SkillManageAction = "create" | "edit" | "patch" | "delete" | "write_file" | "remove_file";
|
|
4
|
-
export interface SkillManageToolParams {
|
|
5
|
-
action: SkillManageAction;
|
|
6
|
-
name: string;
|
|
7
|
-
content?: string;
|
|
8
|
-
category?: string;
|
|
9
|
-
filePath?: string;
|
|
10
|
-
fileContent?: string;
|
|
11
|
-
oldString?: string;
|
|
12
|
-
newString?: string;
|
|
13
|
-
}
|
|
14
|
-
export declare const SKILL_MANAGE_TOOL_SCHEMA: {
|
|
15
|
-
readonly type: "object";
|
|
16
|
-
readonly properties: {
|
|
17
|
-
readonly action: {
|
|
18
|
-
readonly type: "string";
|
|
19
|
-
readonly enum: readonly ["create", "edit", "patch", "delete", "write_file", "remove_file"];
|
|
20
|
-
readonly description: string;
|
|
21
|
-
};
|
|
22
|
-
readonly name: {
|
|
23
|
-
readonly type: "string";
|
|
24
|
-
readonly description: "Skill name (lowercase, max 64 chars, kebab-case: letters, digits, hyphens).";
|
|
25
|
-
};
|
|
26
|
-
readonly content: {
|
|
27
|
-
readonly type: "string";
|
|
28
|
-
readonly description: string;
|
|
29
|
-
};
|
|
30
|
-
readonly category: {
|
|
31
|
-
readonly type: "string";
|
|
32
|
-
readonly description: "Category/domain (e.g. 'devops', 'mlops'). Used by create to organize skills.";
|
|
33
|
-
};
|
|
34
|
-
readonly filePath: {
|
|
35
|
-
readonly type: "string";
|
|
36
|
-
readonly description: string;
|
|
37
|
-
};
|
|
38
|
-
readonly fileContent: {
|
|
39
|
-
readonly type: "string";
|
|
40
|
-
readonly description: "Content for write_file action. Max 1 MiB.";
|
|
41
|
-
};
|
|
42
|
-
readonly oldString: {
|
|
43
|
-
readonly type: "string";
|
|
44
|
-
readonly description: "Text to find for patch action (must match uniquely in SKILL.md).";
|
|
45
|
-
};
|
|
46
|
-
readonly newString: {
|
|
47
|
-
readonly type: "string";
|
|
48
|
-
readonly description: "Replacement text for patch action (can be empty to delete).";
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
readonly required: readonly ["action", "name"];
|
|
52
|
-
};
|
|
53
|
-
export interface SkillManageResult {
|
|
54
|
-
success: boolean;
|
|
55
|
-
message: string;
|
|
56
|
-
path?: string;
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Host-provided skill management backend.
|
|
60
|
-
*/
|
|
61
|
-
export interface SkillManageToolDeps {
|
|
62
|
-
/**
|
|
63
|
-
* Execute a skill management action.
|
|
64
|
-
* The host handles file system operations, validation, and security scanning.
|
|
65
|
-
*/
|
|
66
|
-
manageSkill(params: SkillManageToolParams): Promise<SkillManageResult>;
|
|
67
|
-
/**
|
|
68
|
-
* Validate skill name format.
|
|
69
|
-
* If not provided, tool uses built-in validation.
|
|
70
|
-
*/
|
|
71
|
-
validateName?(name: string): string | null;
|
|
72
|
-
}
|
|
73
|
-
export declare function createSkillManageTool(deps: SkillManageToolDeps): PortableTool<SkillManageToolParams>;
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Skill Manage Tool — create/edit/delete skills.
|
|
3
|
-
// Reference: hermes-agent-2026.4.30/tools/skill_manager_tool.py
|
|
4
|
-
// Category: skill
|
|
5
|
-
// ============================================================
|
|
6
|
-
export const SKILL_MANAGE_TOOL_NAME = "skill_manage";
|
|
7
|
-
export const SKILL_MANAGE_TOOL_SCHEMA = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
action: {
|
|
11
|
-
type: "string",
|
|
12
|
-
enum: ["create", "edit", "patch", "delete", "write_file", "remove_file"],
|
|
13
|
-
description: "Action to perform: create (new skill), edit (overwrite SKILL.md), " +
|
|
14
|
-
"patch (find/replace in SKILL.md), delete (remove skill), " +
|
|
15
|
-
"write_file (add/overwrite supporting file), remove_file (delete supporting file).",
|
|
16
|
-
},
|
|
17
|
-
name: {
|
|
18
|
-
type: "string",
|
|
19
|
-
description: "Skill name (lowercase, max 64 chars, kebab-case: letters, digits, hyphens).",
|
|
20
|
-
},
|
|
21
|
-
content: {
|
|
22
|
-
type: "string",
|
|
23
|
-
description: "Full SKILL.md content (YAML frontmatter + body). Required for create/edit. " +
|
|
24
|
-
"Max 100,000 chars. Must include ---\\nname: ...\\ndescription: ...\\n--- header.",
|
|
25
|
-
},
|
|
26
|
-
category: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Category/domain (e.g. 'devops', 'mlops'). Used by create to organize skills.",
|
|
29
|
-
},
|
|
30
|
-
filePath: {
|
|
31
|
-
type: "string",
|
|
32
|
-
description: "Path within the skill for write_file/remove_file. " +
|
|
33
|
-
"Must be in references/, templates/, scripts/, or assets/ subdirectory.",
|
|
34
|
-
},
|
|
35
|
-
fileContent: {
|
|
36
|
-
type: "string",
|
|
37
|
-
description: "Content for write_file action. Max 1 MiB.",
|
|
38
|
-
},
|
|
39
|
-
oldString: {
|
|
40
|
-
type: "string",
|
|
41
|
-
description: "Text to find for patch action (must match uniquely in SKILL.md).",
|
|
42
|
-
},
|
|
43
|
-
newString: {
|
|
44
|
-
type: "string",
|
|
45
|
-
description: "Replacement text for patch action (can be empty to delete).",
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
required: ["action", "name"],
|
|
49
|
-
};
|
|
50
|
-
const NAME_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
51
|
-
const MAX_CONTENT_LENGTH = 100_000;
|
|
52
|
-
const MAX_FILE_CONTENT_LENGTH = 1_048_576; // 1 MiB
|
|
53
|
-
const ALLOWED_FILE_DIRS = ["references/", "templates/", "scripts/", "assets/"];
|
|
54
|
-
export function createSkillManageTool(deps) {
|
|
55
|
-
return {
|
|
56
|
-
name: SKILL_MANAGE_TOOL_NAME,
|
|
57
|
-
label: "Manage Skills",
|
|
58
|
-
description: "Create, edit, patch, or delete skills. Skills are reusable workflows/knowledge packages " +
|
|
59
|
-
"that can be discovered and invoked. Supports managing supporting files (references, templates).",
|
|
60
|
-
parameters: SKILL_MANAGE_TOOL_SCHEMA,
|
|
61
|
-
execute: async (_toolCallId, params) => {
|
|
62
|
-
// Validate name
|
|
63
|
-
const nameError = deps.validateName
|
|
64
|
-
? deps.validateName(params.name)
|
|
65
|
-
: validateNameBuiltin(params.name);
|
|
66
|
-
if (nameError) {
|
|
67
|
-
return {
|
|
68
|
-
content: [{ type: "text", text: `Error: ${nameError}` }],
|
|
69
|
-
details: { type: "skill_manage", error: "invalid_name" },
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// Action-specific validation
|
|
73
|
-
const validationError = validateAction(params);
|
|
74
|
-
if (validationError) {
|
|
75
|
-
return {
|
|
76
|
-
content: [{ type: "text", text: `Error: ${validationError}` }],
|
|
77
|
-
details: { type: "skill_manage", error: "validation_failed" },
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
const result = await deps.manageSkill(params);
|
|
81
|
-
return {
|
|
82
|
-
content: [{ type: "text", text: result.message }],
|
|
83
|
-
details: {
|
|
84
|
-
type: "skill_manage",
|
|
85
|
-
action: params.action,
|
|
86
|
-
name: params.name,
|
|
87
|
-
success: result.success,
|
|
88
|
-
path: result.path,
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
function validateNameBuiltin(name) {
|
|
95
|
-
if (!name)
|
|
96
|
-
return "name is required.";
|
|
97
|
-
if (!NAME_PATTERN.test(name)) {
|
|
98
|
-
return "name must be lowercase, start with letter/digit, contain only letters, digits, hyphens, dots, underscores (max 64 chars).";
|
|
99
|
-
}
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
function validateAction(params) {
|
|
103
|
-
switch (params.action) {
|
|
104
|
-
case "create":
|
|
105
|
-
case "edit":
|
|
106
|
-
if (!params.content)
|
|
107
|
-
return `content is required for ${params.action}.`;
|
|
108
|
-
if (params.content.length > MAX_CONTENT_LENGTH) {
|
|
109
|
-
return `content exceeds max length (${MAX_CONTENT_LENGTH} chars).`;
|
|
110
|
-
}
|
|
111
|
-
if (!params.content.includes("---")) {
|
|
112
|
-
return "content must include YAML frontmatter (--- delimiters).";
|
|
113
|
-
}
|
|
114
|
-
break;
|
|
115
|
-
case "patch":
|
|
116
|
-
if (!params.oldString)
|
|
117
|
-
return "oldString is required for patch.";
|
|
118
|
-
if (params.newString === undefined)
|
|
119
|
-
return "newString is required for patch (can be empty to delete).";
|
|
120
|
-
break;
|
|
121
|
-
case "write_file":
|
|
122
|
-
if (!params.filePath)
|
|
123
|
-
return "filePath is required for write_file.";
|
|
124
|
-
if (!params.fileContent)
|
|
125
|
-
return "fileContent is required for write_file.";
|
|
126
|
-
if (params.fileContent.length > MAX_FILE_CONTENT_LENGTH) {
|
|
127
|
-
return "fileContent exceeds max length (1 MiB).";
|
|
128
|
-
}
|
|
129
|
-
if (!ALLOWED_FILE_DIRS.some((d) => params.filePath.startsWith(d))) {
|
|
130
|
-
return `filePath must be in one of: ${ALLOWED_FILE_DIRS.join(", ")}`;
|
|
131
|
-
}
|
|
132
|
-
if (params.filePath.includes("..")) {
|
|
133
|
-
return "filePath must not contain path traversal (..).";
|
|
134
|
-
}
|
|
135
|
-
break;
|
|
136
|
-
case "remove_file":
|
|
137
|
-
if (!params.filePath)
|
|
138
|
-
return "filePath is required for remove_file.";
|
|
139
|
-
if (!ALLOWED_FILE_DIRS.some((d) => params.filePath.startsWith(d))) {
|
|
140
|
-
return `filePath must be in one of: ${ALLOWED_FILE_DIRS.join(", ")}`;
|
|
141
|
-
}
|
|
142
|
-
if (params.filePath.includes("..")) {
|
|
143
|
-
return "filePath must not contain path traversal (..).";
|
|
144
|
-
}
|
|
145
|
-
break;
|
|
146
|
-
case "delete":
|
|
147
|
-
// No extra validation needed
|
|
148
|
-
break;
|
|
149
|
-
default:
|
|
150
|
-
return `unknown action: ${params.action}`;
|
|
151
|
-
}
|
|
152
|
-
return null;
|
|
153
|
-
}
|