@prktsol/prkt 1.0.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 (125) hide show
  1. package/.env.devnet.all-protocols.example +18 -0
  2. package/.env.devnet.autonomous.example +16 -0
  3. package/.env.devnet.jupiter.example +16 -0
  4. package/.env.devnet.kamino.example +17 -0
  5. package/.env.devnet.marinade.example +16 -0
  6. package/.env.devnet.orca.example +16 -0
  7. package/.env.devnet.raydium.example +17 -0
  8. package/.env.example +32 -0
  9. package/ARCHITECTURE.md +159 -0
  10. package/CLI.md +509 -0
  11. package/CLI_QUICKSTART.md +108 -0
  12. package/COMPATIBILITY.md +103 -0
  13. package/DEVNET_PROTOCOL_ADDRESSES.md +72 -0
  14. package/README.md +339 -0
  15. package/dist/agent/AgentManager.js +166 -0
  16. package/dist/agent/AgentRuntime.js +92 -0
  17. package/dist/agent/DecisionEngine.js +95 -0
  18. package/dist/agent/MockPriceFeed.js +13 -0
  19. package/dist/agent/intents/types.js +2 -0
  20. package/dist/agent/new-index.js +17 -0
  21. package/dist/agent/policyFactory.js +54 -0
  22. package/dist/agent/registry/AgentRegistry.js +16 -0
  23. package/dist/agent/runner/AgentRunner.js +266 -0
  24. package/dist/agent/strategies/MemoHeartbeatStrategy.js +15 -0
  25. package/dist/agent/strategies/SimpleScriptedTransferStrategy.js +27 -0
  26. package/dist/agent/strategies/TokenRebalancerStrategy.js +35 -0
  27. package/dist/agent/strategies/TreasuryDistributorStrategy.js +29 -0
  28. package/dist/agent/strategies/UniversalDeFiStrategy.js +19 -0
  29. package/dist/agent/types/AgentContext.js +2 -0
  30. package/dist/cli/index.js +1159 -0
  31. package/dist/cli/services/activityStore.js +42 -0
  32. package/dist/cli/services/agentRegistry.js +123 -0
  33. package/dist/cli/services/agentRuntime.js +55 -0
  34. package/dist/cli/services/storagePaths.js +64 -0
  35. package/dist/cli/services/strategyFactory.js +66 -0
  36. package/dist/cli/services/walletCrypto.js +120 -0
  37. package/dist/cli/services/walletRegistry.js +145 -0
  38. package/dist/cli/types.js +2 -0
  39. package/dist/cli/utils/completion.js +62 -0
  40. package/dist/cli/utils/output.js +44 -0
  41. package/dist/config/agentPolicies.js +37 -0
  42. package/dist/config/env.js +249 -0
  43. package/dist/config/policyPresets.js +105 -0
  44. package/dist/core/balances/BalanceService.js +34 -0
  45. package/dist/core/funding/DevnetFundingService.js +105 -0
  46. package/dist/core/idempotency/ExecutionIdempotencyGuard.js +100 -0
  47. package/dist/core/index.js +19 -0
  48. package/dist/core/rpc/RpcClient.js +45 -0
  49. package/dist/core/rpc/RpcFailoverClient.js +97 -0
  50. package/dist/core/tokens/TokenService.js +75 -0
  51. package/dist/core/transactions/PostTransactionVerifier.js +103 -0
  52. package/dist/core/transactions/TransactionService.js +104 -0
  53. package/dist/core/types/services.js +2 -0
  54. package/dist/core/wallet/WalletManager.js +120 -0
  55. package/dist/defi/DeFiCoordinator.js +93 -0
  56. package/dist/defi/DeFiExecutor.js +29 -0
  57. package/dist/defi/DeFiPolicyGuard.js +31 -0
  58. package/dist/defi/adapters/JupiterAdapter.js +25 -0
  59. package/dist/defi/adapters/KaminoAdapter.js +50 -0
  60. package/dist/defi/adapters/MarinadeAdapter.js +25 -0
  61. package/dist/defi/adapters/RaydiumAdapter.js +45 -0
  62. package/dist/defi/kamino/kaminoInstructionCompat.js +24 -0
  63. package/dist/defi/kamino/kaminoLiveConfig.js +60 -0
  64. package/dist/defi/kamino/loadKaminoMarketWithFallback.js +68 -0
  65. package/dist/defi/lp/LpInstructionBuilder.js +2 -0
  66. package/dist/defi/lp/RaydiumLpInstructionBuilder.js +100 -0
  67. package/dist/defi/lp/raydiumDevnetConfig.js +62 -0
  68. package/dist/defi/protocols.js +29 -0
  69. package/dist/defi/types.js +2 -0
  70. package/dist/defi/universal/UniversalDeFiOrchestrator.js +126 -0
  71. package/dist/defi/universal/adapters.js +73 -0
  72. package/dist/defi/universal/index.js +5 -0
  73. package/dist/defi/universal/liveExecutors.js +394 -0
  74. package/dist/defi/universal/types.js +2 -0
  75. package/dist/demo/scenarios/multiAgentDevnetScenario.js +170 -0
  76. package/dist/demo/scripts/runMultiAgentDevnetDemo.js +17 -0
  77. package/dist/dex/JupiterSwapClient.js +59 -0
  78. package/dist/dex/SwapExecutor.js +52 -0
  79. package/dist/index.js +22 -0
  80. package/dist/kora/KoraRpcClient.js +60 -0
  81. package/dist/kora/KoraSigner.js +57 -0
  82. package/dist/kora/gaslessDemo.js +18 -0
  83. package/dist/policy/PolicyGuard.js +158 -0
  84. package/dist/policy/emergencyLock.js +164 -0
  85. package/dist/policy/engine/PolicyEngine.js +237 -0
  86. package/dist/policy/errors.js +10 -0
  87. package/dist/policy/index.js +7 -0
  88. package/dist/policy/sandbox/SandboxExecutor.js +77 -0
  89. package/dist/policy/types/policy.js +2 -0
  90. package/dist/scripts/devnetFunding.js +28 -0
  91. package/dist/scripts/devnetWalletPreflight.js +16 -0
  92. package/dist/scripts/localnetCheck.js +27 -0
  93. package/dist/scripts/managedAgentWallet.js +81 -0
  94. package/dist/scripts/mode.js +6 -0
  95. package/dist/scripts/releaseReadiness.js +93 -0
  96. package/dist/scripts/runAgentUniversalDeFi.js +115 -0
  97. package/dist/scripts/runAutonomousAgentWalletDevnet.js +154 -0
  98. package/dist/scripts/runAutonomousPortfolioDevnet.js +390 -0
  99. package/dist/scripts/runBorrowStrategy.js +35 -0
  100. package/dist/scripts/runDeFiSuite.js +41 -0
  101. package/dist/scripts/runDemoRehearsal.js +111 -0
  102. package/dist/scripts/runDevnetWalletDemo.js +53 -0
  103. package/dist/scripts/runGaslessMemo.js +23 -0
  104. package/dist/scripts/runGaslessWalletDemo.js +60 -0
  105. package/dist/scripts/runKaminoDevnet.js +109 -0
  106. package/dist/scripts/runLpStrategy.js +32 -0
  107. package/dist/scripts/runMarinadeDevnet.js +97 -0
  108. package/dist/scripts/runOrcaLpDevnet.js +208 -0
  109. package/dist/scripts/runRaydiumLpDevnet.js +95 -0
  110. package/dist/scripts/runReleaseReadiness.js +22 -0
  111. package/dist/scripts/runStakeStrategy.js +33 -0
  112. package/dist/scripts/runStressTest.js +41 -0
  113. package/dist/scripts/runTradeLoop.js +53 -0
  114. package/dist/scripts/runUniversalDeFiDemo.js +84 -0
  115. package/dist/scripts/runYieldStrategy.js +33 -0
  116. package/dist/scripts/runtimeFactory.js +27 -0
  117. package/dist/scripts/shared.js +24 -0
  118. package/dist/scripts/simulateAttack.js +40 -0
  119. package/dist/scripts/simulateSwarm.js +106 -0
  120. package/dist/simulation/attack.js +30 -0
  121. package/dist/solana/programs.js +9 -0
  122. package/dist/spl/TokenWallet.js +65 -0
  123. package/dist/types/policy.js +2 -0
  124. package/dist/wallet/WalletManager.js +5 -0
  125. package/package.json +99 -0
@@ -0,0 +1,1159 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const fs_1 = require("fs");
5
+ const spl_token_1 = require("@solana/spl-token");
6
+ const commander_1 = require("commander");
7
+ const web3_js_1 = require("@solana/web3.js");
8
+ const agentRegistry_1 = require("./services/agentRegistry");
9
+ const agentRuntime_1 = require("./services/agentRuntime");
10
+ const activityStore_1 = require("./services/activityStore");
11
+ const storagePaths_1 = require("./services/storagePaths");
12
+ const walletRegistry_1 = require("./services/walletRegistry");
13
+ const walletCrypto_1 = require("./services/walletCrypto");
14
+ const output_1 = require("./utils/output");
15
+ const env_1 = require("../config/env");
16
+ const policyPresets_1 = require("../config/policyPresets");
17
+ const RpcClient_1 = require("../core/rpc/RpcClient");
18
+ const TransactionService_1 = require("../core/transactions/TransactionService");
19
+ const TokenService_1 = require("../core/tokens/TokenService");
20
+ const BalanceService_1 = require("../core/balances/BalanceService");
21
+ const DevnetFundingService_1 = require("../core/funding/DevnetFundingService");
22
+ const multiAgentDevnetScenario_1 = require("../demo/scenarios/multiAgentDevnetScenario");
23
+ const policy_1 = require("../policy");
24
+ const completion_1 = require("./utils/completion");
25
+ const program = new commander_1.Command();
26
+ const walletRegistry = new walletRegistry_1.WalletRegistry();
27
+ const agentRegistry = new agentRegistry_1.AgentRegistryStore(walletRegistry);
28
+ const activityStore = new activityStore_1.ActivityStore();
29
+ const CUSTODY_MODEL = "local-per-user";
30
+ const POLICY_EXECUTION_MODEL = "user-owned agent wallets with policy-guarded execution";
31
+ function outputOptions(command) {
32
+ const options = command.optsWithGlobals();
33
+ return {
34
+ json: Boolean(options.json)
35
+ };
36
+ }
37
+ function activity(kind, details, extra) {
38
+ try {
39
+ activityStore.append({
40
+ createdAtIso: new Date().toISOString(),
41
+ kind,
42
+ details,
43
+ ...extra
44
+ });
45
+ }
46
+ catch (error) {
47
+ const message = error instanceof Error ? error.message : "unknown activity-store error";
48
+ console.error(`Activity log warning: ${message}`);
49
+ }
50
+ }
51
+ function resolveWalletName(entity) {
52
+ const wallet = walletRegistry.find(entity);
53
+ if (wallet) {
54
+ return wallet.name;
55
+ }
56
+ const agent = agentRegistry.find(entity);
57
+ if (agent) {
58
+ return agent.walletName;
59
+ }
60
+ throw new Error(`Unknown wallet/agent '${entity}'.`);
61
+ }
62
+ function resolveAgentRecord(agentId) {
63
+ const agent = agentRegistry.find(agentId);
64
+ if (agent) {
65
+ return agent;
66
+ }
67
+ const wallet = walletRegistry.find(agentId);
68
+ if (wallet) {
69
+ return agentRegistry.ensureForWallet(wallet.name);
70
+ }
71
+ throw new Error(`Unknown agent '${agentId}'.`);
72
+ }
73
+ function parseSol(input) {
74
+ const value = Number(input);
75
+ if (!Number.isFinite(value) || value <= 0) {
76
+ throw new Error("amount must be a positive number");
77
+ }
78
+ return value;
79
+ }
80
+ function parseOptionalCsv(input) {
81
+ if (!input) {
82
+ return undefined;
83
+ }
84
+ const values = input
85
+ .split(",")
86
+ .map((entry) => entry.trim())
87
+ .filter((entry) => entry.length > 0);
88
+ return values.length > 0 ? values : [];
89
+ }
90
+ function parseOptionalPositiveInteger(input, fieldName) {
91
+ if (input === undefined) {
92
+ return undefined;
93
+ }
94
+ const parsed = Number(input);
95
+ if (!Number.isInteger(parsed) || parsed < 0) {
96
+ throw new Error(`${fieldName} must be a non-negative integer`);
97
+ }
98
+ return parsed;
99
+ }
100
+ async function buildServices() {
101
+ const rpcClient = new RpcClient_1.RpcClient((0, env_1.getRpcUrl)(), "confirmed");
102
+ const tokenService = new TokenService_1.TokenService(rpcClient);
103
+ const transactionService = new TransactionService_1.TransactionService(rpcClient);
104
+ const balanceService = new BalanceService_1.BalanceService(rpcClient, tokenService);
105
+ return { balanceService, rpcClient, tokenService, transactionService };
106
+ }
107
+ async function buildOverviewRows() {
108
+ const { balanceService } = await buildServices();
109
+ const agents = agentRegistry.synchronizeWithWallets();
110
+ const rows = [];
111
+ for (const entry of agents) {
112
+ const wallet = walletRegistry.find(entry.walletName);
113
+ if (!wallet) {
114
+ continue;
115
+ }
116
+ const owner = new web3_js_1.PublicKey(wallet.publicKey);
117
+ const sol = await balanceService.getSolBalance(owner);
118
+ const trackedMints = entry.trackedMints ?? [];
119
+ const trackedSpl = [];
120
+ for (const mint of trackedMints) {
121
+ const balance = await balanceService.getSplTokenBalance({
122
+ owner,
123
+ mint: new web3_js_1.PublicKey(mint)
124
+ });
125
+ trackedSpl.push(`${mint.slice(0, 6)}...:${balance.toFixed(4)}`);
126
+ }
127
+ rows.push({
128
+ agent: entry.name,
129
+ lastAction: entry.lastAction ?? "-",
130
+ lastSignature: entry.lastSignature ?? "-",
131
+ policyMode: entry.policyMode,
132
+ sol: sol.toFixed(4),
133
+ status: entry.status,
134
+ trackedSpl: trackedSpl.join(", ") || "-",
135
+ wallet: wallet.publicKey
136
+ });
137
+ }
138
+ return rows;
139
+ }
140
+ program
141
+ .name("prkt")
142
+ .description("PRKT CLI - Solana agentic wallet operations")
143
+ .option("--json", "output machine-readable JSON");
144
+ program
145
+ .command("init")
146
+ .description("initialize local PRKT state for this user install")
147
+ .action((_, command) => {
148
+ const dataDirStatus = (0, storagePaths_1.probeCliDataDir)();
149
+ const payload = {
150
+ cliDataDir: dataDirStatus.path,
151
+ cliDataDirHealth: dataDirStatus.details,
152
+ cliDataDirWritable: dataDirStatus.writable,
153
+ custodyModel: CUSTODY_MODEL,
154
+ masterKeySource: (0, walletCrypto_1.getPlatformMasterKeySource)(),
155
+ policyExecutionModel: POLICY_EXECUTION_MODEL,
156
+ recommendedNextSteps: [
157
+ "Run `prkt config show` to inspect runtime config",
158
+ "Run `prkt wallet create --name <name>` or `prkt agent create --agent <id>` to provision a wallet",
159
+ "Use `prkt policy show --agent <agent>` and `prkt policy set-limits ...` before enabling live execution"
160
+ ]
161
+ };
162
+ activity("config", { action: "init" });
163
+ (0, output_1.printResult)(outputOptions(command), payload, "PRKT initialized");
164
+ });
165
+ const wallet = program.command("wallet").description("wallet management and transfers");
166
+ wallet
167
+ .command("create")
168
+ .requiredOption("--name <name>", "wallet name")
169
+ .description("create a managed wallet")
170
+ .action((options, command) => {
171
+ const created = walletRegistry.create(options.name);
172
+ const agent = agentRegistry.ensureForWallet(options.name);
173
+ activity("wallet", { action: "create", name: options.name, publicKey: created.record.publicKey });
174
+ (0, output_1.printResult)(outputOptions(command), {
175
+ custodyModel: CUSTODY_MODEL,
176
+ dataDir: (0, storagePaths_1.getCliDataDir)(),
177
+ defaultPolicyPreset: agent.policyPreset,
178
+ explorer: (0, output_1.addressExplorer)(created.record.publicKey),
179
+ name: created.record.name,
180
+ publicKey: created.record.publicKey,
181
+ masterKeySource: (0, walletCrypto_1.getPlatformMasterKeySource)(),
182
+ recoveryKey: created.recoveryKey
183
+ }, `Wallet ${options.name} created`);
184
+ });
185
+ wallet
186
+ .command("list")
187
+ .description("list managed wallets")
188
+ .action((_, command) => {
189
+ const wallets = walletRegistry.list().map((entry) => ({
190
+ createdAt: entry.createdAtIso,
191
+ name: entry.name,
192
+ publicKey: entry.publicKey
193
+ }));
194
+ (0, output_1.printResult)(outputOptions(command), wallets, "Managed wallets");
195
+ });
196
+ wallet
197
+ .command("show")
198
+ .requiredOption("--name <name>", "wallet name")
199
+ .description("show wallet details")
200
+ .action((options, command) => {
201
+ const record = walletRegistry.find(options.name);
202
+ if (!record) {
203
+ throw new Error(`Wallet '${options.name}' not found.`);
204
+ }
205
+ (0, output_1.printResult)(outputOptions(command), {
206
+ createdAt: record.createdAtIso,
207
+ explorer: (0, output_1.addressExplorer)(record.publicKey),
208
+ name: record.name,
209
+ publicKey: record.publicKey
210
+ }, `Wallet ${options.name}`);
211
+ });
212
+ wallet
213
+ .command("fund")
214
+ .requiredOption("--name <name>", "wallet name")
215
+ .requiredOption("--sol <amount>", "amount in SOL")
216
+ .description("fund wallet from treasury if configured, otherwise request devnet airdrop")
217
+ .action(async (options, command) => {
218
+ const amountSol = parseSol(options.sol);
219
+ const walletName = resolveWalletName(options.name);
220
+ const walletManager = walletRegistry.toWalletManager(walletName);
221
+ const { balanceService, rpcClient, transactionService } = await buildServices();
222
+ const fundingService = new DevnetFundingService_1.DevnetFundingService(rpcClient, transactionService);
223
+ const funding = await fundingService.fundExactSol({
224
+ amountSol,
225
+ recipient: walletManager.publicKey
226
+ });
227
+ const updatedBalance = await fundingService.waitForMinimumBalance({
228
+ attempts: 15,
229
+ balanceService,
230
+ minimumSol: amountSol,
231
+ recipient: walletManager.publicKey
232
+ });
233
+ activity("wallet", {
234
+ action: "fund",
235
+ amountSol,
236
+ method: funding.source,
237
+ name: options.name
238
+ }, { signature: funding.signature });
239
+ (0, output_1.printResult)(outputOptions(command), {
240
+ amountSol,
241
+ balanceSol: updatedBalance,
242
+ explorer: (0, output_1.txExplorer)(funding.signature),
243
+ signature: funding.signature,
244
+ source: funding.source,
245
+ wallet: walletName
246
+ }, `Wallet ${walletName} funded`);
247
+ });
248
+ wallet
249
+ .command("balance")
250
+ .requiredOption("--name <name>", "wallet name")
251
+ .description("fetch SOL balance")
252
+ .action(async (options, command) => {
253
+ const walletName = resolveWalletName(options.name);
254
+ const walletManager = walletRegistry.toWalletManager(walletName);
255
+ const { balanceService } = await buildServices();
256
+ const sol = await balanceService.getSolBalance(walletManager.publicKey);
257
+ (0, output_1.printResult)(outputOptions(command), {
258
+ balanceSol: sol,
259
+ name: walletName,
260
+ publicKey: walletManager.publicKey.toBase58()
261
+ }, `SOL balance for ${walletName}`);
262
+ });
263
+ wallet
264
+ .command("balance-spl")
265
+ .requiredOption("--name <name>", "wallet name")
266
+ .requiredOption("--mint <mint>", "mint address")
267
+ .description("fetch SPL token balance for wallet")
268
+ .action(async (options, command) => {
269
+ const walletName = resolveWalletName(options.name);
270
+ const walletManager = walletRegistry.toWalletManager(walletName);
271
+ const { balanceService } = await buildServices();
272
+ const mint = new web3_js_1.PublicKey(options.mint);
273
+ const balance = await balanceService.getSplTokenBalance({
274
+ owner: walletManager.publicKey,
275
+ mint
276
+ });
277
+ (0, output_1.printResult)(outputOptions(command), {
278
+ balance,
279
+ mint: mint.toBase58(),
280
+ name: walletName
281
+ }, `SPL balance for ${walletName}`);
282
+ });
283
+ wallet
284
+ .command("export-secret")
285
+ .requiredOption("--name <name>", "wallet name or agent id")
286
+ .requiredOption("--recovery-key <key>", "wallet recovery key")
287
+ .description("decrypt and export the managed wallet secret key")
288
+ .action((options, command) => {
289
+ const walletName = resolveWalletName(options.name);
290
+ const secretKey = Array.from(walletRegistry.exportSecretKeyWithRecovery({
291
+ name: walletName,
292
+ recoveryKey: String(options.recoveryKey)
293
+ }));
294
+ const wallet = walletRegistry.find(walletName);
295
+ (0, output_1.printResult)(outputOptions(command), {
296
+ publicKey: wallet?.publicKey ?? "<missing>",
297
+ secretKey,
298
+ wallet: walletName
299
+ }, `Wallet ${walletName} exported`);
300
+ });
301
+ wallet
302
+ .command("transfer-sol")
303
+ .requiredOption("--from <wallet>", "source wallet name")
304
+ .requiredOption("--to <pubkey>", "destination public key")
305
+ .requiredOption("--amount <amount>", "amount in SOL")
306
+ .description("transfer SOL")
307
+ .action(async (options, command) => {
308
+ const walletManager = walletRegistry.toWalletManager(resolveWalletName(options.from));
309
+ const to = new web3_js_1.PublicKey(options.to);
310
+ const amountSol = parseSol(options.amount);
311
+ const { transactionService } = await buildServices();
312
+ const built = await transactionService.buildTransaction({
313
+ feePayer: walletManager.publicKey,
314
+ instructions: [
315
+ transactionService.buildSolTransferInstructionInSol({
316
+ from: walletManager.publicKey,
317
+ to,
318
+ amountSol
319
+ })
320
+ ],
321
+ signer: walletManager
322
+ });
323
+ const send = await transactionService.sendAndConfirm(built);
324
+ activity("transfer", {
325
+ amountSol,
326
+ from: options.from,
327
+ to: options.to,
328
+ type: "sol"
329
+ }, { signature: send.signature });
330
+ (0, output_1.printResult)(outputOptions(command), {
331
+ amountSol,
332
+ explorer: (0, output_1.txExplorer)(send.signature),
333
+ signature: send.signature
334
+ }, "SOL transfer sent");
335
+ });
336
+ wallet
337
+ .command("transfer-spl")
338
+ .requiredOption("--from <wallet>", "source wallet name")
339
+ .requiredOption("--to <pubkey>", "destination owner public key")
340
+ .requiredOption("--mint <mint>", "mint address")
341
+ .requiredOption("--amount <amount>", "amount in UI units")
342
+ .description("transfer SPL tokens")
343
+ .action(async (options, command) => {
344
+ const walletManager = walletRegistry.toWalletManager(resolveWalletName(options.from));
345
+ const destinationOwner = new web3_js_1.PublicKey(options.to);
346
+ const mint = new web3_js_1.PublicKey(options.mint);
347
+ const amountUi = parseSol(options.amount);
348
+ const { rpcClient, tokenService, transactionService } = await buildServices();
349
+ const mintInfo = await (0, spl_token_1.getMint)(rpcClient.connection, mint, "confirmed");
350
+ const amountRaw = BigInt(Math.round(amountUi * 10 ** mintInfo.decimals));
351
+ const sourceAta = tokenService.findAssociatedTokenAddress(walletManager.publicKey, mint);
352
+ const ensureDestination = await tokenService.ensureAtaInstruction({
353
+ mint,
354
+ owner: destinationOwner,
355
+ payer: walletManager.publicKey
356
+ });
357
+ const instructions = [
358
+ ...(ensureDestination.createInstruction ? [ensureDestination.createInstruction] : []),
359
+ transactionService.buildSplTransferCheckedInstruction({
360
+ sourceAta,
361
+ mint,
362
+ destinationAta: ensureDestination.address,
363
+ owner: walletManager.publicKey,
364
+ amount: amountRaw,
365
+ decimals: mintInfo.decimals
366
+ })
367
+ ];
368
+ const built = await transactionService.buildTransaction({
369
+ feePayer: walletManager.publicKey,
370
+ instructions,
371
+ signer: walletManager
372
+ });
373
+ const send = await transactionService.sendAndConfirm(built);
374
+ activity("transfer", {
375
+ amountRaw: amountRaw.toString(),
376
+ amountUi,
377
+ from: options.from,
378
+ mint: mint.toBase58(),
379
+ to: options.to,
380
+ type: "spl"
381
+ }, { signature: send.signature });
382
+ (0, output_1.printResult)(outputOptions(command), {
383
+ explorer: (0, output_1.txExplorer)(send.signature),
384
+ signature: send.signature
385
+ }, "SPL transfer sent");
386
+ });
387
+ const token = program.command("token").description("SPL token operations");
388
+ token
389
+ .command("mint-demo")
390
+ .requiredOption("--authority <wallet>", "authority wallet name")
391
+ .requiredOption("--decimals <n>", "mint decimals")
392
+ .requiredOption("--amount <amount>", "amount in UI units")
393
+ .description("create demo mint and mint tokens to authority ATA")
394
+ .action(async (options, command) => {
395
+ const authority = walletRegistry.toWalletManager(options.authority);
396
+ const decimals = Number(options.decimals);
397
+ if (!Number.isInteger(decimals) || decimals < 0 || decimals > 9) {
398
+ throw new Error("decimals must be an integer between 0 and 9");
399
+ }
400
+ const amountUi = parseSol(options.amount);
401
+ const { tokenService, transactionService } = await buildServices();
402
+ const mintSetup = await tokenService.buildCreateMintInstructions({
403
+ payer: authority.publicKey,
404
+ mintAuthority: authority.publicKey,
405
+ decimals
406
+ });
407
+ const mintTx = await transactionService.buildTransaction({
408
+ feePayer: authority.publicKey,
409
+ instructions: mintSetup.instructions,
410
+ signer: authority
411
+ });
412
+ mintTx.transaction.sign([mintSetup.mintKeypair]);
413
+ await transactionService.sendAndConfirm(mintTx);
414
+ const authorityAta = await tokenService.ensureAtaInstruction({
415
+ mint: mintSetup.mintKeypair.publicKey,
416
+ owner: authority.publicKey,
417
+ payer: authority.publicKey
418
+ });
419
+ const raw = BigInt(Math.round(amountUi * 10 ** decimals));
420
+ const mintToTx = await transactionService.buildTransaction({
421
+ feePayer: authority.publicKey,
422
+ instructions: [
423
+ ...(authorityAta.createInstruction ? [authorityAta.createInstruction] : []),
424
+ tokenService.buildMintToInstruction({
425
+ mint: mintSetup.mintKeypair.publicKey,
426
+ destinationAta: authorityAta.address,
427
+ authority: authority.publicKey,
428
+ amount: raw
429
+ })
430
+ ],
431
+ signer: authority
432
+ });
433
+ const send = await transactionService.sendAndConfirm(mintToTx);
434
+ activity("token", {
435
+ action: "mint-demo",
436
+ amountRaw: raw.toString(),
437
+ amountUi,
438
+ authority: options.authority,
439
+ decimals,
440
+ mint: mintSetup.mintKeypair.publicKey.toBase58()
441
+ }, { signature: send.signature });
442
+ (0, output_1.printResult)(outputOptions(command), {
443
+ explorer: (0, output_1.txExplorer)(send.signature),
444
+ mint: mintSetup.mintKeypair.publicKey.toBase58(),
445
+ signature: send.signature
446
+ }, "Demo mint created");
447
+ });
448
+ token
449
+ .command("create-ata")
450
+ .requiredOption("--owner <wallet>", "owner wallet name")
451
+ .requiredOption("--mint <mint>", "mint address")
452
+ .description("create ATA if missing")
453
+ .action(async (options, command) => {
454
+ const owner = walletRegistry.toWalletManager(options.owner);
455
+ const mint = new web3_js_1.PublicKey(options.mint);
456
+ const { tokenService, transactionService } = await buildServices();
457
+ const ata = await tokenService.ensureAtaInstruction({
458
+ mint,
459
+ owner: owner.publicKey,
460
+ payer: owner.publicKey
461
+ });
462
+ if (!ata.createInstruction) {
463
+ (0, output_1.printResult)(outputOptions(command), {
464
+ ata: ata.address.toBase58(),
465
+ existed: true
466
+ }, "ATA already exists");
467
+ return;
468
+ }
469
+ const tx = await transactionService.buildTransaction({
470
+ feePayer: owner.publicKey,
471
+ instructions: [ata.createInstruction],
472
+ signer: owner
473
+ });
474
+ const send = await transactionService.sendAndConfirm(tx);
475
+ activity("token", {
476
+ action: "create-ata",
477
+ mint: mint.toBase58(),
478
+ owner: options.owner
479
+ }, { signature: send.signature });
480
+ (0, output_1.printResult)(outputOptions(command), {
481
+ ata: ata.address.toBase58(),
482
+ explorer: (0, output_1.txExplorer)(send.signature),
483
+ signature: send.signature
484
+ }, "ATA created");
485
+ });
486
+ const policy = program.command("policy").description("policy inspection");
487
+ policy
488
+ .command("show")
489
+ .requiredOption("--agent <agent>", "agent name")
490
+ .description("show policy for agent")
491
+ .action((options, command) => {
492
+ const agent = resolveAgentRecord(options.agent);
493
+ const resolved = (0, policyPresets_1.resolvePolicyConfig)({
494
+ agentId: agent.name,
495
+ overrides: agent.policyOverrides,
496
+ presetName: agent.policyPreset ?? policyPresets_1.DEFAULT_POLICY_PRESET
497
+ });
498
+ (0, output_1.printResult)(outputOptions(command), {
499
+ overrides: agent.policyOverrides ?? null,
500
+ policyMode: agent.policyMode,
501
+ preset: agent.policyPreset ?? policyPresets_1.DEFAULT_POLICY_PRESET,
502
+ resolvedConfig: resolved
503
+ }, `Policy for ${agent.name}`);
504
+ });
505
+ policy
506
+ .command("presets")
507
+ .description("list available provider policy presets")
508
+ .action((_, command) => {
509
+ (0, output_1.printResult)(outputOptions(command), (0, policyPresets_1.listPolicyPresetSummaries)(), "Policy presets");
510
+ });
511
+ policy
512
+ .command("set-preset")
513
+ .requiredOption("--agent <agent>", "agent name")
514
+ .requiredOption("--preset <preset>", "preset name")
515
+ .description("assign a provider policy preset to an agent")
516
+ .action((options, command) => {
517
+ const record = resolveAgentRecord(options.agent);
518
+ const preset = options.preset;
519
+ if (!(0, policyPresets_1.listPolicyPresetSummaries)().some((entry) => entry.name === preset)) {
520
+ throw new Error(`Unknown policy preset '${options.preset}'.`);
521
+ }
522
+ const policyMode = preset === "guarded-live" ? "live" : "sandbox";
523
+ const updated = agentRegistry.patch(record.name, {
524
+ policyMode,
525
+ policyPreset: preset
526
+ });
527
+ (0, output_1.printResult)(outputOptions(command), updated, `Policy preset updated for ${record.name}`);
528
+ });
529
+ policy
530
+ .command("set-limits")
531
+ .requiredOption("--agent <agent>", "agent name")
532
+ .option("--approval-mode <mode>", "sandbox or live")
533
+ .option("--max-sol-per-tx-lamports <n>", "max lamports per transaction")
534
+ .option("--max-spl-per-tx-raw <n>", "max raw SPL units per transaction")
535
+ .option("--max-transactions-per-session <n>", "max transactions per session")
536
+ .option("--max-transactions-per-day <n>", "max transactions per day")
537
+ .option("--session-ttl-minutes <n>", "session ttl in minutes")
538
+ .option("--allowed-mints <csv>", "comma-separated allowed mint addresses")
539
+ .option("--allowed-close-destinations <csv>", "comma-separated destinations allowed for token-account close refunds")
540
+ .option("--allowed-destinations <csv>", "comma-separated allowed destination addresses")
541
+ .option("--extra-program-ids <csv>", "comma-separated extra allowed program ids")
542
+ .option("--allow-opaque-program-ids <csv>", "comma-separated opaque programs to allow")
543
+ .option("--deny-unknown-instructions <true|false>", "override unknown-instruction deny behavior")
544
+ .option("--require-simulation-success <true|false>", "override simulation requirement")
545
+ .option("--reject-suspicious-balance-deltas <true|false>", "override suspicious delta rejection")
546
+ .description("set or replace persisted policy overrides for an agent")
547
+ .action((options, command) => {
548
+ const record = resolveAgentRecord(options.agent);
549
+ const approvalMode = options.approvalMode === undefined ? undefined : String(options.approvalMode);
550
+ if (approvalMode !== undefined && approvalMode !== "sandbox" && approvalMode !== "live") {
551
+ throw new Error("--approval-mode must be 'sandbox' or 'live'");
552
+ }
553
+ const updated = agentRegistry.patch(record.name, {
554
+ policyMode: approvalMode ?? record.policyMode,
555
+ policyOverrides: {
556
+ allowOpaqueProgramIds: parseOptionalCsv(options.allowOpaqueProgramIds),
557
+ allowedCloseAccountDestinations: parseOptionalCsv(options.allowedCloseDestinations),
558
+ allowedMints: parseOptionalCsv(options.allowedMints),
559
+ allowedTransferDestinations: parseOptionalCsv(options.allowedDestinations),
560
+ approvalMode: approvalMode,
561
+ denyUnknownInstructionsByDefault: options.denyUnknownInstructions === undefined
562
+ ? undefined
563
+ : String(options.denyUnknownInstructions).toLowerCase() === "true",
564
+ extraAllowedProgramIds: parseOptionalCsv(options.extraProgramIds),
565
+ maxSolPerTxLamports: parseOptionalPositiveInteger(options.maxSolPerTxLamports, "max-sol-per-tx-lamports"),
566
+ maxSplPerTxRawAmount: options.maxSplPerTxRaw
567
+ ? String(BigInt(options.maxSplPerTxRaw))
568
+ : undefined,
569
+ maxTransactionsPerDay: parseOptionalPositiveInteger(options.maxTransactionsPerDay, "max-transactions-per-day"),
570
+ maxTransactionsPerSession: parseOptionalPositiveInteger(options.maxTransactionsPerSession, "max-transactions-per-session"),
571
+ rejectSuspiciousBalanceDeltas: options.rejectSuspiciousBalanceDeltas === undefined
572
+ ? undefined
573
+ : String(options.rejectSuspiciousBalanceDeltas).toLowerCase() === "true",
574
+ requireSimulationSuccess: options.requireSimulationSuccess === undefined
575
+ ? undefined
576
+ : String(options.requireSimulationSuccess).toLowerCase() === "true",
577
+ sessionTtlMinutes: parseOptionalPositiveInteger(options.sessionTtlMinutes, "session-ttl-minutes")
578
+ }
579
+ });
580
+ (0, output_1.printResult)(outputOptions(command), updated, `Policy overrides updated for ${record.name}`);
581
+ });
582
+ policy
583
+ .command("clear-overrides")
584
+ .requiredOption("--agent <agent>", "agent name")
585
+ .description("clear persisted policy overrides for an agent")
586
+ .action((options, command) => {
587
+ const record = resolveAgentRecord(options.agent);
588
+ const updated = agentRegistry.patch(record.name, {
589
+ policyOverrides: undefined
590
+ });
591
+ (0, output_1.printResult)(outputOptions(command), updated, `Policy overrides cleared for ${record.name}`);
592
+ });
593
+ policy
594
+ .command("validate-intent")
595
+ .requiredOption("--agent <agent>", "agent name")
596
+ .requiredOption("--intent-file <file>", "path to intent JSON")
597
+ .description("validate intent-like transaction against policy")
598
+ .action(async (options, command) => {
599
+ const agent = resolveAgentRecord(options.agent);
600
+ const intentRaw = JSON.parse((0, fs_1.readFileSync)(options.intentFile, "utf8"));
601
+ const walletManager = walletRegistry.toWalletManager(agent.walletName);
602
+ const config = (0, policyPresets_1.resolvePolicyConfig)({
603
+ agentId: agent.name,
604
+ overrides: agent.policyOverrides,
605
+ presetName: agent.policyPreset ?? policyPresets_1.DEFAULT_POLICY_PRESET
606
+ });
607
+ const engine = new policy_1.PolicyEngine(config);
608
+ const { tokenService, transactionService } = await buildServices();
609
+ let inspection;
610
+ if (intentRaw.type === "write-memo") {
611
+ const tx = await transactionService.buildTransaction({
612
+ feePayer: walletManager.publicKey,
613
+ instructions: [transactionService.buildMemoInstruction(String(intentRaw.memo ?? ""))],
614
+ signer: walletManager
615
+ });
616
+ inspection = engine.inspect(tx.transaction);
617
+ }
618
+ else if (intentRaw.type === "transfer-sol") {
619
+ const tx = await transactionService.buildTransaction({
620
+ feePayer: walletManager.publicKey,
621
+ instructions: [
622
+ transactionService.buildSolTransferInstruction({
623
+ from: walletManager.publicKey,
624
+ to: new web3_js_1.PublicKey(String(intentRaw.to)),
625
+ lamports: Number(intentRaw.lamports)
626
+ })
627
+ ],
628
+ signer: walletManager
629
+ });
630
+ inspection = engine.inspect(tx.transaction);
631
+ }
632
+ else if (intentRaw.type === "transfer-spl") {
633
+ const mint = new web3_js_1.PublicKey(String(intentRaw.mint));
634
+ const mintDecimals = await tokenService.getMintDecimals(mint);
635
+ const sourceAta = tokenService.findAssociatedTokenAddress(walletManager.publicKey, mint);
636
+ const destOwner = new web3_js_1.PublicKey(String(intentRaw.toOwner));
637
+ const destinationAta = tokenService.findAssociatedTokenAddress(destOwner, mint);
638
+ const tx = await transactionService.buildTransaction({
639
+ feePayer: walletManager.publicKey,
640
+ instructions: [
641
+ transactionService.buildSplTransferCheckedInstruction({
642
+ sourceAta,
643
+ mint,
644
+ destinationAta,
645
+ owner: walletManager.publicKey,
646
+ amount: BigInt(String(intentRaw.amountRaw)),
647
+ decimals: mintDecimals
648
+ })
649
+ ],
650
+ signer: walletManager
651
+ });
652
+ inspection = engine.inspect(tx.transaction);
653
+ }
654
+ else {
655
+ throw new Error("Unsupported intent type for validate-intent. Supported: write-memo, transfer-sol, transfer-spl");
656
+ }
657
+ activity("policy", {
658
+ action: "validate-intent",
659
+ agent: options.agent,
660
+ intentType: intentRaw.type
661
+ });
662
+ (0, output_1.printResult)(outputOptions(command), inspection, "Policy inspection result");
663
+ });
664
+ const agent = program.command("agent").description("agent management");
665
+ agent
666
+ .command("create")
667
+ .requiredOption("--agent <name>", "agent id")
668
+ .option("--owner <owner>", "owner id")
669
+ .description("create an agent with an encrypted managed wallet")
670
+ .action((options, command) => {
671
+ const createdWallet = walletRegistry.create(options.agent);
672
+ const createdAgent = agentRegistry.createAgent({
673
+ agentId: options.agent,
674
+ ownerId: options.owner,
675
+ walletName: createdWallet.record.name
676
+ });
677
+ activity("agent", {
678
+ action: "create",
679
+ ownerId: options.owner ?? null,
680
+ wallet: createdWallet.record.name
681
+ }, { agent: createdAgent.name });
682
+ (0, output_1.printResult)(outputOptions(command), {
683
+ agent: createdAgent.name,
684
+ custodyModel: CUSTODY_MODEL,
685
+ dataDir: (0, storagePaths_1.getCliDataDir)(),
686
+ defaultPolicyPreset: createdAgent.policyPreset,
687
+ masterKeySource: (0, walletCrypto_1.getPlatformMasterKeySource)(),
688
+ ownerId: createdAgent.ownerId ?? null,
689
+ publicKey: createdWallet.record.publicKey,
690
+ recoveryKey: createdWallet.recoveryKey,
691
+ wallet: createdAgent.walletName
692
+ }, `Agent ${createdAgent.name} created`);
693
+ });
694
+ agent
695
+ .command("fund")
696
+ .requiredOption("--agent <name>", "agent id")
697
+ .requiredOption("--sol <amount>", "amount in SOL")
698
+ .description("fund an agent wallet from treasury if configured, otherwise request devnet airdrop")
699
+ .action(async (options, command) => {
700
+ const record = resolveAgentRecord(options.agent);
701
+ const amountSol = parseSol(options.sol);
702
+ const walletManager = walletRegistry.toWalletManager(record.walletName);
703
+ const { balanceService, rpcClient, transactionService } = await buildServices();
704
+ const fundingService = new DevnetFundingService_1.DevnetFundingService(rpcClient, transactionService);
705
+ const funding = await fundingService.fundExactSol({
706
+ amountSol,
707
+ recipient: walletManager.publicKey
708
+ });
709
+ const updatedBalance = await fundingService.waitForMinimumBalance({
710
+ attempts: 15,
711
+ balanceService,
712
+ minimumSol: amountSol,
713
+ recipient: walletManager.publicKey
714
+ });
715
+ activity("agent", {
716
+ action: "fund",
717
+ amountSol,
718
+ ownerId: record.ownerId ?? null
719
+ }, { agent: record.name, signature: funding.signature });
720
+ (0, output_1.printResult)(outputOptions(command), {
721
+ agent: record.name,
722
+ balanceSol: updatedBalance,
723
+ explorer: (0, output_1.txExplorer)(funding.signature),
724
+ publicKey: walletManager.publicKey.toBase58(),
725
+ signature: funding.signature,
726
+ source: funding.source
727
+ }, `Agent ${record.name} funded`);
728
+ });
729
+ agent
730
+ .command("balance")
731
+ .requiredOption("--agent <name>", "agent id")
732
+ .description("fetch SOL balance for the agent wallet")
733
+ .action(async (options, command) => {
734
+ const record = resolveAgentRecord(options.agent);
735
+ const walletManager = walletRegistry.toWalletManager(record.walletName);
736
+ const { balanceService } = await buildServices();
737
+ const sol = await balanceService.getSolBalance(walletManager.publicKey);
738
+ (0, output_1.printResult)(outputOptions(command), {
739
+ agent: record.name,
740
+ balanceSol: sol,
741
+ publicKey: walletManager.publicKey.toBase58(),
742
+ wallet: record.walletName
743
+ }, `SOL balance for ${record.name}`);
744
+ });
745
+ agent
746
+ .command("export-wallet")
747
+ .requiredOption("--agent <name>", "agent id")
748
+ .requiredOption("--recovery-key <key>", "wallet recovery key")
749
+ .description("decrypt and export the agent wallet secret key")
750
+ .action((options, command) => {
751
+ const record = resolveAgentRecord(options.agent);
752
+ const secretKey = Array.from(walletRegistry.exportSecretKeyWithRecovery({
753
+ name: record.walletName,
754
+ recoveryKey: String(options.recoveryKey)
755
+ }));
756
+ const wallet = walletRegistry.find(record.walletName);
757
+ (0, output_1.printResult)(outputOptions(command), {
758
+ agent: record.name,
759
+ ownerId: record.ownerId ?? null,
760
+ publicKey: wallet?.publicKey ?? "<missing>",
761
+ secretKey,
762
+ wallet: record.walletName
763
+ }, `Agent ${record.name} wallet exported`);
764
+ });
765
+ agent
766
+ .command("list")
767
+ .description("list registered agents")
768
+ .action((_, command) => {
769
+ const agents = agentRegistry.synchronizeWithWallets().map((record) => ({
770
+ lastRunAt: record.lastRunAtIso ?? "-",
771
+ name: record.name,
772
+ ownerId: record.ownerId ?? "-",
773
+ policyMode: record.policyMode,
774
+ policyPreset: record.policyPreset,
775
+ status: record.status,
776
+ strategy: record.strategy,
777
+ wallet: record.walletName
778
+ }));
779
+ (0, output_1.printResult)(outputOptions(command), agents, "Agents");
780
+ });
781
+ agent
782
+ .command("show")
783
+ .requiredOption("--agent <name>", "agent name")
784
+ .description("show agent details")
785
+ .action((options, command) => {
786
+ const record = resolveAgentRecord(options.agent);
787
+ const wallet = walletRegistry.find(record.walletName);
788
+ (0, output_1.printResult)(outputOptions(command), {
789
+ ...record,
790
+ resolvedPolicy: (0, policyPresets_1.resolvePolicyConfig)({
791
+ agentId: record.name,
792
+ overrides: record.policyOverrides,
793
+ presetName: record.policyPreset ?? policyPresets_1.DEFAULT_POLICY_PRESET
794
+ }),
795
+ walletPublicKey: wallet?.publicKey ?? "<missing>"
796
+ }, `Agent ${record.name}`);
797
+ });
798
+ agent
799
+ .command("run")
800
+ .requiredOption("--agent <name>", "agent name")
801
+ .requiredOption("--strategy <strategy>", "strategy name")
802
+ .description("run a single agent once")
803
+ .action(async (options, command) => {
804
+ const record = resolveAgentRecord(options.agent);
805
+ const updated = agentRegistry.patch(record.name, {
806
+ status: "active",
807
+ strategy: options.strategy
808
+ });
809
+ const result = await (0, agentRuntime_1.runAgentOnce)({
810
+ agent: updated,
811
+ overrideStrategy: options.strategy
812
+ });
813
+ const lastSignature = result.outcomes.find((entry) => entry.signature)?.signature;
814
+ agentRegistry.patch(updated.name, {
815
+ lastAction: `${options.strategy}:run-once`,
816
+ lastRunAtIso: new Date().toISOString(),
817
+ lastSignature: lastSignature ?? undefined,
818
+ status: "active"
819
+ });
820
+ activity("agent", {
821
+ action: "run",
822
+ outcomes: result.outcomes.length,
823
+ strategy: options.strategy
824
+ }, { agent: updated.name, signature: lastSignature ?? undefined });
825
+ (0, output_1.printResult)(outputOptions(command), {
826
+ ...result,
827
+ explorer: lastSignature ? (0, output_1.txExplorer)(lastSignature) : null
828
+ }, `Agent ${updated.name} run complete`);
829
+ });
830
+ agent
831
+ .command("run-all")
832
+ .description("run all active agents once")
833
+ .action(async (_, command) => {
834
+ const records = agentRegistry.synchronizeWithWallets().filter((entry) => entry.status === "active");
835
+ const results = [];
836
+ for (const record of records) {
837
+ try {
838
+ const result = await (0, agentRuntime_1.runAgentOnce)({ agent: record });
839
+ const lastSignature = result.outcomes.find((entry) => entry.signature)?.signature;
840
+ agentRegistry.patch(record.name, {
841
+ lastAction: `${record.strategy}:run-once`,
842
+ lastRunAtIso: new Date().toISOString(),
843
+ lastSignature: lastSignature ?? undefined
844
+ });
845
+ results.push({
846
+ agent: record.name,
847
+ outcomes: result.outcomes.length,
848
+ signature: lastSignature ?? "-"
849
+ });
850
+ }
851
+ catch (error) {
852
+ const reason = error instanceof Error ? error.message : "unknown error";
853
+ agentRegistry.patch(record.name, {
854
+ lastError: reason,
855
+ lastRunAtIso: new Date().toISOString()
856
+ });
857
+ results.push({
858
+ agent: record.name,
859
+ error: reason,
860
+ outcomes: 0,
861
+ signature: "-"
862
+ });
863
+ }
864
+ }
865
+ activity("agent", { action: "run-all", count: results.length });
866
+ (0, output_1.printResult)(outputOptions(command), results, "Run-all summary");
867
+ });
868
+ agent
869
+ .command("stop")
870
+ .requiredOption("--agent <name>", "agent name")
871
+ .description("mark agent as stopped")
872
+ .action((options, command) => {
873
+ const updated = agentRegistry.patch(options.agent, { status: "stopped" });
874
+ activity("agent", { action: "stop" }, { agent: options.agent });
875
+ (0, output_1.printResult)(outputOptions(command), updated, `Agent ${options.agent} stopped`);
876
+ });
877
+ agent
878
+ .command("logs")
879
+ .requiredOption("--agent <name>", "agent name")
880
+ .description("show recent activity logs for agent")
881
+ .action((options, command) => {
882
+ const logs = activityStore.listByAgent(options.agent, 100).map((entry) => ({
883
+ details: JSON.stringify(entry.details),
884
+ kind: entry.kind,
885
+ signature: entry.signature ?? "-",
886
+ timestamp: entry.createdAtIso
887
+ }));
888
+ (0, output_1.printResult)(outputOptions(command), logs, `Recent logs for ${options.agent}`);
889
+ });
890
+ const monitor = program.command("monitor").description("operational monitoring views");
891
+ monitor
892
+ .command("overview")
893
+ .description("summarize agents, wallets and last activity")
894
+ .action(async (_, command) => {
895
+ const rows = await buildOverviewRows();
896
+ activity("monitor", { action: "overview", rows: rows.length });
897
+ (0, output_1.printResult)(outputOptions(command), rows, "Monitor overview");
898
+ });
899
+ monitor
900
+ .command("watch")
901
+ .description("live-refresh monitor overview")
902
+ .option("--interval <seconds>", "refresh interval in seconds", "5")
903
+ .option("--iterations <n>", "stop after n refreshes", "0")
904
+ .action(async (options, command) => {
905
+ const intervalSeconds = Number(options.interval);
906
+ const iterations = Number(options.iterations);
907
+ if (!Number.isFinite(intervalSeconds) || intervalSeconds <= 0) {
908
+ throw new Error("--interval must be a positive number");
909
+ }
910
+ const json = outputOptions(command).json;
911
+ let count = 0;
912
+ // eslint-disable-next-line no-constant-condition
913
+ while (true) {
914
+ count += 1;
915
+ const rows = await buildOverviewRows();
916
+ const snapshot = {
917
+ iteration: count,
918
+ timestamp: new Date().toISOString(),
919
+ rows
920
+ };
921
+ if (json) {
922
+ console.log(JSON.stringify(snapshot, null, 2));
923
+ }
924
+ else {
925
+ console.clear();
926
+ console.log(`PRKT monitor watch | ${snapshot.timestamp} | iteration ${count}`);
927
+ if (rows.length === 0) {
928
+ console.log("No agents found.");
929
+ }
930
+ else {
931
+ console.table(rows);
932
+ }
933
+ }
934
+ activity("monitor", { action: "watch", iteration: count, rows: rows.length });
935
+ if (iterations > 0 && count >= iterations) {
936
+ break;
937
+ }
938
+ await new Promise((resolve) => setTimeout(resolve, Math.round(intervalSeconds * 1000)));
939
+ }
940
+ });
941
+ monitor
942
+ .command("balances")
943
+ .description("show wallet SOL balances")
944
+ .action(async (_, command) => {
945
+ const { balanceService } = await buildServices();
946
+ const rows = [];
947
+ for (const wallet of walletRegistry.list()) {
948
+ const sol = await balanceService.getSolBalance(new web3_js_1.PublicKey(wallet.publicKey));
949
+ rows.push({
950
+ name: wallet.name,
951
+ publicKey: wallet.publicKey,
952
+ sol: sol.toFixed(4)
953
+ });
954
+ }
955
+ (0, output_1.printResult)(outputOptions(command), rows, "Wallet balances");
956
+ });
957
+ monitor
958
+ .command("txs")
959
+ .description("show recent transaction activity")
960
+ .action((_, command) => {
961
+ const txs = activityStore
962
+ .list(100)
963
+ .filter((entry) => Boolean(entry.signature))
964
+ .map((entry) => ({
965
+ agent: entry.agent ?? "-",
966
+ kind: entry.kind,
967
+ signature: entry.signature,
968
+ timestamp: entry.createdAtIso
969
+ }));
970
+ (0, output_1.printResult)(outputOptions(command), txs, "Recent transactions");
971
+ });
972
+ monitor
973
+ .command("agents")
974
+ .description("show agent runtime state")
975
+ .action((_, command) => {
976
+ const rows = agentRegistry.synchronizeWithWallets().map((entry) => ({
977
+ agent: entry.name,
978
+ lastError: entry.lastError ?? "-",
979
+ lastRunAt: entry.lastRunAtIso ?? "-",
980
+ policyMode: entry.policyMode,
981
+ status: entry.status,
982
+ strategy: entry.strategy
983
+ }));
984
+ (0, output_1.printResult)(outputOptions(command), rows, "Agent state");
985
+ });
986
+ const demo = program.command("demo").description("demo execution helpers");
987
+ demo
988
+ .command("multi-agent-devnet")
989
+ .description("run existing multi-agent devnet demo")
990
+ .action(async (_, command) => {
991
+ const result = await (0, multiAgentDevnetScenario_1.runMultiAgentDevnetScenario)();
992
+ activity("demo", {
993
+ action: "multi-agent-devnet",
994
+ mintAddress: result.mintAddress,
995
+ signatures: result.signatures.length
996
+ });
997
+ (0, output_1.printResult)(outputOptions(command), {
998
+ ...result,
999
+ explorerLinks: result.signatures.map(output_1.txExplorer)
1000
+ }, "Multi-agent devnet demo complete");
1001
+ });
1002
+ program
1003
+ .command("audit")
1004
+ .description("show recent audit log entries")
1005
+ .option("--limit <n>", "max entries", "100")
1006
+ .action((options, command) => {
1007
+ const limit = Number(options.limit);
1008
+ const rows = activityStore.list(Number.isFinite(limit) ? limit : 100).map((entry) => ({
1009
+ agent: entry.agent ?? "-",
1010
+ details: JSON.stringify(entry.details),
1011
+ kind: entry.kind,
1012
+ signature: entry.signature ?? "-",
1013
+ timestamp: entry.createdAtIso
1014
+ }));
1015
+ (0, output_1.printResult)(outputOptions(command), rows, "Audit activity");
1016
+ });
1017
+ const config = program.command("config").description("configuration commands");
1018
+ config
1019
+ .command("show")
1020
+ .description("show runtime config")
1021
+ .action((_, command) => {
1022
+ const rpc = (0, env_1.getRpcUrl)();
1023
+ const dataDirStatus = (0, storagePaths_1.probeCliDataDir)();
1024
+ const payload = {
1025
+ cliDataDir: dataDirStatus.path,
1026
+ cliDataDirHealth: dataDirStatus.details,
1027
+ cliDataDirWritable: dataDirStatus.writable,
1028
+ cluster: (0, env_1.detectClusterFromRpcUrl)(rpc),
1029
+ custodyModel: CUSTODY_MODEL,
1030
+ koraRpc: (0, env_1.getKoraRpcUrl)(),
1031
+ liveRaydiumLp: (0, env_1.isLiveRaydiumLpEnabled)(),
1032
+ liveSwap: (0, env_1.isLiveSwapPathEnabled)(),
1033
+ policyExecutionModel: POLICY_EXECUTION_MODEL,
1034
+ rpc,
1035
+ walletKeySource: (0, walletCrypto_1.getPlatformMasterKeySource)(),
1036
+ universalDefiLiveFirst: (0, env_1.isUniversalDeFiLiveFirstEnabled)(),
1037
+ usdcMint: (0, env_1.getUsdcMintAddress)()
1038
+ };
1039
+ activity("config", { action: "show" });
1040
+ (0, output_1.printResult)(outputOptions(command), payload, "Config");
1041
+ });
1042
+ program
1043
+ .command("doctor")
1044
+ .description("validate env, rpc, and devnet readiness")
1045
+ .action(async (_, command) => {
1046
+ const checks = [];
1047
+ const rpc = (0, env_1.getRpcUrl)();
1048
+ const dataDirStatus = (0, storagePaths_1.probeCliDataDir)();
1049
+ checks.push({
1050
+ check: "cluster",
1051
+ details: (0, env_1.detectClusterFromRpcUrl)(rpc),
1052
+ status: (0, env_1.detectClusterFromRpcUrl)(rpc) === "devnet" ? "ok" : "warn"
1053
+ });
1054
+ try {
1055
+ const connection = new web3_js_1.Connection(rpc, "confirmed");
1056
+ await connection.getLatestBlockhash("confirmed");
1057
+ checks.push({
1058
+ check: "rpc-connectivity",
1059
+ details: rpc,
1060
+ status: "ok"
1061
+ });
1062
+ }
1063
+ catch (error) {
1064
+ checks.push({
1065
+ check: "rpc-connectivity",
1066
+ details: error instanceof Error ? error.message : "unknown rpc error",
1067
+ status: "fail"
1068
+ });
1069
+ }
1070
+ const remoteSigner = (0, env_1.getRemoteSignerConfig)();
1071
+ const treasurySecretKey = (0, env_1.getOptionalDevnetTreasurySecretKey)();
1072
+ const treasuryExists = Boolean(remoteSigner ||
1073
+ treasurySecretKey ||
1074
+ (process.env.AGENT_PRIVATE_KEY && process.env.AGENT_PRIVATE_KEY.length > 0));
1075
+ checks.push({
1076
+ check: "treasury-key",
1077
+ details: remoteSigner
1078
+ ? `remote signer ${remoteSigner.publicKey.toBase58()}`
1079
+ : treasurySecretKey
1080
+ ? "devnet treasury key present"
1081
+ : treasuryExists
1082
+ ? "local demo key present"
1083
+ : "missing signer configuration",
1084
+ status: treasuryExists ? "ok" : "warn"
1085
+ });
1086
+ checks.push({
1087
+ check: "custody-model",
1088
+ details: CUSTODY_MODEL,
1089
+ status: "ok"
1090
+ });
1091
+ checks.push({
1092
+ check: "cli-data-dir",
1093
+ details: dataDirStatus.path,
1094
+ status: "ok"
1095
+ });
1096
+ checks.push({
1097
+ check: "cli-data-dir-writable",
1098
+ details: dataDirStatus.details,
1099
+ status: dataDirStatus.writable ? "ok" : "fail"
1100
+ });
1101
+ checks.push({
1102
+ check: "wallet-key-source",
1103
+ details: (0, walletCrypto_1.getPlatformMasterKeySource)(),
1104
+ status: "ok"
1105
+ });
1106
+ checks.push({
1107
+ check: "policy-execution-model",
1108
+ details: POLICY_EXECUTION_MODEL,
1109
+ status: "ok"
1110
+ });
1111
+ checks.push({
1112
+ check: "live-swap-flag",
1113
+ details: String((0, env_1.isLiveSwapPathEnabled)()),
1114
+ status: "ok"
1115
+ });
1116
+ checks.push({
1117
+ check: "live-raydium-flag",
1118
+ details: String((0, env_1.isLiveRaydiumLpEnabled)()),
1119
+ status: "ok"
1120
+ });
1121
+ checks.push({
1122
+ check: "universal-live-first",
1123
+ details: String((0, env_1.isUniversalDeFiLiveFirstEnabled)()),
1124
+ status: "ok"
1125
+ });
1126
+ activity("doctor", { checks: checks.length });
1127
+ (0, output_1.printResult)(outputOptions(command), checks, "Doctor checks");
1128
+ });
1129
+ program
1130
+ .command("completion")
1131
+ .description("print shell completion script")
1132
+ .argument("[shell]", "shell type: bash | zsh | powershell", "bash")
1133
+ .action((shell) => {
1134
+ const normalized = shell.trim().toLowerCase();
1135
+ if (normalized === "bash") {
1136
+ console.log((0, completion_1.buildBashCompletion)());
1137
+ return;
1138
+ }
1139
+ if (normalized === "zsh") {
1140
+ console.log((0, completion_1.buildZshCompletion)());
1141
+ return;
1142
+ }
1143
+ if (normalized === "powershell" || normalized === "pwsh") {
1144
+ console.log((0, completion_1.buildPowerShellCompletion)());
1145
+ return;
1146
+ }
1147
+ throw new Error("Unsupported shell. Use: bash, zsh, powershell");
1148
+ });
1149
+ async function main() {
1150
+ try {
1151
+ await program.parseAsync(process.argv);
1152
+ }
1153
+ catch (error) {
1154
+ const message = error instanceof Error ? error.message : "Unknown CLI error";
1155
+ console.error(`CLI error: ${message}`);
1156
+ process.exitCode = 1;
1157
+ }
1158
+ }
1159
+ main();