Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/wallet/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewAddCmd(f *cmdutil.Factory) *cobra.Command {
Short: "Provision a new agentic wallet (no KeeperHub account required)",
Long: `Provision a new agentic wallet by calling POST /api/agentic-wallet/provision.

This is a thin wrapper around ` + "`npx @keeperhub/wallet add`" + ` -- the npm package is the
This is a thin wrapper around ` + "`npx -p @keeperhub/wallet keeperhub-wallet add`" + ` -- the npm package is the
canonical tool. Writes {subOrgId, walletAddress, hmacSecret} to ~/.keeperhub/wallet.json
(chmod 0o600) and prints subOrgId + walletAddress (hmacSecret is NEVER printed).`,
Args: cobra.NoArgs,
Expand Down
7 changes: 6 additions & 1 deletion cmd/wallet/agentic_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ func runNpxWallet(f *cmdutil.Factory, cmd *cobra.Command, subcmd string, args []
host := cmdutil.ResolveHost(cmd, cfg)
baseURL := khhttp.BuildBaseURL(host)

childArgs := append([]string{"@keeperhub/wallet", subcmd}, args...)
// Use -p to name the package explicitly and keeperhub-wallet to name the
// binary. Without -p, npx tries to infer the binary from the package name;
// @keeperhub/wallet exposes keeperhub-wallet / keeperhub-wallet-hook /
// keeperhub-wallet-mcp, so npx cannot pick one and exits "could not
// determine executable to run" regardless of whether Node is installed.
childArgs := append([]string{"-p", "@keeperhub/wallet", "keeperhub-wallet", subcmd}, args...)
child := execCommand("npx", childArgs...)
child.Stdin = f.IOStreams.In
child.Stdout = f.IOStreams.Out
Expand Down
55 changes: 55 additions & 0 deletions cmd/wallet/agentic_wrapper_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package wallet

import (
"os/exec"
"testing"

"github.com/keeperhub/cli/internal/config"
khhttp "github.com/keeperhub/cli/internal/http"
"github.com/keeperhub/cli/pkg/cmdutil"
"github.com/keeperhub/cli/pkg/iostreams"
"github.com/spf13/cobra"
)

func TestAgenticWrapperInvokesExplicitBinary(t *testing.T) {
origExec := execCommand
origLook := lookPath
t.Cleanup(func() {
execCommand = origExec
lookPath = origLook
})

lookPath = func(string) (string, error) { return "/usr/bin/npx", nil }

var gotArgs []string
execCommand = func(name string, args ...string) *exec.Cmd {
gotArgs = args
return exec.Command("true")
}

ios, _, _, _ := iostreams.Test()
f := &cmdutil.Factory{
AppVersion: "1.0.0",
IOStreams: ios,
HTTPClient: func() (*khhttp.Client, error) {
return khhttp.NewClient(khhttp.ClientOptions{Host: "https://app.keeperhub.com", AppVersion: "1.0.0"}), nil
},
Config: func() (config.Config, error) {
return config.Config{DefaultHost: "app.keeperhub.com"}, nil
},
}

_ = runNpxWallet(f, &cobra.Command{}, "info", nil)

want := []string{"-p", "@keeperhub/wallet", "keeperhub-wallet"}
for i, w := range want {
if len(gotArgs) <= i || gotArgs[i] != w {
t.Fatalf("argv[%d] = %q, want %q (full argv: %v)", i, func() string {
if len(gotArgs) > i {
return gotArgs[i]
}
return "<missing>"
}(), w, gotArgs)
}
}
}
3 changes: 2 additions & 1 deletion cmd/wallet/agentic_wrapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ func TestNewAddCmd_Help(t *testing.T) {
require.NoError(t, err)
out := outBuf.String()
assert.Contains(t, out, "agentic wallet", "help should describe agentic wallet, not creator wallet")
assert.Contains(t, out, "npx @keeperhub/wallet", "help should reference the underlying npm package")
assert.Contains(t, out, "@keeperhub/wallet", "help should reference the underlying npm package")
assert.Contains(t, out, "keeperhub-wallet", "help should reference the explicit binary name")
}

func TestNewInfoCmd_Help(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion cmd/wallet/feedback.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ wallet paid for. Signs giveFeedback() via Turnkey and broadcasts on Ethereum
mainnet via the KeeperHub server proxy. Caller wallet pays gas natively
(~$0.05-2 per call at typical mainnet gas).

Thin wrapper around ` + "`npx @keeperhub/wallet feedback`" + `. Defaults to rating
Thin wrapper around ` + "`npx -p @keeperhub/wallet keeperhub-wallet feedback`" + `. Defaults to rating
KeeperHub's own ERC-8004 agent (id 31875 on Ethereum); use --agent-id to rate
any other agent.`,
Example: ` # 5-star rating for an execution this wallet paid for
Expand Down
2 changes: 1 addition & 1 deletion cmd/wallet/fund.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewFundCmd(f *cmdutil.Factory) *cobra.Command {
Short: "Print Coinbase Onramp URL (Base USDC) and Tempo deposit address for the agentic wallet",
Long: `Print a Coinbase Onramp URL for Base USDC funding plus the Tempo deposit address.

Thin wrapper around ` + "`npx @keeperhub/wallet fund`" + `. No HTTP calls, no browser launch --
Thin wrapper around ` + "`npx -p @keeperhub/wallet keeperhub-wallet fund`" + `. No HTTP calls, no browser launch --
prints copy-paste instructions only.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
Expand Down
2 changes: 1 addition & 1 deletion cmd/wallet/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func NewInfoCmd(f *cmdutil.Factory) *cobra.Command {
Short: "Print subOrgId and walletAddress from local agentic wallet config",
Long: `Print subOrgId and walletAddress from ~/.keeperhub/wallet.json.

Thin wrapper around ` + "`npx @keeperhub/wallet info`" + `. Exits non-zero if the config is missing.`,
Thin wrapper around ` + "`npx -p @keeperhub/wallet keeperhub-wallet info`" + `. Exits non-zero if the config is missing.`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, _ []string) error {
return runNpxWallet(f, cmd, "info", nil)
Expand Down
2 changes: 1 addition & 1 deletion cmd/wallet/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func NewLinkCmd(f *cmdutil.Factory) *cobra.Command {
Short: "Link the agentic wallet to a KeeperHub account (requires KH_SESSION_COOKIE)",
Long: `Link the current agentic wallet to your KeeperHub account by calling POST /api/agentic-wallet/link.

Thin wrapper around ` + "`npx @keeperhub/wallet link`" + `. Requires the KH_SESSION_COOKIE env var
Thin wrapper around ` + "`npx -p @keeperhub/wallet keeperhub-wallet link`" + `. Requires the KH_SESSION_COOKIE env var
set to a valid kh session cookie (sign in at app.keeperhub.com, copy the session cookie, export it).

This command does not launch a browser session handshake; the env-var contract matches the npm CLI.`,
Expand Down
6 changes: 3 additions & 3 deletions cmd/wallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Creator wallet (REST):
kh w balance show creator-wallet on-chain balances via KeeperHub REST API
kh w tokens list supported tokens

Agentic wallet (thin wrappers around npx @keeperhub/wallet):
Agentic wallet (thin wrappers around npx -p @keeperhub/wallet keeperhub-wallet):
kh w add provision a new agentic wallet (no account required)
kh w info print agentic subOrgId + walletAddress
kh w fund print Coinbase Onramp URL + Tempo deposit address
Expand All @@ -28,8 +28,8 @@ Agentic wallet (thin wrappers around npx @keeperhub/wallet):
# Provision an agentic wallet (npx wrapper):
kh w add

# Check balance on the agentic wallet:
npx @keeperhub/wallet balance`,
# Check balance on the agentic wallet directly:
npx -p @keeperhub/wallet keeperhub-wallet balance`,
}

cmd.PersistentFlags().Bool("json", false, "Output as JSON")
Expand Down
6 changes: 3 additions & 3 deletions docs/kh_wallet.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Creator wallet (REST):
kh w balance show creator-wallet on-chain balances via KeeperHub REST API
kh w tokens list supported tokens

Agentic wallet (thin wrappers around npx @keeperhub/wallet):
Agentic wallet (thin wrappers around npx -p @keeperhub/wallet keeperhub-wallet):
kh w add provision a new agentic wallet (no account required)
kh w info print agentic subOrgId + walletAddress
kh w fund print Coinbase Onramp URL + Tempo deposit address
Expand All @@ -26,8 +26,8 @@ Agentic wallet (thin wrappers around npx @keeperhub/wallet):
# Provision an agentic wallet (npx wrapper):
kh w add

# Check balance on the agentic wallet:
npx @keeperhub/wallet balance
# Check balance on the agentic wallet directly:
npx -p @keeperhub/wallet keeperhub-wallet balance
```

### Options
Expand Down
2 changes: 1 addition & 1 deletion docs/kh_wallet_add.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Provision a new agentic wallet (no KeeperHub account required)

Provision a new agentic wallet by calling POST /api/agentic-wallet/provision.

This is a thin wrapper around `npx @keeperhub/wallet add` -- the npm package is the
This is a thin wrapper around `npx -p @keeperhub/wallet keeperhub-wallet add` -- the npm package is the
canonical tool. Writes {subOrgId, walletAddress, hmacSecret} to ~/.keeperhub/wallet.json
(chmod 0o600) and prints subOrgId + walletAddress (hmacSecret is NEVER printed).

Expand Down
2 changes: 1 addition & 1 deletion docs/kh_wallet_feedback.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ wallet paid for. Signs giveFeedback() via Turnkey and broadcasts on Ethereum
mainnet via the KeeperHub server proxy. Caller wallet pays gas natively
(~$0.05-2 per call at typical mainnet gas).

Thin wrapper around `npx @keeperhub/wallet feedback`. Defaults to rating
Thin wrapper around `npx -p @keeperhub/wallet keeperhub-wallet feedback`. Defaults to rating
KeeperHub's own ERC-8004 agent (id 31875 on Ethereum); use --agent-id to rate
any other agent.

Expand Down
2 changes: 1 addition & 1 deletion docs/kh_wallet_fund.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Print Coinbase Onramp URL (Base USDC) and Tempo deposit address for the agentic

Print a Coinbase Onramp URL for Base USDC funding plus the Tempo deposit address.

Thin wrapper around `npx @keeperhub/wallet fund`. No HTTP calls, no browser launch --
Thin wrapper around `npx -p @keeperhub/wallet keeperhub-wallet fund`. No HTTP calls, no browser launch --
prints copy-paste instructions only.

```
Expand Down
2 changes: 1 addition & 1 deletion docs/kh_wallet_info.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Print subOrgId and walletAddress from local agentic wallet config

Print subOrgId and walletAddress from ~/.keeperhub/wallet.json.

Thin wrapper around `npx @keeperhub/wallet info`. Exits non-zero if the config is missing.
Thin wrapper around `npx -p @keeperhub/wallet keeperhub-wallet info`. Exits non-zero if the config is missing.

```
kh wallet info [flags]
Expand Down
2 changes: 1 addition & 1 deletion docs/kh_wallet_link.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Link the agentic wallet to a KeeperHub account (requires KH_SESSION_COOKIE)

Link the current agentic wallet to your KeeperHub account by calling POST /api/agentic-wallet/link.

Thin wrapper around `npx @keeperhub/wallet link`. Requires the KH_SESSION_COOKIE env var
Thin wrapper around `npx -p @keeperhub/wallet keeperhub-wallet link`. Requires the KH_SESSION_COOKIE env var
set to a valid kh session cookie (sign in at app.keeperhub.com, copy the session cookie, export it).

This command does not launch a browser session handshake; the env-var contract matches the npm CLI.
Expand Down