@antseed/cli 0.1.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.
Files changed (179) hide show
  1. package/.env.example +15 -0
  2. package/README.md +169 -0
  3. package/dist/cli/commands/balance.d.ts +3 -0
  4. package/dist/cli/commands/balance.d.ts.map +1 -0
  5. package/dist/cli/commands/balance.js +64 -0
  6. package/dist/cli/commands/balance.js.map +1 -0
  7. package/dist/cli/commands/browse.d.ts +7 -0
  8. package/dist/cli/commands/browse.d.ts.map +1 -0
  9. package/dist/cli/commands/browse.js +100 -0
  10. package/dist/cli/commands/browse.js.map +1 -0
  11. package/dist/cli/commands/config.d.ts +20 -0
  12. package/dist/cli/commands/config.d.ts.map +1 -0
  13. package/dist/cli/commands/config.js +239 -0
  14. package/dist/cli/commands/config.js.map +1 -0
  15. package/dist/cli/commands/connect.d.ts +14 -0
  16. package/dist/cli/commands/connect.d.ts.map +1 -0
  17. package/dist/cli/commands/connect.js +298 -0
  18. package/dist/cli/commands/connect.js.map +1 -0
  19. package/dist/cli/commands/connect.test.d.ts +2 -0
  20. package/dist/cli/commands/connect.test.d.ts.map +1 -0
  21. package/dist/cli/commands/connect.test.js +54 -0
  22. package/dist/cli/commands/connect.test.js.map +1 -0
  23. package/dist/cli/commands/dashboard.d.ts +6 -0
  24. package/dist/cli/commands/dashboard.d.ts.map +1 -0
  25. package/dist/cli/commands/dashboard.js +48 -0
  26. package/dist/cli/commands/dashboard.js.map +1 -0
  27. package/dist/cli/commands/deposit.d.ts +3 -0
  28. package/dist/cli/commands/deposit.d.ts.map +1 -0
  29. package/dist/cli/commands/deposit.js +48 -0
  30. package/dist/cli/commands/deposit.js.map +1 -0
  31. package/dist/cli/commands/dev.d.ts +3 -0
  32. package/dist/cli/commands/dev.d.ts.map +1 -0
  33. package/dist/cli/commands/dev.js +94 -0
  34. package/dist/cli/commands/dev.js.map +1 -0
  35. package/dist/cli/commands/init.d.ts +3 -0
  36. package/dist/cli/commands/init.d.ts.map +1 -0
  37. package/dist/cli/commands/init.js +91 -0
  38. package/dist/cli/commands/init.js.map +1 -0
  39. package/dist/cli/commands/plugin-create.d.ts +11 -0
  40. package/dist/cli/commands/plugin-create.d.ts.map +1 -0
  41. package/dist/cli/commands/plugin-create.js +201 -0
  42. package/dist/cli/commands/plugin-create.js.map +1 -0
  43. package/dist/cli/commands/plugin-create.test.d.ts +2 -0
  44. package/dist/cli/commands/plugin-create.test.d.ts.map +1 -0
  45. package/dist/cli/commands/plugin-create.test.js +53 -0
  46. package/dist/cli/commands/plugin-create.test.js.map +1 -0
  47. package/dist/cli/commands/plugin.d.ts +3 -0
  48. package/dist/cli/commands/plugin.d.ts.map +1 -0
  49. package/dist/cli/commands/plugin.js +279 -0
  50. package/dist/cli/commands/plugin.js.map +1 -0
  51. package/dist/cli/commands/plugin.test.d.ts +2 -0
  52. package/dist/cli/commands/plugin.test.d.ts.map +1 -0
  53. package/dist/cli/commands/plugin.test.js +53 -0
  54. package/dist/cli/commands/plugin.test.js.map +1 -0
  55. package/dist/cli/commands/profile.d.ts +10 -0
  56. package/dist/cli/commands/profile.d.ts.map +1 -0
  57. package/dist/cli/commands/profile.js +89 -0
  58. package/dist/cli/commands/profile.js.map +1 -0
  59. package/dist/cli/commands/seed.d.ts +11 -0
  60. package/dist/cli/commands/seed.d.ts.map +1 -0
  61. package/dist/cli/commands/seed.js +397 -0
  62. package/dist/cli/commands/seed.js.map +1 -0
  63. package/dist/cli/commands/seed.test.d.ts +2 -0
  64. package/dist/cli/commands/seed.test.d.ts.map +1 -0
  65. package/dist/cli/commands/seed.test.js +57 -0
  66. package/dist/cli/commands/seed.test.js.map +1 -0
  67. package/dist/cli/commands/status.d.ts +8 -0
  68. package/dist/cli/commands/status.d.ts.map +1 -0
  69. package/dist/cli/commands/status.js +55 -0
  70. package/dist/cli/commands/status.js.map +1 -0
  71. package/dist/cli/commands/types.d.ts +14 -0
  72. package/dist/cli/commands/types.d.ts.map +1 -0
  73. package/dist/cli/commands/types.js +41 -0
  74. package/dist/cli/commands/types.js.map +1 -0
  75. package/dist/cli/commands/withdraw.d.ts +3 -0
  76. package/dist/cli/commands/withdraw.d.ts.map +1 -0
  77. package/dist/cli/commands/withdraw.js +48 -0
  78. package/dist/cli/commands/withdraw.js.map +1 -0
  79. package/dist/cli/formatters.d.ts +29 -0
  80. package/dist/cli/formatters.d.ts.map +1 -0
  81. package/dist/cli/formatters.js +67 -0
  82. package/dist/cli/formatters.js.map +1 -0
  83. package/dist/cli/index.d.ts +3 -0
  84. package/dist/cli/index.d.ts.map +1 -0
  85. package/dist/cli/index.js +41 -0
  86. package/dist/cli/index.js.map +1 -0
  87. package/dist/cli/shutdown.d.ts +11 -0
  88. package/dist/cli/shutdown.d.ts.map +1 -0
  89. package/dist/cli/shutdown.js +34 -0
  90. package/dist/cli/shutdown.js.map +1 -0
  91. package/dist/config/defaults.d.ts +6 -0
  92. package/dist/config/defaults.d.ts.map +1 -0
  93. package/dist/config/defaults.js +48 -0
  94. package/dist/config/defaults.js.map +1 -0
  95. package/dist/config/effective.d.ts +26 -0
  96. package/dist/config/effective.d.ts.map +1 -0
  97. package/dist/config/effective.js +84 -0
  98. package/dist/config/effective.js.map +1 -0
  99. package/dist/config/effective.test.d.ts +2 -0
  100. package/dist/config/effective.test.d.ts.map +1 -0
  101. package/dist/config/effective.test.js +65 -0
  102. package/dist/config/effective.test.js.map +1 -0
  103. package/dist/config/loader.d.ts +12 -0
  104. package/dist/config/loader.d.ts.map +1 -0
  105. package/dist/config/loader.js +212 -0
  106. package/dist/config/loader.js.map +1 -0
  107. package/dist/config/loader.test.d.ts +2 -0
  108. package/dist/config/loader.test.d.ts.map +1 -0
  109. package/dist/config/loader.test.js +77 -0
  110. package/dist/config/loader.test.js.map +1 -0
  111. package/dist/config/types.d.ts +133 -0
  112. package/dist/config/types.d.ts.map +1 -0
  113. package/dist/config/types.js +2 -0
  114. package/dist/config/types.js.map +1 -0
  115. package/dist/config/validation.d.ts +10 -0
  116. package/dist/config/validation.d.ts.map +1 -0
  117. package/dist/config/validation.js +50 -0
  118. package/dist/config/validation.js.map +1 -0
  119. package/dist/env/load-env.d.ts +6 -0
  120. package/dist/env/load-env.d.ts.map +1 -0
  121. package/dist/env/load-env.js +18 -0
  122. package/dist/env/load-env.js.map +1 -0
  123. package/dist/plugins/loader.d.ts +7 -0
  124. package/dist/plugins/loader.d.ts.map +1 -0
  125. package/dist/plugins/loader.js +70 -0
  126. package/dist/plugins/loader.js.map +1 -0
  127. package/dist/plugins/manager.d.ts +11 -0
  128. package/dist/plugins/manager.d.ts.map +1 -0
  129. package/dist/plugins/manager.js +52 -0
  130. package/dist/plugins/manager.js.map +1 -0
  131. package/dist/plugins/registry.d.ts +8 -0
  132. package/dist/plugins/registry.d.ts.map +1 -0
  133. package/dist/plugins/registry.js +39 -0
  134. package/dist/plugins/registry.js.map +1 -0
  135. package/dist/proxy/buyer-proxy.d.ts +30 -0
  136. package/dist/proxy/buyer-proxy.d.ts.map +1 -0
  137. package/dist/proxy/buyer-proxy.js +488 -0
  138. package/dist/proxy/buyer-proxy.js.map +1 -0
  139. package/dist/status/node-status.d.ts +22 -0
  140. package/dist/status/node-status.d.ts.map +1 -0
  141. package/dist/status/node-status.js +83 -0
  142. package/dist/status/node-status.js.map +1 -0
  143. package/package.json +39 -0
  144. package/src/cli/commands/balance.ts +77 -0
  145. package/src/cli/commands/browse.ts +113 -0
  146. package/src/cli/commands/config.ts +271 -0
  147. package/src/cli/commands/connect.test.ts +69 -0
  148. package/src/cli/commands/connect.ts +342 -0
  149. package/src/cli/commands/dashboard.ts +59 -0
  150. package/src/cli/commands/deposit.ts +61 -0
  151. package/src/cli/commands/dev.ts +107 -0
  152. package/src/cli/commands/init.ts +99 -0
  153. package/src/cli/commands/plugin-create.test.ts +60 -0
  154. package/src/cli/commands/plugin-create.ts +230 -0
  155. package/src/cli/commands/plugin.test.ts +55 -0
  156. package/src/cli/commands/plugin.ts +295 -0
  157. package/src/cli/commands/profile.ts +95 -0
  158. package/src/cli/commands/seed.test.ts +70 -0
  159. package/src/cli/commands/seed.ts +447 -0
  160. package/src/cli/commands/status.ts +73 -0
  161. package/src/cli/commands/types.ts +56 -0
  162. package/src/cli/commands/withdraw.ts +61 -0
  163. package/src/cli/formatters.ts +64 -0
  164. package/src/cli/index.ts +46 -0
  165. package/src/cli/shutdown.ts +38 -0
  166. package/src/config/defaults.ts +49 -0
  167. package/src/config/effective.test.ts +80 -0
  168. package/src/config/effective.ts +119 -0
  169. package/src/config/loader.test.ts +95 -0
  170. package/src/config/loader.ts +251 -0
  171. package/src/config/types.ts +139 -0
  172. package/src/config/validation.ts +78 -0
  173. package/src/env/load-env.ts +20 -0
  174. package/src/plugins/loader.ts +96 -0
  175. package/src/plugins/manager.ts +66 -0
  176. package/src/plugins/registry.ts +45 -0
  177. package/src/proxy/buyer-proxy.ts +604 -0
  178. package/src/status/node-status.ts +105 -0
  179. package/tsconfig.json +9 -0
package/.env.example ADDED
@@ -0,0 +1,15 @@
1
+ # Enable verbose runtime logs across packages (0/1)
2
+ ANTSEED_DEBUG=0
3
+
4
+ # Dashboard frontend debug logs (0/1)
5
+ VITE_ANTSEED_DEBUG=0
6
+
7
+ # Optional: override env file path for runtime env loading
8
+ # ANTSEED_ENV_FILE=.env
9
+
10
+ # Settlement runtime (requires config.payments.crypto in config.json)
11
+ # ANTSEED_ENABLE_SETTLEMENT=true
12
+ # ANTSEED_SETTLEMENT_IDLE_MS=30000
13
+ # ANTSEED_DEFAULT_ESCROW_USDC=1
14
+ # ANTSEED_AUTO_FUND_ESCROW=true
15
+ # ANTSEED_SELLER_WALLET_ADDRESS=0x...
package/README.md ADDED
@@ -0,0 +1,169 @@
1
+ # Antseed CLI + Dashboard
2
+
3
+ Command-line interface and web dashboard for the Antseed Network -- a P2P marketplace for reselling idle LLM plan capacity.
4
+
5
+ ## Commands
6
+
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `antseed init` | Install trusted provider and router plugins |
10
+ | `antseed seed` | Start seeding your idle LLM capacity to the P2P network |
11
+ | `antseed connect` | Start the buyer proxy and connect to sellers |
12
+ | `antseed plugin add <pkg>` | Install a provider or router plugin from npm |
13
+ | `antseed plugin remove <name>` | Remove an installed plugin |
14
+ | `antseed plugin list` | List installed plugins |
15
+ | `antseed status` | Show current node status |
16
+ | `antseed config` | Manage configuration (`show`, `set`, `seller show/set`, `buyer show/set`, `init`) |
17
+ | `antseed dashboard` | Start the web dashboard for monitoring and configuration |
18
+ | `antseed dev` | Run seller + buyer locally for development and testing |
19
+ | `antseed browse` | Browse available models, prices, and reputation on the network |
20
+
21
+ ## Plugins
22
+
23
+ Antseed uses an open plugin ecosystem. Plugins are installed into `~/.antseed/plugins/` via npm.
24
+
25
+ **Providers** connect your node to an upstream AI API (seeder mode):
26
+
27
+ ```bash
28
+ antseed plugin add @antseed/provider-anthropic # API key auth
29
+ antseed plugin add @antseed/provider-claude-code # Claude Code keychain auth
30
+ antseed seed --provider anthropic
31
+ ```
32
+
33
+ **Routers** select peers and proxy requests (consumer mode):
34
+
35
+ ```bash
36
+ antseed plugin add @antseed/router-local-proxy
37
+ antseed connect --router local-proxy
38
+ ```
39
+
40
+ Run `antseed init` to install all trusted plugins interactively.
41
+
42
+ ## Configuration
43
+
44
+ Configuration is stored at `~/.antseed/config.json` by default. Use `-c` / `--config` to specify an alternative path.
45
+
46
+ Runtime env variables are loaded via `dotenv` from `.env.local` and `.env` in the current working directory.
47
+ See `.env.example` for supported keys.
48
+
49
+ Enable debug logs with either:
50
+
51
+ ```bash
52
+ antseed -v <command>
53
+ ```
54
+
55
+ or:
56
+
57
+ ```bash
58
+ ANTSEED_DEBUG=1 antseed <command>
59
+ ```
60
+
61
+ For dashboard frontend debug logging, set:
62
+
63
+ ```bash
64
+ VITE_ANTSEED_DEBUG=1
65
+ ```
66
+
67
+ Initialize a new config:
68
+
69
+ ```bash
70
+ antseed config init
71
+ ```
72
+
73
+ Pricing is configured in USD per 1M tokens with role-specific defaults and optional provider/model overrides:
74
+
75
+ ```json
76
+ {
77
+ "seller": {
78
+ "pricing": {
79
+ "defaults": {
80
+ "inputUsdPerMillion": 10,
81
+ "outputUsdPerMillion": 10
82
+ },
83
+ "providers": {
84
+ "anthropic": {
85
+ "models": {
86
+ "claude-sonnet-4-5-20250929": {
87
+ "inputUsdPerMillion": 12,
88
+ "outputUsdPerMillion": 18
89
+ }
90
+ }
91
+ }
92
+ }
93
+ }
94
+ },
95
+ "buyer": {
96
+ "preferredProviders": ["anthropic", "openai"],
97
+ "maxPricing": {
98
+ "defaults": {
99
+ "inputUsdPerMillion": 100,
100
+ "outputUsdPerMillion": 100
101
+ }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ Role-first config examples:
108
+
109
+ ```bash
110
+ # Seller defaults
111
+ antseed config seller set pricing.defaults.inputUsdPerMillion 12
112
+ antseed config seller set pricing.defaults.outputUsdPerMillion 36
113
+
114
+ # Seller per-model override for a provider
115
+ antseed config seller set pricing.providers.anthropic.models '{"claude-sonnet-4-5-20250929":{"inputUsdPerMillion":14,"outputUsdPerMillion":42}}'
116
+
117
+ # Buyer preferences and max pricing
118
+ antseed config buyer set preferredProviders '["anthropic","openai"]'
119
+ antseed config buyer set maxPricing.defaults.inputUsdPerMillion 25
120
+ antseed config buyer set maxPricing.defaults.outputUsdPerMillion 75
121
+ ```
122
+
123
+ Runtime-only overrides (do not write your config file):
124
+
125
+ ```bash
126
+ antseed seed --provider anthropic --input-usd-per-million 10 --output-usd-per-million 30
127
+ antseed connect --router local-proxy --max-input-usd-per-million 20 --max-output-usd-per-million 60
128
+ ```
129
+
130
+ ## Settlement Runtime (Seeder)
131
+
132
+ `antseed seed` can enable automatic session settlement when payment config is present.
133
+ `antseed connect` can also enable buyer-side escrow/session locking with the same payment config.
134
+
135
+ Common runtime env controls:
136
+ - `ANTSEED_ENABLE_SETTLEMENT=true|false`
137
+ - `ANTSEED_SETTLEMENT_IDLE_MS=30000`
138
+ - `ANTSEED_DEFAULT_ESCROW_USDC=1`
139
+ - `ANTSEED_AUTO_FUND_ESCROW=true|false`
140
+ - `ANTSEED_SELLER_WALLET_ADDRESS=0x...`
141
+
142
+ Crypto settlement also requires `config.payments.crypto` values in your config file:
143
+ - `chainId` (`base` or `arbitrum`)
144
+ - `rpcUrl`
145
+ - `escrowContractAddress`
146
+ - `usdcContractAddress`
147
+
148
+ If `ANTSEED_ENABLE_SETTLEMENT` is not explicitly set and the RPC endpoint is unreachable,
149
+ the CLI now auto-disables settlement for that run and logs a warning instead of looping RPC network-detection errors.
150
+ Set `ANTSEED_ENABLE_SETTLEMENT=true` to force-enable settlement checks.
151
+
152
+ Runtime behavior:
153
+ - session opens -> optional escrow deposit
154
+ - session finalizes -> exact on-chain split settlement (`seller payout + platform fee + buyer refund remainder`)
155
+ - no receipts -> escrow refund path
156
+
157
+ Provider-specific options are configured via each plugin's config schema (see `antseed plugin add --help`).
158
+
159
+ ## Development
160
+
161
+ ```bash
162
+ npm install
163
+ npm run build
164
+ npm run dev
165
+ ```
166
+
167
+ ## Links
168
+
169
+ - Node SDK: `@antseed/node` (`../node`)
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerBalanceCommand(program: Command): void;
3
+ //# sourceMappingURL=balance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/balance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBzC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyD7D"}
@@ -0,0 +1,64 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { getGlobalOptions } from './types.js';
4
+ import { loadConfig } from '../../config/loader.js';
5
+ import { loadOrCreateIdentity, BaseEscrowClient, identityToEvmAddress, } from '@antseed/node';
6
+ /** Format USDC base units (6 decimals) to human-readable string. */
7
+ function formatUsdc(baseUnits) {
8
+ const whole = baseUnits / 1000000n;
9
+ const frac = baseUnits % 1000000n;
10
+ const fracStr = frac.toString().padStart(6, '0').replace(/0+$/, '') || '0';
11
+ return `${whole}.${fracStr}`;
12
+ }
13
+ export function registerBalanceCommand(program) {
14
+ program
15
+ .command('balance')
16
+ .description('Show escrow balance for your wallet')
17
+ .option('--json', 'output as JSON', false)
18
+ .action(async (options) => {
19
+ const globalOpts = getGlobalOptions(program);
20
+ const config = await loadConfig(globalOpts.config);
21
+ const payments = config.payments;
22
+ if (!payments?.crypto) {
23
+ console.error(chalk.red('Error: No crypto payment configuration found.'));
24
+ console.error(chalk.dim('Configure payments.crypto in your config file or run: antseed init'));
25
+ process.exit(1);
26
+ }
27
+ const identity = await loadOrCreateIdentity(globalOpts.dataDir);
28
+ const address = identityToEvmAddress(identity);
29
+ const escrowClient = new BaseEscrowClient({
30
+ rpcUrl: payments.crypto.rpcUrl,
31
+ contractAddress: payments.crypto.escrowContractAddress,
32
+ usdcAddress: payments.crypto.usdcContractAddress,
33
+ });
34
+ const spinner = ora('Fetching balance...').start();
35
+ try {
36
+ const account = await escrowClient.getBuyerAccount(address);
37
+ const usdcBalance = await escrowClient.getUSDCBalance(address);
38
+ spinner.stop();
39
+ if (options.json) {
40
+ console.log(JSON.stringify({
41
+ address,
42
+ walletUSDC: formatUsdc(usdcBalance),
43
+ escrowDeposited: formatUsdc(account.deposited),
44
+ escrowCommitted: formatUsdc(account.committed),
45
+ escrowAvailable: formatUsdc(account.available),
46
+ }, null, 2));
47
+ return;
48
+ }
49
+ console.log(chalk.bold('Wallet: ') + chalk.cyan(address));
50
+ console.log('');
51
+ console.log(chalk.bold('USDC Balance (wallet): ') + chalk.green(formatUsdc(usdcBalance) + ' USDC'));
52
+ console.log('');
53
+ console.log(chalk.bold('Escrow Account:'));
54
+ console.log(` Deposited: ${chalk.green(formatUsdc(account.deposited) + ' USDC')}`);
55
+ console.log(` Committed: ${chalk.yellow(formatUsdc(account.committed) + ' USDC')}`);
56
+ console.log(` Available: ${chalk.green(formatUsdc(account.available) + ' USDC')}`);
57
+ }
58
+ catch (err) {
59
+ spinner.fail(chalk.red(`Failed to fetch balance: ${err.message}`));
60
+ process.exit(1);
61
+ }
62
+ });
63
+ }
64
+ //# sourceMappingURL=balance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"balance.js","sourceRoot":"","sources":["../../../src/cli/commands/balance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Command } from 'commander';
2
+ /**
3
+ * Register the `antseed browse` command on the Commander program.
4
+ * Discovers peers on the network and displays available models, prices, and reputation.
5
+ */
6
+ export declare function registerBrowseCommand(program: Command): void;
7
+ //# sourceMappingURL=browse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browse.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/browse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBzC;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyF5D"}
@@ -0,0 +1,100 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import Table from 'cli-table3';
4
+ import { getGlobalOptions } from './types.js';
5
+ import { loadConfig } from '../../config/loader.js';
6
+ import { AntseedNode } from '@antseed/node';
7
+ import { parseBootstrapList, toBootstrapConfig } from '@antseed/node/discovery';
8
+ function getReputationColor(reputation) {
9
+ if (reputation >= 80) {
10
+ return chalk.green;
11
+ }
12
+ if (reputation >= 50) {
13
+ return chalk.yellow;
14
+ }
15
+ return chalk.red;
16
+ }
17
+ /**
18
+ * Register the `antseed browse` command on the Commander program.
19
+ * Discovers peers on the network and displays available models, prices, and reputation.
20
+ */
21
+ export function registerBrowseCommand(program) {
22
+ program
23
+ .command('browse')
24
+ .description('Browse available models, prices, and reputation on the P2P network')
25
+ .option('-m, --model <model>', 'filter by model name')
26
+ .option('--json', 'output as JSON', false)
27
+ .action(async (options) => {
28
+ const globalOpts = getGlobalOptions(program);
29
+ const config = await loadConfig(globalOpts.config);
30
+ const bootstrapNodes = config.network.bootstrapNodes.length > 0
31
+ ? toBootstrapConfig(parseBootstrapList(config.network.bootstrapNodes))
32
+ : undefined;
33
+ const spinner = ora('Discovering peers on the network...').start();
34
+ const node = new AntseedNode({
35
+ role: 'buyer',
36
+ bootstrapNodes,
37
+ });
38
+ try {
39
+ await node.start();
40
+ }
41
+ catch (err) {
42
+ spinner.fail(chalk.red(`Failed to connect to network: ${err.message}`));
43
+ process.exit(1);
44
+ }
45
+ try {
46
+ const peers = await node.discoverPeers(options.model);
47
+ spinner.succeed(chalk.green(`Found ${peers.length} peer(s)`));
48
+ if (peers.length === 0) {
49
+ console.log(chalk.dim('No peers found. Try again later or check your bootstrap nodes.'));
50
+ await node.stop();
51
+ return;
52
+ }
53
+ if (options.json) {
54
+ console.log(JSON.stringify(peers, null, 2));
55
+ await node.stop();
56
+ return;
57
+ }
58
+ // Display peers in a table
59
+ const table = new Table({
60
+ head: [
61
+ chalk.bold('Peer ID'),
62
+ chalk.bold('Providers'),
63
+ chalk.bold('Input $/1M'),
64
+ chalk.bold('Output $/1M'),
65
+ chalk.bold('Reputation'),
66
+ chalk.bold('Load'),
67
+ ],
68
+ colWidths: [16, 18, 14, 14, 12, 10],
69
+ });
70
+ for (const peer of peers) {
71
+ const reputation = peer.reputationScore ?? 0;
72
+ const repLabel = `${reputation}%`;
73
+ const repColor = getReputationColor(reputation);
74
+ const load = peer.currentLoad !== undefined && peer.maxConcurrency !== undefined
75
+ ? `${peer.currentLoad}/${peer.maxConcurrency}`
76
+ : chalk.dim('n/a');
77
+ table.push([
78
+ chalk.dim(peer.peerId.slice(0, 12) + '...'),
79
+ peer.providers.join(', '),
80
+ peer.defaultInputUsdPerMillion !== undefined
81
+ ? `$${peer.defaultInputUsdPerMillion.toFixed(2)}`
82
+ : chalk.dim('n/a'),
83
+ peer.defaultOutputUsdPerMillion !== undefined
84
+ ? `$${peer.defaultOutputUsdPerMillion.toFixed(2)}`
85
+ : chalk.dim('n/a'),
86
+ repColor(repLabel),
87
+ load,
88
+ ]);
89
+ }
90
+ console.log('');
91
+ console.log(table.toString());
92
+ console.log('');
93
+ }
94
+ catch (err) {
95
+ spinner.fail(chalk.red(`Discovery failed: ${err.message}`));
96
+ }
97
+ await node.stop();
98
+ });
99
+ }
100
+ //# sourceMappingURL=browse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browse.js","sourceRoot":"","sources":["../../../src/cli/commands/browse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Command } from 'commander';
2
+ import type { AntseedConfig, ProviderConfig, ProviderType } from '../../config/types.js';
3
+ /**
4
+ * Register the `antseed config` command and its subcommands.
5
+ */
6
+ export declare function registerConfigCommand(program: Command): void;
7
+ /**
8
+ * Redact sensitive fields (auth values) from config for display.
9
+ */
10
+ export declare function redactConfig(config: AntseedConfig): Record<string, unknown>;
11
+ /**
12
+ * Set a nested config value by dot-separated key path.
13
+ * @example setConfigValue(config, 'seller.reserveFloor', '20')
14
+ */
15
+ export declare function setConfigValue(config: Record<string, unknown>, key: string, value: string): void;
16
+ /**
17
+ * Build a ProviderConfig with default endpoint and auth header for known providers.
18
+ */
19
+ export declare function buildProviderConfig(type: ProviderType, authValue: string, customEndpoint?: string): ProviderConfig;
20
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIzC,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGzF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyI5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAW3E;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA4BhG;AA8CD;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB,cAAc,CAoBhB"}
@@ -0,0 +1,239 @@
1
+ import chalk from 'chalk';
2
+ import { getGlobalOptions } from './types.js';
3
+ import { loadConfig, saveConfig } from '../../config/loader.js';
4
+ import { assertValidConfig } from '../../config/validation.js';
5
+ /**
6
+ * Register the `antseed config` command and its subcommands.
7
+ */
8
+ export function registerConfigCommand(program) {
9
+ const configCmd = program
10
+ .command('config')
11
+ .description('Manage Antseed configuration');
12
+ // antseed config show
13
+ configCmd
14
+ .command('show')
15
+ .description('Display current configuration (credentials redacted)')
16
+ .action(async () => {
17
+ const globalOpts = getGlobalOptions(program);
18
+ const config = await loadConfig(globalOpts.config);
19
+ const redacted = redactConfig(config);
20
+ console.log(JSON.stringify(redacted, null, 2));
21
+ });
22
+ // antseed config set <key> <value>
23
+ configCmd
24
+ .command('set <key> <value>')
25
+ .description('Set a configuration value (e.g., seller.reserveFloor 20)')
26
+ .action(async (key, value) => {
27
+ try {
28
+ const globalOpts = getGlobalOptions(program);
29
+ const config = await loadConfig(globalOpts.config);
30
+ const validKeys = getValidConfigKeys(config);
31
+ if (!validKeys.includes(key)) {
32
+ console.error(chalk.red(`Invalid config key: ${key}`));
33
+ console.error(chalk.dim(`Available keys: ${validKeys.join(', ')}`));
34
+ process.exitCode = 1;
35
+ return;
36
+ }
37
+ setConfigValue(config, key, value);
38
+ assertValidConfig(config);
39
+ await saveConfig(globalOpts.config, config);
40
+ console.log(chalk.green(`Set ${key} = ${value}`));
41
+ }
42
+ catch (err) {
43
+ console.error(chalk.red(`Error: ${err.message}`));
44
+ process.exitCode = 1;
45
+ }
46
+ });
47
+ const sellerCmd = configCmd
48
+ .command('seller')
49
+ .description('Role-scoped seller configuration commands');
50
+ sellerCmd
51
+ .command('show')
52
+ .description('Display seller configuration')
53
+ .action(async () => {
54
+ const globalOpts = getGlobalOptions(program);
55
+ const config = await loadConfig(globalOpts.config);
56
+ console.log(JSON.stringify(config.seller, null, 2));
57
+ });
58
+ sellerCmd
59
+ .command('set <key> <value>')
60
+ .description('Set seller configuration value (e.g., pricing.defaults.inputUsdPerMillion 12)')
61
+ .action(async (key, value) => {
62
+ await setRoleScopedValue(program, 'seller', key, value);
63
+ });
64
+ const buyerCmd = configCmd
65
+ .command('buyer')
66
+ .description('Role-scoped buyer configuration commands');
67
+ buyerCmd
68
+ .command('show')
69
+ .description('Display buyer configuration')
70
+ .action(async () => {
71
+ const globalOpts = getGlobalOptions(program);
72
+ const config = await loadConfig(globalOpts.config);
73
+ console.log(JSON.stringify(config.buyer, null, 2));
74
+ });
75
+ buyerCmd
76
+ .command('set <key> <value>')
77
+ .description('Set buyer configuration value (e.g., preferredProviders [\"anthropic\",\"openai\"])')
78
+ .action(async (key, value) => {
79
+ await setRoleScopedValue(program, 'buyer', key, value);
80
+ });
81
+ // antseed config add-provider
82
+ configCmd
83
+ .command('add-provider')
84
+ .description('Add a new provider credential')
85
+ .requiredOption('-t, --type <type>', 'provider type (anthropic, openai, google, moonshot)')
86
+ .requiredOption('-k, --key <key>', 'API key or auth token')
87
+ .option('-e, --endpoint <url>', 'custom API endpoint URL')
88
+ .action(async (options) => {
89
+ const knownTypes = ['anthropic', 'openai', 'google', 'moonshot'];
90
+ if (!knownTypes.includes(options.type)) {
91
+ console.error(chalk.red(`Unknown provider type: ${options.type}`));
92
+ console.error(chalk.dim(`Known types: ${knownTypes.join(', ')}`));
93
+ process.exitCode = 1;
94
+ return;
95
+ }
96
+ const globalOpts = getGlobalOptions(program);
97
+ const config = await loadConfig(globalOpts.config);
98
+ const provider = buildProviderConfig(options.type, options.key, options.endpoint);
99
+ config.providers.push(provider);
100
+ await saveConfig(globalOpts.config, config);
101
+ console.log(chalk.green(`Added ${options.type} provider`));
102
+ });
103
+ // antseed config remove-provider <type>
104
+ configCmd
105
+ .command('remove-provider <type>')
106
+ .description('Remove a provider credential by type')
107
+ .action(async (type) => {
108
+ const globalOpts = getGlobalOptions(program);
109
+ const config = await loadConfig(globalOpts.config);
110
+ const before = config.providers.length;
111
+ config.providers = config.providers.filter((p) => p.type !== type);
112
+ const removed = before - config.providers.length;
113
+ await saveConfig(globalOpts.config, config);
114
+ if (removed > 0) {
115
+ console.log(chalk.green(`Removed ${removed} ${type} provider(s)`));
116
+ }
117
+ else {
118
+ console.log(chalk.yellow(`No ${type} provider found`));
119
+ }
120
+ });
121
+ // antseed config init
122
+ configCmd
123
+ .command('init')
124
+ .description('Initialize a new config file with defaults')
125
+ .action(async () => {
126
+ const globalOpts = getGlobalOptions(program);
127
+ const { createDefaultConfig } = await import('../../config/defaults.js');
128
+ const config = createDefaultConfig();
129
+ await saveConfig(globalOpts.config, config);
130
+ console.log(chalk.green(`Config initialized at ${globalOpts.config}`));
131
+ });
132
+ }
133
+ /**
134
+ * Redact sensitive fields (auth values) from config for display.
135
+ */
136
+ export function redactConfig(config) {
137
+ const clone = JSON.parse(JSON.stringify(config));
138
+ const providers = clone['providers'];
139
+ for (const provider of providers ?? []) {
140
+ if (provider['authValue']) {
141
+ const val = provider['authValue'];
142
+ provider['authValue'] = val.slice(0, 8) + '...' + val.slice(-4);
143
+ }
144
+ }
145
+ return clone;
146
+ }
147
+ /**
148
+ * Set a nested config value by dot-separated key path.
149
+ * @example setConfigValue(config, 'seller.reserveFloor', '20')
150
+ */
151
+ export function setConfigValue(config, key, value) {
152
+ const parts = key.split('.');
153
+ let current = config;
154
+ for (let i = 0; i < parts.length - 1; i++) {
155
+ const part = parts[i];
156
+ if (typeof current[part] !== 'object' || current[part] === null) {
157
+ throw new Error(`Invalid config key: ${key}`);
158
+ }
159
+ current = current[part];
160
+ }
161
+ const lastKey = parts[parts.length - 1];
162
+ const trimmed = value.trim();
163
+ if ((trimmed.startsWith('{') && trimmed.endsWith('}')) ||
164
+ (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
165
+ try {
166
+ current[lastKey] = JSON.parse(trimmed);
167
+ return;
168
+ }
169
+ catch {
170
+ throw new Error(`Invalid JSON value for ${key}`);
171
+ }
172
+ }
173
+ // Auto-parse numeric scalars
174
+ const numVal = Number(trimmed);
175
+ current[lastKey] = Number.isNaN(numVal) ? value : numVal;
176
+ }
177
+ function getValidConfigKeys(config, prefix = '') {
178
+ const keys = [];
179
+ for (const [k, v] of Object.entries(config)) {
180
+ if (k === 'providers' || k === 'plugins')
181
+ continue;
182
+ const path = prefix ? `${prefix}.${k}` : k;
183
+ if (v && typeof v === 'object' && !Array.isArray(v)) {
184
+ keys.push(...getValidConfigKeys(v, path));
185
+ }
186
+ else {
187
+ keys.push(path);
188
+ }
189
+ }
190
+ return keys;
191
+ }
192
+ async function setRoleScopedValue(program, role, key, value) {
193
+ try {
194
+ const globalOpts = getGlobalOptions(program);
195
+ const config = await loadConfig(globalOpts.config);
196
+ const fullKey = `${role}.${key}`;
197
+ const validKeys = getValidConfigKeys(config);
198
+ if (!validKeys.includes(fullKey)) {
199
+ console.error(chalk.red(`Invalid ${role} config key: ${key}`));
200
+ const scopedKeys = validKeys
201
+ .filter((path) => path.startsWith(`${role}.`))
202
+ .map((path) => path.slice(role.length + 1));
203
+ console.error(chalk.dim(`Available ${role} keys: ${scopedKeys.join(', ')}`));
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ setConfigValue(config, fullKey, value);
208
+ assertValidConfig(config);
209
+ await saveConfig(globalOpts.config, config);
210
+ console.log(chalk.green(`Set ${fullKey} = ${value}`));
211
+ }
212
+ catch (err) {
213
+ console.error(chalk.red(`Error: ${err.message}`));
214
+ process.exitCode = 1;
215
+ }
216
+ }
217
+ /**
218
+ * Build a ProviderConfig with default endpoint and auth header for known providers.
219
+ */
220
+ export function buildProviderConfig(type, authValue, customEndpoint) {
221
+ const defaults = {
222
+ anthropic: { endpoint: 'https://api.anthropic.com', authHeaderName: 'x-api-key' },
223
+ openai: { endpoint: 'https://api.openai.com', authHeaderName: 'Authorization' },
224
+ google: { endpoint: 'https://generativelanguage.googleapis.com', authHeaderName: 'x-goog-api-key' },
225
+ moonshot: { endpoint: 'https://api.moonshot.cn', authHeaderName: 'Authorization' },
226
+ };
227
+ const fallbackDefaults = {
228
+ endpoint: customEndpoint ?? '',
229
+ authHeaderName: 'Authorization',
230
+ };
231
+ const def = defaults[type] ?? fallbackDefaults;
232
+ return {
233
+ type,
234
+ endpoint: customEndpoint ?? def.endpoint,
235
+ authHeaderName: def.authHeaderName,
236
+ authValue,
237
+ };
238
+ }
239
+ //# sourceMappingURL=config.js.map