@keeperhub/wallet 0.1.8 → 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/dist/index.cjs CHANGED
@@ -43,6 +43,7 @@ __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,
48
49
  selectProtocol: () => selectProtocol,
@@ -196,15 +197,69 @@ function fund(walletAddress) {
196
197
  }
197
198
 
198
199
  // src/skill-install.ts
200
+ var import_node_child_process = require("child_process");
199
201
  var import_promises = require("fs/promises");
202
+ var import_node_fs2 = require("fs");
200
203
  var import_node_path2 = require("path");
201
204
  var import_node_url = require("url");
202
- var HOOK_COMMAND = "keeperhub-wallet-hook";
203
- var KEEPERHUB_HOOK_MARKER = "keeperhub-wallet-hook";
204
- function buildKeeperhubEntry() {
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) {
205
260
  return {
206
261
  matcher: "*",
207
- hooks: [{ type: "command", command: HOOK_COMMAND }]
262
+ hooks: [{ type: "command", command }]
208
263
  };
209
264
  }
210
265
  function resolveDefaultSkillSource() {
@@ -215,7 +270,8 @@ function defaultNotice(msg) {
215
270
  process.stderr.write(`${msg}
216
271
  `);
217
272
  }
218
- async function registerClaudeCodeHook(settingsPath) {
273
+ async function registerClaudeCodeHook(settingsPath, options = {}) {
274
+ const command = options.hookCommand ?? resolveHookCommand();
219
275
  let raw = null;
220
276
  try {
221
277
  raw = await (0, import_promises.readFile)(settingsPath, "utf-8");
@@ -238,12 +294,12 @@ async function registerClaudeCodeHook(settingsPath) {
238
294
  const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
239
295
  const filtered = [];
240
296
  for (const entry of existingPreToolUse) {
241
- const serialised = JSON.stringify(entry);
242
- if (!serialised.includes(KEEPERHUB_HOOK_MARKER)) {
243
- filtered.push(entry);
297
+ const survivor = filterKeeperhubHooksFromEntry(entry);
298
+ if (survivor !== null) {
299
+ filtered.push(survivor);
244
300
  }
245
301
  }
246
- filtered.push(buildKeeperhubEntry());
302
+ filtered.push(buildKeeperhubEntry(command));
247
303
  hooks.PreToolUse = filtered;
248
304
  config.hooks = hooks;
249
305
  await (0, import_promises.mkdir)((0, import_node_path2.dirname)(settingsPath), { recursive: true, mode: 448 });
@@ -259,26 +315,27 @@ async function writeSkillToAgent(agent, skillSource) {
259
315
  await (0, import_promises.chmod)(target, 420);
260
316
  return { agent: agent.agent, path: target, status: "written" };
261
317
  }
262
- function buildNoticeMessage(agent) {
263
- return `${agent.agent} does not support auto-registered PreToolUse hooks; run \`${HOOK_COMMAND}\` on every tool use via ${agent.agent}'s settings file at ${agent.settingsFile}`;
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}`;
264
320
  }
265
321
  async function installSkill(options = {}) {
266
322
  const agents = detectAgents(options.homeOverride);
267
323
  const skillSource = options.skillSourcePath ?? resolveDefaultSkillSource();
268
324
  const onNotice = options.onNotice ?? defaultNotice;
325
+ const hookCommand = options.hookCommand ?? resolveHookCommand();
269
326
  const skillWrites = [];
270
327
  const hookRegistrations = [];
271
328
  for (const agent of agents) {
272
329
  const write = await writeSkillToAgent(agent, skillSource);
273
330
  skillWrites.push(write);
274
331
  if (agent.hookSupport === "claude-code") {
275
- await registerClaudeCodeHook(agent.settingsFile);
332
+ await registerClaudeCodeHook(agent.settingsFile, { hookCommand });
276
333
  hookRegistrations.push({
277
334
  agent: agent.agent,
278
335
  status: "registered"
279
336
  });
280
337
  } else {
281
- const message = buildNoticeMessage(agent);
338
+ const message = buildNoticeMessage(agent, hookCommand);
282
339
  hookRegistrations.push({
283
340
  agent: agent.agent,
284
341
  status: "notice",
@@ -686,6 +743,26 @@ var DEFAULT_TOOL_RE = /keeperhub|wallet|sign/i;
686
743
  function defaultToolMatcher(name) {
687
744
  return DEFAULT_TOOL_RE.test(name);
688
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
+ }
689
766
  function extractAmountMicroUsdc(input) {
690
767
  const ti = input.tool_input ?? {};
691
768
  const challenge = ti.paymentChallenge ?? {};
@@ -735,6 +812,9 @@ async function createPreToolUseHook(options = {}) {
735
812
  if (!(typeof hookInput.tool_name === "string" && toolMatcher(hookInput.tool_name))) {
736
813
  return { decision: "allow" };
737
814
  }
815
+ if (!hasPaymentShape(hookInput)) {
816
+ return { decision: "allow" };
817
+ }
738
818
  const contractAddr = extractContractAddress(hookInput);
739
819
  const amountMicro = extractAmountMicroUsdc(hookInput);
740
820
  if (contractAddr && !safety.allowlisted_contracts.includes(contractAddr)) {
@@ -1084,6 +1164,7 @@ var paymentSigner = createPaymentSigner();
1084
1164
  paymentSigner,
1085
1165
  readWalletConfig,
1086
1166
  registerClaudeCodeHook,
1167
+ resolveHookCommand,
1087
1168
  runCli,
1088
1169
  runHookCli,
1089
1170
  selectProtocol,