@keeperhub/wallet 0.1.7 → 0.1.9
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/README.md +9 -0
- package/dist/cli.cjs +69 -13
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +69 -13
- package/dist/cli.js.map +1 -1
- package/dist/hook-entrypoint.cjs +23 -0
- package/dist/hook-entrypoint.cjs.map +1 -1
- package/dist/hook-entrypoint.js +23 -0
- package/dist/hook-entrypoint.js.map +1 -1
- package/dist/index.cjs +127 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -22
- package/dist/index.d.ts +75 -22
- package/dist/index.js +125 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -43,8 +43,10 @@ __export(index_exports, {
|
|
|
43
43
|
paymentSigner: () => paymentSigner,
|
|
44
44
|
readWalletConfig: () => readWalletConfig,
|
|
45
45
|
registerClaudeCodeHook: () => registerClaudeCodeHook,
|
|
46
|
+
resolveHookCommand: () => resolveHookCommand,
|
|
46
47
|
runCli: () => runCli,
|
|
47
48
|
runHookCli: () => runHookCli,
|
|
49
|
+
selectProtocol: () => selectProtocol,
|
|
48
50
|
tempo: () => tempo,
|
|
49
51
|
validateAndMerge: () => validateAndMerge,
|
|
50
52
|
writeWalletConfig: () => writeWalletConfig
|
|
@@ -195,15 +197,69 @@ function fund(walletAddress) {
|
|
|
195
197
|
}
|
|
196
198
|
|
|
197
199
|
// src/skill-install.ts
|
|
200
|
+
var import_node_child_process = require("child_process");
|
|
198
201
|
var import_promises = require("fs/promises");
|
|
202
|
+
var import_node_fs2 = require("fs");
|
|
199
203
|
var import_node_path2 = require("path");
|
|
200
204
|
var import_node_url = require("url");
|
|
201
|
-
var
|
|
202
|
-
var
|
|
203
|
-
|
|
205
|
+
var HOOK_BIN = "keeperhub-wallet-hook";
|
|
206
|
+
var HOOK_COMMAND_BARE = HOOK_BIN;
|
|
207
|
+
var PACKAGE_NAME = "@keeperhub/wallet";
|
|
208
|
+
function readPackageVersion() {
|
|
209
|
+
try {
|
|
210
|
+
const here = (0, import_node_path2.dirname)((0, import_node_url.fileURLToPath)(__filename));
|
|
211
|
+
const pkgPath = (0, import_node_path2.join)(here, "..", "package.json");
|
|
212
|
+
const raw = (0, import_node_fs2.readFileSync)(pkgPath, "utf-8");
|
|
213
|
+
const parsed = JSON.parse(raw);
|
|
214
|
+
if (typeof parsed.version === "string" && parsed.version.length > 0) {
|
|
215
|
+
return parsed.version;
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
}
|
|
219
|
+
return "latest";
|
|
220
|
+
}
|
|
221
|
+
function buildNpxCommand(version) {
|
|
222
|
+
return `npx -y -p ${PACKAGE_NAME}@${version} ${HOOK_BIN}`;
|
|
223
|
+
}
|
|
224
|
+
var KEEPERHUB_HOOK_MARKER = HOOK_BIN;
|
|
225
|
+
function filterKeeperhubHooksFromEntry(entry) {
|
|
226
|
+
if (typeof entry !== "object" || entry === null) {
|
|
227
|
+
return entry;
|
|
228
|
+
}
|
|
229
|
+
const candidate = entry;
|
|
230
|
+
if (!Array.isArray(candidate.hooks)) {
|
|
231
|
+
return entry;
|
|
232
|
+
}
|
|
233
|
+
const survivors = candidate.hooks.filter((h) => {
|
|
234
|
+
const cmd = h?.command;
|
|
235
|
+
return !(typeof cmd === "string" && cmd.includes(KEEPERHUB_HOOK_MARKER));
|
|
236
|
+
});
|
|
237
|
+
if (survivors.length === candidate.hooks.length) {
|
|
238
|
+
return entry;
|
|
239
|
+
}
|
|
240
|
+
if (survivors.length === 0) {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
return { ...candidate, hooks: survivors };
|
|
244
|
+
}
|
|
245
|
+
function resolveHookCommand() {
|
|
246
|
+
const envOverride = process.env.KEEPERHUB_WALLET_HOOK_COMMAND;
|
|
247
|
+
if (envOverride && envOverride.length > 0) {
|
|
248
|
+
return envOverride;
|
|
249
|
+
}
|
|
250
|
+
try {
|
|
251
|
+
(0, import_node_child_process.execFileSync)("/bin/sh", ["-c", `command -v ${HOOK_BIN}`], {
|
|
252
|
+
stdio: "ignore"
|
|
253
|
+
});
|
|
254
|
+
return HOOK_COMMAND_BARE;
|
|
255
|
+
} catch {
|
|
256
|
+
return buildNpxCommand(readPackageVersion());
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function buildKeeperhubEntry(command) {
|
|
204
260
|
return {
|
|
205
261
|
matcher: "*",
|
|
206
|
-
hooks: [{ type: "command", command
|
|
262
|
+
hooks: [{ type: "command", command }]
|
|
207
263
|
};
|
|
208
264
|
}
|
|
209
265
|
function resolveDefaultSkillSource() {
|
|
@@ -214,7 +270,8 @@ function defaultNotice(msg) {
|
|
|
214
270
|
process.stderr.write(`${msg}
|
|
215
271
|
`);
|
|
216
272
|
}
|
|
217
|
-
async function registerClaudeCodeHook(settingsPath) {
|
|
273
|
+
async function registerClaudeCodeHook(settingsPath, options = {}) {
|
|
274
|
+
const command = options.hookCommand ?? resolveHookCommand();
|
|
218
275
|
let raw = null;
|
|
219
276
|
try {
|
|
220
277
|
raw = await (0, import_promises.readFile)(settingsPath, "utf-8");
|
|
@@ -237,12 +294,12 @@ async function registerClaudeCodeHook(settingsPath) {
|
|
|
237
294
|
const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
|
|
238
295
|
const filtered = [];
|
|
239
296
|
for (const entry of existingPreToolUse) {
|
|
240
|
-
const
|
|
241
|
-
if (
|
|
242
|
-
filtered.push(
|
|
297
|
+
const survivor = filterKeeperhubHooksFromEntry(entry);
|
|
298
|
+
if (survivor !== null) {
|
|
299
|
+
filtered.push(survivor);
|
|
243
300
|
}
|
|
244
301
|
}
|
|
245
|
-
filtered.push(buildKeeperhubEntry());
|
|
302
|
+
filtered.push(buildKeeperhubEntry(command));
|
|
246
303
|
hooks.PreToolUse = filtered;
|
|
247
304
|
config.hooks = hooks;
|
|
248
305
|
await (0, import_promises.mkdir)((0, import_node_path2.dirname)(settingsPath), { recursive: true, mode: 448 });
|
|
@@ -258,26 +315,27 @@ async function writeSkillToAgent(agent, skillSource) {
|
|
|
258
315
|
await (0, import_promises.chmod)(target, 420);
|
|
259
316
|
return { agent: agent.agent, path: target, status: "written" };
|
|
260
317
|
}
|
|
261
|
-
function buildNoticeMessage(agent) {
|
|
262
|
-
return `${agent.agent} does not support auto-registered PreToolUse hooks; run \`${
|
|
318
|
+
function buildNoticeMessage(agent, command) {
|
|
319
|
+
return `${agent.agent} does not support auto-registered PreToolUse hooks; run \`${command}\` on every tool use via ${agent.agent}'s settings file at ${agent.settingsFile}`;
|
|
263
320
|
}
|
|
264
321
|
async function installSkill(options = {}) {
|
|
265
322
|
const agents = detectAgents(options.homeOverride);
|
|
266
323
|
const skillSource = options.skillSourcePath ?? resolveDefaultSkillSource();
|
|
267
324
|
const onNotice = options.onNotice ?? defaultNotice;
|
|
325
|
+
const hookCommand = options.hookCommand ?? resolveHookCommand();
|
|
268
326
|
const skillWrites = [];
|
|
269
327
|
const hookRegistrations = [];
|
|
270
328
|
for (const agent of agents) {
|
|
271
329
|
const write = await writeSkillToAgent(agent, skillSource);
|
|
272
330
|
skillWrites.push(write);
|
|
273
331
|
if (agent.hookSupport === "claude-code") {
|
|
274
|
-
await registerClaudeCodeHook(agent.settingsFile);
|
|
332
|
+
await registerClaudeCodeHook(agent.settingsFile, { hookCommand });
|
|
275
333
|
hookRegistrations.push({
|
|
276
334
|
agent: agent.agent,
|
|
277
335
|
status: "registered"
|
|
278
336
|
});
|
|
279
337
|
} else {
|
|
280
|
-
const message = buildNoticeMessage(agent);
|
|
338
|
+
const message = buildNoticeMessage(agent, hookCommand);
|
|
281
339
|
hookRegistrations.push({
|
|
282
340
|
agent: agent.agent,
|
|
283
341
|
status: "notice",
|
|
@@ -685,6 +743,26 @@ var DEFAULT_TOOL_RE = /keeperhub|wallet|sign/i;
|
|
|
685
743
|
function defaultToolMatcher(name) {
|
|
686
744
|
return DEFAULT_TOOL_RE.test(name);
|
|
687
745
|
}
|
|
746
|
+
function hasPaymentShape(input) {
|
|
747
|
+
const ti = input.tool_input ?? {};
|
|
748
|
+
const challenge = ti.paymentChallenge;
|
|
749
|
+
if (challenge !== void 0 && challenge !== null) {
|
|
750
|
+
return true;
|
|
751
|
+
}
|
|
752
|
+
if (ti.amount !== void 0 && ti.amount !== null) {
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
if (ti.unit !== void 0 && ti.unit !== null) {
|
|
756
|
+
return true;
|
|
757
|
+
}
|
|
758
|
+
for (const field of ["to", "contract", "assetAddress"]) {
|
|
759
|
+
const v = ti[field];
|
|
760
|
+
if (typeof v === "string" && ADDRESS_RE.test(v)) {
|
|
761
|
+
return true;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return false;
|
|
765
|
+
}
|
|
688
766
|
function extractAmountMicroUsdc(input) {
|
|
689
767
|
const ti = input.tool_input ?? {};
|
|
690
768
|
const challenge = ti.paymentChallenge ?? {};
|
|
@@ -734,6 +812,9 @@ async function createPreToolUseHook(options = {}) {
|
|
|
734
812
|
if (!(typeof hookInput.tool_name === "string" && toolMatcher(hookInput.tool_name))) {
|
|
735
813
|
return { decision: "allow" };
|
|
736
814
|
}
|
|
815
|
+
if (!hasPaymentShape(hookInput)) {
|
|
816
|
+
return { decision: "allow" };
|
|
817
|
+
}
|
|
737
818
|
const contractAddr = extractContractAddress(hookInput);
|
|
738
819
|
const amountMicro = extractAmountMicroUsdc(hookInput);
|
|
739
820
|
if (contractAddr && !safety.allowlisted_contracts.includes(contractAddr)) {
|
|
@@ -866,6 +947,30 @@ var NONCE_BYTES = 32;
|
|
|
866
947
|
async function sleep(ms) {
|
|
867
948
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
868
949
|
}
|
|
950
|
+
function selectProtocol(x402, mpp, hint) {
|
|
951
|
+
const h = hint ?? "auto";
|
|
952
|
+
if (h === "x402") {
|
|
953
|
+
if (!x402) {
|
|
954
|
+
throw new KeeperHubError(
|
|
955
|
+
"X402_NOT_OFFERED",
|
|
956
|
+
"x402 is not offered by this endpoint"
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
return "x402";
|
|
960
|
+
}
|
|
961
|
+
if (h === "mpp") {
|
|
962
|
+
if (!mpp) {
|
|
963
|
+
throw new KeeperHubError(
|
|
964
|
+
"MPP_NOT_OFFERED",
|
|
965
|
+
"mpp is not offered by this endpoint"
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
return "mpp";
|
|
969
|
+
}
|
|
970
|
+
if (x402) return "x402";
|
|
971
|
+
if (mpp) return "mpp";
|
|
972
|
+
return null;
|
|
973
|
+
}
|
|
869
974
|
function createPaymentSigner(opts = {}) {
|
|
870
975
|
const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
|
|
871
976
|
const walletLoader = opts.walletLoader ?? readWalletConfig;
|
|
@@ -1008,12 +1113,13 @@ function createPaymentSigner(opts = {}) {
|
|
|
1008
1113
|
return response;
|
|
1009
1114
|
}
|
|
1010
1115
|
const wallet = await walletLoader();
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
}
|
|
1014
|
-
if (x402) {
|
|
1116
|
+
const protocol = selectProtocol(x402, mpp, options?.paymentHint);
|
|
1117
|
+
if (protocol === "x402") {
|
|
1015
1118
|
return payViaX402(response, x402, wallet, options);
|
|
1016
1119
|
}
|
|
1120
|
+
if (protocol === "mpp") {
|
|
1121
|
+
return payViaMpp(response, mpp, wallet, options);
|
|
1122
|
+
}
|
|
1017
1123
|
return response;
|
|
1018
1124
|
}
|
|
1019
1125
|
return {
|
|
@@ -1026,7 +1132,8 @@ function createPaymentSigner(opts = {}) {
|
|
|
1026
1132
|
return pay(first, {
|
|
1027
1133
|
body: init?.body ?? void 0,
|
|
1028
1134
|
headers: init?.headers,
|
|
1029
|
-
method: init?.method
|
|
1135
|
+
method: init?.method,
|
|
1136
|
+
paymentHint: init?.paymentHint
|
|
1030
1137
|
});
|
|
1031
1138
|
}
|
|
1032
1139
|
};
|
|
@@ -1057,8 +1164,10 @@ var paymentSigner = createPaymentSigner();
|
|
|
1057
1164
|
paymentSigner,
|
|
1058
1165
|
readWalletConfig,
|
|
1059
1166
|
registerClaudeCodeHook,
|
|
1167
|
+
resolveHookCommand,
|
|
1060
1168
|
runCli,
|
|
1061
1169
|
runHookCli,
|
|
1170
|
+
selectProtocol,
|
|
1062
1171
|
tempo,
|
|
1063
1172
|
validateAndMerge,
|
|
1064
1173
|
writeWalletConfig
|