@smartledger.technology/openai-claw 0.1.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/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/agent.js +262 -0
- package/dist/agent.js.map +1 -0
- package/dist/autopr/index.js +127 -0
- package/dist/autopr/index.js.map +1 -0
- package/dist/client.js +199 -0
- package/dist/client.js.map +1 -0
- package/dist/commands/index.js +624 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/config.js +71 -0
- package/dist/config.js.map +1 -0
- package/dist/cost.js +97 -0
- package/dist/cost.js.map +1 -0
- package/dist/eval/cli.js +32 -0
- package/dist/eval/cli.js.map +1 -0
- package/dist/eval/index.js +134 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/hooks/index.js +69 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.js +246 -0
- package/dist/index.js.map +1 -0
- package/dist/input.js +96 -0
- package/dist/input.js.map +1 -0
- package/dist/mcp/index.js +135 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/memory/compaction.js +70 -0
- package/dist/memory/compaction.js.map +1 -0
- package/dist/memory/index.js +56 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/notifications/index.js +80 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/permissions/index.js +104 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/planmode.js +12 -0
- package/dist/planmode.js.map +1 -0
- package/dist/plugins/index.js +239 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/prompts/system.js +148 -0
- package/dist/prompts/system.js.map +1 -0
- package/dist/rag/index.js +158 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/self-review/index.js +157 -0
- package/dist/self-review/index.js.map +1 -0
- package/dist/session.js +113 -0
- package/dist/session.js.map +1 -0
- package/dist/skills/index.js +39 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/subagent.js +128 -0
- package/dist/subagent.js.map +1 -0
- package/dist/subagents/index.js +61 -0
- package/dist/subagents/index.js.map +1 -0
- package/dist/tools/bash.js +94 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit.js +64 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.js +34 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.js +87 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.js +44 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/ls.js +39 -0
- package/dist/tools/ls.js.map +1 -0
- package/dist/tools/read.js +126 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/semantic.js +40 -0
- package/dist/tools/semantic.js.map +1 -0
- package/dist/tools/shell.js +131 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/task.js +91 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/todo.js +64 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/types.js +7 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/webfetch.js +62 -0
- package/dist/tools/webfetch.js.map +1 -0
- package/dist/tools/websearch.js +82 -0
- package/dist/tools/websearch.js.map +1 -0
- package/dist/tools/write.js +39 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/ui/repl.js +203 -0
- package/dist/ui/repl.js.map +1 -0
- package/dist/ui/tui/App.js +234 -0
- package/dist/ui/tui/App.js.map +1 -0
- package/dist/ui/tui/Diff.js +38 -0
- package/dist/ui/tui/Diff.js.map +1 -0
- package/dist/ui/tui/MessageView.js +50 -0
- package/dist/ui/tui/MessageView.js.map +1 -0
- package/dist/ui/tui/PermissionPrompt.js +47 -0
- package/dist/ui/tui/PermissionPrompt.js.map +1 -0
- package/dist/ui/tui/SlashSuggest.js +36 -0
- package/dist/ui/tui/SlashSuggest.js.map +1 -0
- package/dist/ui/tui/StatusBar.js +31 -0
- package/dist/ui/tui/StatusBar.js.map +1 -0
- package/dist/ui/tui/highlight.js +66 -0
- package/dist/ui/tui/highlight.js.map +1 -0
- package/dist/ui/tui/index.js +12 -0
- package/dist/ui/tui/index.js.map +1 -0
- package/dist/ui/tui/markdown.js +46 -0
- package/dist/ui/tui/markdown.js.map +1 -0
- package/dist/ui/tui/types.js +2 -0
- package/dist/ui/tui/types.js.map +1 -0
- package/dist/web/index.js +195 -0
- package/dist/web/index.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ok, err } from "./types.js";
|
|
2
|
+
import { semanticSearch } from "../rag/index.js";
|
|
3
|
+
export const semanticTool = {
|
|
4
|
+
name: "Semantic",
|
|
5
|
+
description: "Search the project by semantic meaning, not literal pattern. Returns the top-K most relevant code chunks ranked by embedding similarity. Use this when the user describes what they want by intent (e.g. \"where is auth checked?\") rather than by exact string. Falls back to a helpful error if the index hasn't been built — run /index first.",
|
|
6
|
+
needsPermission: false,
|
|
7
|
+
mutates: false,
|
|
8
|
+
parameters: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
query: { type: "string", description: "Natural-language query — describe what you're looking for" },
|
|
12
|
+
k: { type: "number", description: "Top-K hits to return (default 8)" },
|
|
13
|
+
snippets: {
|
|
14
|
+
type: "boolean",
|
|
15
|
+
description: "Include the chunk text in the output (default false: file paths + scores only)",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
required: ["query"],
|
|
19
|
+
},
|
|
20
|
+
async run(input, ctx) {
|
|
21
|
+
try {
|
|
22
|
+
const k = Math.max(1, Math.min(50, input.k ?? 8));
|
|
23
|
+
const hits = await semanticSearch(ctx.config, input.query, k);
|
|
24
|
+
if (hits.length === 0)
|
|
25
|
+
return ok("(no hits)");
|
|
26
|
+
const lines = hits.map((h, i) => {
|
|
27
|
+
const head = `${i + 1}. ${h.file}#${h.chunkIndex} (score=${h.score.toFixed(3)})`;
|
|
28
|
+
if (!input.snippets)
|
|
29
|
+
return head;
|
|
30
|
+
return `${head}\n${h.text.slice(0, 800)}${h.text.length > 800 ? "\n…" : ""}`;
|
|
31
|
+
});
|
|
32
|
+
return ok(lines.join("\n\n"));
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
return err(e?.message ?? String(e));
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
preview: (input) => `Semantic ${JSON.stringify(input.query).slice(0, 60)}`,
|
|
39
|
+
};
|
|
40
|
+
//# sourceMappingURL=semantic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.js","sourceRoot":"","sources":["../../src/tools/semantic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,EAAE,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,CAAC,MAAM,YAAY,GAA4D;IACnF,IAAI,EAAE,UAAU;IAChB,WAAW,EACT,oVAAoV;IACtV,eAAe,EAAE,KAAK;IACtB,OAAO,EAAE,KAAK;IACd,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2DAA2D,EAAE;YACnG,CAAC,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,kCAAkC,EAAE;YACtE,QAAQ,EAAE;gBACR,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,gFAAgF;aAC9F;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;IACD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG;QAClB,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC,WAAW,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBAC9B,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,UAAU,WAAW,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;gBACjF,IAAI,CAAC,KAAK,CAAC,QAAQ;oBAAE,OAAO,IAAI,CAAC;gBACjC,OAAO,GAAG,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YAC/E,CAAC,CAAC,CAAC;YACH,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,GAAG,CAAC,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE;CAC3E,CAAC"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { ok, err } from "./types.js";
|
|
5
|
+
const shells = new Map();
|
|
6
|
+
function shellsDir(config) {
|
|
7
|
+
const dir = path.join(config.projectDir, "shells");
|
|
8
|
+
if (!fs.existsSync(dir))
|
|
9
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
10
|
+
return dir;
|
|
11
|
+
}
|
|
12
|
+
function nextShellId() {
|
|
13
|
+
return `sh_${Date.now().toString(36)}_${Math.floor(Math.random() * 0xfff).toString(16)}`;
|
|
14
|
+
}
|
|
15
|
+
/** Spawn a background shell. Caller is responsible for messaging the agent. */
|
|
16
|
+
export function spawnBackgroundShell(config, command) {
|
|
17
|
+
const dir = shellsDir(config);
|
|
18
|
+
const id = nextShellId();
|
|
19
|
+
const logFile = path.join(dir, `${id}.log`);
|
|
20
|
+
const out = fs.openSync(logFile, "w");
|
|
21
|
+
const child = spawn("bash", ["-c", command], {
|
|
22
|
+
cwd: config.workdir,
|
|
23
|
+
env: process.env,
|
|
24
|
+
stdio: ["ignore", out, out],
|
|
25
|
+
detached: true,
|
|
26
|
+
});
|
|
27
|
+
child.unref();
|
|
28
|
+
const shell = {
|
|
29
|
+
id,
|
|
30
|
+
pid: child.pid ?? -1,
|
|
31
|
+
command,
|
|
32
|
+
startedAt: Date.now(),
|
|
33
|
+
logFile,
|
|
34
|
+
child,
|
|
35
|
+
status: "running",
|
|
36
|
+
exitCode: null,
|
|
37
|
+
cursor: 0,
|
|
38
|
+
};
|
|
39
|
+
child.on("exit", (code, signal) => {
|
|
40
|
+
shell.status = signal === "SIGKILL" || signal === "SIGTERM" ? "killed" : "exited";
|
|
41
|
+
shell.exitCode = code;
|
|
42
|
+
try {
|
|
43
|
+
fs.closeSync(out);
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
46
|
+
});
|
|
47
|
+
shells.set(id, shell);
|
|
48
|
+
return shell;
|
|
49
|
+
}
|
|
50
|
+
function readLogTail(shell, fromCursor) {
|
|
51
|
+
if (!fs.existsSync(shell.logFile))
|
|
52
|
+
return { chunk: "", newCursor: shell.cursor };
|
|
53
|
+
const stat = fs.statSync(shell.logFile);
|
|
54
|
+
const start = fromCursor ? shell.cursor : 0;
|
|
55
|
+
if (start >= stat.size)
|
|
56
|
+
return { chunk: "", newCursor: stat.size };
|
|
57
|
+
const fd = fs.openSync(shell.logFile, "r");
|
|
58
|
+
const len = stat.size - start;
|
|
59
|
+
const buf = Buffer.alloc(len);
|
|
60
|
+
fs.readSync(fd, buf, 0, len, start);
|
|
61
|
+
fs.closeSync(fd);
|
|
62
|
+
return { chunk: buf.toString("utf8"), newCursor: stat.size };
|
|
63
|
+
}
|
|
64
|
+
export const bashOutputTool = {
|
|
65
|
+
name: "BashOutput",
|
|
66
|
+
description: "Retrieve new output from a background Bash shell since the last poll. Returns the shell's status (running/exited/killed) and the new stdout+stderr bytes. Use this to monitor long-running jobs you launched with Bash(run_in_background: true).",
|
|
67
|
+
needsPermission: false,
|
|
68
|
+
mutates: false,
|
|
69
|
+
parameters: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
shell_id: { type: "string", description: "Shell id returned by Bash(run_in_background: true)" },
|
|
73
|
+
from_start: { type: "boolean", description: "Re-read all output from the beginning (default false: resume from cursor)" },
|
|
74
|
+
},
|
|
75
|
+
required: ["shell_id"],
|
|
76
|
+
},
|
|
77
|
+
async run(input) {
|
|
78
|
+
const shell = shells.get(input.shell_id);
|
|
79
|
+
if (!shell)
|
|
80
|
+
return err(`Unknown shell_id: ${input.shell_id}`);
|
|
81
|
+
const { chunk, newCursor } = readLogTail(shell, !input.from_start);
|
|
82
|
+
if (!input.from_start)
|
|
83
|
+
shell.cursor = newCursor;
|
|
84
|
+
const header = `[shell ${shell.id} status=${shell.status}${shell.exitCode !== null ? ` exit=${shell.exitCode}` : ""}]`;
|
|
85
|
+
return ok(`${header}\n${chunk || "(no new output)"}`);
|
|
86
|
+
},
|
|
87
|
+
preview: (input) => `BashOutput ${input.shell_id}`,
|
|
88
|
+
};
|
|
89
|
+
export const killShellTool = {
|
|
90
|
+
name: "KillShell",
|
|
91
|
+
description: "Terminate a background Bash shell by id. Sends SIGTERM, then SIGKILL after 2s.",
|
|
92
|
+
needsPermission: true,
|
|
93
|
+
mutates: true,
|
|
94
|
+
parameters: {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: {
|
|
97
|
+
shell_id: { type: "string", description: "Shell id to kill" },
|
|
98
|
+
},
|
|
99
|
+
required: ["shell_id"],
|
|
100
|
+
},
|
|
101
|
+
async run(input) {
|
|
102
|
+
const shell = shells.get(input.shell_id);
|
|
103
|
+
if (!shell)
|
|
104
|
+
return err(`Unknown shell_id: ${input.shell_id}`);
|
|
105
|
+
if (shell.status !== "running")
|
|
106
|
+
return ok(`Shell ${shell.id} already ${shell.status}.`);
|
|
107
|
+
try {
|
|
108
|
+
shell.child.kill("SIGTERM");
|
|
109
|
+
setTimeout(() => {
|
|
110
|
+
if (shell.status === "running")
|
|
111
|
+
shell.child.kill("SIGKILL");
|
|
112
|
+
}, 2000);
|
|
113
|
+
return ok(`Sent SIGTERM to shell ${shell.id}.`);
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
return err(`KillShell failed: ${e?.message ?? String(e)}`);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
preview: (input) => `KillShell ${input.shell_id}`,
|
|
120
|
+
};
|
|
121
|
+
/** For /agents-style introspection. */
|
|
122
|
+
export function listShells() {
|
|
123
|
+
return Array.from(shells.values()).map((s) => ({
|
|
124
|
+
id: s.id,
|
|
125
|
+
pid: s.pid,
|
|
126
|
+
command: s.command,
|
|
127
|
+
status: s.status,
|
|
128
|
+
exitCode: s.exitCode,
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/tools/shell.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { ok, err } from "./types.js";
|
|
2
|
+
import { listSubagents } from "../subagents/index.js";
|
|
3
|
+
/** Built lazily so registered agents in .claw/agents/ surface at runtime. */
|
|
4
|
+
export function buildTaskTool(config) {
|
|
5
|
+
const agents = listSubagents(config);
|
|
6
|
+
const enumNames = agents.map((a) => a.name);
|
|
7
|
+
const catalog = agents
|
|
8
|
+
.map((a) => `- ${a.name}${a.tools ? ` (tools: ${a.tools.join(",")})` : ""}: ${a.description}`)
|
|
9
|
+
.join("\n");
|
|
10
|
+
return {
|
|
11
|
+
name: "Task",
|
|
12
|
+
description: `Launch a subagent to handle complex multi-step work in an isolated context. Use for: open-ended research, parallel investigations, or tasks whose tool output would crowd the parent's context. Brief the subagent thoroughly — it sees none of this conversation. Set isolation="worktree" to run the subagent in a temporary git worktree; the returned text will include the diff.\nAvailable subagent types:\n${catalog}`,
|
|
13
|
+
needsPermission: false,
|
|
14
|
+
mutates: false,
|
|
15
|
+
parameters: {
|
|
16
|
+
type: "object",
|
|
17
|
+
properties: {
|
|
18
|
+
description: { type: "string", description: "Short (3-5 word) description of the task" },
|
|
19
|
+
prompt: { type: "string", description: "Self-contained instructions for the subagent" },
|
|
20
|
+
subagent_type: {
|
|
21
|
+
type: "string",
|
|
22
|
+
enum: enumNames,
|
|
23
|
+
description: "Which subagent type to use (default 'general-purpose')",
|
|
24
|
+
},
|
|
25
|
+
isolation: {
|
|
26
|
+
type: "string",
|
|
27
|
+
enum: ["worktree"],
|
|
28
|
+
description: "If 'worktree', the subagent runs in a fresh git worktree and its diff is returned.",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["description", "prompt"],
|
|
32
|
+
},
|
|
33
|
+
async run(input, ctx) {
|
|
34
|
+
if (!ctx.spawnSubagent)
|
|
35
|
+
return err("Subagent spawning is not available in this context.");
|
|
36
|
+
if (input.subagent_type && !enumNames.includes(input.subagent_type)) {
|
|
37
|
+
return err(`Unknown subagent_type: ${input.subagent_type}. Available: ${enumNames.join(", ")}`);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const result = await ctx.spawnSubagent({
|
|
41
|
+
description: input.description,
|
|
42
|
+
prompt: input.prompt,
|
|
43
|
+
subagent_type: input.subagent_type,
|
|
44
|
+
isolation: input.isolation,
|
|
45
|
+
});
|
|
46
|
+
return ok(result);
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return err(`Subagent failed: ${e?.message ?? String(e)}`);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
preview: (input) => `Task: ${input.description}${input.isolation ? " [worktree]" : ""}`,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Static fallback (kept for backwards compat with the existing exports). */
|
|
56
|
+
export const taskTool = {
|
|
57
|
+
name: "Task",
|
|
58
|
+
description: "Launch a subagent to handle complex multi-step work in an isolated context. Use for: open-ended research, parallel investigations, or tasks whose tool output would crowd the parent's context. Brief the subagent thoroughly — it sees none of this conversation. Available subagent types: 'general-purpose', 'explore' (read-only search).",
|
|
59
|
+
needsPermission: false,
|
|
60
|
+
mutates: false,
|
|
61
|
+
parameters: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
description: { type: "string", description: "Short (3-5 word) description of the task" },
|
|
65
|
+
prompt: { type: "string", description: "Self-contained instructions for the subagent" },
|
|
66
|
+
subagent_type: {
|
|
67
|
+
type: "string",
|
|
68
|
+
enum: ["general-purpose", "explore"],
|
|
69
|
+
description: "Which subagent type to use (default 'general-purpose')",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
required: ["description", "prompt"],
|
|
73
|
+
},
|
|
74
|
+
async run(input, ctx) {
|
|
75
|
+
if (!ctx.spawnSubagent)
|
|
76
|
+
return err("Subagent spawning is not available in this context.");
|
|
77
|
+
try {
|
|
78
|
+
const result = await ctx.spawnSubagent({
|
|
79
|
+
description: input.description,
|
|
80
|
+
prompt: input.prompt,
|
|
81
|
+
subagent_type: input.subagent_type,
|
|
82
|
+
});
|
|
83
|
+
return ok(result);
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
return err(`Subagent failed: ${e?.message ?? String(e)}`);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
preview: (input) => `Task: ${input.description}`,
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/tools/task.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ok } from "./types.js";
|
|
4
|
+
let todoList = [];
|
|
5
|
+
export function getTodos() {
|
|
6
|
+
return todoList;
|
|
7
|
+
}
|
|
8
|
+
function todosFile(memoryDir) {
|
|
9
|
+
return path.join(memoryDir, "todos.json");
|
|
10
|
+
}
|
|
11
|
+
export function loadTodos(memoryDir) {
|
|
12
|
+
try {
|
|
13
|
+
const f = todosFile(memoryDir);
|
|
14
|
+
if (!fs.existsSync(f))
|
|
15
|
+
return;
|
|
16
|
+
const raw = JSON.parse(fs.readFileSync(f, "utf8"));
|
|
17
|
+
if (Array.isArray(raw))
|
|
18
|
+
todoList = raw;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// ignore — start fresh
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export const todoWriteTool = {
|
|
25
|
+
name: "TodoWrite",
|
|
26
|
+
description: "Create and manage a structured todo list for the current session. Use for tasks that span 3+ steps. Replace the whole list each call. Mark exactly one item in_progress at a time. The list is persisted to disk and survives /resume.",
|
|
27
|
+
needsPermission: false,
|
|
28
|
+
mutates: false,
|
|
29
|
+
parameters: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
todos: {
|
|
33
|
+
type: "array",
|
|
34
|
+
items: {
|
|
35
|
+
type: "object",
|
|
36
|
+
properties: {
|
|
37
|
+
content: { type: "string", description: "Imperative form, e.g. 'Run the tests'" },
|
|
38
|
+
status: { type: "string", enum: ["pending", "in_progress", "completed"] },
|
|
39
|
+
activeForm: { type: "string", description: "Present continuous, e.g. 'Running the tests'" },
|
|
40
|
+
},
|
|
41
|
+
required: ["content", "status"],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
required: ["todos"],
|
|
46
|
+
},
|
|
47
|
+
async run(input, ctx) {
|
|
48
|
+
todoList = input.todos;
|
|
49
|
+
try {
|
|
50
|
+
fs.writeFileSync(todosFile(ctx.config.memoryDir), JSON.stringify(todoList, null, 2));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// persistence failure is non-fatal — the in-memory list still works for this turn
|
|
54
|
+
}
|
|
55
|
+
const formatted = todoList
|
|
56
|
+
.map((t, i) => {
|
|
57
|
+
const icon = t.status === "completed" ? "[x]" : t.status === "in_progress" ? "[~]" : "[ ]";
|
|
58
|
+
return `${icon} ${i + 1}. ${t.content}`;
|
|
59
|
+
})
|
|
60
|
+
.join("\n");
|
|
61
|
+
return ok(`Todos updated:\n${formatted}`);
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=todo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todo.js","sourceRoot":"","sources":["../../src/tools/todo.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAa,EAAE,EAAE,MAAM,YAAY,CAAC;AAQ3C,IAAI,QAAQ,GAAe,EAAE,CAAC;AAE9B,MAAM,UAAU,QAAQ;IACtB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,SAAS,CAAC,SAAiB;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,SAAiB;IACzC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO;QAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACnD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;YAAE,QAAQ,GAAG,GAAG,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,uBAAuB;IACzB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAgC;IACxD,IAAI,EAAE,WAAW;IACjB,WAAW,EACT,wOAAwO;IAC1O,eAAe,EAAE,KAAK;IACtB,OAAO,EAAE,KAAK;IACd,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE;wBACjF,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,WAAW,CAAC,EAAE;wBACzE,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAE;qBAC5F;oBACD,QAAQ,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;iBAChC;aACF;SACF;QACD,QAAQ,EAAE,CAAC,OAAO,CAAC;KACpB;IACD,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG;QAClB,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC;QACvB,IAAI,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACvF,CAAC;QAAC,MAAM,CAAC;YACP,kFAAkF;QACpF,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ;aACvB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACZ,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YAC3F,OAAO,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1C,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAC;QACd,OAAO,EAAE,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAyDA,MAAM,UAAU,EAAE,CAAC,OAAe,EAAE,OAAgB;IAClD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { convert as htmlToTextConvert } from "html-to-text";
|
|
2
|
+
import { ok, err } from "./types.js";
|
|
3
|
+
const CACHE_TTL_MS = 15 * 60 * 1000;
|
|
4
|
+
const cache = new Map();
|
|
5
|
+
export const webFetchTool = {
|
|
6
|
+
name: "WebFetch",
|
|
7
|
+
description: "Fetch a URL and extract its content as plain text. The `prompt` argument is a question or instruction; the page text is included in the returned content so the calling model can answer it. Responses are cached per-URL for 15 minutes.",
|
|
8
|
+
needsPermission: true,
|
|
9
|
+
mutates: false,
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
url: { type: "string", description: "Fully-qualified URL to fetch" },
|
|
14
|
+
prompt: { type: "string", description: "What you're trying to learn from the page" },
|
|
15
|
+
},
|
|
16
|
+
required: ["url", "prompt"],
|
|
17
|
+
},
|
|
18
|
+
async run(input) {
|
|
19
|
+
let url;
|
|
20
|
+
try {
|
|
21
|
+
url = new URL(input.url);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return err(`Invalid URL: ${input.url}`);
|
|
25
|
+
}
|
|
26
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
27
|
+
return err(`Only http(s) URLs are supported: ${input.url}`);
|
|
28
|
+
}
|
|
29
|
+
const key = url.toString();
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const cached = cache.get(key);
|
|
32
|
+
if (cached && now - cached.fetchedAt < CACHE_TTL_MS) {
|
|
33
|
+
return ok(`URL: ${key}\nPrompt: ${input.prompt}\nCache: hit (age ${Math.round((now - cached.fetchedAt) / 1000)}s)\n\n--- BEGIN CONTENT ---\n${cached.content}\n--- END CONTENT ---`);
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
const res = await fetch(url, {
|
|
37
|
+
redirect: "follow",
|
|
38
|
+
headers: { "User-Agent": "openai-claw/0.1" },
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok)
|
|
41
|
+
return err(`HTTP ${res.status} ${res.statusText} for ${url}`);
|
|
42
|
+
const text = await res.text();
|
|
43
|
+
const stripped = htmlToTextConvert(text, {
|
|
44
|
+
wordwrap: false,
|
|
45
|
+
selectors: [
|
|
46
|
+
{ selector: "script", format: "skip" },
|
|
47
|
+
{ selector: "style", format: "skip" },
|
|
48
|
+
{ selector: "noscript", format: "skip" },
|
|
49
|
+
{ selector: "a", options: { ignoreHref: true } },
|
|
50
|
+
{ selector: "img", format: "skip" },
|
|
51
|
+
],
|
|
52
|
+
}).slice(0, 100_000);
|
|
53
|
+
cache.set(key, { content: stripped, fetchedAt: now });
|
|
54
|
+
return ok(`URL: ${key}\nPrompt: ${input.prompt}\nCache: miss\n\n--- BEGIN CONTENT ---\n${stripped}\n--- END CONTENT ---`);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
return err(`Fetch failed: ${e?.message ?? String(e)}`);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
preview: (input) => `WebFetch ${input.url}`,
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=webfetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webfetch.js","sourceRoot":"","sources":["../../src/tools/webfetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ok, err } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* WebSearch uses DuckDuckGo's HTML endpoint as a zero-key provider.
|
|
4
|
+
* Configure OPENAI_CLAW_SEARCH_PROVIDER=tavily and TAVILY_API_KEY to use Tavily instead.
|
|
5
|
+
*/
|
|
6
|
+
export const webSearchTool = {
|
|
7
|
+
name: "WebSearch",
|
|
8
|
+
description: "Search the web for a query. Returns a list of result titles, URLs, and snippets. Useful for current events or recent docs the model wouldn't know.",
|
|
9
|
+
needsPermission: true,
|
|
10
|
+
mutates: false,
|
|
11
|
+
parameters: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
query: { type: "string", description: "Search query" },
|
|
15
|
+
max_results: { type: "number", description: "Max results to return (default 10)" },
|
|
16
|
+
},
|
|
17
|
+
required: ["query"],
|
|
18
|
+
},
|
|
19
|
+
async run(input) {
|
|
20
|
+
const max = input.max_results ?? 10;
|
|
21
|
+
const provider = process.env.OPENAI_CLAW_SEARCH_PROVIDER ?? "duckduckgo";
|
|
22
|
+
try {
|
|
23
|
+
if (provider === "tavily")
|
|
24
|
+
return ok(await tavilySearch(input.query, max));
|
|
25
|
+
return ok(await duckSearch(input.query, max));
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
return err(`Web search failed: ${e?.message ?? String(e)}`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
preview: (input) => `WebSearch "${input.query}"`,
|
|
32
|
+
};
|
|
33
|
+
async function tavilySearch(query, max) {
|
|
34
|
+
const key = process.env.TAVILY_API_KEY;
|
|
35
|
+
if (!key)
|
|
36
|
+
throw new Error("TAVILY_API_KEY not set");
|
|
37
|
+
const res = await fetch("https://api.tavily.com/search", {
|
|
38
|
+
method: "POST",
|
|
39
|
+
headers: { "Content-Type": "application/json" },
|
|
40
|
+
body: JSON.stringify({ api_key: key, query, max_results: max }),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok)
|
|
43
|
+
throw new Error(`Tavily HTTP ${res.status}`);
|
|
44
|
+
const data = await res.json();
|
|
45
|
+
return (data.results ?? [])
|
|
46
|
+
.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}\n ${r.content}`)
|
|
47
|
+
.join("\n\n");
|
|
48
|
+
}
|
|
49
|
+
async function duckSearch(query, max) {
|
|
50
|
+
const res = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`, { headers: { "User-Agent": "Mozilla/5.0 openai-claw/0.1" } });
|
|
51
|
+
if (!res.ok)
|
|
52
|
+
throw new Error(`DDG HTTP ${res.status}`);
|
|
53
|
+
const html = await res.text();
|
|
54
|
+
const results = [];
|
|
55
|
+
const linkRe = /<a [^>]*class="result__a"[^>]*href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/g;
|
|
56
|
+
const snippetRe = /<a [^>]*class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
57
|
+
const links = [];
|
|
58
|
+
let m;
|
|
59
|
+
while ((m = linkRe.exec(html))) {
|
|
60
|
+
const url = decodeURIComponent(m[1].replace(/^\/\/duckduckgo\.com\/l\/\?uddg=/, "").replace(/&.*$/, ""));
|
|
61
|
+
links.push({ title: strip(m[2]), url });
|
|
62
|
+
}
|
|
63
|
+
const snippets = [];
|
|
64
|
+
while ((m = snippetRe.exec(html)))
|
|
65
|
+
snippets.push(strip(m[1]));
|
|
66
|
+
for (let i = 0; i < Math.min(links.length, max); i++) {
|
|
67
|
+
results.push({ ...links[i], snippet: snippets[i] ?? "" });
|
|
68
|
+
}
|
|
69
|
+
return results.map((r, i) => `${i + 1}. ${r.title}\n ${r.url}\n ${r.snippet}`).join("\n\n");
|
|
70
|
+
}
|
|
71
|
+
function strip(s) {
|
|
72
|
+
return s
|
|
73
|
+
.replace(/<[^>]+>/g, "")
|
|
74
|
+
.replace(/ /g, " ")
|
|
75
|
+
.replace(/&/g, "&")
|
|
76
|
+
.replace(/</g, "<")
|
|
77
|
+
.replace(/>/g, ">")
|
|
78
|
+
.replace(/"/g, '"')
|
|
79
|
+
.replace(/'/g, "'")
|
|
80
|
+
.trim();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=websearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"websearch.js","sourceRoot":"","sources":["../../src/tools/websearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createPatch } from "diff";
|
|
4
|
+
import { err } from "./types.js";
|
|
5
|
+
export const writeTool = {
|
|
6
|
+
name: "Write",
|
|
7
|
+
description: "Write contents to a file. Creates the file if missing, overwrites if it exists. Use absolute paths. For modifying existing files, prefer the Edit tool instead — it only sends the diff.",
|
|
8
|
+
needsPermission: true,
|
|
9
|
+
mutates: true,
|
|
10
|
+
parameters: {
|
|
11
|
+
type: "object",
|
|
12
|
+
properties: {
|
|
13
|
+
file_path: { type: "string", description: "Absolute path to the file" },
|
|
14
|
+
content: { type: "string", description: "Full contents to write" },
|
|
15
|
+
},
|
|
16
|
+
required: ["file_path", "content"],
|
|
17
|
+
},
|
|
18
|
+
async run(input) {
|
|
19
|
+
const fp = path.resolve(input.file_path);
|
|
20
|
+
const dir = path.dirname(fp);
|
|
21
|
+
if (!fs.existsSync(dir))
|
|
22
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
23
|
+
try {
|
|
24
|
+
const existed = fs.existsSync(fp);
|
|
25
|
+
const before = existed ? fs.readFileSync(fp, "utf8") : "";
|
|
26
|
+
fs.writeFileSync(fp, input.content, "utf8");
|
|
27
|
+
const summary = existed
|
|
28
|
+
? `Overwrote ${fp} (${input.content.length} bytes)`
|
|
29
|
+
: `Created ${fp} (${input.content.length} bytes)`;
|
|
30
|
+
const patch = createPatch(path.relative(process.cwd(), fp), before, input.content, "", "");
|
|
31
|
+
return { content: summary, display: patch };
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return err(`Failed to write ${fp}: ${e?.message ?? String(e)}`);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
preview: (input) => `Write ${input.file_path} (${input.content.length} bytes)`,
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAiB,GAAG,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAiD;IACrE,IAAI,EAAE,OAAO;IACb,WAAW,EACT,0LAA0L;IAC5L,eAAe,EAAE,IAAI;IACrB,OAAO,EAAE,IAAI;IACb,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;YACvE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,wBAAwB,EAAE;SACnE;QACD,QAAQ,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;KACnC;IACD,KAAK,CAAC,GAAG,CAAC,KAAK;QACb,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;YAClC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC5C,MAAM,OAAO,GAAG,OAAO;gBACrB,CAAC,CAAC,aAAa,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,SAAS;gBACnD,CAAC,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,SAAS,CAAC;YACpD,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YAC3F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC9C,CAAC;QAAC,OAAO,CAAM,EAAE,CAAC;YAChB,OAAO,GAAG,CAAC,mBAAmB,EAAE,KAAK,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,KAAK,CAAC,SAAS,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,SAAS;CAC/E,CAAC"}
|