@ottocode/openclaw-setu 0.1.2 → 0.1.4
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/chunk-5kkvddc1.js +4 -0
- package/dist/chunk-8pp4as02.js +2 -0
- package/dist/chunk-by6w3tsf.js +3 -0
- package/dist/chunk-e5qz2vx5.js +2 -0
- package/dist/chunk-esz88g73.js +3 -0
- package/dist/chunk-fc5rfx0b.js +3 -0
- package/dist/chunk-g3ma3sec.js +2 -0
- package/dist/chunk-gtxg1zc6.js +2 -0
- package/dist/chunk-h29x1xqe.js +108 -0
- package/dist/chunk-jrrt57tv.js +42 -0
- package/dist/chunk-kn2k3qtn.js +3 -0
- package/dist/chunk-m44tyrbv.js +2 -0
- package/dist/chunk-mbth668g.js +2 -0
- package/dist/chunk-rcdyanw7.js +2 -0
- package/dist/chunk-zy3raqnk.js +3 -0
- package/dist/cli.js +47 -0
- package/dist/index.js +4 -0
- package/package.json +10 -9
- package/src/cli.ts +0 -272
- package/src/config.ts +0 -270
- package/src/index.ts +0 -197
- package/src/proxy.ts +0 -149
- package/src/types.ts +0 -154
- package/src/wallet.ts +0 -79
package/src/index.ts
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
OpenClawPluginDefinition,
|
|
3
|
-
OpenClawPluginApi,
|
|
4
|
-
OpenClawPluginCommandDefinition,
|
|
5
|
-
} from "./types.ts";
|
|
6
|
-
import {
|
|
7
|
-
loadWallet,
|
|
8
|
-
ensureWallet,
|
|
9
|
-
getSetuBalance,
|
|
10
|
-
getWalletKeyPath,
|
|
11
|
-
} from "./wallet.ts";
|
|
12
|
-
import {
|
|
13
|
-
buildProviderConfig,
|
|
14
|
-
injectConfig,
|
|
15
|
-
isConfigured,
|
|
16
|
-
} from "./config.ts";
|
|
17
|
-
import { isValidPrivateKey } from "@ottocode/ai-sdk";
|
|
18
|
-
|
|
19
|
-
const DEFAULT_PORT = 8403;
|
|
20
|
-
|
|
21
|
-
function getPort(api: OpenClawPluginApi): number {
|
|
22
|
-
const cfg = api.pluginConfig as Record<string, unknown> | undefined;
|
|
23
|
-
return (cfg?.port as number) ?? DEFAULT_PORT;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const plugin: OpenClawPluginDefinition = {
|
|
27
|
-
id: "setu",
|
|
28
|
-
name: "Setu",
|
|
29
|
-
description: "Pay for AI with Solana USDC — no API keys, just a wallet.",
|
|
30
|
-
version: "0.1.0",
|
|
31
|
-
|
|
32
|
-
async register(api: OpenClawPluginApi) {
|
|
33
|
-
const port = getPort(api);
|
|
34
|
-
|
|
35
|
-
api.registerProvider({
|
|
36
|
-
id: "setu",
|
|
37
|
-
label: "Setu (Solana USDC)",
|
|
38
|
-
aliases: ["setu-solana"],
|
|
39
|
-
envVars: ["SETU_PRIVATE_KEY"],
|
|
40
|
-
models: buildProviderConfig(port),
|
|
41
|
-
auth: [
|
|
42
|
-
{
|
|
43
|
-
id: "setu-wallet",
|
|
44
|
-
label: "Solana Wallet",
|
|
45
|
-
hint: "Generate or import a Solana wallet — pay per token with USDC",
|
|
46
|
-
kind: "custom",
|
|
47
|
-
async run(ctx) {
|
|
48
|
-
const existing = loadWallet();
|
|
49
|
-
|
|
50
|
-
if (existing) {
|
|
51
|
-
ctx.prompter.note(
|
|
52
|
-
`Existing Setu wallet found: ${existing.publicKey}`,
|
|
53
|
-
);
|
|
54
|
-
return {
|
|
55
|
-
profiles: [
|
|
56
|
-
{
|
|
57
|
-
profileId: "setu-wallet",
|
|
58
|
-
credential: {
|
|
59
|
-
apiKey: "setu-proxy-handles-auth",
|
|
60
|
-
type: "wallet",
|
|
61
|
-
walletAddress: existing.publicKey,
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
],
|
|
65
|
-
configPatch: {
|
|
66
|
-
models: { providers: { setu: buildProviderConfig(port) } },
|
|
67
|
-
},
|
|
68
|
-
defaultModel: `setu/claude-sonnet-4-6`,
|
|
69
|
-
notes: [
|
|
70
|
-
`Wallet: ${existing.publicKey}`,
|
|
71
|
-
`Fund with USDC on Solana to start using.`,
|
|
72
|
-
`Run \`openclaw-setu start\` to start the proxy.`,
|
|
73
|
-
],
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const keyInput = await ctx.prompter.text({
|
|
78
|
-
message:
|
|
79
|
-
"Enter Solana private key (base58) or press Enter to generate a new one:",
|
|
80
|
-
validate: (value: string) => {
|
|
81
|
-
if (value && !isValidPrivateKey(value)) {
|
|
82
|
-
return "Invalid Solana private key";
|
|
83
|
-
}
|
|
84
|
-
return undefined;
|
|
85
|
-
},
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const key = typeof keyInput === "string" ? keyInput : "";
|
|
89
|
-
const wallet = key ? ensureWallet() : ensureWallet();
|
|
90
|
-
if (key && isValidPrivateKey(key)) {
|
|
91
|
-
const { saveWallet } = await import("./wallet.ts");
|
|
92
|
-
saveWallet(key);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const finalWallet = loadWallet()!;
|
|
96
|
-
|
|
97
|
-
await injectConfig(port);
|
|
98
|
-
|
|
99
|
-
return {
|
|
100
|
-
profiles: [
|
|
101
|
-
{
|
|
102
|
-
profileId: "setu-wallet",
|
|
103
|
-
credential: {
|
|
104
|
-
apiKey: "setu-proxy-handles-auth",
|
|
105
|
-
type: "wallet",
|
|
106
|
-
walletAddress: finalWallet.publicKey,
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
],
|
|
110
|
-
configPatch: {
|
|
111
|
-
models: { providers: { setu: buildProviderConfig(port) } },
|
|
112
|
-
},
|
|
113
|
-
defaultModel: `setu/claude-sonnet-4-6`,
|
|
114
|
-
notes: [
|
|
115
|
-
`Wallet generated: ${finalWallet.publicKey}`,
|
|
116
|
-
`Key stored at: ${getWalletKeyPath()}`,
|
|
117
|
-
`Fund with USDC on Solana: ${finalWallet.publicKey}`,
|
|
118
|
-
`Run \`openclaw-setu start\` to start the proxy.`,
|
|
119
|
-
],
|
|
120
|
-
};
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
const walletCmd: OpenClawPluginCommandDefinition = {
|
|
127
|
-
name: "wallet",
|
|
128
|
-
description: "Show your Setu wallet address and balances",
|
|
129
|
-
requireAuth: true,
|
|
130
|
-
async handler() {
|
|
131
|
-
const wallet = loadWallet();
|
|
132
|
-
if (!wallet) {
|
|
133
|
-
return { text: "No Setu wallet found. Run `openclaw-setu setup`." };
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const balances = await getSetuBalance(wallet.privateKey);
|
|
137
|
-
const lines = [`Wallet: ${wallet.publicKey}`];
|
|
138
|
-
|
|
139
|
-
if (balances.setu) {
|
|
140
|
-
lines.push(`Setu Balance: $${balances.setu.balance.toFixed(4)}`);
|
|
141
|
-
lines.push(`Total Spent: $${balances.setu.totalSpent.toFixed(4)}`);
|
|
142
|
-
lines.push(`Requests: ${balances.setu.requestCount}`);
|
|
143
|
-
}
|
|
144
|
-
if (balances.wallet) {
|
|
145
|
-
lines.push(
|
|
146
|
-
`On-chain USDC: $${balances.wallet.usdcBalance.toFixed(4)} (${balances.wallet.network})`,
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return { text: lines.join("\n") };
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
api.registerCommand(walletCmd);
|
|
155
|
-
|
|
156
|
-
const statusCmd: OpenClawPluginCommandDefinition = {
|
|
157
|
-
name: "setu-status",
|
|
158
|
-
description: "Check Setu plugin configuration status",
|
|
159
|
-
async handler() {
|
|
160
|
-
const wallet = loadWallet();
|
|
161
|
-
const configured = isConfigured();
|
|
162
|
-
const lines = [
|
|
163
|
-
`Wallet: ${wallet ? wallet.publicKey : "not set up"}`,
|
|
164
|
-
`OpenClaw config: ${configured ? "injected" : "not configured"}`,
|
|
165
|
-
`Proxy port: ${port}`,
|
|
166
|
-
];
|
|
167
|
-
return { text: lines.join("\n") };
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
api.registerCommand(statusCmd);
|
|
172
|
-
|
|
173
|
-
api.registerService({
|
|
174
|
-
id: "setu-proxy",
|
|
175
|
-
async start() {
|
|
176
|
-
const wallet = loadWallet();
|
|
177
|
-
if (!wallet) {
|
|
178
|
-
api.logger.warn(
|
|
179
|
-
"Setu: No wallet found. Run `openclaw-setu setup` first.",
|
|
180
|
-
);
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
try {
|
|
184
|
-
const { createProxy } = await import("./proxy.ts");
|
|
185
|
-
createProxy({ port, verbose: false });
|
|
186
|
-
api.logger.info(
|
|
187
|
-
`Setu proxy running on http://localhost:${port}`,
|
|
188
|
-
);
|
|
189
|
-
} catch (err) {
|
|
190
|
-
api.logger.error(`Setu proxy failed: ${(err as Error).message}`);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
},
|
|
195
|
-
};
|
|
196
|
-
|
|
197
|
-
export default plugin;
|
package/src/proxy.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { createSetuFetch, createWalletContext } from "@ottocode/ai-sdk";
|
|
2
|
-
import { loadWallet } from "./wallet.ts";
|
|
3
|
-
|
|
4
|
-
const DEFAULT_PORT = 8403;
|
|
5
|
-
const DEFAULT_BASE_URL = "https://api.setu.ottocode.io";
|
|
6
|
-
|
|
7
|
-
export interface ProxyOptions {
|
|
8
|
-
port?: number;
|
|
9
|
-
baseURL?: string;
|
|
10
|
-
verbose?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function createProxy(options: ProxyOptions = {}) {
|
|
14
|
-
const port = options.port ?? DEFAULT_PORT;
|
|
15
|
-
const baseURL = options.baseURL ?? DEFAULT_BASE_URL;
|
|
16
|
-
const verbose = options.verbose ?? false;
|
|
17
|
-
|
|
18
|
-
const wallet = loadWallet();
|
|
19
|
-
if (!wallet) {
|
|
20
|
-
throw new Error(
|
|
21
|
-
"No wallet found. Run `openclaw-setu setup` or `openclaw-setu wallet generate` first.",
|
|
22
|
-
);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const log = verbose
|
|
26
|
-
? (msg: string) => console.log(`[setu-proxy] ${msg}`)
|
|
27
|
-
: (_msg: string) => {};
|
|
28
|
-
|
|
29
|
-
const walletCtx = createWalletContext({ privateKey: wallet.privateKey });
|
|
30
|
-
|
|
31
|
-
const setuFetch = createSetuFetch({
|
|
32
|
-
wallet: walletCtx,
|
|
33
|
-
baseURL,
|
|
34
|
-
callbacks: {
|
|
35
|
-
onPaymentRequired: (amountUsd) => {
|
|
36
|
-
log(`Payment required: $${amountUsd.toFixed(4)}`);
|
|
37
|
-
},
|
|
38
|
-
onPaymentComplete: (data) => {
|
|
39
|
-
log(
|
|
40
|
-
`Payment complete: $${data.amountUsd.toFixed(4)} | balance: $${data.newBalance.toFixed(4)}`,
|
|
41
|
-
);
|
|
42
|
-
},
|
|
43
|
-
onPaymentError: (error) => {
|
|
44
|
-
console.error(`[setu-proxy] Payment error: ${error}`);
|
|
45
|
-
},
|
|
46
|
-
onBalanceUpdate: (update) => {
|
|
47
|
-
log(
|
|
48
|
-
`Cost: $${update.costUsd.toFixed(4)} | remaining: $${update.balanceRemaining.toFixed(4)}`,
|
|
49
|
-
);
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const proxyBaseURL = baseURL;
|
|
55
|
-
|
|
56
|
-
const server = Bun.serve({
|
|
57
|
-
port,
|
|
58
|
-
async fetch(req: Request): Promise<Response> {
|
|
59
|
-
const url = new URL(req.url);
|
|
60
|
-
|
|
61
|
-
if (url.pathname === "/health") {
|
|
62
|
-
return Response.json({
|
|
63
|
-
status: "ok",
|
|
64
|
-
wallet: wallet.publicKey,
|
|
65
|
-
provider: "setu",
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (url.pathname === "/v1/models") {
|
|
70
|
-
log("GET /v1/models");
|
|
71
|
-
const resp = await setuFetch(`${proxyBaseURL}/v1/models`, {
|
|
72
|
-
method: "GET",
|
|
73
|
-
headers: { "Content-Type": "application/json" },
|
|
74
|
-
});
|
|
75
|
-
return new Response(resp.body, {
|
|
76
|
-
status: resp.status,
|
|
77
|
-
headers: {
|
|
78
|
-
"Content-Type":
|
|
79
|
-
resp.headers.get("Content-Type") ?? "application/json",
|
|
80
|
-
"Access-Control-Allow-Origin": "*",
|
|
81
|
-
},
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const isCompletions = url.pathname === "/v1/chat/completions";
|
|
86
|
-
const isResponses = url.pathname === "/v1/responses";
|
|
87
|
-
if (!isCompletions && !isResponses) {
|
|
88
|
-
const targetURL = `${proxyBaseURL}${url.pathname}`;
|
|
89
|
-
log(`Proxying ${req.method} ${url.pathname}`);
|
|
90
|
-
const resp = await setuFetch(targetURL, {
|
|
91
|
-
method: req.method,
|
|
92
|
-
headers: { "Content-Type": "application/json" },
|
|
93
|
-
body: req.method !== "GET" ? await req.text() : undefined,
|
|
94
|
-
});
|
|
95
|
-
return new Response(resp.body, {
|
|
96
|
-
status: resp.status,
|
|
97
|
-
headers: {
|
|
98
|
-
"Content-Type":
|
|
99
|
-
resp.headers.get("Content-Type") ?? "application/json",
|
|
100
|
-
"Access-Control-Allow-Origin": "*",
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const body = await req.text();
|
|
106
|
-
let parsed: Record<string, unknown> = {};
|
|
107
|
-
try {
|
|
108
|
-
parsed = JSON.parse(body);
|
|
109
|
-
} catch {
|
|
110
|
-
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const model = parsed.model as string;
|
|
114
|
-
const stream = parsed.stream as boolean;
|
|
115
|
-
log(
|
|
116
|
-
`${isCompletions ? "POST /v1/chat/completions" : "POST /v1/responses"} model=${model} stream=${stream}`,
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const targetURL = `${proxyBaseURL}${url.pathname}`;
|
|
120
|
-
const resp = await setuFetch(targetURL, {
|
|
121
|
-
method: "POST",
|
|
122
|
-
headers: { "Content-Type": "application/json" },
|
|
123
|
-
body,
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
if (stream && resp.body) {
|
|
127
|
-
return new Response(resp.body, {
|
|
128
|
-
status: resp.status,
|
|
129
|
-
headers: {
|
|
130
|
-
"Content-Type": "text/event-stream",
|
|
131
|
-
"Cache-Control": "no-cache",
|
|
132
|
-
Connection: "keep-alive",
|
|
133
|
-
"Access-Control-Allow-Origin": "*",
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return new Response(resp.body, {
|
|
139
|
-
status: resp.status,
|
|
140
|
-
headers: {
|
|
141
|
-
"Content-Type": "application/json",
|
|
142
|
-
"Access-Control-Allow-Origin": "*",
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
return { server, port, wallet };
|
|
149
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
export type ModelApi =
|
|
2
|
-
| "openai-completions"
|
|
3
|
-
| "openai-responses"
|
|
4
|
-
| "anthropic-messages"
|
|
5
|
-
| "google-generative-ai"
|
|
6
|
-
| "github-copilot"
|
|
7
|
-
| "bedrock-converse-stream";
|
|
8
|
-
|
|
9
|
-
export type ModelDefinitionConfig = {
|
|
10
|
-
id: string;
|
|
11
|
-
name: string;
|
|
12
|
-
api?: ModelApi;
|
|
13
|
-
reasoning?: boolean;
|
|
14
|
-
input?: Array<"text" | "image">;
|
|
15
|
-
cost?: {
|
|
16
|
-
input: number;
|
|
17
|
-
output: number;
|
|
18
|
-
cacheRead?: number;
|
|
19
|
-
cacheWrite?: number;
|
|
20
|
-
};
|
|
21
|
-
contextWindow?: number;
|
|
22
|
-
maxTokens?: number;
|
|
23
|
-
headers?: Record<string, string>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type ModelProviderConfig = {
|
|
27
|
-
baseUrl: string;
|
|
28
|
-
apiKey?: string;
|
|
29
|
-
api?: ModelApi;
|
|
30
|
-
headers?: Record<string, string>;
|
|
31
|
-
authHeader?: boolean;
|
|
32
|
-
models: ModelDefinitionConfig[];
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export type AuthProfileCredential = {
|
|
36
|
-
apiKey?: string;
|
|
37
|
-
type?: string;
|
|
38
|
-
[key: string]: unknown;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type ProviderAuthResult = {
|
|
42
|
-
profiles: Array<{ profileId: string; credential: AuthProfileCredential }>;
|
|
43
|
-
configPatch?: Record<string, unknown>;
|
|
44
|
-
defaultModel?: string;
|
|
45
|
-
notes?: string[];
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export type WizardPrompter = {
|
|
49
|
-
text: (opts: {
|
|
50
|
-
message: string;
|
|
51
|
-
validate?: (value: string) => string | undefined;
|
|
52
|
-
}) => Promise<string | symbol>;
|
|
53
|
-
note: (message: string) => void;
|
|
54
|
-
progress: (message: string) => { stop: (message?: string) => void };
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
export type ProviderAuthContext = {
|
|
58
|
-
config: Record<string, unknown>;
|
|
59
|
-
agentDir?: string;
|
|
60
|
-
workspaceDir?: string;
|
|
61
|
-
prompter: WizardPrompter;
|
|
62
|
-
runtime: { log: (message: string) => void };
|
|
63
|
-
isRemote: boolean;
|
|
64
|
-
openUrl: (url: string) => Promise<void>;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
export type ProviderAuthMethod = {
|
|
68
|
-
id: string;
|
|
69
|
-
label: string;
|
|
70
|
-
hint?: string;
|
|
71
|
-
kind: "oauth" | "api_key" | "token" | "device_code" | "custom";
|
|
72
|
-
run: (ctx: ProviderAuthContext) => Promise<ProviderAuthResult>;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export type ProviderPlugin = {
|
|
76
|
-
id: string;
|
|
77
|
-
label: string;
|
|
78
|
-
docsPath?: string;
|
|
79
|
-
aliases?: string[];
|
|
80
|
-
envVars?: string[];
|
|
81
|
-
models?: ModelProviderConfig;
|
|
82
|
-
auth: ProviderAuthMethod[];
|
|
83
|
-
formatApiKey?: (cred: AuthProfileCredential) => string;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
export type PluginLogger = {
|
|
87
|
-
debug?: (message: string) => void;
|
|
88
|
-
info: (message: string) => void;
|
|
89
|
-
warn: (message: string) => void;
|
|
90
|
-
error: (message: string) => void;
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
export type OpenClawPluginService = {
|
|
94
|
-
id: string;
|
|
95
|
-
start: () => void | Promise<void>;
|
|
96
|
-
stop?: () => void | Promise<void>;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export type OpenClawPluginApi = {
|
|
100
|
-
id: string;
|
|
101
|
-
name: string;
|
|
102
|
-
version?: string;
|
|
103
|
-
description?: string;
|
|
104
|
-
source: string;
|
|
105
|
-
config: Record<string, unknown> & {
|
|
106
|
-
models?: { providers?: Record<string, ModelProviderConfig> };
|
|
107
|
-
agents?: Record<string, unknown>;
|
|
108
|
-
};
|
|
109
|
-
pluginConfig?: Record<string, unknown>;
|
|
110
|
-
logger: PluginLogger;
|
|
111
|
-
registerProvider: (provider: ProviderPlugin) => void;
|
|
112
|
-
registerTool: (tool: unknown, opts?: unknown) => void;
|
|
113
|
-
registerHook: (events: string | string[], handler: unknown, opts?: unknown) => void;
|
|
114
|
-
registerHttpRoute: (params: { path: string; handler: unknown }) => void;
|
|
115
|
-
registerService: (service: OpenClawPluginService) => void;
|
|
116
|
-
registerCommand: (command: unknown) => void;
|
|
117
|
-
resolvePath: (input: string) => string;
|
|
118
|
-
on: (hookName: string, handler: unknown, opts?: unknown) => void;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
export type OpenClawPluginDefinition = {
|
|
122
|
-
id?: string;
|
|
123
|
-
name?: string;
|
|
124
|
-
description?: string;
|
|
125
|
-
version?: string;
|
|
126
|
-
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
127
|
-
activate?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export type PluginCommandContext = {
|
|
131
|
-
senderId?: string;
|
|
132
|
-
channel: string;
|
|
133
|
-
isAuthorizedSender: boolean;
|
|
134
|
-
args?: string;
|
|
135
|
-
commandBody: string;
|
|
136
|
-
config: Record<string, unknown>;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
export type PluginCommandResult = {
|
|
140
|
-
text?: string;
|
|
141
|
-
isError?: boolean;
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
export type PluginCommandHandler = (
|
|
145
|
-
ctx: PluginCommandContext,
|
|
146
|
-
) => PluginCommandResult | Promise<PluginCommandResult>;
|
|
147
|
-
|
|
148
|
-
export type OpenClawPluginCommandDefinition = {
|
|
149
|
-
name: string;
|
|
150
|
-
description: string;
|
|
151
|
-
acceptsArgs?: boolean;
|
|
152
|
-
requireAuth?: boolean;
|
|
153
|
-
handler: PluginCommandHandler;
|
|
154
|
-
};
|
package/src/wallet.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
import {
|
|
5
|
-
generateWallet,
|
|
6
|
-
importWallet,
|
|
7
|
-
isValidPrivateKey,
|
|
8
|
-
fetchBalance,
|
|
9
|
-
fetchWalletUsdcBalance,
|
|
10
|
-
} from "@ottocode/ai-sdk";
|
|
11
|
-
import type { WalletInfo } from "@ottocode/ai-sdk";
|
|
12
|
-
|
|
13
|
-
const WALLET_DIR = join(homedir(), ".openclaw", "setu");
|
|
14
|
-
const WALLET_KEY_PATH = join(WALLET_DIR, "wallet.key");
|
|
15
|
-
|
|
16
|
-
export function getWalletKeyPath(): string {
|
|
17
|
-
return WALLET_KEY_PATH;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function loadWallet(): WalletInfo | null {
|
|
21
|
-
try {
|
|
22
|
-
if (!existsSync(WALLET_KEY_PATH)) return null;
|
|
23
|
-
const privateKey = readFileSync(WALLET_KEY_PATH, "utf-8").trim();
|
|
24
|
-
if (!isValidPrivateKey(privateKey)) return null;
|
|
25
|
-
return importWallet(privateKey);
|
|
26
|
-
} catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function saveWallet(privateKey: string): WalletInfo {
|
|
32
|
-
if (!isValidPrivateKey(privateKey)) {
|
|
33
|
-
throw new Error("Invalid Solana private key");
|
|
34
|
-
}
|
|
35
|
-
const wallet = importWallet(privateKey);
|
|
36
|
-
mkdirSync(WALLET_DIR, { recursive: true });
|
|
37
|
-
writeFileSync(WALLET_KEY_PATH, privateKey, { mode: 0o600 });
|
|
38
|
-
return wallet;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function ensureWallet(): WalletInfo {
|
|
42
|
-
const existing = loadWallet();
|
|
43
|
-
if (existing) return existing;
|
|
44
|
-
const wallet = generateWallet();
|
|
45
|
-
saveWallet(wallet.privateKey);
|
|
46
|
-
return wallet;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function exportWalletKey(): string | null {
|
|
50
|
-
try {
|
|
51
|
-
if (!existsSync(WALLET_KEY_PATH)) return null;
|
|
52
|
-
return readFileSync(WALLET_KEY_PATH, "utf-8").trim();
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export async function getSetuBalance(privateKey: string): Promise<{
|
|
59
|
-
setu: { balance: number; totalSpent: number; requestCount: number } | null;
|
|
60
|
-
wallet: { usdcBalance: number; network: string } | null;
|
|
61
|
-
}> {
|
|
62
|
-
const [setu, wallet] = await Promise.all([
|
|
63
|
-
fetchBalance({ privateKey }),
|
|
64
|
-
fetchWalletUsdcBalance({ privateKey }),
|
|
65
|
-
]);
|
|
66
|
-
|
|
67
|
-
return {
|
|
68
|
-
setu: setu
|
|
69
|
-
? {
|
|
70
|
-
balance: setu.balance,
|
|
71
|
-
totalSpent: setu.totalSpent,
|
|
72
|
-
requestCount: setu.requestCount,
|
|
73
|
-
}
|
|
74
|
-
: null,
|
|
75
|
-
wallet: wallet
|
|
76
|
-
? { usdcBalance: wallet.usdcBalance, network: wallet.network }
|
|
77
|
-
: null,
|
|
78
|
-
};
|
|
79
|
-
}
|