@1sat/cli 0.0.13 → 0.0.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/cli",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "CLI for 1Sat Ordinals SDK",
5
5
  "type": "module",
6
6
  "main": "./src/cli.ts",
@@ -24,7 +24,8 @@
24
24
  "chalk": "^5.0.0",
25
25
  "@clack/prompts": "^0.8.0",
26
26
  "bitcoin-backup": "^0.0.11",
27
- "dotenv": "^17.0.0"
27
+ "dotenv": "^17.0.0",
28
+ "evlog": "^2.10.0"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@types/bun": "^1.3.9",
@@ -7,18 +7,17 @@
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
8
8
  import { Hash, KeyDeriver, PrivateKey, Signature, Utils } from '@bsv/sdk'
9
9
  import type { WalletProtocol } from '@bsv/sdk'
10
+ import { createLogger, initLogger } from 'evlog'
10
11
 
11
12
  const { toBase64, toArray } = Utils
12
13
 
14
+ initLogger({ env: { service: '1sat-mcp-proxy' } })
15
+
13
16
  const MCP_URL = process.env.ONESAT_MCP_URL ?? 'http://127.0.0.1:3322'
14
17
  const KEY_DIR = `${process.env.HOME}/.1sat-wallet`
15
18
  const CLIENT_KEY_PATH = `${KEY_DIR}/mcp-agent.key`
16
19
  const AUTH_PROTOCOL_ID: WalletProtocol = [2, 'authrite message signature']
17
20
 
18
- function log(msg: string): void {
19
- process.stderr.write(`[1sat mcp-proxy] ${msg}\n`)
20
- }
21
-
22
21
  function generateNonce(): string {
23
22
  const bytes = new Uint8Array(32)
24
23
  crypto.getRandomValues(bytes)
@@ -32,7 +31,9 @@ function getClientKey(): PrivateKey {
32
31
  }
33
32
  const key = PrivateKey.fromRandom()
34
33
  writeFileSync(CLIENT_KEY_PATH, key.toWif(), { mode: 0o600 })
35
- log('Generated new agent identity key')
34
+ const log = createLogger({ context: 'startup' })
35
+ log.set({ event: 'key_generated', path: CLIENT_KEY_PATH })
36
+ log.emit()
36
37
  return key
37
38
  }
38
39
 
@@ -75,7 +76,10 @@ async function handshake(key: PrivateKey): Promise<Session> {
75
76
  const sig = Signature.fromDER(data.signature as string, 'hex')
76
77
  if (!serverPub.verify(Array.from(msgHash), sig)) throw new Error('Server signature verification failed')
77
78
 
78
- log(`Authenticated with ${(data.identityKey as string).slice(0, 12)}...`)
79
+ const log = createLogger({ context: 'auth' })
80
+ log.set({ event: 'handshake_complete', serverIdentityKey: (data.identityKey as string).slice(0, 16) })
81
+ log.emit()
82
+
79
83
  return { serverIdentityKey: data.identityKey as string, serverNonce, clientKey: key }
80
84
  }
81
85
 
@@ -98,17 +102,25 @@ function signHeaders(session: Session, pathname: string): Record<string, string>
98
102
  }
99
103
 
100
104
  export async function handleMcpProxyCommand(): Promise<void> {
105
+ const startLog = createLogger({ context: 'startup' })
106
+
101
107
  try {
102
108
  await fetch(MCP_URL, { signal: AbortSignal.timeout(2000) })
103
109
  } catch {
104
- log(`Server not reachable at ${MCP_URL} — is 1Sat wallet running?`)
110
+ startLog.set({ event: 'server_unreachable', url: MCP_URL })
111
+ startLog.emit()
112
+ process.stderr.write(`[1sat mcp-proxy] Server not reachable at ${MCP_URL} — is 1Sat wallet running?\n`)
105
113
  process.exit(1)
106
114
  }
107
115
 
116
+ startLog.set({ event: 'started', url: MCP_URL })
117
+ startLog.emit()
118
+
108
119
  const key = getClientKey()
109
120
  const session = await handshake(key)
110
121
 
111
122
  let mcpSessionId: string | null = null
123
+ let requestCount = 0
112
124
  const decoder = new TextDecoder()
113
125
  const reader = Bun.stdin.stream().getReader()
114
126
  let buffer = ''
@@ -125,6 +137,9 @@ export async function handleMcpProxyCommand(): Promise<void> {
125
137
  buffer = buffer.slice(newlineIdx + 1)
126
138
  if (!line) continue
127
139
 
140
+ requestCount++
141
+ const reqLog = createLogger({ context: 'proxy' })
142
+
128
143
  const headers: Record<string, string> = {
129
144
  'Content-Type': 'application/json',
130
145
  Accept: 'application/json, text/event-stream',
@@ -136,6 +151,11 @@ export async function handleMcpProxyCommand(): Promise<void> {
136
151
  }
137
152
 
138
153
  try {
154
+ let method: string | undefined
155
+ try {
156
+ method = JSON.parse(line).method
157
+ } catch {}
158
+
139
159
  const res = await fetch(`${MCP_URL}/mcp`, { method: 'POST', headers, body: line })
140
160
 
141
161
  const sessionHeader = res.headers.get('mcp-session-id')
@@ -143,6 +163,16 @@ export async function handleMcpProxyCommand(): Promise<void> {
143
163
 
144
164
  const contentType = res.headers.get('content-type') ?? ''
145
165
 
166
+ reqLog.set({
167
+ event: 'request',
168
+ requestNum: requestCount,
169
+ method,
170
+ status: res.status,
171
+ contentType: contentType.split(';')[0],
172
+ sessionId: mcpSessionId?.slice(0, 8),
173
+ })
174
+ reqLog.emit()
175
+
146
176
  if (contentType.includes('text/event-stream')) {
147
177
  const text = await res.text()
148
178
  for (const eventLine of text.split('\n')) {
@@ -157,7 +187,8 @@ export async function handleMcpProxyCommand(): Promise<void> {
157
187
  }
158
188
  } catch (err) {
159
189
  const msg = err instanceof Error ? err.message : String(err)
160
- log(`Request failed: ${msg}`)
190
+ reqLog.set({ event: 'request_failed', requestNum: requestCount, error: msg })
191
+ reqLog.emit()
161
192
  process.stdout.write(`${JSON.stringify({
162
193
  jsonrpc: '2.0',
163
194
  error: { code: -32000, message: `MCP proxy error: ${msg}` },