qlogicagent 0.2.1 → 0.3.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/dist/agent.js +1 -0
- package/dist/cli.js +9 -0
- package/dist/contracts.js +1 -0
- package/dist/index.js +5 -15
- package/dist/orchestration.js +118 -0
- package/package.json +56 -42
- package/dist/agent/agent.js +0 -113
- package/dist/agent/tool-loop.js +0 -575
- package/dist/agent/types.js +0 -14
- package/dist/cli/main.js +0 -23
- package/dist/cli/stdio-server.js +0 -463
- package/dist/config/config.js +0 -21
- package/dist/contracts/hooks.js +0 -7
- package/dist/contracts/index.js +0 -10
- package/dist/contracts/planner.js +0 -2
- package/dist/contracts/skill-candidate.js +0 -195
- package/dist/contracts/todo.js +0 -9
- package/dist/llm/builtin-providers.js +0 -531
- package/dist/llm/index.js +0 -14
- package/dist/llm/llm-client.js +0 -67
- package/dist/llm/model-catalog.js +0 -191
- package/dist/llm/provider-def.js +0 -12
- package/dist/llm/provider-registry.js +0 -147
- package/dist/llm/transport.js +0 -27
- package/dist/llm/transports/anthropic-messages.js +0 -293
- package/dist/llm/transports/openai-chat.js +0 -165
- package/dist/orchestration/agent-registry.js +0 -116
- package/dist/orchestration/approval-aware-tool-plan.js +0 -87
- package/dist/orchestration/context-compression.js +0 -583
- package/dist/orchestration/conversation-repair.js +0 -429
- package/dist/orchestration/curator-scheduler.js +0 -135
- package/dist/orchestration/embedded-failover-policy.js +0 -168
- package/dist/orchestration/error-classification.js +0 -77
- package/dist/orchestration/failover-classification.js +0 -381
- package/dist/orchestration/failover-error.js +0 -198
- package/dist/orchestration/fork-subagent.js +0 -98
- package/dist/orchestration/index.js +0 -267
- package/dist/orchestration/memory-flush-policy.js +0 -85
- package/dist/orchestration/memory-provider.js +0 -2
- package/dist/orchestration/parallel-tool-calls.js +0 -59
- package/dist/orchestration/prompt-cache-strategy.js +0 -228
- package/dist/orchestration/reactive-compact.js +0 -78
- package/dist/orchestration/retry-loop.js +0 -24
- package/dist/orchestration/skill-candidate.js +0 -141
- package/dist/orchestration/skill-consolidation.js +0 -220
- package/dist/orchestration/skill-improvement.js +0 -66
- package/dist/orchestration/skill-similarity.js +0 -131
- package/dist/orchestration/streaming-tool-executor.js +0 -96
- package/dist/orchestration/team-orchestration.js +0 -369
- package/dist/orchestration/team-tool-loop-wiring.js +0 -147
- package/dist/orchestration/tool-choice-policy.js +0 -164
- package/dist/orchestration/tool-loop-state.js +0 -133
- package/dist/orchestration/tool-schema.js +0 -297
- package/dist/orchestration/transcript-repair.js +0 -426
- package/dist/orchestration/turn-loop-guard.js +0 -92
- package/dist/orchestration/web-browser-policy.js +0 -39
- package/dist/runtime/context-compression.js +0 -274
- package/dist/runtime/hook-registry.js +0 -53
- package/dist/runtime/memory-hooks.js +0 -65
- package/dist/runtime/tool-eligibility.js +0 -111
- package/dist/skills/index.js +0 -82
- package/dist/skills/memory-extractor.js +0 -173
- package/dist/skills/memory-query-tool.js +0 -127
- package/dist/skills/memory-store.js +0 -228
- package/dist/skills/memory-tool.js +0 -192
- package/dist/skills/portable-tool.js +0 -14
- package/dist/skills/qmemory-adapter.js +0 -165
- package/dist/skills/skill-frontmatter.js +0 -344
- package/dist/skills/skill-guard.js +0 -229
- package/dist/skills/skill-loader.js +0 -303
- package/dist/skills/skill-source.js +0 -126
- package/dist/skills/skill-types.js +0 -6
- package/dist/skills/think-tool.js +0 -59
- package/dist/skills/todo-tool.js +0 -114
- package/dist/skills/tools/agent-tool.js +0 -142
- package/dist/skills/tools/apply-patch-tool.js +0 -184
- package/dist/skills/tools/ask-user-tool.js +0 -121
- package/dist/skills/tools/brief-tool.js +0 -95
- package/dist/skills/tools/browser-tool.js +0 -155
- package/dist/skills/tools/checkpoint-tool.js +0 -102
- package/dist/skills/tools/config-tool.js +0 -143
- package/dist/skills/tools/cron-tool.js +0 -175
- package/dist/skills/tools/edit-tool.js +0 -70
- package/dist/skills/tools/exec-tool.js +0 -133
- package/dist/skills/tools/image-generate-tool.js +0 -67
- package/dist/skills/tools/instructions-tool.js +0 -187
- package/dist/skills/tools/lsp-tool.js +0 -227
- package/dist/skills/tools/mcp-client-types.js +0 -53
- package/dist/skills/tools/mcp-tool.js +0 -503
- package/dist/skills/tools/memory-tool.js +0 -88
- package/dist/skills/tools/monitor-tool.js +0 -131
- package/dist/skills/tools/music-generate-tool.js +0 -62
- package/dist/skills/tools/notify-tool.js +0 -62
- package/dist/skills/tools/patch-tool.js +0 -505
- package/dist/skills/tools/pdf-tool.js +0 -88
- package/dist/skills/tools/plan-mode-tool.js +0 -122
- package/dist/skills/tools/read-tool.js +0 -84
- package/dist/skills/tools/repl-tool.js +0 -69
- package/dist/skills/tools/search-tool.js +0 -225
- package/dist/skills/tools/send-message-tool.js +0 -76
- package/dist/skills/tools/skill-list-tool.js +0 -54
- package/dist/skills/tools/skill-manage-tool.js +0 -153
- package/dist/skills/tools/skill-view-tool.js +0 -72
- package/dist/skills/tools/sleep-tool.js +0 -81
- package/dist/skills/tools/structured-output-tool.js +0 -176
- package/dist/skills/tools/task-tool.js +0 -161
- package/dist/skills/tools/team-tool.js +0 -105
- package/dist/skills/tools/tool-search-tool.js +0 -110
- package/dist/skills/tools/tts-tool.js +0 -45
- package/dist/skills/tools/video-edit-tool.js +0 -74
- package/dist/skills/tools/video-generate-tool.js +0 -66
- package/dist/skills/tools/video-merge-tool.js +0 -92
- package/dist/skills/tools/video-upscale-tool.js +0 -52
- package/dist/skills/tools/web-fetch-tool.js +0 -92
- package/dist/skills/tools/web-search-tool.js +0 -86
- package/dist/skills/tools/worktree-tool.js +0 -147
- package/dist/skills/tools/write-tool.js +0 -81
- /package/dist/{agent → types/agent}/agent.d.ts +0 -0
- /package/dist/{agent → types/agent}/tool-loop.d.ts +0 -0
- /package/dist/{agent → types/agent}/types.d.ts +0 -0
- /package/dist/{cli → types/cli}/main.d.ts +0 -0
- /package/dist/{cli → types/cli}/stdio-server.d.ts +0 -0
- /package/dist/{config → types/config}/config.d.ts +0 -0
- /package/dist/{contracts → types/contracts}/hooks.d.ts +0 -0
- /package/dist/{contracts → types/contracts}/index.d.ts +0 -0
- /package/dist/{contracts → types/contracts}/planner.d.ts +0 -0
- /package/dist/{contracts → types/contracts}/skill-candidate.d.ts +0 -0
- /package/dist/{contracts → types/contracts}/todo.d.ts +0 -0
- /package/dist/{index.d.ts → types/index.d.ts} +0 -0
- /package/dist/{llm → types/llm}/builtin-providers.d.ts +0 -0
- /package/dist/{llm → types/llm}/index.d.ts +0 -0
- /package/dist/{llm → types/llm}/llm-client.d.ts +0 -0
- /package/dist/{llm → types/llm}/model-catalog.d.ts +0 -0
- /package/dist/{llm → types/llm}/provider-def.d.ts +0 -0
- /package/dist/{llm → types/llm}/provider-registry.d.ts +0 -0
- /package/dist/{llm → types/llm}/transport.d.ts +0 -0
- /package/dist/{llm → types/llm}/transports/anthropic-messages.d.ts +0 -0
- /package/dist/{llm → types/llm}/transports/openai-chat.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/agent-registry.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/approval-aware-tool-plan.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/context-compression.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/conversation-repair.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/curator-scheduler.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/embedded-failover-policy.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/error-classification.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/failover-classification.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/failover-error.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/fork-subagent.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/index.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/memory-flush-policy.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/memory-provider.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/parallel-tool-calls.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/prompt-cache-strategy.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/reactive-compact.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/retry-loop.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/skill-candidate.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/skill-consolidation.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/skill-improvement.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/skill-similarity.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/streaming-tool-executor.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/team-orchestration.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/team-tool-loop-wiring.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/tool-choice-policy.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/tool-loop-state.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/tool-schema.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/transcript-repair.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/turn-loop-guard.d.ts +0 -0
- /package/dist/{orchestration → types/orchestration}/web-browser-policy.d.ts +0 -0
- /package/dist/{runtime → types/runtime}/context-compression.d.ts +0 -0
- /package/dist/{runtime → types/runtime}/hook-registry.d.ts +0 -0
- /package/dist/{runtime → types/runtime}/memory-hooks.d.ts +0 -0
- /package/dist/{runtime → types/runtime}/tool-eligibility.d.ts +0 -0
- /package/dist/{skills → types/skills}/index.d.ts +0 -0
- /package/dist/{skills → types/skills}/memory-extractor.d.ts +0 -0
- /package/dist/{skills → types/skills}/memory-query-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/memory-store.d.ts +0 -0
- /package/dist/{skills → types/skills}/memory-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/portable-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/qmemory-adapter.d.ts +0 -0
- /package/dist/{skills → types/skills}/skill-frontmatter.d.ts +0 -0
- /package/dist/{skills → types/skills}/skill-guard.d.ts +0 -0
- /package/dist/{skills → types/skills}/skill-loader.d.ts +0 -0
- /package/dist/{skills → types/skills}/skill-source.d.ts +0 -0
- /package/dist/{skills → types/skills}/skill-types.d.ts +0 -0
- /package/dist/{skills → types/skills}/think-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/todo-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/agent-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/apply-patch-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/ask-user-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/brief-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/browser-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/checkpoint-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/config-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/cron-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/edit-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/exec-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/image-generate-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/instructions-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/lsp-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/mcp-client-types.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/mcp-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/memory-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/monitor-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/music-generate-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/notify-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/patch-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/pdf-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/plan-mode-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/read-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/repl-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/search-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/send-message-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/skill-list-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/skill-manage-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/skill-view-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/sleep-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/structured-output-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/task-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/team-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/tool-search-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/tts-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/video-edit-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/video-generate-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/video-merge-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/video-upscale-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/web-fetch-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/web-search-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/worktree-tool.d.ts +0 -0
- /package/dist/{skills → types/skills}/tools/write-tool.d.ts +0 -0
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Browser Tool — CDP-based browser automation.
|
|
3
|
-
// Reference: hermes-agent-main/tools/browser_tool.py
|
|
4
|
-
// hermes-agent-main/tools/browser_cdp_tool.py
|
|
5
|
-
// Category: web
|
|
6
|
-
// ============================================================
|
|
7
|
-
export const BROWSER_TOOL_NAME = "browser";
|
|
8
|
-
export const BROWSER_TOOL_SCHEMA = {
|
|
9
|
-
type: "object",
|
|
10
|
-
properties: {
|
|
11
|
-
action: {
|
|
12
|
-
type: "string",
|
|
13
|
-
enum: ["navigate", "click", "type", "scroll", "snapshot", "screenshot", "console", "cdp"],
|
|
14
|
-
description: "Browser action: navigate (go to URL), click (element by ref), type (text into element), " +
|
|
15
|
-
"scroll (direction), snapshot (accessibility tree), screenshot (visual capture), " +
|
|
16
|
-
"console (eval JS / read logs), cdp (raw CDP command).",
|
|
17
|
-
},
|
|
18
|
-
url: {
|
|
19
|
-
type: "string",
|
|
20
|
-
description: "URL to navigate to. Required for 'navigate' action.",
|
|
21
|
-
},
|
|
22
|
-
ref: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: 'Element reference like "@e5" from a previous snapshot. Required for click/type.',
|
|
25
|
-
},
|
|
26
|
-
text: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Text to type into the referenced element. Required for 'type' action.",
|
|
29
|
-
},
|
|
30
|
-
direction: {
|
|
31
|
-
type: "string",
|
|
32
|
-
enum: ["up", "down", "left", "right"],
|
|
33
|
-
description: "Scroll direction. Required for 'scroll' action.",
|
|
34
|
-
},
|
|
35
|
-
method: {
|
|
36
|
-
type: "string",
|
|
37
|
-
description: "CDP method name (e.g. 'Page.reload'). Required for 'cdp' action.",
|
|
38
|
-
},
|
|
39
|
-
params: {
|
|
40
|
-
type: "object",
|
|
41
|
-
description: "Parameters for the CDP method. Optional for 'cdp' action.",
|
|
42
|
-
},
|
|
43
|
-
expression: {
|
|
44
|
-
type: "string",
|
|
45
|
-
description: "JavaScript expression to evaluate. Used with 'console' action.",
|
|
46
|
-
},
|
|
47
|
-
full: {
|
|
48
|
-
type: "boolean",
|
|
49
|
-
description: "Include full accessibility tree (default: compact). Used with 'snapshot'.",
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
required: ["action"],
|
|
53
|
-
};
|
|
54
|
-
export function createBrowserTool(deps) {
|
|
55
|
-
return {
|
|
56
|
-
name: BROWSER_TOOL_NAME,
|
|
57
|
-
label: "Browser",
|
|
58
|
-
description: "Control a headless browser via Chrome DevTools Protocol. " +
|
|
59
|
-
"Actions: navigate (URL), click/type (element refs from snapshot), " +
|
|
60
|
-
"scroll, snapshot (accessibility tree), screenshot (visual), " +
|
|
61
|
-
"console (JS eval/logs), cdp (raw CDP commands). " +
|
|
62
|
-
"Use snapshot to get element refs before click/type.",
|
|
63
|
-
parameters: BROWSER_TOOL_SCHEMA,
|
|
64
|
-
execute: async (_toolCallId, params) => {
|
|
65
|
-
switch (params.action) {
|
|
66
|
-
case "navigate": {
|
|
67
|
-
if (!params.url) {
|
|
68
|
-
return { content: [{ type: "text", text: "Error: url is required for navigate action." }], details: { type: "browser", error: "missing_url" } };
|
|
69
|
-
}
|
|
70
|
-
const blocked = deps.validateUrl(params.url);
|
|
71
|
-
if (blocked) {
|
|
72
|
-
return { content: [{ type: "text", text: `Blocked: ${blocked}` }], details: { type: "browser", error: "url_blocked" } };
|
|
73
|
-
}
|
|
74
|
-
const nav = await deps.navigate(params.url);
|
|
75
|
-
const lines = [`Navigated to: ${nav.snapshot.url}`, `Title: ${nav.snapshot.title}`, "", `Elements: ${nav.snapshot.elements.length}`];
|
|
76
|
-
if (nav.snapshot.elements.length <= 30) {
|
|
77
|
-
for (const e of nav.snapshot.elements) {
|
|
78
|
-
lines.push(` ${e.ref} [${e.role}] ${e.name}${e.text ? `: "${e.text}"` : ""}`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
lines.push("(use snapshot action for full element list)");
|
|
83
|
-
}
|
|
84
|
-
return { content: [{ type: "text", text: lines.join("\n") }], details: { type: "browser", action: "navigate", url: params.url } };
|
|
85
|
-
}
|
|
86
|
-
case "click": {
|
|
87
|
-
if (!params.ref) {
|
|
88
|
-
return { content: [{ type: "text", text: "Error: ref is required for click (e.g. '@e5')." }], details: { type: "browser", error: "missing_ref" } };
|
|
89
|
-
}
|
|
90
|
-
const click = await deps.click(params.ref);
|
|
91
|
-
if (!click.success) {
|
|
92
|
-
return { content: [{ type: "text", text: `Click failed: ${click.error || "unknown"}` }], details: { type: "browser", error: "click_failed" } };
|
|
93
|
-
}
|
|
94
|
-
return { content: [{ type: "text", text: `Clicked ${params.ref}` }], details: { type: "browser", action: "click", ref: params.ref } };
|
|
95
|
-
}
|
|
96
|
-
case "type": {
|
|
97
|
-
if (!params.ref || !params.text) {
|
|
98
|
-
return { content: [{ type: "text", text: "Error: ref and text are required for type action." }], details: { type: "browser", error: "missing_params" } };
|
|
99
|
-
}
|
|
100
|
-
const typed = await deps.type(params.ref, params.text);
|
|
101
|
-
if (!typed.success) {
|
|
102
|
-
return { content: [{ type: "text", text: `Type failed: ${typed.error || "unknown"}` }], details: { type: "browser", error: "type_failed" } };
|
|
103
|
-
}
|
|
104
|
-
return { content: [{ type: "text", text: `Typed "${params.text}" into ${params.ref}` }], details: { type: "browser", action: "type", ref: params.ref } };
|
|
105
|
-
}
|
|
106
|
-
case "scroll": {
|
|
107
|
-
if (!params.direction) {
|
|
108
|
-
return { content: [{ type: "text", text: "Error: direction is required for scroll." }], details: { type: "browser", error: "missing_direction" } };
|
|
109
|
-
}
|
|
110
|
-
await deps.scroll(params.direction);
|
|
111
|
-
return { content: [{ type: "text", text: `Scrolled ${params.direction}` }], details: { type: "browser", action: "scroll", direction: params.direction } };
|
|
112
|
-
}
|
|
113
|
-
case "snapshot": {
|
|
114
|
-
const snap = await deps.snapshot(params.full);
|
|
115
|
-
const lines = [`URL: ${snap.url}`, `Title: ${snap.title}`, "", `Accessibility tree (${snap.elements.length} elements):`, ""];
|
|
116
|
-
for (const e of snap.elements) {
|
|
117
|
-
lines.push(`${e.ref} [${e.role}] ${e.name}${e.text ? ` — "${e.text}"` : ""}`);
|
|
118
|
-
}
|
|
119
|
-
return { content: [{ type: "text", text: lines.join("\n") }], details: { type: "browser", action: "snapshot", elementCount: snap.elements.length } };
|
|
120
|
-
}
|
|
121
|
-
case "screenshot": {
|
|
122
|
-
const shot = await deps.screenshot();
|
|
123
|
-
return {
|
|
124
|
-
content: [{ type: "image", data: shot.base64, mimeType: shot.mimeType }],
|
|
125
|
-
details: { type: "browser", action: "screenshot", width: shot.width, height: shot.height },
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
case "console": {
|
|
129
|
-
const c = await deps.consoleEval(params.expression);
|
|
130
|
-
const lines = [];
|
|
131
|
-
if (c.result !== undefined)
|
|
132
|
-
lines.push(`Result: ${c.result}`);
|
|
133
|
-
if (c.messages?.length) {
|
|
134
|
-
lines.push("Console messages:");
|
|
135
|
-
c.messages.forEach((m) => lines.push(` ${m}`));
|
|
136
|
-
}
|
|
137
|
-
if (c.errors?.length) {
|
|
138
|
-
lines.push("JS errors:");
|
|
139
|
-
c.errors.forEach((e) => lines.push(` ${e}`));
|
|
140
|
-
}
|
|
141
|
-
return { content: [{ type: "text", text: lines.join("\n") || "(no output)" }], details: { type: "browser", action: "console" } };
|
|
142
|
-
}
|
|
143
|
-
case "cdp": {
|
|
144
|
-
if (!params.method) {
|
|
145
|
-
return { content: [{ type: "text", text: "Error: method is required for cdp action." }], details: { type: "browser", error: "missing_method" } };
|
|
146
|
-
}
|
|
147
|
-
const result = await deps.cdp(params.method, params.params);
|
|
148
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], details: { type: "browser", action: "cdp", method: params.method } };
|
|
149
|
-
}
|
|
150
|
-
default:
|
|
151
|
-
return { content: [{ type: "text", text: `Error: unknown action "${params.action}".` }], details: { type: "browser", error: "unknown_action" } };
|
|
152
|
-
}
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
}
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Checkpoint Manager — transparent file history snapshots.
|
|
3
|
-
// Reference: hermes-agent-main/tools/checkpoint_manager.py
|
|
4
|
-
// Category: infrastructure (LLM does NOT directly invoke)
|
|
5
|
-
// ============================================================
|
|
6
|
-
export const CHECKPOINT_TOOL_NAME = "checkpoint";
|
|
7
|
-
export const CHECKPOINT_TOOL_SCHEMA = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
action: {
|
|
11
|
-
type: "string",
|
|
12
|
-
enum: ["create", "list", "restore", "diff"],
|
|
13
|
-
description: "Action: create (snapshot current state), list (show checkpoints), " +
|
|
14
|
-
"restore (revert to checkpoint), diff (show changes since checkpoint).",
|
|
15
|
-
},
|
|
16
|
-
checkpointId: {
|
|
17
|
-
type: "string",
|
|
18
|
-
description: "Checkpoint ID. Required for restore and diff.",
|
|
19
|
-
},
|
|
20
|
-
message: {
|
|
21
|
-
type: "string",
|
|
22
|
-
description: "Optional descriptive message for the checkpoint.",
|
|
23
|
-
},
|
|
24
|
-
paths: {
|
|
25
|
-
type: "array",
|
|
26
|
-
items: { type: "string" },
|
|
27
|
-
description: "File paths to restore (partial restore). Omit to restore everything.",
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
required: ["action"],
|
|
31
|
-
};
|
|
32
|
-
const COMMIT_HASH_PATTERN = /^[0-9a-fA-F]{4,64}$/;
|
|
33
|
-
export function createCheckpointTool(deps) {
|
|
34
|
-
return {
|
|
35
|
-
name: CHECKPOINT_TOOL_NAME,
|
|
36
|
-
label: "Checkpoint",
|
|
37
|
-
description: "Manage workspace checkpoints (shadow snapshots independent of user's git). " +
|
|
38
|
-
"Create snapshots before risky operations, list history, restore on errors, " +
|
|
39
|
-
"or diff to see what changed. Checkpoints do NOT affect user's .git.",
|
|
40
|
-
parameters: CHECKPOINT_TOOL_SCHEMA,
|
|
41
|
-
execute: async (_toolCallId, params) => {
|
|
42
|
-
switch (params.action) {
|
|
43
|
-
case "create": {
|
|
44
|
-
const r = await deps.createCheckpoint(params.message);
|
|
45
|
-
if (!r.success) {
|
|
46
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "checkpoint", error: r.error } };
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
content: [{ type: "text", text: `Checkpoint created: ${r.checkpoint.id}\nMessage: ${r.checkpoint.message}\nFiles: ${r.checkpoint.fileCount}` }],
|
|
50
|
-
details: { type: "checkpoint", action: "create", checkpointId: r.checkpoint.id },
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
case "list": {
|
|
54
|
-
const r = await deps.listCheckpoints();
|
|
55
|
-
if (!r.checkpoints || r.checkpoints.length === 0) {
|
|
56
|
-
return { content: [{ type: "text", text: "No checkpoints available." }], details: { type: "checkpoint", action: "list", count: 0 } };
|
|
57
|
-
}
|
|
58
|
-
const lines = [`Checkpoints (${r.checkpoints.length}):`, ""];
|
|
59
|
-
for (const cp of r.checkpoints) {
|
|
60
|
-
lines.push(`- ${cp.id.slice(0, 8)} [${cp.timestamp}] ${cp.message} (${cp.fileCount} files)`);
|
|
61
|
-
}
|
|
62
|
-
return { content: [{ type: "text", text: lines.join("\n") }], details: { type: "checkpoint", action: "list", count: r.checkpoints.length } };
|
|
63
|
-
}
|
|
64
|
-
case "restore": {
|
|
65
|
-
if (!params.checkpointId) {
|
|
66
|
-
return { content: [{ type: "text", text: "Error: checkpointId required for restore." }], details: { type: "checkpoint", error: "missing_id" } };
|
|
67
|
-
}
|
|
68
|
-
if (!COMMIT_HASH_PATTERN.test(params.checkpointId)) {
|
|
69
|
-
return { content: [{ type: "text", text: "Error: invalid checkpoint ID format." }], details: { type: "checkpoint", error: "invalid_id" } };
|
|
70
|
-
}
|
|
71
|
-
const r = await deps.restoreCheckpoint(params.checkpointId, params.paths);
|
|
72
|
-
if (!r.success) {
|
|
73
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "checkpoint", error: r.error } };
|
|
74
|
-
}
|
|
75
|
-
const scope = params.paths ? `(${params.paths.length} files)` : "(full workspace)";
|
|
76
|
-
return {
|
|
77
|
-
content: [{ type: "text", text: `Restored to checkpoint ${params.checkpointId.slice(0, 8)} ${scope}` }],
|
|
78
|
-
details: { type: "checkpoint", action: "restore", checkpointId: params.checkpointId },
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
case "diff": {
|
|
82
|
-
if (!params.checkpointId) {
|
|
83
|
-
return { content: [{ type: "text", text: "Error: checkpointId required for diff." }], details: { type: "checkpoint", error: "missing_id" } };
|
|
84
|
-
}
|
|
85
|
-
if (!COMMIT_HASH_PATTERN.test(params.checkpointId)) {
|
|
86
|
-
return { content: [{ type: "text", text: "Error: invalid checkpoint ID format." }], details: { type: "checkpoint", error: "invalid_id" } };
|
|
87
|
-
}
|
|
88
|
-
const r = await deps.diffCheckpoint(params.checkpointId);
|
|
89
|
-
if (!r.success) {
|
|
90
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "checkpoint", error: r.error } };
|
|
91
|
-
}
|
|
92
|
-
return {
|
|
93
|
-
content: [{ type: "text", text: r.diff || "(no changes since checkpoint)" }],
|
|
94
|
-
details: { type: "checkpoint", action: "diff", checkpointId: params.checkpointId },
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
default:
|
|
98
|
-
return { content: [{ type: "text", text: `Error: unknown action "${params.action}".` }], details: { type: "checkpoint", error: "unknown_action" } };
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Config Tool — agent configuration management (read/write preferences).
|
|
3
|
-
// Reference: claude-code-haha/src/tools/ConfigTool/ConfigTool.ts
|
|
4
|
-
// Category: system
|
|
5
|
-
// ============================================================
|
|
6
|
-
export const CONFIG_TOOL_NAME = "config";
|
|
7
|
-
export const CONFIG_TOOL_SCHEMA = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
action: {
|
|
11
|
-
type: "string",
|
|
12
|
-
enum: ["get", "set", "list", "reset"],
|
|
13
|
-
description: "Action:\n" +
|
|
14
|
-
"- get: Read a config setting\n" +
|
|
15
|
-
"- set: Write a config setting\n" +
|
|
16
|
-
"- list: List all available settings\n" +
|
|
17
|
-
"- reset: Reset a setting to default",
|
|
18
|
-
},
|
|
19
|
-
key: {
|
|
20
|
-
type: "string",
|
|
21
|
-
description: "Config key path (e.g. 'model', 'language', 'theme', 'permissions.defaultMode'). " +
|
|
22
|
-
"Required for get/set/reset.",
|
|
23
|
-
},
|
|
24
|
-
value: {
|
|
25
|
-
description: "Value to set. Type depends on the setting. Required for 'set' action.",
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
required: ["action"],
|
|
29
|
-
};
|
|
30
|
-
/** Keys that cannot be modified by LLM (security-critical) */
|
|
31
|
-
export const CONFIG_READONLY_KEYS = [
|
|
32
|
-
"permissions.securityPolicy",
|
|
33
|
-
"api.key",
|
|
34
|
-
"api.secret",
|
|
35
|
-
"auth.token",
|
|
36
|
-
"system.adminMode",
|
|
37
|
-
];
|
|
38
|
-
export function createConfigTool(deps) {
|
|
39
|
-
return {
|
|
40
|
-
name: CONFIG_TOOL_NAME,
|
|
41
|
-
label: "Config",
|
|
42
|
-
description: "Read and write agent configuration settings. " +
|
|
43
|
-
"Supports preferences like model selection, language, theme, tool enablement, etc. " +
|
|
44
|
-
"Security-critical settings (API keys, permissions) are read-only. " +
|
|
45
|
-
"Changes persist across sessions.",
|
|
46
|
-
parameters: CONFIG_TOOL_SCHEMA,
|
|
47
|
-
execute: async (_toolCallId, params) => {
|
|
48
|
-
switch (params.action) {
|
|
49
|
-
case "get": {
|
|
50
|
-
if (!params.key) {
|
|
51
|
-
return { content: [{ type: "text", text: "Error: key is required for get." }], details: { type: "config", error: "missing_key" } };
|
|
52
|
-
}
|
|
53
|
-
if (deps.isValidKey && !deps.isValidKey(params.key)) {
|
|
54
|
-
return { content: [{ type: "text", text: `Error: unknown config key "${params.key}". Use action='list' to see available settings.` }], details: { type: "config", error: "unknown_key" } };
|
|
55
|
-
}
|
|
56
|
-
const result = await deps.getConfig(params.key);
|
|
57
|
-
if (!result.success) {
|
|
58
|
-
return { content: [{ type: "text", text: `Error: ${result.error}` }], details: { type: "config", error: result.error } };
|
|
59
|
-
}
|
|
60
|
-
const s = result.setting;
|
|
61
|
-
const lines = [
|
|
62
|
-
`${s.key} = ${JSON.stringify(s.value)}`,
|
|
63
|
-
` Type: ${s.type}${s.options ? ` (${s.options.join(" | ")})` : ""}`,
|
|
64
|
-
` ${s.description}`,
|
|
65
|
-
];
|
|
66
|
-
if (s.readOnly)
|
|
67
|
-
lines.push(" ⚠️ Read-only (cannot be changed)");
|
|
68
|
-
return {
|
|
69
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
70
|
-
details: { type: "config", action: "get", key: params.key, value: s.value },
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
case "set": {
|
|
74
|
-
if (!params.key) {
|
|
75
|
-
return { content: [{ type: "text", text: "Error: key is required for set." }], details: { type: "config", error: "missing_key" } };
|
|
76
|
-
}
|
|
77
|
-
if (params.value === undefined) {
|
|
78
|
-
return { content: [{ type: "text", text: "Error: value is required for set." }], details: { type: "config", error: "missing_value" } };
|
|
79
|
-
}
|
|
80
|
-
// Block security-critical keys
|
|
81
|
-
if (CONFIG_READONLY_KEYS.includes(params.key)) {
|
|
82
|
-
return {
|
|
83
|
-
content: [{ type: "text", text: `Error: "${params.key}" is a security-critical setting and cannot be modified.` }],
|
|
84
|
-
details: { type: "config", error: "readonly_key" },
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
if (deps.isValidKey && !deps.isValidKey(params.key)) {
|
|
88
|
-
return { content: [{ type: "text", text: `Error: unknown config key "${params.key}".` }], details: { type: "config", error: "unknown_key" } };
|
|
89
|
-
}
|
|
90
|
-
const result = await deps.setConfig(params.key, params.value);
|
|
91
|
-
if (!result.success) {
|
|
92
|
-
return { content: [{ type: "text", text: `Error: ${result.error}` }], details: { type: "config", error: result.error } };
|
|
93
|
-
}
|
|
94
|
-
return {
|
|
95
|
-
content: [{ type: "text", text: `Updated "${params.key}": ${JSON.stringify(result.previousValue)} → ${JSON.stringify(params.value)}` }],
|
|
96
|
-
details: { type: "config", action: "set", key: params.key, previousValue: result.previousValue, newValue: params.value },
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
case "list": {
|
|
100
|
-
const result = await deps.listConfig();
|
|
101
|
-
if (!result.settings || result.settings.length === 0) {
|
|
102
|
-
return { content: [{ type: "text", text: "No config settings available." }], details: { type: "config", action: "list", count: 0 } };
|
|
103
|
-
}
|
|
104
|
-
const lines = [`Available settings (${result.settings.length}):`, ""];
|
|
105
|
-
for (const s of result.settings) {
|
|
106
|
-
const ro = s.readOnly ? " [read-only]" : "";
|
|
107
|
-
const val = JSON.stringify(s.value);
|
|
108
|
-
lines.push(` ${s.key} = ${val}${ro}`);
|
|
109
|
-
lines.push(` ${s.description}`);
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
content: [{ type: "text", text: lines.join("\n") }],
|
|
113
|
-
details: { type: "config", action: "list", count: result.settings.length },
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
case "reset": {
|
|
117
|
-
if (!params.key) {
|
|
118
|
-
return { content: [{ type: "text", text: "Error: key is required for reset." }], details: { type: "config", error: "missing_key" } };
|
|
119
|
-
}
|
|
120
|
-
if (CONFIG_READONLY_KEYS.includes(params.key)) {
|
|
121
|
-
return {
|
|
122
|
-
content: [{ type: "text", text: `Error: "${params.key}" cannot be reset (security-critical).` }],
|
|
123
|
-
details: { type: "config", error: "readonly_key" },
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
const result = await deps.resetConfig(params.key);
|
|
127
|
-
if (!result.success) {
|
|
128
|
-
return { content: [{ type: "text", text: `Error: ${result.error}` }], details: { type: "config", error: result.error } };
|
|
129
|
-
}
|
|
130
|
-
return {
|
|
131
|
-
content: [{ type: "text", text: `Reset "${params.key}" to default: ${JSON.stringify(result.setting?.value)}` }],
|
|
132
|
-
details: { type: "config", action: "reset", key: params.key, value: result.setting?.value },
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
default:
|
|
136
|
-
return {
|
|
137
|
-
content: [{ type: "text", text: `Error: unknown action "${params.action}".` }],
|
|
138
|
-
details: { type: "config", error: "unknown_action" },
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// Cron Tool — scheduled task management (CRUD).
|
|
3
|
-
// Reference: hermes-agent-main/tools/cronjob_tools.py
|
|
4
|
-
// Category: system
|
|
5
|
-
// ============================================================
|
|
6
|
-
export const CRON_TOOL_NAME = "cron";
|
|
7
|
-
export const CRON_TOOL_SCHEMA = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
action: {
|
|
11
|
-
type: "string",
|
|
12
|
-
enum: ["create", "list", "get", "update", "delete", "pause", "resume", "trigger"],
|
|
13
|
-
description: "CRUD action: create/list/get/update/delete/pause/resume/trigger.",
|
|
14
|
-
},
|
|
15
|
-
jobId: {
|
|
16
|
-
type: "string",
|
|
17
|
-
description: "Job ID. Required for get/update/delete/pause/resume/trigger.",
|
|
18
|
-
},
|
|
19
|
-
prompt: {
|
|
20
|
-
type: "string",
|
|
21
|
-
description: "Task prompt to execute on schedule. Required for create.",
|
|
22
|
-
},
|
|
23
|
-
schedule: {
|
|
24
|
-
type: "string",
|
|
25
|
-
description: "Schedule expression. Supports:\n" +
|
|
26
|
-
"- Cron: '0 9 * * *' (every day at 9am)\n" +
|
|
27
|
-
"- Shorthand: '5m' (every 5 min), '1h' (hourly), '1d' (daily)\n" +
|
|
28
|
-
"Required for create.",
|
|
29
|
-
},
|
|
30
|
-
name: {
|
|
31
|
-
type: "string",
|
|
32
|
-
description: "Human-readable job name.",
|
|
33
|
-
},
|
|
34
|
-
repeat: {
|
|
35
|
-
type: "number",
|
|
36
|
-
description: "Number of times to repeat (null = infinite). Default: null.",
|
|
37
|
-
},
|
|
38
|
-
allowedTools: {
|
|
39
|
-
type: "array",
|
|
40
|
-
items: { type: "string" },
|
|
41
|
-
description: "Tools the scheduled task is allowed to use.",
|
|
42
|
-
},
|
|
43
|
-
enabled: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description: "Whether the job is enabled (for update).",
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
required: ["action"],
|
|
49
|
-
};
|
|
50
|
-
export const MAX_CRON_JOBS = 50;
|
|
51
|
-
export function createCronTool(deps) {
|
|
52
|
-
return {
|
|
53
|
-
name: CRON_TOOL_NAME,
|
|
54
|
-
label: "Cron",
|
|
55
|
-
description: "Manage scheduled tasks. Create recurring jobs with cron expressions or shorthand " +
|
|
56
|
-
"('5m', '1h', '0 9 * * *'). Jobs persist locally and survive restarts. " +
|
|
57
|
-
"Actions: create, list, get, update, delete, pause, resume, trigger (run now).",
|
|
58
|
-
parameters: CRON_TOOL_SCHEMA,
|
|
59
|
-
execute: async (_toolCallId, params) => {
|
|
60
|
-
switch (params.action) {
|
|
61
|
-
case "create": {
|
|
62
|
-
if (!params.prompt) {
|
|
63
|
-
return { content: [{ type: "text", text: "Error: prompt is required for create." }], details: { type: "cron", error: "missing_prompt" } };
|
|
64
|
-
}
|
|
65
|
-
if (!params.schedule) {
|
|
66
|
-
return { content: [{ type: "text", text: "Error: schedule is required for create." }], details: { type: "cron", error: "missing_schedule" } };
|
|
67
|
-
}
|
|
68
|
-
if (deps.validateSchedule) {
|
|
69
|
-
const err = deps.validateSchedule(params.schedule);
|
|
70
|
-
if (err)
|
|
71
|
-
return { content: [{ type: "text", text: `Error: invalid schedule — ${err}` }], details: { type: "cron", error: "invalid_schedule" } };
|
|
72
|
-
}
|
|
73
|
-
// Check max jobs limit
|
|
74
|
-
const existing = await deps.listJobs();
|
|
75
|
-
if (existing.jobs && existing.jobs.length >= MAX_CRON_JOBS) {
|
|
76
|
-
return { content: [{ type: "text", text: `Error: maximum ${MAX_CRON_JOBS} jobs reached. Delete unused jobs first.` }], details: { type: "cron", error: "max_jobs_reached" } };
|
|
77
|
-
}
|
|
78
|
-
const r = await deps.createJob({ prompt: params.prompt, schedule: params.schedule, name: params.name, repeat: params.repeat, allowedTools: params.allowedTools });
|
|
79
|
-
if (!r.success)
|
|
80
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
81
|
-
return { content: [{ type: "text", text: formatJob(r.job) }], details: { type: "cron", action: "create", jobId: r.job.id } };
|
|
82
|
-
}
|
|
83
|
-
case "list": {
|
|
84
|
-
const r = await deps.listJobs();
|
|
85
|
-
if (!r.jobs || r.jobs.length === 0) {
|
|
86
|
-
return { content: [{ type: "text", text: "No scheduled jobs." }], details: { type: "cron", action: "list", count: 0 } };
|
|
87
|
-
}
|
|
88
|
-
const lines = [`Scheduled jobs (${r.jobs.length}):`, ""];
|
|
89
|
-
for (const j of r.jobs) {
|
|
90
|
-
lines.push(`- **${j.name || j.id}** [${j.state}] ${j.scheduleDisplay} — next: ${j.nextRunAt || "N/A"}`);
|
|
91
|
-
}
|
|
92
|
-
return { content: [{ type: "text", text: lines.join("\n") }], details: { type: "cron", action: "list", count: r.jobs.length } };
|
|
93
|
-
}
|
|
94
|
-
case "get": {
|
|
95
|
-
if (!params.jobId)
|
|
96
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
97
|
-
const r = await deps.getJob(params.jobId);
|
|
98
|
-
if (!r.success)
|
|
99
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
100
|
-
return { content: [{ type: "text", text: formatJob(r.job) }], details: { type: "cron", action: "get", jobId: params.jobId } };
|
|
101
|
-
}
|
|
102
|
-
case "update": {
|
|
103
|
-
if (!params.jobId)
|
|
104
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
105
|
-
const updates = {};
|
|
106
|
-
if (params.prompt !== undefined)
|
|
107
|
-
updates.prompt = params.prompt;
|
|
108
|
-
if (params.schedule !== undefined)
|
|
109
|
-
updates.schedule = params.schedule;
|
|
110
|
-
if (params.name !== undefined)
|
|
111
|
-
updates.name = params.name;
|
|
112
|
-
if (params.enabled !== undefined)
|
|
113
|
-
updates.enabled = params.enabled;
|
|
114
|
-
if (params.repeat !== undefined)
|
|
115
|
-
updates.repeat = params.repeat;
|
|
116
|
-
if (params.allowedTools !== undefined)
|
|
117
|
-
updates.allowedTools = params.allowedTools;
|
|
118
|
-
const r = await deps.updateJob(params.jobId, updates);
|
|
119
|
-
if (!r.success)
|
|
120
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
121
|
-
return { content: [{ type: "text", text: `Job updated.\n${formatJob(r.job)}` }], details: { type: "cron", action: "update", jobId: params.jobId } };
|
|
122
|
-
}
|
|
123
|
-
case "delete": {
|
|
124
|
-
if (!params.jobId)
|
|
125
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
126
|
-
const r = await deps.deleteJob(params.jobId);
|
|
127
|
-
if (!r.success)
|
|
128
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
129
|
-
return { content: [{ type: "text", text: `Job ${params.jobId} deleted.` }], details: { type: "cron", action: "delete", jobId: params.jobId } };
|
|
130
|
-
}
|
|
131
|
-
case "pause": {
|
|
132
|
-
if (!params.jobId)
|
|
133
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
134
|
-
const r = await deps.pauseJob(params.jobId);
|
|
135
|
-
if (!r.success)
|
|
136
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
137
|
-
return { content: [{ type: "text", text: `Job ${params.jobId} paused.` }], details: { type: "cron", action: "pause", jobId: params.jobId } };
|
|
138
|
-
}
|
|
139
|
-
case "resume": {
|
|
140
|
-
if (!params.jobId)
|
|
141
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
142
|
-
const r = await deps.resumeJob(params.jobId);
|
|
143
|
-
if (!r.success)
|
|
144
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
145
|
-
return { content: [{ type: "text", text: `Job ${params.jobId} resumed.` }], details: { type: "cron", action: "resume", jobId: params.jobId } };
|
|
146
|
-
}
|
|
147
|
-
case "trigger": {
|
|
148
|
-
if (!params.jobId)
|
|
149
|
-
return { content: [{ type: "text", text: "Error: jobId required." }], details: { type: "cron", error: "missing_jobId" } };
|
|
150
|
-
const r = await deps.triggerJob(params.jobId);
|
|
151
|
-
if (!r.success)
|
|
152
|
-
return { content: [{ type: "text", text: `Error: ${r.error}` }], details: { type: "cron", error: r.error } };
|
|
153
|
-
return { content: [{ type: "text", text: `Job ${params.jobId} triggered (running now).` }], details: { type: "cron", action: "trigger", jobId: params.jobId } };
|
|
154
|
-
}
|
|
155
|
-
default:
|
|
156
|
-
return { content: [{ type: "text", text: `Error: unknown action "${params.action}".` }], details: { type: "cron", error: "unknown_action" } };
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function formatJob(job) {
|
|
162
|
-
const lines = [
|
|
163
|
-
`Job: ${job.name || job.id}`,
|
|
164
|
-
`ID: ${job.id}`,
|
|
165
|
-
`Schedule: ${job.scheduleDisplay} (${job.schedule})`,
|
|
166
|
-
`State: ${job.state}`,
|
|
167
|
-
`Repeat: ${job.repeat.times === null ? "infinite" : `${job.repeat.completed}/${job.repeat.times}`}`,
|
|
168
|
-
];
|
|
169
|
-
if (job.nextRunAt)
|
|
170
|
-
lines.push(`Next run: ${job.nextRunAt}`);
|
|
171
|
-
if (job.lastRunAt)
|
|
172
|
-
lines.push(`Last run: ${job.lastRunAt} (${job.lastStatus || "unknown"})`);
|
|
173
|
-
lines.push(`Prompt: ${job.prompt.slice(0, 100)}${job.prompt.length > 100 ? "..." : ""}`);
|
|
174
|
-
return lines.join("\n");
|
|
175
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// File Edit Tool — surgical text replacement in files.
|
|
3
|
-
// Category: coding
|
|
4
|
-
// ============================================================
|
|
5
|
-
export const EDIT_TOOL_NAME = "edit";
|
|
6
|
-
export const EDIT_TOOL_SCHEMA = {
|
|
7
|
-
type: "object",
|
|
8
|
-
properties: {
|
|
9
|
-
path: {
|
|
10
|
-
type: "string",
|
|
11
|
-
description: "Path to the file to edit (relative or absolute).",
|
|
12
|
-
},
|
|
13
|
-
oldText: {
|
|
14
|
-
type: "string",
|
|
15
|
-
description: "Exact text to find and replace (must match exactly, including whitespace).",
|
|
16
|
-
},
|
|
17
|
-
newText: {
|
|
18
|
-
type: "string",
|
|
19
|
-
description: "New text to replace the old text with.",
|
|
20
|
-
},
|
|
21
|
-
},
|
|
22
|
-
required: ["path", "oldText", "newText"],
|
|
23
|
-
};
|
|
24
|
-
export function createEditTool(deps) {
|
|
25
|
-
return {
|
|
26
|
-
name: EDIT_TOOL_NAME,
|
|
27
|
-
label: "Edit File",
|
|
28
|
-
description: "Edit a file by replacing exact text. The oldText must match exactly (including whitespace). " +
|
|
29
|
-
"Use this for precise, surgical edits. For multiple edits, call this tool multiple times.",
|
|
30
|
-
parameters: EDIT_TOOL_SCHEMA,
|
|
31
|
-
execute: async (_toolCallId, params) => {
|
|
32
|
-
const resolved = deps.resolvePath(params.path);
|
|
33
|
-
// Concurrent modification check
|
|
34
|
-
if (deps.checkConcurrentModification) {
|
|
35
|
-
const conflict = deps.checkConcurrentModification(resolved);
|
|
36
|
-
if (conflict) {
|
|
37
|
-
return {
|
|
38
|
-
content: [{ type: "text", text: `Concurrent modification detected: ${conflict}. Re-read the file first.` }],
|
|
39
|
-
details: { type: "edit", path: resolved, success: false, reason: "concurrent_modification" },
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
const content = await deps.readFile(resolved);
|
|
44
|
-
const index = content.indexOf(params.oldText);
|
|
45
|
-
if (index === -1) {
|
|
46
|
-
return {
|
|
47
|
-
content: [{ type: "text", text: `Error: oldText not found in ${resolved}. Ensure it matches exactly.` }],
|
|
48
|
-
details: { type: "edit", path: resolved, success: false, reason: "not_found" },
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
// Check for multiple matches
|
|
52
|
-
const secondIndex = content.indexOf(params.oldText, index + 1);
|
|
53
|
-
if (secondIndex !== -1) {
|
|
54
|
-
return {
|
|
55
|
-
content: [{ type: "text", text: `Error: oldText matches multiple locations in ${resolved}. Include more context to make the match unique.` }],
|
|
56
|
-
details: { type: "edit", path: resolved, success: false, reason: "ambiguous" },
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
const newContent = content.slice(0, index) + params.newText + content.slice(index + params.oldText.length);
|
|
60
|
-
await deps.writeFile(resolved, newContent);
|
|
61
|
-
// Compute first changed line
|
|
62
|
-
const preLines = content.slice(0, index).split("\n");
|
|
63
|
-
const firstChangedLine = preLines.length;
|
|
64
|
-
return {
|
|
65
|
-
content: [{ type: "text", text: `Edited ${resolved} (line ${firstChangedLine})` }],
|
|
66
|
-
details: { type: "edit", path: resolved, success: true, firstChangedLine },
|
|
67
|
-
};
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
}
|