@dawnai/cli 1.1.0 → 1.1.1

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/README.md CHANGED
@@ -25,6 +25,10 @@ dawn account overview
25
25
  dawn account fund
26
26
  dawn account wallet
27
27
 
28
+ dawn wallet list
29
+ dawn wallet use <address-or-name>
30
+ dawn wallet current
31
+
28
32
  dawn strategy list
29
33
  dawn strategy create "<text>"
30
34
  dawn strategy status <id>
@@ -45,6 +49,8 @@ dawn run stop <id>
45
49
 
46
50
  dawn skill list
47
51
  dawn skill install [--force] [--dir <path>]
52
+
53
+ dawn sdk doctor
48
54
  ```
49
55
 
50
56
  ## Environment Variables
@@ -57,5 +63,8 @@ dawn skill install [--force] [--dir <path>]
57
63
  ## Notes
58
64
 
59
65
  - Auth token is stored at `~/.dawn-cli/config.json`.
66
+ - Active Moonpay wallet selection is stored in `~/.dawn-cli/config.json` under `moonpay`.
67
+ - `dawn wallet list` shells out to `mp wallet list` and uses the Polygon address for selection.
60
68
  - `dawn account fund` prints the wallet address and Polygon USDC deposit instructions.
61
69
  - `dawn skill install` copies bundled Dawn skills into `~/.claude/skills` for Claude Code.
70
+ - `dawn sdk doctor` verifies the local Dawn SDK executable (`dawnsdk`) is available.
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import process from 'node:process';
6
6
  import readline from 'node:readline/promises';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { fileURLToPath } from 'node:url';
9
- const CLI_VERSION = '1.1.0';
9
+ const CLI_VERSION = '1.1.1';
10
10
  const DAWN_API_BASE_URL = 'https://api.dawn.ai';
11
11
  const FUNDING_LINK_TEMPLATE = process.env.DAWN_HELIO_LINK_TEMPLATE || '';
12
12
  const CLI_HOME = process.env.DAWN_CLI_HOME || path.join(os.homedir(), '.dawn-cli');
@@ -195,6 +195,10 @@ function printUsage() {
195
195
  dawn account fund
196
196
  dawn account wallet
197
197
 
198
+ dawn wallet list
199
+ dawn wallet use <address-or-name>
200
+ dawn wallet current
201
+
198
202
  dawn strategy list
199
203
  dawn strategy create <text>
200
204
  dawn strategy status <id>
@@ -217,6 +221,8 @@ function printUsage() {
217
221
  dawn skill list
218
222
  dawn skill install [--force] [--dir <path>]
219
223
 
224
+ dawn sdk doctor
225
+
220
226
  dawn update
221
227
 
222
228
  dawn --version
@@ -226,6 +232,111 @@ Environment variables:
226
232
  DAWN_CLI_HOME Override config directory (default: ~/.dawn-cli)
227
233
  `);
228
234
  }
235
+ function normalizeEvmAddress(value) {
236
+ if (typeof value !== 'string') {
237
+ return null;
238
+ }
239
+ const trimmed = value.trim();
240
+ if (!/^0x[a-fA-F0-9]{40}$/.test(trimmed)) {
241
+ return null;
242
+ }
243
+ return trimmed.toLowerCase();
244
+ }
245
+ function getMoonpayConfig(config) {
246
+ if (!config.moonpay || typeof config.moonpay !== 'object' || Array.isArray(config.moonpay)) {
247
+ return {};
248
+ }
249
+ const moonpay = config.moonpay;
250
+ return {
251
+ activeWalletAddress: typeof moonpay.activeWalletAddress === 'string' ? moonpay.activeWalletAddress : undefined,
252
+ activeWalletName: typeof moonpay.activeWalletName === 'string' ? moonpay.activeWalletName : undefined,
253
+ };
254
+ }
255
+ async function runMoonpayCommand(args) {
256
+ const result = await new Promise((resolve) => {
257
+ const child = spawn('mp', args, {
258
+ stdio: ['ignore', 'pipe', 'pipe'],
259
+ });
260
+ let stdout = '';
261
+ let stderr = '';
262
+ child.stdout.on('data', (data) => { stdout += data.toString(); });
263
+ child.stderr.on('data', (data) => { stderr += data.toString(); });
264
+ child.on('close', (code) => { resolve({ code: code ?? 1, stdout, stderr }); });
265
+ });
266
+ if (result.code !== 0) {
267
+ throw new Error(result.stderr.trim() || result.stdout.trim() || 'Moonpay CLI command failed.');
268
+ }
269
+ return result.stdout;
270
+ }
271
+ function parseMoonpayWalletList(output) {
272
+ const lines = output.split(/\r?\n/);
273
+ const wallets = [];
274
+ let currentName = null;
275
+ let currentPolygonAddress = null;
276
+ const flushCurrent = () => {
277
+ if (currentName && currentPolygonAddress) {
278
+ wallets.push({
279
+ name: currentName,
280
+ address: currentPolygonAddress,
281
+ });
282
+ }
283
+ };
284
+ for (const line of lines) {
285
+ const nameMatch = line.match(/^\s*-\s*name:\s*(.+)\s*$/);
286
+ if (nameMatch) {
287
+ flushCurrent();
288
+ currentName = nameMatch[1].trim();
289
+ currentPolygonAddress = null;
290
+ continue;
291
+ }
292
+ const polygonMatch = line.match(/^\s*polygon:\s*(0x[a-fA-F0-9]{40})\s*$/);
293
+ if (polygonMatch) {
294
+ currentPolygonAddress = polygonMatch[1].toLowerCase();
295
+ }
296
+ }
297
+ flushCurrent();
298
+ return wallets;
299
+ }
300
+ async function loadMoonpayWallets() {
301
+ const output = await runMoonpayCommand(['wallet', 'list']);
302
+ const wallets = parseMoonpayWalletList(output);
303
+ if (!wallets.length) {
304
+ throw new Error('Could not find Polygon wallets from `mp wallet list`. Ensure Moonpay CLI is installed and has wallets.');
305
+ }
306
+ return wallets;
307
+ }
308
+ function findMoonpayWalletBySelector(wallets, selector) {
309
+ const normalizedAddress = normalizeEvmAddress(selector);
310
+ if (normalizedAddress) {
311
+ const byAddress = wallets.find((wallet) => wallet.address === normalizedAddress);
312
+ if (byAddress) {
313
+ return byAddress;
314
+ }
315
+ }
316
+ const lowered = selector.toLowerCase();
317
+ const byName = wallets.filter((wallet) => wallet.name.toLowerCase() === lowered);
318
+ if (byName.length === 1) {
319
+ return byName[0];
320
+ }
321
+ if (byName.length > 1) {
322
+ throw new Error(`Multiple Moonpay wallets match "${selector}". Use full address or wallet ID instead.`);
323
+ }
324
+ throw new Error(`No Moonpay wallet matched "${selector}". Run: dawn wallet list`);
325
+ }
326
+ function printMoonpayWalletTable(wallets, activeAddress) {
327
+ const rows = wallets.map((wallet) => ({
328
+ active: activeAddress && wallet.address === activeAddress ? '*' : ' ',
329
+ name: wallet.name,
330
+ address: wallet.address,
331
+ }));
332
+ const nameWidth = Math.max(8, ...rows.map((row) => row.name.length));
333
+ const addressWidth = Math.max(42, ...rows.map((row) => row.address.length));
334
+ console.log(`${'A'.padEnd(2)}${'NAME'.padEnd(nameWidth)} ${'POLYGON_ADDRESS'.padEnd(addressWidth)}`);
335
+ console.log(`${'-'.repeat(2)}${'-'.repeat(nameWidth)} ${'-'.repeat(addressWidth)}`);
336
+ for (const row of rows) {
337
+ console.log(`${row.active.padEnd(2)}${row.name.padEnd(nameWidth)} ${row.address}`);
338
+ }
339
+ }
229
340
  function parseFlags(args) {
230
341
  const flags = {};
231
342
  const positional = [];
@@ -732,6 +843,69 @@ async function handleAccount(args) {
732
843
  }
733
844
  throw new Error(`Unknown account command: ${subcommand}`);
734
845
  }
846
+ async function handleWallet(args) {
847
+ if (args.includes('--help') || args.includes('-h')) {
848
+ console.log(`Usage:
849
+ dawn wallet list
850
+ dawn wallet use <address-or-name>
851
+ dawn wallet current`);
852
+ return;
853
+ }
854
+ const [subcommand, ...rest] = args;
855
+ if (!subcommand) {
856
+ throw new Error('Missing wallet command.');
857
+ }
858
+ const config = await loadConfig();
859
+ const moonpayConfig = getMoonpayConfig(config);
860
+ if (subcommand === 'list') {
861
+ const wallets = await loadMoonpayWallets();
862
+ printMoonpayWalletTable(wallets, moonpayConfig.activeWalletAddress);
863
+ console.log('\nUse a wallet: dawn wallet use <address-or-name>');
864
+ return;
865
+ }
866
+ if (subcommand === 'current') {
867
+ const activeAddress = moonpayConfig.activeWalletAddress;
868
+ if (!activeAddress) {
869
+ console.log('No active Moonpay wallet selected. Run: dawn wallet use <address-or-name>');
870
+ return;
871
+ }
872
+ const wallets = await loadMoonpayWallets();
873
+ const wallet = wallets.find((entry) => entry.address === activeAddress);
874
+ if (!wallet) {
875
+ throw new Error(`Active wallet ${activeAddress} is no longer present in Moonpay wallets. Run: dawn wallet list`);
876
+ }
877
+ console.log('Active Moonpay wallet');
878
+ console.log('=====================');
879
+ printKeyValue('Name', wallet.name);
880
+ printKeyValue('Address', wallet.address);
881
+ printKeyValue('Source', 'mp wallet list');
882
+ return;
883
+ }
884
+ if (subcommand === 'use') {
885
+ const selector = rest[0];
886
+ if (!selector) {
887
+ throw new Error('Usage: dawn wallet use <address-or-name>');
888
+ }
889
+ const wallets = await loadMoonpayWallets();
890
+ const selectedWallet = findMoonpayWalletBySelector(wallets, selector);
891
+ const nextConfig = {
892
+ ...config,
893
+ moonpay: {
894
+ ...moonpayConfig,
895
+ activeWalletAddress: selectedWallet.address,
896
+ activeWalletName: selectedWallet.name,
897
+ },
898
+ };
899
+ await saveConfig(nextConfig);
900
+ console.log('Selected Moonpay wallet');
901
+ console.log('=======================');
902
+ printKeyValue('Name', selectedWallet.name);
903
+ printKeyValue('Address', selectedWallet.address);
904
+ printKeyValue('Source', 'mp wallet list');
905
+ return;
906
+ }
907
+ throw new Error(`Unknown wallet command: ${subcommand}`);
908
+ }
735
909
  function renderConversationList(conversations) {
736
910
  if (!Array.isArray(conversations) || conversations.length === 0) {
737
911
  console.log('No strategies found.');
@@ -1454,6 +1628,48 @@ async function handleSkill(args) {
1454
1628
  }
1455
1629
  throw new Error(`Unknown skill command: ${subcommand}`);
1456
1630
  }
1631
+ async function handleSdk(args) {
1632
+ if (args.includes('--help') || args.includes('-h')) {
1633
+ console.log(`Usage:
1634
+ dawn sdk doctor`);
1635
+ return;
1636
+ }
1637
+ const [subcommand] = args;
1638
+ if (!subcommand) {
1639
+ throw new Error('Missing sdk command. Run: dawn sdk doctor');
1640
+ }
1641
+ if (subcommand === 'doctor') {
1642
+ const result = await new Promise((resolve) => {
1643
+ const child = spawn('dawnsdk', ['doctor'], {
1644
+ stdio: ['ignore', 'pipe', 'pipe'],
1645
+ });
1646
+ let stdout = '';
1647
+ let stderr = '';
1648
+ child.stdout.on('data', (data) => { stdout += data.toString(); });
1649
+ child.stderr.on('data', (data) => { stderr += data.toString(); });
1650
+ child.on('close', (code) => { resolve({ code: code ?? 1, stdout, stderr }); });
1651
+ child.on('error', (error) => {
1652
+ resolve({
1653
+ code: 1,
1654
+ stdout: '',
1655
+ stderr: error instanceof Error ? error.message : String(error),
1656
+ });
1657
+ });
1658
+ });
1659
+ if (result.code !== 0) {
1660
+ throw new Error(`Failed to run SDK doctor. ${result.stderr.trim() || result.stdout.trim()}\nInstall locally from repo: cd py/sdk && uv tool install --from . dawnai-sdk --force`);
1661
+ }
1662
+ const output = result.stdout.trim();
1663
+ if (output) {
1664
+ console.log(output);
1665
+ }
1666
+ else {
1667
+ console.log('SDK doctor completed successfully.');
1668
+ }
1669
+ return;
1670
+ }
1671
+ throw new Error(`Unknown sdk command: ${subcommand}`);
1672
+ }
1457
1673
  async function handleUpdate() {
1458
1674
  console.log('Checking for updates...');
1459
1675
  const result = await new Promise((resolve) => {
@@ -1499,6 +1715,10 @@ async function main() {
1499
1715
  await handleAccount(args);
1500
1716
  return;
1501
1717
  }
1718
+ if (cmd === 'wallet') {
1719
+ await handleWallet(args);
1720
+ return;
1721
+ }
1502
1722
  if (cmd === 'strategy') {
1503
1723
  await handleStrategy(args);
1504
1724
  return;
@@ -1511,6 +1731,10 @@ async function main() {
1511
1731
  await handleSkill(args);
1512
1732
  return;
1513
1733
  }
1734
+ if (cmd === 'sdk') {
1735
+ await handleSdk(args);
1736
+ return;
1737
+ }
1514
1738
  if (cmd === 'update') {
1515
1739
  await handleUpdate();
1516
1740
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dawnai/cli",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "User-facing Dawn CLI",
6
6
  "license": "MIT",
package/postinstall.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import fs from 'node:fs/promises';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
+ import { spawn } from 'node:child_process';
6
7
  import { fileURLToPath } from 'node:url';
7
8
 
8
9
  // Only show the banner for global installs (skip when installing as a dependency).
@@ -40,6 +41,73 @@ async function installDefaultClaudeSkill() {
40
41
  return { status: 'installed', path: destinationSkillPath };
41
42
  }
42
43
 
44
+ function runCommand(command, args) {
45
+ return new Promise((resolve) => {
46
+ const child = spawn(command, args, {
47
+ stdio: ['ignore', 'pipe', 'pipe'],
48
+ });
49
+ let stdout = '';
50
+ let stderr = '';
51
+ child.stdout.on('data', (data) => { stdout += data.toString(); });
52
+ child.stderr.on('data', (data) => { stderr += data.toString(); });
53
+ child.on('close', (code) => {
54
+ resolve({
55
+ code: code ?? 1,
56
+ stdout: stdout.trim(),
57
+ stderr: stderr.trim(),
58
+ });
59
+ });
60
+ child.on('error', (error) => {
61
+ resolve({
62
+ code: 1,
63
+ stdout: '',
64
+ stderr: error instanceof Error ? error.message : String(error),
65
+ });
66
+ });
67
+ });
68
+ }
69
+
70
+ async function installLocalSdkExecutable() {
71
+ const currentFilePath = fileURLToPath(import.meta.url);
72
+ const currentDir = path.dirname(currentFilePath);
73
+ const sdkPath = path.resolve(currentDir, '..', 'py', 'sdk');
74
+
75
+ try {
76
+ await fs.access(path.join(sdkPath, 'pyproject.toml'));
77
+ } catch {
78
+ return {
79
+ status: 'missing',
80
+ message:
81
+ 'Local SDK source not found (expected ../py/sdk). Skipping SDK executable bootstrap.',
82
+ };
83
+ }
84
+
85
+ // Preferred path: uv tool install from local sdk package.
86
+ const uvInstall = await runCommand('uv', [
87
+ 'tool',
88
+ 'install',
89
+ '--from',
90
+ sdkPath,
91
+ 'dawnai-sdk',
92
+ '--force',
93
+ ]);
94
+ if (uvInstall.code === 0) {
95
+ return {
96
+ status: 'installed',
97
+ message: `Installed Dawn SDK executable from local source: ${sdkPath}`,
98
+ };
99
+ }
100
+
101
+ return {
102
+ status: 'failed',
103
+ message: [
104
+ 'Could not auto-install Dawn SDK executable from local source using uv.',
105
+ `uv error: ${uvInstall.stderr || uvInstall.stdout || 'unknown error'}`,
106
+ `Manual setup: cd "${sdkPath}" && uv tool install --from . dawnai-sdk --force`,
107
+ ].join('\n '),
108
+ };
109
+ }
110
+
43
111
  let skillInstallMessage = '';
44
112
  try {
45
113
  const result = await installDefaultClaudeSkill();
@@ -53,16 +121,33 @@ try {
53
121
  skillInstallMessage = `\n Note: could not auto-install default Claude skill (${message}).\n`;
54
122
  }
55
123
 
124
+ let sdkInstallMessage = '';
125
+ try {
126
+ const result = await installLocalSdkExecutable();
127
+ if (result.status === 'installed') {
128
+ sdkInstallMessage = `\n SDK bootstrap:\n ${result.message}\n`;
129
+ } else if (result.status === 'missing') {
130
+ sdkInstallMessage = `\n SDK bootstrap:\n ${result.message}\n`;
131
+ } else {
132
+ sdkInstallMessage = `\n SDK bootstrap warning:\n ${result.message}\n`;
133
+ }
134
+ } catch (error) {
135
+ const message = error instanceof Error ? error.message : String(error);
136
+ sdkInstallMessage = `\n SDK bootstrap warning:\n Unexpected error: ${message}\n`;
137
+ }
138
+
56
139
  console.log(`
57
140
  @dawnai/cli installed successfully.
58
141
 
59
142
  Get started:
60
143
  dawn --version Check installed version
61
144
  dawn auth login Authenticate (opens browser)
145
+ dawn sdk doctor Verify local SDK executable
62
146
  dawn skill install Install all bundled Claude Code skills
63
147
  dawn --help Show all commands
64
148
 
65
149
  ${skillInstallMessage}
150
+ ${sdkInstallMessage}
66
151
 
67
152
  Headless / CI / agent environments:
68
153
  export DAWN_JWT_TOKEN="<your-token>"