talon-agent 1.3.0 → 1.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/package.json +3 -1
- package/src/__tests__/compose-tools.test.ts +216 -0
- package/src/__tests__/fuzz.test.ts +0 -2
- package/src/__tests__/gateway-actions.test.ts +1 -423
- package/src/backend/claude-sdk/index.ts +39 -54
- package/src/backend/opencode/index.ts +5 -20
- package/src/bootstrap.ts +70 -6
- package/src/core/gateway-actions.ts +0 -87
- package/src/core/tools/bridge.ts +40 -0
- package/src/core/tools/chat.ts +52 -0
- package/src/core/tools/history.ts +80 -0
- package/src/core/tools/index.ts +82 -0
- package/src/core/tools/mcp-server.ts +64 -0
- package/src/core/tools/media.ts +23 -0
- package/src/core/tools/members.ts +46 -0
- package/src/core/tools/messaging.ts +300 -0
- package/src/core/tools/scheduling.ts +89 -0
- package/src/core/tools/stickers.ts +143 -0
- package/src/core/tools/types.ts +60 -0
- package/src/core/tools/web.ts +26 -0
- package/src/frontend/telegram/actions.ts +10 -1
- package/src/plugins/github/index.ts +106 -0
- package/src/plugins/playwright/index.ts +82 -0
- package/src/storage/sessions.ts +0 -10
- package/src/util/config.ts +20 -1
- package/src/util/log.ts +3 -1
- package/src/backend/claude-sdk/tools.ts +0 -651
- package/src/frontend/teams/tools.ts +0 -175
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub plugin — GitHub API access via the official GitHub MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Registers the GitHub MCP server (Docker image: ghcr.io/github/github-mcp-server),
|
|
5
|
+
* giving the agent access to repository management, issues, PRs, code search, etc.
|
|
6
|
+
*
|
|
7
|
+
* Configuration in ~/.talon/config.json:
|
|
8
|
+
* "github": {
|
|
9
|
+
* "enabled": true,
|
|
10
|
+
* "token": "ghp_..." // optional, defaults to `gh auth token` output
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { execFileSync } from "node:child_process";
|
|
15
|
+
import type { TalonPlugin } from "../../core/plugin.js";
|
|
16
|
+
import { log, logWarn } from "../../util/log.js";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolve a GitHub personal access token.
|
|
20
|
+
* Priority: explicit config > `gh auth token` CLI.
|
|
21
|
+
*/
|
|
22
|
+
function resolveToken(configToken?: string): string | undefined {
|
|
23
|
+
const trimmed = configToken?.trim();
|
|
24
|
+
if (trimmed) return trimmed;
|
|
25
|
+
try {
|
|
26
|
+
return execFileSync("gh", ["auth", "token"], {
|
|
27
|
+
timeout: 5_000,
|
|
28
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
29
|
+
})
|
|
30
|
+
.toString("utf-8")
|
|
31
|
+
.trim();
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createGitHubPlugin(config: { token?: string }): TalonPlugin {
|
|
38
|
+
const token = resolveToken(config.token);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
name: "github",
|
|
42
|
+
description: "GitHub API access via the official GitHub MCP server",
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
|
|
45
|
+
mcpServer: {
|
|
46
|
+
command: "docker",
|
|
47
|
+
args: [
|
|
48
|
+
"run",
|
|
49
|
+
"--rm",
|
|
50
|
+
"-i",
|
|
51
|
+
"-e",
|
|
52
|
+
"GITHUB_PERSONAL_ACCESS_TOKEN",
|
|
53
|
+
"ghcr.io/github/github-mcp-server",
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
validateConfig() {
|
|
58
|
+
const errors: string[] = [];
|
|
59
|
+
|
|
60
|
+
if (!token) {
|
|
61
|
+
errors.push(
|
|
62
|
+
'No GitHub token found. Set "token" in github config or run `gh auth login`.',
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Check Docker is available
|
|
67
|
+
try {
|
|
68
|
+
execFileSync("docker", ["info"], {
|
|
69
|
+
timeout: 10_000,
|
|
70
|
+
stdio: "pipe",
|
|
71
|
+
});
|
|
72
|
+
} catch {
|
|
73
|
+
errors.push(
|
|
74
|
+
"Docker is not available or not running. The GitHub MCP server requires Docker.",
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return errors.length > 0 ? errors : undefined;
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
async init() {
|
|
82
|
+
// Verify the Docker image exists locally
|
|
83
|
+
try {
|
|
84
|
+
execFileSync(
|
|
85
|
+
"docker",
|
|
86
|
+
["image", "inspect", "ghcr.io/github/github-mcp-server"],
|
|
87
|
+
{ timeout: 10_000, stdio: "pipe" },
|
|
88
|
+
);
|
|
89
|
+
log("github", "Docker image verified");
|
|
90
|
+
} catch {
|
|
91
|
+
logWarn(
|
|
92
|
+
"github",
|
|
93
|
+
"Docker image not found locally — will pull on first use (may be slow)",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
log("github", "Ready");
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getEnvVars() {
|
|
101
|
+
return {
|
|
102
|
+
...(token ? { GITHUB_PERSONAL_ACCESS_TOKEN: token } : {}),
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright plugin — browser automation via the official Playwright MCP server.
|
|
3
|
+
*
|
|
4
|
+
* Gives the agent headless Chromium for web scraping, screenshots, PDF generation,
|
|
5
|
+
* and general browser automation.
|
|
6
|
+
*
|
|
7
|
+
* Configuration in ~/.talon/config.json:
|
|
8
|
+
* "playwright": {
|
|
9
|
+
* "enabled": true,
|
|
10
|
+
* "browser": "chromium", // optional, default "chromium"
|
|
11
|
+
* "headless": true // optional, default true
|
|
12
|
+
* }
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
|
+
import { resolve } from "node:path";
|
|
17
|
+
import type { TalonPlugin } from "../../core/plugin.js";
|
|
18
|
+
import { log } from "../../util/log.js";
|
|
19
|
+
|
|
20
|
+
export function createPlaywrightPlugin(config: {
|
|
21
|
+
browser?: string;
|
|
22
|
+
headless?: boolean;
|
|
23
|
+
}): TalonPlugin {
|
|
24
|
+
const browser = config.browser ?? "chromium";
|
|
25
|
+
const headless = config.headless !== false; // default true
|
|
26
|
+
|
|
27
|
+
// Resolve path from Talon's node_modules
|
|
28
|
+
const mcpBin = resolve(
|
|
29
|
+
import.meta.dirname ?? ".",
|
|
30
|
+
"../../../node_modules/@playwright/mcp/cli.js",
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const args = ["--no-sandbox"];
|
|
34
|
+
|
|
35
|
+
if (headless) {
|
|
36
|
+
args.push("--headless");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (browser !== "chromium") {
|
|
40
|
+
args.push("--browser", browser);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
name: "playwright",
|
|
45
|
+
description: "Browser automation via Playwright MCP (headless Chromium)",
|
|
46
|
+
version: "1.0.0",
|
|
47
|
+
|
|
48
|
+
mcpServer: {
|
|
49
|
+
command: "node",
|
|
50
|
+
args: [mcpBin, ...args],
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
validateConfig() {
|
|
54
|
+
const errors: string[] = [];
|
|
55
|
+
|
|
56
|
+
const validBrowsers = [
|
|
57
|
+
"chromium",
|
|
58
|
+
"chrome",
|
|
59
|
+
"firefox",
|
|
60
|
+
"webkit",
|
|
61
|
+
"msedge",
|
|
62
|
+
];
|
|
63
|
+
if (!validBrowsers.includes(browser)) {
|
|
64
|
+
errors.push(
|
|
65
|
+
`Invalid browser "${browser}". Valid options: ${validBrowsers.join(", ")}`,
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!existsSync(mcpBin)) {
|
|
70
|
+
errors.push(
|
|
71
|
+
`@playwright/mcp not found at ${mcpBin} — run "npm install @playwright/mcp"`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return errors.length > 0 ? errors : undefined;
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
async init() {
|
|
79
|
+
log("playwright", `Ready (${browser}, headless=${headless})`);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
package/src/storage/sessions.ts
CHANGED
|
@@ -82,16 +82,6 @@ export function loadSessions(): void {
|
|
|
82
82
|
);
|
|
83
83
|
store = {};
|
|
84
84
|
}
|
|
85
|
-
// SDK sessions don't survive process restarts — the embedded Claude Code
|
|
86
|
-
// subprocess is gone. Clear stale session IDs so we don't try to resume
|
|
87
|
-
// a dead session (which causes the SDK to hang silently on Windows).
|
|
88
|
-
// Keep turns/usage intact — they're historical data used by /resume.
|
|
89
|
-
for (const session of Object.values(store)) {
|
|
90
|
-
if (session.sessionId) {
|
|
91
|
-
session.sessionId = undefined;
|
|
92
|
-
dirty = true;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
85
|
}
|
|
96
86
|
|
|
97
87
|
function saveSessions(): void {
|
package/src/util/config.ts
CHANGED
|
@@ -40,10 +40,18 @@ const configSchema = z.object({
|
|
|
40
40
|
heartbeatIntervalMinutes: z.number().int().min(5).default(60),
|
|
41
41
|
heartbeatModel: z.string().optional(), // Model for heartbeat agent (defaults to main model)
|
|
42
42
|
braveApiKey: z.string().optional(),
|
|
43
|
-
searxngUrl: z.string().default("http://localhost:8080"),
|
|
44
43
|
timezone: z.string().optional(),
|
|
45
44
|
plugins: z.array(pluginEntrySchema).default([]),
|
|
46
45
|
|
|
46
|
+
// GitHub — GitHub API access via official MCP server
|
|
47
|
+
github: z
|
|
48
|
+
.object({
|
|
49
|
+
enabled: z.boolean().default(false),
|
|
50
|
+
/** GitHub personal access token (default: from `gh auth token`) */
|
|
51
|
+
token: z.string().min(1).optional(),
|
|
52
|
+
})
|
|
53
|
+
.optional(),
|
|
54
|
+
|
|
47
55
|
// MemPalace — structured long-term memory with vector search
|
|
48
56
|
mempalace: z
|
|
49
57
|
.object({
|
|
@@ -55,6 +63,17 @@ const configSchema = z.object({
|
|
|
55
63
|
})
|
|
56
64
|
.optional(),
|
|
57
65
|
|
|
66
|
+
// Playwright — headless browser automation via MCP
|
|
67
|
+
playwright: z
|
|
68
|
+
.object({
|
|
69
|
+
enabled: z.boolean().default(false),
|
|
70
|
+
/** Browser engine: chromium (default), chrome, firefox, webkit, msedge */
|
|
71
|
+
browser: z.string().optional(),
|
|
72
|
+
/** Run headless (default: true) */
|
|
73
|
+
headless: z.boolean().default(true),
|
|
74
|
+
})
|
|
75
|
+
.optional(),
|
|
76
|
+
|
|
58
77
|
// Display name shown in terminal UI (defaults to "Talon")
|
|
59
78
|
botDisplayName: z.string().default("Talon"),
|
|
60
79
|
|