




















@@ -1,117 +1,4 @@
1-import { spawn } from "node:child_process";
2-import { existsSync } from "node:fs";
3-import { dirname, join } from "node:path";
4-import { fileURLToPath } from "node:url";
51import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
6-import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
7-8-const __dirname = dirname(fileURLToPath(import.meta.url));
9-10-const ALLOWED_TLON_COMMANDS = new Set([
11-"activity",
12-"channels",
13-"contacts",
14-"groups",
15-"messages",
16-"dms",
17-"posts",
18-"notebook",
19-"settings",
20-"help",
21-"version",
22-]);
23-24-let cachedTlonBinary: string | undefined;
25-26-function findTlonBinary(): string {
27-if (cachedTlonBinary) {
28-return cachedTlonBinary;
29-}
30-const skillBin = join(__dirname, "node_modules", ".bin", "tlon");
31-if (existsSync(skillBin)) {
32-cachedTlonBinary = skillBin;
33-return skillBin;
34-}
35-36-const platformPkg = `@tloncorp/tlon-skill-${process.platform}-${process.arch}`;
37-const platformBin = join(__dirname, "node_modules", platformPkg, "tlon");
38-if (existsSync(platformBin)) {
39-cachedTlonBinary = platformBin;
40-return platformBin;
41-}
42-43-cachedTlonBinary = "tlon";
44-return cachedTlonBinary;
45-}
46-47-function shellSplit(str: string): string[] {
48-const args: string[] = [];
49-let cur = "";
50-let inDouble = false;
51-let inSingle = false;
52-let escape = false;
53-54-for (const ch of str) {
55-if (escape) {
56-cur += ch;
57-escape = false;
58-continue;
59-}
60-if (ch === "\\" && !inSingle) {
61-escape = true;
62-continue;
63-}
64-if (ch === '"' && !inSingle) {
65-inDouble = !inDouble;
66-continue;
67-}
68-if (ch === "'" && !inDouble) {
69-inSingle = !inSingle;
70-continue;
71-}
72-if (/\s/.test(ch) && !inDouble && !inSingle) {
73-if (cur) {
74-args.push(cur);
75-cur = "";
76-}
77-continue;
78-}
79-cur += ch;
80-}
81-if (cur) {
82-args.push(cur);
83-}
84-return args;
85-}
86-87-function runTlonCommand(binary: string, args: string[]): Promise<string> {
88-return new Promise((resolve, reject) => {
89-const child = spawn(binary, args, { env: process.env });
90-91-let stdout = "";
92-let stderr = "";
93-94-child.stdout.on("data", (data) => {
95-stdout += data.toString();
96-});
97-98-child.stderr.on("data", (data) => {
99-stderr += data.toString();
100-});
101-102-child.on("error", (err) => {
103-reject(new Error(`Failed to run tlon: ${err.message}`));
104-});
105-106-child.on("close", (code) => {
107-if (code !== 0) {
108-reject(new Error(stderr || `tlon exited with code ${code}`));
109-return;
110-}
111-resolve(stdout);
112-});
113-});
114-}
11521163export default defineBundledChannelEntry({
1174id: "tlon",
@@ -126,58 +13,4 @@ export default defineBundledChannelEntry({
12613specifier: "./api.js",
12714exportName: "setTlonRuntime",
12815},
129-registerFull(api) {
130-api.registerTool({
131-name: "tlon",
132-label: "Tlon CLI",
133-description:
134-"Tlon/Urbit API operations: activity, channels, contacts, groups, messages, dms, posts, notebook, settings. " +
135-"Examples: 'activity mentions --limit 10', 'channels groups', 'contacts self', 'groups list'",
136-parameters: {
137-type: "object",
138-properties: {
139-command: {
140-type: "string",
141-description:
142-"The tlon command and arguments. " +
143-"Examples: 'activity mentions --limit 10', 'contacts get ~sampel-palnet', 'groups list'",
144-},
145-},
146-required: ["command"],
147-},
148-async execute(_id: string, params: { command: string }) {
149-try {
150-const args = shellSplit(params.command);
151-const subcommand = args[0];
152-if (!ALLOWED_TLON_COMMANDS.has(subcommand)) {
153-return {
154-content: [
155-{
156-type: "text" as const,
157-text: `Error: Unknown tlon subcommand '${subcommand}'. Allowed: ${[...ALLOWED_TLON_COMMANDS].join(", ")}`,
158-},
159-],
160-details: { error: true },
161-};
162-}
163-164-const output = await runTlonCommand(findTlonBinary(), args);
165-return {
166-content: [{ type: "text" as const, text: output }],
167-details: undefined,
168-};
169-} catch (error: unknown) {
170-return {
171-content: [
172-{
173-type: "text" as const,
174-text: `Error: ${formatErrorMessage(error)}`,
175-},
176-],
177-details: { error: true },
178-};
179-}
180-},
181-});
182-},
18316});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。