316 Commits
Author SHA1 Message Date
redshift fec0d99d72 fix: switch clients commands back to callDaemon
Clients management endpoints (/clients, /clients/add, /clients/delete)
should route through the daemon directly, not the auth proxy.
2026-06-01 16:07:44 +08:00
redshift dfc7fbf1f3 added nsec creation during onboarding. 2026-06-01 00:01:23 +08:00
redshift f9412af8b3 version bump and using the new adapters and a local eventsDb. 2026-05-30 18:25:18 +08:00
redshiftandGitHub 2dc2cf64ec Merge pull request #39 from Routstr/feat/auth-url-for-npubs-clients-usage
feat: add auth URL for npubs clients usage
2026-05-30 06:22:45 +00:00
redshiftandGitHub f9a85b3fc6 Merge pull request #38 from Routstr/feat/pi-integration-contexts
feat: add context window support to pi integration
2026-05-30 06:22:03 +00:00
redshiftandGitHub f52da6cffc Merge pull request #37 from jeroenubbink/fix/onboard-silent-output-and-blocked-postinstall
fix(onboard): show integration menu and progress in terminal
2026-05-30 06:21:30 +00:00
redshift 17529e762e feat: add context window support to pi integration
- Add optional contextWindow field to PiModelEntry type
- Map model.context_length to contextWindow when available
- Add context_length to RoutstrModel type in registry
2026-05-30 14:04:24 +08:00
redshift 94cd2ff15d feat: add authUrl config for routing management commands to auth proxy
Adds an authUrl field to RoutstrdConfig so CLI management commands
(npubs, clients, usage) can be directed to the routstrd-auth proxy
instead of the daemon. This fixes 'routstrd npubs list' failing with
'Only POST is supported' when the auth proxy and daemon run on
separate ports (e.g., Cloudron setup: proxy on 8008, daemon on 8009).

Changes:
- config.ts: add authUrl to RoutstrdConfig
- daemon-client.ts: add getAuthBaseUrl(), callAuth(), refactor callDaemon
- cli.ts: npubs/usage commands use callAuth, remote command accepts --auth-url
- clients.ts: clients commands use callAuth
2026-05-30 05:30:42 +00:00
Jeroen UbbinkandClaude Sonnet 4.6 739034b043 fix(onboard): show integration menu and progress in terminal
The logger utility in this project is a file-only logger — every call to
logger.log() / logger.error() writes to ~/.routstrd/logs/YYYY-MM-DD.log
and produces no terminal output whatsoever. This is intentional and correct
for the background daemon (daemon/, start-daemon.ts), which has no attached
terminal.

However, the onboarding and integration code was mistakenly using logger.log
instead of console.log for all of its user-facing output:

- setupIntegration() printed the 1-6 integration menu with logger.log, so
  the user only ever saw the bare prompt 'Select integration [1]: ' with no
  options above it. The selection appeared to be broken.

- Every install*Integration function (opencode, openclaw, claudecode, hermes,
  pi) reported all progress and results with logger.log, so after picking an
  integration nothing appeared to happen.

- initDaemon() used logger.log for 'Initialization complete!' and the
  follow-up wallet instructions, so those were also silently dropped.

- installCocodOrExit() used logger.log for the 'cocod not found, installing'
  message and the success/failure result.

Fix: replace logger.log/logger.error with console.log/console.error in all
CLI-facing code paths (cli.ts, integrations/index.ts, and all five
integration installers). Remove the now-unused logger import from the five
integration files. The logger import in integrations/index.ts is kept because
refreshModelsAndIntegrations() is called by the daemon's internal scheduler
and correctly logs to file there.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 09:02:36 +02:00
redshift 8db3b3cf8b lock v0.3.0 2026-05-25 08:57:57 +08:00
redshift ba52a3c52e bumped version 2026-05-25 08:26:56 +08:00
redshiftandGitHub db3d4809f2 Merge pull request #36 from Routstr/feat/nwc-integration
feat: NWC (Nostr Wallet Connect) integration with auto-refill
2026-05-24 02:39:23 +00:00
redshift e9775c10d4 Display cooldown in minutes instead of milliseconds
- Add cooldownMinutes field to /nwc/status and /nwc/auto-refill responses
- Change auto-refill log from ms to minutes display
- Keep cooldownMs internally for calculations
2026-05-24 10:23:29 +08:00
redshift 789fd9db2b fix(auto-refill): broken backoff and preimage crash causing payment spam
Two bugs caused the auto-refill loop to retry every 5s regardless of outcome:

1) Backoff used lastRefillAt which was only set on success. On failure
   it stayed at 0, so now - 0 < backoffInterval never blocked once the
   daemon had been running > 30s. Switched to a separate lastAttemptAt
   that is updated on every attempt (success or failure).

2) preimage.slice() crashed when NWC returned a payment result without
   a preimage field. This turned successful payments into exceptions,
   triggering retries and causing the wallet to be charged repeatedly.
   Guard preimage with an if-check before calling .slice().
2026-05-24 10:16:16 +08:00
redshift 99244a8bdb feat: hot-reload NWC connection (remove restart requirement)
- Add reconnect() method to wallet adapter that tears down old
  WalletConnect/RelayPool and creates a new one on the fly
- Auto-refill loop now uses a getWallet() getter so it always
  references the latest wallet instance after reconnect
- POST /nwc/connect and /nwc/disconnect handlers call reconnect()
  after saving config, no restart needed
- Remove 'Run routstrd restart' messages from CLI connect/disconnect
2026-05-24 09:22:45 +08:00
redshift 5799c5c5b0 auto-refill: update wallet auto-refill logic 2026-05-24 09:11:13 +08:00
redshift e5f5c0995d auto-refill: add error categorization, exponential backoff, and fatal error handling 2026-05-23 23:13:52 +08:00
redshift 92ca9a7cb0 chore: remove legacy NWC client, fix auto-refill getter 2026-05-23 23:03:48 +08:00
redshift c98709e383 feat: auto-refill no longer requires daemon restart
Changed startAutoRefillLoop to accept a config getter instead of a static
config object. The getter reads config from disk on every check cycle, so
CLI changes (nwc auto-refill on/off) take effect immediately.

- auto-refill.ts: config parameter replaced with getConfig() callback
- wallet/index.ts: always start loop when wallet exists, use getter
- daemon/index.ts: pass getAutoRefillConfig reading from disk sync
- config-store.ts: added loadDaemonConfigSync() for sync disk reads
- http/index.ts + cli.ts: removed 'Restart daemon to apply' messages
2026-05-23 22:37:43 +08:00
redshift b9d30b12a9 nwc: add progress logs to fundFromNWC, trim response to amount+balance
- Add step-by-step logging to fundFromNWC (initial/final balance, invoice,
  payment status, fees) matching pay_invoice.mts pattern
- Remove invoice and preimage from POST /nwc/fund response
- Add final wallet balance to the response after funding completes
2026-05-23 22:26:10 +08:00
redshift 5ee6a39567 refactor: replace custom NwcClient with applesauce-wallet-connect
- auto-refill.ts: use WalletConnect instance directly instead of
  NwcClient + RelayPool; check wallet.service for connection state
- wallet/index.ts: create single shared WalletConnect for auto-refill,
  fundFromNWC, and getNwcStatus; remove NwcClient entirely
- daemon/index.ts: strip all NwcClient creation/connect/logging/cleanup;
  auto-refill now gates on connectionString alone
- add applesauce-wallet-connect dependency
2026-05-23 22:14:15 +08:00
redshift fd07a688fa simplify NWC client: NIP-04 only, remove encryption negotiation, trim test 2026-05-23 14:42:28 +08:00
redshift 47afe3ac7b trim test_nwc.ts to minimal make_invoice + pay_invoice test 2026-05-23 14:28:59 +08:00
redshift 62bd014836 feat: rewrite NWC client with encryption auto-negotiation, EOSE waiting, add test script
- Encryption auto-detection: reads wallet info event (kind 13194) on connect
  to choose NIP-04 vs NIP-44 per NIP-47 spec
- Subscription readiness: wait for EOSE before resolving connect()
- Dual NIP-04 / NIP-44 encrypt/decrypt support
- Proper encryption tags on NIP-44 requests
- test_nwc.ts: standalone NWC test script for make_invoice + pay_invoice
2026-05-23 14:26:45 +08:00
redshift cd9b724ca6 fix(nwc): double hex-encoding of client pubkey and unused connection secret
Two bugs caused NWC responses to never arrive:

1. getPublicKey() in nostr-tools v2 already returns a hex string, but
   the code wrapped it with Buffer.from().toString('hex'), producing a
   double-encoded 128-char string. The relay rejected the REQ filter
   with 'filter item too large' because the #p tag value was invalid.

2. The 'secret' from the NWC connection string (the pre-shared client
   private key per NIP-47) was parsed but never used. Instead a new
   random keypair was generated on every restart, so the wallet service
   would see requests from an unexpected pubkey.

Also removed 'since' from the subscription filter (simpler, some relays
choke on it) and added debug logging for the REQ filter.
2026-05-19 02:00:18 +08:00
redshift 44e6dd884f Merge branch 'main' of github.com-red:Routstr/routstrd into feat/nwc-integration 2026-05-19 01:26:04 +08:00
redshift cee4666f6e nwc integration 2026-05-19 01:25:27 +08:00
redshift 8ae0288d95 docker now has current repo and also added xcashu refunds to the cli 2026-05-19 01:25:00 +08:00
redshift 3f14ae8084 Merge branch 'main' of github.com-red:Routstr/routstrd 2026-05-17 11:49:39 +08:00
redshift fdf65ab0c9 reusing routstrclietn 2026-05-17 11:49:28 +08:00
redshift 5069fcac43 bumpd version 2026-05-16 16:47:20 +05:30
redshift 390701b5ea chore: bump @routstr/sdk to ^0.3.7 2026-05-16 14:20:26 +05:30
redshiftandGitHub 9caae65607 Merge pull request #35 from Routstr/fix/docker-dev-and-logger-cashu-ts-update
feat: add Docker dev environment and fix logging/cashu-ts
2026-05-16 08:29:49 +00:00
redshift 747911c6f6 bumped cashu vferison 2026-05-16 16:25:53 +08:00
redshift fd8f433a36 feat: add Docker dev environment and fix logging/cashu-ts
- Add Dockerfile, docker-compose.yml, and .dockerignore for Bun dev container
- Fix sdkLogger to use logger.warn instead of logger.log for warnings
- Add proper warn method to logger (writes to file instead of console)
- Use console.log for daemon startup messages to keep them visible
- Update cashu-ts getDecodedToken call with explicit well-known-pubkeys
- Use proof.amount.toNumber() for updated cashu-ts Amount type
2026-05-16 16:22:16 +08:00
redshift 8e9013ac7d version bumps 2026-05-15 13:55:24 +05:30
redshift f427cc75ea feat: pass routstrPubkey from config to routeRequests when set 2026-05-14 17:43:30 +05:30
redshiftandGitHub d73f8e5e90 Merge pull request #33 from Routstr/feat/structured-logging
feat(daemon): wire SdkLogger with per-request reqId prefixing
2026-05-09 08:44:21 +00:00
redshiftandGitHub 0685428506 Merge pull request #31 from Routstr/worktree-tui-client-column
feat: widen and reposition client column in TUI recent requests
2026-05-09 03:33:48 +00:00
redshiftandGitHub 384f421b62 Merge pull request #32 from Routstr/feat/tui-npubs-tab
feat(tui): add Npubs tab grouping usage by ownerNpub
2026-05-09 03:33:18 +00:00
redshift bcbf5bfc44 feat(daemon): wire SdkLogger through daemon with per-request reqId prefixing
- daemon/index.ts: add makeSdkLogger() factory, wire daemonSdkLogger into
  createBunSqliteDriver, createProviderRegistryFromStore, ModelManager, ProviderManager
- daemon/http/index.ts: add makeSdkLogger() factory, generate per-request
  reqId via randomBytes(4), pass reqLogger = sdkLogger.child("req:${reqId}")
  to routeRequests so every log line from a request is prefixed [req:XXXXXXXX]
- start-daemon.ts: remove >> logfile 2>&1 redirect and getTodayLogFile();
  all file logging now goes through the daemon's writeLog() with daily rotation

Result: Every log line from a request is prefixed [req:XXXXXXXX], all entries
have [ISO] [INFO/ERROR/DEBUG] timestamps, no duplicates, and the log file
rotates correctly at midnight.
2026-05-08 19:20:00 +08:00
redshift d098d25bc0 feat(tui): add Npubs tab grouping usage by ownerNpub
- Add 'npubs' tab between Clients and Recent (key 7)
- Tab is hidden when no clients have ownerNpub set
- Groups usage entries by ownerNpub via client-id → npub mapping
- Shows truncated npub (first 10 + … + last 6) with full npub on detail line
- Displays requests, cost, tokens, avg cost per npub with bar charts
- Includes 'Top Models per Npub' sub-section
- Tab keys dynamically renumbered (1-7 without npubs, 1-8 with)
- Falls back to Clients tab if Npubs becomes unavailable on refresh
2026-05-08 18:59:17 +08:00
redshiftandClaude Opus 4.7 7a3ae208cd feat: move client column to last position and widen to 14 chars
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:58:07 +08:00
redshift c6290eb356 bump 2026-05-07 21:00:54 +05:30
redshiftandGitHub cd59835e2a Merge pull request #30 from Routstr/worktree-tui-client-column
feat: add client column to recent transactions in TUI
2026-05-07 15:29:30 +00:00
redshiftandGitHub e881a312d0 Merge pull request #29 from Routstr/fix/not-enough-proofs-balance-error
fix: surface cocod "Not enough proofs" as InsufficientBalanceError
2026-05-07 15:29:11 +00:00
redshiftandGitHub ab993d18a5 Merge pull request #28 from Routstr/fix/provider-sync
fix: sync bootstrapped providers into store so providers list is complete
2026-05-07 15:28:43 +00:00
redshiftandClaude Opus 4.7 5aec1af79b feat: add client column to recent transactions in TUI
Adds a CLIENT column between TIME and MODEL in the Recent Requests tab,
color-coded using CLIENT_COLORS. Entries without a client show "unknown".

Closes #25

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-07 12:38:21 +08:00
redshiftandClaude Sonnet 4 622afb04a5 fix: sync bootstrapped providers into store so providers list is complete
After bootstrapProviders runs, newly discovered URLs (e.g. privateprovider.xyz)
were only known to the ModelManager cache and never written into the store's
baseUrlsList. This caused `providers list` and `models -m <id>` to show
different sets of providers. Now the bootstrap step merges any new URLs into
the store so both commands draw from the same source of truth.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-05-06 20:29:40 +08:00
redshiftandClaude Sonnet 4 3abc028395 fix: surface cocod "Not enough proofs" as InsufficientBalanceError
When cocod cannot assemble enough proofs to send (e.g. due to
denomination fragmentation or stale proof state), it returns
"Send failed: Not enough proofs to send". This was propagating
as a generic Error, causing the HTTP handler to return 500 instead
of the structured 402 insufficient_balance response.

Map that cocod error to InsufficientBalanceError in walletAdapter.sendToken
so the existing handler path returns the correct 402.

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-05-06 18:32:46 +08:00