@onekeyfe/hardware-cli 1.1.25-alpha.0

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/src/index.ts ADDED
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @onekeyfe/hardware-cli
3
+ *
4
+ * OneKey hardware wallet CLI for AI agent integration.
5
+ * Provides device management, multi-chain signing, firmware updates,
6
+ * and security management capabilities.
7
+ *
8
+ * Usage:
9
+ * npx @onekeyfe/hardware-cli search
10
+ * npx @onekeyfe/hardware-cli get-address --chain evm
11
+ * npx @onekeyfe/hardware-cli sign-transaction --chain evm --tx '{...}'
12
+ *
13
+ * For AI agent integration, use --json flag for structured output.
14
+ *
15
+ * IMPORTANT: All signing operations require physical confirmation on the
16
+ * hardware device. The CLI handles PIN/Passphrase prompts via stdin for
17
+ * interactive use, or via SDK event system for programmatic use.
18
+ */
19
+
20
+ export { createSDK } from './sdk';
21
+ export type { SDKOptions } from './sdk';
22
+
23
+ export {
24
+ resolveGetAddress,
25
+ resolveGetPublicKey,
26
+ resolveSignTransaction,
27
+ resolveSignMessage,
28
+ resolveBatchGetAddress,
29
+ } from './chains';
30
+
31
+ export type {
32
+ CommonCLIParams,
33
+ GetAddressParams,
34
+ GetPublicKeyParams,
35
+ SignTransactionParams,
36
+ SignMessageParams,
37
+ BatchGetAddressParams,
38
+ } from './chains';
package/src/sdk.ts ADDED
@@ -0,0 +1,198 @@
1
+ /**
2
+ * SDK Factory — creates and initializes the hardware SDK instance
3
+ * for CLI usage with the appropriate transport.
4
+ *
5
+ * CRITICAL: Must register UI event handlers for PIN, Passphrase, and Button
6
+ * confirmation. Without these, the SDK will hang waiting for responses.
7
+ *
8
+ * Reference: packages/core/src/core/index.ts (event registration pattern)
9
+ */
10
+
11
+ // @ts-ignore - hd-common-connect-sdk may not have type declarations
12
+ import HardwareSDK from '@onekeyfe/hd-common-connect-sdk';
13
+ import { DEVICE, UI_EVENT, UI_REQUEST, UI_RESPONSE } from '@onekeyfe/hd-core';
14
+ import { UsbPlugin } from '@onekeyfe/hd-transport-usb';
15
+ import * as readline from 'readline';
16
+
17
+ import type { ConnectSettings } from '@onekeyfe/hd-core';
18
+
19
+ export interface SDKOptions {
20
+ json?: boolean;
21
+ connectId?: string;
22
+ passphraseState?: string;
23
+ useEmptyPassphrase?: boolean;
24
+ }
25
+
26
+ /**
27
+ * Prompt user for input in the terminal (hidden for PIN).
28
+ * Falls back to empty string in non-TTY (piped) mode.
29
+ */
30
+ function promptUser(question: string, hidden = false): Promise<string> {
31
+ if (!process.stdin.isTTY) {
32
+ // Non-interactive mode: return empty (agent should handle via uiResponse)
33
+ return Promise.resolve('');
34
+ }
35
+
36
+ return new Promise(resolve => {
37
+ const rl = readline.createInterface({
38
+ input: process.stdin,
39
+ output: process.stderr, // Use stderr so JSON stdout stays clean
40
+ });
41
+
42
+ if (hidden) {
43
+ // Mute output for PIN entry
44
+ process.stderr.write(question);
45
+ const { stdin } = process;
46
+ const wasRaw = stdin.isRaw;
47
+ if (stdin.setRawMode) stdin.setRawMode(true);
48
+
49
+ let input = '';
50
+ const onData = (char: Buffer) => {
51
+ const c = char.toString('utf8');
52
+ if (c === '\n' || c === '\r' || c === '\u0004') {
53
+ if (stdin.setRawMode) stdin.setRawMode(wasRaw ?? false);
54
+ stdin.removeListener('data', onData);
55
+ process.stderr.write('\n');
56
+ rl.close();
57
+ resolve(input);
58
+ } else if (c === '\u0003') {
59
+ // Ctrl+C
60
+ process.exit(1);
61
+ } else if (c === '\u007F' || c === '\b') {
62
+ // Backspace
63
+ input = input.slice(0, -1);
64
+ } else {
65
+ input += c;
66
+ process.stderr.write('*');
67
+ }
68
+ };
69
+ stdin.on('data', onData);
70
+ } else {
71
+ rl.question(question, answer => {
72
+ rl.close();
73
+ resolve(answer);
74
+ });
75
+ }
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Register UI event handlers for interactive device operations.
81
+ *
82
+ * The SDK emits events when the device needs user interaction:
83
+ * - PIN entry (entered on device screen for Touch/Pro, or via matrix for Classic)
84
+ * - Passphrase input (for hidden wallets)
85
+ * - Button confirmation (user must physically press on device)
86
+ *
87
+ * Reference: packages/core/src/core/index.ts lines 315-330, 1021-1098
88
+ */
89
+ function registerEventHandlers(sdk: typeof HardwareSDK, opts: SDKOptions): void {
90
+ sdk.on(UI_EVENT, (message: any) => {
91
+ // PIN Request
92
+ // For Touch/Pro devices, PIN is entered on-device (device screen shows numpad).
93
+ // For Classic devices, PIN uses a matrix mapping.
94
+ // In CLI context, we auto-acknowledge since PIN entry happens on-device.
95
+ if (message.type === UI_REQUEST.REQUEST_PIN) {
96
+ const pinType = message.payload?.type;
97
+
98
+ if (pinType === 'ButtonRequest_PinEntry' || pinType === 'ButtonRequest_AttachPin') {
99
+ // PIN is entered directly on device screen (Touch/Pro)
100
+ process.stderr.write('[onekey-hw] Please enter PIN on your device screen...\n');
101
+ // No uiResponse needed — device handles PIN input internally
102
+ } else {
103
+ // Classic devices: PIN entry via matrix
104
+ // In CLI mode, prompt user or let agent handle
105
+ process.stderr.write('[onekey-hw] PIN required. Please enter PIN on your device.\n');
106
+ promptUser('PIN (on-device numpad mapping): ', true).then(pin => {
107
+ sdk.uiResponse({
108
+ type: UI_RESPONSE.RECEIVE_PIN,
109
+ payload: pin,
110
+ });
111
+ });
112
+ }
113
+ }
114
+
115
+ // Passphrase Request
116
+ // User must provide passphrase for hidden wallet access.
117
+ // Passphrase can be entered on-device (Touch/Pro) or via host.
118
+ if (message.type === UI_REQUEST.REQUEST_PASSPHRASE) {
119
+ if (opts.useEmptyPassphrase) {
120
+ // Standard wallet (no passphrase)
121
+ sdk.uiResponse({
122
+ type: UI_RESPONSE.RECEIVE_PASSPHRASE,
123
+ payload: {
124
+ value: '',
125
+ passphraseOnDevice: false,
126
+ save: false,
127
+ },
128
+ });
129
+ } else {
130
+ process.stderr.write('[onekey-hw] Passphrase required for hidden wallet.\n');
131
+ promptUser('Enter passphrase (or press Enter for on-device entry): ').then(passphrase => {
132
+ if (passphrase === '') {
133
+ // Enter on device
134
+ sdk.uiResponse({
135
+ type: UI_RESPONSE.RECEIVE_PASSPHRASE,
136
+ payload: {
137
+ value: '',
138
+ passphraseOnDevice: true,
139
+ save: false,
140
+ },
141
+ });
142
+ } else {
143
+ sdk.uiResponse({
144
+ type: UI_RESPONSE.RECEIVE_PASSPHRASE,
145
+ payload: {
146
+ value: passphrase,
147
+ passphraseOnDevice: false,
148
+ save: false,
149
+ },
150
+ });
151
+ }
152
+ });
153
+ }
154
+ }
155
+
156
+ // Passphrase On Device
157
+ if (message.type === UI_REQUEST.REQUEST_PASSPHRASE_ON_DEVICE) {
158
+ process.stderr.write('[onekey-hw] Please enter passphrase on your device screen...\n');
159
+ }
160
+
161
+ // Button Confirmation
162
+ // User must physically press confirm/reject on the device.
163
+ if (message.type === UI_REQUEST.REQUEST_BUTTON) {
164
+ process.stderr.write('[onekey-hw] Please confirm the action on your device...\n');
165
+ }
166
+ });
167
+
168
+ // Device connection events
169
+ sdk.on(DEVICE.CONNECT, (device: any) => {
170
+ if (!opts.json) {
171
+ process.stderr.write(`[onekey-hw] Device connected: ${device?.name || 'Unknown'}\n`);
172
+ }
173
+ });
174
+
175
+ sdk.on(DEVICE.DISCONNECT, (device: any) => {
176
+ if (!opts.json) {
177
+ process.stderr.write(`[onekey-hw] Device disconnected: ${device?.name || 'Unknown'}\n`);
178
+ }
179
+ });
180
+ }
181
+
182
+ export async function createSDK(opts: SDKOptions) {
183
+ const settings: Partial<ConnectSettings> = {
184
+ debug: false,
185
+ fetchConfig: true,
186
+ };
187
+
188
+ // Direct USB via libusb — works on macOS, Linux, Windows
189
+ settings.env = 'lowlevel';
190
+ const plugin = UsbPlugin;
191
+
192
+ await HardwareSDK.init(settings, undefined, plugin);
193
+
194
+ // Register event handlers AFTER init
195
+ registerEventHandlers(HardwareSDK, opts);
196
+
197
+ return HardwareSDK;
198
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "declaration": true,
7
+ "strict": true,
8
+ "noImplicitAny": false,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "outDir": "./dist",
14
+ "rootDir": "./src"
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist", "evals"]
18
+ }