- 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.
- 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
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>
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>
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>
- Updated npubs list to display role (admin/user) for each npub
- Changed header from 'Admin npubs' to 'Npubs' to reflect all roles
- Updated command descriptions to reflect broader scope
- Also fixed 'admin npub' message in add command output
The auth proxy intercepts GET /usage and returns only entries belonging to
the authenticated npub's clients, with owner suffixes stripped. The TUI no
longer needs to filter entries client-side.
- Remove getNpubSuffix and loadConfig from tui/usage/data.ts imports
- Remove old suffix-based filtering logic from fetchUsage()
- Remove unused getNpubSuffix from cli.ts imports
- Add ownerNpub?: string to ClientEntry and DaemonClient interfaces
- Update getClientsFromStore() to preserve ownerNpub field
- GET /clients: include ownerNpub in daemon response
- POST /clients/add: accept and store ownerNpub from auth proxy
- Remove getNpubSuffix/addSuffixToId/removeSuffixFromId from clients.ts (moved to auth proxy)
- Remove CLI-side suffixing in addDaemonClient and deleteClientAction
- Remove config loading from getClientsList (no longer needed for filtering)
- CLI output now shows raw client IDs without suffix stripping
- Add new installHermesIntegration to write ~/.hermes/config.yaml
- Prepend model block with base_url/api_key/default model at top
- Append custom_providers block at the bottom
- Use 3rd model in daemon list as default
- Add Hermes to setup menu and registry
When multiple routstrd processes (or CLI auto-starts) bootstrap simultaneously,
each process found cocod/routstrd unreachable, spawned its own copy, and
contended for the same database socket. The paired ~200ms burst timestamps
in the logs were the symptom.
Fixes applied:
- Add cross-process startup lock (process-lock.ts)
- Uses atomic mkdir as the lock primitive.
- Stores PID + UUID token; verifies ownership on release to avoid
removing a lock taken by a new process after the original crashed.
- Removes stale locks (unreachable PID or lock older than staleAfterMs).
- Exports withCrossProcessLock() for simple RAII-style usage.
- Fix cocod startup race (cocod-client.ts)
- Wrap ensureDaemonRunning() in a socket-derived lock path.
- Re-ping inside the lock before spawning; if another process just started
cocod, the current process detects it and connects instead of spawning.
- Switch from 'cocod daemon' to 'cocod init' for cleaner daemonization.
- Allow exit code 0 from 'cocod init' (normal daemon exit without error).
- Consolidate routstrd daemon startup (daemon-client.ts)
- startDaemonProcess() now delegates to startDaemon() from start-daemon.ts,
sharing the same lock and health-check logic.
- Add cross-process lock to routstrd daemon startup (start-daemon.ts)
- Performs pre-lock isDaemonHealthy() check to skip lock entirely when
already running.
- Performs re-check inside the lock before spawning to avoid duplicate
daemon processes.
- Added 'routstrd refresh' command that:
- Calls /v1/models?refresh=true to refresh routstr21 models
- Calls runIntegrationsForClients() for all registered clients
- Fixed type signature in refreshModelsAndIntegrations (returns any[] not void)
- Imports getClientsList and runIntegrationsForClients in cli.ts
- Created reusable refreshModelsAndIntegrations() function that combines
model refresh with client integration refresh
- Updated src/daemon/index.ts to use the new function in both the scheduled
refresh job and the initial bootstrap refresh
- Merged two chained .then() calls into one in the initial bootstrap flow
- Removed redundant imports (runIntegrationsForClients, getClientsList) from
daemon/index.ts since they're now encapsulated in the function
- Add addSuffixToId() and removeSuffixFromId() helper functions
- Only suffix client IDs, never names
- Update getClientsList, deleteClientAction, and addClientAction to use helpers